UNPKG

stylelint-scss

Version:

A collection of SCSS specific rules for stylelint

75 lines (63 loc) 2.48 kB
import { isRegExp, isString } from "lodash" import resolveNestedSelector from "postcss-resolve-nested-selector" import { utils } from "stylelint" import { hasInterpolatingAmpersand, isStandardRule, isStandardSelector, parseSelector, namespace, } from "../../utils" export const ruleName = namespace("percent-placeholder-pattern") export const messages = utils.ruleMessages(ruleName, { expected: placeholder => `Expected %-placeholder "%${placeholder}" to match specified pattern`, }) export default function (pattern) { return (root, result) => { const validOptions = utils.validateOptions(result, ruleName, { actual: pattern, possible: [ isRegExp, isString ], }) if (!validOptions) { return } const placeholderPattern = (isString(pattern)) ? new RegExp(pattern) : pattern // Checking placeholder definitions (looking among regular rules) root.walkRules(rule => { const { selector } = rule // Just a shorthand for calling `parseSelector` function parse(selector) { parseSelector(selector, result, rule, s => checkSelector(s, rule)) } // If it's a custom prop or a less mixin if (!isStandardRule(rule)) { return } // If the selector has interpolation if (!isStandardSelector(selector)) { return } // Nested selectors are processed in steps, as nesting levels are resolved. // Here we skip processing intermediate parts of selectors (to process only fully resolved selectors) // if (rule.nodes.some(node => node.type === "rule" || node.type === "atrule")) { return } // Only resolve selectors that have an interpolating "&" if (hasInterpolatingAmpersand(selector)) { resolveNestedSelector(selector, rule).forEach(parse) } else { parse(selector) } }) function checkSelector(fullSelector, rule) { // postcss-selector-parser gives %placeholders' nodes a "tag" type fullSelector.walkTags(compoundSelector => { const { value, sourceIndex } = compoundSelector if (value[0] !== "%") { return } const placeholder = value.slice(1) if (placeholderPattern.test(placeholder)) { return } utils.report({ result, ruleName, message: messages.expected(placeholder), node: rule, index: sourceIndex, }) }) } } }