.gitignore added
[dotfiles/.git] / .config / coc / extensions / node_modules / coc-prettier / node_modules / stylelint / lib / rules / number-leading-zero / index.js
1 "use strict";
2
3 const atRuleParamIndex = require("../../utils/atRuleParamIndex");
4 const declarationValueIndex = require("../../utils/declarationValueIndex");
5 const report = require("../../utils/report");
6 const ruleMessages = require("../../utils/ruleMessages");
7 const validateOptions = require("../../utils/validateOptions");
8 const valueParser = require("postcss-value-parser");
9
10 const ruleName = "number-leading-zero";
11
12 const messages = ruleMessages(ruleName, {
13   expected: "Expected a leading zero",
14   rejected: "Unexpected leading zero"
15 });
16
17 const rule = function(expectation, secondary, context) {
18   return (root, result) => {
19     const validOptions = validateOptions(result, ruleName, {
20       actual: expectation,
21       possible: ["always", "never"]
22     });
23     if (!validOptions) {
24       return;
25     }
26
27     root.walkAtRules(atRule => {
28       if (atRule.name.toLowerCase() === "import") {
29         return;
30       }
31
32       check(atRule, atRule.params, atRuleParamIndex);
33     });
34
35     root.walkDecls(decl => check(decl, decl.value, declarationValueIndex));
36
37     function check(node, value, getIndex) {
38       const neverFixPositions = [];
39       const alwaysFixPositions = [];
40
41       // Get out quickly if there are no periods
42       if (value.indexOf(".") === -1) {
43         return;
44       }
45
46       valueParser(value).walk(valueNode => {
47         // Ignore `url` function
48         if (
49           valueNode.type === "function" &&
50           valueNode.value.toLowerCase() === "url"
51         ) {
52           return false;
53         }
54
55         // Ignore strings, comments, etc
56         if (valueNode.type !== "word") {
57           return;
58         }
59
60         // Check leading zero
61         if (expectation === "always") {
62           const match = /(?:\D|^)(\.\d+)/.exec(valueNode.value);
63
64           if (match === null) {
65             return;
66           }
67           // The regexp above consists of 2 capturing groups (or capturing parentheses).
68           // We need the index of the second group. This makes sanse when we have "-.5" as an input
69           // for regex. And we need the index of ".5".
70           const capturingGroupIndex = match[0].length - match[1].length;
71
72           const index =
73             valueNode.sourceIndex + match.index + capturingGroupIndex;
74
75           if (context.fix) {
76             alwaysFixPositions.unshift({
77               index
78             });
79             return;
80           } else {
81             complain(messages.expected, node, getIndex(node) + index);
82           }
83         }
84
85         if (expectation === "never") {
86           const match = /(?:\D|^)(0+)(\.\d+)/.exec(valueNode.value);
87
88           if (match === null) {
89             return;
90           }
91
92           // The regexp above consists of 3 capturing groups (or capturing parentheses).
93           // We need the index of the second group. This makes sanse when we have "-00.5"
94           // as an input for regex. And we need the index of "00".
95           const capturingGroupIndex =
96             match[0].length - (match[1].length + match[2].length);
97
98           const index =
99             valueNode.sourceIndex + match.index + capturingGroupIndex;
100
101           if (context.fix) {
102             neverFixPositions.unshift({
103               startIndex: index,
104               // match[1].length is the length of our matched zero(s)
105               endIndex: index + match[1].length
106             });
107             return;
108           } else {
109             complain(messages.rejected, node, getIndex(node) + index);
110           }
111         }
112       });
113
114       if (alwaysFixPositions.length) {
115         alwaysFixPositions.forEach(function(fixPosition) {
116           const index = fixPosition.index;
117           if (node.type === "atrule") {
118             node.params = addLeadingZero(node.params, index);
119           } else {
120             node.value = addLeadingZero(node.value, index);
121           }
122         });
123       }
124
125       if (neverFixPositions.length) {
126         neverFixPositions.forEach(function(fixPosition) {
127           const startIndex = fixPosition.startIndex;
128           const endIndex = fixPosition.endIndex;
129           if (node.type === "atrule") {
130             node.params = removeLeadingZeros(node.params, startIndex, endIndex);
131           } else {
132             node.value = removeLeadingZeros(node.value, startIndex, endIndex);
133           }
134         });
135       }
136     }
137
138     function complain(message, node, index) {
139       report({
140         result,
141         ruleName,
142         message,
143         node,
144         index
145       });
146     }
147   };
148 };
149
150 function addLeadingZero(input, index) {
151   return input.slice(0, index) + "0" + input.slice(index);
152 }
153
154 function removeLeadingZeros(input, startIndex, endIndex) {
155   return input.slice(0, startIndex) + input.slice(endIndex);
156 }
157
158 rule.ruleName = ruleName;
159 rule.messages = messages;
160 module.exports = rule;