@planningcenter/tapestry-migration-cli 2.4.0-rc.1 → 2.4.0-rc.3
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
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@planningcenter/tapestry-migration-cli",
|
|
3
|
-
"version": "2.4.0-rc.
|
|
3
|
+
"version": "2.4.0-rc.3",
|
|
4
4
|
"description": "CLI tool for Tapestry migrations",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -51,5 +51,5 @@
|
|
|
51
51
|
"publishConfig": {
|
|
52
52
|
"access": "public"
|
|
53
53
|
},
|
|
54
|
-
"gitHead": "
|
|
54
|
+
"gitHead": "4b1aa9118dae6fcb49141a4c0f9d340deaa9cfae"
|
|
55
55
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Transform } from "jscodeshift"
|
|
2
2
|
|
|
3
3
|
import inlineToKind from "./transforms/inlineToKind"
|
|
4
|
+
import removeAs from "./transforms/removeAs"
|
|
4
5
|
import targetBlankToExternal from "./transforms/targetBlankToExternal"
|
|
5
6
|
import toToHref from "./transforms/toToHref"
|
|
6
7
|
|
|
@@ -12,6 +13,7 @@ const transform: Transform = (fileInfo, api, options) => {
|
|
|
12
13
|
inlineToKind,
|
|
13
14
|
toToHref,
|
|
14
15
|
targetBlankToExternal,
|
|
16
|
+
removeAs,
|
|
15
17
|
]
|
|
16
18
|
|
|
17
19
|
for (const individualTransform of transforms) {
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
import jscodeshift from "jscodeshift"
|
|
2
|
+
import { describe, expect, it } from "vitest"
|
|
3
|
+
|
|
4
|
+
import removeAs from "./removeAs"
|
|
5
|
+
|
|
6
|
+
const j = jscodeshift.withParser("tsx")
|
|
7
|
+
|
|
8
|
+
function applyTransform(source: string): string | null {
|
|
9
|
+
return removeAs(
|
|
10
|
+
{ path: "test.tsx", source },
|
|
11
|
+
{ j, jscodeshift: j, report: () => {}, stats: () => {} },
|
|
12
|
+
{}
|
|
13
|
+
) as string | null
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
describe("removeAs transform", () => {
|
|
17
|
+
describe("basic transformations", () => {
|
|
18
|
+
it("should remove as='a' attribute from Link", () => {
|
|
19
|
+
const input = `
|
|
20
|
+
import { Link } from "@planningcenter/tapestry-react"
|
|
21
|
+
|
|
22
|
+
export default function Test() {
|
|
23
|
+
return <Link href="/home" as="a">Home</Link>
|
|
24
|
+
}
|
|
25
|
+
`.trim()
|
|
26
|
+
|
|
27
|
+
const expected = `
|
|
28
|
+
import { Link } from "@planningcenter/tapestry-react"
|
|
29
|
+
|
|
30
|
+
export default function Test() {
|
|
31
|
+
return <Link href="/home">Home</Link>;
|
|
32
|
+
}
|
|
33
|
+
`.trim()
|
|
34
|
+
|
|
35
|
+
const result = applyTransform(input)
|
|
36
|
+
expect(result?.trim()).toBe(expected)
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
it("should only remove as='a' attribute, not other as values", () => {
|
|
40
|
+
const input = `
|
|
41
|
+
import { Link } from "@planningcenter/tapestry-react"
|
|
42
|
+
|
|
43
|
+
export default function Test() {
|
|
44
|
+
return (
|
|
45
|
+
<div>
|
|
46
|
+
<Link href="/home" as="a">Home</Link>
|
|
47
|
+
<Link href="/button" as="button">Button</Link>
|
|
48
|
+
</div>
|
|
49
|
+
)
|
|
50
|
+
}
|
|
51
|
+
`.trim()
|
|
52
|
+
|
|
53
|
+
const result = applyTransform(input)
|
|
54
|
+
expect(result).toContain('href="/home"') // Should remain
|
|
55
|
+
expect(result).not.toContain('as="a"') // Should be removed
|
|
56
|
+
expect(result).toContain('as="button"') // Should remain
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
it("should preserve other attributes while removing as='a'", () => {
|
|
60
|
+
const input = `
|
|
61
|
+
import { Link } from "@planningcenter/tapestry-react"
|
|
62
|
+
|
|
63
|
+
export default function Test() {
|
|
64
|
+
return (
|
|
65
|
+
<Link
|
|
66
|
+
href="/external"
|
|
67
|
+
as="a"
|
|
68
|
+
className="nav-link"
|
|
69
|
+
target="_blank"
|
|
70
|
+
rel="noopener"
|
|
71
|
+
>
|
|
72
|
+
External Link
|
|
73
|
+
</Link>
|
|
74
|
+
)
|
|
75
|
+
}
|
|
76
|
+
`.trim()
|
|
77
|
+
|
|
78
|
+
const result = applyTransform(input)
|
|
79
|
+
expect(result).toContain('href="/external"')
|
|
80
|
+
expect(result).toContain('className="nav-link"')
|
|
81
|
+
expect(result).toContain('target="_blank"')
|
|
82
|
+
expect(result).toContain('rel="noopener"')
|
|
83
|
+
expect(result).not.toContain('as="a"')
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
it("should handle Links without as attribute", () => {
|
|
87
|
+
const input = `
|
|
88
|
+
import { Link } from "@planningcenter/tapestry-react"
|
|
89
|
+
|
|
90
|
+
export default function Test() {
|
|
91
|
+
return <Link href="/internal">Internal Link</Link>
|
|
92
|
+
}
|
|
93
|
+
`.trim()
|
|
94
|
+
|
|
95
|
+
const result = applyTransform(input)
|
|
96
|
+
expect(result).toBeNull() // No changes should be made
|
|
97
|
+
})
|
|
98
|
+
|
|
99
|
+
it("should handle Links with as attribute but different value", () => {
|
|
100
|
+
const input = `
|
|
101
|
+
import { Link } from "@planningcenter/tapestry-react"
|
|
102
|
+
|
|
103
|
+
export default function Test() {
|
|
104
|
+
return <Link href="/button" as="button">Button Link</Link>
|
|
105
|
+
}
|
|
106
|
+
`.trim()
|
|
107
|
+
|
|
108
|
+
const result = applyTransform(input)
|
|
109
|
+
expect(result).toBeNull() // No changes should be made
|
|
110
|
+
})
|
|
111
|
+
})
|
|
112
|
+
|
|
113
|
+
describe("edge cases", () => {
|
|
114
|
+
it("should handle multiple Link components", () => {
|
|
115
|
+
const input = `
|
|
116
|
+
import { Link } from "@planningcenter/tapestry-react"
|
|
117
|
+
|
|
118
|
+
export default function Test() {
|
|
119
|
+
return (
|
|
120
|
+
<div>
|
|
121
|
+
<Link href="/page1" as="a">Page 1</Link>
|
|
122
|
+
<Link href="/page2" as="a">Page 2</Link>
|
|
123
|
+
<Link href="/page3">Page 3</Link>
|
|
124
|
+
</div>
|
|
125
|
+
)
|
|
126
|
+
}
|
|
127
|
+
`.trim()
|
|
128
|
+
|
|
129
|
+
const result = applyTransform(input)
|
|
130
|
+
expect(result).not.toContain('as="a"') // Should be removed from both
|
|
131
|
+
expect(result).toContain('href="/page1"')
|
|
132
|
+
expect(result).toContain('href="/page2"')
|
|
133
|
+
expect(result).toContain('href="/page3"') // Should remain unchanged
|
|
134
|
+
})
|
|
135
|
+
|
|
136
|
+
it("should handle self-closing Link components", () => {
|
|
137
|
+
const input = `
|
|
138
|
+
import { Link } from "@planningcenter/tapestry-react"
|
|
139
|
+
|
|
140
|
+
export default function Test() {
|
|
141
|
+
return <Link href="/external" as="a" />
|
|
142
|
+
}
|
|
143
|
+
`.trim()
|
|
144
|
+
|
|
145
|
+
const result = applyTransform(input)
|
|
146
|
+
expect(result).toContain('href="/external"')
|
|
147
|
+
expect(result).not.toContain('as="a"')
|
|
148
|
+
})
|
|
149
|
+
|
|
150
|
+
it("should handle dynamic as values", () => {
|
|
151
|
+
const input = `
|
|
152
|
+
import { Link } from "@planningcenter/tapestry-react"
|
|
153
|
+
|
|
154
|
+
export default function Test() {
|
|
155
|
+
return <Link href="/external" as={isExternal ? "a" : "button"}>Link</Link>
|
|
156
|
+
}
|
|
157
|
+
`.trim()
|
|
158
|
+
|
|
159
|
+
const result = applyTransform(input)
|
|
160
|
+
expect(result).toBeNull() // No changes should be made for dynamic values
|
|
161
|
+
})
|
|
162
|
+
})
|
|
163
|
+
|
|
164
|
+
describe("import handling", () => {
|
|
165
|
+
it("should only transform when Link is imported from correct package", () => {
|
|
166
|
+
const input = `
|
|
167
|
+
import { Link } from "react-router-dom"
|
|
168
|
+
|
|
169
|
+
export default function Test() {
|
|
170
|
+
return <Link to="/external" as="a">External Link</Link>
|
|
171
|
+
}
|
|
172
|
+
`.trim()
|
|
173
|
+
|
|
174
|
+
const result = applyTransform(input)
|
|
175
|
+
expect(result).toBeNull() // No changes should be made
|
|
176
|
+
})
|
|
177
|
+
|
|
178
|
+
it("should handle aliased imports", () => {
|
|
179
|
+
const input = `
|
|
180
|
+
import { Link as TapestryLink } from "@planningcenter/tapestry-react"
|
|
181
|
+
|
|
182
|
+
export default function Test() {
|
|
183
|
+
return <TapestryLink href="/external" as="a">External Link</TapestryLink>
|
|
184
|
+
}
|
|
185
|
+
`.trim()
|
|
186
|
+
|
|
187
|
+
const result = applyTransform(input)
|
|
188
|
+
expect(result).toContain('href="/external"')
|
|
189
|
+
expect(result).not.toContain('as="a"')
|
|
190
|
+
})
|
|
191
|
+
})
|
|
192
|
+
})
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { removeAttribute } from "../../shared/actions/removeAttribute"
|
|
2
|
+
import { hasAttributeValue } from "../../shared/conditions/hasAttributeValue"
|
|
3
|
+
import { attributeTransformFactory } from "../../shared/transformFactories/attributeTransformFactory"
|
|
4
|
+
|
|
5
|
+
const transform = attributeTransformFactory({
|
|
6
|
+
condition: hasAttributeValue("as", "a"),
|
|
7
|
+
targetComponent: "Link",
|
|
8
|
+
targetPackage: "@planningcenter/tapestry-react",
|
|
9
|
+
transform: (element, { j, source }) => {
|
|
10
|
+
// Remove as attribute
|
|
11
|
+
removeAttribute("as", { element, j, source })
|
|
12
|
+
|
|
13
|
+
return true
|
|
14
|
+
},
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
export default transform
|