@planningcenter/tapestry-migration-cli 3.1.0-rc.8 → 3.1.0-rc.9

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.
Files changed (29) hide show
  1. package/package.json +3 -3
  2. package/src/components/input/transforms/removeTypeInput.test.ts +212 -0
  3. package/src/components/input/transforms/removeTypeInput.ts +22 -0
  4. package/src/components/shared/helpers/unsupportedPropsHelpers.ts +33 -0
  5. package/src/components/shared/transformFactories/stylePropTransformFactory.ts +2 -1
  6. package/src/components/text-area/index.ts +48 -0
  7. package/src/components/text-area/transforms/auditSpreadProps.test.ts +139 -0
  8. package/src/components/text-area/transforms/auditSpreadProps.ts +10 -0
  9. package/src/components/text-area/transforms/convertStyleProps.test.ts +158 -0
  10. package/src/components/text-area/transforms/convertStyleProps.ts +10 -0
  11. package/src/components/text-area/transforms/innerRefToRef.test.ts +206 -0
  12. package/src/components/text-area/transforms/innerRefToRef.ts +14 -0
  13. package/src/components/text-area/transforms/mergeFieldIntoTextArea.test.ts +477 -0
  14. package/src/components/text-area/transforms/mergeFieldIntoTextArea.ts +227 -0
  15. package/src/components/text-area/transforms/moveTextAreaImport.test.ts +168 -0
  16. package/src/components/text-area/transforms/moveTextAreaImport.ts +13 -0
  17. package/src/components/text-area/transforms/removeDuplicateKeys.test.ts +129 -0
  18. package/src/components/text-area/transforms/removeDuplicateKeys.ts +8 -0
  19. package/src/components/text-area/transforms/removeRedundantAriaLabel.test.ts +183 -0
  20. package/src/components/text-area/transforms/removeRedundantAriaLabel.ts +59 -0
  21. package/src/components/text-area/transforms/sizeMapping.test.ts +199 -0
  22. package/src/components/text-area/transforms/sizeMapping.ts +15 -0
  23. package/src/components/text-area/transforms/stateToInvalid.test.ts +204 -0
  24. package/src/components/text-area/transforms/stateToInvalid.ts +57 -0
  25. package/src/components/text-area/transforms/stateToInvalidTernary.test.ts +133 -0
  26. package/src/components/text-area/transforms/stateToInvalidTernary.ts +11 -0
  27. package/src/components/text-area/transforms/unsupportedProps.test.ts +275 -0
  28. package/src/components/text-area/transforms/unsupportedProps.ts +35 -0
  29. package/src/index.ts +3 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@planningcenter/tapestry-migration-cli",
3
- "version": "3.1.0-rc.8",
3
+ "version": "3.1.0-rc.9",
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.1.0-rc.8",
35
+ "@planningcenter/tapestry": "^3.1.0-rc.9",
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": "51c9b65e6a3dcf646b76eb543fc81e27bca3ae16"
55
+ "gitHead": "c3dd0518ee1bbb86ffd8796a6d9604273306a7a0"
56
56
  }
@@ -0,0 +1,212 @@
1
+ import jscodeshift from "jscodeshift"
2
+ import { describe, expect, it } from "vitest"
3
+
4
+ import transform from "./removeTypeInput"
5
+
6
+ const j = jscodeshift.withParser("tsx")
7
+
8
+ // Helper to run transform and get result
9
+ function applyTransform(source: string): string | null {
10
+ const fileInfo = { path: "test.tsx", source }
11
+ const api = {
12
+ j,
13
+ jscodeshift: j,
14
+ report: () => {},
15
+ stats: () => {},
16
+ }
17
+ const result = transform(fileInfo, api, {})
18
+ return result as string | null
19
+ }
20
+
21
+ describe("removeTypeInput transform", () => {
22
+ describe("basic transformation", () => {
23
+ it("should remove type='input' from Input", () => {
24
+ const input = `
25
+ import { Input } from "@planningcenter/tapestry-react"
26
+
27
+ function Component() {
28
+ return <Input type="input" />
29
+ }
30
+ `
31
+
32
+ const result = applyTransform(input)
33
+
34
+ expect(result).toContain("<Input />")
35
+ expect(result).not.toContain('type="input"')
36
+ })
37
+
38
+ it('should remove type="input" from Input with other props', () => {
39
+ const input = `
40
+ import { Input } from "@planningcenter/tapestry-react"
41
+
42
+ function Component() {
43
+ return <Input type="input" onChange={handleChange} />
44
+ }
45
+ `
46
+
47
+ const result = applyTransform(input)
48
+
49
+ expect(result).toContain("<Input onChange={handleChange} />")
50
+ expect(result).not.toContain('type="input"')
51
+ })
52
+
53
+ it("should preserve Input without type='input'", () => {
54
+ const input = `
55
+ import { Input } from "@planningcenter/tapestry-react"
56
+
57
+ function Component() {
58
+ return <Input onChange={handleChange} />
59
+ }
60
+ `
61
+
62
+ const result = applyTransform(input)
63
+
64
+ expect(result).toBeNull()
65
+ })
66
+
67
+ it("should preserve Input with type='email'", () => {
68
+ const input = `
69
+ import { Input } from "@planningcenter/tapestry-react"
70
+
71
+ function Component() {
72
+ return <Input type="email" />
73
+ }
74
+ `
75
+
76
+ const result = applyTransform(input)
77
+
78
+ expect(result).toBeNull()
79
+ })
80
+
81
+ it("should preserve Input with type='number'", () => {
82
+ const input = `
83
+ import { Input } from "@planningcenter/tapestry-react"
84
+
85
+ function Component() {
86
+ return <Input type="number" />
87
+ }
88
+ `
89
+
90
+ const result = applyTransform(input)
91
+
92
+ expect(result).toBeNull()
93
+ })
94
+
95
+ it("should remove type='text' from Input", () => {
96
+ const input = `
97
+ import { Input } from "@planningcenter/tapestry-react"
98
+
99
+ function Component() {
100
+ return <Input type="text" />
101
+ }
102
+ `
103
+
104
+ const result = applyTransform(input)
105
+
106
+ expect(result).toContain("<Input />")
107
+ expect(result).not.toContain('type="text"')
108
+ })
109
+
110
+ it("should remove type='text' from Input with other props", () => {
111
+ const input = `
112
+ import { Input } from "@planningcenter/tapestry-react"
113
+
114
+ function Component() {
115
+ return <Input type="text" value={searchTerm} placeholder="Search" onChange={handleChange} />
116
+ }
117
+ `
118
+
119
+ const result = applyTransform(input)
120
+
121
+ expect(result).not.toContain('type="text"')
122
+ expect(result).toContain("value={searchTerm}")
123
+ expect(result).toContain('placeholder="Search"')
124
+ expect(result).toContain("onChange={handleChange}")
125
+ })
126
+ })
127
+
128
+ describe("multiple inputs", () => {
129
+ it("should handle mixed Input usage", () => {
130
+ const input = `
131
+ import { Input } from "@planningcenter/tapestry-react"
132
+
133
+ function Component() {
134
+ return (
135
+ <div>
136
+ <Input type="input" />
137
+ <Input type="text" />
138
+ <Input type="email" />
139
+ <Input type="input" onChange={handleChange} />
140
+ </div>
141
+ )
142
+ }
143
+ `
144
+
145
+ const result = applyTransform(input)
146
+
147
+ expect(result).toContain('<Input type="email" />')
148
+ expect(result).toContain("<Input onChange={handleChange} />")
149
+ expect(result).not.toContain('type="input"')
150
+ expect(result).not.toContain('type="text"')
151
+ })
152
+ })
153
+
154
+ describe("edge cases", () => {
155
+ it("should not affect HTML input elements", () => {
156
+ const input = `
157
+ import { Input } from "@planningcenter/tapestry-react"
158
+
159
+ function Component() {
160
+ return (
161
+ <div>
162
+ <Input type="input" />
163
+ <input type="input" />
164
+ </div>
165
+ )
166
+ }
167
+ `
168
+
169
+ const result = applyTransform(input)
170
+
171
+ expect(result).toContain("<Input />")
172
+ expect(result).toContain('<input type="input" />')
173
+ })
174
+
175
+ it("should handle expression syntax type={'input'}", () => {
176
+ const input = `
177
+ import { Input } from "@planningcenter/tapestry-react"
178
+
179
+ function Component() {
180
+ return <Input type={"input"} />
181
+ }
182
+ `
183
+
184
+ const result = applyTransform(input)
185
+
186
+ if (result) {
187
+ expect(result).toContain("<Input />")
188
+ expect(result).not.toContain('type={"input"}')
189
+ } else {
190
+ expect(input).toContain('type={"input"}')
191
+ }
192
+ })
193
+ })
194
+
195
+ describe("import handling", () => {
196
+ it("should not affect imports", () => {
197
+ const input = `
198
+ import { Input } from "@planningcenter/tapestry-react"
199
+
200
+ function Component() {
201
+ return <Input type="input" />
202
+ }
203
+ `
204
+
205
+ const result = applyTransform(input)
206
+
207
+ expect(result).toContain(
208
+ 'import { Input } from "@planningcenter/tapestry-react"'
209
+ )
210
+ })
211
+ })
212
+ })
@@ -0,0 +1,22 @@
1
+ import { Transform } from "jscodeshift"
2
+
3
+ import { removeAttribute } from "../../shared/actions/removeAttribute"
4
+ import { hasAttributeValue } from "../../shared/conditions/hasAttributeValue"
5
+ import { orConditions } from "../../shared/conditions/orConditions"
6
+ import { attributeTransformFactory } from "../../shared/transformFactories/attributeTransformFactory"
7
+ import { transformableInput } from "../transformableInput"
8
+
9
+ const transform: Transform = attributeTransformFactory({
10
+ condition: (element, context) =>
11
+ transformableInput(element, context) &&
12
+ orConditions(
13
+ hasAttributeValue("type", "input"),
14
+ hasAttributeValue("type", "text")
15
+ )(element, context),
16
+ targetComponent: "Input",
17
+ targetPackage: "@planningcenter/tapestry-react",
18
+ transform: (element, { j, source }) =>
19
+ removeAttribute("type", { element, j, source }),
20
+ })
21
+
22
+ export default transform
@@ -101,3 +101,36 @@ export const INPUT_SUPPORTED_PROPS = [
101
101
  ...INPUT_SPECIFIC_PROPS,
102
102
  ...STYLE_PROP_NAMES_WITHOUT_CSS,
103
103
  ]
104
+
105
+ export const TEXTAREA_SPECIFIC_PROPS = [
106
+ "autoComplete",
107
+ "autoFocus",
108
+ "cols",
109
+ "defaultValue",
110
+ "description",
111
+ "disabled",
112
+ "dirname",
113
+ "form",
114
+ "hideLabel",
115
+ "invalid",
116
+ "maxLength",
117
+ "minLength",
118
+ "name",
119
+ "onChange",
120
+ "onInput",
121
+ "onSelect",
122
+ "placeholder",
123
+ "readOnly",
124
+ "required",
125
+ "resize",
126
+ "rows",
127
+ "spellCheck",
128
+ "value",
129
+ "wrap",
130
+ ]
131
+
132
+ export const TEXTAREA_SUPPORTED_PROPS = [
133
+ ...COMMON_PROPS,
134
+ ...TEXTAREA_SPECIFIC_PROPS,
135
+ ...STYLE_PROP_NAMES_WITHOUT_CSS,
136
+ ]
@@ -167,6 +167,7 @@ function applyStylesToComponent({
167
167
  }: {
168
168
  element: JSXElement
169
169
  j: JSCodeshift
170
+ source: Collection
170
171
  styles: Record<string, unknown>
171
172
  }) {
172
173
  const styleAttr = getAttribute({ element, name: "style" })
@@ -360,7 +361,7 @@ export function stylePropTransformFactory(config: {
360
361
  if (options.verbose) console.log("Final generated styles:", styles)
361
362
 
362
363
  if (Object.keys(styles).length > 0) {
363
- applyStylesToComponent({ element, j, styles })
364
+ applyStylesToComponent({ element, j, source, styles })
364
365
 
365
366
  if (options.verbose) {
366
367
  const styleAttr = getAttribute({ element, name: "style" })
@@ -0,0 +1,48 @@
1
+ import { Transform } from "jscodeshift"
2
+
3
+ import auditSpreadProps from "./transforms/auditSpreadProps"
4
+ import convertStyleProps from "./transforms/convertStyleProps"
5
+ import innerRefToRef from "./transforms/innerRefToRef"
6
+ import mergeFieldIntoTextArea from "./transforms/mergeFieldIntoTextArea"
7
+ import moveTextAreaImport from "./transforms/moveTextAreaImport"
8
+ import removeDuplicateKeys from "./transforms/removeDuplicateKeys"
9
+ import removeRedundantAriaLabel from "./transforms/removeRedundantAriaLabel"
10
+ import sizeMapping from "./transforms/sizeMapping"
11
+ import stateToInvalid from "./transforms/stateToInvalid"
12
+ import stateToInvalidTernary from "./transforms/stateToInvalidTernary"
13
+ import unsupportedProps from "./transforms/unsupportedProps"
14
+
15
+ const transform: Transform = (fileInfo, api, options) => {
16
+ let currentSource = fileInfo.source
17
+ let hasAnyChanges = false
18
+
19
+ const transforms = [
20
+ mergeFieldIntoTextArea,
21
+ auditSpreadProps,
22
+ innerRefToRef,
23
+ stateToInvalidTernary,
24
+ stateToInvalid,
25
+ sizeMapping,
26
+ convertStyleProps,
27
+ removeDuplicateKeys,
28
+ removeRedundantAriaLabel,
29
+ unsupportedProps,
30
+ moveTextAreaImport,
31
+ ]
32
+
33
+ for (const individualTransform of transforms) {
34
+ const result = individualTransform(
35
+ { ...fileInfo, source: currentSource },
36
+ api,
37
+ options
38
+ )
39
+ if (result && result !== currentSource) {
40
+ currentSource = result as string
41
+ hasAnyChanges = true
42
+ }
43
+ }
44
+
45
+ return hasAnyChanges ? currentSource : null
46
+ }
47
+
48
+ export default transform
@@ -0,0 +1,139 @@
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 TextArea with single spread prop", () => {
23
+ const input = `
24
+ import { TextArea } from "@planningcenter/tapestry-react"
25
+
26
+ export default function Test() {
27
+ const props = { onChange: handleChange }
28
+ return <TextArea {...props} label="Notes" />
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 TextArea with multiple spread props", () => {
38
+ const input = `
39
+ import { TextArea } from "@planningcenter/tapestry-react"
40
+
41
+ export default function Test() {
42
+ const baseProps = { onChange: handleChange }
43
+ const styleProps = { className: "textarea" }
44
+ return <TextArea {...baseProps} {...styleProps} label="Notes" />
45
+ }
46
+ `.trim()
47
+
48
+ const result = applyTransform(input)
49
+ expect(result).toContain(AUDIT_COMMENT)
50
+ expect(result).toContain("{...baseProps}")
51
+ expect(result).toContain("{...styleProps}")
52
+ })
53
+
54
+ it("should handle multiple TextArea components with spread props", () => {
55
+ const input = `
56
+ import { TextArea } from "@planningcenter/tapestry-react"
57
+
58
+ export default function Test() {
59
+ const props1 = { onChange: handleChange1 }
60
+ const props2 = { onChange: handleChange2 }
61
+ return (
62
+ <div>
63
+ <TextArea {...props1} label="Notes" />
64
+ <TextArea {...props2} label="Comments" />
65
+ </div>
66
+ )
67
+ }
68
+ `.trim()
69
+
70
+ const result = applyTransform(input)
71
+ expect(result).toContain(AUDIT_COMMENT)
72
+ expect(result).toContain("{...props1}")
73
+ expect(result).toContain("{...props2}")
74
+ })
75
+ })
76
+
77
+ describe("edge cases", () => {
78
+ it("should not transform TextArea without spread props", () => {
79
+ const input = `
80
+ import { TextArea } from "@planningcenter/tapestry-react"
81
+
82
+ export default function Test() {
83
+ return <TextArea onChange={handleChange} label="Notes" />
84
+ }
85
+ `.trim()
86
+
87
+ const result = applyTransform(input)
88
+ expect(result).toBe(null)
89
+ })
90
+
91
+ it("should not transform if TextArea is not imported from @planningcenter/tapestry-react", () => {
92
+ const input = `
93
+ import { TextArea } from "other-library"
94
+
95
+ export default function Test() {
96
+ const props = { onChange: handleChange }
97
+ return <TextArea {...props} label="Notes" />
98
+ }
99
+ `.trim()
100
+
101
+ const result = applyTransform(input)
102
+ expect(result).toBe(null)
103
+ })
104
+
105
+ it("should handle TextArea with alias import", () => {
106
+ const input = `
107
+ import { TextArea as MyTextArea } from "@planningcenter/tapestry-react"
108
+
109
+ export default function Test() {
110
+ const props = { onChange: handleChange }
111
+ return <MyTextArea {...props} label="Notes" />
112
+ }
113
+ `.trim()
114
+
115
+ const result = applyTransform(input)
116
+ expect(result).toContain(AUDIT_COMMENT)
117
+ expect(result).toContain("{...props}")
118
+ })
119
+
120
+ it("should return null when no TextArea imports exist", () => {
121
+ const input = `
122
+ import { Button } from "@planningcenter/tapestry-react"
123
+
124
+ export default function Test() {
125
+ const props = { onClick: handleClick }
126
+ return <Button {...props}>Save</Button>
127
+ }
128
+ `.trim()
129
+
130
+ const result = applyTransform(input)
131
+ expect(result).toBe(null)
132
+ })
133
+
134
+ it("should return null for empty file", () => {
135
+ const result = applyTransform("")
136
+ expect(result).toBe(null)
137
+ })
138
+ })
139
+ })
@@ -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: "TextArea",
7
+ targetPackage: "@planningcenter/tapestry-react",
8
+ })
9
+
10
+ export default transform
@@ -0,0 +1,158 @@
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, options = {}) {
9
+ const fileInfo = { path: "test.tsx", source }
10
+ const result = transform(
11
+ fileInfo,
12
+ { j, jscodeshift: j, report: () => {}, stats: () => {} },
13
+ options
14
+ ) as string | null
15
+ return result || source
16
+ }
17
+
18
+ describe("convertStyleProps transform", () => {
19
+ describe("visible prop - handled by theme system", () => {
20
+ it("should convert visible={false} to display: none", () => {
21
+ const source = `
22
+ import { TextArea } from "@planningcenter/tapestry-react"
23
+
24
+ export function TestComponent() {
25
+ return <TextArea visible={false} label="Hidden TextArea" />
26
+ }
27
+ `
28
+
29
+ const result = applyTransform(source)
30
+
31
+ expect(result).toContain("style={{")
32
+ expect(result).toContain('display: "none"')
33
+ expect(result).not.toContain("visible={false}")
34
+ })
35
+
36
+ it("should remove visible={true} with no style changes (true is default)", () => {
37
+ const source = `
38
+ import { TextArea } from "@planningcenter/tapestry-react"
39
+
40
+ export function TestComponent() {
41
+ return <TextArea visible={true} label="Visible TextArea" />
42
+ }
43
+ `
44
+
45
+ const result = applyTransform(source)
46
+
47
+ expect(result).not.toContain("visible={true}")
48
+ expect(result).not.toContain("style={{")
49
+ expect(result).toContain('<TextArea label="Visible TextArea" />')
50
+ })
51
+
52
+ it("should handle visible expressions", () => {
53
+ const source = `
54
+ import { TextArea } from "@planningcenter/tapestry-react"
55
+
56
+ export function TestComponent() {
57
+ const isVisible = true
58
+ return <TextArea visible={isVisible} label="Variable TextArea" />
59
+ }
60
+ `
61
+
62
+ const result = applyTransform(source)
63
+
64
+ expect(result).toContain("visible: isVisible")
65
+ expect(result).toContain("style={{")
66
+ })
67
+ })
68
+
69
+ describe("style prop removal", () => {
70
+ it("should remove alignItems prop", () => {
71
+ const source = `
72
+ import { TextArea } from "@planningcenter/tapestry-react"
73
+
74
+ export function TestComponent() {
75
+ return <TextArea alignItems="center" label="Test" />
76
+ }
77
+ `
78
+
79
+ const result = applyTransform(source)
80
+
81
+ expect(result).not.toContain("alignItems=")
82
+ })
83
+
84
+ it("should remove marginTop prop", () => {
85
+ const source = `
86
+ import { TextArea } from "@planningcenter/tapestry-react"
87
+
88
+ export function TestComponent() {
89
+ return <TextArea marginTop={16} label="Test" />
90
+ }
91
+ `
92
+
93
+ const result = applyTransform(source)
94
+
95
+ expect(result).not.toContain("marginTop=")
96
+ })
97
+
98
+ it("should remove multiple style props", () => {
99
+ const source = `
100
+ import { TextArea } from "@planningcenter/tapestry-react"
101
+
102
+ export function TestComponent() {
103
+ return <TextArea alignItems="center" marginTop={16} label="Test" />
104
+ }
105
+ `
106
+
107
+ const result = applyTransform(source)
108
+
109
+ expect(result).not.toContain("alignItems=")
110
+ expect(result).not.toContain("marginTop=")
111
+ })
112
+ })
113
+
114
+ describe("combination of style props", () => {
115
+ it("should handle combination of visible and style props", () => {
116
+ const source = `
117
+ import { TextArea } from "@planningcenter/tapestry-react"
118
+
119
+ export function TestComponent() {
120
+ return (
121
+ <TextArea
122
+ visible={false}
123
+ alignItems="center"
124
+ marginTop={16}
125
+ label="Combined TextArea"
126
+ />
127
+ )
128
+ }
129
+ `
130
+
131
+ const result = applyTransform(source)
132
+
133
+ expect(result).toContain("style={{")
134
+ expect(result).toContain('display: "none"')
135
+ expect(result).not.toContain("visible={false}")
136
+ expect(result).not.toContain("alignItems=")
137
+ expect(result).not.toContain("marginTop=")
138
+ })
139
+ })
140
+
141
+ describe("import handling", () => {
142
+ it("should not affect imports", () => {
143
+ const source = `
144
+ import { TextArea } from "@planningcenter/tapestry-react"
145
+
146
+ export function TestComponent() {
147
+ return <TextArea visible={false} label="Test" />
148
+ }
149
+ `
150
+
151
+ const result = applyTransform(source)
152
+
153
+ expect(result).toContain(
154
+ 'import { TextArea } from "@planningcenter/tapestry-react"'
155
+ )
156
+ })
157
+ })
158
+ })
@@ -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: "TextArea",
9
+ targetPackage: "@planningcenter/tapestry-react",
10
+ })