Skip to content

Commit

Permalink
feat: add icon codemods (adobe#6958)
Browse files Browse the repository at this point in the history
  • Loading branch information
reidbarber committed Aug 29, 2024
1 parent 82e10d3 commit 32f8b8d
Show file tree
Hide file tree
Showing 4 changed files with 1,301 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,50 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`Does not affect existing S2 icons 1`] = `
"import Add from '@react-spectrum/s2/icons/Add';
<Add />;"
`;

exports[`Leave comment if no matching S2 icon found 1`] = `
"import AssetCheck from '@spectrum-icons/workflow/AssetCheck';
// TODO(S2-upgrade): A Spectrum 2 equivalent to 'AssetCheck' was not found. Please update this icon manually.
<AssetCheck />;"
`;

exports[`Migrate S1 icon with different name to S2 1`] = `
"import AlertTriangle from "@react-spectrum/s2/icons/AlertTriangle";
<AlertTriangle />;"
`;

exports[`Migrate S1 icon with different name to S2. Keep name if already taken in scope. 1`] = `
"import Alert from "@react-spectrum/s2/icons/AlertTriangle";
import AlertTriangle from 'elsewhere';
<div>
<Alert />
<AlertTriangle />
</div>"
`;

exports[`Migrate S1 icon with same name to S2 1`] = `
"import Add from "@react-spectrum/s2/icons/Add";
<Add />;"
`;

exports[`Migrate custom-named S1 icon to S2. Keep name as custom name. 1`] = `
"import AlertIcon from "@react-spectrum/s2/icons/AlertTriangle";
import Alert from 'elsewhere';
<div>
<AlertIcon />
<Alert />
</div>"
`;

exports[`Remove Icon and tells people to use compiler? import as svg? 1`] = `
"import {Icon} from '@adobe/react-spectrum';
Expand Down
44 changes: 44 additions & 0 deletions packages/dev/codemods/src/s1-to-s2/__tests__/icon.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,47 @@ function CustomIcon(props) {
);
}
`);

test('Migrate S1 icon with same name to S2', `
import Add from '@spectrum-icons/workflow/Add';
<Add />;
`);

test('Migrate S1 icon with different name to S2', `
import Alert from '@spectrum-icons/workflow/Alert';
<Alert />;
`);

test('Migrate custom-named S1 icon to S2. Keep name as custom name.', `
import AlertIcon from '@spectrum-icons/workflow/Alert';
import Alert from 'elsewhere';
<div>
<AlertIcon />
<Alert />
</div>
`);

test('Migrate S1 icon with different name to S2. Keep name if already taken in scope.', `
import Alert from '@spectrum-icons/workflow/Alert';
import AlertTriangle from 'elsewhere';
<div>
<Alert />
<AlertTriangle />
</div>
`);

test('Leave comment if no matching S2 icon found', `
import AssetCheck from '@spectrum-icons/workflow/AssetCheck';
<AssetCheck />;
`);

test('Does not affect existing S2 icons', `
import Add from '@react-spectrum/s2/icons/Add';
<Add />;
`);
53 changes: 53 additions & 0 deletions packages/dev/codemods/src/s1-to-s2/src/codemods/codemod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {API, FileInfo} from 'jscodeshift';
import {changes as changesJSON} from './changes';
import {functionMap} from './transforms';
import {getComponents} from '../getComponents';
import {iconMap} from '../iconMap';
import * as t from '@babel/types';
import {transformStyleProps} from './styleProps';
import traverse, {Binding, NodePath} from '@babel/traverse';
Expand Down Expand Up @@ -39,6 +40,7 @@ export default function transformer(file: FileInfo, api: API, options: Options)
let importedComponents = new Map<string, t.ImportSpecifier | t.ImportNamespaceSpecifier>();
let elements: [string, NodePath<t.JSXElement>][] = [];
let lastImportPath: NodePath<t.ImportDeclaration> | null = null;
let iconImports: Map<string, {path: NodePath<t.ImportDeclaration>, newName: string | null}> = new Map();
const leadingComments = root.find(j.Program).get('body', 0).node.leadingComments;
traverse(root.paths()[0].node, {
ImportDeclaration(path) {
Expand Down Expand Up @@ -90,6 +92,22 @@ export default function transformer(file: FileInfo, api: API, options: Options)
}
}
}
} else if (path.node.source.value.startsWith('@spectrum-icons/workflow/')) {
let importSource = path.node.source.value;
let iconName = importSource.split('/').pop();
if (!iconName) {return;}

let specifier = path.node.specifiers[0];
if (!specifier || !t.isImportDefaultSpecifier(specifier)) {return;}

let localName = specifier.local.name;

if (iconMap.has(iconName)) {
let newIconName = iconMap.get(iconName)!;
iconImports.set(localName, {path, newName: newIconName});
} else {
iconImports.set(localName, {path, newName: null});
}
}
},
Import(path) {
Expand All @@ -109,6 +127,41 @@ export default function transformer(file: FileInfo, api: API, options: Options)

// TODO: implement this. could be a bit challenging. punting for now.
addComment(call.node, ' TODO(S2-upgrade): check this dynamic import');
},
JSXOpeningElement(path) {
let name = path.node.name;
if (t.isJSXIdentifier(name) && iconImports.has(name.name)) {
let iconInfo = iconImports.get(name.name)!;
if (iconInfo.newName === null) {
addComment(path.node, ` TODO(S2-upgrade): A Spectrum 2 equivalent to '${name.name}' was not found. Please update this icon manually.`);
}
}
}
});

iconImports.forEach((iconInfo, localName) => {
let {path, newName} = iconInfo;
if (newName) {
let newImportSource = `@react-spectrum/s2/icons/${newName}`;

// Check if we can update local name
let newLocalName = localName;
if (localName === path.node.source.value.split('/').pop() && localName !== newName) {
let binding = path.scope.getBinding(localName);
if (binding && !path.scope.hasBinding(newName)) {
newLocalName = newName;
// Rename all references
binding.referencePaths.forEach(refPath => {
if (t.isJSXIdentifier(refPath.node)) {
refPath.node.name = newName;
}
});
}
}

// Update the import
path.node.source = t.stringLiteral(newImportSource);
path.node.specifiers = [t.importDefaultSpecifier(t.identifier(newLocalName))];
}
});

Expand Down
Loading

0 comments on commit 32f8b8d

Please sign in to comment.