.gitignore added
[dotfiles/.git] / .config / coc / extensions / node_modules / coc-prettier / node_modules / stylelint / lib / rules / unit-blacklist / index.js
1 "use strict";
2
3 const _ = require("lodash");
4 const atRuleParamIndex = require("../../utils/atRuleParamIndex");
5 const declarationValueIndex = require("../../utils/declarationValueIndex");
6 const getUnitFromValueNode = require("../../utils/getUnitFromValueNode");
7 const mediaParser = require("postcss-media-query-parser").default;
8 const optionsMatches = require("../../utils/optionsMatches");
9 const report = require("../../utils/report");
10 const ruleMessages = require("../../utils/ruleMessages");
11 const validateObjectWithStringArrayProps = require("../../utils/validateObjectWithStringArrayProps");
12 const validateOptions = require("../../utils/validateOptions");
13 const valueParser = require("postcss-value-parser");
14
15 const ruleName = "unit-blacklist";
16
17 const messages = ruleMessages(ruleName, {
18   rejected: unit => `Unexpected unit "${unit}"`
19 });
20
21 // a function to retrieve only the media feature name
22 // could be externalized in an utils function if needed in other code
23 const getMediaFeatureName = mediaFeatureNode => {
24   const value = mediaFeatureNode.value.toLowerCase();
25
26   return /((-?\w*)*)/i.exec(value)[1];
27 };
28
29 const rule = function(blacklistInput, options) {
30   const blacklist = [].concat(blacklistInput);
31   return (root, result) => {
32     const validOptions = validateOptions(
33       result,
34       ruleName,
35       {
36         actual: blacklist,
37         possible: [_.isString]
38       },
39       {
40         optional: true,
41         actual: options,
42         possible: {
43           ignoreProperties: validateObjectWithStringArrayProps,
44           ignoreMediaFeatureNames: validateObjectWithStringArrayProps
45         }
46       }
47     );
48     if (!validOptions) {
49       return;
50     }
51
52     function check(node, nodeIndex, valueNode, input, option) {
53       const unit = getUnitFromValueNode(valueNode);
54
55       // There is not unit or it is not configured as a violation
56       if (!unit || (unit && blacklist.indexOf(unit.toLowerCase()) === -1)) {
57         return;
58       }
59
60       // The unit has an ignore option for the specific input
61       if (optionsMatches(option, unit.toLowerCase(), input)) {
62         return;
63       }
64
65       report({
66         index: nodeIndex + valueNode.sourceIndex,
67         message: messages.rejected(unit),
68         node,
69         result,
70         ruleName
71       });
72     }
73
74     function checkMedia(node, value, getIndex) {
75       mediaParser(node.params).walk(/^media-feature$/i, mediaFeatureNode => {
76         const mediaName = getMediaFeatureName(mediaFeatureNode),
77           parentValue = mediaFeatureNode.parent.value;
78
79         valueParser(value).walk(function(valueNode) {
80           // Ignore all non-word valueNode and
81           // the values not included in the parentValue string
82           if (
83             valueNode.type !== "word" ||
84             !parentValue.includes(valueNode.value)
85           ) {
86             return;
87           }
88           check(
89             node,
90             getIndex(node),
91             valueNode,
92             mediaName,
93             options ? options.ignoreMediaFeatureNames : {}
94           );
95         });
96         return;
97       });
98     }
99
100     function checkDecl(node, value, getIndex) {
101       // make sure multiplication operations (*) are divided - not handled
102       // by postcss-value-parser
103       value = value.replace(/\*/g, ",");
104
105       valueParser(value).walk(function(valueNode) {
106         // Ignore wrong units within `url` function
107         if (
108           valueNode.type === "function" &&
109           valueNode.value.toLowerCase() === "url"
110         ) {
111           return false;
112         }
113         check(
114           node,
115           getIndex(node),
116           valueNode,
117           node.prop,
118           options ? options.ignoreProperties : {}
119         );
120       });
121     }
122
123     root.walkAtRules(/^media$/i, atRule =>
124       checkMedia(atRule, atRule.params, atRuleParamIndex)
125     );
126     root.walkDecls(decl => checkDecl(decl, decl.value, declarationValueIndex));
127   };
128 };
129
130 rule.primaryOptionArray = true;
131
132 rule.ruleName = ruleName;
133 rule.messages = messages;
134 module.exports = rule;