@planningcenter/tapestry-migration-cli 3.6.0 → 3.7.0-rc.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/dist/tapestry-react-shim.cjs +195 -11
- package/package.json +3 -3
- package/src/components/flex/index.test.ts +181 -0
- package/src/components/flex/index.ts +16 -0
- package/src/components/flex/transforms/alignmentToAlign.test.ts +101 -0
- package/src/components/flex/transforms/alignmentToAlign.ts +74 -20
- package/src/components/flex/transforms/auditSpreadProps.test.ts +93 -0
- package/src/components/flex/transforms/auditSpreadProps.ts +6 -0
- package/src/components/flex/transforms/axisToDirection.test.ts +15 -0
- package/src/components/flex/transforms/axisToDirection.ts +26 -0
- package/src/components/flex/transforms/constants.ts +4 -0
- package/src/components/flex/transforms/convertStyleProps.test.ts +147 -0
- package/src/components/flex/transforms/convertStyleProps.ts +23 -0
- package/src/components/flex/transforms/cssFlexAliasesToProps.test.ts +202 -0
- package/src/components/flex/transforms/cssFlexAliasesToProps.ts +106 -0
- package/src/components/flex/transforms/dedupeAttributes.test.ts +120 -0
- package/src/components/flex/transforms/dedupeAttributes.ts +49 -0
- package/src/components/flex/transforms/distributionToJustify.test.ts +59 -0
- package/src/components/flex/transforms/distributionToJustify.ts +69 -20
- package/src/components/flex/transforms/flexPropToExpand.test.ts +172 -0
- package/src/components/flex/transforms/flexPropToExpand.ts +100 -0
- package/src/components/flex/transforms/mediaQueriesToResponsive.test.ts +795 -0
- package/src/components/flex/transforms/mediaQueriesToResponsive.ts +562 -0
- package/src/components/flex/transforms/paddingPropsToFlex.test.ts +252 -0
- package/src/components/flex/transforms/paddingPropsToFlex.ts +150 -0
- package/src/components/flex/transforms/setDefaultAxis.test.ts +12 -0
- package/src/components/flex/transforms/setDefaultAxis.ts +1 -0
- package/src/components/flex/transforms/spacingToGap.test.ts +87 -0
- package/src/components/flex/transforms/spacingToGap.ts +28 -10
- package/src/components/flex/transforms/unsupportedProps.test.ts +141 -0
- package/src/components/flex/transforms/unsupportedProps.ts +17 -0
- package/src/components/shared/helpers/unsupportedPropsHelpers.ts +41 -0
- package/src/components/shared/transformFactories/stylePropTransformFactory.test.ts +47 -0
- package/src/components/shared/transformFactories/stylePropTransformFactory.ts +16 -0
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import { Transform } from "jscodeshift"
|
|
1
|
+
import { Expression, Transform } from "jscodeshift"
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import { addCommentToAttribute } from "../../shared/actions/addCommentToAttribute"
|
|
4
4
|
import { getAttribute } from "../../shared/actions/getAttribute"
|
|
5
5
|
import { resolveConstantAttributeValue } from "../../shared/actions/resolveConstantAttributeValue"
|
|
6
6
|
import { hasAttribute } from "../../shared/conditions/hasAttribute"
|
|
7
7
|
import { attributeTransformFactory } from "../../shared/transformFactories/attributeTransformFactory"
|
|
8
|
+
import { FLEX_START_END_MAP } from "./constants"
|
|
8
9
|
|
|
9
10
|
const VALID_ALIGN_VALUES = new Set([
|
|
10
11
|
"start",
|
|
@@ -23,42 +24,95 @@ const CONSTANT_ALIGN_MAP: Record<string, string> = {
|
|
|
23
24
|
STRETCH: "stretch",
|
|
24
25
|
}
|
|
25
26
|
|
|
27
|
+
const TODO_TEXT =
|
|
28
|
+
"could not migrate alignment to align automatically; convert this value to start, center, end, stretch, or baseline manually"
|
|
29
|
+
|
|
30
|
+
function normalizeAlignValue(raw: string): string | null {
|
|
31
|
+
const normalized = FLEX_START_END_MAP[raw] ?? raw
|
|
32
|
+
return VALID_ALIGN_VALUES.has(normalized) ? normalized : null
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
type BranchResolution =
|
|
36
|
+
| { kind: "invalid" }
|
|
37
|
+
| { kind: "passthrough" }
|
|
38
|
+
| { kind: "valid"; value: string }
|
|
39
|
+
|
|
40
|
+
function resolveBranch(node: Expression): BranchResolution {
|
|
41
|
+
if (node.type === "StringLiteral") {
|
|
42
|
+
const normalized = normalizeAlignValue(node.value)
|
|
43
|
+
return normalized !== null
|
|
44
|
+
? { kind: "valid", value: normalized }
|
|
45
|
+
: { kind: "invalid" }
|
|
46
|
+
}
|
|
47
|
+
if (node.type === "MemberExpression" && node.property.type === "Identifier") {
|
|
48
|
+
const mapped = CONSTANT_ALIGN_MAP[node.property.name]
|
|
49
|
+
if (mapped === undefined) return { kind: "passthrough" }
|
|
50
|
+
const normalized = normalizeAlignValue(mapped)
|
|
51
|
+
return normalized !== null
|
|
52
|
+
? { kind: "valid", value: normalized }
|
|
53
|
+
: { kind: "invalid" }
|
|
54
|
+
}
|
|
55
|
+
return { kind: "passthrough" }
|
|
56
|
+
}
|
|
57
|
+
|
|
26
58
|
const transform: Transform = attributeTransformFactory({
|
|
27
59
|
condition: hasAttribute("alignment"),
|
|
28
60
|
targetComponent: "StackView",
|
|
29
61
|
targetPackage: "@planningcenter/tapestry-react",
|
|
30
|
-
transform: (element, { j
|
|
62
|
+
transform: (element, { j }) => {
|
|
31
63
|
const alignmentAttribute = getAttribute({ element, name: "alignment" })
|
|
32
64
|
if (!alignmentAttribute) return false
|
|
33
65
|
|
|
66
|
+
const value = alignmentAttribute.value
|
|
67
|
+
|
|
68
|
+
if (
|
|
69
|
+
value?.type === "JSXExpressionContainer" &&
|
|
70
|
+
value.expression.type === "ConditionalExpression"
|
|
71
|
+
) {
|
|
72
|
+
const conditional = value.expression
|
|
73
|
+
const consequent = resolveBranch(conditional.consequent as Expression)
|
|
74
|
+
const alternate = resolveBranch(conditional.alternate as Expression)
|
|
75
|
+
|
|
76
|
+
if (consequent.kind !== "invalid" && alternate.kind !== "invalid") {
|
|
77
|
+
if (consequent.kind === "valid") {
|
|
78
|
+
conditional.consequent = j.stringLiteral(consequent.value)
|
|
79
|
+
}
|
|
80
|
+
if (alternate.kind === "valid") {
|
|
81
|
+
conditional.alternate = j.stringLiteral(alternate.value)
|
|
82
|
+
}
|
|
83
|
+
alignmentAttribute.name.name = "align"
|
|
84
|
+
return true
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
addCommentToAttribute({
|
|
88
|
+
attribute: alignmentAttribute,
|
|
89
|
+
j,
|
|
90
|
+
text: TODO_TEXT,
|
|
91
|
+
})
|
|
92
|
+
return true
|
|
93
|
+
}
|
|
94
|
+
|
|
34
95
|
const resolved = resolveConstantAttributeValue({
|
|
35
96
|
attribute: alignmentAttribute,
|
|
36
97
|
constantMap: CONSTANT_ALIGN_MAP,
|
|
37
98
|
})
|
|
38
|
-
const alignValue =
|
|
39
|
-
resolved !== null &&
|
|
40
|
-
(VALID_ALIGN_VALUES.has(resolved) || resolved === "fill")
|
|
41
|
-
? resolved
|
|
42
|
-
: null
|
|
43
99
|
|
|
44
|
-
if (
|
|
45
|
-
|
|
46
|
-
|
|
100
|
+
if (resolved === "fill") {
|
|
101
|
+
addCommentToAttribute({
|
|
102
|
+
attribute: alignmentAttribute,
|
|
47
103
|
j,
|
|
48
|
-
|
|
49
|
-
source,
|
|
50
|
-
text: "could not migrate alignment to align automatically; convert this value to start, center, end, stretch, or baseline manually",
|
|
104
|
+
text: 'alignment="fill" has no Flex equivalent; remove this prop and use expand on the child element instead',
|
|
51
105
|
})
|
|
52
106
|
return true
|
|
53
107
|
}
|
|
54
108
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
109
|
+
const alignValue = resolved !== null ? normalizeAlignValue(resolved) : null
|
|
110
|
+
|
|
111
|
+
if (alignValue === null) {
|
|
112
|
+
addCommentToAttribute({
|
|
113
|
+
attribute: alignmentAttribute,
|
|
58
114
|
j,
|
|
59
|
-
|
|
60
|
-
source,
|
|
61
|
-
text: 'alignment="fill" has no Flex equivalent; remove this prop and use expand on the child element instead',
|
|
115
|
+
text: TODO_TEXT,
|
|
62
116
|
})
|
|
63
117
|
return true
|
|
64
118
|
}
|
|
@@ -0,0 +1,93 @@
|
|
|
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): string | null {
|
|
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
|
+
it("adds a comment to StackView with spread props", () => {
|
|
22
|
+
const input = `
|
|
23
|
+
import { StackView } from "@planningcenter/tapestry-react"
|
|
24
|
+
|
|
25
|
+
export default function Test() {
|
|
26
|
+
return <StackView {...props}>Test</StackView>
|
|
27
|
+
}
|
|
28
|
+
`.trim()
|
|
29
|
+
|
|
30
|
+
const result = applyTransform(input)
|
|
31
|
+
expect(result).toContain(AUDIT_COMMENT)
|
|
32
|
+
expect(result).toContain("{...props}")
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
it("adds a comment for each spread", () => {
|
|
36
|
+
const input = `
|
|
37
|
+
import { StackView } from "@planningcenter/tapestry-react"
|
|
38
|
+
|
|
39
|
+
export default function Test() {
|
|
40
|
+
return <StackView {...baseProps} {...extraProps}>Test</StackView>
|
|
41
|
+
}
|
|
42
|
+
`.trim()
|
|
43
|
+
|
|
44
|
+
const result = applyTransform(input)
|
|
45
|
+
const commentCount = (result?.match(/spreadAttribute/g) || []).length
|
|
46
|
+
expect(commentCount).toBe(2)
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
it("preserves all other attributes", () => {
|
|
50
|
+
const input = `
|
|
51
|
+
import { StackView } from "@planningcenter/tapestry-react"
|
|
52
|
+
|
|
53
|
+
export default function Test() {
|
|
54
|
+
return <StackView axis="horizontal" spacing={2} {...props}>Test</StackView>
|
|
55
|
+
}
|
|
56
|
+
`.trim()
|
|
57
|
+
|
|
58
|
+
const result = applyTransform(input)
|
|
59
|
+
expect(result).toContain('axis="horizontal"')
|
|
60
|
+
expect(result).toContain("spacing={2}")
|
|
61
|
+
expect(result).toContain("{...props}")
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
describe("no changes scenarios", () => {
|
|
65
|
+
it("returns null when no spread props", () => {
|
|
66
|
+
const input = `
|
|
67
|
+
import { StackView } from "@planningcenter/tapestry-react"
|
|
68
|
+
|
|
69
|
+
export default function Test() {
|
|
70
|
+
return <StackView axis="horizontal">Test</StackView>
|
|
71
|
+
}
|
|
72
|
+
`.trim()
|
|
73
|
+
|
|
74
|
+
expect(applyTransform(input)).toBe(null)
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
it("returns null when not imported from tapestry-react", () => {
|
|
78
|
+
const input = `
|
|
79
|
+
import { StackView } from "some-other-library"
|
|
80
|
+
|
|
81
|
+
export default function Test() {
|
|
82
|
+
return <StackView {...props}>Test</StackView>
|
|
83
|
+
}
|
|
84
|
+
`.trim()
|
|
85
|
+
|
|
86
|
+
expect(applyTransform(input)).toBe(null)
|
|
87
|
+
})
|
|
88
|
+
|
|
89
|
+
it("returns null for empty file", () => {
|
|
90
|
+
expect(applyTransform("")).toBe(null)
|
|
91
|
+
})
|
|
92
|
+
})
|
|
93
|
+
})
|
|
@@ -101,6 +101,21 @@ export default function Test({ orientation }) {
|
|
|
101
101
|
expect(result).not.toContain('direction="')
|
|
102
102
|
})
|
|
103
103
|
|
|
104
|
+
it("migrates a ternary axis value to a ternary direction value", () => {
|
|
105
|
+
const input = `
|
|
106
|
+
import { StackView } from "@planningcenter/tapestry-react"
|
|
107
|
+
|
|
108
|
+
export default function Test() {
|
|
109
|
+
return <StackView axis={isNarrow ? "vertical" : "horizontal"}>Test</StackView>
|
|
110
|
+
}
|
|
111
|
+
`.trim()
|
|
112
|
+
|
|
113
|
+
const result = applyTransform(input)
|
|
114
|
+
expect(result).toContain('direction={isNarrow ? "column" : "row"}')
|
|
115
|
+
expect(result).not.toContain("axis")
|
|
116
|
+
expect(result).not.toContain("TODO")
|
|
117
|
+
})
|
|
118
|
+
|
|
104
119
|
it("maps an aliased StackView import", () => {
|
|
105
120
|
const input = `
|
|
106
121
|
import { StackView as Stack } from "@planningcenter/tapestry-react"
|
|
@@ -31,6 +31,32 @@ const transform: Transform = attributeTransformFactory({
|
|
|
31
31
|
const direction = resolved ? AXIS_DIRECTION_MAP[resolved] : undefined
|
|
32
32
|
|
|
33
33
|
if (!direction) {
|
|
34
|
+
const value = axisAttribute.value
|
|
35
|
+
if (value?.type === "JSXExpressionContainer") {
|
|
36
|
+
const expr = value.expression
|
|
37
|
+
if (
|
|
38
|
+
expr.type === "ConditionalExpression" &&
|
|
39
|
+
expr.consequent.type === "StringLiteral" &&
|
|
40
|
+
expr.alternate.type === "StringLiteral"
|
|
41
|
+
) {
|
|
42
|
+
const consequentDir =
|
|
43
|
+
AXIS_DIRECTION_MAP[expr.consequent.value as string]
|
|
44
|
+
const alternateDir =
|
|
45
|
+
AXIS_DIRECTION_MAP[expr.alternate.value as string]
|
|
46
|
+
if (consequentDir && alternateDir) {
|
|
47
|
+
axisAttribute.name.name = "direction"
|
|
48
|
+
axisAttribute.value = j.jsxExpressionContainer(
|
|
49
|
+
j.conditionalExpression(
|
|
50
|
+
expr.test,
|
|
51
|
+
j.stringLiteral(consequentDir),
|
|
52
|
+
j.stringLiteral(alternateDir)
|
|
53
|
+
)
|
|
54
|
+
)
|
|
55
|
+
return true
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
34
60
|
addComment({
|
|
35
61
|
element,
|
|
36
62
|
j,
|
|
@@ -0,0 +1,147 @@
|
|
|
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 | 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("convertStyleProps transform", () => {
|
|
18
|
+
it("moves a margin style prop to a style object", () => {
|
|
19
|
+
const input = `
|
|
20
|
+
import { StackView } from "@planningcenter/tapestry-react"
|
|
21
|
+
|
|
22
|
+
export default function Test() {
|
|
23
|
+
return <StackView marginTop={2}>Test</StackView>
|
|
24
|
+
}
|
|
25
|
+
`.trim()
|
|
26
|
+
|
|
27
|
+
expect(applyTransform(input)).toMatchInlineSnapshot(`
|
|
28
|
+
"import { StackView } from "@planningcenter/tapestry-react"
|
|
29
|
+
|
|
30
|
+
export default function Test() {
|
|
31
|
+
return (
|
|
32
|
+
<StackView style={{
|
|
33
|
+
marginTop: "16px"
|
|
34
|
+
}}>Test</StackView>
|
|
35
|
+
);
|
|
36
|
+
}"
|
|
37
|
+
`)
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
it("moves a padding style prop to a style object (splitStyles expands shorthand)", () => {
|
|
41
|
+
const input = `
|
|
42
|
+
import { StackView } from "@planningcenter/tapestry-react"
|
|
43
|
+
|
|
44
|
+
export default function Test() {
|
|
45
|
+
return <StackView paddingTop={2}>Test</StackView>
|
|
46
|
+
}
|
|
47
|
+
`.trim()
|
|
48
|
+
|
|
49
|
+
expect(applyTransform(input)).toMatchInlineSnapshot(`
|
|
50
|
+
"import { StackView } from "@planningcenter/tapestry-react"
|
|
51
|
+
|
|
52
|
+
export default function Test() {
|
|
53
|
+
return (
|
|
54
|
+
<StackView style={{
|
|
55
|
+
paddingTop: "16px"
|
|
56
|
+
}}>Test</StackView>
|
|
57
|
+
);
|
|
58
|
+
}"
|
|
59
|
+
`)
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
it("migrates non-excluded style props while leaving excluded Flex props in place", () => {
|
|
63
|
+
const input = `
|
|
64
|
+
import { StackView } from "@planningcenter/tapestry-react"
|
|
65
|
+
|
|
66
|
+
export default function Test() {
|
|
67
|
+
return <StackView gap={2} marginTop={2}>Test</StackView>
|
|
68
|
+
}
|
|
69
|
+
`.trim()
|
|
70
|
+
|
|
71
|
+
expect(applyTransform(input)).toMatchInlineSnapshot(`
|
|
72
|
+
"import { StackView } from "@planningcenter/tapestry-react"
|
|
73
|
+
|
|
74
|
+
export default function Test() {
|
|
75
|
+
return (
|
|
76
|
+
<StackView gap={2} style={{
|
|
77
|
+
marginTop: "16px"
|
|
78
|
+
}}>Test</StackView>
|
|
79
|
+
);
|
|
80
|
+
}"
|
|
81
|
+
`)
|
|
82
|
+
})
|
|
83
|
+
|
|
84
|
+
it("leaves Flex first-class props untouched", () => {
|
|
85
|
+
const input = `
|
|
86
|
+
import { StackView } from "@planningcenter/tapestry-react"
|
|
87
|
+
|
|
88
|
+
export default function Test() {
|
|
89
|
+
return <StackView gap={2} padding={1} direction="row" wrap="wrap" alignSelf="center" columnGap={1} basis="100%" grow={1} shrink={0}>Test</StackView>
|
|
90
|
+
}
|
|
91
|
+
`.trim()
|
|
92
|
+
|
|
93
|
+
expect(applyTransform(input)).toBe(null)
|
|
94
|
+
})
|
|
95
|
+
|
|
96
|
+
it.each(["grow", "shrink", "basis"] as const)(
|
|
97
|
+
"leaves %s untouched and emits no TODO",
|
|
98
|
+
(prop) => {
|
|
99
|
+
const value = prop === "basis" ? '"100%"' : "{1}"
|
|
100
|
+
const input = `
|
|
101
|
+
import { StackView } from "@planningcenter/tapestry-react"
|
|
102
|
+
export default function Test() {
|
|
103
|
+
return <StackView ${prop}=${value}>Test</StackView>
|
|
104
|
+
}
|
|
105
|
+
`.trim()
|
|
106
|
+
|
|
107
|
+
expect(applyTransform(input)).toBe(null)
|
|
108
|
+
}
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
it("leaves axis/alignment/distribution/spacing for the dedicated rename transforms", () => {
|
|
112
|
+
const input = `
|
|
113
|
+
import { StackView } from "@planningcenter/tapestry-react"
|
|
114
|
+
|
|
115
|
+
export default function Test() {
|
|
116
|
+
return <StackView axis="horizontal" alignment="center" distribution="center" spacing={2}>Test</StackView>
|
|
117
|
+
}
|
|
118
|
+
`.trim()
|
|
119
|
+
|
|
120
|
+
const result = applyTransform(input)
|
|
121
|
+
expect(result).toBe(null)
|
|
122
|
+
})
|
|
123
|
+
|
|
124
|
+
it("returns null when there are no style props to migrate", () => {
|
|
125
|
+
const input = `
|
|
126
|
+
import { StackView } from "@planningcenter/tapestry-react"
|
|
127
|
+
|
|
128
|
+
export default function Test() {
|
|
129
|
+
return <StackView>Test</StackView>
|
|
130
|
+
}
|
|
131
|
+
`.trim()
|
|
132
|
+
|
|
133
|
+
expect(applyTransform(input)).toBe(null)
|
|
134
|
+
})
|
|
135
|
+
|
|
136
|
+
it("returns null when StackView is not imported from tapestry-react", () => {
|
|
137
|
+
const input = `
|
|
138
|
+
import { StackView } from "some-other-package"
|
|
139
|
+
|
|
140
|
+
export default function Test() {
|
|
141
|
+
return <StackView marginTop={2}>Test</StackView>
|
|
142
|
+
}
|
|
143
|
+
`.trim()
|
|
144
|
+
|
|
145
|
+
expect(applyTransform(input)).toBe(null)
|
|
146
|
+
})
|
|
147
|
+
})
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { stylePropTransformFactory } from "../../shared/transformFactories/stylePropTransformFactory"
|
|
2
|
+
|
|
3
|
+
const FLEX_PROP_NAMES = [
|
|
4
|
+
"alignItems",
|
|
5
|
+
"alignSelf",
|
|
6
|
+
"basis",
|
|
7
|
+
"columnGap",
|
|
8
|
+
"direction",
|
|
9
|
+
"flex",
|
|
10
|
+
"gap",
|
|
11
|
+
"grow",
|
|
12
|
+
"justifyContent",
|
|
13
|
+
"padding",
|
|
14
|
+
"shrink",
|
|
15
|
+
"wrap",
|
|
16
|
+
]
|
|
17
|
+
|
|
18
|
+
export default stylePropTransformFactory({
|
|
19
|
+
stylesToExclude: FLEX_PROP_NAMES,
|
|
20
|
+
stylesToRemove: [],
|
|
21
|
+
targetComponent: "StackView",
|
|
22
|
+
targetPackage: "@planningcenter/tapestry-react",
|
|
23
|
+
})
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
import jscodeshift from "jscodeshift"
|
|
2
|
+
import { describe, expect, it } from "vitest"
|
|
3
|
+
|
|
4
|
+
import transform from "./cssFlexAliasesToProps"
|
|
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("cssFlexAliasesToProps transform", () => {
|
|
18
|
+
it("renames flexGrow to grow", () => {
|
|
19
|
+
const input = `
|
|
20
|
+
import { StackView } from "@planningcenter/tapestry-react"
|
|
21
|
+
export default function Test() {
|
|
22
|
+
return <StackView flexGrow={1}>Test</StackView>
|
|
23
|
+
}
|
|
24
|
+
`.trim()
|
|
25
|
+
|
|
26
|
+
const result = applyTransform(input)
|
|
27
|
+
expect(result).toContain("grow={1}")
|
|
28
|
+
expect(result).not.toContain("flexGrow")
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
it("renames flexShrink to shrink", () => {
|
|
32
|
+
const input = `
|
|
33
|
+
import { StackView } from "@planningcenter/tapestry-react"
|
|
34
|
+
export default function Test() {
|
|
35
|
+
return <StackView flexShrink={0}>Test</StackView>
|
|
36
|
+
}
|
|
37
|
+
`.trim()
|
|
38
|
+
|
|
39
|
+
const result = applyTransform(input)
|
|
40
|
+
expect(result).toContain("shrink={0}")
|
|
41
|
+
expect(result).not.toContain("flexShrink")
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
it("renames flexBasis to basis", () => {
|
|
45
|
+
const input = `
|
|
46
|
+
import { StackView } from "@planningcenter/tapestry-react"
|
|
47
|
+
export default function Test() {
|
|
48
|
+
return <StackView flexBasis="0%">Test</StackView>
|
|
49
|
+
}
|
|
50
|
+
`.trim()
|
|
51
|
+
|
|
52
|
+
const result = applyTransform(input)
|
|
53
|
+
expect(result).toContain('basis="0%"')
|
|
54
|
+
expect(result).not.toContain("flexBasis")
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
it("handles all three together", () => {
|
|
58
|
+
const input = `
|
|
59
|
+
import { StackView } from "@planningcenter/tapestry-react"
|
|
60
|
+
export default function Test() {
|
|
61
|
+
return <StackView flexGrow={1} flexShrink={0} flexBasis="auto">Test</StackView>
|
|
62
|
+
}
|
|
63
|
+
`.trim()
|
|
64
|
+
|
|
65
|
+
const result = applyTransform(input)
|
|
66
|
+
expect(result).toContain("grow={1}")
|
|
67
|
+
expect(result).toContain("shrink={0}")
|
|
68
|
+
expect(result).toContain('basis="auto"')
|
|
69
|
+
expect(result).not.toContain("flexGrow")
|
|
70
|
+
expect(result).not.toContain("flexShrink")
|
|
71
|
+
expect(result).not.toContain("flexBasis")
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
it("renames flexDirection to direction", () => {
|
|
75
|
+
const input = `
|
|
76
|
+
import { StackView } from "@planningcenter/tapestry-react"
|
|
77
|
+
export default function Test() {
|
|
78
|
+
return <StackView flexDirection="row">Test</StackView>
|
|
79
|
+
}
|
|
80
|
+
`.trim()
|
|
81
|
+
|
|
82
|
+
const result = applyTransform(input)
|
|
83
|
+
expect(result).toContain('direction="row"')
|
|
84
|
+
expect(result).not.toContain("flexDirection")
|
|
85
|
+
expect(result).not.toContain("TODO")
|
|
86
|
+
})
|
|
87
|
+
|
|
88
|
+
it("renames flexWrap to wrap", () => {
|
|
89
|
+
const input = `
|
|
90
|
+
import { StackView } from "@planningcenter/tapestry-react"
|
|
91
|
+
export default function Test() {
|
|
92
|
+
return <StackView flexWrap="wrap">Test</StackView>
|
|
93
|
+
}
|
|
94
|
+
`.trim()
|
|
95
|
+
|
|
96
|
+
const result = applyTransform(input)
|
|
97
|
+
expect(result).toContain('wrap="wrap"')
|
|
98
|
+
expect(result).not.toContain("flexWrap")
|
|
99
|
+
expect(result).not.toContain("TODO")
|
|
100
|
+
})
|
|
101
|
+
|
|
102
|
+
it("migrates justifyContent to justify with value normalization", () => {
|
|
103
|
+
const input = `
|
|
104
|
+
import { StackView } from "@planningcenter/tapestry-react"
|
|
105
|
+
export default function Test() {
|
|
106
|
+
return <StackView justifyContent="flex-start">Test</StackView>
|
|
107
|
+
}
|
|
108
|
+
`.trim()
|
|
109
|
+
|
|
110
|
+
const result = applyTransform(input)
|
|
111
|
+
expect(result).toContain('justify="start"')
|
|
112
|
+
expect(result).not.toContain("justifyContent")
|
|
113
|
+
expect(result).not.toContain("TODO")
|
|
114
|
+
})
|
|
115
|
+
|
|
116
|
+
it("migrates justifyContent center without normalization", () => {
|
|
117
|
+
const input = `
|
|
118
|
+
import { StackView } from "@planningcenter/tapestry-react"
|
|
119
|
+
export default function Test() {
|
|
120
|
+
return <StackView justifyContent="center">Test</StackView>
|
|
121
|
+
}
|
|
122
|
+
`.trim()
|
|
123
|
+
|
|
124
|
+
const result = applyTransform(input)
|
|
125
|
+
expect(result).toContain('justify="center"')
|
|
126
|
+
expect(result).not.toContain("TODO")
|
|
127
|
+
})
|
|
128
|
+
|
|
129
|
+
it("adds a TODO for an unmappable justifyContent value", () => {
|
|
130
|
+
const input = `
|
|
131
|
+
import { StackView } from "@planningcenter/tapestry-react"
|
|
132
|
+
export default function Test() {
|
|
133
|
+
return <StackView justifyContent="stretch">Test</StackView>
|
|
134
|
+
}
|
|
135
|
+
`.trim()
|
|
136
|
+
|
|
137
|
+
const result = applyTransform(input)
|
|
138
|
+
expect(result).toContain("TODO")
|
|
139
|
+
expect(result).toContain("justifyContent")
|
|
140
|
+
})
|
|
141
|
+
|
|
142
|
+
it("adds a TODO for a dynamic justifyContent value", () => {
|
|
143
|
+
const input = `
|
|
144
|
+
import { StackView } from "@planningcenter/tapestry-react"
|
|
145
|
+
export default function Test() {
|
|
146
|
+
return <StackView justifyContent={myVar}>Test</StackView>
|
|
147
|
+
}
|
|
148
|
+
`.trim()
|
|
149
|
+
|
|
150
|
+
const result = applyTransform(input)
|
|
151
|
+
expect(result).toContain("TODO")
|
|
152
|
+
})
|
|
153
|
+
|
|
154
|
+
it("migrates alignItems to align with value normalization", () => {
|
|
155
|
+
const input = `
|
|
156
|
+
import { StackView } from "@planningcenter/tapestry-react"
|
|
157
|
+
export default function Test() {
|
|
158
|
+
return <StackView alignItems="flex-end">Test</StackView>
|
|
159
|
+
}
|
|
160
|
+
`.trim()
|
|
161
|
+
|
|
162
|
+
const result = applyTransform(input)
|
|
163
|
+
expect(result).toContain('align="end"')
|
|
164
|
+
expect(result).not.toContain("alignItems")
|
|
165
|
+
expect(result).not.toContain("TODO")
|
|
166
|
+
})
|
|
167
|
+
|
|
168
|
+
it("adds a TODO for an unmappable alignItems value", () => {
|
|
169
|
+
const input = `
|
|
170
|
+
import { StackView } from "@planningcenter/tapestry-react"
|
|
171
|
+
export default function Test() {
|
|
172
|
+
return <StackView alignItems="space-between">Test</StackView>
|
|
173
|
+
}
|
|
174
|
+
`.trim()
|
|
175
|
+
|
|
176
|
+
const result = applyTransform(input)
|
|
177
|
+
expect(result).toContain("TODO")
|
|
178
|
+
expect(result).toContain("alignItems")
|
|
179
|
+
})
|
|
180
|
+
|
|
181
|
+
it("returns null when StackView has none of the CSS alias props", () => {
|
|
182
|
+
const input = `
|
|
183
|
+
import { StackView } from "@planningcenter/tapestry-react"
|
|
184
|
+
export default function Test() {
|
|
185
|
+
return <StackView gap={2}>Test</StackView>
|
|
186
|
+
}
|
|
187
|
+
`.trim()
|
|
188
|
+
|
|
189
|
+
expect(applyTransform(input)).toBe(null)
|
|
190
|
+
})
|
|
191
|
+
|
|
192
|
+
it("returns null when StackView is not imported from tapestry-react", () => {
|
|
193
|
+
const input = `
|
|
194
|
+
import { StackView } from "some-other-package"
|
|
195
|
+
export default function Test() {
|
|
196
|
+
return <StackView flexGrow={1}>Test</StackView>
|
|
197
|
+
}
|
|
198
|
+
`.trim()
|
|
199
|
+
|
|
200
|
+
expect(applyTransform(input)).toBe(null)
|
|
201
|
+
})
|
|
202
|
+
})
|