@kaizen/components 1.80.3 → 1.80.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/codemods/README.md +12 -0
- package/codemods/migrateV2NextToCurrent/index.ts +40 -0
- package/codemods/migrateV2NextToCurrent/migrateV2NextToCurrent.spec.ts +555 -0
- package/codemods/migrateV2NextToCurrent/migrateV2NextToCurrent.ts +104 -0
- package/codemods/renameV2ComponentImportsAndUsages/index.ts +12 -1
- package/codemods/renameV2ComponentImportsAndUsages/renameV2ComponentImportsAndUsages.ts +57 -136
- package/codemods/utils/createModulePathTransformer.spec.ts +209 -0
- package/codemods/utils/createModulePathTransformer.ts +59 -0
- package/codemods/utils/createRenameMapFromGroups.ts +31 -0
- package/codemods/utils/index.ts +2 -0
- package/dist/styles.css +17 -17
- package/package.json +1 -1
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import ts from 'typescript'
|
|
2
|
+
import {
|
|
3
|
+
createRenameMapFromGroups,
|
|
4
|
+
processImportDeclaration,
|
|
5
|
+
setImportToAdd,
|
|
6
|
+
setImportToRemove,
|
|
7
|
+
updateKaioImports,
|
|
8
|
+
type ComponentGroup,
|
|
9
|
+
type TagImportAttributesMap,
|
|
10
|
+
type UpdateKaioImportsArgs,
|
|
11
|
+
} from '../utils'
|
|
12
|
+
|
|
13
|
+
const componentGroups: ComponentGroup[] = [
|
|
14
|
+
{
|
|
15
|
+
components: ['Menu', 'MenuHeader', 'MenuItem', 'MenuPopover', 'MenuSection', 'MenuTrigger'],
|
|
16
|
+
fromModules: ['@kaizen/components/next', '@kaizen/components/v3/actions'],
|
|
17
|
+
toModule: '@kaizen/components',
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
components: ['Tabs', 'Tab', 'TabList', 'TabPanel', 'Icon', 'Focusable', 'Key'],
|
|
21
|
+
fromModules: ['@kaizen/components/next', '@kaizen/components/future'],
|
|
22
|
+
toModule: '@kaizen/components',
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
components: ['Tooltip', 'TooltipTrigger'],
|
|
26
|
+
fromModules: [
|
|
27
|
+
'@kaizen/components/next',
|
|
28
|
+
'@kaizen/components/future',
|
|
29
|
+
'@kaizen/components/v3/overlays',
|
|
30
|
+
],
|
|
31
|
+
toModule: '@kaizen/components',
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
components: ['ReversedColors'],
|
|
35
|
+
fromModules: ['@kaizen/components/v3/utilities'],
|
|
36
|
+
toModule: '@kaizen/components',
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
components: ['Button', 'ButtonProps', 'ButtonsSizes', 'ButtonVariants'],
|
|
40
|
+
fromModules: [
|
|
41
|
+
'@kaizen/components/next',
|
|
42
|
+
'@kaizen/components/future',
|
|
43
|
+
'@kaizen/components/v3/actions',
|
|
44
|
+
],
|
|
45
|
+
toModule: '@kaizen/components',
|
|
46
|
+
},
|
|
47
|
+
]
|
|
48
|
+
|
|
49
|
+
const renameMap = createRenameMapFromGroups(componentGroups)
|
|
50
|
+
|
|
51
|
+
const modulePathMap = new Map([
|
|
52
|
+
['@kaizen/components/v3/react-aria', '@kaizen/components/react-aria'],
|
|
53
|
+
['@kaizen/components/v3/react-aria-components', '@kaizen/components/react-aria-components'],
|
|
54
|
+
])
|
|
55
|
+
|
|
56
|
+
export const migrateV2NextToCurrent =
|
|
57
|
+
(_tagsMap: TagImportAttributesMap | undefined): ts.TransformerFactory<ts.SourceFile> =>
|
|
58
|
+
(context) =>
|
|
59
|
+
(rootNode) => {
|
|
60
|
+
const importsToRemove: UpdateKaioImportsArgs['importsToRemove'] = new Map()
|
|
61
|
+
const importsToAdd: UpdateKaioImportsArgs['importsToAdd'] = new Map()
|
|
62
|
+
|
|
63
|
+
const visit = (node: ts.Node): ts.Node => {
|
|
64
|
+
if (ts.isImportDeclaration(node)) {
|
|
65
|
+
const moduleSpecifier = node.moduleSpecifier
|
|
66
|
+
if (ts.isStringLiteral(moduleSpecifier)) {
|
|
67
|
+
const moduleName = moduleSpecifier.text
|
|
68
|
+
|
|
69
|
+
if (modulePathMap.has(moduleName)) {
|
|
70
|
+
const newModuleName = modulePathMap.get(moduleName)!
|
|
71
|
+
const namedBindings = node.importClause?.namedBindings
|
|
72
|
+
|
|
73
|
+
if (namedBindings && ts.isNamedImports(namedBindings)) {
|
|
74
|
+
namedBindings.elements.forEach((element) => {
|
|
75
|
+
const importName = element.name.text
|
|
76
|
+
const aliasName = element.propertyName?.text
|
|
77
|
+
|
|
78
|
+
setImportToRemove(importsToRemove, moduleName, aliasName ?? importName)
|
|
79
|
+
|
|
80
|
+
setImportToAdd(importsToAdd, newModuleName, {
|
|
81
|
+
componentName: aliasName ?? importName,
|
|
82
|
+
alias: aliasName ? importName : undefined,
|
|
83
|
+
})
|
|
84
|
+
})
|
|
85
|
+
}
|
|
86
|
+
} else {
|
|
87
|
+
processImportDeclaration(node, {
|
|
88
|
+
importsToRemove,
|
|
89
|
+
importsToAdd,
|
|
90
|
+
renameMap,
|
|
91
|
+
})
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return ts.visitEachChild(node, visit, context)
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const transformedNode = ts.visitNode(rootNode, visit)
|
|
100
|
+
|
|
101
|
+
return updateKaioImports({ importsToRemove, importsToAdd })(context)(
|
|
102
|
+
transformedNode as ts.SourceFile,
|
|
103
|
+
)
|
|
104
|
+
}
|
|
@@ -11,7 +11,18 @@ const run = (): void => {
|
|
|
11
11
|
|
|
12
12
|
transformComponentsInDir(
|
|
13
13
|
targetDir,
|
|
14
|
-
[
|
|
14
|
+
[
|
|
15
|
+
'Select',
|
|
16
|
+
'SelectProps',
|
|
17
|
+
'SelectOption',
|
|
18
|
+
'SelectOptionGroup',
|
|
19
|
+
'SelectItem',
|
|
20
|
+
'SelectOptionNode',
|
|
21
|
+
'SelectOptionGroupNode',
|
|
22
|
+
'SelectItemNode',
|
|
23
|
+
'LikertScaleLegacy',
|
|
24
|
+
'TitleBlockZen',
|
|
25
|
+
],
|
|
15
26
|
(tagNames) => [renameV2ComponentImportsAndUsages(tagNames)],
|
|
16
27
|
)
|
|
17
28
|
}
|
|
@@ -1,123 +1,36 @@
|
|
|
1
1
|
import ts from 'typescript'
|
|
2
2
|
import {
|
|
3
|
+
createRenameMapFromGroups,
|
|
4
|
+
processImportDeclaration,
|
|
3
5
|
setImportToAdd,
|
|
4
6
|
setImportToRemove,
|
|
5
7
|
updateJsxElementTagName,
|
|
6
8
|
updateKaioImports,
|
|
7
|
-
type
|
|
9
|
+
type ComponentGroup,
|
|
8
10
|
type TagImportAttributesMap,
|
|
9
11
|
type UpdateKaioImportsArgs,
|
|
10
12
|
} from '../utils'
|
|
11
13
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
toModule: '@kaizen/components',
|
|
33
|
-
},
|
|
34
|
-
],
|
|
35
|
-
[
|
|
36
|
-
'SelectOption',
|
|
37
|
-
{
|
|
38
|
-
newName: 'SingleSelectOption',
|
|
39
|
-
fromModules: ['@kaizen/components/next', '@kaizen/components/future'],
|
|
40
|
-
toModule: '@kaizen/components',
|
|
41
|
-
},
|
|
42
|
-
],
|
|
43
|
-
[
|
|
44
|
-
'SelectOptionGroup',
|
|
45
|
-
{
|
|
46
|
-
newName: 'SingleSelectOptionGroup',
|
|
47
|
-
fromModules: ['@kaizen/components/next', '@kaizen/components/future'],
|
|
48
|
-
toModule: '@kaizen/components',
|
|
49
|
-
},
|
|
50
|
-
],
|
|
51
|
-
[
|
|
52
|
-
'SelectItem',
|
|
53
|
-
{
|
|
54
|
-
newName: 'SingleSelectItem',
|
|
55
|
-
fromModules: ['@kaizen/components/next', '@kaizen/components/future'],
|
|
56
|
-
toModule: '@kaizen/components',
|
|
57
|
-
},
|
|
58
|
-
],
|
|
59
|
-
[
|
|
60
|
-
'SelectOptionNode',
|
|
61
|
-
{
|
|
62
|
-
newName: 'SingleSelectOptionNode',
|
|
63
|
-
fromModules: ['@kaizen/components/next', '@kaizen/components/future'],
|
|
64
|
-
toModule: '@kaizen/components',
|
|
65
|
-
},
|
|
66
|
-
],
|
|
67
|
-
[
|
|
68
|
-
'SelectOptionGroupNode',
|
|
69
|
-
{
|
|
70
|
-
newName: 'SingleSelectOptionGroupNode',
|
|
71
|
-
fromModules: ['@kaizen/components/next', '@kaizen/components/future'],
|
|
72
|
-
toModule: '@kaizen/components',
|
|
73
|
-
},
|
|
74
|
-
],
|
|
75
|
-
[
|
|
76
|
-
'SelectItemNode',
|
|
77
|
-
{
|
|
78
|
-
newName: 'SingleSelectItemNode',
|
|
79
|
-
fromModules: ['@kaizen/components/next', '@kaizen/components/future'],
|
|
80
|
-
toModule: '@kaizen/components',
|
|
81
|
-
},
|
|
82
|
-
],
|
|
83
|
-
[
|
|
84
|
-
'LikertScaleLegacy',
|
|
85
|
-
{
|
|
86
|
-
newName: 'LikertScale',
|
|
87
|
-
fromModules: ['@kaizen/components'],
|
|
88
|
-
toModule: '@kaizen/components',
|
|
89
|
-
},
|
|
90
|
-
],
|
|
91
|
-
[
|
|
92
|
-
'TitleBlockZen',
|
|
93
|
-
{
|
|
94
|
-
newName: 'TitleBlock',
|
|
95
|
-
fromModules: ['@kaizen/components'],
|
|
96
|
-
toModule: '@kaizen/components',
|
|
97
|
-
},
|
|
98
|
-
],
|
|
99
|
-
])
|
|
100
|
-
|
|
101
|
-
const createComponentRenameConfig = (
|
|
102
|
-
config: RenameConfig,
|
|
103
|
-
fromModule: string,
|
|
104
|
-
): ComponentRenameConfig => ({
|
|
105
|
-
newName: config.newName,
|
|
106
|
-
fromModule,
|
|
107
|
-
toModule: config.toModule,
|
|
108
|
-
})
|
|
109
|
-
|
|
110
|
-
const componentRenameMap = new Map<string, ComponentRenameConfig>()
|
|
111
|
-
for (const [name, config] of Array.from(renameMap.entries())) {
|
|
112
|
-
if (
|
|
113
|
-
!name.endsWith('Props') &&
|
|
114
|
-
!name.includes('Option') &&
|
|
115
|
-
!name.includes('Item') &&
|
|
116
|
-
!name.includes('Node')
|
|
117
|
-
) {
|
|
118
|
-
componentRenameMap.set(name, createComponentRenameConfig(config, config.fromModules[0]))
|
|
119
|
-
}
|
|
120
|
-
}
|
|
14
|
+
const componentGroups: ComponentGroup[] = [
|
|
15
|
+
{
|
|
16
|
+
components: [
|
|
17
|
+
['Select', 'SingleSelect'],
|
|
18
|
+
['SelectProps', 'SingleSelectProps'],
|
|
19
|
+
['SelectOption', 'SingleSelectOption'],
|
|
20
|
+
['SelectOptionGroup', 'SingleSelectOptionGroup'],
|
|
21
|
+
['SelectItem', 'SingleSelectItem'],
|
|
22
|
+
['SelectOptionNode', 'SingleSelectOptionNode'],
|
|
23
|
+
['SelectOptionGroupNode', 'SingleSelectOptionGroupNode'],
|
|
24
|
+
['SelectItemNode', 'SingleSelectItemNode'],
|
|
25
|
+
['LikertScaleLegacy', 'LikertScale'],
|
|
26
|
+
['TitleBlockZen', 'TitleBlock'],
|
|
27
|
+
],
|
|
28
|
+
fromModules: ['@kaizen/components/next', '@kaizen/components/future', '@kaizen/components'],
|
|
29
|
+
toModule: '@kaizen/components',
|
|
30
|
+
},
|
|
31
|
+
]
|
|
32
|
+
|
|
33
|
+
const renameMap = createRenameMapFromGroups(componentGroups)
|
|
121
34
|
|
|
122
35
|
export const renameV2ComponentImportsAndUsages =
|
|
123
36
|
(tagsMap: TagImportAttributesMap | undefined): ts.TransformerFactory<ts.SourceFile> =>
|
|
@@ -129,25 +42,12 @@ export const renameV2ComponentImportsAndUsages =
|
|
|
129
42
|
|
|
130
43
|
const visit = (node: ts.Node): ts.Node => {
|
|
131
44
|
if (ts.isImportDeclaration(node)) {
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
importSpecifier.propertyName?.getText() ?? importSpecifier.name?.getText()
|
|
139
|
-
|
|
140
|
-
const renameConfig = renameMap.get(importName)
|
|
141
|
-
if (renameConfig?.fromModules.includes(moduleSpecifier)) {
|
|
142
|
-
validRenames.add(importName)
|
|
143
|
-
setImportToRemove(importsToRemove, moduleSpecifier, importName)
|
|
144
|
-
setImportToAdd(importsToAdd, renameConfig.toModule, {
|
|
145
|
-
componentName: renameConfig.newName,
|
|
146
|
-
isTypeOnly: importSpecifier.isTypeOnly || importClause.isTypeOnly,
|
|
147
|
-
})
|
|
148
|
-
}
|
|
149
|
-
})
|
|
150
|
-
}
|
|
45
|
+
processImportDeclaration(node, {
|
|
46
|
+
importsToRemove,
|
|
47
|
+
importsToAdd,
|
|
48
|
+
renameMap,
|
|
49
|
+
validRenames,
|
|
50
|
+
})
|
|
151
51
|
}
|
|
152
52
|
|
|
153
53
|
if (
|
|
@@ -157,17 +57,31 @@ export const renameV2ComponentImportsAndUsages =
|
|
|
157
57
|
) {
|
|
158
58
|
if (ts.isPropertyAccessExpression(node.tagName)) {
|
|
159
59
|
const left = node.tagName.expression.getText()
|
|
160
|
-
const
|
|
60
|
+
const renameConfig = renameMap.get(left)
|
|
161
61
|
|
|
162
|
-
if (
|
|
163
|
-
setImportToRemove(importsToRemove,
|
|
164
|
-
setImportToAdd(importsToAdd,
|
|
62
|
+
if (renameConfig) {
|
|
63
|
+
setImportToRemove(importsToRemove, renameConfig.fromModules[0], left)
|
|
64
|
+
setImportToAdd(importsToAdd, renameConfig.toModule, {
|
|
65
|
+
componentName: renameConfig.newName,
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
// Create temporary map for updateJsxElementTagName
|
|
69
|
+
const tempComponentMap = new Map([
|
|
70
|
+
[
|
|
71
|
+
left,
|
|
72
|
+
{
|
|
73
|
+
newName: renameConfig.newName,
|
|
74
|
+
fromModule: renameConfig.fromModules[0],
|
|
75
|
+
toModule: renameConfig.toModule,
|
|
76
|
+
},
|
|
77
|
+
],
|
|
78
|
+
])
|
|
165
79
|
|
|
166
80
|
return updateJsxElementTagName(
|
|
167
81
|
context.factory,
|
|
168
82
|
node,
|
|
169
|
-
|
|
170
|
-
|
|
83
|
+
renameConfig.newName,
|
|
84
|
+
tempComponentMap,
|
|
171
85
|
)
|
|
172
86
|
}
|
|
173
87
|
|
|
@@ -199,7 +113,14 @@ export const renameV2ComponentImportsAndUsages =
|
|
|
199
113
|
})
|
|
200
114
|
const jsxElementName = alias ?? renameConfig.newName
|
|
201
115
|
const tempComponentMap = new Map([
|
|
202
|
-
[
|
|
116
|
+
[
|
|
117
|
+
kaioComponentName,
|
|
118
|
+
{
|
|
119
|
+
newName: renameConfig.newName,
|
|
120
|
+
fromModule: oldImportSource,
|
|
121
|
+
toModule: renameConfig.toModule,
|
|
122
|
+
},
|
|
123
|
+
],
|
|
203
124
|
])
|
|
204
125
|
return updateJsxElementTagName(context.factory, node, jsxElementName, tempComponentMap)
|
|
205
126
|
}
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
import type ts from 'typescript'
|
|
2
|
+
import { parseJsx } from '../__tests__/utils'
|
|
3
|
+
import { processImportDeclaration, type ProcessImportOptions } from './createModulePathTransformer'
|
|
4
|
+
|
|
5
|
+
const createTestOptions = (): ProcessImportOptions => ({
|
|
6
|
+
importsToRemove: new Map(),
|
|
7
|
+
importsToAdd: new Map(),
|
|
8
|
+
renameMap: new Map([
|
|
9
|
+
[
|
|
10
|
+
'OldComponent',
|
|
11
|
+
{
|
|
12
|
+
newName: 'NewComponent',
|
|
13
|
+
fromModules: ['@kaizen/components/v3/actions'],
|
|
14
|
+
toModule: '@kaizen/components',
|
|
15
|
+
},
|
|
16
|
+
],
|
|
17
|
+
[
|
|
18
|
+
'Select',
|
|
19
|
+
{
|
|
20
|
+
newName: 'SingleSelect',
|
|
21
|
+
fromModules: ['@kaizen/components/next', '@kaizen/components/future'],
|
|
22
|
+
toModule: '@kaizen/components',
|
|
23
|
+
},
|
|
24
|
+
],
|
|
25
|
+
]),
|
|
26
|
+
validRenames: new Set(),
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
const getImportDeclaration = (code: string): ts.ImportDeclaration => {
|
|
30
|
+
const sourceFile = parseJsx(code)
|
|
31
|
+
return sourceFile.statements[0] as ts.ImportDeclaration
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
describe('processImportDeclaration', () => {
|
|
35
|
+
it('should transform basic import', () => {
|
|
36
|
+
const options = createTestOptions()
|
|
37
|
+
const importDeclaration = getImportDeclaration(
|
|
38
|
+
`import { OldComponent } from "@kaizen/components/v3/actions"`,
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
processImportDeclaration(importDeclaration, options)
|
|
42
|
+
|
|
43
|
+
expect(options.importsToRemove.get('@kaizen/components/v3/actions')).toContain('OldComponent')
|
|
44
|
+
expect(options.importsToAdd.get('@kaizen/components')?.get('NewComponent')).toEqual({
|
|
45
|
+
componentName: 'NewComponent',
|
|
46
|
+
alias: undefined,
|
|
47
|
+
isTypeOnly: false,
|
|
48
|
+
})
|
|
49
|
+
expect(options.validRenames?.has('OldComponent')).toBe(true)
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
it('should transform aliased import', () => {
|
|
53
|
+
const options = createTestOptions()
|
|
54
|
+
const importDeclaration = getImportDeclaration(
|
|
55
|
+
`import { OldComponent as MyComponent } from "@kaizen/components/v3/actions"`,
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
processImportDeclaration(importDeclaration, options)
|
|
59
|
+
|
|
60
|
+
expect(options.importsToRemove.get('@kaizen/components/v3/actions')).toContain('OldComponent')
|
|
61
|
+
expect(options.importsToAdd.get('@kaizen/components')?.get('NewComponent')).toEqual({
|
|
62
|
+
componentName: 'NewComponent',
|
|
63
|
+
alias: 'MyComponent',
|
|
64
|
+
isTypeOnly: false,
|
|
65
|
+
})
|
|
66
|
+
expect(options.validRenames?.has('OldComponent')).toBe(true)
|
|
67
|
+
})
|
|
68
|
+
|
|
69
|
+
it('should transform type-only import at import clause level', () => {
|
|
70
|
+
const options = createTestOptions()
|
|
71
|
+
const importDeclaration = getImportDeclaration(
|
|
72
|
+
`import type { OldComponent } from "@kaizen/components/v3/actions"`,
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
processImportDeclaration(importDeclaration, options)
|
|
76
|
+
|
|
77
|
+
expect(options.importsToRemove.get('@kaizen/components/v3/actions')).toContain('OldComponent')
|
|
78
|
+
expect(options.importsToAdd.get('@kaizen/components')?.get('NewComponent')).toEqual({
|
|
79
|
+
componentName: 'NewComponent',
|
|
80
|
+
alias: undefined,
|
|
81
|
+
isTypeOnly: true,
|
|
82
|
+
})
|
|
83
|
+
expect(options.validRenames?.has('OldComponent')).toBe(true)
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
it('should transform inline type-only import', () => {
|
|
87
|
+
const options = createTestOptions()
|
|
88
|
+
const importDeclaration = getImportDeclaration(
|
|
89
|
+
`import { type OldComponent } from "@kaizen/components/v3/actions"`,
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
processImportDeclaration(importDeclaration, options)
|
|
93
|
+
|
|
94
|
+
expect(options.importsToRemove.get('@kaizen/components/v3/actions')).toContain('OldComponent')
|
|
95
|
+
expect(options.importsToAdd.get('@kaizen/components')?.get('NewComponent')).toEqual({
|
|
96
|
+
componentName: 'NewComponent',
|
|
97
|
+
alias: undefined,
|
|
98
|
+
isTypeOnly: true,
|
|
99
|
+
})
|
|
100
|
+
expect(options.validRenames?.has('OldComponent')).toBe(true)
|
|
101
|
+
})
|
|
102
|
+
|
|
103
|
+
it('should handle mixed imports in single declaration', () => {
|
|
104
|
+
const options = createTestOptions()
|
|
105
|
+
const importDeclaration = getImportDeclaration(
|
|
106
|
+
`import { OldComponent, AnotherComponent } from "@kaizen/components/v3/actions"`,
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
processImportDeclaration(importDeclaration, options)
|
|
110
|
+
|
|
111
|
+
expect(options.importsToRemove.get('@kaizen/components/v3/actions')).toContain('OldComponent')
|
|
112
|
+
expect(options.importsToRemove.get('@kaizen/components/v3/actions')).not.toContain(
|
|
113
|
+
'AnotherComponent',
|
|
114
|
+
)
|
|
115
|
+
expect(options.importsToAdd.get('@kaizen/components')?.get('NewComponent')).toEqual({
|
|
116
|
+
componentName: 'NewComponent',
|
|
117
|
+
alias: undefined,
|
|
118
|
+
isTypeOnly: false,
|
|
119
|
+
})
|
|
120
|
+
expect(options.validRenames?.has('OldComponent')).toBe(true)
|
|
121
|
+
})
|
|
122
|
+
|
|
123
|
+
it('should ignore imports from non-targeted modules', () => {
|
|
124
|
+
const options = createTestOptions()
|
|
125
|
+
const importDeclaration = getImportDeclaration(
|
|
126
|
+
`import { OldComponent } from "some-other-library"`,
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
processImportDeclaration(importDeclaration, options)
|
|
130
|
+
|
|
131
|
+
expect(options.importsToRemove.size).toBe(0)
|
|
132
|
+
expect(options.importsToAdd.size).toBe(0)
|
|
133
|
+
expect(options.validRenames?.size).toBe(0)
|
|
134
|
+
})
|
|
135
|
+
|
|
136
|
+
it('should ignore imports not in rename map', () => {
|
|
137
|
+
const options = createTestOptions()
|
|
138
|
+
const importDeclaration = getImportDeclaration(
|
|
139
|
+
`import { SomeOtherComponent } from "@kaizen/components/v3/actions"`,
|
|
140
|
+
)
|
|
141
|
+
|
|
142
|
+
processImportDeclaration(importDeclaration, options)
|
|
143
|
+
|
|
144
|
+
expect(options.importsToRemove.size).toBe(0)
|
|
145
|
+
expect(options.importsToAdd.size).toBe(0)
|
|
146
|
+
expect(options.validRenames?.size).toBe(0)
|
|
147
|
+
})
|
|
148
|
+
|
|
149
|
+
it('should handle multiple fromModules for same component', () => {
|
|
150
|
+
const options = createTestOptions()
|
|
151
|
+
const importDeclaration1 = getImportDeclaration(
|
|
152
|
+
`import { Select } from "@kaizen/components/next"`,
|
|
153
|
+
)
|
|
154
|
+
const importDeclaration2 = getImportDeclaration(
|
|
155
|
+
`import { Select } from "@kaizen/components/future"`,
|
|
156
|
+
)
|
|
157
|
+
|
|
158
|
+
processImportDeclaration(importDeclaration1, options)
|
|
159
|
+
|
|
160
|
+
expect(options.importsToRemove.get('@kaizen/components/next')).toContain('Select')
|
|
161
|
+
expect(options.importsToAdd.get('@kaizen/components')?.get('SingleSelect')).toEqual({
|
|
162
|
+
componentName: 'SingleSelect',
|
|
163
|
+
alias: undefined,
|
|
164
|
+
isTypeOnly: false,
|
|
165
|
+
})
|
|
166
|
+
expect(options.validRenames?.has('Select')).toBe(true)
|
|
167
|
+
|
|
168
|
+
// Reset for second test
|
|
169
|
+
options.importsToRemove.clear()
|
|
170
|
+
options.importsToAdd.clear()
|
|
171
|
+
options.validRenames?.clear()
|
|
172
|
+
|
|
173
|
+
processImportDeclaration(importDeclaration2, options)
|
|
174
|
+
|
|
175
|
+
expect(options.importsToRemove.get('@kaizen/components/future')).toContain('Select')
|
|
176
|
+
expect(options.importsToAdd.get('@kaizen/components')?.get('SingleSelect')).toEqual({
|
|
177
|
+
componentName: 'SingleSelect',
|
|
178
|
+
alias: undefined,
|
|
179
|
+
isTypeOnly: false,
|
|
180
|
+
})
|
|
181
|
+
expect(options.validRenames?.has('Select')).toBe(true)
|
|
182
|
+
})
|
|
183
|
+
|
|
184
|
+
it('should handle default imports gracefully', () => {
|
|
185
|
+
const options = createTestOptions()
|
|
186
|
+
const importDeclaration = getImportDeclaration(
|
|
187
|
+
`import OldComponent from "@kaizen/components/v3/actions"`,
|
|
188
|
+
)
|
|
189
|
+
|
|
190
|
+
processImportDeclaration(importDeclaration, options)
|
|
191
|
+
|
|
192
|
+
expect(options.importsToRemove.size).toBe(0)
|
|
193
|
+
expect(options.importsToAdd.size).toBe(0)
|
|
194
|
+
expect(options.validRenames?.size).toBe(0)
|
|
195
|
+
})
|
|
196
|
+
|
|
197
|
+
it('should handle namespace imports gracefully', () => {
|
|
198
|
+
const options = createTestOptions()
|
|
199
|
+
const importDeclaration = getImportDeclaration(
|
|
200
|
+
`import * as Components from "@kaizen/components/v3/actions"`,
|
|
201
|
+
)
|
|
202
|
+
|
|
203
|
+
processImportDeclaration(importDeclaration, options)
|
|
204
|
+
|
|
205
|
+
expect(options.importsToRemove.size).toBe(0)
|
|
206
|
+
expect(options.importsToAdd.size).toBe(0)
|
|
207
|
+
expect(options.validRenames?.size).toBe(0)
|
|
208
|
+
})
|
|
209
|
+
})
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import ts from 'typescript'
|
|
2
|
+
import { setImportToAdd, setImportToRemove, type UpdateKaioImportsArgs } from './updateKaioImports'
|
|
3
|
+
|
|
4
|
+
export type ModuleRenameConfig = {
|
|
5
|
+
newName: string
|
|
6
|
+
fromModules: string[]
|
|
7
|
+
toModule: string
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export type ProcessImportOptions = {
|
|
11
|
+
importsToRemove: NonNullable<UpdateKaioImportsArgs['importsToRemove']>
|
|
12
|
+
importsToAdd: NonNullable<UpdateKaioImportsArgs['importsToAdd']>
|
|
13
|
+
renameMap: Map<string, ModuleRenameConfig>
|
|
14
|
+
validRenames?: Set<string>
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Takes an import declaration and transforms it as specified in the options.renameMap
|
|
19
|
+
*
|
|
20
|
+
* @param node - The import declaration to process
|
|
21
|
+
* @param options - Configuration for import transformations
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* ```typescript
|
|
25
|
+
* // For an import like: import { OldButton } from '@kaizen/legacy'
|
|
26
|
+
* // With renameMap: { 'OldButton': { newName: 'Button', fromModules: ['@kaizen/legacy'], toModule: '@kaizen/button' } }
|
|
27
|
+
* // Results in: import { Button } from '@kaizen/button'
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
export const processImportDeclaration = (
|
|
31
|
+
node: ts.ImportDeclaration,
|
|
32
|
+
options: ProcessImportOptions,
|
|
33
|
+
): void => {
|
|
34
|
+
const { importsToRemove, importsToAdd, renameMap, validRenames } = options
|
|
35
|
+
const moduleSpecifier = node.moduleSpecifier.getText().slice(1, -1)
|
|
36
|
+
|
|
37
|
+
const importClause = node.importClause
|
|
38
|
+
if (importClause?.namedBindings && ts.isNamedImports(importClause.namedBindings)) {
|
|
39
|
+
importClause.namedBindings.elements.forEach((importSpecifier) => {
|
|
40
|
+
const importName = importSpecifier.propertyName?.getText() ?? importSpecifier.name?.getText()
|
|
41
|
+
|
|
42
|
+
const renameConfig = renameMap.get(importName)
|
|
43
|
+
if (renameConfig?.fromModules.includes(moduleSpecifier)) {
|
|
44
|
+
validRenames?.add(importName)
|
|
45
|
+
setImportToRemove(importsToRemove, moduleSpecifier, importName)
|
|
46
|
+
|
|
47
|
+
const alias = importSpecifier.propertyName?.getText()
|
|
48
|
+
? importSpecifier.name?.getText()
|
|
49
|
+
: undefined
|
|
50
|
+
|
|
51
|
+
setImportToAdd(importsToAdd, renameConfig.toModule, {
|
|
52
|
+
componentName: renameConfig.newName,
|
|
53
|
+
alias,
|
|
54
|
+
isTypeOnly: importSpecifier.isTypeOnly || importClause.isTypeOnly,
|
|
55
|
+
})
|
|
56
|
+
}
|
|
57
|
+
})
|
|
58
|
+
}
|
|
59
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { ModuleRenameConfig } from './createModulePathTransformer'
|
|
2
|
+
|
|
3
|
+
export type ComponentEntry = string | [string, string] // [oldName, newName]
|
|
4
|
+
|
|
5
|
+
export type ComponentGroup = {
|
|
6
|
+
components: ComponentEntry[]
|
|
7
|
+
fromModules: string[]
|
|
8
|
+
toModule: string
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export const createRenameMapFromGroups = (
|
|
12
|
+
groups: ComponentGroup[],
|
|
13
|
+
): Map<string, ModuleRenameConfig> => {
|
|
14
|
+
const renameMap = new Map<string, ModuleRenameConfig>()
|
|
15
|
+
|
|
16
|
+
groups.forEach(({ components, fromModules, toModule }) => {
|
|
17
|
+
components.forEach((componentEntry) => {
|
|
18
|
+
const [oldName, newName] = Array.isArray(componentEntry)
|
|
19
|
+
? componentEntry
|
|
20
|
+
: [componentEntry, componentEntry]
|
|
21
|
+
|
|
22
|
+
renameMap.set(oldName, {
|
|
23
|
+
newName,
|
|
24
|
+
fromModules,
|
|
25
|
+
toModule,
|
|
26
|
+
})
|
|
27
|
+
})
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
return renameMap
|
|
31
|
+
}
|
package/codemods/utils/index.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export * from './createJsxElementWithChildren'
|
|
2
2
|
export * from './createProp'
|
|
3
|
+
export * from './createRenameMapFromGroups'
|
|
3
4
|
export * from './getPropValueText'
|
|
4
5
|
export * from './getKaioTagName'
|
|
5
6
|
export * from './migrateStringProp'
|
|
@@ -10,3 +11,4 @@ export * from './updateKaioImports'
|
|
|
10
11
|
export * from './updateJsxElementWithNewProps'
|
|
11
12
|
export * from './transformV1ButtonPropsToButtonOrLinkButton'
|
|
12
13
|
export * from './updateJsxElementTagName'
|
|
14
|
+
export * from './createModulePathTransformer'
|