| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196 | 'use strict';const eachDeclarationBlock = require('../../utils/eachDeclarationBlock');const isCustomProperty = require('../../utils/isCustomProperty');const isStandardSyntaxProperty = require('../../utils/isStandardSyntaxProperty');const optionsMatches = require('../../utils/optionsMatches');const report = require('../../utils/report');const ruleMessages = require('../../utils/ruleMessages');const validateOptions = require('../../utils/validateOptions');const { isString } = require('../../utils/validateTypes');const vendor = require('../../utils/vendor');const ruleName = 'declaration-block-no-duplicate-properties';const messages = ruleMessages(ruleName, {	rejected: (property) => `Unexpected duplicate "${property}"`,});const meta = {	url: 'https://stylelint.io/user-guide/rules/declaration-block-no-duplicate-properties',	fixable: true,};/** @type {import('stylelint').Rule} */const rule = (primary, secondaryOptions, context) => {	return (root, result) => {		const validOptions = validateOptions(			result,			ruleName,			{ actual: primary },			{				actual: secondaryOptions,				possible: {					ignore: [						'consecutive-duplicates',						'consecutive-duplicates-with-different-values',						'consecutive-duplicates-with-same-prefixless-values',					],					ignoreProperties: [isString],				},				optional: true,			},		);		if (!validOptions) {			return;		}		const ignoreDuplicates = optionsMatches(secondaryOptions, 'ignore', 'consecutive-duplicates');		const ignoreDiffValues = optionsMatches(			secondaryOptions,			'ignore',			'consecutive-duplicates-with-different-values',		);		const ignorePrefixlessSameValues = optionsMatches(			secondaryOptions,			'ignore',			'consecutive-duplicates-with-same-prefixless-values',		);		eachDeclarationBlock(root, (eachDecl) => {			/** @type {import('postcss').Declaration[]} */			const decls = [];			eachDecl((decl) => {				const prop = decl.prop;				const lowerProp = decl.prop.toLowerCase();				const value = decl.value;				if (!isStandardSyntaxProperty(prop)) {					return;				}				if (isCustomProperty(prop)) {					return;				}				// Return early if the property is to be ignored				if (optionsMatches(secondaryOptions, 'ignoreProperties', prop)) {					return;				}				// Ignore the src property as commonly duplicated in at-fontface				if (lowerProp === 'src') {					return;				}				const indexDuplicate = decls.findIndex((d) => d.prop.toLowerCase() === lowerProp);				if (indexDuplicate !== -1) {					if (ignoreDiffValues || ignorePrefixlessSameValues) {						// fails if duplicates are not consecutive						if (indexDuplicate !== decls.length - 1) {							if (context.fix) {								removePreviousDuplicate(decls, lowerProp);								return;							}							report({								message: messages.rejected(prop),								node: decl,								result,								ruleName,								word: prop,							});							return;						}						const duplicateDecl = decls[indexDuplicate];						const duplicateValue = duplicateDecl ? duplicateDecl.value : '';						if (ignorePrefixlessSameValues) {							// fails if values of consecutive, unprefixed duplicates are equal							if (vendor.unprefixed(value) !== vendor.unprefixed(duplicateValue)) {								if (context.fix) {									removePreviousDuplicate(decls, lowerProp);									return;								}								report({									message: messages.rejected(prop),									node: decl,									result,									ruleName,									word: prop,								});								return;							}						}						// fails if values of consecutive duplicates are equal						if (value === duplicateValue) {							if (context.fix) {								removePreviousDuplicate(decls, lowerProp);								return;							}							report({								message: messages.rejected(prop),								node: decl,								result,								ruleName,								word: prop,							});							return;						}						return;					}					if (ignoreDuplicates && indexDuplicate === decls.length - 1) {						return;					}					if (context.fix) {						removePreviousDuplicate(decls, lowerProp);						return;					}					report({						message: messages.rejected(prop),						node: decl,						result,						ruleName,						word: prop,					});				}				decls.push(decl);			});		});	};};/** * @param {import('postcss').Declaration[]} declarations * @param {string} lowerProperty * @returns {void} * */function removePreviousDuplicate(declarations, lowerProperty) {	const declToRemove = declarations.find((d) => d.prop.toLowerCase() === lowerProperty);	if (declToRemove) declToRemove.remove();}rule.ruleName = ruleName;rule.messages = messages;rule.meta = meta;module.exports = rule;
 |