@planningcenter/tapestry-migration-cli 3.1.0-rc.8 → 3.1.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/dist/tapestry-react-shim.cjs +7 -1
- package/package.json +3 -3
- package/src/components/input/transformableInput.ts +47 -6
- package/src/components/input/transforms/mergeFieldIntoInput.test.ts +78 -0
- package/src/components/input/transforms/mergeFieldIntoInput.ts +6 -212
- package/src/components/input/transforms/removeDuplicateKeys.test.ts +3 -3
- package/src/components/input/transforms/removeTypeInput.test.ts +212 -0
- package/src/components/input/transforms/removeTypeInput.ts +22 -0
- package/src/components/input/transforms/removeTypeText.ts +2 -3
- package/src/components/input/transforms/unsupportedProps.test.ts +20 -20
- package/src/components/select/index.ts +58 -0
- package/src/components/select/transformableSelect.ts +7 -0
- package/src/components/select/transforms/auditSpreadProps.test.ts +103 -0
- package/src/components/select/transforms/auditSpreadProps.ts +26 -0
- package/src/components/select/transforms/childrenToOptions.test.ts +367 -0
- package/src/components/select/transforms/childrenToOptions.ts +295 -0
- package/src/components/select/transforms/convertLegacyOptions.test.ts +150 -0
- package/src/components/select/transforms/convertLegacyOptions.ts +105 -0
- package/src/components/select/transforms/convertStyleProps.test.ts +73 -0
- package/src/components/select/transforms/convertStyleProps.ts +12 -0
- package/src/components/select/transforms/emptyValueToPlaceholder.test.ts +122 -0
- package/src/components/select/transforms/emptyValueToPlaceholder.ts +22 -0
- package/src/components/select/transforms/innerRefToRef.test.ts +89 -0
- package/src/components/select/transforms/innerRefToRef.ts +18 -0
- package/src/components/select/transforms/mapChildrenToOptions.test.ts +521 -0
- package/src/components/select/transforms/mapChildrenToOptions.ts +312 -0
- package/src/components/select/transforms/mergeFieldIntoSelect.test.ts +506 -0
- package/src/components/select/transforms/mergeFieldIntoSelect.ts +7 -0
- package/src/components/select/transforms/mergeSelectLabel.test.ts +458 -0
- package/src/components/select/transforms/mergeSelectLabel.ts +225 -0
- package/src/components/select/transforms/moveSelectImport.test.ts +148 -0
- package/src/components/select/transforms/moveSelectImport.ts +14 -0
- package/src/components/select/transforms/removeDefaultProps.test.ts +249 -0
- package/src/components/select/transforms/removeDefaultProps.ts +112 -0
- package/src/components/select/transforms/sizeMapping.test.ts +188 -0
- package/src/components/select/transforms/sizeMapping.ts +17 -0
- package/src/components/select/transforms/skipMultipleSelect.test.ts +148 -0
- package/src/components/select/transforms/skipMultipleSelect.ts +23 -0
- package/src/components/select/transforms/stateToInvalid.test.ts +217 -0
- package/src/components/select/transforms/stateToInvalid.ts +59 -0
- package/src/components/select/transforms/stateToInvalidTernary.test.ts +146 -0
- package/src/components/select/transforms/stateToInvalidTernary.ts +13 -0
- package/src/components/select/transforms/unsupportedProps.test.ts +252 -0
- package/src/components/select/transforms/unsupportedProps.ts +44 -0
- package/src/components/shared/helpers/getAttributeExpression.ts +26 -0
- package/src/components/shared/helpers/unsupportedPropsHelpers.ts +52 -2
- package/src/components/shared/transformFactories/mergeFieldFactory.ts +244 -0
- package/src/components/shared/transformFactories/stylePropTransformFactory.ts +2 -1
- package/src/components/text-area/index.ts +48 -0
- package/src/components/text-area/transforms/auditSpreadProps.test.ts +139 -0
- package/src/components/text-area/transforms/auditSpreadProps.ts +10 -0
- package/src/components/text-area/transforms/convertStyleProps.test.ts +158 -0
- package/src/components/text-area/transforms/convertStyleProps.ts +10 -0
- package/src/components/text-area/transforms/innerRefToRef.test.ts +206 -0
- package/src/components/text-area/transforms/innerRefToRef.ts +14 -0
- package/src/components/text-area/transforms/mergeFieldIntoTextArea.test.ts +477 -0
- package/src/components/text-area/transforms/mergeFieldIntoTextArea.ts +5 -0
- package/src/components/text-area/transforms/moveTextAreaImport.test.ts +168 -0
- package/src/components/text-area/transforms/moveTextAreaImport.ts +13 -0
- package/src/components/text-area/transforms/removeDuplicateKeys.test.ts +129 -0
- package/src/components/text-area/transforms/removeDuplicateKeys.ts +8 -0
- package/src/components/text-area/transforms/removeRedundantAriaLabel.test.ts +183 -0
- package/src/components/text-area/transforms/removeRedundantAriaLabel.ts +59 -0
- package/src/components/text-area/transforms/sizeMapping.test.ts +199 -0
- package/src/components/text-area/transforms/sizeMapping.ts +15 -0
- package/src/components/text-area/transforms/stateToInvalid.test.ts +204 -0
- package/src/components/text-area/transforms/stateToInvalid.ts +57 -0
- package/src/components/text-area/transforms/stateToInvalidTernary.test.ts +133 -0
- package/src/components/text-area/transforms/stateToInvalidTernary.ts +11 -0
- package/src/components/text-area/transforms/unsupportedProps.test.ts +275 -0
- package/src/components/text-area/transforms/unsupportedProps.ts +35 -0
- package/src/index.ts +4 -1
|
@@ -276,7 +276,7 @@ function Test() {
|
|
|
276
276
|
expect(result).not.toContain("TODO: tapestry-migration")
|
|
277
277
|
})
|
|
278
278
|
|
|
279
|
-
it("should
|
|
279
|
+
it("should not transform Input with type='range' (unsupported type bails)", () => {
|
|
280
280
|
const input = `
|
|
281
281
|
import { Input } from "@planningcenter/tapestry-react"
|
|
282
282
|
|
|
@@ -286,10 +286,10 @@ function Test() {
|
|
|
286
286
|
`.trim()
|
|
287
287
|
|
|
288
288
|
const result = applyTransform(input)
|
|
289
|
-
expect(result).
|
|
289
|
+
expect(result).toBe(input)
|
|
290
290
|
})
|
|
291
291
|
|
|
292
|
-
it("should
|
|
292
|
+
it("should not transform Input with type={'range'} expression container (unsupported type bails)", () => {
|
|
293
293
|
const input = `
|
|
294
294
|
import { Input } from "@planningcenter/tapestry-react"
|
|
295
295
|
|
|
@@ -299,11 +299,10 @@ function Test() {
|
|
|
299
299
|
`.trim()
|
|
300
300
|
|
|
301
301
|
const result = applyTransform(input)
|
|
302
|
-
expect(result).
|
|
303
|
-
expect(result).toContain("TODO: tapestry-migration (type)")
|
|
302
|
+
expect(result).toBe(input)
|
|
304
303
|
})
|
|
305
304
|
|
|
306
|
-
it("should
|
|
305
|
+
it("should not transform Input with dynamic type in unsupported-types section (bails)", () => {
|
|
307
306
|
const input = `
|
|
308
307
|
import { Input } from "@planningcenter/tapestry-react"
|
|
309
308
|
|
|
@@ -313,11 +312,10 @@ function Test() {
|
|
|
313
312
|
`.trim()
|
|
314
313
|
|
|
315
314
|
const result = applyTransform(input)
|
|
316
|
-
expect(result).
|
|
317
|
-
expect(result).not.toContain("TODO: tapestry-migration (type)")
|
|
315
|
+
expect(result).toBe(input)
|
|
318
316
|
})
|
|
319
317
|
|
|
320
|
-
it("should
|
|
318
|
+
it("should not transform Input with type='file' (unsupported type bails)", () => {
|
|
321
319
|
const input = `
|
|
322
320
|
import { Input } from "@planningcenter/tapestry-react"
|
|
323
321
|
|
|
@@ -327,7 +325,7 @@ function Test() {
|
|
|
327
325
|
`.trim()
|
|
328
326
|
|
|
329
327
|
const result = applyTransform(input)
|
|
330
|
-
expect(result).
|
|
328
|
+
expect(result).toBe(input)
|
|
331
329
|
})
|
|
332
330
|
|
|
333
331
|
it("should not flag pattern on type='text'", () => {
|
|
@@ -356,7 +354,7 @@ function Test() {
|
|
|
356
354
|
expect(result).not.toContain("TODO: tapestry-migration")
|
|
357
355
|
})
|
|
358
356
|
|
|
359
|
-
it("should not
|
|
357
|
+
it("should not transform Input when type prop is dynamic (bails)", () => {
|
|
360
358
|
const input = `
|
|
361
359
|
import { Input } from "@planningcenter/tapestry-react"
|
|
362
360
|
|
|
@@ -366,7 +364,7 @@ function Test() {
|
|
|
366
364
|
`.trim()
|
|
367
365
|
|
|
368
366
|
const result = applyTransform(input)
|
|
369
|
-
expect(result).
|
|
367
|
+
expect(result).toBe(input)
|
|
370
368
|
})
|
|
371
369
|
|
|
372
370
|
it("should flag step without a type attr", () => {
|
|
@@ -465,8 +463,10 @@ function Test() {
|
|
|
465
463
|
"submit",
|
|
466
464
|
"reset",
|
|
467
465
|
"button",
|
|
468
|
-
])(
|
|
469
|
-
|
|
466
|
+
])(
|
|
467
|
+
"should not transform Input with type='%s' (unsupported type bails)",
|
|
468
|
+
(type) => {
|
|
469
|
+
const input = `
|
|
470
470
|
import { Input } from "@planningcenter/tapestry-react"
|
|
471
471
|
|
|
472
472
|
function Test() {
|
|
@@ -474,10 +474,10 @@ function Test() {
|
|
|
474
474
|
}
|
|
475
475
|
`.trim()
|
|
476
476
|
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
477
|
+
const result = applyTransform(input)
|
|
478
|
+
expect(result).toBe(input)
|
|
479
|
+
}
|
|
480
|
+
)
|
|
481
481
|
|
|
482
482
|
it("should not flag accepted type values", () => {
|
|
483
483
|
const types = [
|
|
@@ -503,7 +503,7 @@ function Test() {
|
|
|
503
503
|
}
|
|
504
504
|
})
|
|
505
505
|
|
|
506
|
-
it("should not
|
|
506
|
+
it("should not transform Input when type prop is dynamic (bails)", () => {
|
|
507
507
|
const input = `
|
|
508
508
|
import { Input } from "@planningcenter/tapestry-react"
|
|
509
509
|
|
|
@@ -513,7 +513,7 @@ function Test() {
|
|
|
513
513
|
`.trim()
|
|
514
514
|
|
|
515
515
|
const result = applyTransform(input)
|
|
516
|
-
expect(result).
|
|
516
|
+
expect(result).toBe(input)
|
|
517
517
|
})
|
|
518
518
|
})
|
|
519
519
|
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { Transform } from "jscodeshift"
|
|
2
|
+
|
|
3
|
+
import auditSpreadProps from "./transforms/auditSpreadProps"
|
|
4
|
+
import childrenToOptions from "./transforms/childrenToOptions"
|
|
5
|
+
import convertLegacyOptions from "./transforms/convertLegacyOptions"
|
|
6
|
+
import convertStyleProps from "./transforms/convertStyleProps"
|
|
7
|
+
import emptyValueToPlaceholder from "./transforms/emptyValueToPlaceholder"
|
|
8
|
+
import innerRefToRef from "./transforms/innerRefToRef"
|
|
9
|
+
import mapChildrenToOptions from "./transforms/mapChildrenToOptions"
|
|
10
|
+
import mergeFieldIntoSelect from "./transforms/mergeFieldIntoSelect"
|
|
11
|
+
import mergeSelectLabel from "./transforms/mergeSelectLabel"
|
|
12
|
+
import moveSelectImport from "./transforms/moveSelectImport"
|
|
13
|
+
import removeDefaultProps from "./transforms/removeDefaultProps"
|
|
14
|
+
import sizeMapping from "./transforms/sizeMapping"
|
|
15
|
+
import skipMultipleSelect from "./transforms/skipMultipleSelect"
|
|
16
|
+
import stateToInvalid from "./transforms/stateToInvalid"
|
|
17
|
+
import stateToInvalidTernary from "./transforms/stateToInvalidTernary"
|
|
18
|
+
import unsupportedProps from "./transforms/unsupportedProps"
|
|
19
|
+
|
|
20
|
+
const transform: Transform = (fileInfo, api, options) => {
|
|
21
|
+
let currentSource = fileInfo.source
|
|
22
|
+
let hasAnyChanges = false
|
|
23
|
+
|
|
24
|
+
const transforms = [
|
|
25
|
+
skipMultipleSelect,
|
|
26
|
+
mergeSelectLabel,
|
|
27
|
+
mergeFieldIntoSelect,
|
|
28
|
+
auditSpreadProps,
|
|
29
|
+
mapChildrenToOptions,
|
|
30
|
+
childrenToOptions,
|
|
31
|
+
convertLegacyOptions,
|
|
32
|
+
emptyValueToPlaceholder,
|
|
33
|
+
innerRefToRef,
|
|
34
|
+
sizeMapping,
|
|
35
|
+
stateToInvalidTernary,
|
|
36
|
+
stateToInvalid,
|
|
37
|
+
removeDefaultProps,
|
|
38
|
+
convertStyleProps,
|
|
39
|
+
unsupportedProps,
|
|
40
|
+
moveSelectImport,
|
|
41
|
+
]
|
|
42
|
+
|
|
43
|
+
for (const individualTransform of transforms) {
|
|
44
|
+
const result = individualTransform(
|
|
45
|
+
{ ...fileInfo, source: currentSource },
|
|
46
|
+
api,
|
|
47
|
+
options
|
|
48
|
+
)
|
|
49
|
+
if (result && result !== currentSource) {
|
|
50
|
+
currentSource = result as string
|
|
51
|
+
hasAnyChanges = true
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return hasAnyChanges ? currentSource : null
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export default transform
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { hasAttribute } from "../shared/conditions/hasAttribute"
|
|
2
|
+
import { notCondition } from "../shared/conditions/notCondition"
|
|
3
|
+
import { TransformCondition } from "../shared/types"
|
|
4
|
+
|
|
5
|
+
export const transformableSelect: TransformCondition = notCondition(
|
|
6
|
+
hasAttribute("multiple")
|
|
7
|
+
)
|
|
@@ -0,0 +1,103 @@
|
|
|
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) {
|
|
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("should add comment to Select with spread props", () => {
|
|
22
|
+
const input = `
|
|
23
|
+
import { Select } from "@planningcenter/tapestry-react"
|
|
24
|
+
|
|
25
|
+
export default function Test() {
|
|
26
|
+
const props = { onChange: handleChange }
|
|
27
|
+
return <Select {...props} emptyValue="Pick one" />
|
|
28
|
+
}
|
|
29
|
+
`.trim()
|
|
30
|
+
|
|
31
|
+
const result = applyTransform(input)
|
|
32
|
+
expect(result).toContain(AUDIT_COMMENT)
|
|
33
|
+
expect(result).toContain("{...props}")
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
it("should not transform Select without spread props", () => {
|
|
37
|
+
const input = `
|
|
38
|
+
import { Select } from "@planningcenter/tapestry-react"
|
|
39
|
+
|
|
40
|
+
export default function Test() {
|
|
41
|
+
return <Select emptyValue="Pick one" />
|
|
42
|
+
}
|
|
43
|
+
`.trim()
|
|
44
|
+
|
|
45
|
+
const result = applyTransform(input)
|
|
46
|
+
expect(result).toBe(null)
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
it("should not transform if Select is not imported from @planningcenter/tapestry-react", () => {
|
|
50
|
+
const input = `
|
|
51
|
+
import { Select } from "other-library"
|
|
52
|
+
|
|
53
|
+
export default function Test() {
|
|
54
|
+
const props = { onChange: handleChange }
|
|
55
|
+
return <Select {...props} />
|
|
56
|
+
}
|
|
57
|
+
`.trim()
|
|
58
|
+
|
|
59
|
+
const result = applyTransform(input)
|
|
60
|
+
expect(result).toBe(null)
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
it("should handle multiple Select components with spread props", () => {
|
|
64
|
+
const input = `
|
|
65
|
+
import { Select } from "@planningcenter/tapestry-react"
|
|
66
|
+
|
|
67
|
+
export default function Test() {
|
|
68
|
+
const props1 = { onChange: handleChange1 }
|
|
69
|
+
const props2 = { onChange: handleChange2 }
|
|
70
|
+
return (
|
|
71
|
+
<div>
|
|
72
|
+
<Select {...props1} emptyValue="Pick one" />
|
|
73
|
+
<Select {...props2} emptyValue="Pick another" />
|
|
74
|
+
</div>
|
|
75
|
+
)
|
|
76
|
+
}
|
|
77
|
+
`.trim()
|
|
78
|
+
|
|
79
|
+
const result = applyTransform(input)
|
|
80
|
+
expect(result).toContain(AUDIT_COMMENT)
|
|
81
|
+
expect(result).toContain("{...props1}")
|
|
82
|
+
expect(result).toContain("{...props2}")
|
|
83
|
+
})
|
|
84
|
+
|
|
85
|
+
it("should return null for empty file", () => {
|
|
86
|
+
const result = applyTransform("")
|
|
87
|
+
expect(result).toBe(null)
|
|
88
|
+
})
|
|
89
|
+
|
|
90
|
+
it("should return null when no Select imports exist", () => {
|
|
91
|
+
const input = `
|
|
92
|
+
import { Button } from "@planningcenter/tapestry-react"
|
|
93
|
+
|
|
94
|
+
export default function Test() {
|
|
95
|
+
const props = { onClick: handleClick }
|
|
96
|
+
return <Button {...props}>Save</Button>
|
|
97
|
+
}
|
|
98
|
+
`.trim()
|
|
99
|
+
|
|
100
|
+
const result = applyTransform(input)
|
|
101
|
+
expect(result).toBe(null)
|
|
102
|
+
})
|
|
103
|
+
})
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { Transform } from "jscodeshift"
|
|
2
|
+
|
|
3
|
+
import { addCommentToAttribute } from "../../shared/actions/addCommentToAttribute"
|
|
4
|
+
import { getSpreadProps } from "../../shared/actions/getSpreadProps"
|
|
5
|
+
import { hasSpreadProps } from "../../shared/actions/hasSpreadProps"
|
|
6
|
+
import { andConditions } from "../../shared/conditions/andConditions"
|
|
7
|
+
import { attributeTransformFactory } from "../../shared/transformFactories/attributeTransformFactory"
|
|
8
|
+
import { transformableSelect } from "../transformableSelect"
|
|
9
|
+
|
|
10
|
+
const COMMENT =
|
|
11
|
+
"Spread props can contain unsupported props, please explore usages and migrate as needed."
|
|
12
|
+
|
|
13
|
+
const transform: Transform = attributeTransformFactory({
|
|
14
|
+
condition: andConditions(transformableSelect, hasSpreadProps),
|
|
15
|
+
targetComponent: "Select",
|
|
16
|
+
targetPackage: "@planningcenter/tapestry-react",
|
|
17
|
+
transform: (element, { j }) => {
|
|
18
|
+
const spreadProps = getSpreadProps(element)
|
|
19
|
+
spreadProps.forEach((prop) =>
|
|
20
|
+
addCommentToAttribute({ attribute: prop, j, text: COMMENT })
|
|
21
|
+
)
|
|
22
|
+
return spreadProps.length > 0
|
|
23
|
+
},
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
export default transform
|
|
@@ -0,0 +1,367 @@
|
|
|
1
|
+
import jscodeshift from "jscodeshift"
|
|
2
|
+
import { describe, expect, it } from "vitest"
|
|
3
|
+
|
|
4
|
+
import transform from "./childrenToOptions"
|
|
5
|
+
|
|
6
|
+
const j = jscodeshift.withParser("tsx")
|
|
7
|
+
|
|
8
|
+
function applyTransform(source: string): string {
|
|
9
|
+
const fileInfo = { path: "test.tsx", source }
|
|
10
|
+
const result = transform(
|
|
11
|
+
fileInfo,
|
|
12
|
+
{ j, jscodeshift: j, report: () => {}, stats: () => {} },
|
|
13
|
+
{}
|
|
14
|
+
) as string | null
|
|
15
|
+
return result || source
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
describe("childrenToOptions transform", () => {
|
|
19
|
+
describe("basic Select.Option conversion", () => {
|
|
20
|
+
it("should convert simple Select.Option children to options prop", () => {
|
|
21
|
+
const input = `
|
|
22
|
+
import { Select } from "@planningcenter/tapestry-react"
|
|
23
|
+
|
|
24
|
+
function Test() {
|
|
25
|
+
return (
|
|
26
|
+
<Select emptyValue="Pick one">
|
|
27
|
+
<Select.Option value="apple">Apple</Select.Option>
|
|
28
|
+
<Select.Option value="orange">Orange</Select.Option>
|
|
29
|
+
</Select>
|
|
30
|
+
)
|
|
31
|
+
}
|
|
32
|
+
`.trim()
|
|
33
|
+
|
|
34
|
+
const result = applyTransform(input)
|
|
35
|
+
expect(result).toContain("options={")
|
|
36
|
+
expect(result).toContain('label: "Apple"')
|
|
37
|
+
expect(result).toContain('value: "apple"')
|
|
38
|
+
expect(result).toContain('label: "Orange"')
|
|
39
|
+
expect(result).toContain('value: "orange"')
|
|
40
|
+
expect(result).not.toContain("Select.Option")
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
it("should preserve data-* attributes on options", () => {
|
|
44
|
+
const input = `
|
|
45
|
+
import { Select } from "@planningcenter/tapestry-react"
|
|
46
|
+
|
|
47
|
+
function Test() {
|
|
48
|
+
return (
|
|
49
|
+
<Select emptyValue="Pick one">
|
|
50
|
+
<Select.Option value="apple" data-testid="apple-opt">Apple</Select.Option>
|
|
51
|
+
</Select>
|
|
52
|
+
)
|
|
53
|
+
}
|
|
54
|
+
`.trim()
|
|
55
|
+
|
|
56
|
+
const result = applyTransform(input)
|
|
57
|
+
expect(result).toContain('"data-testid": "apple-opt"')
|
|
58
|
+
expect(result).toContain('label: "Apple"')
|
|
59
|
+
expect(result).toContain('value: "apple"')
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
it("should preserve dynamic data-* attribute expressions on options", () => {
|
|
63
|
+
const input = `
|
|
64
|
+
import { Select } from "@planningcenter/tapestry-react"
|
|
65
|
+
|
|
66
|
+
function Test() {
|
|
67
|
+
return (
|
|
68
|
+
<Select emptyValue="Pick one">
|
|
69
|
+
<Select.Option value="apple" data-pendo={pendoIds.apple}>Apple</Select.Option>
|
|
70
|
+
</Select>
|
|
71
|
+
)
|
|
72
|
+
}
|
|
73
|
+
`.trim()
|
|
74
|
+
|
|
75
|
+
const result = applyTransform(input)
|
|
76
|
+
expect(result).toContain('"data-pendo": pendoIds.apple')
|
|
77
|
+
expect(result).toContain('label: "Apple"')
|
|
78
|
+
expect(result).toContain('value: "apple"')
|
|
79
|
+
})
|
|
80
|
+
|
|
81
|
+
it("should handle disabled options", () => {
|
|
82
|
+
const input = `
|
|
83
|
+
import { Select } from "@planningcenter/tapestry-react"
|
|
84
|
+
|
|
85
|
+
function Test() {
|
|
86
|
+
return (
|
|
87
|
+
<Select emptyValue="Pick one">
|
|
88
|
+
<Select.Option value="apple" disabled>Apple</Select.Option>
|
|
89
|
+
<Select.Option value="orange">Orange</Select.Option>
|
|
90
|
+
</Select>
|
|
91
|
+
)
|
|
92
|
+
}
|
|
93
|
+
`.trim()
|
|
94
|
+
|
|
95
|
+
const result = applyTransform(input)
|
|
96
|
+
expect(result).toContain("disabled: true")
|
|
97
|
+
expect(result).toContain('label: "Apple"')
|
|
98
|
+
expect(result).toContain('value: "apple"')
|
|
99
|
+
})
|
|
100
|
+
|
|
101
|
+
it("should convert Select.Option with expression string value", () => {
|
|
102
|
+
const input = `
|
|
103
|
+
import { Select } from "@planningcenter/tapestry-react"
|
|
104
|
+
|
|
105
|
+
function Test() {
|
|
106
|
+
return (
|
|
107
|
+
<Select emptyValue="Pick one">
|
|
108
|
+
<Select.Option value={"apple"}>Apple</Select.Option>
|
|
109
|
+
</Select>
|
|
110
|
+
)
|
|
111
|
+
}
|
|
112
|
+
`.trim()
|
|
113
|
+
|
|
114
|
+
const result = applyTransform(input)
|
|
115
|
+
expect(result).toContain("options={")
|
|
116
|
+
expect(result).toContain('value: "apple"')
|
|
117
|
+
expect(result).toContain('label: "Apple"')
|
|
118
|
+
})
|
|
119
|
+
|
|
120
|
+
it("should make Select self-closing after removing children", () => {
|
|
121
|
+
const input = `
|
|
122
|
+
import { Select } from "@planningcenter/tapestry-react"
|
|
123
|
+
|
|
124
|
+
function Test() {
|
|
125
|
+
return (
|
|
126
|
+
<Select emptyValue="Pick one">
|
|
127
|
+
<Select.Option value="a">A</Select.Option>
|
|
128
|
+
</Select>
|
|
129
|
+
)
|
|
130
|
+
}
|
|
131
|
+
`.trim()
|
|
132
|
+
|
|
133
|
+
const result = applyTransform(input)
|
|
134
|
+
expect(result).not.toContain("</Select>")
|
|
135
|
+
expect(result).toContain("/>")
|
|
136
|
+
})
|
|
137
|
+
})
|
|
138
|
+
|
|
139
|
+
describe("Select.OptionGroup conversion", () => {
|
|
140
|
+
it("should convert OptionGroup with title to grouped options", () => {
|
|
141
|
+
const input = `
|
|
142
|
+
import { Select } from "@planningcenter/tapestry-react"
|
|
143
|
+
|
|
144
|
+
function Test() {
|
|
145
|
+
return (
|
|
146
|
+
<Select emptyValue="Pick one">
|
|
147
|
+
<Select.OptionGroup title="Fruits">
|
|
148
|
+
<Select.Option value="apple">Apple</Select.Option>
|
|
149
|
+
<Select.Option value="orange">Orange</Select.Option>
|
|
150
|
+
</Select.OptionGroup>
|
|
151
|
+
</Select>
|
|
152
|
+
)
|
|
153
|
+
}
|
|
154
|
+
`.trim()
|
|
155
|
+
|
|
156
|
+
const result = applyTransform(input)
|
|
157
|
+
expect(result).toContain("options={")
|
|
158
|
+
expect(result).toContain('label: "Fruits"')
|
|
159
|
+
expect(result).toContain("options: [")
|
|
160
|
+
expect(result).toContain('label: "Apple"')
|
|
161
|
+
expect(result).toContain('value: "apple"')
|
|
162
|
+
})
|
|
163
|
+
|
|
164
|
+
it("should handle mixed options and option groups", () => {
|
|
165
|
+
const input = `
|
|
166
|
+
import { Select } from "@planningcenter/tapestry-react"
|
|
167
|
+
|
|
168
|
+
function Test() {
|
|
169
|
+
return (
|
|
170
|
+
<Select emptyValue="Pick one">
|
|
171
|
+
<Select.Option value="none">None</Select.Option>
|
|
172
|
+
<Select.OptionGroup title="Fruits">
|
|
173
|
+
<Select.Option value="apple">Apple</Select.Option>
|
|
174
|
+
</Select.OptionGroup>
|
|
175
|
+
</Select>
|
|
176
|
+
)
|
|
177
|
+
}
|
|
178
|
+
`.trim()
|
|
179
|
+
|
|
180
|
+
const result = applyTransform(input)
|
|
181
|
+
expect(result).toContain("options={")
|
|
182
|
+
expect(result).toContain('label: "None"')
|
|
183
|
+
expect(result).toContain('label: "Fruits"')
|
|
184
|
+
})
|
|
185
|
+
})
|
|
186
|
+
|
|
187
|
+
describe("complex children (should flag for manual migration)", () => {
|
|
188
|
+
it("should add comment for dynamic children (ternary)", () => {
|
|
189
|
+
const input = `
|
|
190
|
+
import { Select } from "@planningcenter/tapestry-react"
|
|
191
|
+
|
|
192
|
+
function Test() {
|
|
193
|
+
return (
|
|
194
|
+
<Select emptyValue="Pick one">
|
|
195
|
+
{showOptions ? <Select.Option value="a">A</Select.Option> : null}
|
|
196
|
+
</Select>
|
|
197
|
+
)
|
|
198
|
+
}
|
|
199
|
+
`.trim()
|
|
200
|
+
|
|
201
|
+
const result = applyTransform(input)
|
|
202
|
+
expect(result).toContain("TODO: tapestry-migration")
|
|
203
|
+
expect(result).toContain("dynamic expressions")
|
|
204
|
+
})
|
|
205
|
+
|
|
206
|
+
it("should add comment for Select.Option with function children", () => {
|
|
207
|
+
const input = `
|
|
208
|
+
import { Select } from "@planningcenter/tapestry-react"
|
|
209
|
+
|
|
210
|
+
function Test() {
|
|
211
|
+
return (
|
|
212
|
+
<Select emptyValue="Pick one">
|
|
213
|
+
<Select.Option value="custom">
|
|
214
|
+
{(selected) => selected ? "Selected!" : "Not selected"}
|
|
215
|
+
</Select.Option>
|
|
216
|
+
</Select>
|
|
217
|
+
)
|
|
218
|
+
}
|
|
219
|
+
`.trim()
|
|
220
|
+
|
|
221
|
+
const result = applyTransform(input)
|
|
222
|
+
expect(result).toContain("TODO: tapestry-migration")
|
|
223
|
+
expect(result).toContain("could not be automatically converted")
|
|
224
|
+
})
|
|
225
|
+
|
|
226
|
+
it("should add comment for Select.Option with dynamic value", () => {
|
|
227
|
+
const input = `
|
|
228
|
+
import { Select } from "@planningcenter/tapestry-react"
|
|
229
|
+
|
|
230
|
+
function Test() {
|
|
231
|
+
return (
|
|
232
|
+
<Select emptyValue="Pick one">
|
|
233
|
+
<Select.Option value={dynamicValue}>Label</Select.Option>
|
|
234
|
+
</Select>
|
|
235
|
+
)
|
|
236
|
+
}
|
|
237
|
+
`.trim()
|
|
238
|
+
|
|
239
|
+
const result = applyTransform(input)
|
|
240
|
+
expect(result).toContain("TODO: tapestry-migration")
|
|
241
|
+
expect(result).toContain("could not be automatically converted")
|
|
242
|
+
})
|
|
243
|
+
|
|
244
|
+
it("should add comment for Select.Option with JSX children", () => {
|
|
245
|
+
const input = `
|
|
246
|
+
import { Select } from "@planningcenter/tapestry-react"
|
|
247
|
+
|
|
248
|
+
function Test() {
|
|
249
|
+
return (
|
|
250
|
+
<Select emptyValue="Pick one">
|
|
251
|
+
<Select.Option value="user">
|
|
252
|
+
<img src="avatar.png" /> Alice
|
|
253
|
+
</Select.Option>
|
|
254
|
+
</Select>
|
|
255
|
+
)
|
|
256
|
+
}
|
|
257
|
+
`.trim()
|
|
258
|
+
|
|
259
|
+
const result = applyTransform(input)
|
|
260
|
+
expect(result).toContain("TODO: tapestry-migration")
|
|
261
|
+
expect(result).toContain("could not be automatically converted")
|
|
262
|
+
})
|
|
263
|
+
|
|
264
|
+
it("should add comment for Select.Value children", () => {
|
|
265
|
+
const input = `
|
|
266
|
+
import { Select } from "@planningcenter/tapestry-react"
|
|
267
|
+
|
|
268
|
+
function Test() {
|
|
269
|
+
return (
|
|
270
|
+
<Select emptyValue="Pick one">
|
|
271
|
+
<Select.Value>Custom display</Select.Value>
|
|
272
|
+
<Select.Option value="a">A</Select.Option>
|
|
273
|
+
</Select>
|
|
274
|
+
)
|
|
275
|
+
}
|
|
276
|
+
`.trim()
|
|
277
|
+
|
|
278
|
+
const result = applyTransform(input)
|
|
279
|
+
expect(result).toContain("TODO: tapestry-migration")
|
|
280
|
+
expect(result).toContain("Select.Value")
|
|
281
|
+
})
|
|
282
|
+
|
|
283
|
+
it("should add comment for Select.OptionGroup with dynamic title", () => {
|
|
284
|
+
const input = `
|
|
285
|
+
import { Select } from "@planningcenter/tapestry-react"
|
|
286
|
+
|
|
287
|
+
function Test() {
|
|
288
|
+
return (
|
|
289
|
+
<Select emptyValue="Pick one">
|
|
290
|
+
<Select.OptionGroup title={groupTitle}>
|
|
291
|
+
<Select.Option value="a">A</Select.Option>
|
|
292
|
+
</Select.OptionGroup>
|
|
293
|
+
</Select>
|
|
294
|
+
)
|
|
295
|
+
}
|
|
296
|
+
`.trim()
|
|
297
|
+
|
|
298
|
+
const result = applyTransform(input)
|
|
299
|
+
expect(result).toContain("TODO: tapestry-migration")
|
|
300
|
+
expect(result).toContain("could not be automatically converted")
|
|
301
|
+
})
|
|
302
|
+
})
|
|
303
|
+
|
|
304
|
+
describe("edge cases", () => {
|
|
305
|
+
it("should not transform Select without children", () => {
|
|
306
|
+
const input = `
|
|
307
|
+
import { Select } from "@planningcenter/tapestry-react"
|
|
308
|
+
|
|
309
|
+
function Test() {
|
|
310
|
+
return <Select emptyValue="Pick one" options={options} />
|
|
311
|
+
}
|
|
312
|
+
`.trim()
|
|
313
|
+
|
|
314
|
+
const result = applyTransform(input)
|
|
315
|
+
expect(result).toBe(input)
|
|
316
|
+
})
|
|
317
|
+
|
|
318
|
+
it("should not transform other components", () => {
|
|
319
|
+
const input = `
|
|
320
|
+
import { Button } from "@planningcenter/tapestry-react"
|
|
321
|
+
|
|
322
|
+
function Test() {
|
|
323
|
+
return <Button>Click me</Button>
|
|
324
|
+
}
|
|
325
|
+
`.trim()
|
|
326
|
+
|
|
327
|
+
const result = applyTransform(input)
|
|
328
|
+
expect(result).toBe(input)
|
|
329
|
+
})
|
|
330
|
+
|
|
331
|
+
it("should handle aliased Select import", () => {
|
|
332
|
+
const input = `
|
|
333
|
+
import { Select as TapestrySelect } from "@planningcenter/tapestry-react"
|
|
334
|
+
|
|
335
|
+
function Test() {
|
|
336
|
+
return (
|
|
337
|
+
<TapestrySelect emptyValue="Pick one">
|
|
338
|
+
<TapestrySelect.Option value="a">A</TapestrySelect.Option>
|
|
339
|
+
</TapestrySelect>
|
|
340
|
+
)
|
|
341
|
+
}
|
|
342
|
+
`.trim()
|
|
343
|
+
|
|
344
|
+
const result = applyTransform(input)
|
|
345
|
+
expect(result).toContain("options={")
|
|
346
|
+
expect(result).toContain('label: "A"')
|
|
347
|
+
expect(result).toContain('value: "a"')
|
|
348
|
+
})
|
|
349
|
+
|
|
350
|
+
it("should handle Select with only whitespace children (no-op)", () => {
|
|
351
|
+
const input = `
|
|
352
|
+
import { Select } from "@planningcenter/tapestry-react"
|
|
353
|
+
|
|
354
|
+
function Test() {
|
|
355
|
+
return (
|
|
356
|
+
<Select emptyValue="Pick one">
|
|
357
|
+
</Select>
|
|
358
|
+
)
|
|
359
|
+
}
|
|
360
|
+
`.trim()
|
|
361
|
+
|
|
362
|
+
const result = applyTransform(input)
|
|
363
|
+
// Only whitespace children, should add comment since no options found
|
|
364
|
+
expect(result).toContain("TODO: tapestry-migration")
|
|
365
|
+
})
|
|
366
|
+
})
|
|
367
|
+
})
|