Skip to content

Commit 70f3ab8

Browse files
authored
Improve ESLint migrations for v9 (#2735)
1 parent d89175a commit 70f3ab8

File tree

6 files changed

+151
-14
lines changed

6 files changed

+151
-14
lines changed

.changeset/metal-games-knock.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@sumup-oss/eslint-plugin-circuit-ui': minor
3+
---
4+
5+
Expanded the `renamed-package-scope` ESLint rule to cover additional occurrences of package names such as in Jest module mocks.

.changeset/quick-books-train.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@sumup-oss/eslint-plugin-circuit-ui': patch
3+
---
4+
5+
Fixed the `no-renamed-props` ESLint rule to add the `as="strong"` prop when migrating the Body's `variant="highlight"` prop to match the previous semantics.

packages/eslint-plugin-circuit-ui/no-renamed-props/index.spec.ts

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -340,6 +340,12 @@ ruleTester.run('no-renamed-props', noRenamedProps, {
340340
}
341341
342342
function ComponentB() {
343+
return (
344+
<Body as="span" variant="highlight">Lorem ipsum</Body>
345+
)
346+
}
347+
348+
function ComponentC() {
343349
return (
344350
<Body variant="alert">Lorem ipsum</Body>
345351
)
@@ -348,17 +354,27 @@ ruleTester.run('no-renamed-props', noRenamedProps, {
348354
output: `
349355
function ComponentA() {
350356
return (
351-
<Body weight="bold">Lorem ipsum</Body>
357+
<Body as="strong" weight="bold">Lorem ipsum</Body>
352358
)
353359
}
354360
355361
function ComponentB() {
362+
return (
363+
<Body as="span" weight="bold">Lorem ipsum</Body>
364+
)
365+
}
366+
367+
function ComponentC() {
356368
return (
357369
<Body color="danger">Lorem ipsum</Body>
358370
)
359371
}
360372
`,
361-
errors: [{ messageId: 'bodyVariant' }, { messageId: 'bodyVariant' }],
373+
errors: [
374+
{ messageId: 'bodyVariant' },
375+
{ messageId: 'bodyVariant' },
376+
{ messageId: 'bodyVariant' },
377+
],
362378
},
363379
],
364380
});

packages/eslint-plugin-circuit-ui/no-renamed-props/index.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -290,15 +290,20 @@ const configs: (Config & { components: string[] })[] = [
290290
const current = getAttributeValue(attribute);
291291

292292
if (current === 'highlight') {
293-
const replacement = `weight="bold"`;
293+
const replacement = `as="strong" weight="bold"`;
294294
const weightAttribute = findAttribute(node, 'weight');
295+
const asAttribute = findAttribute(node, 'as');
295296
context.report({
296297
node: attribute,
297298
messageId: 'bodyVariant',
298299
data: { component, current, replacement },
299300
fix: weightAttribute
300301
? undefined
301302
: (fixer) => {
303+
// Don't override an existing `as` attribute
304+
if (asAttribute) {
305+
return fixer.replaceText(attribute, 'weight="bold"');
306+
}
302307
return fixer.replaceText(attribute, replacement);
303308
},
304309
});

packages/eslint-plugin-circuit-ui/renamed-package-scope/index.spec.ts

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,5 +78,63 @@ ruleTester.run('renamed-package-scope', renamedPackageScope, {
7878
`,
7979
errors: [{ messageId: 'refactor' }],
8080
},
81+
{
82+
name: 'dynamic import from the old package scope',
83+
code: `
84+
const components = await import('@sumup/circuit-ui');
85+
`,
86+
output: `
87+
const components = await import('@sumup-oss/circuit-ui');
88+
`,
89+
errors: [{ messageId: 'refactor' }],
90+
},
91+
{
92+
name: 'module mock of the old package scope',
93+
code: `
94+
jest.mock('@sumup/circuit-ui');
95+
96+
jest.mock('@sumup/intl', () => ({
97+
...jest.requireActual('@sumup/intl'),
98+
formatNumber: jest.fn(),
99+
}));
100+
`,
101+
output: `
102+
jest.mock('@sumup-oss/circuit-ui');
103+
104+
jest.mock('@sumup-oss/intl', () => ({
105+
...jest.requireActual('@sumup-oss/intl'),
106+
formatNumber: jest.fn(),
107+
}));
108+
`,
109+
errors: [
110+
{ messageId: 'refactor' },
111+
{ messageId: 'refactor' },
112+
{ messageId: 'refactor' },
113+
],
114+
},
115+
{
116+
name: 'module mock of the old package scope with type annotations',
117+
code: `
118+
vi.mock('@sumup/circuit-ui', () => ({
119+
...vi.importActual<typeof import('@sumup/circuit-ui')>(
120+
'@sumup/circuit-ui',
121+
),
122+
useCollapsible: vi.fn(),
123+
}));
124+
`,
125+
output: `
126+
vi.mock('@sumup-oss/circuit-ui', () => ({
127+
...vi.importActual<typeof import('@sumup-oss/circuit-ui')>(
128+
'@sumup-oss/circuit-ui',
129+
),
130+
useCollapsible: vi.fn(),
131+
}));
132+
`,
133+
errors: [
134+
{ messageId: 'refactor' },
135+
{ messageId: 'refactor' },
136+
{ messageId: 'refactor' },
137+
],
138+
},
81139
],
82140
});

packages/eslint-plugin-circuit-ui/renamed-package-scope/index.ts

Lines changed: 59 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -66,21 +66,69 @@ export const renamedPackageScope = createRule({
6666
// See https://eslint.org/docs/latest/extend/selectors#known-issues
6767
const escapedFrom = from.replace('/', '\\u002F');
6868

69+
function fixPackageName(node: TSESTree.Node | TSESTree.Token) {
70+
context.report({
71+
node,
72+
messageId: 'refactor',
73+
data: { from, to },
74+
fix(fixer) {
75+
return fixer.replaceText(
76+
node,
77+
context.sourceCode.getText(node).replace(from, to),
78+
);
79+
},
80+
});
81+
}
82+
6983
return Object.assign(visitors, {
7084
[`ImportDeclaration:has(Literal[value=/${escapedFrom}(?!-).*/])`]: (
7185
node: TSESTree.ImportDeclaration,
7286
) => {
73-
context.report({
74-
node,
75-
messageId: 'refactor',
76-
data: { from, to },
77-
fix(fixer) {
78-
return fixer.replaceText(
79-
node,
80-
context.sourceCode.getText(node).replace(from, to),
81-
);
82-
},
83-
});
87+
const { source } = node;
88+
89+
if (source.type !== 'Literal') {
90+
return;
91+
}
92+
93+
fixPackageName(source);
94+
},
95+
[`ImportExpression:has(Literal[value=/${escapedFrom}(?!-).*/])`]: (
96+
node: TSESTree.ImportExpression,
97+
) => {
98+
const { source } = node;
99+
100+
if (source.type !== 'Literal') {
101+
return;
102+
}
103+
104+
fixPackageName(source);
105+
},
106+
[`CallExpression:has(Identifier[name=/(mock|requireActual|importActual)/]):has(Literal[value=/${escapedFrom}(?!-).*/])`]:
107+
(node: TSESTree.CallExpression) => {
108+
const firstArg = node.arguments[0];
109+
110+
if (firstArg.type !== 'Literal') {
111+
return;
112+
}
113+
114+
fixPackageName(firstArg);
115+
},
116+
[`TSImportType:has(Literal[value=/${escapedFrom}(?!-).*/])`]: (
117+
node: TSESTree.TSImportType,
118+
) => {
119+
const { argument } = node;
120+
121+
if (argument.type !== 'TSLiteralType') {
122+
return;
123+
}
124+
125+
const { literal } = argument;
126+
127+
if (literal.type !== 'Literal') {
128+
return;
129+
}
130+
131+
fixPackageName(literal);
84132
},
85133
});
86134
}, {});

0 commit comments

Comments
 (0)