Skip to content

Commit

Permalink
feat: Codemod: handle legacy Link API (adobe#6907)
Browse files Browse the repository at this point in the history
* handle legacy Link API by removing a element

* handle custom link components
  • Loading branch information
reidbarber committed Aug 21, 2024
1 parent 859615a commit 2e689d9
Show file tree
Hide file tree
Showing 5 changed files with 86 additions and 1 deletion.
1 change: 1 addition & 0 deletions .storybook-s2/docs/Migrating.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,7 @@ export function Migrating() {
<H3>Link</H3>
<ul className="sb-unstyled">
<li className={style({font: 'body', marginY: 8})}>Change <Code>variant="overBackground"</Code> to <Code>staticColor="white"</Code></li>
<li className={style({font: 'body', marginY: 8})}>If <Code>a</Code> was used inside <Code>Link</Code> (legacy API), remove the <Code>a</Code> and apply props (i.e <Code>href</Code>) directly to <Code>Link</Code></li>
</ul>

<H3>ListBox</H3>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,21 @@ let props = {variant: 'overBackground'};
</Link>
</div>"
`;

exports[`Leaves comment if inner link element is a custom router link (deprecated API) 1`] = `
"import { Link } from "@react-spectrum/s2";
import { Link as RouterLink } from "react-router-dom";
<div>
// TODO(S2-upgrade): You may have been using a custom link component here. You'll need to update this manually.
<Link to="https://www.imdb.com/title/tt6348138/">The missing link.</Link>
</div>"
`;

exports[`Remove inner anchor element (deprecated API) 1`] = `
"import { Link } from "@react-spectrum/s2";
<div>
<Link href="https://www.imdb.com/title/tt6348138/" target="_blank">The missing link.</Link>
</div>"
`;
25 changes: 25 additions & 0 deletions packages/dev/codemods/src/s1-to-s2/__tests__/link.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,28 @@ let props = {variant: 'overBackground'};
</Link>
</div>
`);

test('Remove inner anchor element (deprecated API)', `
import {Link} from '@adobe/react-spectrum';
<div>
<Link>
<a href="https://www.imdb.com/title/tt6348138/" target="_blank">
The missing link.
</a>
</Link>
</div>
`);

test('Leaves comment if inner link element is a custom router link (deprecated API)', `
import {Link} from '@adobe/react-spectrum';
import { Link as RouterLink } from "react-router-dom";
<div>
<Link>
<RouterLink to="https://www.imdb.com/title/tt6348138/">
The missing link.
</RouterLink>
</Link>
</div>
`);
12 changes: 12 additions & 0 deletions packages/dev/codemods/src/s1-to-s2/src/codemods/changes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,10 @@ type FunctionInfo =
| {
name: 'updateAvatarSize',
args: {}
}
| {
name: 'updateLegacyLink',
args: {}
};

type Change = {
Expand Down Expand Up @@ -591,6 +595,14 @@ export const changes: ChangesJSON = {
newValue: 'white'
}
}
},
{
description: 'Remove inner anchor element if used (legacy API)',
reason: 'Updated API',
function: {
name: 'updateLegacyLink',
args: {}
}
}
]
},
Expand Down
31 changes: 30 additions & 1 deletion packages/dev/codemods/src/s1-to-s2/src/codemods/transforms.ts
Original file line number Diff line number Diff line change
Expand Up @@ -918,6 +918,34 @@ function updateAvatarSize(
}
}

/**
* Handles the legacy `Link` API where an `a` tag or custom router component could be used within a `Link` component.
* Removes the inner component and moves its attributes to the `Link` component.
*/
function updateLegacyLink(
path: NodePath<t.JSXElement>
) {
let missingOuterHref = t.isJSXElement(path.node) && !path.node.openingElement.attributes.some((attr) => t.isJSXAttribute(attr) && attr.name.name === 'href');
if (missingOuterHref) {
let innerLink = path.node.children.find((child) => t.isJSXElement(child) && t.isJSXIdentifier(child.openingElement.name));
if (innerLink && t.isJSXElement(innerLink)) {
let innerAttributes = innerLink.openingElement.attributes;
let outerAttributes = path.node.openingElement.attributes;
innerAttributes.forEach((attr) => {
outerAttributes.push(attr);
});

if (
t.isJSXIdentifier(innerLink.openingElement.name) &&
innerLink.openingElement.name.name !== 'a'
) {
addComment(path.node, ' TODO(S2-upgrade): You may have been using a custom link component here. You\'ll need to update this manually.');
}
path.node.children = innerLink.children;
}
}
}

export const functionMap = {
updatePropNameAndValue,
updatePropValueAndAddNewProp,
Expand All @@ -936,5 +964,6 @@ export const functionMap = {
convertDimensionValueToPx,
updatePlacementToSingleValue,
removeComponentIfWithinParent,
updateAvatarSize
updateAvatarSize,
updateLegacyLink
};

0 comments on commit 2e689d9

Please sign in to comment.