| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275 | 'use strict';const declarationValueIndex = require('../../utils/declarationValueIndex');const getDeclarationValue = require('../../utils/getDeclarationValue');const isSingleLineString = require('../../utils/isSingleLineString');const isStandardSyntaxFunction = require('../../utils/isStandardSyntaxFunction');const report = require('../../utils/report');const ruleMessages = require('../../utils/ruleMessages');const setDeclarationValue = require('../../utils/setDeclarationValue');const validateOptions = require('../../utils/validateOptions');const valueParser = require('postcss-value-parser');const ruleName = 'function-parentheses-newline-inside';const messages = ruleMessages(ruleName, {	expectedOpening: 'Expected newline after "("',	expectedClosing: 'Expected newline before ")"',	expectedOpeningMultiLine: 'Expected newline after "(" in a multi-line function',	rejectedOpeningMultiLine: 'Unexpected whitespace after "(" in a multi-line function',	expectedClosingMultiLine: 'Expected newline before ")" in a multi-line function',	rejectedClosingMultiLine: 'Unexpected whitespace before ")" in a multi-line function',});const meta = {	url: 'https://stylelint.io/user-guide/rules/function-parentheses-newline-inside',	fixable: true,};/** @type {import('stylelint').Rule} */const rule = (primary, _secondaryOptions, context) => {	return (root, result) => {		const validOptions = validateOptions(result, ruleName, {			actual: primary,			possible: ['always', 'always-multi-line', 'never-multi-line'],		});		if (!validOptions) {			return;		}		root.walkDecls((decl) => {			if (!decl.value.includes('(')) {				return;			}			let hasFixed = false;			const declValue = getDeclarationValue(decl);			const parsedValue = valueParser(declValue);			parsedValue.walk((valueNode) => {				if (valueNode.type !== 'function') {					return;				}				if (!isStandardSyntaxFunction(valueNode)) {					return;				}				const functionString = valueParser.stringify(valueNode);				const isMultiLine = !isSingleLineString(functionString);				const containsNewline = (/** @type {string} */ str) => str.includes('\n');				// Check opening ...				const openingIndex = valueNode.sourceIndex + valueNode.value.length + 1;				const checkBefore = getCheckBefore(valueNode);				if (primary === 'always' && !containsNewline(checkBefore)) {					if (context.fix) {						hasFixed = true;						fixBeforeForAlways(valueNode, context.newline || '');					} else {						complain(messages.expectedOpening, openingIndex);					}				}				if (isMultiLine && primary === 'always-multi-line' && !containsNewline(checkBefore)) {					if (context.fix) {						hasFixed = true;						fixBeforeForAlways(valueNode, context.newline || '');					} else {						complain(messages.expectedOpeningMultiLine, openingIndex);					}				}				if (isMultiLine && primary === 'never-multi-line' && checkBefore !== '') {					if (context.fix) {						hasFixed = true;						fixBeforeForNever(valueNode);					} else {						complain(messages.rejectedOpeningMultiLine, openingIndex);					}				}				// Check closing ...				const closingIndex = valueNode.sourceIndex + functionString.length - 2;				const checkAfter = getCheckAfter(valueNode);				if (primary === 'always' && !containsNewline(checkAfter)) {					if (context.fix) {						hasFixed = true;						fixAfterForAlways(valueNode, context.newline || '');					} else {						complain(messages.expectedClosing, closingIndex);					}				}				if (isMultiLine && primary === 'always-multi-line' && !containsNewline(checkAfter)) {					if (context.fix) {						hasFixed = true;						fixAfterForAlways(valueNode, context.newline || '');					} else {						complain(messages.expectedClosingMultiLine, closingIndex);					}				}				if (isMultiLine && primary === 'never-multi-line' && checkAfter !== '') {					if (context.fix) {						hasFixed = true;						fixAfterForNever(valueNode);					} else {						complain(messages.rejectedClosingMultiLine, closingIndex);					}				}			});			if (hasFixed) {				setDeclarationValue(decl, parsedValue.toString());			}			/**			 * @param {string} message			 * @param {number} offset			 */			function complain(message, offset) {				report({					ruleName,					result,					message,					node: decl,					index: declarationValueIndex(decl) + offset,				});			}		});	};};/** @typedef {import('postcss-value-parser').FunctionNode} FunctionNode *//** * @param {FunctionNode} valueNode */function getCheckBefore(valueNode) {	let before = valueNode.before;	for (const node of valueNode.nodes) {		if (node.type === 'comment') {			continue;		}		if (node.type === 'space') {			before += node.value;			continue;		}		break;	}	return before;}/** * @param {FunctionNode} valueNode */function getCheckAfter(valueNode) {	let after = '';	for (const node of [...valueNode.nodes].reverse()) {		if (node.type === 'comment') {			continue;		}		if (node.type === 'space') {			after = node.value + after;			continue;		}		break;	}	after += valueNode.after;	return after;}/** * @param {FunctionNode} valueNode * @param {string} newline */function fixBeforeForAlways(valueNode, newline) {	let target;	for (const node of valueNode.nodes) {		if (node.type === 'comment') {			continue;		}		if (node.type === 'space') {			target = node;			continue;		}		break;	}	if (target) {		target.value = newline + target.value;	} else {		valueNode.before = newline + valueNode.before;	}}/** * @param {FunctionNode} valueNode */function fixBeforeForNever(valueNode) {	valueNode.before = '';	for (const node of valueNode.nodes) {		if (node.type === 'comment') {			continue;		}		if (node.type === 'space') {			node.value = '';			continue;		}		break;	}}/** * @param {FunctionNode} valueNode * @param {string} newline */function fixAfterForAlways(valueNode, newline) {	valueNode.after = newline + valueNode.after;}/** * @param {FunctionNode} valueNode */function fixAfterForNever(valueNode) {	valueNode.after = '';	for (const node of [...valueNode.nodes].reverse()) {		if (node.type === 'comment') {			continue;		}		if (node.type === 'space') {			node.value = '';			continue;		}		break;	}}rule.ruleName = ruleName;rule.messages = messages;rule.meta = meta;module.exports = rule;
 |