@planningcenter/tapestry-migration-cli 2.4.0-rc.9 → 2.4.1-rc.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.
Files changed (42) hide show
  1. package/README.md +100 -6
  2. package/dist/tapestry-react-shim.cjs +1 -1
  3. package/package.json +2 -2
  4. package/src/components/button/index.ts +3 -3
  5. package/src/components/button/transforms/innerRefToRef.test.ts +170 -0
  6. package/src/components/button/transforms/innerRefToRef.ts +14 -0
  7. package/src/components/button/transforms/unsupportedProps.ts +8 -31
  8. package/src/components/checkbox/index.ts +38 -0
  9. package/src/components/checkbox/transforms/childrenToLabel.test.ts +146 -0
  10. package/src/components/checkbox/transforms/childrenToLabel.ts +54 -0
  11. package/src/components/checkbox/transforms/convertStyleProps.test.ts +161 -0
  12. package/src/components/checkbox/transforms/convertStyleProps.ts +10 -0
  13. package/src/components/checkbox/transforms/innerRefToRef.test.ts +161 -0
  14. package/src/components/checkbox/transforms/innerRefToRef.ts +14 -0
  15. package/src/components/checkbox/transforms/moveCheckboxImport.test.ts +182 -0
  16. package/src/components/checkbox/transforms/moveCheckboxImport.ts +13 -0
  17. package/src/components/checkbox/transforms/sizeMapping.test.ts +193 -0
  18. package/src/components/checkbox/transforms/sizeMapping.ts +45 -0
  19. package/src/components/checkbox/transforms/unsupportedProps.test.ts +243 -0
  20. package/src/components/checkbox/transforms/unsupportedProps.ts +47 -0
  21. package/src/components/link/index.ts +14 -4
  22. package/src/components/link/transforms/auditSpreadProps.test.ts +351 -0
  23. package/src/components/link/transforms/auditSpreadProps.ts +24 -0
  24. package/src/components/link/transforms/innerRefToRef.test.ts +170 -0
  25. package/src/components/link/transforms/innerRefToRef.ts +14 -0
  26. package/src/components/link/transforms/moveLinkImport.test.ts +295 -0
  27. package/src/components/{button/transforms/linkToButton.ts → link/transforms/moveLinkImport.ts} +4 -5
  28. package/src/components/link/transforms/{inlineMemberToKind.test.ts → removeInlineMember.test.ts} +13 -28
  29. package/src/components/link/transforms/removeInlineMember.ts +11 -0
  30. package/src/components/link/transforms/{inlinePropToKind.test.ts → removeInlineProp.test.ts} +12 -29
  31. package/src/components/link/transforms/{inlinePropToKind.ts → removeInlineProp.ts} +0 -9
  32. package/src/components/link/transforms/tooltipToWrapper.test.ts +392 -0
  33. package/src/components/link/transforms/tooltipToWrapper.ts +35 -0
  34. package/src/components/link/transforms/unsupportedProps.test.ts +265 -0
  35. package/src/components/link/transforms/unsupportedProps.ts +58 -0
  36. package/src/components/shared/helpers/unsupportedPropsHelpers.ts +35 -0
  37. package/src/components/shared/transformFactories/stylePropTransformFactory.ts +1 -0
  38. package/src/index.ts +18 -7
  39. package/src/jscodeshiftRunner.ts +9 -1
  40. package/src/reportGenerator.ts +23 -2
  41. package/src/components/button/transforms/linkToButton.test.ts +0 -426
  42. package/src/components/link/transforms/inlineMemberToKind.ts +0 -49
@@ -0,0 +1,161 @@
1
+ import jscodeshift from "jscodeshift"
2
+ import { describe, expect, it } from "vitest"
3
+
4
+ import transform from "./convertStyleProps"
5
+
6
+ const j = jscodeshift.withParser("tsx")
7
+
8
+ function applyTransform(source: string, options = {}) {
9
+ const fileInfo = { path: "test.tsx", source }
10
+ const result = transform(
11
+ fileInfo,
12
+ { j, jscodeshift: j, report: () => {}, stats: () => {} },
13
+ options
14
+ ) as string | null
15
+ return result || source
16
+ }
17
+
18
+ describe("convertStyleProps transform", () => {
19
+ describe("visible prop - handled by theme system", () => {
20
+ it("should convert visible={false} to display: none", () => {
21
+ const source = `
22
+ import { Checkbox } from "@planningcenter/tapestry-react"
23
+
24
+ export function TestComponent() {
25
+ return <Checkbox visible={false} label="Hidden Checkbox" />
26
+ }
27
+ `
28
+
29
+ const result = applyTransform(source)
30
+
31
+ expect(result).toContain("style={{")
32
+ expect(result).toContain('display: "none"')
33
+ expect(result).not.toContain("visible={false}")
34
+ })
35
+
36
+ it("should remove visible={true} with no style changes (true is default)", () => {
37
+ const source = `
38
+ import { Checkbox } from "@planningcenter/tapestry-react"
39
+
40
+ export function TestComponent() {
41
+ return <Checkbox visible={true} label="Visible Checkbox" />
42
+ }
43
+ `
44
+
45
+ const result = applyTransform(source)
46
+
47
+ // visible={true} is default behavior, so it should be removed with no style added
48
+ expect(result).not.toContain("visible={true}")
49
+ expect(result).not.toContain("style={{") // No style should be added
50
+ expect(result).toContain('<Checkbox label="Visible Checkbox" />')
51
+ })
52
+
53
+ it("should handle visible expressions", () => {
54
+ const source = `
55
+ import { Checkbox } from "@planningcenter/tapestry-react"
56
+
57
+ export function TestComponent() {
58
+ const isVisible = true
59
+ return <Checkbox visible={isVisible} label="Variable Checkbox" />
60
+ }
61
+ `
62
+
63
+ const result = applyTransform(source)
64
+
65
+ // Note: visible expressions are handled by handleVisibleExpressions transform,
66
+ // not convertStyleProps, so the visible prop should remain
67
+ expect(result).toContain("visible: isVisible")
68
+ expect(result).toContain("style={{") // Style should be added for expressions
69
+ })
70
+ })
71
+
72
+ describe("style prop removal", () => {
73
+ it("should remove alignItems prop", () => {
74
+ const source = `
75
+ import { Checkbox } from "@planningcenter/tapestry-react"
76
+
77
+ export function TestComponent() {
78
+ return <Checkbox alignItems="center" label="Test" />
79
+ }
80
+ `
81
+
82
+ const result = applyTransform(source)
83
+
84
+ expect(result).not.toContain("alignItems=")
85
+ })
86
+
87
+ it("should remove marginTop prop", () => {
88
+ const source = `
89
+ import { Checkbox } from "@planningcenter/tapestry-react"
90
+
91
+ export function TestComponent() {
92
+ return <Checkbox marginTop={16} label="Test" />
93
+ }
94
+ `
95
+
96
+ const result = applyTransform(source)
97
+
98
+ expect(result).not.toContain("marginTop=")
99
+ })
100
+
101
+ it("should remove multiple style props", () => {
102
+ const source = `
103
+ import { Checkbox } from "@planningcenter/tapestry-react"
104
+
105
+ export function TestComponent() {
106
+ return <Checkbox alignItems="center" marginTop={16} label="Test" />
107
+ }
108
+ `
109
+
110
+ const result = applyTransform(source)
111
+
112
+ expect(result).not.toContain("alignItems=")
113
+ expect(result).not.toContain("marginTop=")
114
+ })
115
+ })
116
+
117
+ describe("combination of style props", () => {
118
+ it("should handle combination of visible and style props", () => {
119
+ const source = `
120
+ import { Checkbox } from "@planningcenter/tapestry-react"
121
+
122
+ export function TestComponent() {
123
+ return (
124
+ <Checkbox
125
+ visible={false}
126
+ alignItems="center"
127
+ marginTop={16}
128
+ label="Combined Checkbox"
129
+ />
130
+ )
131
+ }
132
+ `
133
+
134
+ const result = applyTransform(source)
135
+
136
+ expect(result).toContain("style={{")
137
+ expect(result).toContain('display: "none"') // from visible={false}
138
+ expect(result).not.toContain("visible={false}")
139
+ expect(result).not.toContain("alignItems=")
140
+ expect(result).not.toContain("marginTop=")
141
+ })
142
+ })
143
+
144
+ describe("import handling", () => {
145
+ it("should not affect imports", () => {
146
+ const source = `
147
+ import { Checkbox } from "@planningcenter/tapestry-react"
148
+
149
+ export function TestComponent() {
150
+ return <Checkbox visible={false} label="Test" />
151
+ }
152
+ `
153
+
154
+ const result = applyTransform(source)
155
+
156
+ expect(result).toContain(
157
+ 'import { Checkbox } from "@planningcenter/tapestry-react"'
158
+ )
159
+ })
160
+ })
161
+ })
@@ -0,0 +1,10 @@
1
+ import { stackViewPlugin } from "../../../stubs/stackViewPlugin"
2
+ import { stylePropTransformFactory } from "../../shared/transformFactories/stylePropTransformFactory"
3
+
4
+ export default stylePropTransformFactory({
5
+ plugin: stackViewPlugin,
6
+ stylesToKeep: ["visible"],
7
+ stylesToRemove: [],
8
+ targetComponent: "Checkbox",
9
+ targetPackage: "@planningcenter/tapestry-react",
10
+ })
@@ -0,0 +1,161 @@
1
+ import jscodeshift from "jscodeshift"
2
+ import { describe, expect, it } from "vitest"
3
+
4
+ import transform from "./innerRefToRef"
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("innerRefToRef transform", () => {
19
+ describe("innerRef to ref conversion", () => {
20
+ it("should convert innerRef to ref", () => {
21
+ const input = `
22
+ import { Checkbox } from "@planningcenter/tapestry-react"
23
+
24
+ function Test() {
25
+ const checkboxRef = React.useRef()
26
+ return <Checkbox innerRef={checkboxRef} label="Test" />
27
+ }
28
+ `.trim()
29
+
30
+ const result = applyTransform(input)
31
+ expect(result).toContain("ref={checkboxRef}")
32
+ expect(result).not.toContain("innerRef=")
33
+ })
34
+
35
+ it("should convert innerRef with expression", () => {
36
+ const input = `
37
+ import { Checkbox } from "@planningcenter/tapestry-react"
38
+
39
+ function Test() {
40
+ return <Checkbox innerRef={myRef} label="Test" />
41
+ }
42
+ `.trim()
43
+
44
+ const result = applyTransform(input)
45
+ expect(result).toContain("ref={myRef}")
46
+ expect(result).not.toContain("innerRef=")
47
+ })
48
+
49
+ it("should convert innerRef with callback", () => {
50
+ const input = `
51
+ import { Checkbox } from "@planningcenter/tapestry-react"
52
+
53
+ function Test() {
54
+ return <Checkbox innerRef={(el) => console.log(el)} label="Test" />
55
+ }
56
+ `.trim()
57
+
58
+ const result = applyTransform(input)
59
+ expect(result).toContain("ref={(el) => console.log(el)}")
60
+ expect(result).not.toContain("innerRef=")
61
+ })
62
+
63
+ it("should not affect existing ref props", () => {
64
+ const input = `
65
+ import { Checkbox } from "@planningcenter/tapestry-react"
66
+
67
+ function Test() {
68
+ const checkboxRef = React.useRef()
69
+ return <Checkbox ref={checkboxRef} label="Test" />
70
+ }
71
+ `.trim()
72
+
73
+ const result = applyTransform(input)
74
+ expect(result).toContain("ref={checkboxRef}")
75
+ expect(result).not.toContain("innerRef=")
76
+ })
77
+
78
+ it("should handle multiple checkboxes", () => {
79
+ const input = `
80
+ import { Checkbox } from "@planningcenter/tapestry-react"
81
+
82
+ function Test() {
83
+ const ref1 = React.useRef()
84
+ const ref2 = React.useRef()
85
+ return (
86
+ <div>
87
+ <Checkbox innerRef={ref1} label="First" />
88
+ <Checkbox innerRef={ref2} label="Second" />
89
+ </div>
90
+ )
91
+ }
92
+ `.trim()
93
+
94
+ const result = applyTransform(input)
95
+ expect(result).toContain("ref={ref1}")
96
+ expect(result).toContain("ref={ref2}")
97
+ expect(result).not.toContain("innerRef=")
98
+ })
99
+ })
100
+
101
+ describe("edge cases", () => {
102
+ it("should not affect other components", () => {
103
+ const input = `
104
+ import { Button, Checkbox } from "@planningcenter/tapestry-react"
105
+
106
+ function Test() {
107
+ const buttonRef = React.useRef()
108
+ const checkboxRef = React.useRef()
109
+ return (
110
+ <div>
111
+ <Button innerRef={buttonRef}>Click me</Button>
112
+ <Checkbox innerRef={checkboxRef} label="Test" />
113
+ </div>
114
+ )
115
+ }
116
+ `.trim()
117
+
118
+ const result = applyTransform(input)
119
+ expect(result).toContain("<Button innerRef={buttonRef}>Click me</Button>")
120
+ expect(result).toContain("ref={checkboxRef}")
121
+ })
122
+
123
+ it("should handle checkbox without innerRef", () => {
124
+ const input = `
125
+ import { Checkbox } from "@planningcenter/tapestry-react"
126
+
127
+ function Test() {
128
+ return <Checkbox label="Test" />
129
+ }
130
+ `.trim()
131
+
132
+ const result = applyTransform(input)
133
+ expect(result).toContain('<Checkbox label="Test" />')
134
+ })
135
+
136
+ it("should preserve other props", () => {
137
+ const input = `
138
+ import { Checkbox } from "@planningcenter/tapestry-react"
139
+
140
+ function Test() {
141
+ const checkboxRef = React.useRef()
142
+ return (
143
+ <Checkbox
144
+ innerRef={checkboxRef}
145
+ label="Test"
146
+ checked
147
+ disabled
148
+ />
149
+ )
150
+ }
151
+ `.trim()
152
+
153
+ const result = applyTransform(input)
154
+ expect(result).toContain("ref={checkboxRef}")
155
+ expect(result).toContain('label="Test"')
156
+ expect(result).toContain("checked")
157
+ expect(result).toContain("disabled")
158
+ expect(result).not.toContain("innerRef=")
159
+ })
160
+ })
161
+ })
@@ -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
+ const transform = attributeTransformFactory({
6
+ condition: hasAttribute("innerRef"),
7
+ targetComponent: "Checkbox",
8
+ targetPackage: "@planningcenter/tapestry-react",
9
+ transform: (element) => {
10
+ return transformAttributeName("innerRef", "ref", { element })
11
+ },
12
+ })
13
+
14
+ export default transform
@@ -0,0 +1,182 @@
1
+ import jscodeshift from "jscodeshift"
2
+ import { describe, expect, it } from "vitest"
3
+
4
+ import transform from "./moveCheckboxImport"
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("moveCheckboxImport transform", () => {
19
+ describe("import migration", () => {
20
+ it("should change import from tapestry-react to tapestry", () => {
21
+ const input = `
22
+ import { Checkbox } from "@planningcenter/tapestry-react"
23
+
24
+ function Test() {
25
+ return <Checkbox label="Test" />
26
+ }
27
+ `.trim()
28
+
29
+ const result = applyTransform(input)
30
+ expect(result).toContain(
31
+ 'import { Checkbox } from "@planningcenter/tapestry"'
32
+ )
33
+ expect(result).not.toContain("@planningcenter/tapestry-react")
34
+ })
35
+
36
+ it("should handle multiple imports", () => {
37
+ const input = `
38
+ import { Button, Checkbox } from "@planningcenter/tapestry-react"
39
+
40
+ function Test() {
41
+ return (
42
+ <div>
43
+ <Button>Click</Button>
44
+ <Checkbox label="Test" />
45
+ </div>
46
+ )
47
+ }
48
+ `.trim()
49
+
50
+ const result = applyTransform(input)
51
+ expect(result).toContain(
52
+ 'import { Button } from "@planningcenter/tapestry-react"'
53
+ )
54
+ expect(result).toContain(
55
+ 'import { Checkbox } from "@planningcenter/tapestry"'
56
+ )
57
+ })
58
+
59
+ it("should handle default import", () => {
60
+ const input = `
61
+ import Checkbox from "@planningcenter/tapestry-react"
62
+
63
+ function Test() {
64
+ return <Checkbox label="Test" />
65
+ }
66
+ `.trim()
67
+
68
+ const result = applyTransform(input)
69
+ expect(result).toContain(
70
+ 'import Checkbox from "@planningcenter/tapestry-react"'
71
+ )
72
+ })
73
+
74
+ it("should handle mixed imports", () => {
75
+ const input = `
76
+ import { Button } from "@planningcenter/tapestry-react"
77
+ import { Checkbox } from "@planningcenter/tapestry-react"
78
+
79
+ function Test() {
80
+ return (
81
+ <div>
82
+ <Button>Click</Button>
83
+ <Checkbox label="Test" />
84
+ </div>
85
+ )
86
+ }
87
+ `.trim()
88
+
89
+ const result = applyTransform(input)
90
+ expect(result).toContain(
91
+ 'import { Button } from "@planningcenter/tapestry-react"'
92
+ )
93
+ expect(result).toContain(
94
+ 'import { Checkbox } from "@planningcenter/tapestry-react"'
95
+ )
96
+ })
97
+
98
+ it("should not affect other components", () => {
99
+ const input = `
100
+ import { Button } from "@planningcenter/tapestry-react"
101
+
102
+ function Test() {
103
+ return <Button>Click me</Button>
104
+ }
105
+ `.trim()
106
+
107
+ const result = applyTransform(input)
108
+ expect(result).toContain(
109
+ 'import { Button } from "@planningcenter/tapestry-react"'
110
+ )
111
+ })
112
+ })
113
+
114
+ describe("edge cases", () => {
115
+ it("should handle already migrated imports", () => {
116
+ const input = `
117
+ import { Checkbox } from "@planningcenter/tapestry"
118
+
119
+ function Test() {
120
+ return <Checkbox label="Test" />
121
+ }
122
+ `.trim()
123
+
124
+ const result = applyTransform(input)
125
+ expect(result).toContain(
126
+ 'import { Checkbox } from "@planningcenter/tapestry"'
127
+ )
128
+ })
129
+
130
+ it("should handle no imports", () => {
131
+ const input = `
132
+ function Test() {
133
+ return <div>No imports</div>
134
+ }
135
+ `.trim()
136
+
137
+ const result = applyTransform(input)
138
+ expect(result).toBe(input)
139
+ })
140
+
141
+ it("should handle checkbox not used", () => {
142
+ const input = `
143
+ import { Checkbox } from "@planningcenter/tapestry-react"
144
+
145
+ function Test() {
146
+ return <div>No checkbox used</div>
147
+ }
148
+ `.trim()
149
+
150
+ const result = applyTransform(input)
151
+ expect(result).toContain(
152
+ 'import { Checkbox } from "@planningcenter/tapestry-react"'
153
+ )
154
+ })
155
+
156
+ it("should preserve other attributes", () => {
157
+ const input = `
158
+ import { Checkbox } from "@planningcenter/tapestry-react"
159
+
160
+ function Test() {
161
+ return (
162
+ <Checkbox
163
+ label="Test"
164
+ checked
165
+ disabled
166
+ onChange={() => {}}
167
+ />
168
+ )
169
+ }
170
+ `.trim()
171
+
172
+ const result = applyTransform(input)
173
+ expect(result).toContain(
174
+ 'import { Checkbox } from "@planningcenter/tapestry"'
175
+ )
176
+ expect(result).toContain('label="Test"')
177
+ expect(result).toContain("checked")
178
+ expect(result).toContain("disabled")
179
+ expect(result).toContain("onChange={() => {}}")
180
+ })
181
+ })
182
+ })
@@ -0,0 +1,13 @@
1
+ import { Transform } from "jscodeshift"
2
+
3
+ import { componentTransformFactory } from "../../shared/transformFactories/componentTransformFactory"
4
+
5
+ const transform: Transform = componentTransformFactory({
6
+ condition: () => true,
7
+ fromComponent: "Checkbox",
8
+ fromPackage: "@planningcenter/tapestry-react",
9
+ toComponent: "Checkbox",
10
+ toPackage: "@planningcenter/tapestry",
11
+ })
12
+
13
+ export default transform