@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.
Files changed (38) hide show
  1. package/CHANGELOG.md +1 -1
  2. package/README.md +5 -87
  3. package/lib/__node_tests__/codemodHelpers.test.tsx +455 -0
  4. package/lib/__node_tests__/{updateV10Breaking.test.ts → codemods.test.ts} +3 -3
  5. package/lib/__node_tests__/{testHelpers.ts → runTest.ts} +1 -3
  6. package/lib/index.ts +1 -16
  7. package/lib/{utils → instui-codemods}/updateToV10Colors.ts +6 -7
  8. package/lib/updateV10Breaking.ts +12 -26
  9. package/lib/{helpers → utils}/codemodHelpers.ts +153 -164
  10. package/lib/utils/codemodTypeCheckers.ts +221 -0
  11. package/lib/utils/instUICodemodExecutor.ts +89 -0
  12. package/package.json +2 -2
  13. package/tsconfig.build.tsbuildinfo +1 -1
  14. package/lib/helpers/replaceDeprecatedImports.ts +0 -546
  15. package/lib/helpers/replaceDeprecatedProps.ts +0 -230
  16. package/lib/updateImports.ts +0 -86
  17. package/lib/updatePropNames.ts +0 -66
  18. package/lib/updateV7Props.ts +0 -101
  19. package/lib/updateV8Breaking.ts +0 -49
  20. package/lib/updateV8ReactDOM.ts +0 -61
  21. package/lib/updateV9Breaking.ts +0 -54
  22. package/lib/utils/UpdateV7ButtonsLink.ts +0 -139
  23. package/lib/utils/requireUncached.ts +0 -28
  24. package/lib/utils/updateToV8Theming.ts +0 -84
  25. package/lib/utils/updateToV9Theming.ts +0 -70
  26. package/lib/utils/updateV7ButtonsClose.ts +0 -104
  27. package/lib/utils/updateV7ButtonsIconCircle.ts +0 -240
  28. package/lib/utils/updateV7ButtonsMisc.ts +0 -137
  29. package/lib/utils/updateV7ButtonsWithText.ts +0 -111
  30. package/lib/utils/updateV7FocusableView.ts +0 -105
  31. package/lib/utils/updateV7Heading.ts +0 -145
  32. package/lib/utils/updateV7Lists.ts +0 -113
  33. package/lib/utils/updateV7Pill.ts +0 -83
  34. package/lib/utils/updateV7Popover.ts +0 -133
  35. package/lib/utils/updateV7Tabs.ts +0 -129
  36. package/lib/utils/updateV8RenderProp.ts +0 -142
  37. package/lib/utils/updateV8ThemeProp.ts +0 -51
  38. package/lib/utils/warnV7ComponentDeprecations.ts +0 -96
@@ -1,139 +0,0 @@
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 {
26
- addImportIfNeeded,
27
- findAttribute,
28
- findElements,
29
- isJSXAttribue,
30
- printWarning,
31
- renameElements
32
- } from '../helpers/codemodHelpers'
33
- import { Collection, JSCodeshift, Literal } from 'jscodeshift'
34
-
35
- /**
36
- * Does the following updates on a <Button>:
37
- * - `variant="link" href=` -> `<Link isWithinText={false} href=..` and a
38
- * warning that padding can be removed.
39
- * - `variant="link-inverse" href=` ->
40
- * <Link isWithinText={false} color="link-inverse" href=` and a warning
41
- * that padding can be removed
42
- * - `variant="link"` or `variant="link-inverse"` and no `href` attribute ->
43
- * display a warning how to upgrade
44
- */
45
- export default function UpdateV7ButtonsLink(
46
- j: JSCodeshift,
47
- root: Collection,
48
- importedName: string,
49
- filePath: string
50
- ) {
51
- ///// variant=link or variant=link-inverse, no href attribute display warning
52
- findElements(filePath, j, root, importedName, {
53
- name: 'variant',
54
- value: ['link', 'link-inverse']
55
- }).forEach((path) => {
56
- const attributes = path.value.openingElement.attributes
57
- if (!attributes) {
58
- displayNoHrefWarning(filePath, path.value.loc!.start.line)
59
- return
60
- }
61
- for (const attr of attributes) {
62
- if (isJSXAttribue(attr) && attr.name.name === 'href') {
63
- return
64
- }
65
- }
66
- displayNoHrefWarning(filePath, path.value.loc!.start.line)
67
- })
68
- ////// find the link and link-inverse variants with href
69
- const linkVariants = findElements(filePath, j, root, importedName, [
70
- { name: 'variant', value: 'link' },
71
- { name: 'href' }
72
- ])
73
- const linkInverseVariants = findElements(filePath, j, root, importedName, [
74
- { name: 'variant', value: 'link-inverse' },
75
- { name: 'href' }
76
- ])
77
- ///// insert import for Link to these and rename them
78
- if (linkVariants.length > 0 || linkInverseVariants.length > 0) {
79
- const linkImportName = addImportIfNeeded(j, root, 'Link', [
80
- '@instructure/ui-link',
81
- '@instructure/ui'
82
- ])
83
- renameElements(filePath, linkVariants, importedName, linkImportName)
84
- renameElements(filePath, linkInverseVariants, importedName, linkImportName)
85
- }
86
-
87
- ///// insert isWithinText={false} and remove variant for variant="link"
88
- findAttribute(filePath, j, linkVariants, 'href').insertAfter(
89
- j.jsxAttribute(
90
- j.jsxIdentifier('isWithinText'),
91
- j.jsxExpressionContainer(j.jsxIdentifier('false'))
92
- )
93
- )
94
- findAttribute(filePath, j, linkVariants, 'variant').remove()
95
- linkVariants.forEach((path) => {
96
- displayHrefWarning(filePath, path.value.loc!.start.line)
97
- })
98
-
99
- ///// variant="link-inverse" => color="link-inverse" isWithinText={false}
100
- findAttribute(filePath, j, linkInverseVariants, 'href').insertAfter(
101
- j.jsxAttribute(
102
- j.jsxIdentifier('isWithinText'),
103
- j.jsxExpressionContainer(j.jsxIdentifier('false'))
104
- )
105
- )
106
- findAttribute(filePath, j, linkInverseVariants, 'variant').replaceWith(
107
- (nodePath) => {
108
- const { node } = nodePath
109
- node.name.name = 'color'
110
- ;(node.value as Literal).value = 'link-inverse'
111
- return nodePath.node
112
- }
113
- )
114
- linkVariants.forEach((path) => {
115
- displayHrefWarning(filePath, path.value.loc!.start.line)
116
- })
117
- }
118
-
119
- function displayHrefWarning(filePath: string, lineNumber: number) {
120
- printWarning(
121
- filePath,
122
- lineNumber,
123
- 'Button with link or link-inverse variant might need the removal' +
124
- ' of margin/padding parameters. Also you will likely need to add ' +
125
- '@instructure/ui-link as a dependency. For more see ' +
126
- 'https://instructure.design/v7/#button-upgrade-guide/#button-upgrade-for-version-8.0-upgrading-variant-link-or-link-inverse-upgrade-examples-for-link-variant-with-an-href-attribute-and-padding-overrides'
127
- )
128
- }
129
-
130
- function displayNoHrefWarning(filePath: string, lineNumber: number) {
131
- printWarning(
132
- filePath,
133
- lineNumber,
134
- 'Button with link or link-inverse variants cannot be upgraded ' +
135
- 'manually when it has no href prop. Also you will likely need to add ' +
136
- '@instructure/ui-link as a dependency. Read more at ' +
137
- 'https://instructure.design/v7/#button-upgrade-guide/#button-upgrade-for-version-8.0-upgrading-variant-link-or-link-inverse-upgrade-examples-for-link-variant-with-no-href-attribute-and-padding-overrides'
138
- )
139
- }
@@ -1,28 +0,0 @@
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
- export default function requireUncached(module: string) {
26
- delete require.cache[require.resolve(module)]
27
- return require(module)
28
- }
@@ -1,84 +0,0 @@
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 { Collection, JSCodeshift } from 'jscodeshift'
26
- import {
27
- addImportIfNeeded,
28
- findElements,
29
- findEveryImport,
30
- findImport,
31
- isIdentifier,
32
- isMemberExpression,
33
- renameElements
34
- } from '../helpers/codemodHelpers'
35
-
36
- /**
37
- * Does the following changes:
38
- * 1. `<ApplyTheme` -> `<InstUISettingsProvider`
39
- * 2. `Menu.theme` -> `Menu.componentId` (for every InstUI component)
40
- */
41
- export function updateToV8Theming(
42
- j: JSCodeshift,
43
- root: Collection,
44
- filePath: string
45
- ) {
46
- let hasModifications = false
47
- const importedName = findImport(j, root, 'ApplyTheme', [
48
- '@instructure/ui',
49
- '@instructure/ui-themeable'
50
- ])
51
- // <ApplyTheme> -> <InstUISettingsProvider>
52
- if (importedName) {
53
- const applyThemeElements = findElements(filePath, j, root, importedName)
54
- const instUISettingsProvider = addImportIfNeeded(
55
- j,
56
- root,
57
- 'InstUISettingsProvider',
58
- '@instructure/emotion'
59
- )
60
- renameElements(
61
- filePath,
62
- applyThemeElements,
63
- importedName,
64
- instUISettingsProvider
65
- )
66
- hasModifications = true
67
- }
68
- // Menu.theme -> Menu.componentId (for every InstUI component)
69
- const importedComponents = findEveryImport(j, root, '@instructure/ui', false)
70
- root.find(j.MemberExpression).forEach((path) => {
71
- const astNode = path.value
72
- if (
73
- isMemberExpression(astNode) &&
74
- isIdentifier(astNode.object) &&
75
- importedComponents.includes(astNode.object.name) &&
76
- isIdentifier(astNode.property) &&
77
- astNode.property.name === 'theme'
78
- ) {
79
- hasModifications = true
80
- astNode.property.name = 'componentId'
81
- }
82
- })
83
- return hasModifications
84
- }
@@ -1,70 +0,0 @@
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 { Collection, JSCodeshift } from 'jscodeshift'
26
- import {
27
- findElements,
28
- findImport,
29
- renameElements,
30
- replaceImport
31
- } from '../helpers/codemodHelpers'
32
-
33
- /**
34
- * Does the following changes:
35
- * 1. `<EmotionThemeProvider>` -> `<InstUISettingsProvider>`
36
- */
37
- export function updateToV9Theming(
38
- j: JSCodeshift,
39
- root: Collection,
40
- filePath: string
41
- ) {
42
- let hasModifications = false
43
- const importedName = findImport(j, root, 'EmotionThemeProvider', [
44
- '@instructure/emotion'
45
- ])
46
- // <EmotionThemeProvider> -> <InstUISettingsProvider>
47
- if (importedName) {
48
- const emotionThemeProviderElements = findElements(
49
- filePath,
50
- j,
51
- root,
52
- importedName
53
- )
54
- const instUISettingsProvider = replaceImport(
55
- j,
56
- root,
57
- 'EmotionThemeProvider',
58
- 'InstUISettingsProvider',
59
- '@instructure/emotion'
60
- )
61
- renameElements(
62
- filePath,
63
- emotionThemeProviderElements,
64
- importedName,
65
- instUISettingsProvider
66
- )
67
- hasModifications = true
68
- }
69
- return hasModifications
70
- }
@@ -1,104 +0,0 @@
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 { Collection, JSCodeshift, Literal } from 'jscodeshift'
26
- import {
27
- findAttribute,
28
- findElements,
29
- findImport,
30
- getVisibleChildren,
31
- isJSXExpressionContainer,
32
- isJSXText,
33
- printWarning,
34
- removeAllChildren
35
- } from '../helpers/codemodHelpers'
36
-
37
- /**
38
- * Does the following updates on a <CloseButton>:
39
- * - `buttonRef=` -> `elementRef=`
40
- * - `variant="icon"` removed
41
- * - `variant="icon-inverse"` -> `color="primary-inverse"`
42
- *
43
- * If it has children it outputs a warning on how to upgrade them
44
- **/
45
- export default function updateV7ButtonsClose(
46
- j: JSCodeshift,
47
- root: Collection,
48
- filePath: string
49
- ) {
50
- const closeButtonImportName = findImport(j, root, 'CloseButton', [
51
- '@instructure/ui-buttons',
52
- '@instructure/ui'
53
- ])
54
- if (!closeButtonImportName) {
55
- return false
56
- }
57
- ///// replace <CloseButton buttonRef=.. with <CloseButton elementRef=..
58
- findElements(filePath, j, root, closeButtonImportName)
59
- .find(j.JSXIdentifier, { name: 'buttonRef' })
60
- .replaceWith('elementRef')
61
-
62
- ///// If it has children try to move them under screenReaderLabel
63
- findElements(filePath, j, root, closeButtonImportName).forEach((path) => {
64
- const children = getVisibleChildren(path.value.children)
65
- if (children.length == 1) {
66
- const firstChild = children[0]
67
- let screenReaderLabelText
68
- if (isJSXText(firstChild)) {
69
- screenReaderLabelText = j.stringLiteral(firstChild.value)
70
- } else if (isJSXExpressionContainer(firstChild)) {
71
- screenReaderLabelText = firstChild
72
- }
73
- path.value.openingElement.attributes!.push(
74
- j.jsxAttribute(
75
- j.jsxIdentifier('screenReaderLabel'),
76
- screenReaderLabelText
77
- )
78
- )
79
- removeAllChildren(path.value)
80
- } else if (children.length > 1) {
81
- printWarning(
82
- filePath,
83
- path.value.loc?.start.line,
84
- 'Cannot update CloseButton because it has multiple children.' +
85
- 'Children should be moved to the `screenReaderLabel` prop,' +
86
- 'You will need to update this manually.'
87
- )
88
- }
89
- })
90
-
91
- ///// Remove variant="icon" prop
92
- findAttribute(filePath, j, root, 'variant', 'icon').remove()
93
-
94
- ///// Change variant="icon-inverse" to color="primary-inverse"
95
- findAttribute(filePath, j, root, 'variant', 'icon-inverse').replaceWith(
96
- (nodePath) => {
97
- const { node } = nodePath
98
- node.name.name = 'color'
99
- ;(node.value as Literal).value = 'primary-inverse'
100
- return nodePath.node
101
- }
102
- )
103
- return true
104
- }
@@ -1,240 +0,0 @@
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 {
26
- Collection,
27
- JSCodeshift,
28
- JSXAttribute,
29
- JSXIdentifier,
30
- Literal
31
- } from 'jscodeshift'
32
- import {
33
- addImportIfNeeded,
34
- findAttribute,
35
- findElements,
36
- getVisibleChildren,
37
- isJSXElement,
38
- isJSXExpressionContainer,
39
- isJSXText,
40
- printWarning,
41
- removeAllChildren,
42
- renameElements
43
- } from '../helpers/codemodHelpers'
44
-
45
- /**
46
- * Does the following updates on a <Button>:
47
- * - variant="icon" -> <IconButton withBackground={false} withBorder={false}
48
- * - variant="icon-inverse" -> <IconButton color="primary-inverse" withBackground={false} withBorder={false}
49
- * - variant="circle-default" -> <IconButton color="secondary" shape="circle"
50
- * - variant="circle-danger" -> <IconButton color="danger" shape="circle"
51
- * - variant="icon" -> <IconButton color="secondary" shape="circle"
52
- *
53
- * This codemod also adds an import to `IconButton`.
54
- *
55
- * It also outputs a warning and does not do anything if one of these variants
56
- * has visible children (it simply checks whether it has 1
57
- * `<ScreenReaderContent>` child.)
58
- **/
59
- export default function updateV7ButtonsIconCircle(
60
- j: JSCodeshift,
61
- root: Collection,
62
- importedName: string,
63
- filePath: string
64
- ) {
65
- // find out if the button has got any visible text inside it, in this case
66
- // just display a warning, that it cannot be upgraded.
67
- const buttonsWithNoText = findElements(filePath, j, root, importedName, {
68
- name: 'variant',
69
- value: [
70
- 'icon',
71
- 'icon-inverse',
72
- 'circle-default',
73
- 'circle-primary',
74
- 'circle-danger'
75
- ]
76
- }).filter((path) => {
77
- // finds all with no/ScreenReader children
78
- const children = getVisibleChildren(path.value.children)
79
- if (children.length == 0) {
80
- return true
81
- }
82
- if (children.length > 1) {
83
- printWarning(
84
- filePath,
85
- path.value.loc?.start.line,
86
- 'Cannot update icon/circle Button because it has multiple ' +
87
- 'children. You will need to update this manually.'
88
- )
89
- return false
90
- }
91
- let screenReaderChildText
92
- const child = children[0]
93
- if (
94
- isJSXElement(child) &&
95
- (child.openingElement.name as JSXIdentifier).name ===
96
- 'ScreenReaderContent'
97
- ) {
98
- const screenReaderChildren = getVisibleChildren(child.children)
99
- if (screenReaderChildren.length === 1) {
100
- if (!screenReaderChildText) {
101
- const firstChild = screenReaderChildren[0]
102
- if (isJSXText(firstChild)) {
103
- screenReaderChildText = j.stringLiteral(firstChild.value)
104
- } else if (isJSXExpressionContainer(firstChild)) {
105
- screenReaderChildText = firstChild
106
- } else {
107
- printWarning(
108
- filePath,
109
- path.value.loc?.start.line,
110
- 'Cannot update icon/circle Button because I cant ' +
111
- 'recognize whats inside its ScreenReaderContent. ' +
112
- 'You will need to update this manually.'
113
- )
114
- return false
115
- }
116
- } else {
117
- printWarning(
118
- filePath,
119
- path.value.loc?.start.line,
120
- 'Cannot update icon/circle Button because it has ' +
121
- 'multiple ScreenReaderContent children. You will need to ' +
122
- 'update this manually.'
123
- )
124
- return false
125
- }
126
- }
127
- }
128
- if (screenReaderChildText) {
129
- path.value.openingElement.attributes!.push(
130
- j.jsxAttribute(
131
- j.jsxIdentifier('screenReaderLabel'),
132
- screenReaderChildText
133
- )
134
- )
135
- removeAllChildren(path.value)
136
- return true
137
- }
138
- printWarning(
139
- filePath,
140
- path.value.loc?.start.line,
141
- 'Cannot update icon/circle Button because it has visible ' +
142
- 'children. You will need to update this manually.'
143
- )
144
- return false
145
- })
146
-
147
- if (buttonsWithNoText.length == 0) {
148
- return
149
- }
150
- // add IconButton import
151
- const iconButtonImportName = addImportIfNeeded(
152
- j,
153
- root,
154
- 'IconButton',
155
- '@instructure/ui-buttons'
156
- )
157
-
158
- // rename every <Button> to <IconButton> (or whatever alias it's imported under)
159
- renameElements(filePath, buttonsWithNoText, 'Button', iconButtonImportName)
160
-
161
- // remove variant="icon", add withBorder={false} withBackground={false}
162
- const iconButton = findAttribute(
163
- filePath,
164
- j,
165
- buttonsWithNoText,
166
- 'variant',
167
- 'icon'
168
- ).remove()
169
- addWithBorderBackground(j, iconButton)
170
-
171
- // change variant="icon-inverse" to color="primary-inverse" withBorder={false} withBackground={false}
172
- const iconInverse = findAttribute(
173
- filePath,
174
- j,
175
- buttonsWithNoText,
176
- 'variant',
177
- 'icon-inverse'
178
- ).replaceWith((nodePath) => {
179
- const { node } = nodePath
180
- node.name.name = 'color'
181
- ;(node.value as Literal).value = 'primary-inverse'
182
- return nodePath.node
183
- })
184
- addWithBorderBackground(j, iconInverse)
185
-
186
- // change variant="circle-default" to color="secondary" shape="circle"
187
- findAttribute(filePath, j, buttonsWithNoText, 'variant', 'circle-default')
188
- .replaceWith((nodePath) => {
189
- const { node } = nodePath
190
- node.name.name = 'color'
191
- ;(node.value as Literal).value = 'secondary'
192
- return nodePath.node
193
- })
194
- .insertAfter(
195
- j.jsxAttribute(j.jsxIdentifier('shape'), j.stringLiteral('circle'))
196
- )
197
-
198
- // change variant="circle-primary" to color="primary" shape="circle"
199
- findAttribute(filePath, j, buttonsWithNoText, 'variant', 'circle-primary')
200
- .replaceWith((nodePath) => {
201
- const { node } = nodePath
202
- node.name.name = 'color'
203
- ;(node.value as Literal).value = 'primary'
204
- return nodePath.node
205
- })
206
- .insertAfter(
207
- j.jsxAttribute(j.jsxIdentifier('shape'), j.stringLiteral('circle'))
208
- )
209
-
210
- // change variant="circle-danger" to color="danger" shape="circle"
211
- findAttribute(filePath, j, buttonsWithNoText, 'variant', 'circle-danger')
212
- .replaceWith((nodePath) => {
213
- const { node } = nodePath
214
- node.name.name = 'color'
215
- ;(node.value as Literal).value = 'danger'
216
- return nodePath.node
217
- })
218
- .insertAfter(
219
- j.jsxAttribute(j.jsxIdentifier('shape'), j.stringLiteral('circle'))
220
- )
221
- }
222
-
223
- function addWithBorderBackground(
224
- j: JSCodeshift,
225
- root: Collection<JSXAttribute>
226
- ) {
227
- root
228
- .insertAfter(
229
- j.jsxAttribute(
230
- j.jsxIdentifier('withBorder'),
231
- j.jsxExpressionContainer(j.jsxIdentifier('false'))
232
- )
233
- )
234
- .insertAfter(
235
- j.jsxAttribute(
236
- j.jsxIdentifier('withBackground'),
237
- j.jsxExpressionContainer(j.jsxIdentifier('false'))
238
- )
239
- )
240
- }