@instructure/ui-codemods 8.17.1-snapshot.30 → 8.17.1-snapshot.71

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.
@@ -0,0 +1,74 @@
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 { API, FileInfo } from 'jscodeshift'
26
+ import formatSource from './utils/formatSource'
27
+
28
+ /**
29
+ * Renames components theme={} prop to themeOverride={}
30
+ */
31
+ export default function updateV8Props(file: FileInfo, api: API) {
32
+ const j = api.jscodeshift
33
+ const root = j(file.source)
34
+ const instUIImports: string[] = []
35
+ root
36
+ .find(j.ImportDeclaration)
37
+ .filter((path) => {
38
+ const importSource = path.node.source.value
39
+ if (importSource && typeof importSource === 'string') {
40
+ return !!importSource.match(/@instructure\/ui/gm)
41
+ }
42
+ return false
43
+ })
44
+ .forEach((path) => {
45
+ if (path.node.specifiers) {
46
+ path.node.specifiers.forEach((specifier) => {
47
+ if (specifier.local) {
48
+ instUIImports.push(specifier.local.name)
49
+ }
50
+ })
51
+ }
52
+ })
53
+ let isChanged = false
54
+ instUIImports.forEach((instUIImport) => {
55
+ const elems = root
56
+ .find(j.JSXOpeningElement, {
57
+ name: {
58
+ type: 'JSXIdentifier',
59
+ name: instUIImport
60
+ }
61
+ })
62
+ .find(j.JSXIdentifier, {
63
+ name: 'theme'
64
+ })
65
+ elems.replaceWith('themeOverride')
66
+ if (elems.length > 0) {
67
+ isChanged = true
68
+ }
69
+ })
70
+ if (isChanged) {
71
+ return formatSource(root.toSource(), file.path)
72
+ }
73
+ return null
74
+ }
@@ -0,0 +1,139 @@
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/v7PropsUpdateHelpers'
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
+ }
@@ -0,0 +1,104 @@
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/v7PropsUpdateHelpers'
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
+ }
@@ -0,0 +1,240 @@
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/v7PropsUpdateHelpers'
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
+ }
@@ -0,0 +1,137 @@
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
+ findAttribute,
27
+ findElements,
28
+ isJSXAttribue,
29
+ isJSXExpressionContainer,
30
+ isLiteral,
31
+ printWarning
32
+ } from '../helpers/v7PropsUpdateHelpers'
33
+ import { Collection, JSCodeshift } from 'jscodeshift'
34
+
35
+ /**
36
+ * Does the following updates on a <Button>:
37
+ * - `buttonRef` -> `elementRef`
38
+ * - `fluidWidth` -> removed and `display="block" textAlign="start"` added
39
+ * (overwrites any existing `display` and `textAlign` props)
40
+ * - `icon` -> `renderIcon`
41
+ */
42
+ export default function updateV7ButtonsMisc(
43
+ j: JSCodeshift,
44
+ root: Collection,
45
+ importedName: string,
46
+ filePath: string
47
+ ) {
48
+ ///// <Button fluidWidth .. -> <Button display="block" textAlign="start"
49
+ // remove fluidWidth attribute if its value is 'false' (it's the default)
50
+ findElements(filePath, j, root, importedName)
51
+ .find(j.JSXAttribute, {
52
+ name: {
53
+ name: 'fluidWidth'
54
+ },
55
+ value: {
56
+ expression: {
57
+ value: false
58
+ }
59
+ }
60
+ })
61
+ .remove()
62
+
63
+ const buttonsWithFluidWidth = findElements(filePath, j, root, importedName, {
64
+ name: 'fluidWidth'
65
+ }).filter((path) => {
66
+ const attributes = path.value.openingElement.attributes!
67
+ for (const att of attributes) {
68
+ if (isJSXAttribue(att) && att.name.name === 'fluidWidth') {
69
+ if (!att.value) {
70
+ // <Button fluidWidth />
71
+ return true
72
+ }
73
+ if (
74
+ isJSXExpressionContainer(att.value) &&
75
+ isLiteral(att.value.expression) &&
76
+ typeof att.value.expression.value === 'boolean'
77
+ ) {
78
+ // <Button fluidWidth={true} />
79
+ return att.value.expression.value
80
+ } else {
81
+ printWarning(
82
+ filePath,
83
+ att.loc?.start.line,
84
+ "Button's `fluidWidth` attribute has non-literal" +
85
+ ' value, please update manually.'
86
+ )
87
+ return false
88
+ }
89
+ }
90
+ }
91
+ return false
92
+ })
93
+ // remove fluidWidth attribute
94
+ findAttribute(filePath, j, buttonsWithFluidWidth, 'fluidWidth').remove()
95
+ // remove display attribute
96
+ findAttribute(filePath, j, buttonsWithFluidWidth, 'display')
97
+ .forEach((path) => {
98
+ printWarning(
99
+ filePath,
100
+ path.value.loc!.start.line,
101
+ "'display' attribute was changed to 'block'"
102
+ )
103
+ })
104
+ .remove()
105
+ // remove textAlign attribute
106
+ findAttribute(filePath, j, buttonsWithFluidWidth, 'textAlign')
107
+ .forEach((path) => {
108
+ printWarning(
109
+ filePath,
110
+ path.value.loc!.start.line,
111
+ "'textAlign' attribute was changed to 'start'"
112
+ )
113
+ })
114
+ .remove()
115
+ // add display="block" attribute
116
+ buttonsWithFluidWidth.forEach((path) => {
117
+ path.value.openingElement.attributes!.push(
118
+ j.jsxAttribute(j.jsxIdentifier('display'), j.stringLiteral('block'))
119
+ )
120
+ })
121
+ // add textAlign="start" attribute
122
+ buttonsWithFluidWidth.forEach((path) => {
123
+ path.value.openingElement!.attributes!.push(
124
+ j.jsxAttribute(j.jsxIdentifier('textAlign'), j.stringLiteral('start'))
125
+ )
126
+ })
127
+
128
+ ///// replace <Button icon=.. with <Button renderIcon=..
129
+ findElements(filePath, j, root, importedName)
130
+ .find(j.JSXIdentifier, { name: 'icon' })
131
+ .replaceWith('renderIcon')
132
+
133
+ ///// replace <Button buttonRef=.. with <Button elementRef=..
134
+ findElements(filePath, j, root, importedName)
135
+ .find(j.JSXIdentifier, { name: 'buttonRef' })
136
+ .replaceWith('elementRef')
137
+ }