From 7ff086afd1b4a091287bac269ee60818ddff47e1 Mon Sep 17 00:00:00 2001 From: Kristiyan Kostadinov Date: Tue, 6 Mar 2018 11:17:37 -0500 Subject: [PATCH] build: add stylelint rule to avoid top-level ampersands in themes (#10280) * Adds a stylelint rule that will log a warning for top-level ampersand selectors inside of mixins. This will help us avoid issues like #9991 in the future. * Makes the `mat-radio-color` internal. --- src/lib/radio/_radio-theme.scss | 8 ++-- stylelint-config.json | 6 ++- .../no-top-level-ampersand-in-mixin/index.js | 44 +++++++++++++++++++ 3 files changed, 53 insertions(+), 5 deletions(-) create mode 100644 tools/stylelint/no-top-level-ampersand-in-mixin/index.js diff --git a/src/lib/radio/_radio-theme.scss b/src/lib/radio/_radio-theme.scss index 910db6386e3..a0414f45695 100644 --- a/src/lib/radio/_radio-theme.scss +++ b/src/lib/radio/_radio-theme.scss @@ -2,7 +2,7 @@ @import '../core/theming/theming'; @import '../core/typography/typography-utils'; -@mixin mat-radio-color($palette) { +@mixin _mat-radio-color($palette) { &.mat-radio-checked .mat-radio-outer-circle { border-color: mat-color($palette); } @@ -43,15 +43,15 @@ .mat-radio-button { &.mat-primary { - @include mat-radio-color($primary); + @include _mat-radio-color($primary); } &.mat-accent { - @include mat-radio-color($accent); + @include _mat-radio-color($accent); } &.mat-warn { - @include mat-radio-color($warn); + @include _mat-radio-color($warn); } } } diff --git a/stylelint-config.json b/stylelint-config.json index 45541cc3cfa..7b4cdf09ab2 100644 --- a/stylelint-config.json +++ b/stylelint-config.json @@ -4,7 +4,8 @@ "./tools/stylelint/selector-nested-pattern-scoped/index.js", "./tools/stylelint/selector-no-deep/index.js", "./tools/stylelint/no-nested-mixin/index.js", - "./tools/stylelint/no-concrete-rules/index.js" + "./tools/stylelint/no-concrete-rules/index.js", + "./tools/stylelint/no-top-level-ampersand-in-mixin/index.js" ], "rules": { "material/no-prefixes": [["last 2 versions", "not ie <= 10", "not ie_mob <= 10"]], @@ -17,6 +18,9 @@ "material/no-concrete-rules": [true, { "filePattern": "^_.*\\.scss$" }], + "material/no-top-level-ampersand-in-mixin": [true, { + "filePattern": "-theme\\.scss$" + }], "color-hex-case": "lower", "color-no-invalid-hex": true, diff --git a/tools/stylelint/no-top-level-ampersand-in-mixin/index.js b/tools/stylelint/no-top-level-ampersand-in-mixin/index.js new file mode 100644 index 00000000000..ad6a0bfd215 --- /dev/null +++ b/tools/stylelint/no-top-level-ampersand-in-mixin/index.js @@ -0,0 +1,44 @@ +const stylelint = require('stylelint'); +const path = require('path'); +const ruleName = 'material/no-top-level-ampersand-in-mixin'; +const messages = stylelint.utils.ruleMessages(ruleName, { + expected: () => `Selectors starting with an ampersand ` + + `are not allowed inside top-level mixin rules` +}); + +/** + * Stylelint rule that doesn't allow for the top-level rules inside a + * mixin to start with an ampersand. Does not apply to internal mixins. + */ +const plugin = stylelint.createPlugin(ruleName, (isEnabled, options) => { + return (root, result) => { + if (!isEnabled) return; + + const filePattern = new RegExp(options.filePattern); + const fileName = path.basename(root.source.input.file); + + if (!filePattern.test(fileName)) return; + + root.walkAtRules(node => { + // Skip non-mixin atrules and internal mixins. + if (node.name !== 'mixin' || node.params.indexOf('_') === 0) { + return; + } + + node.nodes.forEach(childNode => { + if (childNode.type === 'rule' && childNode.selector.indexOf('&') === 0) { + stylelint.utils.report({ + result, + ruleName, + message: messages.expected(), + node: childNode + }); + } + }); + }); + }; +}); + +plugin.ruleName = ruleName; +plugin.messages = messages; +module.exports = plugin;