123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105 |
- 'use strict';
- const isStandardSyntaxCombinator = require('../utils/isStandardSyntaxCombinator');
- const isStandardSyntaxRule = require('../utils/isStandardSyntaxRule');
- const parseSelector = require('../utils/parseSelector');
- const report = require('../utils/report');
- /**
- * @typedef {(args: { source: string, index: number, errTarget: string, err: (message: string) => void }) => void} LocationChecker
- *
- * @param {{
- * root: import('postcss').Root,
- * result: import('stylelint').PostcssResult,
- * locationChecker: LocationChecker,
- * locationType: 'before' | 'after',
- * checkedRuleName: string,
- * fix: ((combinator: import('postcss-selector-parser').Combinator) => boolean) | null,
- * }} opts
- * @returns {void}
- */
- module.exports = function selectorCombinatorSpaceChecker(opts) {
- let hasFixed;
- opts.root.walkRules((rule) => {
- if (!isStandardSyntaxRule(rule)) {
- return;
- }
- hasFixed = false;
- const selector = rule.raws.selector ? rule.raws.selector.raw : rule.selector;
- const fixedSelector = parseSelector(selector, opts.result, rule, (selectorTree) => {
- selectorTree.walkCombinators((node) => {
- // Ignore non-standard combinators
- if (!isStandardSyntaxCombinator(node)) {
- return;
- }
- // Ignore spaced descendant combinator
- if (/\s/.test(node.value)) {
- return;
- }
- // Check the exist of node in prev of the combinator.
- // in case some that aren't the first begin with combinators (nesting syntax)
- if (opts.locationType === 'before' && !node.prev()) {
- return;
- }
- const parentParentNode = node.parent && node.parent.parent;
- // Ignore pseudo-classes selector like `.foo:nth-child(2n + 1) {}`
- if (parentParentNode && parentParentNode.type === 'pseudo') {
- return;
- }
- const sourceIndex = node.sourceIndex;
- const index =
- node.value.length > 1 && opts.locationType === 'before'
- ? sourceIndex
- : sourceIndex + node.value.length - 1;
- check(selector, node, index, rule, sourceIndex);
- });
- });
- if (hasFixed && fixedSelector) {
- if (!rule.raws.selector) {
- rule.selector = fixedSelector;
- } else {
- rule.raws.selector.raw = fixedSelector;
- }
- }
- });
- /**
- * @param {string} source
- * @param {import('postcss-selector-parser').Combinator} combinator
- * @param {number} index
- * @param {import('postcss').Node} node
- * @param {number} sourceIndex
- */
- function check(source, combinator, index, node, sourceIndex) {
- opts.locationChecker({
- source,
- index,
- errTarget: combinator.value,
- err: (message) => {
- if (opts.fix && opts.fix(combinator)) {
- hasFixed = true;
- return;
- }
- report({
- message,
- node,
- index: sourceIndex,
- result: opts.result,
- ruleName: opts.checkedRuleName,
- });
- },
- });
- }
- };
|