@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
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import jscodeshift from "jscodeshift"
|
|
2
|
+
import { describe, expect, it } from "vitest"
|
|
3
|
+
|
|
4
|
+
import transform from "./removeDuplicateKeys"
|
|
5
|
+
|
|
6
|
+
const j = jscodeshift.withParser("tsx")
|
|
7
|
+
|
|
8
|
+
function applyTransform(source: string) {
|
|
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("removeDuplicateKeys transform", () => {
|
|
18
|
+
describe("TextArea elements with duplicate attributes", () => {
|
|
19
|
+
it("should remove duplicate attributes from TextArea elements", () => {
|
|
20
|
+
const source = `
|
|
21
|
+
import { TextArea } from "@planningcenter/tapestry-react"
|
|
22
|
+
|
|
23
|
+
export function TestComponent() {
|
|
24
|
+
return <TextArea label="First" disabled label="Second">Save</TextArea>
|
|
25
|
+
}
|
|
26
|
+
`
|
|
27
|
+
|
|
28
|
+
const result = applyTransform(source)
|
|
29
|
+
|
|
30
|
+
expect(result).not.toBeNull()
|
|
31
|
+
expect(result).toContain('label="First"')
|
|
32
|
+
expect(result).not.toContain('label="Second"')
|
|
33
|
+
expect(result).toContain("disabled")
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
it("should preserve first occurrence of duplicate attributes", () => {
|
|
37
|
+
const source = `
|
|
38
|
+
import { TextArea } from "@planningcenter/tapestry-react"
|
|
39
|
+
|
|
40
|
+
export function TestComponent() {
|
|
41
|
+
return <TextArea onClick={handleFirst} aria-label="First" onClick={handleSecond} aria-label="Second" />
|
|
42
|
+
}
|
|
43
|
+
`
|
|
44
|
+
|
|
45
|
+
const result = applyTransform(source)
|
|
46
|
+
|
|
47
|
+
expect(result).not.toBeNull()
|
|
48
|
+
expect(result).toContain("onClick={handleFirst}")
|
|
49
|
+
expect(result).not.toContain("onClick={handleSecond}")
|
|
50
|
+
expect(result).toContain('aria-label="First"')
|
|
51
|
+
expect(result).not.toContain('aria-label="Second"')
|
|
52
|
+
})
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
describe("TextArea elements without duplicate attributes", () => {
|
|
56
|
+
it("should return null when no duplicates exist", () => {
|
|
57
|
+
const source = `
|
|
58
|
+
import { TextArea } from "@planningcenter/tapestry-react"
|
|
59
|
+
|
|
60
|
+
export function TestComponent() {
|
|
61
|
+
return <TextArea label="Name" disabled />
|
|
62
|
+
}
|
|
63
|
+
`
|
|
64
|
+
|
|
65
|
+
const result = applyTransform(source)
|
|
66
|
+
|
|
67
|
+
expect(result).toBeNull()
|
|
68
|
+
})
|
|
69
|
+
|
|
70
|
+
it("should return null for TextArea with no attributes", () => {
|
|
71
|
+
const source = `
|
|
72
|
+
import { TextArea } from "@planningcenter/tapestry-react"
|
|
73
|
+
|
|
74
|
+
export function TestComponent() {
|
|
75
|
+
return <TextArea />
|
|
76
|
+
}
|
|
77
|
+
`
|
|
78
|
+
|
|
79
|
+
const result = applyTransform(source)
|
|
80
|
+
|
|
81
|
+
expect(result).toBeNull()
|
|
82
|
+
})
|
|
83
|
+
})
|
|
84
|
+
|
|
85
|
+
describe("import handling", () => {
|
|
86
|
+
it("should only process files that import TextArea from tapestry-react", () => {
|
|
87
|
+
const source = `
|
|
88
|
+
import { TextArea } from "some-other-library"
|
|
89
|
+
|
|
90
|
+
export function TestComponent() {
|
|
91
|
+
return <TextArea label="First" label="Second" />
|
|
92
|
+
}
|
|
93
|
+
`
|
|
94
|
+
|
|
95
|
+
const result = applyTransform(source)
|
|
96
|
+
|
|
97
|
+
expect(result).toBeNull()
|
|
98
|
+
})
|
|
99
|
+
})
|
|
100
|
+
|
|
101
|
+
describe("mixed elements", () => {
|
|
102
|
+
it("should only process TextArea elements, not other elements", () => {
|
|
103
|
+
const source = `
|
|
104
|
+
import { TextArea } from "@planningcenter/tapestry-react"
|
|
105
|
+
|
|
106
|
+
export function TestComponent() {
|
|
107
|
+
return (
|
|
108
|
+
<div>
|
|
109
|
+
<TextArea label="First" label="Second" />
|
|
110
|
+
<div className="container" className="wrapper">Content</div>
|
|
111
|
+
</div>
|
|
112
|
+
)
|
|
113
|
+
}
|
|
114
|
+
`
|
|
115
|
+
|
|
116
|
+
const result = applyTransform(source)
|
|
117
|
+
|
|
118
|
+
expect(result).not.toBeNull()
|
|
119
|
+
|
|
120
|
+
// TextArea duplicates should be removed
|
|
121
|
+
expect(result).toContain('label="First"')
|
|
122
|
+
expect(result).not.toContain('label="Second"')
|
|
123
|
+
|
|
124
|
+
// Other elements should remain unchanged
|
|
125
|
+
expect(result).toContain('className="container"')
|
|
126
|
+
expect(result).toContain('className="wrapper"')
|
|
127
|
+
})
|
|
128
|
+
})
|
|
129
|
+
})
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { removeDuplicateKeys } from "../../shared/actions/removeDuplicateKeys"
|
|
2
|
+
import { attributeTransformFactory } from "../../shared/transformFactories/attributeTransformFactory"
|
|
3
|
+
|
|
4
|
+
export default attributeTransformFactory({
|
|
5
|
+
targetComponent: "TextArea",
|
|
6
|
+
targetPackage: "@planningcenter/tapestry-react",
|
|
7
|
+
transform: removeDuplicateKeys,
|
|
8
|
+
})
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import jscodeshift from "jscodeshift"
|
|
2
|
+
import { describe, expect, it } from "vitest"
|
|
3
|
+
|
|
4
|
+
import transform from "./removeRedundantAriaLabel"
|
|
5
|
+
|
|
6
|
+
const j = jscodeshift.withParser("tsx")
|
|
7
|
+
|
|
8
|
+
// Helper to run transform and get result
|
|
9
|
+
function applyTransform(source: string): string | null {
|
|
10
|
+
const fileInfo = { path: "test.tsx", source }
|
|
11
|
+
const api = {
|
|
12
|
+
j,
|
|
13
|
+
jscodeshift: j,
|
|
14
|
+
report: () => {},
|
|
15
|
+
stats: () => {},
|
|
16
|
+
}
|
|
17
|
+
const result = transform(fileInfo, api, {})
|
|
18
|
+
return result as string | null
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
describe("removeRedundantAriaLabel transform", () => {
|
|
22
|
+
describe("basic transformation", () => {
|
|
23
|
+
it("should remove aria-label when both aria-label and label are equal static strings", () => {
|
|
24
|
+
const input = `
|
|
25
|
+
import { TextArea } from "@planningcenter/tapestry-react"
|
|
26
|
+
|
|
27
|
+
function Component() {
|
|
28
|
+
return <TextArea aria-label="Name" label="Name" />
|
|
29
|
+
}
|
|
30
|
+
`
|
|
31
|
+
|
|
32
|
+
const result = applyTransform(input)
|
|
33
|
+
|
|
34
|
+
expect(result).toContain('<TextArea label="Name" />')
|
|
35
|
+
expect(result).not.toContain("aria-label")
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
it("should preserve aria-label when no label prop exists", () => {
|
|
39
|
+
const input = `
|
|
40
|
+
import { TextArea } from "@planningcenter/tapestry-react"
|
|
41
|
+
|
|
42
|
+
function Component() {
|
|
43
|
+
return <TextArea aria-label="Name" />
|
|
44
|
+
}
|
|
45
|
+
`
|
|
46
|
+
|
|
47
|
+
const result = applyTransform(input)
|
|
48
|
+
|
|
49
|
+
expect(result).toBeNull()
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
it("should return null when TextArea has neither aria-label nor label", () => {
|
|
53
|
+
const input = `
|
|
54
|
+
import { TextArea } from "@planningcenter/tapestry-react"
|
|
55
|
+
|
|
56
|
+
function Component() {
|
|
57
|
+
return <TextArea onChange={handleChange} />
|
|
58
|
+
}
|
|
59
|
+
`
|
|
60
|
+
|
|
61
|
+
const result = applyTransform(input)
|
|
62
|
+
|
|
63
|
+
expect(result).toBeNull()
|
|
64
|
+
})
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
describe("preserves aria-label when not provably redundant", () => {
|
|
68
|
+
it("should keep aria-label when it differs from label", () => {
|
|
69
|
+
const input = `
|
|
70
|
+
import { TextArea } from "@planningcenter/tapestry-react"
|
|
71
|
+
|
|
72
|
+
function Component() {
|
|
73
|
+
return <TextArea aria-label="Enter your name" label="Name" />
|
|
74
|
+
}
|
|
75
|
+
`
|
|
76
|
+
|
|
77
|
+
const result = applyTransform(input)
|
|
78
|
+
|
|
79
|
+
expect(result).toBeNull()
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
it("should keep aria-label when label is a dynamic expression", () => {
|
|
83
|
+
const input = `
|
|
84
|
+
import { TextArea } from "@planningcenter/tapestry-react"
|
|
85
|
+
|
|
86
|
+
function Component() {
|
|
87
|
+
return <TextArea aria-label="Name" label={labelText} />
|
|
88
|
+
}
|
|
89
|
+
`
|
|
90
|
+
|
|
91
|
+
const result = applyTransform(input)
|
|
92
|
+
|
|
93
|
+
expect(result).toBeNull()
|
|
94
|
+
})
|
|
95
|
+
|
|
96
|
+
it("should keep aria-label when it is a dynamic expression", () => {
|
|
97
|
+
const input = `
|
|
98
|
+
import { TextArea } from "@planningcenter/tapestry-react"
|
|
99
|
+
|
|
100
|
+
function Component() {
|
|
101
|
+
return <TextArea aria-label={ariaText} label="Name" />
|
|
102
|
+
}
|
|
103
|
+
`
|
|
104
|
+
|
|
105
|
+
const result = applyTransform(input)
|
|
106
|
+
|
|
107
|
+
expect(result).toBeNull()
|
|
108
|
+
})
|
|
109
|
+
|
|
110
|
+
it("should keep aria-label when label is a JSX element", () => {
|
|
111
|
+
const input = `
|
|
112
|
+
import { TextArea } from "@planningcenter/tapestry-react"
|
|
113
|
+
|
|
114
|
+
function Component() {
|
|
115
|
+
return <TextArea aria-label="Name" label={<span>Name</span>} />
|
|
116
|
+
}
|
|
117
|
+
`
|
|
118
|
+
|
|
119
|
+
const result = applyTransform(input)
|
|
120
|
+
|
|
121
|
+
expect(result).toBeNull()
|
|
122
|
+
})
|
|
123
|
+
})
|
|
124
|
+
|
|
125
|
+
describe("edge cases", () => {
|
|
126
|
+
it("should not affect other components with the same props", () => {
|
|
127
|
+
const input = `
|
|
128
|
+
import { TextArea } from "@planningcenter/tapestry-react"
|
|
129
|
+
|
|
130
|
+
function Component() {
|
|
131
|
+
return (
|
|
132
|
+
<div>
|
|
133
|
+
<TextArea aria-label="Name" label="Name" />
|
|
134
|
+
<textarea aria-label="Name" label="Name" />
|
|
135
|
+
</div>
|
|
136
|
+
)
|
|
137
|
+
}
|
|
138
|
+
`
|
|
139
|
+
|
|
140
|
+
const result = applyTransform(input)
|
|
141
|
+
|
|
142
|
+
expect(result).toContain('<TextArea label="Name" />')
|
|
143
|
+
expect(result).toContain('<textarea aria-label="Name" label="Name" />')
|
|
144
|
+
})
|
|
145
|
+
|
|
146
|
+
it("should handle expression syntax aria-label={'Name'} matching label='Name'", () => {
|
|
147
|
+
const input = `
|
|
148
|
+
import { TextArea } from "@planningcenter/tapestry-react"
|
|
149
|
+
|
|
150
|
+
function Component() {
|
|
151
|
+
return <TextArea aria-label={"Name"} label="Name" />
|
|
152
|
+
}
|
|
153
|
+
`
|
|
154
|
+
|
|
155
|
+
const result = applyTransform(input)
|
|
156
|
+
|
|
157
|
+
expect(result).toContain('<TextArea label="Name" />')
|
|
158
|
+
expect(result).not.toContain("aria-label")
|
|
159
|
+
})
|
|
160
|
+
|
|
161
|
+
it("should handle multiple TextAreas in one file with mixed cases", () => {
|
|
162
|
+
const input = `
|
|
163
|
+
import { TextArea } from "@planningcenter/tapestry-react"
|
|
164
|
+
|
|
165
|
+
function Component() {
|
|
166
|
+
return (
|
|
167
|
+
<div>
|
|
168
|
+
<TextArea aria-label="Name" label="Name" />
|
|
169
|
+
<TextArea aria-label="Email" />
|
|
170
|
+
<TextArea label="Phone" />
|
|
171
|
+
</div>
|
|
172
|
+
)
|
|
173
|
+
}
|
|
174
|
+
`
|
|
175
|
+
|
|
176
|
+
const result = applyTransform(input)
|
|
177
|
+
|
|
178
|
+
expect(result).toContain('<TextArea label="Name" />')
|
|
179
|
+
expect(result).toContain('aria-label="Email"')
|
|
180
|
+
expect(result).toContain('<TextArea label="Phone" />')
|
|
181
|
+
})
|
|
182
|
+
})
|
|
183
|
+
})
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { JSXAttribute, JSXSpreadAttribute, Transform } from "jscodeshift"
|
|
2
|
+
|
|
3
|
+
import { removeAttribute } from "../../shared/actions/removeAttribute"
|
|
4
|
+
import { andConditions } from "../../shared/conditions/andConditions"
|
|
5
|
+
import { hasAttribute } from "../../shared/conditions/hasAttribute"
|
|
6
|
+
import { attributeTransformFactory } from "../../shared/transformFactories/attributeTransformFactory"
|
|
7
|
+
|
|
8
|
+
function getStaticStringValue(
|
|
9
|
+
attr: JSXAttribute | JSXSpreadAttribute | undefined
|
|
10
|
+
): string | null {
|
|
11
|
+
if (!attr || attr.type !== "JSXAttribute" || !attr.value) return null
|
|
12
|
+
const value = attr.value
|
|
13
|
+
if (value.type === "Literal" || value.type === "StringLiteral") {
|
|
14
|
+
return typeof value.value === "string" ? value.value : null
|
|
15
|
+
}
|
|
16
|
+
// Handle expression containers with string literals, e.g. aria-label={"Name"}
|
|
17
|
+
if (
|
|
18
|
+
value.type === "JSXExpressionContainer" &&
|
|
19
|
+
value.expression &&
|
|
20
|
+
(value.expression.type === "Literal" ||
|
|
21
|
+
value.expression.type === "StringLiteral") &&
|
|
22
|
+
typeof value.expression.value === "string"
|
|
23
|
+
) {
|
|
24
|
+
return value.expression.value
|
|
25
|
+
}
|
|
26
|
+
return null
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const transform: Transform = attributeTransformFactory({
|
|
30
|
+
condition: andConditions(hasAttribute("aria-label"), hasAttribute("label")),
|
|
31
|
+
targetComponent: "TextArea",
|
|
32
|
+
targetPackage: "@planningcenter/tapestry-react",
|
|
33
|
+
transform: (element, { j, source }) => {
|
|
34
|
+
const attrs = element.openingElement.attributes || []
|
|
35
|
+
const labelAttr = attrs.find(
|
|
36
|
+
(a) => a.type === "JSXAttribute" && a.name.name === "label"
|
|
37
|
+
)
|
|
38
|
+
const ariaLabelAttr = attrs.find(
|
|
39
|
+
(a) => a.type === "JSXAttribute" && a.name.name === "aria-label"
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
const labelValue = getStaticStringValue(labelAttr)
|
|
43
|
+
const ariaLabelValue = getStaticStringValue(ariaLabelAttr)
|
|
44
|
+
|
|
45
|
+
// Only remove aria-label when both are static strings and equal
|
|
46
|
+
if (
|
|
47
|
+
labelValue != null &&
|
|
48
|
+
ariaLabelValue != null &&
|
|
49
|
+
labelValue === ariaLabelValue
|
|
50
|
+
) {
|
|
51
|
+
return removeAttribute("aria-label", { element, j, source })
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Otherwise keep aria-label to avoid accessibility regressions
|
|
55
|
+
return false
|
|
56
|
+
},
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
export default transform
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
import jscodeshift from "jscodeshift"
|
|
2
|
+
import { describe, expect, it } from "vitest"
|
|
3
|
+
|
|
4
|
+
import transform from "./sizeMapping"
|
|
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("sizeMapping transform", () => {
|
|
19
|
+
describe("size value transformations", () => {
|
|
20
|
+
it("should transform xs to md", () => {
|
|
21
|
+
const input = `
|
|
22
|
+
import { TextArea } from "@planningcenter/tapestry-react"
|
|
23
|
+
|
|
24
|
+
function Test() {
|
|
25
|
+
return <TextArea size="xs" label="Extra small textarea" />
|
|
26
|
+
}
|
|
27
|
+
`.trim()
|
|
28
|
+
|
|
29
|
+
const result = applyTransform(input)
|
|
30
|
+
expect(result).toContain('size="md"')
|
|
31
|
+
expect(result).not.toContain('size="xs"')
|
|
32
|
+
expect(result).toContain('Size "xs" was mapped to "md"')
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
it("should transform sm to md", () => {
|
|
36
|
+
const input = `
|
|
37
|
+
import { TextArea } from "@planningcenter/tapestry-react"
|
|
38
|
+
|
|
39
|
+
function Test() {
|
|
40
|
+
return <TextArea size="sm" label="Small textarea" />
|
|
41
|
+
}
|
|
42
|
+
`.trim()
|
|
43
|
+
|
|
44
|
+
const result = applyTransform(input)
|
|
45
|
+
expect(result).toContain('size="md"')
|
|
46
|
+
expect(result).not.toContain('size="sm"')
|
|
47
|
+
expect(result).toContain('Size "sm" was mapped to "md"')
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
it("should transform xl to lg", () => {
|
|
51
|
+
const input = `
|
|
52
|
+
import { TextArea } from "@planningcenter/tapestry-react"
|
|
53
|
+
|
|
54
|
+
function Test() {
|
|
55
|
+
return <TextArea size="xl" label="Extra large textarea" />
|
|
56
|
+
}
|
|
57
|
+
`.trim()
|
|
58
|
+
|
|
59
|
+
const result = applyTransform(input)
|
|
60
|
+
expect(result).toContain('size="lg"')
|
|
61
|
+
expect(result).not.toContain('size="xl"')
|
|
62
|
+
expect(result).toContain('Size "xl" was mapped to "lg"')
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
it('should transform size={"xs"} to md', () => {
|
|
66
|
+
const input = `
|
|
67
|
+
import { TextArea } from "@planningcenter/tapestry-react"
|
|
68
|
+
|
|
69
|
+
function Test() {
|
|
70
|
+
return <TextArea size={"xs"} label="Extra small textarea" />
|
|
71
|
+
}
|
|
72
|
+
`.trim()
|
|
73
|
+
|
|
74
|
+
const result = applyTransform(input)
|
|
75
|
+
expect(result).toContain('size="md"')
|
|
76
|
+
expect(result).toContain('Size "xs" was mapped to "md"')
|
|
77
|
+
})
|
|
78
|
+
|
|
79
|
+
it("should not transform supported sizes", () => {
|
|
80
|
+
const input = `
|
|
81
|
+
import { TextArea } from "@planningcenter/tapestry-react"
|
|
82
|
+
|
|
83
|
+
function Test() {
|
|
84
|
+
return (
|
|
85
|
+
<div>
|
|
86
|
+
<TextArea size="md" label="Medium textarea" />
|
|
87
|
+
<TextArea size="lg" label="Large textarea" />
|
|
88
|
+
</div>
|
|
89
|
+
)
|
|
90
|
+
}
|
|
91
|
+
`.trim()
|
|
92
|
+
|
|
93
|
+
const result = applyTransform(input)
|
|
94
|
+
expect(result).toContain('size="md"')
|
|
95
|
+
expect(result).toContain('size="lg"')
|
|
96
|
+
expect(result).not.toContain("TODO: tapestry-migration")
|
|
97
|
+
})
|
|
98
|
+
})
|
|
99
|
+
|
|
100
|
+
describe("edge cases", () => {
|
|
101
|
+
it("should not affect TextArea without size prop", () => {
|
|
102
|
+
const input = `
|
|
103
|
+
import { TextArea } from "@planningcenter/tapestry-react"
|
|
104
|
+
|
|
105
|
+
function Test() {
|
|
106
|
+
return <TextArea label="No size" />
|
|
107
|
+
}
|
|
108
|
+
`.trim()
|
|
109
|
+
|
|
110
|
+
const result = applyTransform(input)
|
|
111
|
+
expect(result).toBe(input)
|
|
112
|
+
})
|
|
113
|
+
|
|
114
|
+
it("should not affect other components", () => {
|
|
115
|
+
const input = `
|
|
116
|
+
import { Button, TextArea } from "@planningcenter/tapestry-react"
|
|
117
|
+
|
|
118
|
+
function Test() {
|
|
119
|
+
return (
|
|
120
|
+
<div>
|
|
121
|
+
<Button size="xs">Small button</Button>
|
|
122
|
+
<TextArea size="md" label="Medium textarea" />
|
|
123
|
+
</div>
|
|
124
|
+
)
|
|
125
|
+
}
|
|
126
|
+
`.trim()
|
|
127
|
+
|
|
128
|
+
const result = applyTransform(input)
|
|
129
|
+
expect(result).toContain('size="xs"')
|
|
130
|
+
expect(result).toContain('size="md"')
|
|
131
|
+
})
|
|
132
|
+
|
|
133
|
+
it("should handle multiple TextAreas with different sizes", () => {
|
|
134
|
+
const input = `
|
|
135
|
+
import { TextArea } from "@planningcenter/tapestry-react"
|
|
136
|
+
|
|
137
|
+
function Test() {
|
|
138
|
+
return (
|
|
139
|
+
<div>
|
|
140
|
+
<TextArea size="xs" label="Extra small" />
|
|
141
|
+
<TextArea size="sm" label="Small" />
|
|
142
|
+
<TextArea size="md" label="Medium" />
|
|
143
|
+
<TextArea size="xl" label="Extra large" />
|
|
144
|
+
</div>
|
|
145
|
+
)
|
|
146
|
+
}
|
|
147
|
+
`.trim()
|
|
148
|
+
|
|
149
|
+
const result = applyTransform(input)
|
|
150
|
+
expect(result).not.toContain('size="xs"')
|
|
151
|
+
expect(result).not.toContain('size="sm"')
|
|
152
|
+
expect(result).not.toContain('size="xl"')
|
|
153
|
+
// Should have 3 comments (xs->md, sm->md, xl->lg)
|
|
154
|
+
const sizeMappingMatches = result.match(/Size ".*" was mapped to/g)
|
|
155
|
+
expect(sizeMappingMatches).toHaveLength(3)
|
|
156
|
+
})
|
|
157
|
+
|
|
158
|
+
it("should preserve other props", () => {
|
|
159
|
+
const input = `
|
|
160
|
+
import { TextArea } from "@planningcenter/tapestry-react"
|
|
161
|
+
|
|
162
|
+
function Test() {
|
|
163
|
+
return (
|
|
164
|
+
<TextArea
|
|
165
|
+
size="xs"
|
|
166
|
+
label="Notes"
|
|
167
|
+
rows={5}
|
|
168
|
+
disabled
|
|
169
|
+
onChange={() => {}}
|
|
170
|
+
/>
|
|
171
|
+
)
|
|
172
|
+
}
|
|
173
|
+
`.trim()
|
|
174
|
+
|
|
175
|
+
const result = applyTransform(input)
|
|
176
|
+
expect(result).toContain('size="md"')
|
|
177
|
+
expect(result).toContain('label="Notes"')
|
|
178
|
+
expect(result).toContain("rows={5}")
|
|
179
|
+
expect(result).toContain("disabled")
|
|
180
|
+
expect(result).toContain("onChange={() => {}}")
|
|
181
|
+
expect(result).toContain('Size "xs" was mapped to "md"')
|
|
182
|
+
})
|
|
183
|
+
|
|
184
|
+
it("should not transform expression values", () => {
|
|
185
|
+
const input = `
|
|
186
|
+
import { TextArea } from "@planningcenter/tapestry-react"
|
|
187
|
+
|
|
188
|
+
function Test() {
|
|
189
|
+
const size = "xs"
|
|
190
|
+
return <TextArea size={size} label="Variable size" />
|
|
191
|
+
}
|
|
192
|
+
`.trim()
|
|
193
|
+
|
|
194
|
+
const result = applyTransform(input)
|
|
195
|
+
expect(result).toContain("size={size}")
|
|
196
|
+
expect(result).not.toContain("Size")
|
|
197
|
+
})
|
|
198
|
+
})
|
|
199
|
+
})
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Transform } from "jscodeshift"
|
|
2
|
+
|
|
3
|
+
import { sizeMappingFactory } from "../../shared/transformFactories/sizeMappingFactory"
|
|
4
|
+
|
|
5
|
+
const transform: Transform = sizeMappingFactory({
|
|
6
|
+
sizeMapping: {
|
|
7
|
+
sm: "md",
|
|
8
|
+
xl: "lg",
|
|
9
|
+
xs: "md",
|
|
10
|
+
},
|
|
11
|
+
targetComponent: "TextArea",
|
|
12
|
+
targetPackage: "@planningcenter/tapestry-react",
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
export default transform
|