@planningcenter/tapestry-migration-cli 3.1.0-rc.9 → 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.ts +3 -3
- 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 +19 -2
- package/src/components/shared/transformFactories/mergeFieldFactory.ts +244 -0
- package/src/components/text-area/transforms/mergeFieldIntoTextArea.ts +4 -226
- package/src/index.ts +2 -1
|
@@ -1,227 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { mergeFieldFactory } from "../../shared/transformFactories/mergeFieldFactory"
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
removeImportFromDeclaration,
|
|
7
|
-
} from "../../shared/transformFactories/helpers/manageImports"
|
|
8
|
-
|
|
9
|
-
const SCOPE = "mergeFieldIntoTextArea"
|
|
10
|
-
|
|
11
|
-
const transform: Transform = (fileInfo, api) => {
|
|
12
|
-
const j = api.jscodeshift
|
|
13
|
-
const source = j(fileInfo.source)
|
|
14
|
-
|
|
15
|
-
const fieldLocalName = getImportName(
|
|
16
|
-
"Field",
|
|
17
|
-
"@planningcenter/tapestry-react",
|
|
18
|
-
{ j, source }
|
|
19
|
-
)
|
|
20
|
-
if (!fieldLocalName) return null
|
|
21
|
-
|
|
22
|
-
const textAreaLocalName = getImportName(
|
|
23
|
-
"TextArea",
|
|
24
|
-
"@planningcenter/tapestry-react",
|
|
25
|
-
{ j, source }
|
|
26
|
-
)
|
|
27
|
-
if (!textAreaLocalName) return null
|
|
28
|
-
|
|
29
|
-
let hasChanges = false
|
|
30
|
-
let anyFieldRemoved = false
|
|
31
|
-
|
|
32
|
-
source.find(j.JSXElement).forEach((path) => {
|
|
33
|
-
const el = path.value
|
|
34
|
-
const opening = el.openingElement
|
|
35
|
-
|
|
36
|
-
if (opening.name.type !== "JSXIdentifier") return
|
|
37
|
-
if (opening.name.name !== fieldLocalName) return
|
|
38
|
-
|
|
39
|
-
const elementChildren = (el.children || []).filter(
|
|
40
|
-
(child) =>
|
|
41
|
-
child.type !== "JSXText" || (child as JSXText).value.trim() !== ""
|
|
42
|
-
)
|
|
43
|
-
|
|
44
|
-
const textAreaChildren = elementChildren.filter((child) => {
|
|
45
|
-
if (child.type !== "JSXElement") return false
|
|
46
|
-
const childOpening = (child as JSXElement).openingElement
|
|
47
|
-
return (
|
|
48
|
-
childOpening.name.type === "JSXIdentifier" &&
|
|
49
|
-
childOpening.name.name === textAreaLocalName
|
|
50
|
-
)
|
|
51
|
-
}) as JSXElement[]
|
|
52
|
-
|
|
53
|
-
// Case: exactly 1 child and it is a TextArea — merge props and unwrap
|
|
54
|
-
if (elementChildren.length === 1 && textAreaChildren.length === 1) {
|
|
55
|
-
const textAreaEl = textAreaChildren[0]
|
|
56
|
-
const fieldAttrs = opening.attributes || []
|
|
57
|
-
|
|
58
|
-
// Bail out if Field has spread props — we can't know what they contain
|
|
59
|
-
const hasFieldSpreads = fieldAttrs.some(
|
|
60
|
-
(attr) => attr.type === "JSXSpreadAttribute"
|
|
61
|
-
)
|
|
62
|
-
if (hasFieldSpreads) {
|
|
63
|
-
addComment({
|
|
64
|
-
element: textAreaEl,
|
|
65
|
-
j,
|
|
66
|
-
scope: SCOPE,
|
|
67
|
-
source,
|
|
68
|
-
text: "Field has spread props that cannot be auto-merged into TextArea. Please migrate manually.",
|
|
69
|
-
})
|
|
70
|
-
hasChanges = true
|
|
71
|
-
return
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
for (const attr of fieldAttrs) {
|
|
75
|
-
if (attr.type !== "JSXAttribute") continue
|
|
76
|
-
if (attr.name.type !== "JSXIdentifier") continue
|
|
77
|
-
|
|
78
|
-
const attrName = attr.name.name
|
|
79
|
-
const textAreaAttrs = textAreaEl.openingElement.attributes || []
|
|
80
|
-
|
|
81
|
-
if (attrName === "label") {
|
|
82
|
-
const hasLabel = textAreaAttrs.some(
|
|
83
|
-
(a) =>
|
|
84
|
-
a.type === "JSXAttribute" &&
|
|
85
|
-
a.name?.type === "JSXIdentifier" &&
|
|
86
|
-
a.name.name === "label"
|
|
87
|
-
)
|
|
88
|
-
if (hasLabel) {
|
|
89
|
-
addComment({
|
|
90
|
-
element: textAreaEl,
|
|
91
|
-
j,
|
|
92
|
-
scope: SCOPE,
|
|
93
|
-
source,
|
|
94
|
-
text: "Field had label prop but TextArea already has label. Please migrate manually.",
|
|
95
|
-
})
|
|
96
|
-
} else {
|
|
97
|
-
textAreaEl.openingElement.attributes.push(attr)
|
|
98
|
-
}
|
|
99
|
-
} else if (attrName === "feedbackText") {
|
|
100
|
-
const hasDescription = textAreaAttrs.some(
|
|
101
|
-
(a) =>
|
|
102
|
-
a.type === "JSXAttribute" &&
|
|
103
|
-
a.name?.type === "JSXIdentifier" &&
|
|
104
|
-
a.name.name === "description"
|
|
105
|
-
)
|
|
106
|
-
if (hasDescription) {
|
|
107
|
-
addComment({
|
|
108
|
-
element: textAreaEl,
|
|
109
|
-
j,
|
|
110
|
-
scope: SCOPE,
|
|
111
|
-
source,
|
|
112
|
-
text: "Field had feedbackText prop but TextArea already has description. Please migrate manually.",
|
|
113
|
-
})
|
|
114
|
-
} else {
|
|
115
|
-
const newAttr = j.jsxAttribute(
|
|
116
|
-
j.jsxIdentifier("description"),
|
|
117
|
-
attr.value
|
|
118
|
-
)
|
|
119
|
-
textAreaEl.openingElement.attributes.push(newAttr)
|
|
120
|
-
}
|
|
121
|
-
} else if (attrName === "state") {
|
|
122
|
-
const hasState = textAreaAttrs.some(
|
|
123
|
-
(a) =>
|
|
124
|
-
a.type === "JSXAttribute" &&
|
|
125
|
-
a.name?.type === "JSXIdentifier" &&
|
|
126
|
-
a.name.name === "state"
|
|
127
|
-
)
|
|
128
|
-
if (hasState) {
|
|
129
|
-
addComment({
|
|
130
|
-
element: textAreaEl,
|
|
131
|
-
j,
|
|
132
|
-
scope: SCOPE,
|
|
133
|
-
source,
|
|
134
|
-
text: "Field had state prop but TextArea already has state. Please migrate manually.",
|
|
135
|
-
})
|
|
136
|
-
} else {
|
|
137
|
-
textAreaEl.openingElement.attributes.push(attr)
|
|
138
|
-
}
|
|
139
|
-
} else if (attrName === "key") {
|
|
140
|
-
const hasKey = textAreaAttrs.some(
|
|
141
|
-
(a) =>
|
|
142
|
-
a.type === "JSXAttribute" &&
|
|
143
|
-
a.name?.type === "JSXIdentifier" &&
|
|
144
|
-
a.name.name === "key"
|
|
145
|
-
)
|
|
146
|
-
if (!hasKey) {
|
|
147
|
-
textAreaEl.openingElement.attributes.push(attr)
|
|
148
|
-
}
|
|
149
|
-
} else {
|
|
150
|
-
// Unsupported prop — add comment to TextArea
|
|
151
|
-
addComment({
|
|
152
|
-
element: textAreaEl,
|
|
153
|
-
j,
|
|
154
|
-
scope: SCOPE,
|
|
155
|
-
source,
|
|
156
|
-
text: `Field prop '${attrName}' is not supported by TextArea. Please migrate manually.`,
|
|
157
|
-
})
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
const parent = path.parent?.value
|
|
162
|
-
if (parent?.children) {
|
|
163
|
-
const idx = parent.children.indexOf(el)
|
|
164
|
-
if (idx === -1) return
|
|
165
|
-
parent.children.splice(idx, 1, ...(el.children || []))
|
|
166
|
-
} else {
|
|
167
|
-
// Root JSX (e.g. directly inside return parens) — use path.replace
|
|
168
|
-
const nonWsChildren = (el.children || []).filter(
|
|
169
|
-
(child) =>
|
|
170
|
-
child.type !== "JSXText" || (child as JSXText).value.trim() !== ""
|
|
171
|
-
)
|
|
172
|
-
if (nonWsChildren.length === 1) {
|
|
173
|
-
path.replace(nonWsChildren[0])
|
|
174
|
-
} else {
|
|
175
|
-
path.replace(
|
|
176
|
-
j.jsxFragment(
|
|
177
|
-
j.jsxOpeningFragment(),
|
|
178
|
-
j.jsxClosingFragment(),
|
|
179
|
-
el.children || []
|
|
180
|
-
)
|
|
181
|
-
)
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
hasChanges = true
|
|
185
|
-
anyFieldRemoved = true
|
|
186
|
-
return
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
// Case: more than 1 non-whitespace child — comment each TextArea child, leave Field
|
|
190
|
-
if (elementChildren.length > 1) {
|
|
191
|
-
for (const child of textAreaChildren) {
|
|
192
|
-
addComment({
|
|
193
|
-
element: child,
|
|
194
|
-
j,
|
|
195
|
-
scope: SCOPE,
|
|
196
|
-
source,
|
|
197
|
-
text: "Field has multiple children and cannot be auto-merged into TextArea. Please migrate manually.",
|
|
198
|
-
})
|
|
199
|
-
hasChanges = true
|
|
200
|
-
}
|
|
201
|
-
return
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
// Case: exactly 1 child but not a TextArea — skip without comment
|
|
205
|
-
})
|
|
206
|
-
|
|
207
|
-
// Remove Field from imports only if all Field usages were converted
|
|
208
|
-
if (anyFieldRemoved) {
|
|
209
|
-
const stillUsesField =
|
|
210
|
-
source.find(j.JSXOpeningElement, {
|
|
211
|
-
name: { name: fieldLocalName },
|
|
212
|
-
}).length > 0
|
|
213
|
-
|
|
214
|
-
if (!stillUsesField) {
|
|
215
|
-
const fieldImports = source.find(j.ImportDeclaration, {
|
|
216
|
-
source: { value: "@planningcenter/tapestry-react" },
|
|
217
|
-
})
|
|
218
|
-
for (let i = 0; i < fieldImports.length; i++) {
|
|
219
|
-
removeImportFromDeclaration(fieldImports.at(i), "Field")
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
return hasChanges ? source.toSource() : null
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
export default transform
|
|
3
|
+
export default mergeFieldFactory({
|
|
4
|
+
targetComponent: "TextArea",
|
|
5
|
+
})
|
package/src/index.ts
CHANGED
|
@@ -17,6 +17,7 @@ const COMPONENTS_SET = new Set([
|
|
|
17
17
|
"input",
|
|
18
18
|
"link",
|
|
19
19
|
"radio",
|
|
20
|
+
"select",
|
|
20
21
|
"text-area",
|
|
21
22
|
"toggle-switch",
|
|
22
23
|
])
|
|
@@ -26,7 +27,7 @@ program
|
|
|
26
27
|
.description("Run a migration of a component from Tapestry React to Tapestry")
|
|
27
28
|
.argument(
|
|
28
29
|
"<component-name>",
|
|
29
|
-
"The name of the component to migrate (button, checkbox, input, link, radio, text-area, toggle-switch)"
|
|
30
|
+
"The name of the component to migrate (button, checkbox, input, link, radio, select, text-area, toggle-switch)"
|
|
30
31
|
)
|
|
31
32
|
.requiredOption(
|
|
32
33
|
"-p, --path <path>",
|