Skip to content

Commit 9794a18

Browse files
committed
More robust stylelint shim to support reporting
1 parent 7886de6 commit 9794a18

File tree

6 files changed

+426
-99
lines changed

6 files changed

+426
-99
lines changed

polaris-migrator/README.md

Lines changed: 24 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -278,37 +278,47 @@ migrations
278278

279279
#### The SASS migration function
280280

281-
Each migrator has a default export adhering to the [PostCSS Plugin API](https://github.com/postcss/postcss/blob/main/docs/writing-a-plugin.md) with one main difference: events are only executed once.
281+
Each migrator has a default export adhering to the [Stylelint Rule API](https://github.com/postcss/postcss/blob/main/docs/writing-a-plugin.md). A PostCSS AST is passed as the `root` and can be mutated inline, or emit warning/error reports.
282282

283283
Continuing the example, here is what the migration may look like if our goal is to replace the Sass function `hello()` with `world()`.
284284

285285
```ts
286286
// polaris-migrator/src/migrations/replace-sass-function/replace-sass-function.ts
287-
import valueParser from 'postcss-value-parser';
288-
289287
import {
290288
isSassFunction,
291-
StopWalkingFunctionNodes,
292289
createSassMigrator,
290+
StopWalkingFunctionNodes,
293291
} from '../../utilities/sass';
292+
import type {PolarisMigrator} from '../../utilities/sass';
294293

295-
// options can be passed in from cli / config.
296-
export default createSassMigrator('replace-sass-function', (/* options */) => {
297-
return {
298-
Declaration(decl) {
294+
const replaceHelloWorld: PolarisMigrator = (_, {methods}, context) => {
295+
return (root) => {
296+
methods.walkDecls(root, (decl) => {
299297
const parsedValue = valueParser(decl.value);
300-
301298
parsedValue.walk((node) => {
302299
if (isSassFunction('hello', node)) {
303-
node.value = 'world';
300+
if (context.fix) {
301+
node.value = 'world';
302+
} else {
303+
methods.report({
304+
node: decl,
305+
severity: 'error',
306+
message:
307+
'Method hello() is no longer supported. Please migrate to world().',
308+
});
309+
}
310+
304311
return StopWalkingFunctionNodes;
305312
}
306313
});
307-
308-
decl.value = parsedValue.toString();
309-
},
314+
if (context.fix) {
315+
decl.value = parsedValue.toString();
316+
}
317+
});
310318
};
311-
});
319+
};
320+
321+
export default createSassMigrator('replace-hello-world', replaceHelloWorld);
312322
```
313323

314324
A more complete example can be seen in [`replace-spacing-lengths.ts`](https://github.com/Shopify/polaris/blob/main/polaris-migrator/src/migrations/replace-spacing-lengths/replace-spacing-lengths.ts).

polaris-migrator/src/migrations/replace-spacing-lengths/replace-spacing-lengths.ts

Lines changed: 62 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
import valueParser from 'postcss-value-parser';
22

3-
import {POLARIS_MIGRATOR_COMMENT} from '../../constants';
43
import {
5-
createInlineComment,
64
getFunctionArgs,
75
isNumericOperator,
86
isSassFunction,
@@ -16,39 +14,30 @@ import {isKeyOf} from '../../utilities/type-guards';
1614

1715
export default createSassMigrator(
1816
'replace-sass-space',
19-
(_, options, context) => {
17+
(_, {methods, options}, context) => {
2018
const namespacedRem = namespace('rem', options);
2119

2220
return (root) => {
23-
root.walkDecls((decl) => {
21+
methods.walkDecls(root, (decl) => {
2422
if (!spaceProps.has(decl.prop)) return;
2523

26-
/**
27-
* A collection of transformable values to migrate (e.g. decl lengths, functions, etc.)
28-
*
29-
* Note: This is evaluated at the end of each visitor execution to determine whether
30-
* or not to replace the declaration or insert a comment.
31-
*/
32-
const targets: {replaced: boolean}[] = [];
3324
let hasNumericOperator = false;
25+
3426
const parsedValue = valueParser(decl.value);
3527

3628
handleSpaceProps();
3729

38-
if (targets.some(({replaced}) => !replaced || hasNumericOperator)) {
39-
decl.before(
40-
createInlineComment(POLARIS_MIGRATOR_COMMENT, {prose: true}),
41-
);
42-
decl.before(
43-
createInlineComment(`${decl.prop}: ${parsedValue.toString()};`),
44-
);
45-
} else if (context.fix) {
30+
if (context.fix) {
4631
decl.value = parsedValue.toString();
4732
}
4833

49-
//
50-
// Handlers
51-
//
34+
if (hasNumericOperator) {
35+
methods.report({
36+
node: decl,
37+
severity: 'warning',
38+
message: 'Numeric operator detected.',
39+
});
40+
}
5241

5342
function handleSpaceProps() {
5443
parsedValue.walk((node) => {
@@ -64,41 +53,71 @@ export default createSassMigrator(
6453

6554
if (!isTransformableLength(dimension)) return;
6655

67-
targets.push({replaced: false});
68-
6956
const valueInPx = toTransformablePx(node.value);
7057

71-
if (!isKeyOf(spaceMap, valueInPx)) return;
58+
if (!isKeyOf(spaceMap, valueInPx)) {
59+
methods.report({
60+
node: decl,
61+
severity: 'error',
62+
message: `Non-tokenizable value '${node.value}'`,
63+
});
64+
return;
65+
}
7266

73-
targets[targets.length - 1]!.replaced = true;
67+
if (context.fix) {
68+
node.value = `var(${spaceMap[valueInPx]})`;
69+
return;
70+
}
7471

75-
node.value = `var(${spaceMap[valueInPx]})`;
72+
methods.report({
73+
node: decl,
74+
severity: 'error',
75+
message: `Prefer var(${spaceMap[valueInPx]}) Polaris token.`,
76+
});
7677
return;
7778
}
7879

7980
if (node.type === 'function') {
8081
if (isSassFunction(namespacedRem, node)) {
81-
targets.push({replaced: false});
82-
8382
const args = getFunctionArgs(node);
8483

85-
if (args.length !== 1) return;
84+
if (args.length !== 1) {
85+
methods.report({
86+
node: decl,
87+
severity: 'error',
88+
message: `Expected 1 argument, got ${args.length}`,
89+
});
90+
return;
91+
}
8692

8793
const valueInPx = toTransformablePx(args[0]);
8894

89-
if (!isKeyOf(spaceMap, valueInPx)) return;
90-
91-
targets[targets.length - 1]!.replaced = true;
92-
93-
node.value = 'var';
94-
node.nodes = [
95-
{
96-
type: 'word',
97-
value: spaceMap[valueInPx],
98-
sourceIndex: node.nodes[0]?.sourceIndex ?? 0,
99-
sourceEndIndex: spaceMap[valueInPx].length,
100-
},
101-
];
95+
if (!isKeyOf(spaceMap, valueInPx)) {
96+
methods.report({
97+
node: decl,
98+
severity: 'error',
99+
message: `Non-tokenizable value '${args[0].trim()}'`,
100+
});
101+
return;
102+
}
103+
104+
if (context.fix) {
105+
node.value = 'var';
106+
node.nodes = [
107+
{
108+
type: 'word',
109+
value: spaceMap[valueInPx],
110+
sourceIndex: node.nodes[0]?.sourceIndex ?? 0,
111+
sourceEndIndex: spaceMap[valueInPx].length,
112+
},
113+
];
114+
return;
115+
}
116+
methods.report({
117+
node: decl,
118+
severity: 'error',
119+
message: `Prefer var(${spaceMap[valueInPx]}) Polaris token.`,
120+
});
102121
}
103122

104123
return StopWalkingFunctionNodes;

polaris-migrator/src/migrations/replace-spacing-lengths/tests/replace-spacing-lengths.output.scss

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
padding: 0;
1616
padding: 1;
1717
padding: 2;
18+
// polaris-migrator: Unable to migrate the following expression. Please upgrade manually.
19+
// warning: Numeric operator detected.
1820
padding: #{16px + 16px};
1921
padding: layout-width(nav);
2022
padding: 10em;
@@ -23,55 +25,65 @@
2325
padding: var(--p-space-4, 16px);
2426
// Comment
2527
// polaris-migrator: Unable to migrate the following expression. Please upgrade manually.
26-
// padding: 10px;
28+
// error: Non-tokenizable value '10px'
2729
padding: 10px;
2830
// polaris-migrator: Unable to migrate the following expression. Please upgrade manually.
29-
// padding: 10rem;
31+
// error: Non-tokenizable value '10rem'
3032
padding: 10rem;
3133
// polaris-migrator: Unable to migrate the following expression. Please upgrade manually.
32-
// padding: 10px 10px;
34+
// error: Non-tokenizable value '10px'
3335
padding: 10px 10px;
3436
// polaris-migrator: Unable to migrate the following expression. Please upgrade manually.
37+
// error: Non-tokenizable value '10px'
3538
// padding: var(--p-space-4) 10px;
3639
padding: 16px 10px;
3740
// polaris-migrator: Unable to migrate the following expression. Please upgrade manually.
38-
// padding: 10rem 10rem;
41+
// error: Non-tokenizable value '10rem'
3942
padding: 10rem 10rem;
4043
// polaris-migrator: Unable to migrate the following expression. Please upgrade manually.
44+
// error: Non-tokenizable value '10rem'
4145
// padding: var(--p-space-4) 10rem;
4246
padding: 1rem 10rem;
4347
// polaris-migrator: Unable to migrate the following expression. Please upgrade manually.
44-
// padding: 10px 10rem;
48+
// error: Non-tokenizable value '10px'
49+
// error: Non-tokenizable value '10rem'
4550
padding: 10px 10rem;
4651
// polaris-migrator: Unable to migrate the following expression. Please upgrade manually.
52+
// error: Non-tokenizable value '10rem'
4753
// padding: var(--p-space-4) 10rem;
4854
padding: 16px 10rem;
4955
// polaris-migrator: Unable to migrate the following expression. Please upgrade manually.
56+
// error: Non-tokenizable value '10px'
5057
// padding: 10px var(--p-space-4);
5158
padding: 10px 1rem;
5259
// polaris-migrator: Unable to migrate the following expression. Please upgrade manually.
60+
// error: Non-tokenizable value '-16px'
5361
// padding: var(--p-space-4) -16px;
5462
padding: 16px -16px;
5563
// polaris-migrator: Unable to migrate the following expression. Please upgrade manually.
64+
// warning: Numeric operator detected.
5665
// padding: var(--p-space-4) + var(--p-space-4);
5766
padding: 16px + 16px;
5867
// polaris-migrator: Unable to migrate the following expression. Please upgrade manually.
68+
// warning: Numeric operator detected.
5969
// padding: var(--p-space-4) + var(--p-space-4) var(--p-space-4);
6070
padding: 16px + 16px 16px;
6171
// polaris-migrator: Unable to migrate the following expression. Please upgrade manually.
72+
// warning: Numeric operator detected.
6273
// padding: $var + var(--p-space-4);
6374
padding: $var + 16px;
6475
padding: calc(16px + 16px);
6576
// polaris-migrator: Unable to migrate the following expression. Please upgrade manually.
77+
// warning: Numeric operator detected.
6678
// padding: var(--p-space-4) + #{16px + 16px};
6779
padding: 16px + #{16px + 16px};
6880
// Skip negative lengths. Need to discuss replacement strategy e.g.
6981
// calc(-1 * var(--p-space-*)) vs var(--p-space--*)
7082
// polaris-migrator: Unable to migrate the following expression. Please upgrade manually.
71-
// padding: -16px;
83+
// error: Non-tokenizable value '-16px'
7284
padding: -16px;
7385
// polaris-migrator: Unable to migrate the following expression. Please upgrade manually.
74-
// padding: -10px;
86+
// error: Non-tokenizable value '-10px'
7587
padding: -10px;
7688

7789
// REM FUNCTION
@@ -86,21 +98,26 @@
8698
padding: calc(10rem + var(--p-choice-size, #{rem(10px)}));
8799
// Comment
88100
// polaris-migrator: Unable to migrate the following expression. Please upgrade manually.
89-
// padding: rem(10px);
101+
// error: Non-tokenizable value '10px'
90102
padding: rem(10px);
91103
// polaris-migrator: Unable to migrate the following expression. Please upgrade manually.
92-
// padding: rem(10px) rem(10px);
104+
// error: Non-tokenizable value '10px'
93105
padding: rem(10px) rem(10px);
94106
// polaris-migrator: Unable to migrate the following expression. Please upgrade manually.
107+
// error: Non-tokenizable value '10px'
95108
// padding: var(--p-space-4) rem(10px);
96109
padding: rem(16px) rem(10px);
97110
// polaris-migrator: Unable to migrate the following expression. Please upgrade manually.
111+
// error: Non-tokenizable value '-16px'
98112
// padding: var(--p-space-4) -16px;
99113
padding: rem(16px) -16px;
100114
// polaris-migrator: Unable to migrate the following expression. Please upgrade manually.
115+
// warning: Numeric operator detected.
101116
// padding: var(--p-space-4) + var(--p-space-4);
102117
padding: rem(16px) + 16px;
103118
// polaris-migrator: Unable to migrate the following expression. Please upgrade manually.
119+
// error: Non-tokenizable value '$var \* 16px'
120+
// warning: Numeric operator detected.
104121
// padding: rem($var * var(--p-space-4));
105122
padding: rem($var * 16px);
106123
}

0 commit comments

Comments
 (0)