@planningcenter/tapestry-migration-cli 2.3.0-rc.4 → 2.3.0-rc.6
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/package.json +2 -2
- package/src/components/button/index.ts +3 -1
- package/src/components/button/transforms/themeVariantToKind.test.ts +401 -0
- package/src/components/button/transforms/themeVariantToKind.ts +90 -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/getAttributeValue.test.ts +261 -0
- package/src/components/shared/actions/getAttributeValue.ts +15 -0
- package/src/components/shared/transformFactories/attributeCombineFactory.test.ts +374 -0
- package/src/components/shared/transformFactories/attributeCombineFactory.ts +300 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@planningcenter/tapestry-migration-cli",
|
|
3
|
-
"version": "2.3.0-rc.
|
|
3
|
+
"version": "2.3.0-rc.6",
|
|
4
4
|
"description": "CLI tool for Tapestry migrations",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -47,5 +47,5 @@
|
|
|
47
47
|
"publishConfig": {
|
|
48
48
|
"access": "public"
|
|
49
49
|
},
|
|
50
|
-
"gitHead": "
|
|
50
|
+
"gitHead": "3fd2471ea7cb42e4fcf68d4c62bdd97c66282978"
|
|
51
51
|
}
|
|
@@ -5,6 +5,7 @@ import iconRightToSuffix from "./transforms/iconRightToSuffix"
|
|
|
5
5
|
import linkToButton from "./transforms/linkToButton"
|
|
6
6
|
import moveButtonImport from "./transforms/moveButtonImport"
|
|
7
7
|
import removeToTransform from "./transforms/removeTo"
|
|
8
|
+
import themeVariantToKind from "./transforms/themeVariantToKind"
|
|
8
9
|
import titleToLabel from "./transforms/titleToLabel"
|
|
9
10
|
import tooltipToWrapper from "./transforms/tooltipToWrapper"
|
|
10
11
|
|
|
@@ -14,10 +15,11 @@ const transform: Transform = (fileInfo, api, options) => {
|
|
|
14
15
|
|
|
15
16
|
const transforms: Transform[] = [
|
|
16
17
|
linkToButton,
|
|
17
|
-
titleToLabel,
|
|
18
18
|
tooltipToWrapper,
|
|
19
19
|
iconRightToSuffix,
|
|
20
20
|
iconLeftToPrefix,
|
|
21
|
+
themeVariantToKind,
|
|
22
|
+
titleToLabel,
|
|
21
23
|
removeToTransform,
|
|
22
24
|
moveButtonImport,
|
|
23
25
|
]
|
|
@@ -0,0 +1,401 @@
|
|
|
1
|
+
import jscodeshift from "jscodeshift"
|
|
2
|
+
import { describe, expect, it } from "vitest"
|
|
3
|
+
|
|
4
|
+
import transform from "./themeVariantToKind"
|
|
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("themeVariantToKind", () => {
|
|
18
|
+
describe("supported theme/variant combinations", () => {
|
|
19
|
+
it("should convert primary/fill to kind primary", () => {
|
|
20
|
+
const source = `
|
|
21
|
+
import { Button } from "@planningcenter/tapestry-react"
|
|
22
|
+
<Button theme="primary" variant="fill">Save</Button>
|
|
23
|
+
`
|
|
24
|
+
|
|
25
|
+
const result = applyTransform(source)
|
|
26
|
+
|
|
27
|
+
expect(result).toContain('kind="primary"')
|
|
28
|
+
expect(result).not.toContain('theme="primary"')
|
|
29
|
+
expect(result).not.toContain('variant="fill"')
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
it("should convert default/outline to kind secondary", () => {
|
|
33
|
+
const source = `
|
|
34
|
+
import { Button } from "@planningcenter/tapestry-react"
|
|
35
|
+
<Button theme="default" variant="outline">Cancel</Button>
|
|
36
|
+
`
|
|
37
|
+
|
|
38
|
+
const result = applyTransform(source)
|
|
39
|
+
|
|
40
|
+
expect(result).toContain('kind="secondary"')
|
|
41
|
+
expect(result).not.toContain('theme="default"')
|
|
42
|
+
expect(result).not.toContain('variant="outline"')
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
it("should convert destroy/naked to kind ghost-delete", () => {
|
|
46
|
+
const source = `
|
|
47
|
+
import { Button } from "@planningcenter/tapestry-react"
|
|
48
|
+
<Button theme="destroy" variant="naked">Delete</Button>
|
|
49
|
+
`
|
|
50
|
+
|
|
51
|
+
const result = applyTransform(source)
|
|
52
|
+
|
|
53
|
+
expect(result).toContain('kind="ghost-delete"')
|
|
54
|
+
expect(result).not.toContain('theme="destroy"')
|
|
55
|
+
expect(result).not.toContain('variant="naked"')
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
it("should handle error theme (alias for destroy)", () => {
|
|
59
|
+
const source = `
|
|
60
|
+
import { Button } from "@planningcenter/tapestry-react"
|
|
61
|
+
<Button theme="error" variant="outline">Error</Button>
|
|
62
|
+
`
|
|
63
|
+
|
|
64
|
+
const result = applyTransform(source)
|
|
65
|
+
|
|
66
|
+
expect(result).toContain('kind="secondary-delete"')
|
|
67
|
+
expect(result).not.toContain('theme="error"')
|
|
68
|
+
expect(result).not.toContain('variant="outline"')
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
it("should handle default values when props are missing", () => {
|
|
72
|
+
const source = `
|
|
73
|
+
import { Button } from "@planningcenter/tapestry-react"
|
|
74
|
+
<Button theme="primary">Save</Button>
|
|
75
|
+
`
|
|
76
|
+
|
|
77
|
+
const result = applyTransform(source)
|
|
78
|
+
|
|
79
|
+
expect(result).toContain('kind="primary"')
|
|
80
|
+
expect(result).not.toContain('theme="primary"')
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
it("should handle variant only", () => {
|
|
84
|
+
const source = `
|
|
85
|
+
import { Button } from "@planningcenter/tapestry-react"
|
|
86
|
+
<Button variant="outline">Cancel</Button>
|
|
87
|
+
`
|
|
88
|
+
|
|
89
|
+
const result = applyTransform(source)
|
|
90
|
+
|
|
91
|
+
expect(result).toContain('kind="secondary"')
|
|
92
|
+
expect(result).not.toContain('variant="outline"')
|
|
93
|
+
})
|
|
94
|
+
})
|
|
95
|
+
|
|
96
|
+
describe("unsupported theme/variant combinations", () => {
|
|
97
|
+
it("should add comment for unsupported theme", () => {
|
|
98
|
+
const source = `
|
|
99
|
+
import { Button } from "@planningcenter/tapestry-react"
|
|
100
|
+
<Button theme="custom" variant="fill">Save</Button>
|
|
101
|
+
`
|
|
102
|
+
|
|
103
|
+
const result = applyTransform(source)
|
|
104
|
+
|
|
105
|
+
expect(result).toContain(
|
|
106
|
+
"TODO: tapestry-migration (theme/variant): cannot be converted"
|
|
107
|
+
)
|
|
108
|
+
expect(result).toContain('theme="custom"') // in the comment
|
|
109
|
+
expect(result).toContain('variant="fill"') // in the comment
|
|
110
|
+
expect(result).not.toContain("kind=")
|
|
111
|
+
// Attributes should be removed from the element itself
|
|
112
|
+
expect(result).toContain("<Button>Save</Button>") // no attributes left
|
|
113
|
+
})
|
|
114
|
+
|
|
115
|
+
it("should add comment for unsupported variant", () => {
|
|
116
|
+
const source = `
|
|
117
|
+
import { Button } from "@planningcenter/tapestry-react"
|
|
118
|
+
<Button theme="primary" variant="custom">Save</Button>
|
|
119
|
+
`
|
|
120
|
+
|
|
121
|
+
const result = applyTransform(source)
|
|
122
|
+
|
|
123
|
+
expect(result).toContain(
|
|
124
|
+
"TODO: tapestry-migration (theme/variant): cannot be converted"
|
|
125
|
+
)
|
|
126
|
+
expect(result).toContain('theme="primary"')
|
|
127
|
+
expect(result).toContain('variant="custom"')
|
|
128
|
+
expect(result).not.toContain("kind=")
|
|
129
|
+
})
|
|
130
|
+
|
|
131
|
+
it("should add comment for unsupported theme only", () => {
|
|
132
|
+
const source = `
|
|
133
|
+
import { Button } from "@planningcenter/tapestry-react"
|
|
134
|
+
<Button theme="unsupported">Save</Button>
|
|
135
|
+
`
|
|
136
|
+
|
|
137
|
+
const result = applyTransform(source)
|
|
138
|
+
|
|
139
|
+
expect(result).toContain(
|
|
140
|
+
"TODO: tapestry-migration (theme/variant): cannot be converted"
|
|
141
|
+
)
|
|
142
|
+
expect(result).toContain('theme="unsupported"')
|
|
143
|
+
expect(result).not.toContain("kind=")
|
|
144
|
+
})
|
|
145
|
+
|
|
146
|
+
it("should add comment for unsupported variant only", () => {
|
|
147
|
+
const source = `
|
|
148
|
+
import { Button } from "@planningcenter/tapestry-react"
|
|
149
|
+
<Button variant="unsupported">Save</Button>
|
|
150
|
+
`
|
|
151
|
+
|
|
152
|
+
const result = applyTransform(source)
|
|
153
|
+
|
|
154
|
+
expect(result).toContain(
|
|
155
|
+
"TODO: tapestry-migration (theme/variant): cannot be converted"
|
|
156
|
+
)
|
|
157
|
+
expect(result).toContain('variant="unsupported"')
|
|
158
|
+
expect(result).not.toContain("kind=")
|
|
159
|
+
})
|
|
160
|
+
})
|
|
161
|
+
|
|
162
|
+
describe("expression containers", () => {
|
|
163
|
+
it("should handle theme as expression", () => {
|
|
164
|
+
const source = `
|
|
165
|
+
import { Button } from "@planningcenter/tapestry-react"
|
|
166
|
+
<Button theme={themeValue} variant="fill">Save</Button>
|
|
167
|
+
`
|
|
168
|
+
|
|
169
|
+
const result = applyTransform(source)
|
|
170
|
+
|
|
171
|
+
expect(result).toContain(
|
|
172
|
+
"TODO: tapestry-migration (theme/variant): cannot be converted"
|
|
173
|
+
)
|
|
174
|
+
expect(result).toContain("themeValue")
|
|
175
|
+
})
|
|
176
|
+
|
|
177
|
+
it("should handle variant as expression", () => {
|
|
178
|
+
const source = `
|
|
179
|
+
import { Button } from "@planningcenter/tapestry-react"
|
|
180
|
+
<Button theme="primary" variant={variantValue}>Save</Button>
|
|
181
|
+
`
|
|
182
|
+
|
|
183
|
+
const result = applyTransform(source)
|
|
184
|
+
|
|
185
|
+
expect(result).toContain(
|
|
186
|
+
"TODO: tapestry-migration (theme/variant): cannot be converted"
|
|
187
|
+
)
|
|
188
|
+
expect(result).toContain("variantValue")
|
|
189
|
+
})
|
|
190
|
+
})
|
|
191
|
+
|
|
192
|
+
describe("no matching attributes", () => {
|
|
193
|
+
it("should not transform buttons without theme or variant", () => {
|
|
194
|
+
const source = `
|
|
195
|
+
import { Button } from "@planningcenter/tapestry-react"
|
|
196
|
+
<Button onClick={handleClick}>Save</Button>
|
|
197
|
+
`
|
|
198
|
+
|
|
199
|
+
const result = applyTransform(source)
|
|
200
|
+
|
|
201
|
+
expect(result).toBe(null) // No changes
|
|
202
|
+
})
|
|
203
|
+
})
|
|
204
|
+
|
|
205
|
+
describe("edge cases", () => {
|
|
206
|
+
it("should handle empty theme value", () => {
|
|
207
|
+
const source = `
|
|
208
|
+
import { Button } from "@planningcenter/tapestry-react"
|
|
209
|
+
<Button theme="" variant="fill">Save</Button>
|
|
210
|
+
`
|
|
211
|
+
|
|
212
|
+
const result = applyTransform(source)
|
|
213
|
+
|
|
214
|
+
// Empty theme is treated as default, so it should convert successfully
|
|
215
|
+
expect(result).toContain('kind="neutral"')
|
|
216
|
+
expect(result).not.toContain('theme=""')
|
|
217
|
+
expect(result).not.toContain('variant="fill"')
|
|
218
|
+
})
|
|
219
|
+
|
|
220
|
+
it("should handle boolean theme attribute", () => {
|
|
221
|
+
const source = `
|
|
222
|
+
import { Button } from "@planningcenter/tapestry-react"
|
|
223
|
+
<Button theme variant="fill">Save</Button>
|
|
224
|
+
`
|
|
225
|
+
|
|
226
|
+
const result = applyTransform(source)
|
|
227
|
+
|
|
228
|
+
// Boolean theme attribute becomes default theme, so it should convert successfully
|
|
229
|
+
expect(result).toContain('kind="neutral"')
|
|
230
|
+
expect(result).not.toContain("theme=")
|
|
231
|
+
expect(result).not.toContain('variant="fill"')
|
|
232
|
+
})
|
|
233
|
+
|
|
234
|
+
it("should preserve existing kind attribute when no theme/variant", () => {
|
|
235
|
+
const source = `
|
|
236
|
+
import { Button } from "@planningcenter/tapestry-react"
|
|
237
|
+
<Button kind="existing">Save</Button>
|
|
238
|
+
`
|
|
239
|
+
|
|
240
|
+
const result = applyTransform(source)
|
|
241
|
+
|
|
242
|
+
expect(result).toBe(null) // No changes made
|
|
243
|
+
})
|
|
244
|
+
|
|
245
|
+
it("should handle JSX expression theme values", () => {
|
|
246
|
+
const source = `
|
|
247
|
+
import { Button } from "@planningcenter/tapestry-react"
|
|
248
|
+
<Button theme={"primary"} variant="fill">Save</Button>
|
|
249
|
+
`
|
|
250
|
+
|
|
251
|
+
const result = applyTransform(source)
|
|
252
|
+
|
|
253
|
+
expect(result).toContain(
|
|
254
|
+
"TODO: tapestry-migration (theme/variant): cannot be converted"
|
|
255
|
+
)
|
|
256
|
+
expect(result).toContain('{"primary"}')
|
|
257
|
+
})
|
|
258
|
+
})
|
|
259
|
+
|
|
260
|
+
describe("mixed scenarios", () => {
|
|
261
|
+
it("should handle multiple buttons with different combinations", () => {
|
|
262
|
+
const source = `
|
|
263
|
+
import { Button } from "@planningcenter/tapestry-react"
|
|
264
|
+
<div>
|
|
265
|
+
<Button theme="primary" variant="fill">Save</Button>
|
|
266
|
+
<Button theme="unsupported" variant="fill">Custom</Button>
|
|
267
|
+
<Button variant="outline">Cancel</Button>
|
|
268
|
+
</div>
|
|
269
|
+
`
|
|
270
|
+
|
|
271
|
+
const result = applyTransform(source)
|
|
272
|
+
|
|
273
|
+
// First button should convert properly
|
|
274
|
+
expect(result).toContain('kind="primary"')
|
|
275
|
+
|
|
276
|
+
// Second button should have comment
|
|
277
|
+
expect(result).toContain(
|
|
278
|
+
"TODO: tapestry-migration (theme/variant): cannot be converted"
|
|
279
|
+
)
|
|
280
|
+
expect(result).toContain('theme="unsupported"')
|
|
281
|
+
|
|
282
|
+
// Third button should convert to secondary
|
|
283
|
+
expect(result).toContain('kind="secondary"')
|
|
284
|
+
})
|
|
285
|
+
|
|
286
|
+
it("should handle buttons with existing kind attribute and theme/variant", () => {
|
|
287
|
+
const source = `
|
|
288
|
+
import { Button } from "@planningcenter/tapestry-react"
|
|
289
|
+
<Button kind="existing" theme="primary" variant="fill">Save</Button>
|
|
290
|
+
`
|
|
291
|
+
|
|
292
|
+
const result = applyTransform(source)
|
|
293
|
+
|
|
294
|
+
// Should still transform theme/variant and add new kind
|
|
295
|
+
expect(result).toContain('kind="primary"')
|
|
296
|
+
expect(result).not.toContain('theme="primary"')
|
|
297
|
+
expect(result).not.toContain('variant="fill"')
|
|
298
|
+
// The existing kind should be replaced with the new one
|
|
299
|
+
})
|
|
300
|
+
})
|
|
301
|
+
|
|
302
|
+
it("should handle conditionals in theme/variant values", () => {
|
|
303
|
+
const source = `
|
|
304
|
+
import { Button } from "@planningcenter/tapestry-react"
|
|
305
|
+
<Button theme={isPrimary ? "primary" : "default"} variant={isPrimary ? "fill" : "outline"}>Save</Button>
|
|
306
|
+
`
|
|
307
|
+
|
|
308
|
+
const result = applyTransform(source)
|
|
309
|
+
|
|
310
|
+
expect(result).toContain(
|
|
311
|
+
'Button kind={isPrimary ? "primary" : "secondary"}'
|
|
312
|
+
)
|
|
313
|
+
})
|
|
314
|
+
|
|
315
|
+
it("should handle conditionals with undefined values", () => {
|
|
316
|
+
const source = `
|
|
317
|
+
import { Button } from "@planningcenter/tapestry-react"
|
|
318
|
+
<Button theme={phoenixEnabled ? 'primary' : 'primary'} variant={phoenixEnabled ? 'outline' : undefined}>Save</Button>
|
|
319
|
+
`
|
|
320
|
+
|
|
321
|
+
const result = applyTransform(source)
|
|
322
|
+
|
|
323
|
+
expect(result).toContain(
|
|
324
|
+
'Button kind={phoenixEnabled ? "secondary-interaction" : "primary"}'
|
|
325
|
+
)
|
|
326
|
+
})
|
|
327
|
+
|
|
328
|
+
it("should handle conditionals with undefined values for theme", () => {
|
|
329
|
+
const source = `
|
|
330
|
+
import { Button } from "@planningcenter/tapestry-react"
|
|
331
|
+
<Button theme={phoenixEnabled ? 'default' : undefined} variant={phoenixEnabled ? 'naked' : undefined}>Save</Button>
|
|
332
|
+
`
|
|
333
|
+
|
|
334
|
+
const result = applyTransform(source)
|
|
335
|
+
|
|
336
|
+
expect(result).toContain(
|
|
337
|
+
'Button kind={phoenixEnabled ? "ghost" : "neutral"}'
|
|
338
|
+
)
|
|
339
|
+
})
|
|
340
|
+
|
|
341
|
+
it("should handle conditionals for only variant", () => {
|
|
342
|
+
const source = `
|
|
343
|
+
import { Button } from "@planningcenter/tapestry-react"
|
|
344
|
+
<Button theme="primary" variant={phoenixEnabled ? 'outline' : undefined}>Save</Button>
|
|
345
|
+
`
|
|
346
|
+
|
|
347
|
+
const result = applyTransform(source)
|
|
348
|
+
|
|
349
|
+
expect(result).toContain(
|
|
350
|
+
'Button kind={phoenixEnabled ? "secondary-interaction" : "primary"}'
|
|
351
|
+
)
|
|
352
|
+
})
|
|
353
|
+
|
|
354
|
+
it("should handle conditionals for only variant", () => {
|
|
355
|
+
const source = `
|
|
356
|
+
import { Button } from "@planningcenter/tapestry-react"
|
|
357
|
+
<Button theme={phoenixEnabled ? 'neutral' : undefined} variant="outline">Save</Button>
|
|
358
|
+
`
|
|
359
|
+
|
|
360
|
+
const result = applyTransform(source)
|
|
361
|
+
|
|
362
|
+
expect(result).toContain(
|
|
363
|
+
'Button kind={phoenixEnabled ? "secondary" : "secondary"}'
|
|
364
|
+
)
|
|
365
|
+
})
|
|
366
|
+
|
|
367
|
+
it("should handle conditionals for no variant", () => {
|
|
368
|
+
const source = `
|
|
369
|
+
import { Button } from "@planningcenter/tapestry-react"
|
|
370
|
+
<Button theme={phoenixEnabled ? 'neutral' : undefined}>Save</Button>
|
|
371
|
+
`
|
|
372
|
+
|
|
373
|
+
const result = applyTransform(source)
|
|
374
|
+
|
|
375
|
+
expect(result).toContain(
|
|
376
|
+
'Button kind={phoenixEnabled ? "neutral" : "neutral"}'
|
|
377
|
+
)
|
|
378
|
+
})
|
|
379
|
+
|
|
380
|
+
it("should handle when theme is null", () => {
|
|
381
|
+
const source = `
|
|
382
|
+
import { Button } from "@planningcenter/tapestry-react"
|
|
383
|
+
<Button theme={null} variant="fill">Save</Button>
|
|
384
|
+
`
|
|
385
|
+
|
|
386
|
+
const result = applyTransform(source)
|
|
387
|
+
|
|
388
|
+
expect(result).toContain('<Button kind="neutral">')
|
|
389
|
+
})
|
|
390
|
+
|
|
391
|
+
it("should handle when theme is false", () => {
|
|
392
|
+
const source = `
|
|
393
|
+
import { Button } from "@planningcenter/tapestry-react"
|
|
394
|
+
<Button theme={false} variant="fill">Save</Button>
|
|
395
|
+
`
|
|
396
|
+
|
|
397
|
+
const result = applyTransform(source)
|
|
398
|
+
|
|
399
|
+
expect(result).toContain('<Button kind="neutral">')
|
|
400
|
+
})
|
|
401
|
+
})
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { addComment } from "../../shared/actions/addComment"
|
|
2
|
+
import { getAttributeValue } from "../../shared/actions/getAttributeValue"
|
|
3
|
+
import { removeAttribute } from "../../shared/actions/removeAttribute"
|
|
4
|
+
import { attributeCombineFactory } from "../../shared/transformFactories/attributeCombineFactory"
|
|
5
|
+
|
|
6
|
+
const KIND_MAP = {
|
|
7
|
+
default: {
|
|
8
|
+
default: "neutral",
|
|
9
|
+
fill: "neutral",
|
|
10
|
+
naked: "ghost",
|
|
11
|
+
outline: "secondary",
|
|
12
|
+
solid: "primary",
|
|
13
|
+
},
|
|
14
|
+
error: {
|
|
15
|
+
default: "delete",
|
|
16
|
+
fill: "delete",
|
|
17
|
+
naked: "ghost-delete",
|
|
18
|
+
outline: "secondary-delete",
|
|
19
|
+
solid: "delete",
|
|
20
|
+
},
|
|
21
|
+
neutral: {
|
|
22
|
+
default: "neutral",
|
|
23
|
+
fill: "neutral",
|
|
24
|
+
naked: "ghost",
|
|
25
|
+
outline: "secondary",
|
|
26
|
+
solid: "primary",
|
|
27
|
+
},
|
|
28
|
+
primary: {
|
|
29
|
+
default: "primary",
|
|
30
|
+
fill: "primary",
|
|
31
|
+
naked: "ghost-interaction",
|
|
32
|
+
outline: "secondary-interaction",
|
|
33
|
+
solid: "primary",
|
|
34
|
+
},
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* JSCodeshift transform: Convert Button theme/variant props to kind
|
|
39
|
+
*/
|
|
40
|
+
const transform = attributeCombineFactory({
|
|
41
|
+
component: "Button",
|
|
42
|
+
defaults: {
|
|
43
|
+
theme: "default",
|
|
44
|
+
variant: "fill",
|
|
45
|
+
},
|
|
46
|
+
mappingTable: KIND_MAP,
|
|
47
|
+
onUnsupported: ({ element, attributes, j, source }) => {
|
|
48
|
+
const removedAttrs: string[] = []
|
|
49
|
+
|
|
50
|
+
attributes.forEach(({ attribute, name }) => {
|
|
51
|
+
if (attribute) {
|
|
52
|
+
removeAttribute(name, { element, j, source })
|
|
53
|
+
const attributeValue = getAttributeValue({ attribute, j })
|
|
54
|
+
if (attributeValue) {
|
|
55
|
+
removedAttrs.push(`${name}="${attributeValue}"`)
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
if (removedAttrs.length > 0) {
|
|
61
|
+
const text = `cannot be converted - removed: ${removedAttrs.join(", ")}`
|
|
62
|
+
addComment({
|
|
63
|
+
element,
|
|
64
|
+
j,
|
|
65
|
+
scope: attributes.map(({ name }) => name).join("/"),
|
|
66
|
+
source,
|
|
67
|
+
text,
|
|
68
|
+
})
|
|
69
|
+
}
|
|
70
|
+
return true
|
|
71
|
+
},
|
|
72
|
+
package: "@planningcenter/tapestry-react",
|
|
73
|
+
sourceAttributes: ["theme", "variant"],
|
|
74
|
+
targetAttribute: "kind",
|
|
75
|
+
valueNormalizers: {
|
|
76
|
+
theme: (value: string | null | undefined) => {
|
|
77
|
+
if (value === "destroy" || value === "delete") return "error"
|
|
78
|
+
if (value === "info" || value === "success" || value === "interaction")
|
|
79
|
+
return "primary"
|
|
80
|
+
return value || "default"
|
|
81
|
+
},
|
|
82
|
+
variant: (value: string | null | undefined) => {
|
|
83
|
+
if (value === "ghost") return "naked"
|
|
84
|
+
if (value === "solid") return "fill"
|
|
85
|
+
return value || "fill"
|
|
86
|
+
},
|
|
87
|
+
},
|
|
88
|
+
})
|
|
89
|
+
|
|
90
|
+
export default transform
|