+++ /dev/null
-"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 mapLowercaseKeywordsToCamelCase = new Map();
-keywordSets.camelCaseKeywords.forEach(func => {
- mapLowercaseKeywordsToCamelCase.set(func.toLowerCase(), func);
-});
-
-const rule = function(expectation, options) {
- return (root, result) => {
- const validOptions = validateOptions(
- result,
- ruleName,
- {
- actual: expectation,
- possible: ["lower", "upper"]
- },
- {
- actual: options,
- possible: {
- ignoreProperties: [_.isString],
- ignoreKeywords: [_.isString]
- },
- optional: true
- }
- );
- if (!validOptions) {
- return;
- }
-
- root.walkDecls(decl => {
- const prop = decl.prop,
- value = decl.value;
-
- valueParser(value).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;
- }
-
- const keyword = node.value;
-
- // Ignore css variables, and hex values, and math operators, and sass interpolation
- if (
- node.type !== "word" ||
- !isStandardSyntaxValue(node.value) ||
- value.indexOf("#") !== -1 ||
- ignoredCharacters.has(keyword) ||
- getUnitFromValueNode(node)
- ) {
- return;
- }
-
- if (
- prop === "animation" &&
- !keywordSets.animationShorthandKeywords.has(valueLowerCase) &&
- !keywordSets.animationNameKeywords.has(valueLowerCase)
- ) {
- return;
- }
- if (
- prop === "animation-name" &&
- !keywordSets.animationNameKeywords.has(valueLowerCase)
- ) {
- return;
- }
- if (
- prop === "font" &&
- !keywordSets.fontShorthandKeywords.has(valueLowerCase) &&
- !keywordSets.fontFamilyKeywords.has(valueLowerCase)
- ) {
- return;
- }
- if (
- prop === "font-family" &&
- !keywordSets.fontFamilyKeywords.has(valueLowerCase)
- ) {
- return;
- }
- if (
- prop === "counter-increment" &&
- isCounterIncrementCustomIdentValue(valueLowerCase)
- ) {
- return;
- }
- if (
- prop === "counter-reset" &&
- isCounterResetCustomIdentValue(valueLowerCase)
- ) {
- return;
- }
- if (
- prop === "grid-row" &&
- !keywordSets.gridRowKeywords.has(valueLowerCase)
- ) {
- return;
- }
- if (
- prop === "grid-column" &&
- !keywordSets.gridColumnKeywords.has(valueLowerCase)
- ) {
- return;
- }
- if (
- prop === "grid-area" &&
- !keywordSets.gridAreaKeywords.has(valueLowerCase)
- ) {
- return;
- }
- if (
- prop === "list-style" &&
- !keywordSets.listStyleShorthandKeywords.has(valueLowerCase) &&
- !keywordSets.listStyleTypeKeywords.has(valueLowerCase)
- ) {
- return;
- }
- if (
- prop === "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;
- }
-
- report({
- message: messages.expected(keyword, expectedKeyword),
- node: decl,
- index: declarationValueIndex(decl) + node.sourceIndex,
- result,
- ruleName
- });
- });
- });
- };
-};
-
-rule.ruleName = ruleName;
-rule.messages = messages;
-module.exports = rule;