@planningcenter/tapestry-migration-cli 3.4.1-qa-897.0 → 3.4.1-qa-928.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@planningcenter/tapestry-migration-cli",
3
- "version": "3.4.1-qa-897.0",
3
+ "version": "3.4.1-qa-928.0",
4
4
  "description": "CLI tool for Tapestry migrations",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -30,13 +30,13 @@
30
30
  },
31
31
  "devDependencies": {
32
32
  "@emotion/react": "^11.14.0",
33
- "@planningcenter/tapestry": "^3.4.1-qa-897.0",
33
+ "@planningcenter/tapestry": "^3.4.1-qa-928.0",
34
34
  "@planningcenter/tapestry-react": "^4.11.5",
35
35
  "@types/jscodeshift": "^17.3.0",
36
36
  "@types/node": "^20.0.0",
37
37
  "typescript": "^5.8.3",
38
38
  "vite": "^6.4.1",
39
- "vitest": "^3.0.0"
39
+ "vitest": "^4.1.0"
40
40
  },
41
41
  "files": [
42
42
  "src/**/*",
@@ -50,5 +50,5 @@
50
50
  "publishConfig": {
51
51
  "access": "public"
52
52
  },
53
- "gitHead": "01c6459cbc97d4208cc7b06836bc07d129dac1cb"
53
+ "gitHead": "83250d30ce43157ae728980f1968118b6905e05c"
54
54
  }
@@ -52,6 +52,40 @@ describe("spinnerToLoadingButton transform", () => {
52
52
  expect(result).not.toContain("spinner={true}")
53
53
  })
54
54
 
55
+ it("should drop spinner styling props from a logical expression", () => {
56
+ const source = `
57
+ import { Button } from "@planningcenter/tapestry-react"
58
+
59
+ export function TestComponent() {
60
+ return <Button spinner={isSaving && { color: "light-8", trackColor: "light-2" }} />
61
+ }
62
+ `
63
+
64
+ const result = applyTransform(source)
65
+
66
+ expect(result).toContain("loading={isSaving}")
67
+ expect(result).not.toContain("spinner")
68
+ expect(result).not.toContain("color")
69
+ expect(result).not.toContain("trackColor")
70
+ })
71
+
72
+ it("should convert a bare spinner object to loading={true}", () => {
73
+ const source = `
74
+ import { Button } from "@planningcenter/tapestry-react"
75
+
76
+ export function TestComponent() {
77
+ return <Button spinner={{ color: "light-8", trackColor: "light-2" }} />
78
+ }
79
+ `
80
+
81
+ const result = applyTransform(source)
82
+
83
+ expect(result).toContain("loading={true}")
84
+ expect(result).not.toContain("spinner")
85
+ expect(result).not.toContain("color")
86
+ expect(result).not.toContain("trackColor")
87
+ })
88
+
55
89
  it("should handle boolean spinner prop", () => {
56
90
  const source = `
57
91
  import { Button } from "@planningcenter/tapestry-react"
@@ -1,12 +1,47 @@
1
+ import { JSCodeshift, JSXElement } from "jscodeshift"
2
+
1
3
  import { transformAttributeName } from "../../shared/actions/transformAttributeName"
2
4
  import { hasAttribute } from "../../shared/conditions/hasAttribute"
5
+ import { findAttribute } from "../../shared/findAttribute"
3
6
  import { attributeTransformFactory } from "../../shared/transformFactories/attributeTransformFactory"
4
7
 
8
+ /**
9
+ * The tapestry-react `spinner` prop accepts a boolean or an object of spinner
10
+ * styling props (e.g. `{ color, trackColor }`), and is often written as
11
+ * `spinner={condition && { ... }}`. The tapestry `loading` prop is boolean only,
12
+ * so any object of additional spinner props must be dropped:
13
+ *
14
+ * spinner={isSaving && { color: "light-8" }} -> loading={isSaving}
15
+ * spinner={{ color: "light-8" }} -> loading={true}
16
+ */
17
+ function stripSpinnerObject(element: JSXElement, j: JSCodeshift) {
18
+ const attribute = findAttribute(element.openingElement.attributes, "spinner")
19
+ if (!attribute || attribute.value?.type !== "JSXExpressionContainer") return
20
+
21
+ const { expression } = attribute.value
22
+
23
+ // spinner={condition && { ... }} -> loading={condition}
24
+ if (
25
+ expression.type === "LogicalExpression" &&
26
+ expression.operator === "&&" &&
27
+ expression.right.type === "ObjectExpression"
28
+ ) {
29
+ attribute.value.expression = expression.left
30
+ return
31
+ }
32
+
33
+ // spinner={{ ... }} -> loading={true}
34
+ if (expression.type === "ObjectExpression") {
35
+ attribute.value.expression = j.booleanLiteral(true)
36
+ }
37
+ }
38
+
5
39
  export default attributeTransformFactory({
6
40
  condition: hasAttribute("spinner"),
7
41
  targetComponent: "Button",
8
42
  targetPackage: "@planningcenter/tapestry-react",
9
43
  transform: (element, { j, options }) => {
44
+ stripSpinnerObject(element, j)
10
45
  transformAttributeName("spinner", "loading", { element, j, options })
11
46
 
12
47
  return true