@planningcenter/tapestry-migration-cli 3.2.3-rc.4 → 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
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import jscodeshift from "jscodeshift"
|
|
2
|
+
import { describe, expect, it } from "vitest"
|
|
3
|
+
|
|
4
|
+
import transform from "./sizeMapping"
|
|
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("sizeMapping transform", () => {
|
|
19
|
+
describe("size value transformations", () => {
|
|
20
|
+
it("should transform xs to md", () => {
|
|
21
|
+
const input = `
|
|
22
|
+
import { DateField } from "@planningcenter/tapestry-react"
|
|
23
|
+
|
|
24
|
+
function Test() {
|
|
25
|
+
return <DateField size="xs" value={date} onChange={setDate} />
|
|
26
|
+
}
|
|
27
|
+
`.trim()
|
|
28
|
+
|
|
29
|
+
const result = applyTransform(input)
|
|
30
|
+
expect(result).toContain('size="md"')
|
|
31
|
+
expect(result).not.toContain('size="xs"')
|
|
32
|
+
expect(result).toContain('Size "xs" was mapped to "md"')
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
it("should transform sm to md", () => {
|
|
36
|
+
const input = `
|
|
37
|
+
import { DateField } from "@planningcenter/tapestry-react"
|
|
38
|
+
|
|
39
|
+
function Test() {
|
|
40
|
+
return <DateField size="sm" value={date} onChange={setDate} />
|
|
41
|
+
}
|
|
42
|
+
`.trim()
|
|
43
|
+
|
|
44
|
+
const result = applyTransform(input)
|
|
45
|
+
expect(result).toContain('size="md"')
|
|
46
|
+
expect(result).not.toContain('size="sm"')
|
|
47
|
+
expect(result).toContain('Size "sm" was mapped to "md"')
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
it("should transform xl to lg", () => {
|
|
51
|
+
const input = `
|
|
52
|
+
import { DateField } from "@planningcenter/tapestry-react"
|
|
53
|
+
|
|
54
|
+
function Test() {
|
|
55
|
+
return <DateField size="xl" value={date} onChange={setDate} />
|
|
56
|
+
}
|
|
57
|
+
`.trim()
|
|
58
|
+
|
|
59
|
+
const result = applyTransform(input)
|
|
60
|
+
expect(result).toContain('size="lg"')
|
|
61
|
+
expect(result).not.toContain('size="xl"')
|
|
62
|
+
expect(result).toContain('Size "xl" was mapped to "lg"')
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
it('should transform size={"sm"} expression container', () => {
|
|
66
|
+
const input = `
|
|
67
|
+
import { DateField } from "@planningcenter/tapestry-react"
|
|
68
|
+
|
|
69
|
+
function Test() {
|
|
70
|
+
return <DateField size={"sm"} value={date} onChange={setDate} />
|
|
71
|
+
}
|
|
72
|
+
`.trim()
|
|
73
|
+
|
|
74
|
+
const result = applyTransform(input)
|
|
75
|
+
expect(result).toContain('size="md"')
|
|
76
|
+
expect(result).toContain('Size "sm" was mapped to "md"')
|
|
77
|
+
})
|
|
78
|
+
|
|
79
|
+
it("should not transform already valid sizes", () => {
|
|
80
|
+
const input = `
|
|
81
|
+
import { DateField } from "@planningcenter/tapestry-react"
|
|
82
|
+
|
|
83
|
+
function Test() {
|
|
84
|
+
return (
|
|
85
|
+
<div>
|
|
86
|
+
<DateField size="md" value={date1} onChange={setDate1} />
|
|
87
|
+
<DateField size="lg" value={date2} onChange={setDate2} />
|
|
88
|
+
</div>
|
|
89
|
+
)
|
|
90
|
+
}
|
|
91
|
+
`.trim()
|
|
92
|
+
|
|
93
|
+
const result = applyTransform(input)
|
|
94
|
+
expect(result).toContain('size="md"')
|
|
95
|
+
expect(result).toContain('size="lg"')
|
|
96
|
+
expect(result).not.toContain("TODO: tapestry-migration")
|
|
97
|
+
})
|
|
98
|
+
})
|
|
99
|
+
|
|
100
|
+
describe("edge cases", () => {
|
|
101
|
+
it("should not affect DateField without size prop", () => {
|
|
102
|
+
const input = `
|
|
103
|
+
import { DateField } from "@planningcenter/tapestry-react"
|
|
104
|
+
|
|
105
|
+
function Test() {
|
|
106
|
+
return <DateField value={date} onChange={setDate} />
|
|
107
|
+
}
|
|
108
|
+
`.trim()
|
|
109
|
+
|
|
110
|
+
const result = applyTransform(input)
|
|
111
|
+
expect(result).toBe(input)
|
|
112
|
+
})
|
|
113
|
+
|
|
114
|
+
it("should not transform expression values (variables)", () => {
|
|
115
|
+
const input = `
|
|
116
|
+
import { DateField } from "@planningcenter/tapestry-react"
|
|
117
|
+
|
|
118
|
+
function Test() {
|
|
119
|
+
const size = "sm"
|
|
120
|
+
return <DateField size={size} value={date} onChange={setDate} />
|
|
121
|
+
}
|
|
122
|
+
`.trim()
|
|
123
|
+
|
|
124
|
+
const result = applyTransform(input)
|
|
125
|
+
expect(result).toContain("size={size}")
|
|
126
|
+
expect(result).not.toContain("Size")
|
|
127
|
+
})
|
|
128
|
+
|
|
129
|
+
it("should not affect other components", () => {
|
|
130
|
+
const input = `
|
|
131
|
+
import { DateField } from "@planningcenter/tapestry-react"
|
|
132
|
+
import { Input } from "@planningcenter/tapestry-react"
|
|
133
|
+
|
|
134
|
+
function Test() {
|
|
135
|
+
return (
|
|
136
|
+
<div>
|
|
137
|
+
<Input size="sm" label="Name" />
|
|
138
|
+
<DateField size="md" value={date} onChange={setDate} />
|
|
139
|
+
</div>
|
|
140
|
+
)
|
|
141
|
+
}
|
|
142
|
+
`.trim()
|
|
143
|
+
|
|
144
|
+
const result = applyTransform(input)
|
|
145
|
+
expect(result).toContain('<Input size="sm"')
|
|
146
|
+
expect(result).toContain('size="md"')
|
|
147
|
+
})
|
|
148
|
+
|
|
149
|
+
it("should handle multiple DateFields with different sizes", () => {
|
|
150
|
+
const input = `
|
|
151
|
+
import { DateField } from "@planningcenter/tapestry-react"
|
|
152
|
+
|
|
153
|
+
function Test() {
|
|
154
|
+
return (
|
|
155
|
+
<div>
|
|
156
|
+
<DateField size="xs" value={date1} onChange={setDate1} />
|
|
157
|
+
<DateField size="sm" value={date2} onChange={setDate2} />
|
|
158
|
+
<DateField size="md" value={date3} onChange={setDate3} />
|
|
159
|
+
<DateField size="xl" value={date4} onChange={setDate4} />
|
|
160
|
+
</div>
|
|
161
|
+
)
|
|
162
|
+
}
|
|
163
|
+
`.trim()
|
|
164
|
+
|
|
165
|
+
const result = applyTransform(input)
|
|
166
|
+
expect(result).not.toContain('size="xs"')
|
|
167
|
+
expect(result).not.toContain('size="sm"')
|
|
168
|
+
expect(result).not.toContain('size="xl"')
|
|
169
|
+
const sizeMappingMatches = result.match(/Size ".*" was mapped to/g)
|
|
170
|
+
expect(sizeMappingMatches).toHaveLength(3)
|
|
171
|
+
})
|
|
172
|
+
})
|
|
173
|
+
})
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Transform } from "jscodeshift"
|
|
2
|
+
|
|
3
|
+
import { sizeMappingFactory } from "../../shared/transformFactories/sizeMappingFactory"
|
|
4
|
+
|
|
5
|
+
const transform: Transform = sizeMappingFactory({
|
|
6
|
+
sizeMapping: {
|
|
7
|
+
sm: "md",
|
|
8
|
+
xl: "lg",
|
|
9
|
+
xs: "md",
|
|
10
|
+
},
|
|
11
|
+
targetComponent: "DateField",
|
|
12
|
+
targetPackage: "@planningcenter/tapestry-react",
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
export default transform
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import jscodeshift from "jscodeshift"
|
|
2
|
+
import { describe, expect, it } from "vitest"
|
|
3
|
+
|
|
4
|
+
import transform from "./stateToInvalid"
|
|
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("stateToInvalid transform", () => {
|
|
19
|
+
describe("state='error' to invalid", () => {
|
|
20
|
+
it("should convert state='error' to invalid boolean", () => {
|
|
21
|
+
const input = `
|
|
22
|
+
import { DateField } from "@planningcenter/tapestry-react"
|
|
23
|
+
|
|
24
|
+
function Test() {
|
|
25
|
+
return <DateField state="error" value={date} onChange={setDate} />
|
|
26
|
+
}
|
|
27
|
+
`.trim()
|
|
28
|
+
|
|
29
|
+
const result = applyTransform(input)
|
|
30
|
+
expect(result).toContain("invalid")
|
|
31
|
+
expect(result).not.toContain('state="error"')
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
it('should convert state={"error"} expression to invalid', () => {
|
|
35
|
+
const input = `
|
|
36
|
+
import { DateField } from "@planningcenter/tapestry-react"
|
|
37
|
+
|
|
38
|
+
function Test() {
|
|
39
|
+
return <DateField state={"error"} value={date} onChange={setDate} />
|
|
40
|
+
}
|
|
41
|
+
`.trim()
|
|
42
|
+
|
|
43
|
+
const result = applyTransform(input)
|
|
44
|
+
expect(result).toContain("invalid")
|
|
45
|
+
expect(result).not.toContain("state=")
|
|
46
|
+
})
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
describe("state='success' removal", () => {
|
|
50
|
+
it("should remove state='success' and add TODO comment", () => {
|
|
51
|
+
const input = `
|
|
52
|
+
import { DateField } from "@planningcenter/tapestry-react"
|
|
53
|
+
|
|
54
|
+
function Test() {
|
|
55
|
+
return <DateField state="success" value={date} onChange={setDate} />
|
|
56
|
+
}
|
|
57
|
+
`.trim()
|
|
58
|
+
|
|
59
|
+
const result = applyTransform(input)
|
|
60
|
+
expect(result).not.toContain('<DateField state="success"')
|
|
61
|
+
expect(result).toContain("TODO: tapestry-migration")
|
|
62
|
+
expect(result).toContain("no equivalent")
|
|
63
|
+
})
|
|
64
|
+
})
|
|
65
|
+
|
|
66
|
+
describe("dynamic state value", () => {
|
|
67
|
+
it("should add TODO comment for dynamic state value", () => {
|
|
68
|
+
const input = `
|
|
69
|
+
import { DateField } from "@planningcenter/tapestry-react"
|
|
70
|
+
|
|
71
|
+
function Test() {
|
|
72
|
+
return <DateField state={fieldState} value={date} onChange={setDate} />
|
|
73
|
+
}
|
|
74
|
+
`.trim()
|
|
75
|
+
|
|
76
|
+
const result = applyTransform(input)
|
|
77
|
+
expect(result).toContain("TODO: tapestry-migration")
|
|
78
|
+
expect(result).toContain("Migrate this prop manually")
|
|
79
|
+
})
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
describe("edge cases", () => {
|
|
83
|
+
it("should not transform DateField without state prop", () => {
|
|
84
|
+
const input = `
|
|
85
|
+
import { DateField } from "@planningcenter/tapestry-react"
|
|
86
|
+
|
|
87
|
+
function Test() {
|
|
88
|
+
return <DateField value={date} onChange={setDate} />
|
|
89
|
+
}
|
|
90
|
+
`.trim()
|
|
91
|
+
|
|
92
|
+
const result = applyTransform(input)
|
|
93
|
+
expect(result).toBe(input)
|
|
94
|
+
})
|
|
95
|
+
|
|
96
|
+
it("should not affect other components", () => {
|
|
97
|
+
const input = `
|
|
98
|
+
import { Button } from "@planningcenter/tapestry-react"
|
|
99
|
+
|
|
100
|
+
function Test() {
|
|
101
|
+
return <Button state="error">Click</Button>
|
|
102
|
+
}
|
|
103
|
+
`.trim()
|
|
104
|
+
|
|
105
|
+
const result = applyTransform(input)
|
|
106
|
+
expect(result).toBe(input)
|
|
107
|
+
})
|
|
108
|
+
})
|
|
109
|
+
})
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { Transform } from "jscodeshift"
|
|
2
|
+
|
|
3
|
+
import { addAttribute } from "../../shared/actions/addAttribute"
|
|
4
|
+
import { addComment } from "../../shared/actions/addComment"
|
|
5
|
+
import { getAttribute } from "../../shared/actions/getAttribute"
|
|
6
|
+
import { getAttributeValue } from "../../shared/actions/getAttributeValue"
|
|
7
|
+
import { removeAttribute } from "../../shared/actions/removeAttribute"
|
|
8
|
+
import { hasAttribute } from "../../shared/conditions/hasAttribute"
|
|
9
|
+
import { attributeTransformFactory } from "../../shared/transformFactories/attributeTransformFactory"
|
|
10
|
+
|
|
11
|
+
const transform: Transform = attributeTransformFactory({
|
|
12
|
+
condition: hasAttribute("state"),
|
|
13
|
+
targetComponent: "DateField",
|
|
14
|
+
targetPackage: "@planningcenter/tapestry-react",
|
|
15
|
+
transform: (element, { j, source }) => {
|
|
16
|
+
const attr = getAttribute({ element, name: "state" })
|
|
17
|
+
if (!attr) return false
|
|
18
|
+
|
|
19
|
+
const value = getAttributeValue({ attribute: attr, j })
|
|
20
|
+
|
|
21
|
+
if (value === "error") {
|
|
22
|
+
removeAttribute("state", { element, j, source })
|
|
23
|
+
addAttribute({
|
|
24
|
+
booleanAsShorthand: true,
|
|
25
|
+
element,
|
|
26
|
+
j,
|
|
27
|
+
name: "invalid",
|
|
28
|
+
value: true,
|
|
29
|
+
})
|
|
30
|
+
return true
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (value === "success") {
|
|
34
|
+
removeAttribute("state", { element, j, source })
|
|
35
|
+
addComment({
|
|
36
|
+
element,
|
|
37
|
+
j,
|
|
38
|
+
scope: "state",
|
|
39
|
+
source,
|
|
40
|
+
text: "'state=\"success\"' has no equivalent in the new DatePicker API. Remove this prop and implement success feedback separately.",
|
|
41
|
+
})
|
|
42
|
+
return true
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Dynamic value — can't determine at compile time
|
|
46
|
+
addComment({
|
|
47
|
+
element,
|
|
48
|
+
j,
|
|
49
|
+
scope: "state",
|
|
50
|
+
source,
|
|
51
|
+
text: "'state' has been replaced by 'invalid' (boolean). For error state, use invalid={true}. 'success' has no equivalent. Migrate this prop manually.",
|
|
52
|
+
})
|
|
53
|
+
return true
|
|
54
|
+
},
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
export default transform
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import jscodeshift from "jscodeshift"
|
|
2
|
+
import { describe, expect, it } from "vitest"
|
|
3
|
+
|
|
4
|
+
import transform from "./stateToInvalidTernary"
|
|
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("stateToInvalidTernary transform", () => {
|
|
19
|
+
it("should convert ternary state={x ? 'error' : undefined} to invalid={x}", () => {
|
|
20
|
+
const input = `
|
|
21
|
+
import { DateField } from "@planningcenter/tapestry-react"
|
|
22
|
+
|
|
23
|
+
function Test() {
|
|
24
|
+
return <DateField state={hasError ? "error" : undefined} value={date} onChange={setDate} />
|
|
25
|
+
}
|
|
26
|
+
`.trim()
|
|
27
|
+
|
|
28
|
+
const result = applyTransform(input)
|
|
29
|
+
expect(result).toContain("invalid={hasError}")
|
|
30
|
+
expect(result).not.toContain("state=")
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
it("should convert ternary state={x ? 'error' : null} to invalid={x}", () => {
|
|
34
|
+
const input = `
|
|
35
|
+
import { DateField } from "@planningcenter/tapestry-react"
|
|
36
|
+
|
|
37
|
+
function Test() {
|
|
38
|
+
return <DateField state={hasError ? "error" : null} value={date} onChange={setDate} />
|
|
39
|
+
}
|
|
40
|
+
`.trim()
|
|
41
|
+
|
|
42
|
+
const result = applyTransform(input)
|
|
43
|
+
expect(result).toContain("invalid={hasError}")
|
|
44
|
+
expect(result).not.toContain("state=")
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
it("should not transform without state 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 { Button } from "@planningcenter/tapestry-react"
|
|
63
|
+
|
|
64
|
+
function Test() {
|
|
65
|
+
return <Button state={hasError ? "error" : undefined}>Click</Button>
|
|
66
|
+
}
|
|
67
|
+
`.trim()
|
|
68
|
+
|
|
69
|
+
const result = applyTransform(input)
|
|
70
|
+
expect(result).toBe(input)
|
|
71
|
+
})
|
|
72
|
+
})
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { hasAttribute } from "../../shared/conditions/hasAttribute"
|
|
2
|
+
import { ternaryConditionalToPropFactory } from "../../shared/transformFactories/ternaryConditionalToPropFactory"
|
|
3
|
+
|
|
4
|
+
export default ternaryConditionalToPropFactory({
|
|
5
|
+
condition: hasAttribute("state"),
|
|
6
|
+
fromProp: "state",
|
|
7
|
+
matchValue: "error",
|
|
8
|
+
targetComponent: "DateField",
|
|
9
|
+
targetPackage: "@planningcenter/tapestry-react",
|
|
10
|
+
toProp: "invalid",
|
|
11
|
+
})
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import jscodeshift from "jscodeshift"
|
|
2
|
+
import { describe, expect, it } from "vitest"
|
|
3
|
+
|
|
4
|
+
import transform from "./unsupportedProps"
|
|
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("unsupportedProps transform", () => {
|
|
19
|
+
it("should flag placement as unsupported", () => {
|
|
20
|
+
const input = `
|
|
21
|
+
import { DateField } from "@planningcenter/tapestry-react"
|
|
22
|
+
|
|
23
|
+
function Test() {
|
|
24
|
+
return <DateField placement="bottom" value={date} onChange={setDate} />
|
|
25
|
+
}
|
|
26
|
+
`.trim()
|
|
27
|
+
|
|
28
|
+
const result = applyTransform(input)
|
|
29
|
+
expect(result).toContain("TODO: tapestry-migration")
|
|
30
|
+
expect(result).toContain("placement")
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
it("should flag defaultOpen as unsupported", () => {
|
|
34
|
+
const input = `
|
|
35
|
+
import { DateField } from "@planningcenter/tapestry-react"
|
|
36
|
+
|
|
37
|
+
function Test() {
|
|
38
|
+
return <DateField defaultOpen value={date} onChange={setDate} />
|
|
39
|
+
}
|
|
40
|
+
`.trim()
|
|
41
|
+
|
|
42
|
+
const result = applyTransform(input)
|
|
43
|
+
expect(result).toContain("TODO: tapestry-migration")
|
|
44
|
+
expect(result).toContain("defaultOpen")
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
it("should flag calendarProps as unsupported", () => {
|
|
48
|
+
const input = `
|
|
49
|
+
import { DateField } from "@planningcenter/tapestry-react"
|
|
50
|
+
|
|
51
|
+
function Test() {
|
|
52
|
+
return <DateField calendarProps={{ size: "sm" }} value={date} onChange={setDate} />
|
|
53
|
+
}
|
|
54
|
+
`.trim()
|
|
55
|
+
|
|
56
|
+
const result = applyTransform(input)
|
|
57
|
+
expect(result).toContain("TODO: tapestry-migration")
|
|
58
|
+
expect(result).toContain("calendarProps")
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
it("should flag popoverProps as unsupported", () => {
|
|
62
|
+
const input = `
|
|
63
|
+
import { DateField } from "@planningcenter/tapestry-react"
|
|
64
|
+
|
|
65
|
+
function Test() {
|
|
66
|
+
return <DateField popoverProps={{ placement: "top" }} value={date} onChange={setDate} />
|
|
67
|
+
}
|
|
68
|
+
`.trim()
|
|
69
|
+
|
|
70
|
+
const result = applyTransform(input)
|
|
71
|
+
expect(result).toContain("TODO: tapestry-migration")
|
|
72
|
+
expect(result).toContain("popoverProps")
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
it("should flag lockScrollWhileOpen as unsupported", () => {
|
|
76
|
+
const input = `
|
|
77
|
+
import { DateField } from "@planningcenter/tapestry-react"
|
|
78
|
+
|
|
79
|
+
function Test() {
|
|
80
|
+
return <DateField lockScrollWhileOpen={false} value={date} onChange={setDate} />
|
|
81
|
+
}
|
|
82
|
+
`.trim()
|
|
83
|
+
|
|
84
|
+
const result = applyTransform(input)
|
|
85
|
+
expect(result).toContain("TODO: tapestry-migration")
|
|
86
|
+
expect(result).toContain("lockScrollWhileOpen")
|
|
87
|
+
})
|
|
88
|
+
|
|
89
|
+
it("should flag keepInView as unsupported", () => {
|
|
90
|
+
const input = `
|
|
91
|
+
import { DateField } from "@planningcenter/tapestry-react"
|
|
92
|
+
|
|
93
|
+
function Test() {
|
|
94
|
+
return <DateField keepInView value={date} onChange={setDate} />
|
|
95
|
+
}
|
|
96
|
+
`.trim()
|
|
97
|
+
|
|
98
|
+
const result = applyTransform(input)
|
|
99
|
+
expect(result).toContain("TODO: tapestry-migration")
|
|
100
|
+
expect(result).toContain("keepInView")
|
|
101
|
+
})
|
|
102
|
+
|
|
103
|
+
it("should not flag supported props", () => {
|
|
104
|
+
const input = `
|
|
105
|
+
import { DateField } from "@planningcenter/tapestry-react"
|
|
106
|
+
|
|
107
|
+
function Test() {
|
|
108
|
+
return (
|
|
109
|
+
<DateField
|
|
110
|
+
value={date}
|
|
111
|
+
onChange={setDate}
|
|
112
|
+
disabled
|
|
113
|
+
required
|
|
114
|
+
size="md"
|
|
115
|
+
label="Start date"
|
|
116
|
+
description="Pick a date"
|
|
117
|
+
invalid
|
|
118
|
+
min={minDate}
|
|
119
|
+
max={maxDate}
|
|
120
|
+
className="my-date"
|
|
121
|
+
id="date-field"
|
|
122
|
+
/>
|
|
123
|
+
)
|
|
124
|
+
}
|
|
125
|
+
`.trim()
|
|
126
|
+
|
|
127
|
+
const result = applyTransform(input)
|
|
128
|
+
expect(result).not.toContain("TODO: tapestry-migration")
|
|
129
|
+
})
|
|
130
|
+
|
|
131
|
+
it("should allow aria-* and data-* attributes", () => {
|
|
132
|
+
const input = `
|
|
133
|
+
import { DateField } from "@planningcenter/tapestry-react"
|
|
134
|
+
|
|
135
|
+
function Test() {
|
|
136
|
+
return <DateField aria-describedby="help" data-testid="date" value={date} onChange={setDate} />
|
|
137
|
+
}
|
|
138
|
+
`.trim()
|
|
139
|
+
|
|
140
|
+
const result = applyTransform(input)
|
|
141
|
+
expect(result).not.toContain("TODO: tapestry-migration")
|
|
142
|
+
})
|
|
143
|
+
|
|
144
|
+
it("should flag css prop with specific message", () => {
|
|
145
|
+
const input = `
|
|
146
|
+
import { DateField } from "@planningcenter/tapestry-react"
|
|
147
|
+
|
|
148
|
+
function Test() {
|
|
149
|
+
return <DateField css={{ color: "red" }} value={date} onChange={setDate} />
|
|
150
|
+
}
|
|
151
|
+
`.trim()
|
|
152
|
+
|
|
153
|
+
const result = applyTransform(input)
|
|
154
|
+
expect(result).toContain("TODO: tapestry-migration")
|
|
155
|
+
expect(result).toContain("CSS prop is not supported")
|
|
156
|
+
})
|
|
157
|
+
|
|
158
|
+
it("should not affect other components", () => {
|
|
159
|
+
const input = `
|
|
160
|
+
import { Button } from "@planningcenter/tapestry-react"
|
|
161
|
+
|
|
162
|
+
function Test() {
|
|
163
|
+
return <Button formatValue="test">Click</Button>
|
|
164
|
+
}
|
|
165
|
+
`.trim()
|
|
166
|
+
|
|
167
|
+
const result = applyTransform(input)
|
|
168
|
+
expect(result).toBe(input)
|
|
169
|
+
})
|
|
170
|
+
})
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { JSXAttribute, Transform } from "jscodeshift"
|
|
2
|
+
|
|
3
|
+
import { addCommentToUnsupportedProps } from "../../shared/actions/addCommentToUnsupportedProps"
|
|
4
|
+
import { DATE_PICKER_SUPPORTED_PROPS } from "../../shared/helpers/unsupportedPropsHelpers"
|
|
5
|
+
import { attributeTransformFactory } from "../../shared/transformFactories/attributeTransformFactory"
|
|
6
|
+
|
|
7
|
+
const transform: Transform = attributeTransformFactory({
|
|
8
|
+
targetComponent: "DateField",
|
|
9
|
+
targetPackage: "@planningcenter/tapestry-react",
|
|
10
|
+
transform: (element, { j }) => {
|
|
11
|
+
const attrs = element.openingElement.attributes || []
|
|
12
|
+
|
|
13
|
+
const UNSUPPORTED_PROPS = attrs
|
|
14
|
+
.filter(
|
|
15
|
+
(attr) =>
|
|
16
|
+
attr.type === "JSXAttribute" &&
|
|
17
|
+
!DATE_PICKER_SUPPORTED_PROPS.includes(attr.name.name as string) &&
|
|
18
|
+
!(attr.name.name as string).startsWith("aria-") &&
|
|
19
|
+
!(attr.name.name as string).startsWith("data-")
|
|
20
|
+
)
|
|
21
|
+
.map((attr) => (attr as JSXAttribute).name.name as string)
|
|
22
|
+
|
|
23
|
+
return addCommentToUnsupportedProps({
|
|
24
|
+
element,
|
|
25
|
+
j,
|
|
26
|
+
messageSuffix: (prop) => {
|
|
27
|
+
if (prop === "css") {
|
|
28
|
+
return "\n * CSS prop is not supported. Use className or style prop instead.\n"
|
|
29
|
+
}
|
|
30
|
+
return ""
|
|
31
|
+
},
|
|
32
|
+
props: UNSUPPORTED_PROPS,
|
|
33
|
+
})
|
|
34
|
+
},
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
export default transform
|
|
@@ -175,3 +175,21 @@ export const TIME_FIELD_SUPPORTED_PROPS = [
|
|
|
175
175
|
...COMMON_PROPS,
|
|
176
176
|
...TIME_FIELD_SPECIFIC_PROPS,
|
|
177
177
|
]
|
|
178
|
+
export const DATE_PICKER_SPECIFIC_PROPS = [
|
|
179
|
+
"description",
|
|
180
|
+
"disabled",
|
|
181
|
+
"firstDayOfWeek",
|
|
182
|
+
"hideLabel",
|
|
183
|
+
"invalid",
|
|
184
|
+
"isDateUnavailable",
|
|
185
|
+
"max",
|
|
186
|
+
"min",
|
|
187
|
+
"onChange",
|
|
188
|
+
"readOnly",
|
|
189
|
+
"required",
|
|
190
|
+
"value",
|
|
191
|
+
]
|
|
192
|
+
export const DATE_PICKER_SUPPORTED_PROPS = [
|
|
193
|
+
...COMMON_PROPS,
|
|
194
|
+
...DATE_PICKER_SPECIFIC_PROPS,
|
|
195
|
+
]
|