@planningcenter/tapestry-migration-cli 3.4.1-rc.9 → 3.5.0
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/README.md +22 -0
- package/dist/tapestry-react-shim.cjs +5 -1
- package/package.json +3 -3
- package/src/availableComponents.ts +13 -0
- package/src/components/dropdown/index.test.ts +244 -4
- package/src/components/dropdown/index.ts +28 -2
- package/src/components/dropdown/transforms/auditSpreadProps.test.ts +110 -0
- package/src/components/dropdown/transforms/auditSpreadProps.ts +10 -0
- package/src/components/dropdown/transforms/dividerToSeparator.test.ts +134 -0
- package/src/components/dropdown/transforms/dividerToSeparator.ts +67 -0
- package/src/components/dropdown/transforms/itemToAction.test.ts +19 -1
- package/src/components/dropdown/transforms/itemToAction.ts +14 -2
- package/src/components/dropdown/transforms/linkToLink.test.ts +19 -1
- package/src/components/dropdown/transforms/linkToLink.ts +13 -2
- package/src/components/dropdown/transforms/moveDropdownImport.test.ts +93 -0
- package/src/components/dropdown/transforms/moveDropdownImport.ts +13 -0
- package/src/components/dropdown/transforms/placementIdToMenu.test.ts +140 -0
- package/src/components/dropdown/transforms/placementIdToMenu.ts +96 -0
- package/src/components/dropdown/transforms/unsupportedProps.test.ts +145 -0
- package/src/components/dropdown/transforms/unsupportedProps.ts +12 -0
- package/src/components/dropdown/transforms/unsupportedPropsDivider.test.ts +143 -0
- package/src/components/dropdown/transforms/unsupportedPropsDivider.ts +26 -0
- package/src/components/dropdown/transforms/unsupportedPropsItem.test.ts +123 -0
- package/src/components/dropdown/transforms/unsupportedPropsItem.ts +12 -0
- package/src/components/dropdown/transforms/unsupportedPropsLink.test.ts +107 -0
- package/src/components/dropdown/transforms/unsupportedPropsLink.ts +12 -0
- package/src/components/dropdown/transforms/variantToKind.test.ts +292 -0
- package/src/components/dropdown/transforms/variantToKind.ts +138 -0
- package/src/components/dropdown/transforms/wrapIconTrigger.test.ts +336 -0
- package/src/components/dropdown/transforms/wrapIconTrigger.ts +233 -0
- package/src/components/dropdown/transforms/wrapMenu.test.ts +153 -0
- package/src/components/dropdown/transforms/wrapMenu.ts +54 -0
- package/src/components/dropdown/transforms/wrapTrigger.test.ts +283 -0
- package/src/components/dropdown/transforms/wrapTrigger.ts +98 -0
- package/src/components/input/transforms/unsupportedProps.test.ts +14 -13
- package/src/components/shared/conditions/isChildOf.test.ts +89 -0
- package/src/components/shared/conditions/isChildOf.ts +43 -0
- package/src/components/shared/helpers/unsupportedPropsHelpers.ts +36 -0
- package/src/index.ts +5 -18
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@planningcenter/tapestry-migration-cli",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.5.0",
|
|
4
4
|
"description": "CLI tool for Tapestry migrations",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
},
|
|
31
31
|
"devDependencies": {
|
|
32
32
|
"@emotion/react": "^11.14.0",
|
|
33
|
-
"@planningcenter/tapestry": "^3.
|
|
33
|
+
"@planningcenter/tapestry": "^3.5.0",
|
|
34
34
|
"@planningcenter/tapestry-react": "^4.11.5",
|
|
35
35
|
"@types/jscodeshift": "^17.3.0",
|
|
36
36
|
"@types/node": "^20.0.0",
|
|
@@ -50,5 +50,5 @@
|
|
|
50
50
|
"publishConfig": {
|
|
51
51
|
"access": "public"
|
|
52
52
|
},
|
|
53
|
-
"gitHead": "
|
|
53
|
+
"gitHead": "958f1f269ca37d78e9a9c0ec66c208a7115331dc"
|
|
54
54
|
}
|
|
@@ -40,7 +40,7 @@ import { Dropdown } from "@planningcenter/tapestry-react"
|
|
|
40
40
|
|
|
41
41
|
export default function Test() {
|
|
42
42
|
return (
|
|
43
|
-
<Dropdown
|
|
43
|
+
<Dropdown onClose={handleClose}>
|
|
44
44
|
<Dropdown.Item onSelect={fn}>Edit</Dropdown.Item>
|
|
45
45
|
</Dropdown>
|
|
46
46
|
)
|
|
@@ -53,12 +53,252 @@ export default function Test() {
|
|
|
53
53
|
expect(result).not.toContain("Dropdown.Item")
|
|
54
54
|
})
|
|
55
55
|
|
|
56
|
-
it("
|
|
56
|
+
it("applies wrapMenu through the chain", () => {
|
|
57
|
+
const input = `
|
|
58
|
+
import { Dropdown } from "@planningcenter/tapestry-react"
|
|
59
|
+
|
|
60
|
+
export default function Test() {
|
|
61
|
+
return (
|
|
62
|
+
<Dropdown onClose={handleClose}>
|
|
63
|
+
<Dropdown.Item onSelect={fn}>Edit</Dropdown.Item>
|
|
64
|
+
</Dropdown>
|
|
65
|
+
)
|
|
66
|
+
}
|
|
67
|
+
`.trim()
|
|
68
|
+
|
|
69
|
+
const result = applyTransform(input)
|
|
70
|
+
expect(result).toContain("<DropdownMenu>")
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
it("applies placementIdToMenu through the chain", () => {
|
|
74
|
+
const input = `
|
|
75
|
+
import { Dropdown } from "@planningcenter/tapestry-react"
|
|
76
|
+
|
|
77
|
+
export default function Test() {
|
|
78
|
+
return (
|
|
79
|
+
<Dropdown placement="bottom-end">
|
|
80
|
+
<DropdownMenu>
|
|
81
|
+
<Dropdown.Item onSelect={fn}>Edit</Dropdown.Item>
|
|
82
|
+
</DropdownMenu>
|
|
83
|
+
</Dropdown>
|
|
84
|
+
)
|
|
85
|
+
}
|
|
86
|
+
`.trim()
|
|
87
|
+
|
|
88
|
+
const result = applyTransform(input)
|
|
89
|
+
expect(result).toContain('<DropdownMenu placement="bottom end"')
|
|
90
|
+
expect(result).not.toMatch(/<Dropdown\s[^>]*placement/)
|
|
91
|
+
})
|
|
92
|
+
|
|
93
|
+
it("applies wrapTrigger through the chain", () => {
|
|
57
94
|
const input = `
|
|
58
95
|
import { Dropdown } from "@planningcenter/tapestry-react"
|
|
59
96
|
|
|
60
|
-
export default function Test(
|
|
61
|
-
return
|
|
97
|
+
export default function Test() {
|
|
98
|
+
return (
|
|
99
|
+
<Dropdown title="Actions">
|
|
100
|
+
<Dropdown.Item onSelect={fn}>Edit</Dropdown.Item>
|
|
101
|
+
</Dropdown>
|
|
102
|
+
)
|
|
103
|
+
}
|
|
104
|
+
`.trim()
|
|
105
|
+
|
|
106
|
+
const result = applyTransform(input)
|
|
107
|
+
expect(result).toContain("<DropdownTrigger>")
|
|
108
|
+
expect(result).toContain('<DropdownButton label="Actions"')
|
|
109
|
+
expect(result).not.toContain('title="Actions"')
|
|
110
|
+
})
|
|
111
|
+
|
|
112
|
+
it("applies unsupportedPropsDivider through the chain", () => {
|
|
113
|
+
const input = `
|
|
114
|
+
import { Dropdown, Divider } from "@planningcenter/tapestry-react"
|
|
115
|
+
|
|
116
|
+
export default function Test() {
|
|
117
|
+
return <Dropdown><Divider axis="vertical" /></Dropdown>
|
|
118
|
+
}
|
|
119
|
+
`.trim()
|
|
120
|
+
|
|
121
|
+
const result = applyTransform(input)
|
|
122
|
+
expect(result).toContain("TODO: tapestry-migration (axis)")
|
|
123
|
+
})
|
|
124
|
+
|
|
125
|
+
it("applies dividerToSeparator through the chain", () => {
|
|
126
|
+
const input = `
|
|
127
|
+
import { Dropdown, Divider } from "@planningcenter/tapestry-react"
|
|
128
|
+
|
|
129
|
+
export default function Test() {
|
|
130
|
+
return <Dropdown><Divider /></Dropdown>
|
|
131
|
+
}
|
|
132
|
+
`.trim()
|
|
133
|
+
|
|
134
|
+
const result = applyTransform(input)
|
|
135
|
+
expect(result).toContain("<DropdownSeparator")
|
|
136
|
+
expect(result).not.toContain("<Divider")
|
|
137
|
+
})
|
|
138
|
+
|
|
139
|
+
it("applies unsupportedPropsItem through the chain", () => {
|
|
140
|
+
const input = `
|
|
141
|
+
import { Dropdown } from "@planningcenter/tapestry-react"
|
|
142
|
+
|
|
143
|
+
export default function Test() {
|
|
144
|
+
return (
|
|
145
|
+
<Dropdown title="Actions">
|
|
146
|
+
<Dropdown.Item as={Link} onSelect={fn}>Edit</Dropdown.Item>
|
|
147
|
+
</Dropdown>
|
|
148
|
+
)
|
|
149
|
+
}
|
|
150
|
+
`.trim()
|
|
151
|
+
|
|
152
|
+
const result = applyTransform(input)
|
|
153
|
+
expect(result).toContain("TODO: tapestry-migration (as)")
|
|
154
|
+
})
|
|
155
|
+
|
|
156
|
+
it("applies unsupportedPropsLink through the chain", () => {
|
|
157
|
+
const input = `
|
|
158
|
+
import { Dropdown } from "@planningcenter/tapestry-react"
|
|
159
|
+
|
|
160
|
+
export default function Test() {
|
|
161
|
+
return (
|
|
162
|
+
<Dropdown title="Actions">
|
|
163
|
+
<Dropdown.Link to="/edit" disabled>Edit</Dropdown.Link>
|
|
164
|
+
</Dropdown>
|
|
165
|
+
)
|
|
166
|
+
}
|
|
167
|
+
`.trim()
|
|
168
|
+
|
|
169
|
+
const result = applyTransform(input)
|
|
170
|
+
expect(result).toContain("TODO: tapestry-migration (disabled)")
|
|
171
|
+
})
|
|
172
|
+
|
|
173
|
+
it("applies auditSpreadProps through the chain", () => {
|
|
174
|
+
const input = `
|
|
175
|
+
import { Dropdown } from "@planningcenter/tapestry-react"
|
|
176
|
+
|
|
177
|
+
export default function Test() {
|
|
178
|
+
return (
|
|
179
|
+
<Dropdown {...props} title="Actions">
|
|
180
|
+
<Dropdown.Item onSelect={fn}>Edit</Dropdown.Item>
|
|
181
|
+
</Dropdown>
|
|
182
|
+
)
|
|
183
|
+
}
|
|
184
|
+
`.trim()
|
|
185
|
+
|
|
186
|
+
const result = applyTransform(input)
|
|
187
|
+
expect(result).toContain("TODO: tapestry-migration (spreadAttribute)")
|
|
188
|
+
})
|
|
189
|
+
|
|
190
|
+
it("applies unsupportedProps through the chain", () => {
|
|
191
|
+
const input = `
|
|
192
|
+
import { Dropdown } from "@planningcenter/tapestry-react"
|
|
193
|
+
|
|
194
|
+
export default function Test() {
|
|
195
|
+
return <Dropdown variant="outline" onClose={fn}><Dropdown.Item onSelect={fn}>Edit</Dropdown.Item></Dropdown>
|
|
196
|
+
}
|
|
197
|
+
`.trim()
|
|
198
|
+
|
|
199
|
+
const result = applyTransform(input)
|
|
200
|
+
expect(result).toContain("TODO: tapestry-migration (variant)")
|
|
201
|
+
})
|
|
202
|
+
|
|
203
|
+
it("applies wrapIconTrigger through the chain", () => {
|
|
204
|
+
const input = `
|
|
205
|
+
import { Dropdown } from "@planningcenter/tapestry-react"
|
|
206
|
+
|
|
207
|
+
export default function Test() {
|
|
208
|
+
return (
|
|
209
|
+
<Dropdown icon={{ name: "general.pencil" }} title="Edit options">
|
|
210
|
+
<Dropdown.Item onSelect={fn}>Edit</Dropdown.Item>
|
|
211
|
+
</Dropdown>
|
|
212
|
+
)
|
|
213
|
+
}
|
|
214
|
+
`.trim()
|
|
215
|
+
|
|
216
|
+
const result = applyTransform(input)
|
|
217
|
+
expect(result).toContain("<DropdownTrigger>")
|
|
218
|
+
expect(result).toContain("<DropdownIconButton")
|
|
219
|
+
expect(result).toContain('aria-label="Edit options"')
|
|
220
|
+
expect(result).toContain("#pencil")
|
|
221
|
+
expect(result).not.toContain("icon={{ name:")
|
|
222
|
+
expect(result).not.toContain('title="Edit options"')
|
|
223
|
+
expect(result).not.toContain('from "@planningcenter/tapestry-react"')
|
|
224
|
+
})
|
|
225
|
+
|
|
226
|
+
it("applies variantToKind through the chain (variant)", () => {
|
|
227
|
+
const input = `
|
|
228
|
+
import { Dropdown } from "@planningcenter/tapestry-react"
|
|
229
|
+
|
|
230
|
+
export default function Test() {
|
|
231
|
+
return (
|
|
232
|
+
<Dropdown title="Actions" variant="outline">
|
|
233
|
+
<Dropdown.Item onSelect={fn}>Edit</Dropdown.Item>
|
|
234
|
+
</Dropdown>
|
|
235
|
+
)
|
|
236
|
+
}
|
|
237
|
+
`.trim()
|
|
238
|
+
|
|
239
|
+
const result = applyTransform(input)
|
|
240
|
+
expect(result).toContain('kind="secondary"')
|
|
241
|
+
expect(result).not.toContain('variant="outline"')
|
|
242
|
+
const dropdownButtonLine = result
|
|
243
|
+
?.split("\n")
|
|
244
|
+
.find((l) => l.includes("<DropdownButton"))
|
|
245
|
+
expect(dropdownButtonLine).toContain("kind")
|
|
246
|
+
})
|
|
247
|
+
|
|
248
|
+
it("applies variantToKind through the chain (theme)", () => {
|
|
249
|
+
const input = `
|
|
250
|
+
import { Dropdown } from "@planningcenter/tapestry-react"
|
|
251
|
+
|
|
252
|
+
export default function Test() {
|
|
253
|
+
return (
|
|
254
|
+
<Dropdown title="Actions" theme="error">
|
|
255
|
+
<Dropdown.Item onSelect={fn}>Edit</Dropdown.Item>
|
|
256
|
+
</Dropdown>
|
|
257
|
+
)
|
|
258
|
+
}
|
|
259
|
+
`.trim()
|
|
260
|
+
|
|
261
|
+
const result = applyTransform(input)
|
|
262
|
+
expect(result).toContain('kind="delete"')
|
|
263
|
+
expect(result).not.toContain('theme="error"')
|
|
264
|
+
const dropdownButtonLine = result
|
|
265
|
+
?.split("\n")
|
|
266
|
+
.find((l) => l.includes("<DropdownButton"))
|
|
267
|
+
expect(dropdownButtonLine).toContain("kind")
|
|
268
|
+
})
|
|
269
|
+
|
|
270
|
+
it("applies moveDropdownImport through the chain", () => {
|
|
271
|
+
const input = `
|
|
272
|
+
import { Dropdown } from "@planningcenter/tapestry-react"
|
|
273
|
+
|
|
274
|
+
export default function Test() {
|
|
275
|
+
return (
|
|
276
|
+
<Dropdown onClose={fn}>
|
|
277
|
+
<DropdownTrigger><DropdownButton label="Actions" /></DropdownTrigger>
|
|
278
|
+
<DropdownMenu><DropdownAction onAction={fn}>Edit</DropdownAction></DropdownMenu>
|
|
279
|
+
</Dropdown>
|
|
280
|
+
)
|
|
281
|
+
}
|
|
282
|
+
`.trim()
|
|
283
|
+
|
|
284
|
+
const result = applyTransform(input)
|
|
285
|
+
expect(result).toContain('from "@planningcenter/tapestry"')
|
|
286
|
+
expect(result).not.toContain('from "@planningcenter/tapestry-react"')
|
|
287
|
+
})
|
|
288
|
+
|
|
289
|
+
it("returns null when there is nothing to transform", () => {
|
|
290
|
+
const input = `
|
|
291
|
+
import { Dropdown } from "@planningcenter/tapestry"
|
|
292
|
+
|
|
293
|
+
export default function Test() {
|
|
294
|
+
return (
|
|
295
|
+
<Dropdown onClose={handleClose}>
|
|
296
|
+
<DropdownTrigger><DropdownButton label="Actions" /></DropdownTrigger>
|
|
297
|
+
<DropdownMenu>
|
|
298
|
+
<DropdownAction onAction={fn}>Edit</DropdownAction>
|
|
299
|
+
</DropdownMenu>
|
|
300
|
+
</Dropdown>
|
|
301
|
+
)
|
|
62
302
|
}
|
|
63
303
|
`.trim()
|
|
64
304
|
|
|
@@ -1,14 +1,40 @@
|
|
|
1
1
|
import { Transform } from "jscodeshift"
|
|
2
2
|
|
|
3
|
+
import auditSpreadProps from "./transforms/auditSpreadProps"
|
|
4
|
+
import dividerToSeparator from "./transforms/dividerToSeparator"
|
|
3
5
|
import itemToAction from "./transforms/itemToAction"
|
|
4
6
|
import linkToLink from "./transforms/linkToLink"
|
|
7
|
+
import moveDropdownImport from "./transforms/moveDropdownImport"
|
|
8
|
+
import placementIdToMenu from "./transforms/placementIdToMenu"
|
|
9
|
+
import unsupportedProps from "./transforms/unsupportedProps"
|
|
10
|
+
import unsupportedPropsDivider from "./transforms/unsupportedPropsDivider"
|
|
11
|
+
import unsupportedPropsItem from "./transforms/unsupportedPropsItem"
|
|
12
|
+
import unsupportedPropsLink from "./transforms/unsupportedPropsLink"
|
|
13
|
+
import variantToKind from "./transforms/variantToKind"
|
|
14
|
+
import wrapIconTrigger from "./transforms/wrapIconTrigger"
|
|
15
|
+
import wrapMenu from "./transforms/wrapMenu"
|
|
16
|
+
import wrapTrigger from "./transforms/wrapTrigger"
|
|
5
17
|
|
|
6
|
-
// When moveDropdownImport is added, it must remain last in the chain.
|
|
7
18
|
const transform: Transform = (fileInfo, api, options) => {
|
|
8
19
|
let currentSource = fileInfo.source
|
|
9
20
|
let hasAnyChanges = false
|
|
10
21
|
|
|
11
|
-
const transforms: Transform[] = [
|
|
22
|
+
const transforms: Transform[] = [
|
|
23
|
+
unsupportedPropsItem,
|
|
24
|
+
unsupportedPropsLink,
|
|
25
|
+
unsupportedPropsDivider,
|
|
26
|
+
itemToAction,
|
|
27
|
+
linkToLink,
|
|
28
|
+
wrapMenu,
|
|
29
|
+
placementIdToMenu,
|
|
30
|
+
wrapIconTrigger,
|
|
31
|
+
wrapTrigger,
|
|
32
|
+
variantToKind,
|
|
33
|
+
dividerToSeparator,
|
|
34
|
+
auditSpreadProps,
|
|
35
|
+
unsupportedProps,
|
|
36
|
+
moveDropdownImport,
|
|
37
|
+
]
|
|
12
38
|
|
|
13
39
|
for (const individualTransform of transforms) {
|
|
14
40
|
const result = individualTransform(
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import jscodeshift from "jscodeshift"
|
|
2
|
+
import { describe, expect, it } from "vitest"
|
|
3
|
+
|
|
4
|
+
import transform from "./auditSpreadProps"
|
|
5
|
+
|
|
6
|
+
const j = jscodeshift.withParser("tsx")
|
|
7
|
+
|
|
8
|
+
const AUDIT_COMMENT =
|
|
9
|
+
"TODO: tapestry-migration (spreadAttribute): Spread props can contain unsupported props, please explore usages and migrate as needed."
|
|
10
|
+
|
|
11
|
+
function applyTransform(source: string): string | null {
|
|
12
|
+
const fileInfo = { path: "test.tsx", source }
|
|
13
|
+
return transform(
|
|
14
|
+
fileInfo,
|
|
15
|
+
{ j, jscodeshift: j, report: () => {}, stats: () => {} },
|
|
16
|
+
{}
|
|
17
|
+
) as string | null
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
describe("auditSpreadProps transform", () => {
|
|
21
|
+
it("adds a comment to Dropdown with spread props", () => {
|
|
22
|
+
const input = `
|
|
23
|
+
import { Dropdown } from "@planningcenter/tapestry-react"
|
|
24
|
+
|
|
25
|
+
export default function Test() {
|
|
26
|
+
const props = { onClose: handleClose }
|
|
27
|
+
return (
|
|
28
|
+
<Dropdown {...props} title="Actions">
|
|
29
|
+
<Dropdown.Item onSelect={fn}>Edit</Dropdown.Item>
|
|
30
|
+
</Dropdown>
|
|
31
|
+
)
|
|
32
|
+
}
|
|
33
|
+
`.trim()
|
|
34
|
+
|
|
35
|
+
const result = applyTransform(input)
|
|
36
|
+
expect(result).toContain(AUDIT_COMMENT)
|
|
37
|
+
expect(result).toContain("{...props}")
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
it("adds a comment for each spread", () => {
|
|
41
|
+
const input = `
|
|
42
|
+
import { Dropdown } from "@planningcenter/tapestry-react"
|
|
43
|
+
|
|
44
|
+
export default function Test() {
|
|
45
|
+
return (
|
|
46
|
+
<Dropdown {...baseProps} {...extraProps} title="Actions">
|
|
47
|
+
<Dropdown.Item onSelect={fn}>Edit</Dropdown.Item>
|
|
48
|
+
</Dropdown>
|
|
49
|
+
)
|
|
50
|
+
}
|
|
51
|
+
`.trim()
|
|
52
|
+
|
|
53
|
+
const result = applyTransform(input)
|
|
54
|
+
const commentCount = (result?.match(/spreadAttribute/g) || []).length
|
|
55
|
+
expect(commentCount).toBe(2)
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
it("preserves all other attributes", () => {
|
|
59
|
+
const input = `
|
|
60
|
+
import { Dropdown } from "@planningcenter/tapestry-react"
|
|
61
|
+
|
|
62
|
+
export default function Test() {
|
|
63
|
+
return (
|
|
64
|
+
<Dropdown title="Actions" placement="bottom-start" {...props}>
|
|
65
|
+
<Dropdown.Item onSelect={fn}>Edit</Dropdown.Item>
|
|
66
|
+
</Dropdown>
|
|
67
|
+
)
|
|
68
|
+
}
|
|
69
|
+
`.trim()
|
|
70
|
+
|
|
71
|
+
const result = applyTransform(input)
|
|
72
|
+
expect(result).toContain('title="Actions"')
|
|
73
|
+
expect(result).toContain('placement="bottom-start"')
|
|
74
|
+
expect(result).toContain("{...props}")
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
describe("no changes scenarios", () => {
|
|
78
|
+
it("returns null when no spread props", () => {
|
|
79
|
+
const input = `
|
|
80
|
+
import { Dropdown } from "@planningcenter/tapestry-react"
|
|
81
|
+
|
|
82
|
+
export default function Test() {
|
|
83
|
+
return (
|
|
84
|
+
<Dropdown title="Actions">
|
|
85
|
+
<Dropdown.Item onSelect={fn}>Edit</Dropdown.Item>
|
|
86
|
+
</Dropdown>
|
|
87
|
+
)
|
|
88
|
+
}
|
|
89
|
+
`.trim()
|
|
90
|
+
|
|
91
|
+
expect(applyTransform(input)).toBe(null)
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
it("returns null when not imported from tapestry-react", () => {
|
|
95
|
+
const input = `
|
|
96
|
+
import { Dropdown } from "some-other-library"
|
|
97
|
+
|
|
98
|
+
export default function Test() {
|
|
99
|
+
return <Dropdown {...props} title="Actions" />
|
|
100
|
+
}
|
|
101
|
+
`.trim()
|
|
102
|
+
|
|
103
|
+
expect(applyTransform(input)).toBe(null)
|
|
104
|
+
})
|
|
105
|
+
|
|
106
|
+
it("returns null for empty file", () => {
|
|
107
|
+
expect(applyTransform("")).toBe(null)
|
|
108
|
+
})
|
|
109
|
+
})
|
|
110
|
+
})
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Transform } from "jscodeshift"
|
|
2
|
+
|
|
3
|
+
import { commentOnSpreadPropsFactory } from "../../shared/transformFactories/commentOnSpreadPropsFactory"
|
|
4
|
+
|
|
5
|
+
const transform: Transform = commentOnSpreadPropsFactory({
|
|
6
|
+
targetComponent: "Dropdown",
|
|
7
|
+
targetPackage: "@planningcenter/tapestry-react",
|
|
8
|
+
})
|
|
9
|
+
|
|
10
|
+
export default transform
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import jscodeshift from "jscodeshift"
|
|
2
|
+
import { describe, expect, it } from "vitest"
|
|
3
|
+
|
|
4
|
+
import transform from "./dividerToSeparator"
|
|
5
|
+
|
|
6
|
+
const j = jscodeshift.withParser("tsx")
|
|
7
|
+
|
|
8
|
+
function applyTransform(source: string): string | null {
|
|
9
|
+
const fileInfo = { path: "test.tsx", source }
|
|
10
|
+
return transform(
|
|
11
|
+
fileInfo,
|
|
12
|
+
{ j, jscodeshift: j, report: () => {}, stats: () => {} },
|
|
13
|
+
{}
|
|
14
|
+
) as string | null
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
describe("dividerToSeparator transform", () => {
|
|
18
|
+
it("renames Divider to DropdownSeparator when inside a Dropdown", () => {
|
|
19
|
+
const input = `
|
|
20
|
+
import { Dropdown, Divider } from "@planningcenter/tapestry-react"
|
|
21
|
+
|
|
22
|
+
export default function Test() {
|
|
23
|
+
return <Dropdown><Divider /></Dropdown>
|
|
24
|
+
}
|
|
25
|
+
`.trim()
|
|
26
|
+
|
|
27
|
+
const result = applyTransform(input)
|
|
28
|
+
expect(result).toContain("<DropdownSeparator")
|
|
29
|
+
expect(result).not.toContain("<Divider")
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
it("handles non-self-closing Divider inside a Dropdown", () => {
|
|
33
|
+
const input = `
|
|
34
|
+
import { Dropdown, Divider } from "@planningcenter/tapestry-react"
|
|
35
|
+
|
|
36
|
+
export default function Test() {
|
|
37
|
+
return <Dropdown><Divider></Divider></Dropdown>
|
|
38
|
+
}
|
|
39
|
+
`.trim()
|
|
40
|
+
|
|
41
|
+
const result = applyTransform(input)
|
|
42
|
+
expect(result).toContain("<DropdownSeparator>")
|
|
43
|
+
expect(result).toContain("</DropdownSeparator>")
|
|
44
|
+
expect(result).not.toContain("<Divider")
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
it("renames multiple Dividers inside a Dropdown", () => {
|
|
48
|
+
const input = `
|
|
49
|
+
import { Dropdown, Divider } from "@planningcenter/tapestry-react"
|
|
50
|
+
|
|
51
|
+
export default function Test() {
|
|
52
|
+
return (
|
|
53
|
+
<Dropdown>
|
|
54
|
+
<Divider />
|
|
55
|
+
<Divider />
|
|
56
|
+
</Dropdown>
|
|
57
|
+
)
|
|
58
|
+
}
|
|
59
|
+
`.trim()
|
|
60
|
+
|
|
61
|
+
const result = applyTransform(input)
|
|
62
|
+
const count = (result?.match(/<DropdownSeparator/g) || []).length
|
|
63
|
+
expect(count).toBe(2)
|
|
64
|
+
expect(result).not.toContain("<Divider")
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
it("adds DropdownSeparator import from tapestry and removes Divider import when all Dividers are inside a Dropdown", () => {
|
|
68
|
+
const input = `
|
|
69
|
+
import { Dropdown, Divider } from "@planningcenter/tapestry-react"
|
|
70
|
+
|
|
71
|
+
export default function Test() {
|
|
72
|
+
return <Dropdown><Divider /></Dropdown>
|
|
73
|
+
}
|
|
74
|
+
`.trim()
|
|
75
|
+
|
|
76
|
+
const result = applyTransform(input)
|
|
77
|
+
expect(result).toContain('from "@planningcenter/tapestry"')
|
|
78
|
+
expect(result).toContain("DropdownSeparator")
|
|
79
|
+
expect(result).not.toContain(
|
|
80
|
+
'import { Dropdown, Divider } from "@planningcenter/tapestry-react"'
|
|
81
|
+
)
|
|
82
|
+
})
|
|
83
|
+
|
|
84
|
+
it("keeps Divider import when some Dividers are outside a Dropdown", () => {
|
|
85
|
+
const input = `
|
|
86
|
+
import { Dropdown, Divider } from "@planningcenter/tapestry-react"
|
|
87
|
+
|
|
88
|
+
export default function Test() {
|
|
89
|
+
return (
|
|
90
|
+
<div>
|
|
91
|
+
<Divider />
|
|
92
|
+
<Dropdown><Divider /></Dropdown>
|
|
93
|
+
</div>
|
|
94
|
+
)
|
|
95
|
+
}
|
|
96
|
+
`.trim()
|
|
97
|
+
|
|
98
|
+
const result = applyTransform(input)
|
|
99
|
+
expect(result).toContain("DropdownSeparator")
|
|
100
|
+
expect(result).toContain(
|
|
101
|
+
'import { Dropdown, Divider } from "@planningcenter/tapestry-react"'
|
|
102
|
+
)
|
|
103
|
+
})
|
|
104
|
+
|
|
105
|
+
describe("no changes scenarios", () => {
|
|
106
|
+
it("returns null when Divider is not inside a Dropdown", () => {
|
|
107
|
+
const input = `
|
|
108
|
+
import { Divider } from "@planningcenter/tapestry-react"
|
|
109
|
+
|
|
110
|
+
export default function Test() {
|
|
111
|
+
return <Divider />
|
|
112
|
+
}
|
|
113
|
+
`.trim()
|
|
114
|
+
|
|
115
|
+
expect(applyTransform(input)).toBe(null)
|
|
116
|
+
})
|
|
117
|
+
|
|
118
|
+
it("returns null when Divider is not imported from tapestry-react", () => {
|
|
119
|
+
const input = `
|
|
120
|
+
import { Divider } from "some-other-library"
|
|
121
|
+
|
|
122
|
+
export default function Test() {
|
|
123
|
+
return <Divider />
|
|
124
|
+
}
|
|
125
|
+
`.trim()
|
|
126
|
+
|
|
127
|
+
expect(applyTransform(input)).toBe(null)
|
|
128
|
+
})
|
|
129
|
+
|
|
130
|
+
it("returns null for empty file", () => {
|
|
131
|
+
expect(applyTransform("")).toBe(null)
|
|
132
|
+
})
|
|
133
|
+
})
|
|
134
|
+
})
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { Transform } from "jscodeshift"
|
|
2
|
+
|
|
3
|
+
import { transformElementName } from "../../shared/actions/transformElementName"
|
|
4
|
+
import { isChildOf } from "../../shared/conditions/isChildOf"
|
|
5
|
+
import { attributeTransformFactory } from "../../shared/transformFactories/attributeTransformFactory"
|
|
6
|
+
import {
|
|
7
|
+
addImport,
|
|
8
|
+
getImportName,
|
|
9
|
+
removeImportFromDeclaration,
|
|
10
|
+
} from "../../shared/transformFactories/helpers/manageImports"
|
|
11
|
+
|
|
12
|
+
const transform: Transform = (fileInfo, api, options) => {
|
|
13
|
+
const j = api.jscodeshift
|
|
14
|
+
const source = j(fileInfo.source)
|
|
15
|
+
|
|
16
|
+
const dropdownLocalName = getImportName(
|
|
17
|
+
"Dropdown",
|
|
18
|
+
"@planningcenter/tapestry-react",
|
|
19
|
+
{ j, source }
|
|
20
|
+
)
|
|
21
|
+
if (!dropdownLocalName) return null
|
|
22
|
+
|
|
23
|
+
const result = attributeTransformFactory({
|
|
24
|
+
condition: isChildOf(dropdownLocalName, source, j),
|
|
25
|
+
targetComponent: "Divider",
|
|
26
|
+
targetPackage: "@planningcenter/tapestry-react",
|
|
27
|
+
transform: (element) =>
|
|
28
|
+
transformElementName({ element, name: "DropdownSeparator" }),
|
|
29
|
+
})(fileInfo, api, options)
|
|
30
|
+
|
|
31
|
+
if (!result) return null
|
|
32
|
+
|
|
33
|
+
const updatedSource = j(result as string)
|
|
34
|
+
|
|
35
|
+
addImport({
|
|
36
|
+
component: "DropdownSeparator",
|
|
37
|
+
fromPackage: "@planningcenter/tapestry-react",
|
|
38
|
+
j,
|
|
39
|
+
pkg: "@planningcenter/tapestry",
|
|
40
|
+
source: updatedSource,
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
const dividerLocalName = getImportName(
|
|
44
|
+
"Divider",
|
|
45
|
+
"@planningcenter/tapestry-react",
|
|
46
|
+
{ j, source: updatedSource }
|
|
47
|
+
)
|
|
48
|
+
if (dividerLocalName) {
|
|
49
|
+
const dividerStillUsed =
|
|
50
|
+
updatedSource.find(j.JSXOpeningElement, {
|
|
51
|
+
name: { name: dividerLocalName },
|
|
52
|
+
}).length > 0
|
|
53
|
+
|
|
54
|
+
if (!dividerStillUsed) {
|
|
55
|
+
removeImportFromDeclaration(
|
|
56
|
+
updatedSource.find(j.ImportDeclaration, {
|
|
57
|
+
source: { value: "@planningcenter/tapestry-react" },
|
|
58
|
+
}),
|
|
59
|
+
"Divider"
|
|
60
|
+
)
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return updatedSource.toSource()
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export default transform
|