@planningcenter/tapestry-migration-cli 2.2.1-qa-362.0 → 2.3.0-rc.10
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 +5065 -0
- package/package.json +9 -5
- package/src/components/button/index.ts +53 -3
- package/src/components/button/transforms/auditSpreadProps.test.ts +352 -0
- package/src/components/button/transforms/auditSpreadProps.ts +24 -0
- package/src/components/button/transforms/childrenToLabel.test.ts +363 -0
- package/src/components/button/transforms/childrenToLabel.ts +84 -0
- package/src/components/button/transforms/commentOnVisualKindDifference.ts +24 -0
- package/src/components/button/transforms/convertStyleProps.test.ts +464 -0
- package/src/components/button/transforms/convertStyleProps.ts +16 -0
- package/src/components/button/transforms/iconLeftToPrefix.test.ts +432 -0
- package/src/components/button/transforms/iconLeftToPrefix.ts +33 -0
- package/src/components/button/transforms/iconRightToSuffix.test.ts +407 -0
- package/src/components/button/transforms/iconRightToSuffix.ts +33 -0
- package/src/components/button/transforms/iconToIconButton.test.ts +377 -0
- package/src/components/button/transforms/iconToIconButton.ts +53 -0
- package/src/components/button/transforms/removeAsButton.ts +15 -0
- package/src/components/button/transforms/removeDuplicateKeys.test.ts +302 -0
- package/src/components/button/transforms/removeDuplicateKeys.ts +8 -0
- package/src/components/button/transforms/reviewStyles.ts +17 -0
- package/src/components/button/transforms/spinnerToLoadingButton.test.ts +165 -0
- package/src/components/button/transforms/spinnerToLoadingButton.ts +14 -0
- package/src/components/button/transforms/themeVariantToKind.test.ts +401 -0
- package/src/components/button/transforms/themeVariantToKind.ts +90 -0
- package/src/components/button/transforms/tooltipToWrapper.test.ts +392 -0
- package/src/components/button/transforms/tooltipToWrapper.ts +35 -0
- package/src/components/button/transforms/unsupportedProps.ts +73 -0
- package/src/components/shared/actions/addAttribute.test.ts +300 -0
- package/src/components/shared/actions/addAttribute.ts +65 -0
- package/src/components/shared/actions/addComment.test.ts +1 -1
- package/src/components/shared/actions/addCommentToAttribute.test.ts +45 -0
- package/src/components/shared/actions/addCommentToAttribute.ts +28 -0
- package/src/components/shared/actions/addCommentToUnsupportedProps.ts +29 -0
- package/src/components/shared/actions/convertAttributeFromObjectToJSXElement.test.ts +139 -0
- package/src/components/shared/actions/convertAttributeFromObjectToJSXElement.ts +81 -0
- package/src/components/shared/actions/createWrapper.test.ts +642 -0
- package/src/components/shared/actions/createWrapper.ts +70 -0
- package/src/components/shared/actions/getAttribute.ts +18 -0
- package/src/components/shared/actions/getAttributeValue.test.ts +261 -0
- package/src/components/shared/actions/getAttributeValue.ts +15 -0
- package/src/components/shared/actions/getAttributeValueAsProps.ts +57 -0
- package/src/components/shared/actions/getSpreadProps.ts +7 -0
- package/src/components/shared/actions/hasSpreadProps.ts +7 -0
- package/src/components/shared/actions/removeChildren.ts +7 -0
- package/src/components/shared/actions/removeDuplicateKeys.test.ts +280 -0
- package/src/components/shared/actions/removeDuplicateKeys.ts +45 -0
- package/src/components/shared/actions/removeUnusedImport.test.ts +302 -0
- package/src/components/shared/actions/removeUnusedImport.ts +81 -0
- package/src/components/shared/actions/transformElementName.test.ts +9 -9
- package/src/components/shared/actions/transformElementName.ts +13 -16
- package/src/components/shared/conditions/hasChildren.ts +5 -0
- package/src/components/shared/getJavaScriptTheme.ts +68 -0
- package/src/components/shared/jsThemeLoader.ts +85 -0
- package/src/components/shared/transformFactories/attributeCombineFactory.test.ts +374 -0
- package/src/components/shared/transformFactories/attributeCombineFactory.ts +300 -0
- package/src/components/shared/transformFactories/attributeTransformFactory.ts +14 -6
- package/src/components/shared/transformFactories/componentTransformFactory.ts +1 -1
- package/src/components/shared/transformFactories/helpers/addImport.test.ts +278 -0
- package/src/components/shared/transformFactories/helpers/manageImports.ts +53 -20
- package/src/components/shared/transformFactories/stylePropTransformFactory.ts +362 -0
- package/src/index.ts +4 -0
- package/src/stubs/stackViewPlugin.ts +33 -0
- package/src/stubs/tapestry-stub.ts +16 -0
- package/src/tapestry-react-shim.ts +7 -0
|
@@ -0,0 +1,302 @@
|
|
|
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("Button elements with duplicate attributes", () => {
|
|
19
|
+
it("should remove duplicate attributes from Button elements", () => {
|
|
20
|
+
const source = `
|
|
21
|
+
import { Button } from "@planningcenter/tapestry-react"
|
|
22
|
+
|
|
23
|
+
export function TestComponent() {
|
|
24
|
+
return <Button kind="primary" disabled kind="secondary">Save</Button>
|
|
25
|
+
}
|
|
26
|
+
`
|
|
27
|
+
|
|
28
|
+
const result = applyTransform(source)
|
|
29
|
+
|
|
30
|
+
expect(result).not.toBeNull()
|
|
31
|
+
expect(result).toContain('kind="primary"')
|
|
32
|
+
expect(result).not.toContain('kind="secondary"')
|
|
33
|
+
expect(result).toContain("disabled")
|
|
34
|
+
expect(result).toContain("Save")
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
it("should handle multiple Button elements with duplicates", () => {
|
|
38
|
+
const source = `
|
|
39
|
+
import { Button } from "@planningcenter/tapestry-react"
|
|
40
|
+
|
|
41
|
+
export function TestComponent() {
|
|
42
|
+
return (
|
|
43
|
+
<div>
|
|
44
|
+
<Button kind="primary" size="large" kind="secondary">Save</Button>
|
|
45
|
+
<Button disabled loading disabled>Cancel</Button>
|
|
46
|
+
</div>
|
|
47
|
+
)
|
|
48
|
+
}
|
|
49
|
+
`
|
|
50
|
+
|
|
51
|
+
const result = applyTransform(source)
|
|
52
|
+
|
|
53
|
+
expect(result).not.toBeNull()
|
|
54
|
+
expect(result).toContain('kind="primary"')
|
|
55
|
+
expect(result).not.toContain('kind="secondary"')
|
|
56
|
+
expect(result).toContain('size="large"')
|
|
57
|
+
|
|
58
|
+
expect(result).toContain("<Button disabled loading>")
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
it("should preserve first occurrence of duplicate attributes", () => {
|
|
62
|
+
const source = `
|
|
63
|
+
import { Button } from "@planningcenter/tapestry-react"
|
|
64
|
+
|
|
65
|
+
export function TestComponent() {
|
|
66
|
+
return <Button onClick={handleFirst} aria-label="First" onClick={handleSecond} aria-label="Second">Click</Button>
|
|
67
|
+
}
|
|
68
|
+
`
|
|
69
|
+
|
|
70
|
+
const result = applyTransform(source)
|
|
71
|
+
|
|
72
|
+
expect(result).not.toBeNull()
|
|
73
|
+
expect(result).toContain("onClick={handleFirst}")
|
|
74
|
+
expect(result).not.toContain("onClick={handleSecond}")
|
|
75
|
+
expect(result).toContain('aria-label="First"')
|
|
76
|
+
expect(result).not.toContain('aria-label="Second"')
|
|
77
|
+
})
|
|
78
|
+
})
|
|
79
|
+
|
|
80
|
+
describe("Button elements without duplicate attributes", () => {
|
|
81
|
+
it("should return null when no duplicates exist", () => {
|
|
82
|
+
const source = `
|
|
83
|
+
import { Button } from "@planningcenter/tapestry-react"
|
|
84
|
+
|
|
85
|
+
export function TestComponent() {
|
|
86
|
+
return <Button kind="primary" size="large" disabled>Save</Button>
|
|
87
|
+
}
|
|
88
|
+
`
|
|
89
|
+
|
|
90
|
+
const result = applyTransform(source)
|
|
91
|
+
|
|
92
|
+
expect(result).toBeNull() // No changes needed
|
|
93
|
+
})
|
|
94
|
+
|
|
95
|
+
it("should return null for Button with no attributes", () => {
|
|
96
|
+
const source = `
|
|
97
|
+
import { Button } from "@planningcenter/tapestry-react"
|
|
98
|
+
|
|
99
|
+
export function TestComponent() {
|
|
100
|
+
return <Button>Save</Button>
|
|
101
|
+
}
|
|
102
|
+
`
|
|
103
|
+
|
|
104
|
+
const result = applyTransform(source)
|
|
105
|
+
|
|
106
|
+
expect(result).toBeNull()
|
|
107
|
+
})
|
|
108
|
+
})
|
|
109
|
+
|
|
110
|
+
describe("import handling", () => {
|
|
111
|
+
it("should only process files that import Button from tapestry-react", () => {
|
|
112
|
+
const source = `
|
|
113
|
+
import { Button } from "some-other-library"
|
|
114
|
+
|
|
115
|
+
export function TestComponent() {
|
|
116
|
+
return <Button kind="primary" kind="secondary">Save</Button>
|
|
117
|
+
}
|
|
118
|
+
`
|
|
119
|
+
|
|
120
|
+
const result = applyTransform(source)
|
|
121
|
+
|
|
122
|
+
expect(result).toBeNull() // Should not process non-tapestry Buttons
|
|
123
|
+
})
|
|
124
|
+
|
|
125
|
+
it("should handle aliased Button imports", () => {
|
|
126
|
+
const source = `
|
|
127
|
+
import { Button as TapestryButton } from "@planningcenter/tapestry-react"
|
|
128
|
+
|
|
129
|
+
export function TestComponent() {
|
|
130
|
+
return <TapestryButton kind="primary" disabled kind="secondary">Save</TapestryButton>
|
|
131
|
+
}
|
|
132
|
+
`
|
|
133
|
+
|
|
134
|
+
const result = applyTransform(source)
|
|
135
|
+
|
|
136
|
+
expect(result).not.toBeNull()
|
|
137
|
+
expect(result).toContain("<TapestryButton")
|
|
138
|
+
expect(result).toContain('kind="primary"')
|
|
139
|
+
expect(result).not.toContain('kind="secondary"')
|
|
140
|
+
expect(result).toContain("</TapestryButton>")
|
|
141
|
+
})
|
|
142
|
+
|
|
143
|
+
it("should handle renamed imports", () => {
|
|
144
|
+
const source = `
|
|
145
|
+
import { Button as PrimaryButton } from "@planningcenter/tapestry-react"
|
|
146
|
+
|
|
147
|
+
export function TestComponent() {
|
|
148
|
+
return <PrimaryButton size="large" onClick={handler} size="small">Click</PrimaryButton>
|
|
149
|
+
}
|
|
150
|
+
`
|
|
151
|
+
|
|
152
|
+
const result = applyTransform(source)
|
|
153
|
+
|
|
154
|
+
expect(result).not.toBeNull()
|
|
155
|
+
expect(result).toContain('size="large"')
|
|
156
|
+
expect(result).not.toContain('size="small"')
|
|
157
|
+
})
|
|
158
|
+
})
|
|
159
|
+
|
|
160
|
+
describe("mixed elements", () => {
|
|
161
|
+
it("should only process Button elements, not other elements", () => {
|
|
162
|
+
const source = `
|
|
163
|
+
import { Button } from "@planningcenter/tapestry-react"
|
|
164
|
+
|
|
165
|
+
export function TestComponent() {
|
|
166
|
+
return (
|
|
167
|
+
<div>
|
|
168
|
+
<Button kind="primary" kind="secondary">Save</Button>
|
|
169
|
+
<div className="container" className="wrapper">Content</div>
|
|
170
|
+
<span role="button" role="link">Text</span>
|
|
171
|
+
</div>
|
|
172
|
+
)
|
|
173
|
+
}
|
|
174
|
+
`
|
|
175
|
+
|
|
176
|
+
const result = applyTransform(source)
|
|
177
|
+
|
|
178
|
+
expect(result).not.toBeNull()
|
|
179
|
+
|
|
180
|
+
// Button duplicates should be removed
|
|
181
|
+
expect(result).toContain('kind="primary"')
|
|
182
|
+
expect(result).not.toContain('kind="secondary"')
|
|
183
|
+
|
|
184
|
+
// Other elements should remain unchanged (duplicates preserved)
|
|
185
|
+
expect(result).toContain('className="container"')
|
|
186
|
+
expect(result).toContain('className="wrapper"')
|
|
187
|
+
expect(result).toContain('role="button"')
|
|
188
|
+
expect(result).toContain('role="link"')
|
|
189
|
+
})
|
|
190
|
+
|
|
191
|
+
it("should process multiple Button elements independently", () => {
|
|
192
|
+
const source = `
|
|
193
|
+
import { Button } from "@planningcenter/tapestry-react"
|
|
194
|
+
|
|
195
|
+
export function TestComponent() {
|
|
196
|
+
return (
|
|
197
|
+
<form>
|
|
198
|
+
<Button type="submit" kind="primary" type="button">Submit</Button>
|
|
199
|
+
<Button disabled loading disabled>Loading</Button>
|
|
200
|
+
<Button size="small">Small</Button>
|
|
201
|
+
</form>
|
|
202
|
+
)
|
|
203
|
+
}
|
|
204
|
+
`
|
|
205
|
+
|
|
206
|
+
const result = applyTransform(source)
|
|
207
|
+
|
|
208
|
+
expect(result).not.toBeNull()
|
|
209
|
+
|
|
210
|
+
// First button: should keep first 'type'
|
|
211
|
+
expect(result).toContain('type="submit"')
|
|
212
|
+
expect(result).not.toContain('type="button"')
|
|
213
|
+
|
|
214
|
+
expect(result).toContain("<Button disabled loading>")
|
|
215
|
+
|
|
216
|
+
// Third button: should remain unchanged
|
|
217
|
+
expect(result).toContain('size="small"')
|
|
218
|
+
})
|
|
219
|
+
})
|
|
220
|
+
|
|
221
|
+
describe("complex JSX scenarios", () => {
|
|
222
|
+
it("should handle nested Button elements", () => {
|
|
223
|
+
const source = `
|
|
224
|
+
import { Button } from "@planningcenter/tapestry-react"
|
|
225
|
+
|
|
226
|
+
export function TestComponent() {
|
|
227
|
+
return (
|
|
228
|
+
<div>
|
|
229
|
+
<div className="toolbar">
|
|
230
|
+
<Button kind="primary" disabled kind="secondary">
|
|
231
|
+
Save
|
|
232
|
+
</Button>
|
|
233
|
+
</div>
|
|
234
|
+
<Button size="large" onClick={handler} size="small">
|
|
235
|
+
Cancel
|
|
236
|
+
</Button>
|
|
237
|
+
</div>
|
|
238
|
+
)
|
|
239
|
+
}
|
|
240
|
+
`
|
|
241
|
+
|
|
242
|
+
const result = applyTransform(source)
|
|
243
|
+
|
|
244
|
+
expect(result).not.toBeNull()
|
|
245
|
+
expect(result).toContain('kind="primary"')
|
|
246
|
+
expect(result).not.toContain('kind="secondary"')
|
|
247
|
+
expect(result).toContain('size="large"')
|
|
248
|
+
expect(result).not.toContain('size="small"')
|
|
249
|
+
})
|
|
250
|
+
|
|
251
|
+
it("should handle Button elements with children and complex attributes", () => {
|
|
252
|
+
const source = `
|
|
253
|
+
import { Button } from "@planningcenter/tapestry-react"
|
|
254
|
+
|
|
255
|
+
export function TestComponent() {
|
|
256
|
+
return (
|
|
257
|
+
<Button
|
|
258
|
+
kind="primary"
|
|
259
|
+
onClick={() => console.log('first')}
|
|
260
|
+
className="btn-primary"
|
|
261
|
+
kind="secondary"
|
|
262
|
+
onClick={() => console.log('second')}
|
|
263
|
+
data-testid="save-button"
|
|
264
|
+
>
|
|
265
|
+
<span>Save Changes</span>
|
|
266
|
+
</Button>
|
|
267
|
+
)
|
|
268
|
+
}
|
|
269
|
+
`
|
|
270
|
+
|
|
271
|
+
const result = applyTransform(source)
|
|
272
|
+
|
|
273
|
+
expect(result).not.toBeNull()
|
|
274
|
+
expect(result).toContain('kind="primary"')
|
|
275
|
+
expect(result).not.toContain('kind="secondary"')
|
|
276
|
+
expect(result).toContain("onClick={() => console.log('first')}")
|
|
277
|
+
expect(result).not.toContain("onClick={() => console.log('second')}")
|
|
278
|
+
expect(result).toContain('data-testid="save-button"')
|
|
279
|
+
expect(result).toContain("<span>Save Changes</span>")
|
|
280
|
+
})
|
|
281
|
+
})
|
|
282
|
+
|
|
283
|
+
describe("self-closing Button elements", () => {
|
|
284
|
+
it("should handle self-closing Button elements with duplicates", () => {
|
|
285
|
+
const source = `
|
|
286
|
+
import { Button } from "@planningcenter/tapestry-react"
|
|
287
|
+
|
|
288
|
+
export function TestComponent() {
|
|
289
|
+
return <Button kind="primary" disabled kind="secondary" />
|
|
290
|
+
}
|
|
291
|
+
`
|
|
292
|
+
|
|
293
|
+
const result = applyTransform(source)
|
|
294
|
+
|
|
295
|
+
expect(result).not.toBeNull()
|
|
296
|
+
expect(result).toContain('kind="primary"')
|
|
297
|
+
expect(result).not.toContain('kind="secondary"')
|
|
298
|
+
expect(result).toContain("disabled")
|
|
299
|
+
expect(result).toContain("/>")
|
|
300
|
+
})
|
|
301
|
+
})
|
|
302
|
+
})
|
|
@@ -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: "Button",
|
|
6
|
+
targetPackage: "@planningcenter/tapestry-react",
|
|
7
|
+
transform: removeDuplicateKeys,
|
|
8
|
+
})
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { addCommentToAttribute } from "../../shared/actions/addCommentToAttribute"
|
|
2
|
+
import { getAttribute } from "../../shared/actions/getAttribute"
|
|
3
|
+
import { hasAttribute } from "../../shared/conditions/hasAttribute"
|
|
4
|
+
import { attributeTransformFactory } from "../../shared/transformFactories/attributeTransformFactory"
|
|
5
|
+
|
|
6
|
+
const COMMENT = `review custom styles - Button styles may need to be updated for new design system.`
|
|
7
|
+
|
|
8
|
+
export default attributeTransformFactory({
|
|
9
|
+
condition: hasAttribute("style"),
|
|
10
|
+
targetComponent: "Button",
|
|
11
|
+
targetPackage: "@planningcenter/tapestry-react",
|
|
12
|
+
transform: (element, { j }) => {
|
|
13
|
+
const attribute = getAttribute({ element, name: "style" })!
|
|
14
|
+
addCommentToAttribute({ attribute, j, text: COMMENT })
|
|
15
|
+
return true
|
|
16
|
+
},
|
|
17
|
+
})
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import jscodeshift from "jscodeshift"
|
|
2
|
+
import { describe, expect, it } from "vitest"
|
|
3
|
+
|
|
4
|
+
import transform from "./spinnerToLoadingButton"
|
|
5
|
+
|
|
6
|
+
const j = jscodeshift.withParser("tsx")
|
|
7
|
+
|
|
8
|
+
function applyTransform(source: string, options = {}) {
|
|
9
|
+
const fileInfo = { path: "test.tsx", source }
|
|
10
|
+
return transform(
|
|
11
|
+
fileInfo,
|
|
12
|
+
{ j, jscodeshift: j, report: () => {}, stats: () => {} },
|
|
13
|
+
options
|
|
14
|
+
) as string | null
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
describe("spinnerToLoadingButton transform", () => {
|
|
18
|
+
describe("Button with spinner prop", () => {
|
|
19
|
+
it("should Button with spinner to use loading prop", () => {
|
|
20
|
+
const source = `
|
|
21
|
+
import { Button } from "@planningcenter/tapestry-react"
|
|
22
|
+
|
|
23
|
+
export function TestComponent() {
|
|
24
|
+
return <Button spinner={isLoading} kind="primary">Save</Button>
|
|
25
|
+
}
|
|
26
|
+
`
|
|
27
|
+
|
|
28
|
+
const result = applyTransform(source)
|
|
29
|
+
|
|
30
|
+
expect(result).toContain("<Button")
|
|
31
|
+
expect(result).toContain("</Button>")
|
|
32
|
+
expect(result).toContain("loading={isLoading}")
|
|
33
|
+
expect(result).not.toContain("spinner={isLoading}")
|
|
34
|
+
expect(result).toContain('kind="primary"')
|
|
35
|
+
expect(result).toContain("Save")
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
it("should handle self-closing Button with spinner", () => {
|
|
39
|
+
const source = `
|
|
40
|
+
import { Button } from "@planningcenter/tapestry-react"
|
|
41
|
+
|
|
42
|
+
export function TestComponent() {
|
|
43
|
+
return <Button spinner={true} aria-label="Loading" />
|
|
44
|
+
}
|
|
45
|
+
`
|
|
46
|
+
|
|
47
|
+
const result = applyTransform(source)
|
|
48
|
+
|
|
49
|
+
expect(result).toContain("<Button")
|
|
50
|
+
expect(result).toContain("loading={true}")
|
|
51
|
+
expect(result).toContain('aria-label="Loading" />')
|
|
52
|
+
expect(result).not.toContain("spinner={true}")
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
it("should handle boolean spinner prop", () => {
|
|
56
|
+
const source = `
|
|
57
|
+
import { Button } from "@planningcenter/tapestry-react"
|
|
58
|
+
|
|
59
|
+
export function TestComponent() {
|
|
60
|
+
return <Button spinner disabled>Loading...</Button>
|
|
61
|
+
}
|
|
62
|
+
`
|
|
63
|
+
|
|
64
|
+
const result = applyTransform(source)
|
|
65
|
+
|
|
66
|
+
expect(result).toContain("<Button")
|
|
67
|
+
expect(result).toContain("loading")
|
|
68
|
+
expect(result).toContain("disabled")
|
|
69
|
+
expect(result).not.toContain("spinner")
|
|
70
|
+
})
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
describe("Button without spinner prop", () => {
|
|
74
|
+
it("should return null when no spinner prop is present", () => {
|
|
75
|
+
const source = `
|
|
76
|
+
import { Button } from "@planningcenter/tapestry-react"
|
|
77
|
+
|
|
78
|
+
export function TestComponent() {
|
|
79
|
+
return <Button kind="primary">No Spinner</Button>
|
|
80
|
+
}
|
|
81
|
+
`
|
|
82
|
+
|
|
83
|
+
const result = applyTransform(source)
|
|
84
|
+
|
|
85
|
+
expect(result).toBeNull()
|
|
86
|
+
})
|
|
87
|
+
|
|
88
|
+
it("should not process non-tapestry Buttons", () => {
|
|
89
|
+
const source = `
|
|
90
|
+
import { Button } from "some-other-library"
|
|
91
|
+
|
|
92
|
+
export function TestComponent() {
|
|
93
|
+
return <Button spinner={true}>Other Button</Button>
|
|
94
|
+
}
|
|
95
|
+
`
|
|
96
|
+
|
|
97
|
+
const result = applyTransform(source)
|
|
98
|
+
|
|
99
|
+
expect(result).toBeNull()
|
|
100
|
+
})
|
|
101
|
+
})
|
|
102
|
+
|
|
103
|
+
describe("edge cases", () => {
|
|
104
|
+
it("should preserve all other Button props", () => {
|
|
105
|
+
const source = `
|
|
106
|
+
import { Button } from "@planningcenter/tapestry-react"
|
|
107
|
+
|
|
108
|
+
export function TestComponent() {
|
|
109
|
+
return (
|
|
110
|
+
<Button
|
|
111
|
+
spinner={isSubmitting}
|
|
112
|
+
kind="primary"
|
|
113
|
+
size="large"
|
|
114
|
+
disabled={isDisabled}
|
|
115
|
+
onClick={handleClick}
|
|
116
|
+
className="submit-btn"
|
|
117
|
+
type="submit"
|
|
118
|
+
>
|
|
119
|
+
Submit Form
|
|
120
|
+
</Button>
|
|
121
|
+
)
|
|
122
|
+
}
|
|
123
|
+
`
|
|
124
|
+
|
|
125
|
+
const result = applyTransform(source)
|
|
126
|
+
|
|
127
|
+
expect(result).toContain('kind="primary"')
|
|
128
|
+
expect(result).toContain('size="large"')
|
|
129
|
+
expect(result).toContain("disabled={isDisabled}")
|
|
130
|
+
expect(result).toContain("onClick={handleClick}")
|
|
131
|
+
expect(result).toContain('className="submit-btn"')
|
|
132
|
+
expect(result).toContain('type="submit"')
|
|
133
|
+
expect(result).toContain("Submit Form")
|
|
134
|
+
expect(result).toContain("<Button")
|
|
135
|
+
expect(result).toContain("loading={isSubmitting}")
|
|
136
|
+
expect(result).not.toContain("spinner={isSubmitting}")
|
|
137
|
+
})
|
|
138
|
+
|
|
139
|
+
it("should handle multiple Buttons with different spinner configurations", () => {
|
|
140
|
+
const source = `
|
|
141
|
+
import { Button } from "@planningcenter/tapestry-react"
|
|
142
|
+
|
|
143
|
+
export function TestComponent() {
|
|
144
|
+
return (
|
|
145
|
+
<div>
|
|
146
|
+
<Button spinner={loading1}>Save</Button>
|
|
147
|
+
<Button kind="secondary">Cancel</Button>
|
|
148
|
+
<Button spinner={loading2} disabled>Delete</Button>
|
|
149
|
+
</div>
|
|
150
|
+
)
|
|
151
|
+
}
|
|
152
|
+
`
|
|
153
|
+
|
|
154
|
+
const result = applyTransform(source)
|
|
155
|
+
|
|
156
|
+
expect(result).not.toBeNull()
|
|
157
|
+
|
|
158
|
+
expect(result).toContain('<Button kind="secondary">Cancel</Button>')
|
|
159
|
+
expect(result).toContain("<Button loading={loading1}")
|
|
160
|
+
expect(result).toContain("<Button loading={loading2}")
|
|
161
|
+
expect(result).not.toContain("spinner={loading1}")
|
|
162
|
+
expect(result).not.toContain("spinner={loading2}")
|
|
163
|
+
})
|
|
164
|
+
})
|
|
165
|
+
})
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { transformAttributeName } from "../../shared/actions/transformAttributeName"
|
|
2
|
+
import { hasAttribute } from "../../shared/conditions/hasAttribute"
|
|
3
|
+
import { attributeTransformFactory } from "../../shared/transformFactories/attributeTransformFactory"
|
|
4
|
+
|
|
5
|
+
export default attributeTransformFactory({
|
|
6
|
+
condition: hasAttribute("spinner"),
|
|
7
|
+
targetComponent: "Button",
|
|
8
|
+
targetPackage: "@planningcenter/tapestry-react",
|
|
9
|
+
transform: (element) => {
|
|
10
|
+
transformAttributeName("spinner", "loading", { element })
|
|
11
|
+
|
|
12
|
+
return true
|
|
13
|
+
},
|
|
14
|
+
})
|