123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235 |
- // @ts-nocheck
- 'use strict';
- const _ = require('lodash');
- const declarationValueIndex = require('../../utils/declarationValueIndex');
- const getUnitFromValueNode = require('../../utils/getUnitFromValueNode');
- const isCounterIncrementCustomIdentValue = require('../../utils/isCounterIncrementCustomIdentValue');
- const isCounterResetCustomIdentValue = require('../../utils/isCounterResetCustomIdentValue');
- const isStandardSyntaxValue = require('../../utils/isStandardSyntaxValue');
- const keywordSets = require('../../reference/keywordSets');
- const matchesStringOrRegExp = require('../../utils/matchesStringOrRegExp');
- const report = require('../../utils/report');
- const ruleMessages = require('../../utils/ruleMessages');
- const validateOptions = require('../../utils/validateOptions');
- const valueParser = require('postcss-value-parser');
- const ruleName = 'value-keyword-case';
- const messages = ruleMessages(ruleName, {
- expected: (actual, expected) => `Expected "${actual}" to be "${expected}"`,
- });
- // Operators are interpreted as "words" by the value parser, so we want to make sure to ignore them.
- const ignoredCharacters = new Set(['+', '-', '/', '*', '%']);
- const gridRowProps = new Set(['grid-row', 'grid-row-start', 'grid-row-end']);
- const gridColumnProps = new Set(['grid-column', 'grid-column-start', 'grid-column-end']);
- const mapLowercaseKeywordsToCamelCase = new Map();
- keywordSets.camelCaseKeywords.forEach((func) => {
- mapLowercaseKeywordsToCamelCase.set(func.toLowerCase(), func);
- });
- function rule(expectation, options, context) {
- return (root, result) => {
- const validOptions = validateOptions(
- result,
- ruleName,
- {
- actual: expectation,
- possible: ['lower', 'upper'],
- },
- {
- actual: options,
- possible: {
- ignoreProperties: [_.isString, _.isRegExp],
- ignoreKeywords: [_.isString, _.isRegExp],
- ignoreFunctions: [_.isString, _.isRegExp],
- },
- optional: true,
- },
- );
- if (!validOptions) {
- return;
- }
- root.walkDecls((decl) => {
- const prop = decl.prop;
- const propLowerCase = decl.prop.toLowerCase();
- const value = decl.value;
- const parsed = valueParser(decl.raws.value ? decl.raws.value.raw : decl.value);
- let needFix = false;
- parsed.walk((node) => {
- const valueLowerCase = node.value.toLowerCase();
- // Ignore system colors
- if (keywordSets.systemColors.has(valueLowerCase)) {
- return;
- }
- // Ignore keywords within `url` and `var` function
- if (
- node.type === 'function' &&
- (valueLowerCase === 'url' ||
- valueLowerCase === 'var' ||
- valueLowerCase === 'counter' ||
- valueLowerCase === 'counters' ||
- valueLowerCase === 'attr')
- ) {
- return false;
- }
- // ignore keywords within ignoreFunctions functions
- const ignoreFunctions = (options && options.ignoreFunctions) || [];
- if (
- node.type === 'function' &&
- ignoreFunctions.length > 0 &&
- matchesStringOrRegExp(valueLowerCase, ignoreFunctions)
- ) {
- return false;
- }
- const keyword = node.value;
- // Ignore css variables, and hex values, and math operators, and sass interpolation
- if (
- node.type !== 'word' ||
- !isStandardSyntaxValue(node.value) ||
- value.includes('#') ||
- ignoredCharacters.has(keyword) ||
- getUnitFromValueNode(node)
- ) {
- return;
- }
- if (
- propLowerCase === 'animation' &&
- !keywordSets.animationShorthandKeywords.has(valueLowerCase) &&
- !keywordSets.animationNameKeywords.has(valueLowerCase)
- ) {
- return;
- }
- if (
- propLowerCase === 'animation-name' &&
- !keywordSets.animationNameKeywords.has(valueLowerCase)
- ) {
- return;
- }
- if (
- propLowerCase === 'font' &&
- !keywordSets.fontShorthandKeywords.has(valueLowerCase) &&
- !keywordSets.fontFamilyKeywords.has(valueLowerCase)
- ) {
- return;
- }
- if (
- propLowerCase === 'font-family' &&
- !keywordSets.fontFamilyKeywords.has(valueLowerCase)
- ) {
- return;
- }
- if (
- propLowerCase === 'counter-increment' &&
- isCounterIncrementCustomIdentValue(valueLowerCase)
- ) {
- return;
- }
- if (propLowerCase === 'counter-reset' && isCounterResetCustomIdentValue(valueLowerCase)) {
- return;
- }
- if (gridRowProps.has(propLowerCase) && !keywordSets.gridRowKeywords.has(valueLowerCase)) {
- return;
- }
- if (
- gridColumnProps.has(propLowerCase) &&
- !keywordSets.gridColumnKeywords.has(valueLowerCase)
- ) {
- return;
- }
- if (propLowerCase === 'grid-area' && !keywordSets.gridAreaKeywords.has(valueLowerCase)) {
- return;
- }
- if (
- propLowerCase === 'list-style' &&
- !keywordSets.listStyleShorthandKeywords.has(valueLowerCase) &&
- !keywordSets.listStyleTypeKeywords.has(valueLowerCase)
- ) {
- return;
- }
- if (
- propLowerCase === 'list-style-type' &&
- !keywordSets.listStyleTypeKeywords.has(valueLowerCase)
- ) {
- return;
- }
- const ignoreKeywords = (options && options.ignoreKeywords) || [];
- const ignoreProperties = (options && options.ignoreProperties) || [];
- if (ignoreKeywords.length > 0 && matchesStringOrRegExp(keyword, ignoreKeywords)) {
- return;
- }
- if (ignoreProperties.length > 0 && matchesStringOrRegExp(prop, ignoreProperties)) {
- return;
- }
- const keywordLowerCase = keyword.toLocaleLowerCase();
- let expectedKeyword = null;
- if (expectation === 'lower' && mapLowercaseKeywordsToCamelCase.has(keywordLowerCase)) {
- expectedKeyword = mapLowercaseKeywordsToCamelCase.get(keywordLowerCase);
- } else if (expectation === 'lower') {
- expectedKeyword = keyword.toLowerCase();
- } else {
- expectedKeyword = keyword.toUpperCase();
- }
- if (keyword === expectedKeyword) {
- return;
- }
- if (context.fix) {
- needFix = true;
- node.value = expectedKeyword;
- return;
- }
- report({
- message: messages.expected(keyword, expectedKeyword),
- node: decl,
- index: declarationValueIndex(decl) + node.sourceIndex,
- result,
- ruleName,
- });
- });
- if (context.fix && needFix) {
- decl.value = parsed.toString();
- }
- });
- };
- }
- rule.ruleName = ruleName;
- rule.messages = messages;
- module.exports = rule;
|