@sanity/ui-codemod 1.0.0-alpha.1

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 (157) hide show
  1. package/bin/run.js +5 -0
  2. package/dist/_chunks-es/addAttribute.js +11 -0
  3. package/dist/_chunks-es/addAttribute.js.map +1 -0
  4. package/dist/_chunks-es/box.mods.js +186 -0
  5. package/dist/_chunks-es/box.mods.js.map +1 -0
  6. package/dist/_chunks-es/flex.mods.js +74 -0
  7. package/dist/_chunks-es/flex.mods.js.map +1 -0
  8. package/dist/_chunks-es/getTransformPath.js +75 -0
  9. package/dist/_chunks-es/getTransformPath.js.map +1 -0
  10. package/dist/_chunks-es/grid.mods.js +110 -0
  11. package/dist/_chunks-es/grid.mods.js.map +1 -0
  12. package/dist/_chunks-es/layout-mods.js +424 -0
  13. package/dist/_chunks-es/layout-mods.js.map +1 -0
  14. package/dist/_chunks-es/transformComponent.js +359 -0
  15. package/dist/_chunks-es/transformComponent.js.map +1 -0
  16. package/dist/commands/latest/box.d.ts +47 -0
  17. package/dist/commands/latest/box.js +17 -0
  18. package/dist/commands/latest/box.js.map +1 -0
  19. package/dist/commands/latest/card.d.ts +47 -0
  20. package/dist/commands/latest/card.js +17 -0
  21. package/dist/commands/latest/card.js.map +1 -0
  22. package/dist/commands/latest/code.d.ts +47 -0
  23. package/dist/commands/latest/code.js +17 -0
  24. package/dist/commands/latest/code.js.map +1 -0
  25. package/dist/commands/latest/container.d.ts +47 -0
  26. package/dist/commands/latest/container.js +17 -0
  27. package/dist/commands/latest/container.js.map +1 -0
  28. package/dist/commands/latest/flex.d.ts +47 -0
  29. package/dist/commands/latest/flex.js +17 -0
  30. package/dist/commands/latest/flex.js.map +1 -0
  31. package/dist/commands/latest/grid.d.ts +47 -0
  32. package/dist/commands/latest/grid.js +17 -0
  33. package/dist/commands/latest/grid.js.map +1 -0
  34. package/dist/commands/latest/heading.d.ts +47 -0
  35. package/dist/commands/latest/heading.js +17 -0
  36. package/dist/commands/latest/heading.js.map +1 -0
  37. package/dist/commands/latest/text.d.ts +47 -0
  38. package/dist/commands/latest/text.js +17 -0
  39. package/dist/commands/latest/text.js.map +1 -0
  40. package/dist/transforms/latest/box/box.d.ts +18 -0
  41. package/dist/transforms/latest/box/box.js +101 -0
  42. package/dist/transforms/latest/box/box.js.map +1 -0
  43. package/dist/transforms/latest/card/card.d.ts +18 -0
  44. package/dist/transforms/latest/card/card.js +618 -0
  45. package/dist/transforms/latest/card/card.js.map +1 -0
  46. package/dist/transforms/latest/code/code.d.ts +18 -0
  47. package/dist/transforms/latest/code/code.js +73 -0
  48. package/dist/transforms/latest/code/code.js.map +1 -0
  49. package/dist/transforms/latest/container/container.d.ts +18 -0
  50. package/dist/transforms/latest/container/container.js +91 -0
  51. package/dist/transforms/latest/container/container.js.map +1 -0
  52. package/dist/transforms/latest/flex/flex.d.ts +18 -0
  53. package/dist/transforms/latest/flex/flex.js +19 -0
  54. package/dist/transforms/latest/flex/flex.js.map +1 -0
  55. package/dist/transforms/latest/grid/grid.d.ts +18 -0
  56. package/dist/transforms/latest/grid/grid.js +19 -0
  57. package/dist/transforms/latest/grid/grid.js.map +1 -0
  58. package/dist/transforms/latest/heading/heading.d.ts +18 -0
  59. package/dist/transforms/latest/heading/heading.js +85 -0
  60. package/dist/transforms/latest/heading/heading.js.map +1 -0
  61. package/dist/transforms/latest/text/text.d.ts +18 -0
  62. package/dist/transforms/latest/text/text.js +88 -0
  63. package/dist/transforms/latest/text/text.js.map +1 -0
  64. package/package.json +68 -0
  65. package/src/baseCommand.ts +74 -0
  66. package/src/commands/latest/box.ts +21 -0
  67. package/src/commands/latest/card.ts +21 -0
  68. package/src/commands/latest/code.ts +21 -0
  69. package/src/commands/latest/container.ts +21 -0
  70. package/src/commands/latest/flex.ts +21 -0
  71. package/src/commands/latest/grid.ts +21 -0
  72. package/src/commands/latest/heading.ts +21 -0
  73. package/src/commands/latest/inline.ts +21 -0
  74. package/src/commands/latest/label.ts +21 -0
  75. package/src/commands/latest/stack.ts +21 -0
  76. package/src/commands/latest/text.ts +21 -0
  77. package/src/constants/latest/layout-mods.ts +422 -0
  78. package/src/transforms/latest/box/box.mods.ts +88 -0
  79. package/src/transforms/latest/box/box.test.ts +204 -0
  80. package/src/transforms/latest/box/box.ts +104 -0
  81. package/src/transforms/latest/card/card.mods.ts +592 -0
  82. package/src/transforms/latest/card/card.test.ts +207 -0
  83. package/src/transforms/latest/card/card.ts +71 -0
  84. package/src/transforms/latest/code/code.mods.ts +57 -0
  85. package/src/transforms/latest/code/code.test.ts +61 -0
  86. package/src/transforms/latest/code/code.ts +53 -0
  87. package/src/transforms/latest/container/container.mods.ts +77 -0
  88. package/src/transforms/latest/container/container.test.ts +105 -0
  89. package/src/transforms/latest/container/container.ts +42 -0
  90. package/src/transforms/latest/flex/flex.mods.ts +73 -0
  91. package/src/transforms/latest/flex/flex.test.ts +80 -0
  92. package/src/transforms/latest/flex/flex.ts +42 -0
  93. package/src/transforms/latest/grid/grid.mods.ts +109 -0
  94. package/src/transforms/latest/grid/grid.test.ts +97 -0
  95. package/src/transforms/latest/grid/grid.ts +42 -0
  96. package/src/transforms/latest/heading/heading.mods.ts +70 -0
  97. package/src/transforms/latest/heading/heading.test.ts +87 -0
  98. package/src/transforms/latest/heading/heading.ts +53 -0
  99. package/src/transforms/latest/inline/inline.mods.ts +65 -0
  100. package/src/transforms/latest/inline/inline.test.ts +57 -0
  101. package/src/transforms/latest/inline/inline.ts +42 -0
  102. package/src/transforms/latest/label/label.mods.ts +72 -0
  103. package/src/transforms/latest/label/label.test.ts +113 -0
  104. package/src/transforms/latest/label/label.ts +67 -0
  105. package/src/transforms/latest/stack/stack.mods.ts +12 -0
  106. package/src/transforms/latest/stack/stack.test.ts +160 -0
  107. package/src/transforms/latest/stack/stack.ts +102 -0
  108. package/src/transforms/latest/text/text.mods.ts +72 -0
  109. package/src/transforms/latest/text/text.test.ts +113 -0
  110. package/src/transforms/latest/text/text.ts +57 -0
  111. package/src/types/AnyExpression.ts +9 -0
  112. package/src/types/AttributeMods.ts +16 -0
  113. package/src/types/BaseOptions.ts +6 -0
  114. package/src/utils/addAttribute.test.ts +43 -0
  115. package/src/utils/addAttribute.ts +26 -0
  116. package/src/utils/addImportSpecifier.test.ts +36 -0
  117. package/src/utils/addImportSpecifier.ts +42 -0
  118. package/src/utils/getAttribute.ts +22 -0
  119. package/src/utils/getAttributeExpression.ts +22 -0
  120. package/src/utils/getAttributeValue.ts +20 -0
  121. package/src/utils/getClonedImportSpecifiers.ts +29 -0
  122. package/src/utils/getComponentJsxNames.ts +17 -0
  123. package/src/utils/getComponentLocalNames.ts +69 -0
  124. package/src/utils/getCompositeAttrValue.ts +39 -0
  125. package/src/utils/getMappingArray.ts +36 -0
  126. package/src/utils/getMappingExpression.ts +22 -0
  127. package/src/utils/getMappingValue.ts +52 -0
  128. package/src/utils/getShorthandAttributes.ts +54 -0
  129. package/src/utils/getSplitImportSpecifiers.ts +40 -0
  130. package/src/utils/getStaticAttributeExpression.ts +35 -0
  131. package/src/utils/getStyleExpression.ts +37 -0
  132. package/src/utils/getStyledComponentAliases.ts +28 -0
  133. package/src/utils/getStyledComponentName.ts +52 -0
  134. package/src/utils/getTransformPath.ts +17 -0
  135. package/src/utils/insertTodoWarning.ts +48 -0
  136. package/src/utils/isImportBindingUsed.ts +53 -0
  137. package/src/utils/isValidStyleType.ts +21 -0
  138. package/src/utils/mergeStyle.ts +64 -0
  139. package/src/utils/removeUnusedImport.test.ts +77 -0
  140. package/src/utils/removeUnusedImport.ts +57 -0
  141. package/src/utils/replaceElement.test.ts +181 -0
  142. package/src/utils/replaceElement.ts +106 -0
  143. package/src/utils/replaceStyledComponent.test.ts +57 -0
  144. package/src/utils/replaceStyledComponent.ts +60 -0
  145. package/src/utils/shouldTransformComponent.test.ts +61 -0
  146. package/src/utils/shouldTransformComponent.ts +40 -0
  147. package/src/utils/testUtils.ts +54 -0
  148. package/src/utils/transformAttributes.test.ts +544 -0
  149. package/src/utils/transformAttributes.ts +248 -0
  150. package/src/utils/transformComponent.test.ts +45 -0
  151. package/src/utils/transformComponent.ts +31 -0
  152. package/src/utils/transformImport.test.ts +175 -0
  153. package/src/utils/transformImport.ts +55 -0
  154. package/src/utils/transformImportAlias.test.ts +40 -0
  155. package/src/utils/transformImportAlias.ts +49 -0
  156. package/src/utils/transformStyledComponents.test.ts +172 -0
  157. package/src/utils/transformStyledComponents.ts +58 -0
@@ -0,0 +1,65 @@
1
+ import type {AttributeMods} from '../../../types/AttributeMods'
2
+
3
+ /** @internal */
4
+ export const INLINE_MODS: AttributeMods = {
5
+ flex: {
6
+ type: 'style-mapped',
7
+ style: 'flex',
8
+ mapping: {
9
+ none: '0 0 auto',
10
+ auto: '1 1 auto',
11
+ initial: '0 1 auto',
12
+ 1: '1',
13
+ 2: '2',
14
+ 3: '3',
15
+ 4: '4',
16
+ 5: '5',
17
+ 6: '6',
18
+ 7: '7',
19
+ 8: '8',
20
+ 9: '9',
21
+ 10: '10',
22
+ 11: '11',
23
+ 12: '12',
24
+ },
25
+ },
26
+ margin: {
27
+ type: 'warn-only',
28
+ warning:
29
+ 'Please double check the Inline migration below. Margin is not supported in either version.',
30
+ },
31
+ marginX: {
32
+ type: 'warn-only',
33
+ warning:
34
+ 'Please double check the Inline migration below. Margin is not supported in either version.',
35
+ },
36
+ marginY: {
37
+ type: 'warn-only',
38
+ warning:
39
+ 'Please double check the Inline migration below. Margin is not supported in either version.',
40
+ },
41
+ marginTop: {
42
+ type: 'warn-only',
43
+ warning:
44
+ 'Please double check the Inline migration below. Margin is not supported in either version.',
45
+ },
46
+ marginRight: {
47
+ type: 'warn-only',
48
+ warning:
49
+ 'Please double check the Inline migration below. Margin is not supported in either version.',
50
+ },
51
+ marginBottom: {
52
+ type: 'warn-only',
53
+ warning:
54
+ 'Please double check the Inline migration below. Margin is not supported in either version.',
55
+ },
56
+ marginLeft: {
57
+ type: 'warn-only',
58
+ warning:
59
+ 'Please double check the Inline migration below. Margin is not supported in either version.',
60
+ },
61
+ space: {
62
+ type: 'rename-only',
63
+ name: 'gap',
64
+ },
65
+ }
@@ -0,0 +1,57 @@
1
+ import {defineInlineTest} from '../../../utils/testUtils'
2
+ import transform from './inline'
3
+
4
+ defineInlineTest(
5
+ transform,
6
+ {fromPackage: '@legacy/ui', toPackage: '@sanity/ui'},
7
+ `
8
+ import {Inline} from '@legacy/ui'
9
+
10
+ <Inline />
11
+ `,
12
+ `
13
+ import {Inline} from "@sanity/ui"
14
+
15
+ <Inline />
16
+ `,
17
+ 'updates Inline import path based on fromPackage and toPackage',
18
+ )
19
+
20
+ defineInlineTest(
21
+ transform,
22
+ {},
23
+ `
24
+ <Inline space={2} />
25
+ `,
26
+ `
27
+ <Inline gap={2} />
28
+ `,
29
+ 'renames space prop to gap',
30
+ )
31
+
32
+ defineInlineTest(
33
+ transform,
34
+ {},
35
+ `
36
+ <Inline flex="auto" />
37
+ `,
38
+ `
39
+ <Inline style={{
40
+ flex: "1 1 auto"
41
+ }} />
42
+ `,
43
+ 'moves flex prop to style',
44
+ )
45
+
46
+ defineInlineTest(
47
+ transform,
48
+ {},
49
+ `
50
+ <Inline margin={2} />
51
+ `,
52
+ `
53
+ // UI-CODEMOD TODO: Please double check the Inline migration below. Margin is not supported in either version.
54
+ <Inline margin={2} />
55
+ `,
56
+ 'warns if margin prop is present',
57
+ )
@@ -0,0 +1,42 @@
1
+ import {type API, type FileInfo} from 'jscodeshift'
2
+
3
+ import type {BaseOptions} from '../../../types/BaseOptions'
4
+ import {getComponentLocalNames} from '../../../utils/getComponentLocalNames'
5
+ import {shouldTransformComponent} from '../../../utils/shouldTransformComponent'
6
+ import {transformAttributes} from '../../../utils/transformAttributes'
7
+ import {transformComponent} from '../../../utils/transformComponent'
8
+ import {transformImport} from '../../../utils/transformImport'
9
+ import {INLINE_MODS} from './inline.mods'
10
+
11
+ const TODO_WARNING = 'Please double check the Inline migration below'
12
+
13
+ /** @internal */
14
+ export default function transform(
15
+ fileInfo: FileInfo,
16
+ api: API,
17
+ options?: BaseOptions,
18
+ ): string | undefined {
19
+ const {fromPackage, toPackage} = options || {}
20
+
21
+ return transformComponent(fileInfo, api, ({j, root, markChanged}) => {
22
+ const localNames = getComponentLocalNames(j, root, 'Inline', options)
23
+
24
+ if (!shouldTransformComponent(j, root, 'Inline', localNames, options)) {
25
+ return
26
+ }
27
+
28
+ if (transformImport(j, root, 'Inline', fromPackage, toPackage)) {
29
+ markChanged()
30
+ }
31
+
32
+ root
33
+ .find(j.JSXOpeningElement, {
34
+ name: {type: 'JSXIdentifier', name: 'Inline'},
35
+ })
36
+ .forEach((path) => {
37
+ if (transformAttributes(j, path, INLINE_MODS, TODO_WARNING)) {
38
+ markChanged()
39
+ }
40
+ })
41
+ })
42
+ }
@@ -0,0 +1,72 @@
1
+ import type {AttributeMods} from '../../../types/AttributeMods'
2
+
3
+ /** @internal */
4
+ export const LABEL_MODS: AttributeMods = {
5
+ accent: {
6
+ type: 'rename-mapped',
7
+ name: 'tone',
8
+ mapping: {
9
+ true: 'suggest',
10
+ },
11
+ },
12
+ flex: {
13
+ type: 'style-mapped',
14
+ style: 'flex',
15
+ mapping: {
16
+ none: '0 0 auto',
17
+ auto: '1 1 auto',
18
+ initial: '0 1 auto',
19
+ 1: '1',
20
+ 2: '2',
21
+ 3: '3',
22
+ 4: '4',
23
+ 5: '5',
24
+ 6: '6',
25
+ 7: '7',
26
+ 8: '8',
27
+ 9: '9',
28
+ 10: '10',
29
+ 11: '11',
30
+ 12: '12',
31
+ },
32
+ },
33
+ maxWidth: {
34
+ type: 'style-mapped',
35
+ style: 'maxWidth',
36
+ mapping: {
37
+ auto: 'none',
38
+ fill: '100%',
39
+ 0: '20rem',
40
+ 1: '40rem',
41
+ 2: '60rem',
42
+ 3: '80rem',
43
+ 4: '100rem',
44
+ 5: '120rem',
45
+ },
46
+ },
47
+ textOverflow: {
48
+ type: 'rename-mapped',
49
+ name: 'truncate',
50
+ mapping: {
51
+ ellipsis: 1,
52
+ clip: 1,
53
+ },
54
+ },
55
+ width: {
56
+ type: 'style-mapped',
57
+ style: 'width',
58
+ mapping: {
59
+ auto: 'auto',
60
+ fill: '100%',
61
+ stretch: 'stretch',
62
+ min: 'min-content',
63
+ max: 'max-content',
64
+ 0: '20rem',
65
+ 1: '40rem',
66
+ 2: '60rem',
67
+ 3: '80rem',
68
+ 4: '100rem',
69
+ 5: '120rem',
70
+ },
71
+ },
72
+ }
@@ -0,0 +1,113 @@
1
+ import {defineInlineTest} from '../../../utils/testUtils'
2
+ import transform from './label'
3
+
4
+ defineInlineTest(
5
+ transform,
6
+ {fromPackage: '@legacy/ui', toPackage: '@sanity/ui'},
7
+ `
8
+ import {Label} from '@legacy/ui'
9
+
10
+ <Label />
11
+ `,
12
+ `
13
+ import {Eyebrow} from "@sanity/ui"
14
+
15
+ <Eyebrow as="div" trim={true} />
16
+ `,
17
+ 'updates Eyebrow import path based on fromPackage and toPackage',
18
+ )
19
+
20
+ defineInlineTest(
21
+ transform,
22
+ {},
23
+ `
24
+ <Label />
25
+ `,
26
+ `
27
+ <Eyebrow as="div" trim={true} />
28
+ `,
29
+ 'adds trim prop',
30
+ )
31
+
32
+ defineInlineTest(
33
+ transform,
34
+ {},
35
+ `
36
+ <Label />
37
+ `,
38
+ `
39
+ <Eyebrow as="div" trim={true} />
40
+ `,
41
+ 'adds as prop',
42
+ )
43
+
44
+ defineInlineTest(
45
+ transform,
46
+ {},
47
+ `
48
+ <Label as="span" />
49
+ `,
50
+ `
51
+ <Eyebrow as="span" trim={true} />
52
+ `,
53
+ 'does not add as prop if already set',
54
+ )
55
+
56
+ defineInlineTest(
57
+ transform,
58
+ {},
59
+ `
60
+ <Label flex="auto" />
61
+ `,
62
+ `
63
+ <Eyebrow
64
+ style={{
65
+ flex: "1 1 auto"
66
+ }}
67
+ as="div"
68
+ trim={true} />
69
+ `,
70
+ 'moves flex prop to style',
71
+ )
72
+
73
+ defineInlineTest(
74
+ transform,
75
+ {},
76
+ `
77
+ <Label accent />
78
+ `,
79
+ `
80
+ <Eyebrow tone="suggest" as="div" trim={true} />
81
+ `,
82
+ 'renames accent prop and updates mapped values',
83
+ )
84
+
85
+ defineInlineTest(
86
+ transform,
87
+ {},
88
+ `
89
+ <Label textOverflow="ellipsis" />
90
+ `,
91
+ `
92
+ <Eyebrow truncate={1} as="div" trim={true} />
93
+ `,
94
+ 'renames textOverflow prop and updates mapped values',
95
+ )
96
+
97
+ defineInlineTest(
98
+ transform,
99
+ {},
100
+ `
101
+ <Label width={1} maxWidth="fill" />
102
+ `,
103
+ `
104
+ <Eyebrow
105
+ style={{
106
+ width: "40rem",
107
+ maxWidth: "100%"
108
+ }}
109
+ as="div"
110
+ trim={true} />
111
+ `,
112
+ 'moves width props to style and updates mapped value',
113
+ )
@@ -0,0 +1,67 @@
1
+ import {type API, type FileInfo} from 'jscodeshift'
2
+
3
+ import type {BaseOptions} from '../../../types/BaseOptions'
4
+ import {addAttribute} from '../../../utils/addAttribute'
5
+ import {getComponentLocalNames} from '../../../utils/getComponentLocalNames'
6
+ import {replaceElement} from '../../../utils/replaceElement'
7
+ import {shouldTransformComponent} from '../../../utils/shouldTransformComponent'
8
+ import {transformAttributes} from '../../../utils/transformAttributes'
9
+ import {transformComponent} from '../../../utils/transformComponent'
10
+ import {transformImport} from '../../../utils/transformImport'
11
+ import {LABEL_MODS} from './label.mods'
12
+
13
+ const TODO_WARNING = 'Please double check the Label migration below'
14
+
15
+ /** @internal */
16
+ export default function transform(
17
+ fileInfo: FileInfo,
18
+ api: API,
19
+ options: BaseOptions,
20
+ ): string | undefined {
21
+ const {fromPackage, toPackage} = options || {}
22
+
23
+ return transformComponent(fileInfo, api, ({j, root, markChanged}) => {
24
+ const localNames = getComponentLocalNames(j, root, 'Label', options)
25
+
26
+ if (!shouldTransformComponent(j, root, 'Label', localNames, options)) {
27
+ return
28
+ }
29
+
30
+ if (transformImport(j, root, 'Label', fromPackage, toPackage)) {
31
+ markChanged()
32
+ }
33
+
34
+ if (
35
+ replaceElement(
36
+ j,
37
+ root,
38
+ () => true,
39
+ {
40
+ element: 'Label',
41
+ },
42
+ {
43
+ element: 'Eyebrow',
44
+ callback: (path) => {
45
+ let changed = false
46
+
47
+ if (transformAttributes(j, path, LABEL_MODS, TODO_WARNING)) {
48
+ changed = true
49
+ }
50
+
51
+ if (addAttribute(j, path.node, 'as', 'div')) {
52
+ changed = true
53
+ }
54
+
55
+ if (addAttribute(j, path.node, 'trim', true)) {
56
+ changed = true
57
+ }
58
+
59
+ return changed
60
+ },
61
+ },
62
+ )
63
+ ) {
64
+ markChanged()
65
+ }
66
+ })
67
+ }
@@ -0,0 +1,12 @@
1
+ import type {AttributeMods} from '../../../types/AttributeMods'
2
+
3
+ /** @internal */
4
+ export const STACK_MODS: AttributeMods = {
5
+ sizing: {
6
+ type: 'remove',
7
+ },
8
+ space: {
9
+ type: 'rename-only',
10
+ name: 'gap',
11
+ },
12
+ }
@@ -0,0 +1,160 @@
1
+ import {defineInlineTest} from '../../../utils/testUtils'
2
+ import transform from './stack'
3
+
4
+ defineInlineTest(
5
+ transform,
6
+ {fromPackage: '@legacy/ui', toPackage: '@sanity/ui'},
7
+ `
8
+ import {Stack} from '@legacy/ui'
9
+
10
+ <Stack />
11
+ `,
12
+ `
13
+ import {VStack} from "@sanity/ui"
14
+
15
+ <VStack />
16
+ `,
17
+ 'renames Stack and updates import path based on fromPackage and toPackage',
18
+ )
19
+
20
+ defineInlineTest(
21
+ transform,
22
+ {fromPackage: '@legacy/ui', toPackage: '@sanity/ui'},
23
+ `
24
+ import {Stack} from '@legacy/ui'
25
+
26
+ <Stack padding={2} />
27
+ `,
28
+ `
29
+ import {Flex} from "@sanity/ui"
30
+
31
+ <Flex padding={2} flexDirection="column" />
32
+ `,
33
+ 'replaces Stack with Flex and updates import path based on fromPackage and toPackage',
34
+ )
35
+
36
+ defineInlineTest(
37
+ transform,
38
+ {fromPackage: '@legacy/ui', toPackage: '@sanity/ui'},
39
+ `
40
+ import {Stack, Text} from '@legacy/ui'
41
+
42
+ <Stack />
43
+ `,
44
+ `
45
+ import { Text } from '@legacy/ui';
46
+
47
+ import { VStack } from "@sanity/ui";
48
+
49
+ <VStack />
50
+ `,
51
+ 'renames Stack and updates import path with multiple specifiers',
52
+ )
53
+
54
+ defineInlineTest(
55
+ transform,
56
+ {fromPackage: '@legacy/ui', toPackage: '@sanity/ui'},
57
+ `
58
+ import {Stack, Text} from '@legacy/ui'
59
+
60
+ <Stack margin={2} />
61
+ `,
62
+ `
63
+ import { Text } from '@legacy/ui';
64
+
65
+ import { Flex } from "@sanity/ui";
66
+
67
+ <Flex margin={2} flexDirection="column" />
68
+ `,
69
+ 'replaces Stack and updates import path with multiple specifiers',
70
+ )
71
+
72
+ defineInlineTest(
73
+ transform,
74
+ {},
75
+ `
76
+ <Stack gap={2} />
77
+ `,
78
+ `
79
+ <VStack gap={2} />
80
+ `,
81
+ 'renames Stack with gap',
82
+ )
83
+
84
+ defineInlineTest(
85
+ transform,
86
+ {},
87
+ `
88
+ <Stack space={2} sizing="border" />
89
+ `,
90
+ `
91
+ <VStack gap={2} />
92
+ `,
93
+ 'renames Stack and transforms attributes',
94
+ )
95
+
96
+ defineInlineTest(
97
+ transform,
98
+ {},
99
+ `
100
+ import {Stack} from '@sanity/ui'
101
+
102
+ <>
103
+ <Stack />
104
+ <Stack overflow="auto" />
105
+ </>
106
+ `,
107
+ `
108
+ import { Flex, VStack } from '@sanity/ui';
109
+
110
+ <>
111
+ <VStack />
112
+ <Flex overflow="auto" flexDirection="column" />
113
+ </>
114
+ `,
115
+ 'replaces Stack with Flex and adds Flex import',
116
+ )
117
+
118
+ defineInlineTest(
119
+ transform,
120
+ {},
121
+ `
122
+ import {Stack} from '@sanity/ui'
123
+
124
+ <Stack padding={1} />
125
+ `,
126
+ `
127
+ import {Flex} from '@sanity/ui'
128
+
129
+ <Flex padding={1} flexDirection="column" />
130
+ `,
131
+ 'replaces Stack with Flex and removes Stack import',
132
+ )
133
+
134
+ defineInlineTest(
135
+ transform,
136
+ {},
137
+ `
138
+ <Stack padding={1}>
139
+ <span />
140
+ </Stack>
141
+ `,
142
+ `
143
+ <Flex padding={1} flexDirection="column">
144
+ <span />
145
+ </Flex>
146
+ `,
147
+ 'replaces Stack with Flex and updates closing tag',
148
+ )
149
+
150
+ defineInlineTest(
151
+ transform,
152
+ {},
153
+ `
154
+ <Stack padding={1} width="fill" />
155
+ `,
156
+ `
157
+ <Flex padding={1} width="100%" flexDirection="column" />
158
+ `,
159
+ 'replaces Stack with Flex and transforms attributes',
160
+ )
@@ -0,0 +1,102 @@
1
+ import {type API, type FileInfo, type JSXElement} from 'jscodeshift'
2
+
3
+ import type {BaseOptions} from '../../../types/BaseOptions'
4
+ import {addAttribute} from '../../../utils/addAttribute'
5
+ import {getComponentLocalNames} from '../../../utils/getComponentLocalNames'
6
+ import {replaceElement} from '../../../utils/replaceElement'
7
+ import {shouldTransformComponent} from '../../../utils/shouldTransformComponent'
8
+ import {transformAttributes} from '../../../utils/transformAttributes'
9
+ import {transformComponent} from '../../../utils/transformComponent'
10
+ import {transformImport} from '../../../utils/transformImport'
11
+ import {FLEX_MODS} from '../flex/flex.mods'
12
+ import {STACK_MODS} from './stack.mods'
13
+
14
+ const STACK_TODO_WARNING = 'Please double check the Stack migration below'
15
+ const FLEX_TODO_WARNING = 'Please double check the Flex migration below'
16
+
17
+ function hasFlexAttrs(attrs: JSXElement['openingElement']['attributes']) {
18
+ if (!attrs) {
19
+ return false
20
+ }
21
+
22
+ return attrs.some(
23
+ (attr) =>
24
+ attr.type === 'JSXAttribute' &&
25
+ attr.name.type === 'JSXIdentifier' &&
26
+ (attr.name.name.startsWith('padding') ||
27
+ attr.name.name.startsWith('margin') ||
28
+ attr.name.name.startsWith('overflow') ||
29
+ attr.name.name.startsWith('flex')),
30
+ )
31
+ }
32
+
33
+ /** @internal */
34
+ export default function transform(
35
+ fileInfo: FileInfo,
36
+ api: API,
37
+ options?: BaseOptions,
38
+ ): string | undefined {
39
+ const {fromPackage, toPackage} = options || {}
40
+
41
+ return transformComponent(fileInfo, api, ({j, root, markChanged}) => {
42
+ const localNames = getComponentLocalNames(j, root, 'Stack', options)
43
+
44
+ if (!shouldTransformComponent(j, root, 'Stack', localNames, options)) {
45
+ return
46
+ }
47
+
48
+ if (transformImport(j, root, 'Stack', fromPackage, toPackage)) {
49
+ markChanged()
50
+ }
51
+
52
+ if (
53
+ replaceElement(
54
+ j,
55
+ root,
56
+ (attrs) => {
57
+ return hasFlexAttrs(attrs)
58
+ },
59
+ {
60
+ element: 'Stack',
61
+ },
62
+ {
63
+ element: 'Flex',
64
+ callback: (path) => {
65
+ let changed = false
66
+
67
+ if (addAttribute(j, path.node, 'flexDirection', 'column')) {
68
+ changed = true
69
+ }
70
+
71
+ if (transformAttributes(j, path, FLEX_MODS, FLEX_TODO_WARNING)) {
72
+ changed = true
73
+ }
74
+
75
+ return changed
76
+ },
77
+ },
78
+ )
79
+ ) {
80
+ markChanged()
81
+ }
82
+
83
+ if (
84
+ replaceElement(
85
+ j,
86
+ root,
87
+ (attrs) => {
88
+ return !hasFlexAttrs(attrs)
89
+ },
90
+ {
91
+ element: 'Stack',
92
+ },
93
+ {
94
+ element: 'VStack',
95
+ callback: (path) => transformAttributes(j, path, STACK_MODS, STACK_TODO_WARNING),
96
+ },
97
+ )
98
+ ) {
99
+ markChanged()
100
+ }
101
+ })
102
+ }