index.ts
2.27 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
import { lodash as _ } from '@umijs/utils';
import { extname, parse, relative, sep } from 'path';
/**
* convert path into componentName
* like:
* - src/index.tsx => SrcIndex
* - components/Header.tsx => ComponentHeader
*
* @param filePath
* @returns {string} componentName
*/
export const path2Component = (filePath: string): string => {
const { ext } = parse(filePath);
const filePathWithoutExt = filePath
// remove extension
.replace(ext, '')
.split(sep)
// upperFirst
.map((item) => _.upperFirst(item.replace(/\W/g, '')))
.join('');
return filePathWithoutExt;
};
// @ts-ignore
export default (babel) => {
const { types: t } = babel;
return {
visitor: {
// @ts-ignore
ExportDefaultDeclaration: {
enter(path: any, state: any) {
const def = path.node.declaration;
const { cwd, filename } = state.file.opts;
const relativePath = relative(cwd, filename);
if (
/^\.(tsx|jsx)$/.test(extname(relativePath)) &&
// hidden relativePath
!/(^|\/)\.[^\/\.]/g.test(relativePath) &&
!relativePath.includes('node_modules')
) {
let componentName = path2Component(relativePath);
if (!componentName) {
return;
}
// solve identifier conflict
const identifiers = Object.keys(path.scope.bindings || {});
// add index if conflict
let idx = 0;
// loop util componentName conflict
while (identifiers.includes(componentName)) {
componentName = `${componentName}${idx}`;
idx += 1;
}
// generate component name identifier
const named = t.identifier(componentName);
if (t.isArrowFunctionExpression(def)) {
const varDec = t.variableDeclaration('const', [
t.variableDeclarator(named, def),
]);
const [varDeclPath] = path.insertBefore(varDec);
path.scope.registerDeclaration(varDeclPath);
path.replaceWith(t.exportDefaultDeclaration(named));
} else if (t.isFunctionDeclaration(def) && !def.id) {
def.id = named;
}
}
},
},
},
};
};