| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123 | 'use strict';const declarationValueIndex = require('../utils/declarationValueIndex');const getDeclarationValue = require('../utils/getDeclarationValue');const isStandardSyntaxFunction = require('../utils/isStandardSyntaxFunction');const report = require('../utils/report');const setDeclarationValue = require('../utils/setDeclarationValue');const valueParser = require('postcss-value-parser');/** @typedef {import('postcss-value-parser').Node} ValueParserNode *//** @typedef {import('postcss-value-parser').DivNode} ValueParserDivNode *//** @typedef {(args: { source: string, index: number, err: (message: string) => void }) => void} LocationChecker *//** * @param {{ *   root: import('postcss').Root, *   locationChecker: LocationChecker, *   fix: ((node: ValueParserDivNode, index: number, nodes: ValueParserNode[]) => boolean) | null, *   result: import('stylelint').PostcssResult, *   checkedRuleName: string, * }} opts */module.exports = function functionCommaSpaceChecker(opts) {	opts.root.walkDecls((decl) => {		const declValue = getDeclarationValue(decl);		let hasFixed;		const parsedValue = valueParser(declValue);		parsedValue.walk((valueNode) => {			if (valueNode.type !== 'function') {				return;			}			if (!isStandardSyntaxFunction(valueNode)) {				return;			}			// Ignore `url()` arguments, which may contain data URIs or other funky stuff			if (valueNode.value.toLowerCase() === 'url') {				return;			}			const argumentStrings = valueNode.nodes.map((node) => valueParser.stringify(node));			const functionArguments = (() => {				// Remove function name and parens				let result = valueNode.before + argumentStrings.join('') + valueNode.after;				// 1. Remove comments including preceding whitespace (when only succeeded by whitespace)				// 2. Remove all other comments, but leave adjacent whitespace intact				// eslint-disable-next-line regexp/no-dupe-disjunctions -- TODO: Possible to simplify the regex.				result = result.replace(/( *\/(\*.*\*\/(?!\S)|\/.*)|(\/(\*.*\*\/|\/.*)))/, '');				return result;			})();			/**			 * Gets the index of the comma for checking.			 * @param {ValueParserDivNode} commaNode The comma node			 * @param {number} nodeIndex The index of the comma node			 * @returns {number} The index of the comma for checking			 */			const getCommaCheckIndex = (commaNode, nodeIndex) => {				let commaBefore =					valueNode.before + argumentStrings.slice(0, nodeIndex).join('') + commaNode.before;				// 1. Remove comments including preceding whitespace (when only succeeded by whitespace)				// 2. Remove all other comments, but leave adjacent whitespace intact				// eslint-disable-next-line regexp/no-dupe-disjunctions -- TODO: Possible to simplify the regex.				commaBefore = commaBefore.replace(/( *\/(\*.*\*\/(?!\S)|\/.*)|(\/(\*.*\*\/|\/.*)))/, '');				return commaBefore.length;			};			/** @type {{ commaNode: ValueParserDivNode, checkIndex: number, nodeIndex: number }[]} */			const commaDataList = [];			for (const [nodeIndex, node] of valueNode.nodes.entries()) {				if (node.type !== 'div' || node.value !== ',') {					continue;				}				const checkIndex = getCommaCheckIndex(node, nodeIndex);				commaDataList.push({					commaNode: node,					checkIndex,					nodeIndex,				});			}			for (const { commaNode, checkIndex, nodeIndex } of commaDataList) {				opts.locationChecker({					source: functionArguments,					index: checkIndex,					err: (message) => {						const index =							declarationValueIndex(decl) + commaNode.sourceIndex + commaNode.before.length;						if (opts.fix && opts.fix(commaNode, nodeIndex, valueNode.nodes)) {							hasFixed = true;							return;						}						report({							index,							message,							node: decl,							result: opts.result,							ruleName: opts.checkedRuleName,						});					},				});			}		});		if (hasFixed) {			setDeclarationValue(decl, parsedValue.toString());		}	});};
 |