.gitignore added
[dotfiles/.git] / .config / coc / extensions / node_modules / coc-prettier / node_modules / stylelint / lib / rules / declaration-block-no-duplicate-properties / index.js
1 "use strict";
2
3 const _ = require("lodash");
4 const isCustomProperty = require("../../utils/isCustomProperty");
5 const isStandardSyntaxProperty = require("../../utils/isStandardSyntaxProperty");
6 const optionsMatches = require("../../utils/optionsMatches");
7 const report = require("../../utils/report");
8 const ruleMessages = require("../../utils/ruleMessages");
9 const validateOptions = require("../../utils/validateOptions");
10
11 const ruleName = "declaration-block-no-duplicate-properties";
12
13 const messages = ruleMessages(ruleName, {
14   rejected: property => `Unexpected duplicate "${property}"`
15 });
16
17 const rule = function(on, options) {
18   return (root, result) => {
19     const validOptions = validateOptions(
20       result,
21       ruleName,
22       { actual: on },
23       {
24         actual: options,
25         possible: {
26           ignore: [
27             "consecutive-duplicates",
28             "consecutive-duplicates-with-different-values"
29           ],
30           ignoreProperties: [_.isString]
31         },
32         optional: true
33       }
34     );
35     if (!validOptions) {
36       return;
37     }
38
39     // In order to accommodate nested blocks (postcss-nested),
40     // we need to run a shallow loop (instead of eachDecl() or eachRule(),
41     // which loop recursively) and allow each nested block to accumulate
42     // its own list of properties -- so that a property in a nested rule
43     // does not conflict with the same property in the parent rule
44     root.each(node => {
45       if (node.type === "rule" || node.type === "atrule") {
46         checkRulesInNode(node);
47       }
48     });
49
50     function checkRulesInNode(node) {
51       const decls = [];
52       const values = [];
53
54       node.each(child => {
55         if (child.nodes && child.nodes.length) {
56           checkRulesInNode(child);
57         }
58
59         if (child.type !== "decl") {
60           return;
61         }
62
63         const prop = child.prop;
64         const value = child.value;
65
66         if (!isStandardSyntaxProperty(prop)) {
67           return;
68         }
69         if (isCustomProperty(prop)) {
70           return;
71         }
72
73         // Return early if the property is to be ignored
74         if (optionsMatches(options, "ignoreProperties", prop)) {
75           return;
76         }
77
78         // Ignore the src property as commonly duplicated in at-fontface
79         if (prop.toLowerCase() === "src") {
80           return;
81         }
82
83         const indexDuplicate = decls.indexOf(prop.toLowerCase());
84
85         if (indexDuplicate !== -1) {
86           if (
87             optionsMatches(
88               options,
89               "ignore",
90               "consecutive-duplicates-with-different-values"
91             )
92           ) {
93             // if duplicates are not consecutive
94             if (indexDuplicate !== decls.length - 1) {
95               report({
96                 message: messages.rejected(prop),
97                 node: child,
98                 result,
99                 ruleName
100               });
101               return;
102             }
103             // if values of consecutive duplicates are equal
104             if (value === values[indexDuplicate]) {
105               report({
106                 message: messages.rejected(value),
107                 node: child,
108                 result,
109                 ruleName
110               });
111               return;
112             }
113             return;
114           }
115
116           if (
117             optionsMatches(options, "ignore", "consecutive-duplicates") &&
118             indexDuplicate === decls.length - 1
119           ) {
120             return;
121           }
122
123           report({
124             message: messages.rejected(prop),
125             node: child,
126             result,
127             ruleName
128           });
129         }
130
131         decls.push(prop.toLowerCase());
132         values.push(value.toLowerCase());
133       });
134     }
135   };
136 };
137
138 rule.ruleName = ruleName;
139 rule.messages = messages;
140 module.exports = rule;