forked from vuejs/vue-codemod
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathadd-import.ts
100 lines (92 loc) · 2.52 KB
/
add-import.ts
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
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
import wrap from '../src/wrapAstTransformation'
import type { ASTTransformation } from '../src/wrapAstTransformation'
import type {
ImportSpecifier,
ImportDefaultSpecifier,
ImportNamespaceSpecifier,
} from 'jscodeshift'
type DefaultSpecifierParam = {
type: 'default'
local: string
}
type NamedSpecifierParam = {
type: 'named'
imported: string
local?: string
}
type NamespaceSpecifierParam = {
type: 'namespace'
local: string
}
type Params = {
specifier:
| DefaultSpecifierParam
| NamedSpecifierParam
| NamespaceSpecifierParam
source: string
}
export const transformAST: ASTTransformation<Params> = (
{ root, j },
{ specifier, source }
) => {
let localBinding: string
if (specifier.type === 'named') {
localBinding = specifier.local || specifier.imported
} else {
localBinding = specifier.local
}
const duplicate = root.find(j.ImportDeclaration, {
specifiers: (
arr: Array<
ImportSpecifier | ImportDefaultSpecifier | ImportNamespaceSpecifier
>
) =>
// @ts-ignore there's a bug in ast-types definition, the `local` should be non-nullable
arr.some((s) => s.local.name === localBinding),
source: {
value: source,
},
})
if (duplicate.length) {
return
}
let newImportSpecifier
if (specifier.type === 'default') {
newImportSpecifier = j.importDefaultSpecifier(j.identifier(specifier.local))
} else if (specifier.type === 'named') {
newImportSpecifier = j.importSpecifier(
j.identifier(specifier.imported),
j.identifier(localBinding)
)
} else {
// namespace
newImportSpecifier = j.importNamespaceSpecifier(j.identifier(localBinding))
}
const matchedDecl = root.find(j.ImportDeclaration, {
source: {
value: source,
},
})
if (
matchedDecl.length &&
!matchedDecl.find(j.ImportNamespaceSpecifier).length
) {
// add new specifier to the existing import declaration
matchedDecl.get(0).node.specifiers.push(newImportSpecifier)
} else {
const newImportDecl = j.importDeclaration(
[newImportSpecifier],
j.stringLiteral(source)
)
const lastImportDecl = root.find(j.ImportDeclaration).at(-1)
if (lastImportDecl.length) {
// add the new import declaration after all other import declarations
lastImportDecl.insertAfter(newImportDecl)
} else {
// add new import declaration at the beginning of the file
root.get().node.program.body.unshift(newImportDecl)
}
}
}
export default wrap(transformAST)
export const parser = 'babylon'