Skip to content

Commit 9f20fd2

Browse files
committed
refactor: convert new theme-mixin-api stylelint rule to typescript
We recently refactored all stylelint rules to TypeScript. Similarly we should migrate the new rule that has been added in the density feature branch.
1 parent 46868f1 commit 9f20fd2

File tree

2 files changed

+33
-28
lines changed

2 files changed

+33
-28
lines changed

.stylelintrc.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
"./tools/stylelint/no-nested-mixin.ts",
88
"./tools/stylelint/no-concrete-rules.ts",
99
"./tools/stylelint/no-top-level-ampersand-in-mixin.ts",
10-
"./tools/stylelint/theme-mixin-api.js"
10+
"./tools/stylelint/theme-mixin-api.ts"
1111
],
1212
"rules": {
1313
"material/no-prefixes": [true, {

tools/stylelint/theme-mixin-api.js renamed to tools/stylelint/theme-mixin-api.ts

Lines changed: 32 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
const stylelint = require('stylelint');
1+
import {AtRule, Declaration, Node, Result, Root} from 'postcss';
2+
import {createPlugin, Plugin, utils} from 'stylelint';
23

34
/** Name of this stylelint rule. */
45
const ruleName = 'material/theme-mixin-api';
@@ -19,10 +20,11 @@ const themeMixinRegex =
1920
* 3. Checks if the `-theme` mixins have the duplicate style check set up. We want to
2021
* consistently check for duplicative theme styles so that we can warn consumers.
2122
*/
22-
const plugin = stylelint.createPlugin(ruleName, (isEnabled, options, context) => {
23-
return (root, result) => {
24-
if (!isEnabled)
23+
const plugin = (isEnabled: boolean, options: never, context: {fix: boolean}) => {
24+
return (root: Root, result: Result) => {
25+
if (!isEnabled) {
2526
return;
27+
}
2628

2729
root.walkAtRules('mixin', node => {
2830
const matches = node.params.match(themeMixinRegex);
@@ -38,21 +40,21 @@ const plugin = stylelint.createPlugin(ruleName, (isEnabled, options, context) =>
3840
// a comma. This is not always correct because Sass maps can be constructed in parameters.
3941
// These would contain commas that throw of the argument retrieval. It's acceptable that
4042
// this rule will fail in such edge-cases. There is no AST for `postcss.AtRule` params.
41-
const arguments = matches[5].split(',');
43+
const args = matches[5].split(',');
4244

4345
if (type === 'theme') {
44-
validateThemeMixin(node, componentName, arguments);
46+
validateThemeMixin(node, componentName, args);
4547
} else {
46-
validateIndividualSystemMixins(node, type, arguments);
48+
validateIndividualSystemMixins(node, type, args);
4749
}
4850
});
4951

50-
function validateThemeMixin(node, componentName, arguments) {
51-
if (arguments.length !== 1) {
52+
function validateThemeMixin(node: AtRule, componentName: string, args: string[]) {
53+
if (args.length !== 1) {
5254
reportError(node, 'Expected theme mixin to only declare a single argument.');
53-
} else if (arguments[0] !== '$theme-or-color-config') {
55+
} else if (args[0] !== '$theme-or-color-config') {
5456
if (context.fix) {
55-
node.params = node.params.replace(arguments[0], '$theme-or-color-config');
57+
node.params = node.params.replace(args[0], '$theme-or-color-config');
5658
} else {
5759
reportError(node, 'Expected first mixin argument to be called `$theme-or-color-config`.');
5860
}
@@ -62,11 +64,13 @@ const plugin = stylelint.createPlugin(ruleName, (isEnabled, options, context) =>
6264
const legacyColorExtractExpr = `_mat-legacy-get-theme($theme-or-color-config)`;
6365
const duplicateStylesCheckExpr =
6466
`_mat-check-duplicate-theme-styles(${themePropName}, '${componentName}')`;
65-
const legacyConfigDecl =
66-
node.nodes.find(n => n.type === 'decl' && n.value === legacyColorExtractExpr);
67-
const hasDuplicateStylesCheck = node.nodes.find(
68-
n =>
69-
n.type === 'atrule' && n.name === 'include' && n.params === duplicateStylesCheckExpr);
67+
const legacyConfigDecl = !!node.nodes &&
68+
node.nodes.find(
69+
(n): n is Declaration => n.type === 'decl' && n.value === legacyColorExtractExpr);
70+
const hasDuplicateStylesCheck = !!node.nodes &&
71+
node.nodes.find(
72+
n => n.type === 'atrule' && n.name === 'include' &&
73+
n.params === duplicateStylesCheckExpr);
7074

7175
if (!legacyConfigDecl) {
7276
if (context.fix) {
@@ -98,21 +102,21 @@ const plugin = stylelint.createPlugin(ruleName, (isEnabled, options, context) =>
98102
}
99103
}
100104

101-
function validateIndividualSystemMixins(node, type, arguments) {
102-
if (arguments.length !== 1) {
105+
function validateIndividualSystemMixins(node: AtRule, type: string, args: string[]) {
106+
if (args.length !== 1) {
103107
reportError(node, 'Expected mixin to only declare a single argument.');
104-
} else if (arguments[0] !== '$config-or-theme') {
108+
} else if (args[0] !== '$config-or-theme') {
105109
if (context.fix) {
106-
node.params = node.params.replace(arguments[0], '$config-or-theme');
110+
node.params = node.params.replace(args[0], '$config-or-theme');
107111
} else {
108112
reportError(node, 'Expected first mixin argument to be called `$config-or-theme`.');
109113
}
110114
}
111115

112116
const expectedProperty = type === 'density' ? '$density-scale' : '$config';
113117
const expectedValue = `mat-get-${type}-config($config-or-theme)`;
114-
const configExtractionNode =
115-
node.nodes.find(n => n.type === 'decl' && n.value === expectedValue);
118+
const configExtractionNode = !!node.nodes &&
119+
node.nodes.find((n): n is Declaration => n.type === 'decl' && n.value === expectedValue);
116120

117121
if (!configExtractionNode) {
118122
if (context.fix) {
@@ -131,11 +135,12 @@ const plugin = stylelint.createPlugin(ruleName, (isEnabled, options, context) =>
131135
}
132136
}
133137

134-
function reportError(node, message) {
135-
stylelint.utils.report({result, ruleName, node, message});
138+
function reportError(node: Node, message: string) {
139+
utils.report({result, ruleName, node, message});
136140
}
137141
};
138-
});
142+
};
139143

140-
plugin.ruleName = ruleName;
141-
module.exports = plugin;
144+
// Note: We need to cast the value explicitly to `Plugin` because the stylelint types
145+
// do not type the context parameter. https://stylelint.io/developer-guide/rules#add-autofix
146+
module.exports = createPlugin(ruleName, plugin as Plugin);

0 commit comments

Comments
 (0)