@planningcenter/tapestry-migration-cli 3.1.0-rc.7 → 3.1.0-rc.9
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 +3 -3
- package/src/components/input/transforms/removeTypeInput.test.ts +212 -0
- package/src/components/input/transforms/removeTypeInput.ts +22 -0
- package/src/components/shared/helpers/unsupportedPropsHelpers.ts +33 -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 +227 -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 +3 -1
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { Transform } from "jscodeshift"
|
|
2
|
+
|
|
3
|
+
import { addAttribute } from "../../shared/actions/addAttribute"
|
|
4
|
+
import { addComment } from "../../shared/actions/addComment"
|
|
5
|
+
import { getAttribute } from "../../shared/actions/getAttribute"
|
|
6
|
+
import { getAttributeValue } from "../../shared/actions/getAttributeValue"
|
|
7
|
+
import { removeAttribute } from "../../shared/actions/removeAttribute"
|
|
8
|
+
import { hasAttribute } from "../../shared/conditions/hasAttribute"
|
|
9
|
+
import { attributeTransformFactory } from "../../shared/transformFactories/attributeTransformFactory"
|
|
10
|
+
|
|
11
|
+
const transform: Transform = attributeTransformFactory({
|
|
12
|
+
condition: hasAttribute("state"),
|
|
13
|
+
targetComponent: "TextArea",
|
|
14
|
+
targetPackage: "@planningcenter/tapestry-react",
|
|
15
|
+
transform: (element, { j, source }) => {
|
|
16
|
+
const attr = getAttribute({ element, name: "state" })
|
|
17
|
+
if (!attr) return false
|
|
18
|
+
|
|
19
|
+
const value = getAttributeValue({ attribute: attr, j })
|
|
20
|
+
|
|
21
|
+
if (value === "error") {
|
|
22
|
+
removeAttribute("state", { element, j, source })
|
|
23
|
+
addAttribute({
|
|
24
|
+
booleanAsShorthand: true,
|
|
25
|
+
element,
|
|
26
|
+
j,
|
|
27
|
+
name: "invalid",
|
|
28
|
+
value: true,
|
|
29
|
+
})
|
|
30
|
+
return true
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (value === "success") {
|
|
34
|
+
removeAttribute("state", { element, j, source })
|
|
35
|
+
addComment({
|
|
36
|
+
element,
|
|
37
|
+
j,
|
|
38
|
+
scope: "state",
|
|
39
|
+
source,
|
|
40
|
+
text: "'state=\"success\"' has no equivalent in the new TextArea API. Remove this prop and implement success feedback separately.",
|
|
41
|
+
})
|
|
42
|
+
return true
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Dynamic value — can't determine at compile time
|
|
46
|
+
addComment({
|
|
47
|
+
element,
|
|
48
|
+
j,
|
|
49
|
+
scope: "state",
|
|
50
|
+
source,
|
|
51
|
+
text: "'state' has been replaced by 'invalid' (boolean). For error state, use invalid={true}. 'success' has no equivalent. Migrate this prop manually.",
|
|
52
|
+
})
|
|
53
|
+
return true
|
|
54
|
+
},
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
export default transform
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import jscodeshift from "jscodeshift"
|
|
2
|
+
import { describe, expect, it } from "vitest"
|
|
3
|
+
|
|
4
|
+
import transform from "./stateToInvalidTernary"
|
|
5
|
+
|
|
6
|
+
const j = jscodeshift.withParser("tsx")
|
|
7
|
+
|
|
8
|
+
function applyTransform(source: string): string | null {
|
|
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("stateToInvalidTernary transform", () => {
|
|
18
|
+
describe("successful conversions", () => {
|
|
19
|
+
it("converts state={hasError ? 'error' : null} → invalid={hasError}", () => {
|
|
20
|
+
const input = `
|
|
21
|
+
import { TextArea } from "@planningcenter/tapestry-react"
|
|
22
|
+
|
|
23
|
+
function Test() {
|
|
24
|
+
return <TextArea state={hasError ? "error" : null} label="Notes" />
|
|
25
|
+
}
|
|
26
|
+
`.trim()
|
|
27
|
+
|
|
28
|
+
const result = applyTransform(input)
|
|
29
|
+
expect(result).not.toBeNull()
|
|
30
|
+
expect(result).toContain("invalid={hasError}")
|
|
31
|
+
expect(result).not.toContain("state=")
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
it("converts member expression: state={form.hasError ? 'error' : null} → invalid={form.hasError}", () => {
|
|
35
|
+
const input = `
|
|
36
|
+
import { TextArea } from "@planningcenter/tapestry-react"
|
|
37
|
+
|
|
38
|
+
function Test() {
|
|
39
|
+
return <TextArea state={form.hasError ? "error" : null} label="Notes" />
|
|
40
|
+
}
|
|
41
|
+
`.trim()
|
|
42
|
+
|
|
43
|
+
const result = applyTransform(input)
|
|
44
|
+
expect(result).not.toBeNull()
|
|
45
|
+
expect(result).toContain("invalid={form.hasError}")
|
|
46
|
+
expect(result).not.toContain("state=")
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
it("converts binary expression: state={errors.length > 0 ? 'error' : null} → invalid={errors.length > 0}", () => {
|
|
50
|
+
const input = `
|
|
51
|
+
import { TextArea } from "@planningcenter/tapestry-react"
|
|
52
|
+
|
|
53
|
+
function Test() {
|
|
54
|
+
return <TextArea state={errors.length > 0 ? "error" : null} label="Notes" />
|
|
55
|
+
}
|
|
56
|
+
`.trim()
|
|
57
|
+
|
|
58
|
+
const result = applyTransform(input)
|
|
59
|
+
expect(result).not.toBeNull()
|
|
60
|
+
expect(result).toContain("invalid={errors.length > 0}")
|
|
61
|
+
expect(result).not.toContain("state=")
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
it("converts state={hasError ? 'error' : undefined} → invalid={hasError}", () => {
|
|
65
|
+
const input = `
|
|
66
|
+
import { TextArea } from "@planningcenter/tapestry-react"
|
|
67
|
+
|
|
68
|
+
function Test() {
|
|
69
|
+
return <TextArea state={hasError ? "error" : undefined} label="Notes" />
|
|
70
|
+
}
|
|
71
|
+
`.trim()
|
|
72
|
+
|
|
73
|
+
const result = applyTransform(input)
|
|
74
|
+
expect(result).not.toBeNull()
|
|
75
|
+
expect(result).toContain("invalid={hasError}")
|
|
76
|
+
expect(result).not.toContain("state=")
|
|
77
|
+
})
|
|
78
|
+
})
|
|
79
|
+
|
|
80
|
+
describe("no-op cases", () => {
|
|
81
|
+
it("returns null when consequent is not 'error'", () => {
|
|
82
|
+
const input = `
|
|
83
|
+
import { TextArea } from "@planningcenter/tapestry-react"
|
|
84
|
+
|
|
85
|
+
function Test() {
|
|
86
|
+
return <TextArea state={hasWarning ? "warning" : null} label="Notes" />
|
|
87
|
+
}
|
|
88
|
+
`.trim()
|
|
89
|
+
|
|
90
|
+
const result = applyTransform(input)
|
|
91
|
+
expect(result).toBeNull()
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
it("returns null when alternate is not null/undefined", () => {
|
|
95
|
+
const input = `
|
|
96
|
+
import { TextArea } from "@planningcenter/tapestry-react"
|
|
97
|
+
|
|
98
|
+
function Test() {
|
|
99
|
+
return <TextArea state={hasError ? "error" : "success"} label="Notes" />
|
|
100
|
+
}
|
|
101
|
+
`.trim()
|
|
102
|
+
|
|
103
|
+
const result = applyTransform(input)
|
|
104
|
+
expect(result).toBeNull()
|
|
105
|
+
})
|
|
106
|
+
|
|
107
|
+
it("returns null when TextArea is from a different package", () => {
|
|
108
|
+
const input = `
|
|
109
|
+
import { TextArea } from "other-library"
|
|
110
|
+
|
|
111
|
+
function Test() {
|
|
112
|
+
return <TextArea state={hasError ? "error" : null} label="Notes" />
|
|
113
|
+
}
|
|
114
|
+
`.trim()
|
|
115
|
+
|
|
116
|
+
const result = applyTransform(input)
|
|
117
|
+
expect(result).toBeNull()
|
|
118
|
+
})
|
|
119
|
+
|
|
120
|
+
it("returns null when TextArea has no state prop", () => {
|
|
121
|
+
const input = `
|
|
122
|
+
import { TextArea } from "@planningcenter/tapestry-react"
|
|
123
|
+
|
|
124
|
+
function Test() {
|
|
125
|
+
return <TextArea label="Notes" />
|
|
126
|
+
}
|
|
127
|
+
`.trim()
|
|
128
|
+
|
|
129
|
+
const result = applyTransform(input)
|
|
130
|
+
expect(result).toBeNull()
|
|
131
|
+
})
|
|
132
|
+
})
|
|
133
|
+
})
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { hasAttribute } from "../../shared/conditions/hasAttribute"
|
|
2
|
+
import { ternaryConditionalToPropFactory } from "../../shared/transformFactories/ternaryConditionalToPropFactory"
|
|
3
|
+
|
|
4
|
+
export default ternaryConditionalToPropFactory({
|
|
5
|
+
condition: hasAttribute("state"),
|
|
6
|
+
fromProp: "state",
|
|
7
|
+
matchValue: "error",
|
|
8
|
+
targetComponent: "TextArea",
|
|
9
|
+
targetPackage: "@planningcenter/tapestry-react",
|
|
10
|
+
toProp: "invalid",
|
|
11
|
+
})
|
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
import jscodeshift from "jscodeshift"
|
|
2
|
+
import { describe, expect, it } from "vitest"
|
|
3
|
+
|
|
4
|
+
import transform from "./unsupportedProps"
|
|
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("unsupportedProps transform", () => {
|
|
19
|
+
describe("unsupported prop detection", () => {
|
|
20
|
+
it("should add comment for css prop", () => {
|
|
21
|
+
const input = `
|
|
22
|
+
import { TextArea } from "@planningcenter/tapestry-react"
|
|
23
|
+
|
|
24
|
+
function Test() {
|
|
25
|
+
return <TextArea css={{ color: 'red' }} label="Notes" />
|
|
26
|
+
}
|
|
27
|
+
`.trim()
|
|
28
|
+
|
|
29
|
+
const result = applyTransform(input)
|
|
30
|
+
expect(result).toContain(
|
|
31
|
+
"/* TODO: tapestry-migration (css): 'css' is not supported, please migrate as needed."
|
|
32
|
+
)
|
|
33
|
+
expect(result).toContain(
|
|
34
|
+
"CSS prop is not supported. Use className or style prop instead."
|
|
35
|
+
)
|
|
36
|
+
expect(result).toContain("css={{ color: 'red' }}")
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
it("should add comment for custom unsupported prop", () => {
|
|
40
|
+
const input = `
|
|
41
|
+
import { TextArea } from "@planningcenter/tapestry-react"
|
|
42
|
+
|
|
43
|
+
function Test() {
|
|
44
|
+
return <TextArea naked label="Notes" />
|
|
45
|
+
}
|
|
46
|
+
`.trim()
|
|
47
|
+
|
|
48
|
+
const result = applyTransform(input)
|
|
49
|
+
expect(result).toContain(
|
|
50
|
+
"/* TODO: tapestry-migration (naked): 'naked' is not supported, please migrate as needed."
|
|
51
|
+
)
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
it("should add comments for multiple unsupported props", () => {
|
|
55
|
+
const input = `
|
|
56
|
+
import { TextArea } from "@planningcenter/tapestry-react"
|
|
57
|
+
|
|
58
|
+
function Test() {
|
|
59
|
+
return (
|
|
60
|
+
<TextArea
|
|
61
|
+
css={{ color: 'red' }}
|
|
62
|
+
naked
|
|
63
|
+
subdued
|
|
64
|
+
label="Notes"
|
|
65
|
+
/>
|
|
66
|
+
)
|
|
67
|
+
}
|
|
68
|
+
`.trim()
|
|
69
|
+
|
|
70
|
+
const result = applyTransform(input)
|
|
71
|
+
expect(result).toContain("/* TODO: tapestry-migration (css):")
|
|
72
|
+
expect(result).toContain("/* TODO: tapestry-migration (naked):")
|
|
73
|
+
expect(result).toContain("/* TODO: tapestry-migration (subdued):")
|
|
74
|
+
})
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
describe("supported props", () => {
|
|
78
|
+
it("should not add comments for supported textarea props", () => {
|
|
79
|
+
const input = `
|
|
80
|
+
import { TextArea } from "@planningcenter/tapestry-react"
|
|
81
|
+
|
|
82
|
+
function Test() {
|
|
83
|
+
const ref = React.useRef()
|
|
84
|
+
return (
|
|
85
|
+
<TextArea
|
|
86
|
+
defaultValue="hello"
|
|
87
|
+
disabled
|
|
88
|
+
ref={ref}
|
|
89
|
+
label="Notes"
|
|
90
|
+
name="notes"
|
|
91
|
+
onChange={() => {}}
|
|
92
|
+
placeholder="Enter notes"
|
|
93
|
+
readOnly
|
|
94
|
+
required
|
|
95
|
+
rows={5}
|
|
96
|
+
resize="vertical"
|
|
97
|
+
value="test"
|
|
98
|
+
/>
|
|
99
|
+
)
|
|
100
|
+
}
|
|
101
|
+
`.trim()
|
|
102
|
+
|
|
103
|
+
const result = applyTransform(input)
|
|
104
|
+
expect(result).not.toContain("TODO: tapestry-migration")
|
|
105
|
+
})
|
|
106
|
+
|
|
107
|
+
it("should not add comments for standard HTML textarea attributes", () => {
|
|
108
|
+
const input = `
|
|
109
|
+
import { TextArea } from "@planningcenter/tapestry-react"
|
|
110
|
+
|
|
111
|
+
function Test() {
|
|
112
|
+
return (
|
|
113
|
+
<TextArea
|
|
114
|
+
autoComplete="off"
|
|
115
|
+
autoFocus
|
|
116
|
+
cols={40}
|
|
117
|
+
spellCheck={false}
|
|
118
|
+
wrap="soft"
|
|
119
|
+
label="Notes"
|
|
120
|
+
/>
|
|
121
|
+
)
|
|
122
|
+
}
|
|
123
|
+
`.trim()
|
|
124
|
+
|
|
125
|
+
const result = applyTransform(input)
|
|
126
|
+
expect(result).not.toContain("TODO: tapestry-migration")
|
|
127
|
+
})
|
|
128
|
+
|
|
129
|
+
it("should not add comments for common props", () => {
|
|
130
|
+
const input = `
|
|
131
|
+
import { TextArea } from "@planningcenter/tapestry-react"
|
|
132
|
+
|
|
133
|
+
function Test() {
|
|
134
|
+
return (
|
|
135
|
+
<TextArea
|
|
136
|
+
className="test"
|
|
137
|
+
id="textarea"
|
|
138
|
+
key="key"
|
|
139
|
+
style={{ color: 'red' }}
|
|
140
|
+
tabIndex={0}
|
|
141
|
+
label="Notes"
|
|
142
|
+
/>
|
|
143
|
+
)
|
|
144
|
+
}
|
|
145
|
+
`.trim()
|
|
146
|
+
|
|
147
|
+
const result = applyTransform(input)
|
|
148
|
+
expect(result).not.toContain("TODO: tapestry-migration")
|
|
149
|
+
})
|
|
150
|
+
|
|
151
|
+
it("should not add comments for aria props", () => {
|
|
152
|
+
const input = `
|
|
153
|
+
import { TextArea } from "@planningcenter/tapestry-react"
|
|
154
|
+
|
|
155
|
+
function Test() {
|
|
156
|
+
return (
|
|
157
|
+
<TextArea
|
|
158
|
+
aria-label="Test textarea"
|
|
159
|
+
aria-describedby="description"
|
|
160
|
+
label="Notes"
|
|
161
|
+
/>
|
|
162
|
+
)
|
|
163
|
+
}
|
|
164
|
+
`.trim()
|
|
165
|
+
|
|
166
|
+
const result = applyTransform(input)
|
|
167
|
+
expect(result).not.toContain("TODO: tapestry-migration")
|
|
168
|
+
})
|
|
169
|
+
|
|
170
|
+
it("should not add comments for data props", () => {
|
|
171
|
+
const input = `
|
|
172
|
+
import { TextArea } from "@planningcenter/tapestry-react"
|
|
173
|
+
|
|
174
|
+
function Test() {
|
|
175
|
+
return (
|
|
176
|
+
<TextArea
|
|
177
|
+
data-testid="textarea"
|
|
178
|
+
data-cy="test-textarea"
|
|
179
|
+
label="Notes"
|
|
180
|
+
/>
|
|
181
|
+
)
|
|
182
|
+
}
|
|
183
|
+
`.trim()
|
|
184
|
+
|
|
185
|
+
const result = applyTransform(input)
|
|
186
|
+
expect(result).not.toContain("TODO: tapestry-migration")
|
|
187
|
+
})
|
|
188
|
+
})
|
|
189
|
+
|
|
190
|
+
describe("edge cases", () => {
|
|
191
|
+
it("should not affect TextArea without unsupported props", () => {
|
|
192
|
+
const input = `
|
|
193
|
+
import { TextArea } from "@planningcenter/tapestry-react"
|
|
194
|
+
|
|
195
|
+
function Test() {
|
|
196
|
+
return <TextArea label="Notes" />
|
|
197
|
+
}
|
|
198
|
+
`.trim()
|
|
199
|
+
|
|
200
|
+
const result = applyTransform(input)
|
|
201
|
+
expect(result).not.toContain("TODO: tapestry-migration")
|
|
202
|
+
expect(result).toBe(input)
|
|
203
|
+
})
|
|
204
|
+
|
|
205
|
+
it("should not affect other components", () => {
|
|
206
|
+
const input = `
|
|
207
|
+
import { Button, TextArea } from "@planningcenter/tapestry-react"
|
|
208
|
+
|
|
209
|
+
function Test() {
|
|
210
|
+
return (
|
|
211
|
+
<div>
|
|
212
|
+
<Button css={{ color: 'red' }}>Click me</Button>
|
|
213
|
+
<TextArea label="Notes" />
|
|
214
|
+
</div>
|
|
215
|
+
)
|
|
216
|
+
}
|
|
217
|
+
`.trim()
|
|
218
|
+
|
|
219
|
+
const result = applyTransform(input)
|
|
220
|
+
expect(result).not.toContain("TODO: tapestry-migration")
|
|
221
|
+
expect(result).toContain("css={{ color: 'red' }}")
|
|
222
|
+
})
|
|
223
|
+
|
|
224
|
+
it("should handle mixed supported and unsupported props", () => {
|
|
225
|
+
const input = `
|
|
226
|
+
import { TextArea } from "@planningcenter/tapestry-react"
|
|
227
|
+
|
|
228
|
+
function Test() {
|
|
229
|
+
return (
|
|
230
|
+
<TextArea
|
|
231
|
+
rows={5}
|
|
232
|
+
css={{ color: 'red' }}
|
|
233
|
+
disabled
|
|
234
|
+
naked
|
|
235
|
+
label="Notes"
|
|
236
|
+
/>
|
|
237
|
+
)
|
|
238
|
+
}
|
|
239
|
+
`.trim()
|
|
240
|
+
|
|
241
|
+
const result = applyTransform(input)
|
|
242
|
+
expect(result).toContain("/* TODO: tapestry-migration (css):")
|
|
243
|
+
expect(result).toContain("/* TODO: tapestry-migration (naked):")
|
|
244
|
+
expect(result).toContain("rows={5}")
|
|
245
|
+
expect(result).toContain("disabled")
|
|
246
|
+
expect(result).toContain('label="Notes"')
|
|
247
|
+
})
|
|
248
|
+
|
|
249
|
+
it("should not transform if not imported from @planningcenter/tapestry-react", () => {
|
|
250
|
+
const input = `
|
|
251
|
+
import { TextArea } from "other-library"
|
|
252
|
+
|
|
253
|
+
function Test() {
|
|
254
|
+
return <TextArea naked label="Notes" />
|
|
255
|
+
}
|
|
256
|
+
`.trim()
|
|
257
|
+
|
|
258
|
+
const result = applyTransform(input)
|
|
259
|
+
expect(result).toBe(input)
|
|
260
|
+
})
|
|
261
|
+
|
|
262
|
+
it("should handle alias import", () => {
|
|
263
|
+
const input = `
|
|
264
|
+
import { TextArea as MyTextArea } from "@planningcenter/tapestry-react"
|
|
265
|
+
|
|
266
|
+
function Test() {
|
|
267
|
+
return <MyTextArea naked label="Notes" />
|
|
268
|
+
}
|
|
269
|
+
`.trim()
|
|
270
|
+
|
|
271
|
+
const result = applyTransform(input)
|
|
272
|
+
expect(result).toContain("/* TODO: tapestry-migration (naked):")
|
|
273
|
+
})
|
|
274
|
+
})
|
|
275
|
+
})
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { JSXAttribute, Transform } from "jscodeshift"
|
|
2
|
+
|
|
3
|
+
import { addCommentToUnsupportedProps } from "../../shared/actions/addCommentToUnsupportedProps"
|
|
4
|
+
import { TEXTAREA_SUPPORTED_PROPS } from "../../shared/helpers/unsupportedPropsHelpers"
|
|
5
|
+
import { attributeTransformFactory } from "../../shared/transformFactories/attributeTransformFactory"
|
|
6
|
+
|
|
7
|
+
const transform: Transform = attributeTransformFactory({
|
|
8
|
+
targetComponent: "TextArea",
|
|
9
|
+
targetPackage: "@planningcenter/tapestry-react",
|
|
10
|
+
transform: (element, { j }) => {
|
|
11
|
+
const UNSUPPORTED_PROPS = (element.openingElement.attributes || [])
|
|
12
|
+
.filter(
|
|
13
|
+
(attr) =>
|
|
14
|
+
attr.type === "JSXAttribute" &&
|
|
15
|
+
!TEXTAREA_SUPPORTED_PROPS.includes(attr.name.name as string) &&
|
|
16
|
+
!(attr.name.name as string).startsWith("aria-") &&
|
|
17
|
+
!(attr.name.name as string).startsWith("data-")
|
|
18
|
+
)
|
|
19
|
+
.map((attr) => (attr as JSXAttribute).name.name as string)
|
|
20
|
+
|
|
21
|
+
return addCommentToUnsupportedProps({
|
|
22
|
+
element,
|
|
23
|
+
j,
|
|
24
|
+
messageSuffix: (prop) => {
|
|
25
|
+
if (prop === "css") {
|
|
26
|
+
return "\n * CSS prop is not supported. Use className or style prop instead.\n"
|
|
27
|
+
}
|
|
28
|
+
return ""
|
|
29
|
+
},
|
|
30
|
+
props: UNSUPPORTED_PROPS,
|
|
31
|
+
})
|
|
32
|
+
},
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
export default transform
|
package/src/index.ts
CHANGED
|
@@ -14,8 +14,10 @@ program
|
|
|
14
14
|
const COMPONENTS_SET = new Set([
|
|
15
15
|
"button",
|
|
16
16
|
"checkbox",
|
|
17
|
+
"input",
|
|
17
18
|
"link",
|
|
18
19
|
"radio",
|
|
20
|
+
"text-area",
|
|
19
21
|
"toggle-switch",
|
|
20
22
|
])
|
|
21
23
|
|
|
@@ -24,7 +26,7 @@ program
|
|
|
24
26
|
.description("Run a migration of a component from Tapestry React to Tapestry")
|
|
25
27
|
.argument(
|
|
26
28
|
"<component-name>",
|
|
27
|
-
"The name of the component to migrate (button, checkbox, link, radio, toggle-switch)"
|
|
29
|
+
"The name of the component to migrate (button, checkbox, input, link, radio, text-area, toggle-switch)"
|
|
28
30
|
)
|
|
29
31
|
.requiredOption(
|
|
30
32
|
"-p, --path <path>",
|