@planningcenter/tapestry-migration-cli 3.1.0-rc.14 → 3.1.0-rc.16
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/select/transforms/childrenToOptions.test.ts +38 -0
- package/src/components/select/transforms/childrenToOptions.ts +13 -0
- package/src/components/select/transforms/mapChildrenToOptions.test.ts +23 -0
- package/src/components/select/transforms/mapChildrenToOptions.ts +13 -25
- package/src/components/shared/helpers/getAttributeExpression.ts +26 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@planningcenter/tapestry-migration-cli",
|
|
3
|
-
"version": "3.1.0-rc.
|
|
3
|
+
"version": "3.1.0-rc.16",
|
|
4
4
|
"description": "CLI tool for Tapestry migrations",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
},
|
|
33
33
|
"devDependencies": {
|
|
34
34
|
"@emotion/react": "^11.14.0",
|
|
35
|
-
"@planningcenter/tapestry": "^3.1.0-rc.
|
|
35
|
+
"@planningcenter/tapestry": "^3.1.0-rc.16",
|
|
36
36
|
"@planningcenter/tapestry-react": "^4.11.5",
|
|
37
37
|
"@types/jscodeshift": "^17.3.0",
|
|
38
38
|
"@types/node": "^20.0.0",
|
|
@@ -52,5 +52,5 @@
|
|
|
52
52
|
"publishConfig": {
|
|
53
53
|
"access": "public"
|
|
54
54
|
},
|
|
55
|
-
"gitHead": "
|
|
55
|
+
"gitHead": "d3f8d5b0ac2eafea617315fdcfa7a4911e67294d"
|
|
56
56
|
}
|
|
@@ -40,6 +40,44 @@ function Test() {
|
|
|
40
40
|
expect(result).not.toContain("Select.Option")
|
|
41
41
|
})
|
|
42
42
|
|
|
43
|
+
it("should preserve data-* attributes on options", () => {
|
|
44
|
+
const input = `
|
|
45
|
+
import { Select } from "@planningcenter/tapestry-react"
|
|
46
|
+
|
|
47
|
+
function Test() {
|
|
48
|
+
return (
|
|
49
|
+
<Select emptyValue="Pick one">
|
|
50
|
+
<Select.Option value="apple" data-testid="apple-opt">Apple</Select.Option>
|
|
51
|
+
</Select>
|
|
52
|
+
)
|
|
53
|
+
}
|
|
54
|
+
`.trim()
|
|
55
|
+
|
|
56
|
+
const result = applyTransform(input)
|
|
57
|
+
expect(result).toContain('"data-testid": "apple-opt"')
|
|
58
|
+
expect(result).toContain('label: "Apple"')
|
|
59
|
+
expect(result).toContain('value: "apple"')
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
it("should preserve dynamic data-* attribute expressions on options", () => {
|
|
63
|
+
const input = `
|
|
64
|
+
import { Select } from "@planningcenter/tapestry-react"
|
|
65
|
+
|
|
66
|
+
function Test() {
|
|
67
|
+
return (
|
|
68
|
+
<Select emptyValue="Pick one">
|
|
69
|
+
<Select.Option value="apple" data-pendo={pendoIds.apple}>Apple</Select.Option>
|
|
70
|
+
</Select>
|
|
71
|
+
)
|
|
72
|
+
}
|
|
73
|
+
`.trim()
|
|
74
|
+
|
|
75
|
+
const result = applyTransform(input)
|
|
76
|
+
expect(result).toContain('"data-pendo": pendoIds.apple')
|
|
77
|
+
expect(result).toContain('label: "Apple"')
|
|
78
|
+
expect(result).toContain('value: "apple"')
|
|
79
|
+
})
|
|
80
|
+
|
|
43
81
|
it("should handle disabled options", () => {
|
|
44
82
|
const input = `
|
|
45
83
|
import { Select } from "@planningcenter/tapestry-react"
|
|
@@ -10,6 +10,7 @@ import { addComment } from "../../shared/actions/addComment"
|
|
|
10
10
|
import { removeChildren } from "../../shared/actions/removeChildren"
|
|
11
11
|
import { andConditions } from "../../shared/conditions/andConditions"
|
|
12
12
|
import { hasChildren } from "../../shared/conditions/hasChildren"
|
|
13
|
+
import { getAttributeExpression } from "../../shared/helpers/getAttributeExpression"
|
|
13
14
|
import { attributeTransformFactory } from "../../shared/transformFactories/attributeTransformFactory"
|
|
14
15
|
import { getImportName } from "../../shared/transformFactories/helpers/manageImports"
|
|
15
16
|
import { transformableSelect } from "../transformableSelect"
|
|
@@ -126,6 +127,18 @@ function convertOptionToObjectExpression(
|
|
|
126
127
|
)
|
|
127
128
|
}
|
|
128
129
|
|
|
130
|
+
// Preserve data-* attributes on the option object
|
|
131
|
+
const attrs = optionElement.openingElement.attributes || []
|
|
132
|
+
for (const attr of attrs) {
|
|
133
|
+
if (attr.type !== "JSXAttribute") continue
|
|
134
|
+
const name = attr.name.name as string
|
|
135
|
+
if (!name.startsWith("data-")) continue
|
|
136
|
+
const expr = getAttributeExpression(optionElement, name)
|
|
137
|
+
if (expr) {
|
|
138
|
+
properties.push(j.objectProperty(j.stringLiteral(name), expr))
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
129
142
|
return j.objectExpression(properties)
|
|
130
143
|
}
|
|
131
144
|
|
|
@@ -42,6 +42,29 @@ function Test() {
|
|
|
42
42
|
expect(result).not.toContain("</Select>")
|
|
43
43
|
})
|
|
44
44
|
|
|
45
|
+
it("should preserve data-* attributes on options", () => {
|
|
46
|
+
const input = `
|
|
47
|
+
import { Select } from "@planningcenter/tapestry-react"
|
|
48
|
+
|
|
49
|
+
function Test() {
|
|
50
|
+
return (
|
|
51
|
+
<Select>
|
|
52
|
+
{items.map(item => (
|
|
53
|
+
<Select.Option key={item.id} value={item.id} data-id={item.id}>
|
|
54
|
+
{item.name}
|
|
55
|
+
</Select.Option>
|
|
56
|
+
))}
|
|
57
|
+
</Select>
|
|
58
|
+
)
|
|
59
|
+
}
|
|
60
|
+
`.trim()
|
|
61
|
+
|
|
62
|
+
const result = applyTransform(input)
|
|
63
|
+
expect(result).toContain('"data-id": item.id')
|
|
64
|
+
expect(result).toContain("label: item.name")
|
|
65
|
+
expect(result).toContain("value: item.id")
|
|
66
|
+
})
|
|
67
|
+
|
|
45
68
|
it("should handle nested property access in children", () => {
|
|
46
69
|
const input = `
|
|
47
70
|
import { Select } from "@planningcenter/tapestry-react"
|
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
import { removeChildren } from "../../shared/actions/removeChildren"
|
|
13
13
|
import { andConditions } from "../../shared/conditions/andConditions"
|
|
14
14
|
import { hasChildren } from "../../shared/conditions/hasChildren"
|
|
15
|
+
import { getAttributeExpression } from "../../shared/helpers/getAttributeExpression"
|
|
15
16
|
import { attributeTransformFactory } from "../../shared/transformFactories/attributeTransformFactory"
|
|
16
17
|
import { getImportName } from "../../shared/transformFactories/helpers/manageImports"
|
|
17
18
|
import { transformableSelect } from "../transformableSelect"
|
|
@@ -31,31 +32,6 @@ function isSelectOption(node: JSXElement, localSelectName: string): boolean {
|
|
|
31
32
|
)
|
|
32
33
|
}
|
|
33
34
|
|
|
34
|
-
/**
|
|
35
|
-
* Gets the expression AST node for a JSX attribute value.
|
|
36
|
-
* Returns the expression node for dynamic values, or a StringLiteral for static ones.
|
|
37
|
-
*/
|
|
38
|
-
function getAttributeExpression(
|
|
39
|
-
element: JSXElement,
|
|
40
|
-
attrName: string
|
|
41
|
-
): Expression | null {
|
|
42
|
-
const attrs = element.openingElement.attributes || []
|
|
43
|
-
for (const attr of attrs) {
|
|
44
|
-
if (attr.type !== "JSXAttribute") continue
|
|
45
|
-
if (attr.name.name !== attrName) continue
|
|
46
|
-
|
|
47
|
-
if (!attr.value) return null // boolean shorthand has no expression
|
|
48
|
-
if (attr.value.type === "StringLiteral") return attr.value
|
|
49
|
-
if (attr.value.type === "JSXExpressionContainer") {
|
|
50
|
-
const expr = attr.value.expression
|
|
51
|
-
if (expr.type === "JSXEmptyExpression") return null
|
|
52
|
-
return expr as Expression
|
|
53
|
-
}
|
|
54
|
-
return null
|
|
55
|
-
}
|
|
56
|
-
return null
|
|
57
|
-
}
|
|
58
|
-
|
|
59
35
|
/**
|
|
60
36
|
* Gets the disabled expression if present and not a simple boolean shorthand true.
|
|
61
37
|
* Returns the expression node, or true for shorthand, or null if not present.
|
|
@@ -282,6 +258,18 @@ const transform: Transform = attributeTransformFactory({
|
|
|
282
258
|
properties.push(j.objectProperty(j.identifier("disabled"), disabledExpr))
|
|
283
259
|
}
|
|
284
260
|
|
|
261
|
+
// Preserve data-* attributes on the option object
|
|
262
|
+
const attrs = optionElement.openingElement.attributes || []
|
|
263
|
+
for (const attr of attrs) {
|
|
264
|
+
if (attr.type !== "JSXAttribute") continue
|
|
265
|
+
const name = attr.name.name as string
|
|
266
|
+
if (!name.startsWith("data-")) continue
|
|
267
|
+
const expr = getAttributeExpression(optionElement, name)
|
|
268
|
+
if (expr) {
|
|
269
|
+
properties.push(j.objectProperty(j.stringLiteral(name), expr))
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
285
273
|
// Build new .map() callback that returns an object
|
|
286
274
|
const objectReturn = j.objectExpression(properties)
|
|
287
275
|
const newCallback = j.arrowFunctionExpression(
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { Expression, JSXElement } from "jscodeshift"
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Gets the expression AST node for a JSX attribute value.
|
|
5
|
+
* Returns the expression node for dynamic values, or a StringLiteral for static ones.
|
|
6
|
+
*/
|
|
7
|
+
export function getAttributeExpression(
|
|
8
|
+
element: JSXElement,
|
|
9
|
+
attrName: string
|
|
10
|
+
): Expression | null {
|
|
11
|
+
const attrs = element.openingElement.attributes || []
|
|
12
|
+
for (const attr of attrs) {
|
|
13
|
+
if (attr.type !== "JSXAttribute") continue
|
|
14
|
+
if (attr.name.name !== attrName) continue
|
|
15
|
+
|
|
16
|
+
if (!attr.value) return null // boolean shorthand has no expression
|
|
17
|
+
if (attr.value.type === "StringLiteral") return attr.value
|
|
18
|
+
if (attr.value.type === "JSXExpressionContainer") {
|
|
19
|
+
const expr = attr.value.expression
|
|
20
|
+
if (expr.type === "JSXEmptyExpression") return null
|
|
21
|
+
return expr as Expression
|
|
22
|
+
}
|
|
23
|
+
return null
|
|
24
|
+
}
|
|
25
|
+
return null
|
|
26
|
+
}
|