.gitignore added
[dotfiles/.git] / .config / coc / extensions / node_modules / coc-prettier / node_modules / stylelint / lib / rules / color-named / index.js
1 "use strict";
2
3 const _ = require("lodash");
4 const declarationValueIndex = require("../../utils/declarationValueIndex");
5 const isStandardSyntaxFunction = require("../../utils/isStandardSyntaxFunction");
6 const isStandardSyntaxValue = require("../../utils/isStandardSyntaxValue");
7 const keywordSets = require("../../reference/keywordSets");
8 const namedColorDataHex = require("../../reference/namedColorData");
9 const optionsMatches = require("../../utils/optionsMatches");
10 const propertySets = require("../../reference/propertySets");
11 const report = require("../../utils/report");
12 const ruleMessages = require("../../utils/ruleMessages");
13 const validateOptions = require("../../utils/validateOptions");
14 const valueParser = require("postcss-value-parser");
15
16 const generateColorFuncs = require("./generateColorFuncs");
17
18 const ruleName = "color-named";
19
20 const messages = ruleMessages(ruleName, {
21   expected: (named, original) => `Expected "${original}" to be "${named}"`,
22   rejected: named => `Unexpected named color "${named}"`
23 });
24
25 // Todo tested on case insensivity
26 const NODE_TYPES = ["word", "function"];
27
28 const rule = function(expectation, options) {
29   return (root, result) => {
30     const validOptions = validateOptions(
31       result,
32       ruleName,
33       {
34         actual: expectation,
35         possible: ["never", "always-where-possible"]
36       },
37       {
38         actual: options,
39         possible: {
40           ignoreProperties: [_.isString],
41           ignore: ["inside-function"]
42         },
43         optional: true
44       }
45     );
46
47     if (!validOptions) {
48       return;
49     }
50
51     const namedColors = Object.keys(namedColorDataHex);
52     const namedColorData = {};
53     namedColors.forEach(name => {
54       const hex = namedColorDataHex[name];
55       namedColorData[name] = {
56         hex,
57         func: generateColorFuncs(hex[0])
58       };
59     });
60
61     root.walkDecls(decl => {
62       if (propertySets.acceptCustomIdents.has(decl.prop)) {
63         return;
64       }
65
66       // Return early if the property is to be ignored
67       if (optionsMatches(options, "ignoreProperties", decl.prop)) {
68         return;
69       }
70
71       valueParser(decl.value).walk(node => {
72         const value = node.value,
73           type = node.type,
74           sourceIndex = node.sourceIndex;
75
76         if (
77           optionsMatches(options, "ignore", "inside-function") &&
78           type === "function"
79         ) {
80           return false;
81         }
82
83         if (!isStandardSyntaxFunction(node)) {
84           return false;
85         }
86
87         if (!isStandardSyntaxValue(value)) {
88           return;
89         }
90         // Return early if neither a word nor a function
91         if (NODE_TYPES.indexOf(type) === -1) {
92           return;
93         }
94
95         // Check for named colors for "never" option
96         if (
97           expectation === "never" &&
98           type === "word" &&
99           namedColors.indexOf(value.toLowerCase()) !== -1
100         ) {
101           complain(
102             messages.rejected(value),
103             decl,
104             declarationValueIndex(decl) + sourceIndex
105           );
106           return;
107         }
108
109         // Check "always-where-possible" option ...
110         if (expectation !== "always-where-possible") {
111           return;
112         }
113
114         // First by checking for alternative color function representations ...
115         if (
116           type === "function" &&
117           keywordSets.colorFunctionNames.has(value.toLowerCase())
118         ) {
119           // Remove all spaces to match what's in `representations`
120           const normalizedFunctionString = valueParser
121             .stringify(node)
122             .replace(/\s+/g, "");
123           let namedColor;
124           for (let i = 0, l = namedColors.length; i < l; i++) {
125             namedColor = namedColors[i];
126             if (
127               namedColorData[namedColor].func.indexOf(
128                 normalizedFunctionString.toLowerCase()
129               ) !== -1
130             ) {
131               complain(
132                 messages.expected(namedColor, normalizedFunctionString),
133                 decl,
134                 declarationValueIndex(decl) + sourceIndex
135               );
136               return; // Exit as soon as a problem is found
137             }
138           }
139           return;
140         }
141
142         // Then by checking for alternative hex representations
143         let namedColor;
144         for (let i = 0, l = namedColors.length; i < l; i++) {
145           namedColor = namedColors[i];
146           if (
147             namedColorData[namedColor].hex.indexOf(value.toLowerCase()) !== -1
148           ) {
149             complain(
150               messages.expected(namedColor, value),
151               decl,
152               declarationValueIndex(decl) + sourceIndex
153             );
154             return; // Exit as soon as a problem is found
155           }
156         }
157       });
158     });
159
160     function complain(message, node, index) {
161       report({
162         result,
163         ruleName,
164         message,
165         node,
166         index
167       });
168     }
169   };
170 };
171
172 rule.ruleName = ruleName;
173 rule.messages = messages;
174 module.exports = rule;