From fca576e703192a4c73e6f2223da8d55f087a860a Mon Sep 17 00:00:00 2001 From: Futa Ikeda Date: Thu, 10 Oct 2024 18:09:00 -0400 Subject: [PATCH 1/2] skip ci; WIP new linter rule --- .stylelintrc.yml | 3 +++ ember-osf-web-stylelint.js | 42 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+) create mode 100644 ember-osf-web-stylelint.js diff --git a/.stylelintrc.yml b/.stylelintrc.yml index ccebd23756c..ab63b9f7672 100644 --- a/.stylelintrc.yml +++ b/.stylelintrc.yml @@ -1,6 +1,8 @@ extends: - stylelint-config-css-modules - stylelint-config-sass-guidelines +plugins: + - ./ember-osf-web-stylelint rules: indentation: 4 max-nesting-depth: 2 @@ -13,3 +15,4 @@ rules: - ignoreProperties: - composes - compose-with + ember-osf-web-stylelint-plugin/no-unlocalized-selectors: true diff --git a/ember-osf-web-stylelint.js b/ember-osf-web-stylelint.js new file mode 100644 index 00000000000..44eeaa33e0f --- /dev/null +++ b/ember-osf-web-stylelint.js @@ -0,0 +1,42 @@ +// eslint-disable @typescript-eslin/no-var-requires +const stylelint = require('stylelint'); + +/* + * This rule prevents the use of bare element selectors in CSS + * Bare element selectors are selectors that are not wrapped in or paired with a class or id +*/ + +const ruleName = 'ember-osf-web-stylelint-plugin/no-unlocalized-selectors'; +const messages = stylelint.utils.ruleMessages(ruleName, { + expected: selector => `Rule "${selector}" should be wrapped in or paired with a local-class or ID`, +}); + +module.exports = stylelint.createPlugin(ruleName, _ => + (postcssRoot, postcssResult) => { + postcssRoot.walkRules(rule => { + const selector = rule.selector; + const isChildRule = rule.parent.type === 'rule'; // top-level rules have rule.parent.type === 'root' + const hasGlobal = selector.includes(':global'); + if ( + isChildRule || + (!hasGlobal && (selector.includes('.') || selector.includes('#'))) // has a local-class or local-id + ) { + return; + } + + if ( + /^[a-z]+/.test(selector) || // starts with a letter + /^:global\([a-z]+/.test(selector) // or starts with :global + ) { + stylelint.utils.report({ + ruleName, + result: postcssResult, + message: messages.expected(selector), + node: rule, + }); + } + }); + }); + +module.exports.ruleName = ruleName; +module.exports.messages = messages; From 03de218bfbea2f38fe53cbdf1551d7ae33cded7b Mon Sep 17 00:00:00 2001 From: Futa Ikeda Date: Fri, 11 Oct 2024 10:50:09 -0400 Subject: [PATCH 2/2] skip ci --- .stylelintrc.yml | 4 ++-- .../no-unlocalized-selectors.js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) rename ember-osf-web-stylelint.js => ember-osf-web-stylelint/no-unlocalized-selectors.js (95%) diff --git a/.stylelintrc.yml b/.stylelintrc.yml index ab63b9f7672..30755dd10d1 100644 --- a/.stylelintrc.yml +++ b/.stylelintrc.yml @@ -2,7 +2,7 @@ extends: - stylelint-config-css-modules - stylelint-config-sass-guidelines plugins: - - ./ember-osf-web-stylelint + - ./ember-osf-web-stylelint/no-unlocalized-selectors.js rules: indentation: 4 max-nesting-depth: 2 @@ -15,4 +15,4 @@ rules: - ignoreProperties: - composes - compose-with - ember-osf-web-stylelint-plugin/no-unlocalized-selectors: true + ember-osf-web-stylelint/no-unlocalized-selectors: true diff --git a/ember-osf-web-stylelint.js b/ember-osf-web-stylelint/no-unlocalized-selectors.js similarity index 95% rename from ember-osf-web-stylelint.js rename to ember-osf-web-stylelint/no-unlocalized-selectors.js index 44eeaa33e0f..c80e90bdbb7 100644 --- a/ember-osf-web-stylelint.js +++ b/ember-osf-web-stylelint/no-unlocalized-selectors.js @@ -6,7 +6,7 @@ const stylelint = require('stylelint'); * Bare element selectors are selectors that are not wrapped in or paired with a class or id */ -const ruleName = 'ember-osf-web-stylelint-plugin/no-unlocalized-selectors'; +const ruleName = 'ember-osf-web-stylelint/no-unlocalized-selectors'; const messages = stylelint.utils.ruleMessages(ruleName, { expected: selector => `Rule "${selector}" should be wrapped in or paired with a local-class or ID`, });