Skip to content

Commit 0cc04ec

Browse files
committed
Add relative option for migration
1 parent a8d80cf commit 0cc04ec

File tree

9 files changed

+288
-32
lines changed

9 files changed

+288
-32
lines changed

.changeset/old-mayflies-clean.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@shopify/polaris-migrator': minor
3+
---
4+
5+
Add relative option for replace-text-component migration
Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,32 @@
1-
import type {API, FileInfo} from 'jscodeshift';
1+
import type {API, FileInfo, Options} from 'jscodeshift';
22

33
import {hasImportDeclaration} from '../../utilities/imports';
44

55
import {replaceDisplayText} from './steps/replace-display-text';
66
import {replaceOther} from './steps/replace-other';
77
import {replaceTextStyle} from './steps/replace-text-style';
88

9+
export interface MigrationOptions extends Options {
10+
relative: string;
11+
}
12+
913
export default function replaceTextComponent(
1014
file: FileInfo,
1115
{jscodeshift: j}: API,
16+
options: MigrationOptions,
1217
) {
1318
const source = j(file.source);
1419

15-
if (!hasImportDeclaration(j, source, '@shopify/polaris')) {
20+
if (
21+
!options.relative &&
22+
!hasImportDeclaration(j, source, '@shopify/polaris')
23+
) {
1624
return file.source;
1725
}
1826

19-
replaceDisplayText(j, source);
20-
replaceOther(j, source);
21-
replaceTextStyle(j, source);
27+
replaceDisplayText(j, source, options);
28+
replaceOther(j, source, options);
29+
replaceTextStyle(j, source, options);
2230

2331
return source.toSource();
2432
}

polaris-migrator/src/migrations/replace-text-component/steps/replace-display-text.ts

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,11 @@ import {
1111
getImportSpecifierName,
1212
hasImportSpecifier,
1313
removeImportSpecifier,
14+
getImportSourcePaths,
15+
renameImportDeclaration,
16+
removeImportDeclaration,
1417
} from '../../../utilities/imports';
18+
import type {MigrationOptions} from '../replace-text-component';
1519

1620
const displayTextSizeMap = {
1721
small: 'headingXl',
@@ -26,17 +30,33 @@ const displayTextSizeMap = {
2630
export function replaceDisplayText<NodeType = ASTNode>(
2731
j: JSCodeshift,
2832
source: Collection<NodeType>,
33+
options: MigrationOptions,
2934
) {
30-
if (hasImportSpecifier(j, source, 'Text', '@shopify/polaris')) {
31-
removeImportSpecifier(j, source, 'DisplayText', '@shopify/polaris');
32-
} else {
33-
renameImportSpecifier(j, source, 'DisplayText', 'Text', '@shopify/polaris');
34-
}
35+
const sourcePaths = getImportSourcePaths(j, source, {
36+
relative: Boolean(options.relative),
37+
currentFileName: 'DisplayText',
38+
nextFileName: 'Text',
39+
});
40+
41+
if (!sourcePaths) return;
3542

3643
const localElementName =
37-
getImportSpecifierName(j, source, 'DisplayText', '@shopify/polaris') ||
44+
getImportSpecifierName(j, source, 'DisplayText', sourcePaths.current) ||
3845
'DisplayText';
3946

47+
if (hasImportSpecifier(j, source, 'Text', sourcePaths.next)) {
48+
if (options.relative) {
49+
removeImportDeclaration(j, source, sourcePaths.current);
50+
} else {
51+
removeImportSpecifier(j, source, 'DisplayText', sourcePaths.current);
52+
}
53+
} else {
54+
if (options.relative) {
55+
renameImportDeclaration(j, source, sourcePaths.current, sourcePaths.next);
56+
}
57+
renameImportSpecifier(j, source, 'DisplayText', 'Text', sourcePaths.next);
58+
}
59+
4060
source.findJSXElements(localElementName).forEach((element) => {
4161
replaceJSXElement(j, element, 'Text');
4262
replaceJSXAttributes(j, element, 'size', 'variant', displayTextSizeMap);

polaris-migrator/src/migrations/replace-text-component/steps/replace-other.ts

Lines changed: 33 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,11 @@ import {
1111
getImportSpecifierName,
1212
hasImportSpecifier,
1313
removeImportSpecifier,
14+
getImportSourcePaths,
15+
removeImportDeclaration,
16+
renameImportDeclaration,
1417
} from '../../../utilities/imports';
18+
import type {MigrationOptions} from '../replace-text-component';
1519

1620
const components = {
1721
Heading: {
@@ -38,24 +42,41 @@ const components = {
3842
export function replaceOther<NodeType = ASTNode>(
3943
j: JSCodeshift,
4044
source: Collection<NodeType>,
45+
options: MigrationOptions,
4146
) {
47+
const relative = Boolean(options.relative);
48+
4249
Object.entries(components).forEach(([componentName, {variant, as}]) => {
43-
if (hasImportSpecifier(j, source, 'Text', '@shopify/polaris')) {
44-
removeImportSpecifier(j, source, componentName, '@shopify/polaris');
45-
} else {
46-
renameImportSpecifier(
47-
j,
48-
source,
49-
componentName,
50-
'Text',
51-
'@shopify/polaris',
52-
);
53-
}
50+
const sourcePaths = getImportSourcePaths(j, source, {
51+
relative,
52+
currentFileName: componentName,
53+
nextFileName: 'Text',
54+
});
55+
56+
if (!sourcePaths) return;
5457

5558
const localElementName =
56-
getImportSpecifierName(j, source, componentName, '@shopify/polaris') ||
59+
getImportSpecifierName(j, source, componentName, sourcePaths.current) ||
5760
componentName;
5861

62+
if (hasImportSpecifier(j, source, 'Text', sourcePaths.next)) {
63+
if (options.relative) {
64+
removeImportDeclaration(j, source, sourcePaths.current);
65+
} else {
66+
removeImportSpecifier(j, source, componentName, sourcePaths.current);
67+
}
68+
} else {
69+
if (options.relative) {
70+
renameImportDeclaration(
71+
j,
72+
source,
73+
sourcePaths.current,
74+
sourcePaths.next,
75+
);
76+
}
77+
renameImportSpecifier(j, source, componentName, 'Text', sourcePaths.next);
78+
}
79+
5980
source.findJSXElements(localElementName).forEach((element) => {
6081
replaceJSXElement(j, element, 'Text');
6182
insertJSXAttribute(j, element, 'variant', variant);

polaris-migrator/src/migrations/replace-text-component/steps/replace-text-style.ts

Lines changed: 48 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,12 @@ import {
1414
getImportSpecifierName,
1515
hasImportSpecifier,
1616
removeImportSpecifier,
17+
getImportSourcePaths,
18+
renameImportDeclaration,
19+
removeImportDeclaration,
20+
insertImportDeclaration,
1721
} from '../../../utilities/imports';
22+
import type {MigrationOptions} from '../replace-text-component';
1823

1924
const variationMap = {
2025
strong: {fontWeight: 'bold'},
@@ -31,17 +36,33 @@ const variationMap = {
3136
export function replaceTextStyle<NodeType = ASTNode>(
3237
j: JSCodeshift,
3338
source: Collection<NodeType>,
39+
options: MigrationOptions,
3440
) {
35-
if (hasImportSpecifier(j, source, 'Text', '@shopify/polaris')) {
36-
removeImportSpecifier(j, source, 'TextStyle', '@shopify/polaris');
37-
} else {
38-
renameImportSpecifier(j, source, 'TextStyle', 'Text', '@shopify/polaris');
39-
}
41+
const sourcePaths = getImportSourcePaths(j, source, {
42+
relative: Boolean(options.relative),
43+
currentFileName: 'TextStyle',
44+
nextFileName: 'Text',
45+
});
46+
47+
if (!sourcePaths) return;
4048

4149
const localElementName =
42-
getImportSpecifierName(j, source, 'TextStyle', '@shopify/polaris') ||
50+
getImportSpecifierName(j, source, 'TextStyle', sourcePaths.current) ||
4351
'TextStyle';
4452

53+
if (hasImportSpecifier(j, source, 'Text', sourcePaths.next)) {
54+
if (options.relative) {
55+
removeImportDeclaration(j, source, sourcePaths.current);
56+
} else {
57+
removeImportSpecifier(j, source, 'TextStyle', sourcePaths.current);
58+
}
59+
} else {
60+
if (options.relative) {
61+
renameImportDeclaration(j, source, sourcePaths.current, sourcePaths.next);
62+
}
63+
renameImportSpecifier(j, source, 'TextStyle', 'Text', sourcePaths.current);
64+
}
65+
4566
source.findJSXElements(localElementName).forEach((element) => {
4667
replaceJSXElement(j, element, 'Text');
4768
insertJSXAttribute(j, element, 'variant', 'bodyMd');
@@ -50,10 +71,29 @@ export function replaceTextStyle<NodeType = ASTNode>(
5071
.forEach((literal) => {
5172
const currentValue = literal.node.value as keyof typeof variationMap;
5273
if (currentValue === 'code') {
74+
const inlineTextSourcePath = options.relative
75+
? sourcePaths.current.replace('TextStyle', 'InlineCode')
76+
: '@shopify/polaris';
77+
5378
if (
54-
!hasImportSpecifier(j, source, 'InlineCode', '@shopify/polaris')
79+
!hasImportSpecifier(j, source, 'InlineCode', inlineTextSourcePath)
5580
) {
56-
insertImportSpecifier(j, source, 'InlineCode', '@shopify/polaris');
81+
if (options.relative) {
82+
insertImportDeclaration(
83+
j,
84+
source,
85+
'InlineCode',
86+
inlineTextSourcePath,
87+
sourcePaths.next,
88+
);
89+
} else {
90+
insertImportSpecifier(
91+
j,
92+
source,
93+
'InlineCode',
94+
inlineTextSourcePath,
95+
);
96+
}
5797
}
5898

5999
const InlineCode = j.jsxElement(
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// @ts-nocheck
2+
import React from 'react';
3+
4+
import {DisplayText} from '../DisplayText';
5+
import {Heading} from '../Heading';
6+
import {Subheading} from '../Subheading';
7+
import {Caption} from '../Caption';
8+
import {TextStyle} from '../TextStyle';
9+
import {VisuallyHidden} from '../VisuallyHidden';
10+
11+
export function App() {
12+
return (
13+
<>
14+
<DisplayText size="extraLarge">Display text</DisplayText>
15+
<DisplayText size="large">Display text</DisplayText>
16+
<DisplayText size="medium">Display text</DisplayText>
17+
<DisplayText size="small">Display text</DisplayText>
18+
<Heading element="h1">Heading</Heading>
19+
<Heading>Heading</Heading>
20+
<Subheading element="h2">Subheading</Subheading>
21+
<Subheading>Subheading</Subheading>
22+
<Caption>Caption</Caption>
23+
<TextStyle variation="strong">Strong</TextStyle>
24+
<TextStyle variation="positive">Positive</TextStyle>
25+
<TextStyle variation="negative">Negative</TextStyle>
26+
<TextStyle variation="warning">Warning</TextStyle>
27+
<TextStyle variation="code">Code</TextStyle>
28+
<VisuallyHidden>Hidden text</VisuallyHidden>
29+
</>
30+
);
31+
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
// @ts-nocheck
2+
import React from 'react';
3+
4+
import {Text} from '../Text';
5+
import {InlineCode} from '../InlineCode';
6+
7+
export function App() {
8+
return (
9+
<>
10+
<Text variant="heading4xl" as="p">
11+
Display text
12+
</Text>
13+
<Text variant="heading3xl" as="p">
14+
Display text
15+
</Text>
16+
<Text variant="heading2xl" as="p">
17+
Display text
18+
</Text>
19+
<Text variant="headingXl" as="p">
20+
Display text
21+
</Text>
22+
<Text as="h1" variant="headingLg">
23+
Heading
24+
</Text>
25+
<Text variant="headingLg" as="h2">
26+
Heading
27+
</Text>
28+
<Text as="h2" variant="headingSm">
29+
Subheading
30+
</Text>
31+
<Text variant="headingSm" as="h3">
32+
Subheading
33+
</Text>
34+
<Text variant="bodySm" as="p">
35+
Caption
36+
</Text>
37+
<Text variant="bodyMd" fontWeight="bold" as="span">
38+
Strong
39+
</Text>
40+
<Text variant="bodyMd" color="success" as="span">
41+
Positive
42+
</Text>
43+
<Text variant="bodyMd" color="critical" as="span">
44+
Negative
45+
</Text>
46+
<Text variant="bodyMd" color="warning" as="span">
47+
Warning
48+
</Text>
49+
<Text variant="bodyMd" as="span">
50+
<InlineCode>Code</InlineCode>
51+
</Text>
52+
<Text variant="bodySm" as="span" visuallyHidden>
53+
Hidden text
54+
</Text>
55+
</>
56+
);
57+
}
Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
import {check} from '../../../utilities/testUtils';
22

33
const migration = 'replace-text-component';
4-
const fixtures = ['replace-components'];
4+
const fixtures = ['replace-components-relative'];
55

66
for (const fixture of fixtures) {
77
check(__dirname, {
88
fixture,
99
migration,
10+
options: {
11+
relative: fixture.includes('relative') ? true : undefined,
12+
},
1013
});
1114
}

0 commit comments

Comments
 (0)