@planningcenter/tapestry-migration-cli 3.2.3-rc.3 → 3.2.3-rc.5
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/date-picker/index.ts +56 -0
- package/src/components/date-picker/transforms/auditSpreadProps.test.ts +97 -0
- package/src/components/date-picker/transforms/auditSpreadProps.ts +10 -0
- package/src/components/date-picker/transforms/convertStyleProps.test.ts +58 -0
- package/src/components/date-picker/transforms/convertStyleProps.ts +10 -0
- package/src/components/date-picker/transforms/maxDateToMax.test.ts +87 -0
- package/src/components/date-picker/transforms/maxDateToMax.ts +16 -0
- package/src/components/date-picker/transforms/mergeFieldIntoDateField.test.ts +240 -0
- package/src/components/date-picker/transforms/mergeFieldIntoDateField.ts +5 -0
- package/src/components/date-picker/transforms/minDateToMin.test.ts +87 -0
- package/src/components/date-picker/transforms/minDateToMin.ts +16 -0
- package/src/components/date-picker/transforms/momentToDateString.test.ts +240 -0
- package/src/components/date-picker/transforms/momentToDateString.ts +87 -0
- package/src/components/date-picker/transforms/moveDatePickerImport.test.ts +157 -0
- package/src/components/date-picker/transforms/moveDatePickerImport.ts +14 -0
- package/src/components/date-picker/transforms/nativeDateToString.test.ts +220 -0
- package/src/components/date-picker/transforms/nativeDateToString.ts +59 -0
- package/src/components/date-picker/transforms/removeDuplicateKeys.test.ts +120 -0
- package/src/components/date-picker/transforms/removeDuplicateKeys.ts +8 -0
- package/src/components/date-picker/transforms/removeFormatValue.test.ts +119 -0
- package/src/components/date-picker/transforms/removeFormatValue.ts +22 -0
- package/src/components/date-picker/transforms/removePlaceholder.test.ts +117 -0
- package/src/components/date-picker/transforms/removePlaceholder.ts +22 -0
- package/src/components/date-picker/transforms/sizeMapping.test.ts +173 -0
- package/src/components/date-picker/transforms/sizeMapping.ts +15 -0
- package/src/components/date-picker/transforms/stateToInvalid.test.ts +109 -0
- package/src/components/date-picker/transforms/stateToInvalid.ts +57 -0
- package/src/components/date-picker/transforms/stateToInvalidTernary.test.ts +72 -0
- package/src/components/date-picker/transforms/stateToInvalidTernary.ts +11 -0
- package/src/components/date-picker/transforms/unsupportedProps.test.ts +170 -0
- package/src/components/date-picker/transforms/unsupportedProps.ts +37 -0
- package/src/components/shared/helpers/unsupportedPropsHelpers.ts +18 -0
- package/src/index.ts +1 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@planningcenter/tapestry-migration-cli",
|
|
3
|
-
"version": "3.2.3-rc.
|
|
3
|
+
"version": "3.2.3-rc.5",
|
|
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.2.3-rc.
|
|
35
|
+
"@planningcenter/tapestry": "^3.2.3-rc.5",
|
|
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": "709a2ca95766701dd9466ee22c1e8a96fa3da9df"
|
|
56
56
|
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { Transform } from "jscodeshift"
|
|
2
|
+
|
|
3
|
+
import auditSpreadProps from "./transforms/auditSpreadProps"
|
|
4
|
+
import convertStyleProps from "./transforms/convertStyleProps"
|
|
5
|
+
import maxDateToMax from "./transforms/maxDateToMax"
|
|
6
|
+
import mergeFieldIntoDateField from "./transforms/mergeFieldIntoDateField"
|
|
7
|
+
import minDateToMin from "./transforms/minDateToMin"
|
|
8
|
+
import momentToDateString from "./transforms/momentToDateString"
|
|
9
|
+
import moveDatePickerImport from "./transforms/moveDatePickerImport"
|
|
10
|
+
import nativeDateToString from "./transforms/nativeDateToString"
|
|
11
|
+
import removeDuplicateKeys from "./transforms/removeDuplicateKeys"
|
|
12
|
+
import removeFormatValue from "./transforms/removeFormatValue"
|
|
13
|
+
import removePlaceholder from "./transforms/removePlaceholder"
|
|
14
|
+
import sizeMapping from "./transforms/sizeMapping"
|
|
15
|
+
import stateToInvalid from "./transforms/stateToInvalid"
|
|
16
|
+
import stateToInvalidTernary from "./transforms/stateToInvalidTernary"
|
|
17
|
+
import unsupportedProps from "./transforms/unsupportedProps"
|
|
18
|
+
|
|
19
|
+
const transform: Transform = (fileInfo, api, options) => {
|
|
20
|
+
let currentSource = fileInfo.source
|
|
21
|
+
let hasAnyChanges = false
|
|
22
|
+
|
|
23
|
+
const transforms = [
|
|
24
|
+
mergeFieldIntoDateField,
|
|
25
|
+
auditSpreadProps,
|
|
26
|
+
sizeMapping,
|
|
27
|
+
stateToInvalidTernary,
|
|
28
|
+
stateToInvalid,
|
|
29
|
+
momentToDateString,
|
|
30
|
+
nativeDateToString,
|
|
31
|
+
minDateToMin,
|
|
32
|
+
maxDateToMax,
|
|
33
|
+
convertStyleProps,
|
|
34
|
+
removeFormatValue,
|
|
35
|
+
removePlaceholder,
|
|
36
|
+
removeDuplicateKeys,
|
|
37
|
+
unsupportedProps,
|
|
38
|
+
moveDatePickerImport,
|
|
39
|
+
]
|
|
40
|
+
|
|
41
|
+
for (const individualTransform of transforms) {
|
|
42
|
+
const result = individualTransform(
|
|
43
|
+
{ ...fileInfo, source: currentSource },
|
|
44
|
+
api,
|
|
45
|
+
options
|
|
46
|
+
)
|
|
47
|
+
if (result && result !== currentSource) {
|
|
48
|
+
currentSource = result as string
|
|
49
|
+
hasAnyChanges = true
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return hasAnyChanges ? currentSource : null
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export default transform
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import jscodeshift from "jscodeshift"
|
|
2
|
+
import { describe, expect, it } from "vitest"
|
|
3
|
+
|
|
4
|
+
import transform from "./auditSpreadProps"
|
|
5
|
+
|
|
6
|
+
const j = jscodeshift.withParser("tsx")
|
|
7
|
+
|
|
8
|
+
const AUDIT_COMMENT =
|
|
9
|
+
"TODO: tapestry-migration (spreadAttribute): Spread props can contain unsupported props, please explore usages and migrate as needed."
|
|
10
|
+
|
|
11
|
+
function applyTransform(source: string) {
|
|
12
|
+
const fileInfo = { path: "test.tsx", source }
|
|
13
|
+
return transform(
|
|
14
|
+
fileInfo,
|
|
15
|
+
{ j, jscodeshift: j, report: () => {}, stats: () => {} },
|
|
16
|
+
{}
|
|
17
|
+
) as string | null
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
describe("auditSpreadProps transform", () => {
|
|
21
|
+
describe("basic transformations", () => {
|
|
22
|
+
it("should add comment to DateField with spread props", () => {
|
|
23
|
+
const input = `
|
|
24
|
+
import { DateField } from "@planningcenter/tapestry-react"
|
|
25
|
+
|
|
26
|
+
export default function Test() {
|
|
27
|
+
const props = { onChange: handleChange }
|
|
28
|
+
return <DateField {...props} value={date} onChange={setDate} />
|
|
29
|
+
}
|
|
30
|
+
`.trim()
|
|
31
|
+
|
|
32
|
+
const result = applyTransform(input)
|
|
33
|
+
expect(result).toContain(AUDIT_COMMENT)
|
|
34
|
+
expect(result).toContain("{...props}")
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
it("should add comment to DateField with multiple spread props", () => {
|
|
38
|
+
const input = `
|
|
39
|
+
import { DateField } from "@planningcenter/tapestry-react"
|
|
40
|
+
|
|
41
|
+
export default function Test() {
|
|
42
|
+
const baseProps = { onChange: handleChange }
|
|
43
|
+
const extraProps = { disabled: true }
|
|
44
|
+
return <DateField {...baseProps} {...extraProps} value={date} onChange={setDate} />
|
|
45
|
+
}
|
|
46
|
+
`.trim()
|
|
47
|
+
|
|
48
|
+
const result = applyTransform(input)
|
|
49
|
+
expect(result).toContain(AUDIT_COMMENT)
|
|
50
|
+
expect(result).toContain("{...baseProps}")
|
|
51
|
+
expect(result).toContain("{...extraProps}")
|
|
52
|
+
})
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
describe("edge cases", () => {
|
|
56
|
+
it("should not transform DateField without spread props", () => {
|
|
57
|
+
const input = `
|
|
58
|
+
import { DateField } from "@planningcenter/tapestry-react"
|
|
59
|
+
|
|
60
|
+
export default function Test() {
|
|
61
|
+
return <DateField value={date} onChange={setDate} />
|
|
62
|
+
}
|
|
63
|
+
`.trim()
|
|
64
|
+
|
|
65
|
+
const result = applyTransform(input)
|
|
66
|
+
expect(result).toBe(null)
|
|
67
|
+
})
|
|
68
|
+
|
|
69
|
+
it("should not transform if DateField is not imported from @planningcenter/tapestry-react", () => {
|
|
70
|
+
const input = `
|
|
71
|
+
import { DateField } from "other-library"
|
|
72
|
+
|
|
73
|
+
export default function Test() {
|
|
74
|
+
const props = { onChange: handleChange }
|
|
75
|
+
return <DateField {...props} value={date} />
|
|
76
|
+
}
|
|
77
|
+
`.trim()
|
|
78
|
+
|
|
79
|
+
const result = applyTransform(input)
|
|
80
|
+
expect(result).toBe(null)
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
it("should return null when no DateField imports exist", () => {
|
|
84
|
+
const input = `
|
|
85
|
+
import { Button } from "@planningcenter/tapestry-react"
|
|
86
|
+
|
|
87
|
+
export default function Test() {
|
|
88
|
+
const props = { onClick: handleClick }
|
|
89
|
+
return <Button {...props}>Save</Button>
|
|
90
|
+
}
|
|
91
|
+
`.trim()
|
|
92
|
+
|
|
93
|
+
const result = applyTransform(input)
|
|
94
|
+
expect(result).toBe(null)
|
|
95
|
+
})
|
|
96
|
+
})
|
|
97
|
+
})
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Transform } from "jscodeshift"
|
|
2
|
+
|
|
3
|
+
import { commentOnSpreadPropsFactory } from "../../shared/transformFactories/commentOnSpreadPropsFactory"
|
|
4
|
+
|
|
5
|
+
const transform: Transform = commentOnSpreadPropsFactory({
|
|
6
|
+
targetComponent: "DateField",
|
|
7
|
+
targetPackage: "@planningcenter/tapestry-react",
|
|
8
|
+
})
|
|
9
|
+
|
|
10
|
+
export default transform
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import jscodeshift from "jscodeshift"
|
|
2
|
+
import { describe, expect, it } from "vitest"
|
|
3
|
+
|
|
4
|
+
import transform from "./convertStyleProps"
|
|
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("convertStyleProps transform", () => {
|
|
19
|
+
it("should convert marginTop style prop to inline style", () => {
|
|
20
|
+
const input = `
|
|
21
|
+
import { DateField } from "@planningcenter/tapestry-react"
|
|
22
|
+
|
|
23
|
+
function Test() {
|
|
24
|
+
return <DateField marginTop="16px" value={date} onChange={setDate} />
|
|
25
|
+
}
|
|
26
|
+
`.trim()
|
|
27
|
+
|
|
28
|
+
const result = applyTransform(input)
|
|
29
|
+
expect(result).toContain("style=")
|
|
30
|
+
expect(result).not.toContain('marginTop="16px"')
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
it("should not transform DateField without style props", () => {
|
|
34
|
+
const input = `
|
|
35
|
+
import { DateField } from "@planningcenter/tapestry-react"
|
|
36
|
+
|
|
37
|
+
function Test() {
|
|
38
|
+
return <DateField value={date} onChange={setDate} />
|
|
39
|
+
}
|
|
40
|
+
`.trim()
|
|
41
|
+
|
|
42
|
+
const result = applyTransform(input)
|
|
43
|
+
expect(result).toBe(input)
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
it("should not affect other components", () => {
|
|
47
|
+
const input = `
|
|
48
|
+
import { Button } from "@planningcenter/tapestry-react"
|
|
49
|
+
|
|
50
|
+
function Test() {
|
|
51
|
+
return <Button marginTop="16px">Click</Button>
|
|
52
|
+
}
|
|
53
|
+
`.trim()
|
|
54
|
+
|
|
55
|
+
const result = applyTransform(input)
|
|
56
|
+
expect(result).toBe(input)
|
|
57
|
+
})
|
|
58
|
+
})
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { stackViewPlugin } from "../../../stubs/stackViewPlugin"
|
|
2
|
+
import { stylePropTransformFactory } from "../../shared/transformFactories/stylePropTransformFactory"
|
|
3
|
+
|
|
4
|
+
export default stylePropTransformFactory({
|
|
5
|
+
plugin: stackViewPlugin,
|
|
6
|
+
stylesToKeep: ["visible"],
|
|
7
|
+
stylesToRemove: [],
|
|
8
|
+
targetComponent: "DateField",
|
|
9
|
+
targetPackage: "@planningcenter/tapestry-react",
|
|
10
|
+
})
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import jscodeshift from "jscodeshift"
|
|
2
|
+
import { describe, expect, it } from "vitest"
|
|
3
|
+
|
|
4
|
+
import transform from "./maxDateToMax"
|
|
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("maxDateToMax transform", () => {
|
|
19
|
+
it("should rename maxDate to max", () => {
|
|
20
|
+
const input = `
|
|
21
|
+
import { DateField } from "@planningcenter/tapestry-react"
|
|
22
|
+
|
|
23
|
+
function Test() {
|
|
24
|
+
return <DateField maxDate={endDate} value={date} onChange={setDate} />
|
|
25
|
+
}
|
|
26
|
+
`.trim()
|
|
27
|
+
|
|
28
|
+
const result = applyTransform(input)
|
|
29
|
+
expect(result).toContain("max={endDate}")
|
|
30
|
+
expect(result).not.toContain("maxDate")
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
it("should rename maxDate with inline Date value", () => {
|
|
34
|
+
const input = `
|
|
35
|
+
import { DateField } from "@planningcenter/tapestry-react"
|
|
36
|
+
|
|
37
|
+
function Test() {
|
|
38
|
+
return <DateField maxDate={new Date("2024-12-31")} value={date} onChange={setDate} />
|
|
39
|
+
}
|
|
40
|
+
`.trim()
|
|
41
|
+
|
|
42
|
+
const result = applyTransform(input)
|
|
43
|
+
expect(result).toContain("max={")
|
|
44
|
+
expect(result).not.toContain("maxDate=")
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
it("should not transform DateField without maxDate prop", () => {
|
|
48
|
+
const input = `
|
|
49
|
+
import { DateField } from "@planningcenter/tapestry-react"
|
|
50
|
+
|
|
51
|
+
function Test() {
|
|
52
|
+
return <DateField value={date} onChange={setDate} />
|
|
53
|
+
}
|
|
54
|
+
`.trim()
|
|
55
|
+
|
|
56
|
+
const result = applyTransform(input)
|
|
57
|
+
expect(result).toBe(input)
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
it("should not affect other components", () => {
|
|
61
|
+
const input = `
|
|
62
|
+
import { Input } from "@planningcenter/tapestry-react"
|
|
63
|
+
|
|
64
|
+
function Test() {
|
|
65
|
+
return <Input maxDate={endDate} label="Name" />
|
|
66
|
+
}
|
|
67
|
+
`.trim()
|
|
68
|
+
|
|
69
|
+
const result = applyTransform(input)
|
|
70
|
+
expect(result).toBe(input)
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
it("should preserve other props", () => {
|
|
74
|
+
const input = `
|
|
75
|
+
import { DateField } from "@planningcenter/tapestry-react"
|
|
76
|
+
|
|
77
|
+
function Test() {
|
|
78
|
+
return <DateField minDate={startDate} maxDate={endDate} value={date} onChange={setDate} />
|
|
79
|
+
}
|
|
80
|
+
`.trim()
|
|
81
|
+
|
|
82
|
+
const result = applyTransform(input)
|
|
83
|
+
expect(result).toContain("max={endDate}")
|
|
84
|
+
expect(result).toContain("minDate={startDate}")
|
|
85
|
+
expect(result).toContain("value={date}")
|
|
86
|
+
})
|
|
87
|
+
})
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Transform } from "jscodeshift"
|
|
2
|
+
|
|
3
|
+
import { transformAttributeName } from "../../shared/actions/transformAttributeName"
|
|
4
|
+
import { hasAttribute } from "../../shared/conditions/hasAttribute"
|
|
5
|
+
import { attributeTransformFactory } from "../../shared/transformFactories/attributeTransformFactory"
|
|
6
|
+
|
|
7
|
+
const transform: Transform = attributeTransformFactory({
|
|
8
|
+
condition: hasAttribute("maxDate"),
|
|
9
|
+
targetComponent: "DateField",
|
|
10
|
+
targetPackage: "@planningcenter/tapestry-react",
|
|
11
|
+
transform: (element, { j, options }) => {
|
|
12
|
+
return transformAttributeName("maxDate", "max", { element, j, options })
|
|
13
|
+
},
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
export default transform
|
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
import jscodeshift from "jscodeshift"
|
|
2
|
+
import { describe, expect, it } from "vitest"
|
|
3
|
+
|
|
4
|
+
import transform from "./mergeFieldIntoDateField"
|
|
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("mergeFieldIntoDateField transform", () => {
|
|
18
|
+
describe("basic prop merging", () => {
|
|
19
|
+
it("merges label prop from Field into DateField", () => {
|
|
20
|
+
const input = `
|
|
21
|
+
import { DateField, Field } from "@planningcenter/tapestry-react"
|
|
22
|
+
|
|
23
|
+
function Test() {
|
|
24
|
+
return (
|
|
25
|
+
<Field label="Start date"><DateField value={date} onChange={setDate} /></Field>
|
|
26
|
+
)
|
|
27
|
+
}
|
|
28
|
+
`.trim()
|
|
29
|
+
|
|
30
|
+
const result = applyTransform(input)
|
|
31
|
+
expect(result).not.toBeNull()
|
|
32
|
+
expect(result).not.toContain("<Field")
|
|
33
|
+
expect(result).toContain('label="Start date"')
|
|
34
|
+
expect(result).toContain("<DateField")
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
it("renames feedbackText to description on DateField", () => {
|
|
38
|
+
const input = `
|
|
39
|
+
import { DateField, Field } from "@planningcenter/tapestry-react"
|
|
40
|
+
|
|
41
|
+
function Test() {
|
|
42
|
+
return (
|
|
43
|
+
<Field feedbackText="Required"><DateField value={date} onChange={setDate} /></Field>
|
|
44
|
+
)
|
|
45
|
+
}
|
|
46
|
+
`.trim()
|
|
47
|
+
|
|
48
|
+
const result = applyTransform(input)
|
|
49
|
+
expect(result).not.toBeNull()
|
|
50
|
+
expect(result).not.toContain("<Field")
|
|
51
|
+
expect(result).not.toContain("feedbackText")
|
|
52
|
+
expect(result).toContain('description="Required"')
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
it("copies state prop as-is to DateField", () => {
|
|
56
|
+
const input = `
|
|
57
|
+
import { DateField, Field } from "@planningcenter/tapestry-react"
|
|
58
|
+
|
|
59
|
+
function Test() {
|
|
60
|
+
return (
|
|
61
|
+
<Field state="error"><DateField value={date} onChange={setDate} /></Field>
|
|
62
|
+
)
|
|
63
|
+
}
|
|
64
|
+
`.trim()
|
|
65
|
+
|
|
66
|
+
const result = applyTransform(input)
|
|
67
|
+
expect(result).not.toBeNull()
|
|
68
|
+
expect(result).not.toContain("<Field")
|
|
69
|
+
expect(result).toContain('state="error"')
|
|
70
|
+
})
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
describe("unsupported props", () => {
|
|
74
|
+
it("adds TODO comment for helpContent and removes Field", () => {
|
|
75
|
+
const input = `
|
|
76
|
+
import { DateField, Field } from "@planningcenter/tapestry-react"
|
|
77
|
+
|
|
78
|
+
function Test() {
|
|
79
|
+
return (
|
|
80
|
+
<Field helpContent="Help"><DateField value={date} onChange={setDate} /></Field>
|
|
81
|
+
)
|
|
82
|
+
}
|
|
83
|
+
`.trim()
|
|
84
|
+
|
|
85
|
+
const result = applyTransform(input)
|
|
86
|
+
expect(result).not.toBeNull()
|
|
87
|
+
expect(result).not.toContain("<Field")
|
|
88
|
+
expect(result).toContain(
|
|
89
|
+
"TODO: tapestry-migration (mergeFieldIntoDateField)"
|
|
90
|
+
)
|
|
91
|
+
expect(result).toContain("helpContent")
|
|
92
|
+
expect(result).toContain("not supported by DateField")
|
|
93
|
+
})
|
|
94
|
+
})
|
|
95
|
+
|
|
96
|
+
describe("conflict detection", () => {
|
|
97
|
+
it("adds warning when DateField already has label", () => {
|
|
98
|
+
const input = `
|
|
99
|
+
import { DateField, Field } from "@planningcenter/tapestry-react"
|
|
100
|
+
|
|
101
|
+
function Test() {
|
|
102
|
+
return (
|
|
103
|
+
<Field label="Name"><DateField label="Other" value={date} onChange={setDate} /></Field>
|
|
104
|
+
)
|
|
105
|
+
}
|
|
106
|
+
`.trim()
|
|
107
|
+
|
|
108
|
+
const result = applyTransform(input)
|
|
109
|
+
expect(result).not.toBeNull()
|
|
110
|
+
expect(result).not.toContain("<Field")
|
|
111
|
+
expect(result).toContain('label="Other"')
|
|
112
|
+
expect(result).toContain(
|
|
113
|
+
"TODO: tapestry-migration (mergeFieldIntoDateField)"
|
|
114
|
+
)
|
|
115
|
+
expect(result).toContain("already has label")
|
|
116
|
+
})
|
|
117
|
+
})
|
|
118
|
+
|
|
119
|
+
describe("multiple children", () => {
|
|
120
|
+
it("adds comment when Field has multiple children", () => {
|
|
121
|
+
const input = `
|
|
122
|
+
import { DateField, Field } from "@planningcenter/tapestry-react"
|
|
123
|
+
|
|
124
|
+
function Test() {
|
|
125
|
+
return (
|
|
126
|
+
<Field><DateField value={date} onChange={setDate} /><button /></Field>
|
|
127
|
+
)
|
|
128
|
+
}
|
|
129
|
+
`.trim()
|
|
130
|
+
|
|
131
|
+
const result = applyTransform(input)
|
|
132
|
+
expect(result).not.toBeNull()
|
|
133
|
+
expect(result).toContain("<Field")
|
|
134
|
+
expect(result).toContain(
|
|
135
|
+
"TODO: tapestry-migration (mergeFieldIntoDateField)"
|
|
136
|
+
)
|
|
137
|
+
expect(result).toContain("multiple children")
|
|
138
|
+
})
|
|
139
|
+
})
|
|
140
|
+
|
|
141
|
+
describe("spread props on Field", () => {
|
|
142
|
+
it("bails out with TODO comment when Field has spread props", () => {
|
|
143
|
+
const input = `
|
|
144
|
+
import { DateField, Field } from "@planningcenter/tapestry-react"
|
|
145
|
+
|
|
146
|
+
function Test() {
|
|
147
|
+
return (
|
|
148
|
+
<Field {...fieldProps}><DateField value={date} onChange={setDate} /></Field>
|
|
149
|
+
)
|
|
150
|
+
}
|
|
151
|
+
`.trim()
|
|
152
|
+
|
|
153
|
+
const result = applyTransform(input)
|
|
154
|
+
expect(result).not.toBeNull()
|
|
155
|
+
expect(result).toContain("<Field")
|
|
156
|
+
expect(result).toContain(
|
|
157
|
+
"TODO: tapestry-migration (mergeFieldIntoDateField)"
|
|
158
|
+
)
|
|
159
|
+
expect(result).toContain("spread props")
|
|
160
|
+
})
|
|
161
|
+
})
|
|
162
|
+
|
|
163
|
+
describe("import cleanup", () => {
|
|
164
|
+
it("removes Field from import when all Fields are converted", () => {
|
|
165
|
+
const input = `
|
|
166
|
+
import { DateField, Field } from "@planningcenter/tapestry-react"
|
|
167
|
+
|
|
168
|
+
function Test() {
|
|
169
|
+
return (
|
|
170
|
+
<Field label="Start date"><DateField value={date} onChange={setDate} /></Field>
|
|
171
|
+
)
|
|
172
|
+
}
|
|
173
|
+
`.trim()
|
|
174
|
+
|
|
175
|
+
const result = applyTransform(input)
|
|
176
|
+
expect(result).not.toBeNull()
|
|
177
|
+
expect(result).not.toContain("{ DateField, Field }")
|
|
178
|
+
expect(result).toContain("DateField")
|
|
179
|
+
})
|
|
180
|
+
})
|
|
181
|
+
|
|
182
|
+
describe("not from tapestry-react", () => {
|
|
183
|
+
it("returns null when Field is not imported from tapestry-react", () => {
|
|
184
|
+
const input = `
|
|
185
|
+
import { Field } from "some-other-library"
|
|
186
|
+
import { DateField } from "@planningcenter/tapestry-react"
|
|
187
|
+
|
|
188
|
+
function Test() {
|
|
189
|
+
return (
|
|
190
|
+
<Field label="Name"><DateField value={date} onChange={setDate} /></Field>
|
|
191
|
+
)
|
|
192
|
+
}
|
|
193
|
+
`.trim()
|
|
194
|
+
|
|
195
|
+
const result = applyTransform(input)
|
|
196
|
+
expect(result).toBeNull()
|
|
197
|
+
})
|
|
198
|
+
|
|
199
|
+
it("returns null when DateField is not imported from tapestry-react", () => {
|
|
200
|
+
const input = `
|
|
201
|
+
import { Field } from "@planningcenter/tapestry-react"
|
|
202
|
+
import { DateField } from "some-other-library"
|
|
203
|
+
|
|
204
|
+
function Test() {
|
|
205
|
+
return (
|
|
206
|
+
<Field label="Name"><DateField value={date} onChange={setDate} /></Field>
|
|
207
|
+
)
|
|
208
|
+
}
|
|
209
|
+
`.trim()
|
|
210
|
+
|
|
211
|
+
const result = applyTransform(input)
|
|
212
|
+
expect(result).toBeNull()
|
|
213
|
+
})
|
|
214
|
+
})
|
|
215
|
+
|
|
216
|
+
describe("full prop set", () => {
|
|
217
|
+
it("merges label, feedbackText, state and flags helpContent as unsupported", () => {
|
|
218
|
+
const input = `
|
|
219
|
+
import { DateField, Field } from "@planningcenter/tapestry-react"
|
|
220
|
+
|
|
221
|
+
function Test() {
|
|
222
|
+
return (
|
|
223
|
+
<Field label="Start date" feedbackText="Required" state="error" helpContent="Help">
|
|
224
|
+
<DateField value={date} onChange={setDate} />
|
|
225
|
+
</Field>
|
|
226
|
+
)
|
|
227
|
+
}
|
|
228
|
+
`.trim()
|
|
229
|
+
|
|
230
|
+
const result = applyTransform(input)
|
|
231
|
+
expect(result).not.toBeNull()
|
|
232
|
+
expect(result).not.toContain("<Field")
|
|
233
|
+
expect(result).toContain('label="Start date"')
|
|
234
|
+
expect(result).toContain('description="Required"')
|
|
235
|
+
expect(result).toContain('state="error"')
|
|
236
|
+
expect(result).toContain("helpContent")
|
|
237
|
+
expect(result).toContain("not supported by DateField")
|
|
238
|
+
})
|
|
239
|
+
})
|
|
240
|
+
})
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import jscodeshift from "jscodeshift"
|
|
2
|
+
import { describe, expect, it } from "vitest"
|
|
3
|
+
|
|
4
|
+
import transform from "./minDateToMin"
|
|
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("minDateToMin transform", () => {
|
|
19
|
+
it("should rename minDate to min", () => {
|
|
20
|
+
const input = `
|
|
21
|
+
import { DateField } from "@planningcenter/tapestry-react"
|
|
22
|
+
|
|
23
|
+
function Test() {
|
|
24
|
+
return <DateField minDate={startDate} value={date} onChange={setDate} />
|
|
25
|
+
}
|
|
26
|
+
`.trim()
|
|
27
|
+
|
|
28
|
+
const result = applyTransform(input)
|
|
29
|
+
expect(result).toContain("min={startDate}")
|
|
30
|
+
expect(result).not.toContain("minDate")
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
it("should rename minDate with inline Date value", () => {
|
|
34
|
+
const input = `
|
|
35
|
+
import { DateField } from "@planningcenter/tapestry-react"
|
|
36
|
+
|
|
37
|
+
function Test() {
|
|
38
|
+
return <DateField minDate={new Date("2024-01-01")} value={date} onChange={setDate} />
|
|
39
|
+
}
|
|
40
|
+
`.trim()
|
|
41
|
+
|
|
42
|
+
const result = applyTransform(input)
|
|
43
|
+
expect(result).toContain("min={")
|
|
44
|
+
expect(result).not.toContain("minDate=")
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
it("should not transform DateField without minDate prop", () => {
|
|
48
|
+
const input = `
|
|
49
|
+
import { DateField } from "@planningcenter/tapestry-react"
|
|
50
|
+
|
|
51
|
+
function Test() {
|
|
52
|
+
return <DateField value={date} onChange={setDate} />
|
|
53
|
+
}
|
|
54
|
+
`.trim()
|
|
55
|
+
|
|
56
|
+
const result = applyTransform(input)
|
|
57
|
+
expect(result).toBe(input)
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
it("should not affect other components", () => {
|
|
61
|
+
const input = `
|
|
62
|
+
import { Input } from "@planningcenter/tapestry-react"
|
|
63
|
+
|
|
64
|
+
function Test() {
|
|
65
|
+
return <Input minDate={startDate} label="Name" />
|
|
66
|
+
}
|
|
67
|
+
`.trim()
|
|
68
|
+
|
|
69
|
+
const result = applyTransform(input)
|
|
70
|
+
expect(result).toBe(input)
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
it("should preserve other props", () => {
|
|
74
|
+
const input = `
|
|
75
|
+
import { DateField } from "@planningcenter/tapestry-react"
|
|
76
|
+
|
|
77
|
+
function Test() {
|
|
78
|
+
return <DateField minDate={startDate} maxDate={endDate} value={date} onChange={setDate} />
|
|
79
|
+
}
|
|
80
|
+
`.trim()
|
|
81
|
+
|
|
82
|
+
const result = applyTransform(input)
|
|
83
|
+
expect(result).toContain("min={startDate}")
|
|
84
|
+
expect(result).toContain("maxDate={endDate}")
|
|
85
|
+
expect(result).toContain("value={date}")
|
|
86
|
+
})
|
|
87
|
+
})
|