Skip to content

Instantly share code, notes, and snippets.

@aleclarson
Last active February 22, 2023 07:32
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save aleclarson/2cb1be7aab5500198c985eaf07119ed2 to your computer and use it in GitHub Desktop.
Save aleclarson/2cb1be7aab5500198c985eaf07119ed2 to your computer and use it in GitHub Desktop.
Add missing & prefix to nested CSS rules that start with identifiers
// https://github.com/w3c/csswg-drafts/issues/7980#issuecomment-1378047080
const stylelint = require("stylelint");
const parseSelector = require("postcss-selector-parser");
const t = parseSelector;
const ruleName = "alloc/required-nesting-selector";
const messages = stylelint.utils.ruleMessages(ruleName, {
expected: selector => `Expected "& ${selector}"`,
});
module.exports = stylelint.createPlugin(ruleName, (_1, _2, context) => {
return (root, result) => {
root.walkRules(rule => {
if (rule.parent.type == "root") return;
if (rule.parent.type == "atrule") return;
let fixed = false;
const processor = parseSelector(root => {
root.each(selector => {
const startsWithIdentifier =
selector.first.type == "tag" && selector.first.value.match(/^[a-zA-Z]/) != null;
if (!startsWithIdentifier) return;
const hasNestingSelector = selector.walk(node => node.type == "nesting");
if (hasNestingSelector) return;
if (context.fix) {
selector.insertBefore(selector.first, t.nesting({ spaces: { after: " " } }));
fixed = true;
} else {
stylelint.utils.report({
ruleName,
result,
node: rule,
index: selector.first.sourceIndex,
message: messages.expected(selector.toString().trim()),
});
}
});
});
const newSelector = processor.processSync(rule.selector);
if (fixed) {
rule.selector = newSelector;
}
});
};
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment