@instructure/ui-codemods 10.20.2-snapshot-11 → 10.20.2-snapshot-13
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/CHANGELOG.md +1 -1
- package/README.md +5 -87
- package/lib/__node_tests__/codemodHelpers.test.tsx +455 -0
- package/lib/__node_tests__/{updateV10Breaking.test.ts → codemods.test.ts} +3 -3
- package/lib/__node_tests__/{testHelpers.ts → runTest.ts} +1 -3
- package/lib/index.ts +1 -16
- package/lib/{utils → instui-codemods}/updateToV10Colors.ts +6 -7
- package/lib/updateV10Breaking.ts +12 -26
- package/lib/{helpers → utils}/codemodHelpers.ts +153 -164
- package/lib/utils/codemodTypeCheckers.ts +221 -0
- package/lib/utils/instUICodemodExecutor.ts +89 -0
- package/package.json +2 -2
- package/tsconfig.build.tsbuildinfo +1 -1
- package/lib/helpers/replaceDeprecatedImports.ts +0 -546
- package/lib/helpers/replaceDeprecatedProps.ts +0 -230
- package/lib/updateImports.ts +0 -86
- package/lib/updatePropNames.ts +0 -66
- package/lib/updateV7Props.ts +0 -101
- package/lib/updateV8Breaking.ts +0 -49
- package/lib/updateV8ReactDOM.ts +0 -61
- package/lib/updateV9Breaking.ts +0 -54
- package/lib/utils/UpdateV7ButtonsLink.ts +0 -139
- package/lib/utils/requireUncached.ts +0 -28
- package/lib/utils/updateToV8Theming.ts +0 -84
- package/lib/utils/updateToV9Theming.ts +0 -70
- package/lib/utils/updateV7ButtonsClose.ts +0 -104
- package/lib/utils/updateV7ButtonsIconCircle.ts +0 -240
- package/lib/utils/updateV7ButtonsMisc.ts +0 -137
- package/lib/utils/updateV7ButtonsWithText.ts +0 -111
- package/lib/utils/updateV7FocusableView.ts +0 -105
- package/lib/utils/updateV7Heading.ts +0 -145
- package/lib/utils/updateV7Lists.ts +0 -113
- package/lib/utils/updateV7Pill.ts +0 -83
- package/lib/utils/updateV7Popover.ts +0 -133
- package/lib/utils/updateV7Tabs.ts +0 -129
- package/lib/utils/updateV8RenderProp.ts +0 -142
- package/lib/utils/updateV8ThemeProp.ts +0 -51
- package/lib/utils/warnV7ComponentDeprecations.ts +0 -96
package/CHANGELOG.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
-
## [10.20.2-snapshot-
|
|
6
|
+
## [10.20.2-snapshot-13](https://github.com/instructure/instructure-ui/compare/v10.20.1...v10.20.2-snapshot-13) (2025-06-26)
|
|
7
7
|
|
|
8
8
|
**Note:** Version bump only for package @instructure/ui-codemods
|
|
9
9
|
|
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@ category: packages
|
|
|
4
4
|
|
|
5
5
|
## ui-codemods
|
|
6
6
|
|
|
7
|
-
The ui-codemods package should make it easier to deal with API changes when upgrading Instructure UI libraries.
|
|
7
|
+
The `ui-codemods` package should make it easier to deal with API changes when upgrading Instructure UI libraries.
|
|
8
8
|
|
|
9
9
|
[![npm][npm]][npm-url]
|
|
10
10
|
[![MIT License][license-badge]][license]
|
|
@@ -18,102 +18,20 @@ The codemod scripts can be installed via the following command:
|
|
|
18
18
|
---
|
|
19
19
|
type: code
|
|
20
20
|
---
|
|
21
|
-
|
|
21
|
+
# use here the InstUI version number you are upgrading to
|
|
22
|
+
npm install @instructure/ui-codemods@10
|
|
22
23
|
```
|
|
23
24
|
|
|
24
|
-
The configuration files are located in the [instui-config](#instui-config) package.
|
|
25
|
-
This can be installed via the following command:
|
|
26
|
-
|
|
27
|
-
```sh
|
|
28
|
-
---
|
|
29
|
-
type: code
|
|
30
|
-
---
|
|
31
|
-
npm install @instructure/instui-config
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
### Updating Deprecated Props
|
|
35
|
-
|
|
36
|
-
This codemod helps you update your project by renaming `props` that have had names changed (e.g., `onReady` => `onOpen`).
|
|
37
|
-
|
|
38
|
-
```sh
|
|
39
|
-
---
|
|
40
|
-
type: code
|
|
41
|
-
---
|
|
42
|
-
jscodeshift -t node_modules/@instructure/ui-codemods/lib/updatePropNames.ts <path> --config=node_modules/@instructure/instui-config/codemod-configs/v<version number ex. 5 or 6>/propNames.config.json
|
|
43
|
-
```
|
|
44
|
-
|
|
45
|
-
### Updating Package Imports
|
|
46
|
-
|
|
47
|
-
This codemod helps you update your project by renaming `imports` that have changed (e.g., `instructure-ui` => `@instructure/<package name>`).
|
|
48
|
-
|
|
49
|
-
```sh
|
|
50
|
-
---
|
|
51
|
-
type: code
|
|
52
|
-
---
|
|
53
|
-
jscodeshift -t node_modules/@instructure/ui-codemods/lib/updateImports.ts <path> --config=node_modules/@instructure/instui-config/codemod-configs/v<version number ex. 5 or 6>/imports.config.js
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
### Updating more complex props to the InstUI v8 syntax
|
|
57
|
-
|
|
58
|
-
This codemod upgrades more complex changes like Button, also outputs any manual changes needed to the console. Run this in a InstUI v7 codebase only. This command has an optional fileName parameter, supplying this will append to the given file the warnings.
|
|
59
|
-
|
|
60
|
-
```sh
|
|
61
|
-
---
|
|
62
|
-
type: code
|
|
63
|
-
---
|
|
64
|
-
jscodeshift -t node_modules/@instructure/ui-codemods/lib/updateV7Props.ts <path> -fileName updateV7PropsWarnings.txt
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
### Codemod for breaking changes after updating the dependencies to V8
|
|
68
|
-
|
|
69
|
-
```sh
|
|
70
|
-
---
|
|
71
|
-
type: code
|
|
72
|
-
---
|
|
73
|
-
jscodeshift -t node_modules/@instructure/ui-codemods/lib/updateV8Breaking.ts <path>
|
|
74
|
-
```
|
|
75
|
-
|
|
76
|
-
This codemod updates breaking changes after a v8 upgrade. Run this in a project after you have upgraded your dependencies to InstUI v8.
|
|
77
|
-
|
|
78
|
-
### Codemod for breaking changes after updating the dependencies to V9
|
|
79
|
-
|
|
80
|
-
```sh
|
|
81
|
-
---
|
|
82
|
-
type: code
|
|
83
|
-
---
|
|
84
|
-
jscodeshift -t node_modules/@instructure/ui-codemods/lib/updateV9Breaking.ts <path> --parser=tsx --usePrettier=false
|
|
85
|
-
```
|
|
86
|
-
|
|
87
|
-
This codemod addresses breaking changes following a v9 upgrade. Notably, it updates `EmotionThemeProvider` to `InstUISettingsProvider`. Execute this in your project post-upgrade to InstUI v9. Prettier is turned on by default for output formatting, and you can also use the `usePrettier` flag. Additionally, the parser flag can specify the parser for jsx and tsx files.
|
|
88
|
-
|
|
89
25
|
### Codemod for changing the color palette to the v10 color palette
|
|
90
26
|
|
|
91
27
|
```sh
|
|
92
28
|
---
|
|
93
29
|
type: code
|
|
94
30
|
---
|
|
95
|
-
jscodeshift -t node_modules/@instructure/ui-codemods/lib/updateV10Breaking.ts <path> --
|
|
96
|
-
```
|
|
97
|
-
|
|
98
|
-
This codemod updates the `canvas` and `canvas-high-contrast` color palettes. Execute this in your project post-upgrade to InstUI v10. Prettier is turned on by default for output formatting, and you can also use the `usePrettier` flag. Additionally, the parser flag can specify the parser for jsx and tsx files.
|
|
99
|
-
|
|
100
|
-
### Codemod for adding a wrapper to ReactDOM.render()
|
|
101
|
-
|
|
102
|
-
```sh
|
|
103
|
-
---
|
|
104
|
-
type: code
|
|
105
|
-
---
|
|
106
|
-
jscodeshift -t node_modules/@instructure/ui-codemods/lib/updateV8ReactDOM.ts <path> -fileName updateV8ReactDOM.txt
|
|
31
|
+
npx jscodeshift@17.3.0 -t node_modules/@instructure/ui-codemods/lib/updateV10Breaking.ts <path> --usePrettier=false
|
|
107
32
|
```
|
|
108
33
|
|
|
109
|
-
This codemod updates
|
|
110
|
-
ReactDOM.render(<div />) -> ReactDOM.render(<Root><div /></Root>).
|
|
111
|
-
Parameters (all optional):
|
|
112
|
-
|
|
113
|
-
- `fileName`: supplying this will append to the given file the warnings.
|
|
114
|
-
- `wrapperPath`: The import path for the wrapper, default value is '@canvas/react-root'.
|
|
115
|
-
- `wrapperTag`: The tag to wrap render calls in, default is 'Root'.
|
|
116
|
-
- `isDefaultImport`: Is the given tag a default import? Default value is `true`.
|
|
34
|
+
This codemod updates the `canvas` and `canvas-high-contrast` color palettes. Execute this in your project post-upgrade to InstUI v10. Prettier is turned on by default for output formatting, and you can also use the `usePrettier` flag.
|
|
117
35
|
|
|
118
36
|
[npm]: https://img.shields.io/npm/v/@instructure/ui-codemods.svg
|
|
119
37
|
[npm-url]: https://npmjs.com/package/@instructure/ui-codemods
|
|
@@ -0,0 +1,455 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* The MIT License (MIT)
|
|
3
|
+
*
|
|
4
|
+
* Copyright (c) 2015 - present Instructure, Inc.
|
|
5
|
+
*
|
|
6
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
7
|
+
* of this software and associated documentation files (the "Software"), to deal
|
|
8
|
+
* in the Software without restriction, including without limitation the rights
|
|
9
|
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
10
|
+
* copies of the Software, and to permit persons to whom the Software is
|
|
11
|
+
* furnished to do so, subject to the following conditions:
|
|
12
|
+
*
|
|
13
|
+
* The above copyright notice and this permission notice shall be included in all
|
|
14
|
+
* copies or substantial portions of the Software.
|
|
15
|
+
*
|
|
16
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
17
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
18
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
19
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
20
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
21
|
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
22
|
+
* SOFTWARE.
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
import j from 'jscodeshift'
|
|
26
|
+
import {
|
|
27
|
+
findAttribute,
|
|
28
|
+
getVisibleChildren,
|
|
29
|
+
renameElements,
|
|
30
|
+
findImport,
|
|
31
|
+
findEveryImport,
|
|
32
|
+
addImportIfNeeded,
|
|
33
|
+
replaceImport,
|
|
34
|
+
removeAllChildren
|
|
35
|
+
} from '../utils/codemodHelpers'
|
|
36
|
+
import { expect } from 'vitest'
|
|
37
|
+
|
|
38
|
+
describe('test codemod helpers', () => {
|
|
39
|
+
it('test findAttribute', () => {
|
|
40
|
+
const data = j(
|
|
41
|
+
`<>
|
|
42
|
+
<button id='1234' aloneAttr>asd</button>
|
|
43
|
+
<button test={false}>asd</button>
|
|
44
|
+
<test id={asd.gfd}>asd</test>
|
|
45
|
+
<div {...{id:5}} />
|
|
46
|
+
</>`
|
|
47
|
+
)
|
|
48
|
+
const r = findAttribute('', j, data, 'id')
|
|
49
|
+
expect(j(r.paths()).toSource()).toEqual(["id='1234'", 'id={asd.gfd}'])
|
|
50
|
+
|
|
51
|
+
const r2 = findAttribute('', j, data, 'id', '1234')
|
|
52
|
+
expect(j(r2.paths()).toSource()).toEqual("id='1234'")
|
|
53
|
+
|
|
54
|
+
const r3 = findAttribute('', j, data, 'aloneAttr')
|
|
55
|
+
expect(j(r3.paths()).toSource()).toEqual('aloneAttr')
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
it('test getVisibleChildren', () => {
|
|
59
|
+
const data = j(
|
|
60
|
+
`<button>
|
|
61
|
+
|
|
62
|
+
<button id='1234' aloneAttr>asd</button>
|
|
63
|
+
|
|
64
|
+
</button>`
|
|
65
|
+
)
|
|
66
|
+
const r = getVisibleChildren(
|
|
67
|
+
data.paths()[0].value.program.body[0].expression.children
|
|
68
|
+
)
|
|
69
|
+
expect(j(r).toSource()).toEqual("<button id='1234' aloneAttr>asd</button>")
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
it('test renameElements', () => {
|
|
73
|
+
// Test simple tag renaming
|
|
74
|
+
const simpleSource = `<Button id="test">Click me</Button>`
|
|
75
|
+
let root = j(simpleSource)
|
|
76
|
+
const buttonElements = root.find(j.JSXElement, {
|
|
77
|
+
openingElement: {
|
|
78
|
+
name: {
|
|
79
|
+
type: 'JSXIdentifier',
|
|
80
|
+
name: 'Button'
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
})
|
|
84
|
+
renameElements('test.js', buttonElements, 'Button', 'PrimaryButton')
|
|
85
|
+
expect(root.toSource()).toEqual(
|
|
86
|
+
`<PrimaryButton id="test">Click me</PrimaryButton>`
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
// Test self-closing tag renaming
|
|
90
|
+
const selfClosingSource = `<Icon size="small" />`
|
|
91
|
+
root = j(selfClosingSource)
|
|
92
|
+
const iconElements = root.find(j.JSXElement, {
|
|
93
|
+
openingElement: {
|
|
94
|
+
name: {
|
|
95
|
+
type: 'JSXIdentifier',
|
|
96
|
+
name: 'Icon'
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
})
|
|
100
|
+
renameElements('test.js', iconElements, 'Icon', 'SVGIcon')
|
|
101
|
+
expect(root.toSource()).toEqual(`<SVGIcon size="small" />`)
|
|
102
|
+
|
|
103
|
+
// Test compound tag renaming
|
|
104
|
+
const compoundSource = `<Component.SubItem active={true}>Child</Component.SubItem>`
|
|
105
|
+
root = j(compoundSource)
|
|
106
|
+
const compoundElements = root.find(j.JSXElement, {
|
|
107
|
+
openingElement: {
|
|
108
|
+
name: {
|
|
109
|
+
type: 'JSXMemberExpression',
|
|
110
|
+
object: {
|
|
111
|
+
name: 'Component'
|
|
112
|
+
},
|
|
113
|
+
property: {
|
|
114
|
+
name: 'SubItem'
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
})
|
|
119
|
+
renameElements(
|
|
120
|
+
'test.js',
|
|
121
|
+
compoundElements,
|
|
122
|
+
'Component.SubItem',
|
|
123
|
+
'NewComponent.ListItem'
|
|
124
|
+
)
|
|
125
|
+
expect(root.toSource()).toEqual(
|
|
126
|
+
`<NewComponent.ListItem active={true}>Child</NewComponent.ListItem>`
|
|
127
|
+
)
|
|
128
|
+
})
|
|
129
|
+
|
|
130
|
+
it('test findImport', () => {
|
|
131
|
+
// Test standard named import
|
|
132
|
+
const source = `
|
|
133
|
+
import { Button } from '@instructure/ui-buttons'
|
|
134
|
+
import { Text } from '@instructure/ui-text'
|
|
135
|
+
import React from 'react'
|
|
136
|
+
`
|
|
137
|
+
let root = j(source)
|
|
138
|
+
|
|
139
|
+
// Find existing import
|
|
140
|
+
let result = findImport(j, root, 'Button', '@instructure/ui-buttons')
|
|
141
|
+
expect(result).toEqual('Button')
|
|
142
|
+
|
|
143
|
+
// Find import with multiple possible paths
|
|
144
|
+
result = findImport(j, root, 'Button', [
|
|
145
|
+
'@instructure/ui-something',
|
|
146
|
+
'@instructure/ui-buttons'
|
|
147
|
+
])
|
|
148
|
+
expect(result).toEqual('Button')
|
|
149
|
+
|
|
150
|
+
// Not existing import
|
|
151
|
+
result = findImport(j, root, 'Modal', '@instructure/ui-buttons')
|
|
152
|
+
expect(result).toBeUndefined()
|
|
153
|
+
|
|
154
|
+
// Import from wrong path
|
|
155
|
+
result = findImport(j, root, 'Button', '@instructure/ui-wrong')
|
|
156
|
+
expect(result).toBeUndefined()
|
|
157
|
+
|
|
158
|
+
// Test aliased import
|
|
159
|
+
const aliasedSource = `
|
|
160
|
+
import { Button as PrimaryButton } from '@instructure/ui-buttons'
|
|
161
|
+
import { Text } from '@instructure/ui-text'
|
|
162
|
+
`
|
|
163
|
+
root = j(aliasedSource)
|
|
164
|
+
result = findImport(j, root, 'Button', '@instructure/ui-buttons')
|
|
165
|
+
expect(result).toEqual('PrimaryButton')
|
|
166
|
+
|
|
167
|
+
// Test default import
|
|
168
|
+
const defaultImportSource = `
|
|
169
|
+
import DefaultButton from '@instructure/ui-buttons'
|
|
170
|
+
import { Text } from '@instructure/ui-text'
|
|
171
|
+
`
|
|
172
|
+
root = j(defaultImportSource)
|
|
173
|
+
result = findImport(j, root, 'DefaultButton', '@instructure/ui-buttons')
|
|
174
|
+
expect(result).toEqual('DefaultButton')
|
|
175
|
+
})
|
|
176
|
+
|
|
177
|
+
it('test findEveryImport', () => {
|
|
178
|
+
// Test with exactMatch = true (default)
|
|
179
|
+
const source = `
|
|
180
|
+
import { Button, IconButton } from '@instructure/ui-buttons'
|
|
181
|
+
import { Text, Heading } from '@instructure/ui-text'
|
|
182
|
+
import React from 'react'
|
|
183
|
+
import { Modal as Dialog } from '@instructure/ui-modal'
|
|
184
|
+
import DefaultIcon from '@instructure/ui-icons'
|
|
185
|
+
`
|
|
186
|
+
const root = j(source)
|
|
187
|
+
|
|
188
|
+
// Find imports from exact path
|
|
189
|
+
let result = findEveryImport(j, root, '@instructure/ui-buttons')
|
|
190
|
+
expect(result.sort()).toEqual(['Button', 'IconButton'])
|
|
191
|
+
|
|
192
|
+
// Renamed imports should return the local name
|
|
193
|
+
result = findEveryImport(j, root, '@instructure/ui-modal')
|
|
194
|
+
expect(result).toEqual(['Dialog'])
|
|
195
|
+
|
|
196
|
+
// Default imports should be included
|
|
197
|
+
result = findEveryImport(j, root, '@instructure/ui-icons')
|
|
198
|
+
expect(result).toEqual(['DefaultIcon'])
|
|
199
|
+
|
|
200
|
+
// No imports from a specific path
|
|
201
|
+
result = findEveryImport(j, root, '@instructure/ui-missing')
|
|
202
|
+
expect(result).toEqual([])
|
|
203
|
+
|
|
204
|
+
// Test with exactMatch = false
|
|
205
|
+
result = findEveryImport(j, root, '@instructure/ui', false)
|
|
206
|
+
expect(result.sort()).toEqual([
|
|
207
|
+
'Button',
|
|
208
|
+
'DefaultIcon',
|
|
209
|
+
'Dialog',
|
|
210
|
+
'Heading',
|
|
211
|
+
'IconButton',
|
|
212
|
+
'Text'
|
|
213
|
+
])
|
|
214
|
+
|
|
215
|
+
// Test with partial path that doesn't match
|
|
216
|
+
result = findEveryImport(j, root, 'non-existent', false)
|
|
217
|
+
expect(result).toEqual([])
|
|
218
|
+
})
|
|
219
|
+
|
|
220
|
+
it('test addImportIfNeeded', () => {
|
|
221
|
+
// Test adding a new import when no imports from the path exist
|
|
222
|
+
const source = `import { Button } from '@instructure/ui-buttons'
|
|
223
|
+
import React from 'react'`
|
|
224
|
+
let root = j(source)
|
|
225
|
+
|
|
226
|
+
// Add new import from a new path
|
|
227
|
+
let result = addImportIfNeeded(j, root, 'Modal', '@instructure/ui-modal')
|
|
228
|
+
expect(result).toEqual('Modal')
|
|
229
|
+
expect(root.toSource())
|
|
230
|
+
.toEqual(`import { Button } from '@instructure/ui-buttons'
|
|
231
|
+
import React from 'react'
|
|
232
|
+
import { Modal } from "@instructure/ui-modal";`)
|
|
233
|
+
|
|
234
|
+
// Test adding to existing import statement
|
|
235
|
+
root = j(source)
|
|
236
|
+
result = addImportIfNeeded(j, root, 'IconButton', '@instructure/ui-buttons')
|
|
237
|
+
expect(result).toEqual('IconButton')
|
|
238
|
+
expect(root.toSource()).toContain(
|
|
239
|
+
"import { Button, IconButton } from '@instructure/ui-buttons'"
|
|
240
|
+
)
|
|
241
|
+
|
|
242
|
+
// Test adding a default import
|
|
243
|
+
root = j(source)
|
|
244
|
+
result = addImportIfNeeded(
|
|
245
|
+
j,
|
|
246
|
+
root,
|
|
247
|
+
'DefaultIcon',
|
|
248
|
+
'@instructure/ui-icons',
|
|
249
|
+
true
|
|
250
|
+
)
|
|
251
|
+
expect(result).toEqual('DefaultIcon')
|
|
252
|
+
expect(root.toSource()).toContain(
|
|
253
|
+
`import DefaultIcon from "@instructure/ui-icons"`
|
|
254
|
+
)
|
|
255
|
+
|
|
256
|
+
// Test not adding an import when it already exists
|
|
257
|
+
root = j(`
|
|
258
|
+
import { Button, IconButton } from '@instructure/ui-buttons'
|
|
259
|
+
import React from 'react'
|
|
260
|
+
`)
|
|
261
|
+
result = addImportIfNeeded(j, root, 'Button', '@instructure/ui-buttons')
|
|
262
|
+
expect(result).toEqual('Button')
|
|
263
|
+
expect(root.toSource()).toEqual(`
|
|
264
|
+
import { Button, IconButton } from '@instructure/ui-buttons'
|
|
265
|
+
import React from 'react'
|
|
266
|
+
`)
|
|
267
|
+
|
|
268
|
+
// Test with multiple possible paths
|
|
269
|
+
root = j(source)
|
|
270
|
+
result = addImportIfNeeded(j, root, 'Text', [
|
|
271
|
+
'@instructure/ui-text',
|
|
272
|
+
'@instructure/ui-components'
|
|
273
|
+
])
|
|
274
|
+
expect(result).toEqual('Text')
|
|
275
|
+
expect(root.toSource()).toContain(
|
|
276
|
+
`import { Text } from "@instructure/ui-text"`
|
|
277
|
+
)
|
|
278
|
+
|
|
279
|
+
root = j(source)
|
|
280
|
+
result = addImportIfNeeded(j, root, 'Text', [
|
|
281
|
+
'@instructure/ui-text',
|
|
282
|
+
'@instructure/ui-buttons'
|
|
283
|
+
])
|
|
284
|
+
expect(result).toEqual('Text')
|
|
285
|
+
expect(root.toSource()).toContain(
|
|
286
|
+
`import { Button, Text } from '@instructure/ui-buttons'`
|
|
287
|
+
)
|
|
288
|
+
// Test with aliased import
|
|
289
|
+
const aliasedSource = `
|
|
290
|
+
import { Button as PrimaryButton } from '@instructure/ui-buttons'
|
|
291
|
+
import React from 'react'
|
|
292
|
+
`
|
|
293
|
+
root = j(aliasedSource)
|
|
294
|
+
result = addImportIfNeeded(j, root, 'Button', '@instructure/ui-buttons')
|
|
295
|
+
expect(result).toEqual('PrimaryButton')
|
|
296
|
+
// No new import should be added since it exists as an alias
|
|
297
|
+
expect(root.toSource())
|
|
298
|
+
.toContain(`import { Button as PrimaryButton } from '@instructure/ui-buttons'
|
|
299
|
+
import React from 'react'`)
|
|
300
|
+
})
|
|
301
|
+
|
|
302
|
+
it('test replaceImport', () => {
|
|
303
|
+
// Test replacing a named import
|
|
304
|
+
const source = `
|
|
305
|
+
import { Button, IconButton } from '@instructure/ui-buttons'
|
|
306
|
+
import { Text } from '@instructure/ui-text'
|
|
307
|
+
import React from 'react'
|
|
308
|
+
`
|
|
309
|
+
let root = j(source)
|
|
310
|
+
|
|
311
|
+
// Replace a simple named import
|
|
312
|
+
let result = replaceImport(
|
|
313
|
+
j,
|
|
314
|
+
root,
|
|
315
|
+
'Button',
|
|
316
|
+
'PrimaryButton',
|
|
317
|
+
'@instructure/ui-buttons'
|
|
318
|
+
)
|
|
319
|
+
expect(result).toEqual('PrimaryButton')
|
|
320
|
+
expect(root.toSource()).toContain(
|
|
321
|
+
"import { PrimaryButton, IconButton } from '@instructure/ui-buttons'"
|
|
322
|
+
)
|
|
323
|
+
expect(root.toSource()).not.toContain(' Button')
|
|
324
|
+
|
|
325
|
+
// Test replacing only matches the correct path
|
|
326
|
+
root = j(source)
|
|
327
|
+
result = replaceImport(
|
|
328
|
+
j,
|
|
329
|
+
root,
|
|
330
|
+
'Text',
|
|
331
|
+
'Typography',
|
|
332
|
+
'@instructure/ui-text'
|
|
333
|
+
)
|
|
334
|
+
expect(result).toEqual('Typography')
|
|
335
|
+
expect(root.toSource()).toEqual(`
|
|
336
|
+
import { Button, IconButton } from '@instructure/ui-buttons'
|
|
337
|
+
import { Typography } from '@instructure/ui-text'
|
|
338
|
+
import React from 'react'
|
|
339
|
+
`)
|
|
340
|
+
|
|
341
|
+
// Test replacing with multiple possible paths
|
|
342
|
+
root = j(source)
|
|
343
|
+
result = replaceImport(j, root, 'Text', 'Typography', [
|
|
344
|
+
'@instructure/ui-something',
|
|
345
|
+
'@instructure/ui-text'
|
|
346
|
+
])
|
|
347
|
+
expect(result).toEqual('Typography')
|
|
348
|
+
expect(root.toSource()).toContain(
|
|
349
|
+
"import { Typography } from '@instructure/ui-text'"
|
|
350
|
+
)
|
|
351
|
+
|
|
352
|
+
// Test replacing a default import
|
|
353
|
+
const defaultImportSource = `
|
|
354
|
+
import DefaultButton, { UglyButton } from '@instructure/ui-buttons'
|
|
355
|
+
import { Text } from '@instructure/ui-text'
|
|
356
|
+
`
|
|
357
|
+
root = j(defaultImportSource)
|
|
358
|
+
result = replaceImport(
|
|
359
|
+
j,
|
|
360
|
+
root,
|
|
361
|
+
'DefaultButton',
|
|
362
|
+
'PrimaryButton',
|
|
363
|
+
'@instructure/ui-buttons',
|
|
364
|
+
true
|
|
365
|
+
)
|
|
366
|
+
expect(result).toEqual('PrimaryButton')
|
|
367
|
+
expect(root.toSource()).toEqual(`
|
|
368
|
+
import PrimaryButton, { UglyButton } from '@instructure/ui-buttons'
|
|
369
|
+
import { Text } from '@instructure/ui-text'
|
|
370
|
+
`)
|
|
371
|
+
|
|
372
|
+
// Test replacing non-existent import (should not modify the source)
|
|
373
|
+
const originalSource = `import { Button } from '@instructure/ui-buttons'`
|
|
374
|
+
root = j(originalSource)
|
|
375
|
+
result = replaceImport(j, root, 'Modal', 'Dialog', '@instructure/ui-modal')
|
|
376
|
+
expect(result).toEqual('Dialog')
|
|
377
|
+
expect(root.toSource()).toEqual(originalSource) // Source should be unchanged
|
|
378
|
+
})
|
|
379
|
+
|
|
380
|
+
it('test removeAllChildren', () => {
|
|
381
|
+
// Test removing children from a standard element
|
|
382
|
+
const source = `<Container><Child>Text content</Child><AnotherChild /></Container>`
|
|
383
|
+
let root = j(source)
|
|
384
|
+
const containerElements = root.find(j.JSXElement, {
|
|
385
|
+
openingElement: {
|
|
386
|
+
name: {
|
|
387
|
+
type: 'JSXIdentifier',
|
|
388
|
+
name: 'Container'
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
})
|
|
392
|
+
|
|
393
|
+
// Apply removeAllChildren to the Container element
|
|
394
|
+
removeAllChildren(containerElements.nodes()[0])
|
|
395
|
+
expect(root.toSource()).toEqual(`<Container />`)
|
|
396
|
+
|
|
397
|
+
// Test removing children from a nested element structure
|
|
398
|
+
const nestedSource = `
|
|
399
|
+
<Wrapper>
|
|
400
|
+
<Container>
|
|
401
|
+
<Child>Text content</Child>
|
|
402
|
+
<AnotherChild />
|
|
403
|
+
</Container>
|
|
404
|
+
</Wrapper>
|
|
405
|
+
`
|
|
406
|
+
root = j(nestedSource)
|
|
407
|
+
const innerContainers = root.find(j.JSXElement, {
|
|
408
|
+
openingElement: {
|
|
409
|
+
name: {
|
|
410
|
+
type: 'JSXIdentifier',
|
|
411
|
+
name: 'Container'
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
})
|
|
415
|
+
|
|
416
|
+
removeAllChildren(innerContainers.nodes()[0])
|
|
417
|
+
expect(root.toSource()).toEqual(`
|
|
418
|
+
<Wrapper>
|
|
419
|
+
<Container />
|
|
420
|
+
</Wrapper>
|
|
421
|
+
`)
|
|
422
|
+
|
|
423
|
+
// Test with an element that already has no children (self-closing)
|
|
424
|
+
const selfClosingSource = `<EmptyElement />`
|
|
425
|
+
root = j(selfClosingSource)
|
|
426
|
+
const emptyElements = root.find(j.JSXElement, {
|
|
427
|
+
openingElement: {
|
|
428
|
+
name: {
|
|
429
|
+
type: 'JSXIdentifier',
|
|
430
|
+
name: 'EmptyElement'
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
})
|
|
434
|
+
|
|
435
|
+
removeAllChildren(emptyElements.nodes()[0])
|
|
436
|
+
expect(root.toSource()).toEqual(`<EmptyElement />`)
|
|
437
|
+
|
|
438
|
+
// Test with an element that has attributes
|
|
439
|
+
const attributeSource = `<Button id="test" onClick={handleClick}>Click me</Button>`
|
|
440
|
+
root = j(attributeSource)
|
|
441
|
+
const buttonElements = root.find(j.JSXElement, {
|
|
442
|
+
openingElement: {
|
|
443
|
+
name: {
|
|
444
|
+
type: 'JSXIdentifier',
|
|
445
|
+
name: 'Button'
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
})
|
|
449
|
+
|
|
450
|
+
removeAllChildren(buttonElements.nodes()[0])
|
|
451
|
+
expect(root.toSource()).toEqual(
|
|
452
|
+
`<Button id="test" onClick={handleClick} />`
|
|
453
|
+
)
|
|
454
|
+
})
|
|
455
|
+
})
|
|
@@ -22,11 +22,11 @@
|
|
|
22
22
|
* SOFTWARE.
|
|
23
23
|
*/
|
|
24
24
|
|
|
25
|
-
import { runTest } from './
|
|
25
|
+
import { runTest } from './runTest'
|
|
26
26
|
import updateV10Breaking from '../updateV10Breaking'
|
|
27
27
|
|
|
28
|
-
describe('
|
|
29
|
-
it('test color codemods', () => {
|
|
28
|
+
describe('test codemods', () => {
|
|
29
|
+
it('test InstUI v10 color codemods', () => {
|
|
30
30
|
runTest(updateV10Breaking)
|
|
31
31
|
})
|
|
32
32
|
})
|
|
@@ -63,9 +63,7 @@ export function runTest(codemod: Transform) {
|
|
|
63
63
|
// based on the file's extension.
|
|
64
64
|
// Also, this is closer to how its used, there is always a correct
|
|
65
65
|
// filename
|
|
66
|
-
runInlineTest(codemod, {}, { path: inputPath, source: input }, expected
|
|
67
|
-
parser: 'tsx'
|
|
68
|
-
})
|
|
66
|
+
runInlineTest(codemod, {}, { path: inputPath, source: input }, expected)
|
|
69
67
|
fixturesRun++
|
|
70
68
|
}
|
|
71
69
|
})
|
package/lib/index.ts
CHANGED
|
@@ -22,21 +22,6 @@
|
|
|
22
22
|
* SOFTWARE.
|
|
23
23
|
*/
|
|
24
24
|
|
|
25
|
-
import updatePropNames from './updatePropNames'
|
|
26
|
-
import updateImports from './updateImports'
|
|
27
|
-
import updateV7Props from './updateV7Props'
|
|
28
|
-
import updateV8Breaking from './updateV8Breaking'
|
|
29
|
-
import UpdateV8ReactDOM from './updateV8ReactDOM'
|
|
30
|
-
import updateV9Breaking from './updateV9Breaking'
|
|
31
25
|
import updateV10Breaking from './updateV10Breaking'
|
|
32
26
|
|
|
33
|
-
export {
|
|
34
|
-
updatePropNames,
|
|
35
|
-
updateImports,
|
|
36
|
-
updateV7Props,
|
|
37
|
-
updateV8Breaking,
|
|
38
|
-
UpdateV8ReactDOM,
|
|
39
|
-
updateV9Breaking,
|
|
40
|
-
updateV10Breaking
|
|
41
|
-
}
|
|
42
|
-
export default updatePropNames
|
|
27
|
+
export { updateV10Breaking }
|
|
@@ -23,11 +23,8 @@
|
|
|
23
23
|
*/
|
|
24
24
|
|
|
25
25
|
import { Collection, JSCodeshift } from 'jscodeshift'
|
|
26
|
-
import {
|
|
27
|
-
|
|
28
|
-
isIdentifier,
|
|
29
|
-
isMemberExpression
|
|
30
|
-
} from '../helpers/codemodHelpers'
|
|
26
|
+
import { findImport } from '../utils/codemodHelpers'
|
|
27
|
+
import { isIdentifier, isMemberExpression } from '../utils/codemodTypeCheckers'
|
|
31
28
|
|
|
32
29
|
const colorMapping: { [index: string]: string } = {
|
|
33
30
|
brand: 'blue4570',
|
|
@@ -77,9 +74,11 @@ export function updateToV10Colors(
|
|
|
77
74
|
astNode.property.name = colorMapping[astNode.property.name]
|
|
78
75
|
}
|
|
79
76
|
})
|
|
80
|
-
if(!hasModifications) {
|
|
77
|
+
if (!hasModifications) {
|
|
81
78
|
// eslint-disable-next-line no-console
|
|
82
|
-
console.log(
|
|
79
|
+
console.log(
|
|
80
|
+
'Warning: ' + _filePath + ' might need manual replacement of colors'
|
|
81
|
+
)
|
|
83
82
|
}
|
|
84
83
|
}
|
|
85
84
|
return hasModifications
|