.gitignore added
[dotfiles/.git] / .config / coc / extensions / node_modules / coc-prettier / node_modules / stylelint / lib / rules / selector-pseudo-class-no-unknown / index.js
1 "use strict";
2
3 const _ = require("lodash");
4 const atRuleParamIndex = require("../../utils/atRuleParamIndex");
5 const isCustomSelector = require("../../utils/isCustomSelector");
6 const isStandardSyntaxAtRule = require("../../utils/isStandardSyntaxAtRule");
7 const isStandardSyntaxRule = require("../../utils/isStandardSyntaxRule");
8 const isStandardSyntaxSelector = require("../../utils/isStandardSyntaxSelector");
9 const keywordSets = require("../../reference/keywordSets");
10 const optionsMatches = require("../../utils/optionsMatches");
11 const parseSelector = require("../../utils/parseSelector");
12 const postcss = require("postcss");
13 const report = require("../../utils/report");
14 const ruleMessages = require("../../utils/ruleMessages");
15 const validateOptions = require("../../utils/validateOptions");
16
17 const ruleName = "selector-pseudo-class-no-unknown";
18
19 const messages = ruleMessages(ruleName, {
20   rejected: selector => `Unexpected unknown pseudo-class selector "${selector}"`
21 });
22
23 const rule = function(actual, options) {
24   return (root, result) => {
25     const validOptions = validateOptions(
26       result,
27       ruleName,
28       { actual },
29       {
30         actual: options,
31         possible: {
32           ignorePseudoClasses: [_.isString]
33         },
34         optional: true
35       }
36     );
37     if (!validOptions) {
38       return;
39     }
40
41     function check(selector, result, node) {
42       parseSelector(selector, result, node, selectorTree => {
43         selectorTree.walkPseudos(pseudoNode => {
44           const value = pseudoNode.value;
45
46           if (!isStandardSyntaxSelector(value)) {
47             return;
48           }
49
50           if (isCustomSelector(value)) {
51             return;
52           }
53
54           // Ignore pseudo-elements
55           if (value.slice(0, 2) === "::") {
56             return;
57           }
58
59           if (
60             optionsMatches(
61               options,
62               "ignorePseudoClasses",
63               pseudoNode.value.slice(1)
64             )
65           ) {
66             return;
67           }
68
69           let index = null;
70           const name = value.slice(1).toLowerCase();
71
72           if (node.type === "atrule" && node.name === "page") {
73             if (keywordSets.atRulePagePseudoClasses.has(name)) {
74               return;
75             }
76
77             index = atRuleParamIndex(node) + pseudoNode.sourceIndex;
78           } else {
79             if (
80               postcss.vendor.prefix(name) ||
81               keywordSets.pseudoClasses.has(name) ||
82               keywordSets.pseudoElements.has(name)
83             ) {
84               return;
85             }
86
87             const firstSelectorNode =
88               pseudoNode.parent && pseudoNode.parent.nodes
89                 ? pseudoNode.parent.nodes[0]
90                 : null;
91
92             if (
93               firstSelectorNode &&
94               firstSelectorNode.value.slice(0, 2) === "::"
95             ) {
96               const prevPseudoNodeValue = postcss.vendor.unprefixed(
97                 firstSelectorNode.value.toLowerCase().slice(2)
98               );
99
100               if (
101                 keywordSets.webkitProprietaryPseudoElements.has(
102                   prevPseudoNodeValue
103                 ) &&
104                 keywordSets.webkitProprietaryPseudoClasses.has(name)
105               ) {
106                 return;
107               }
108             }
109
110             index = pseudoNode.sourceIndex;
111           }
112
113           report({
114             message: messages.rejected(value),
115             node,
116             index,
117             ruleName,
118             result
119           });
120         });
121       });
122     }
123
124     root.walk(node => {
125       let selector = null;
126
127       if (node.type === "rule") {
128         if (!isStandardSyntaxRule(node)) {
129           return;
130         }
131
132         selector = node.selector;
133       } else if (
134         node.type === "atrule" &&
135         node.name === "page" &&
136         node.params
137       ) {
138         if (!isStandardSyntaxAtRule(node)) {
139           return;
140         }
141
142         selector = node.params;
143       }
144
145       // Return if selector empty, it is meaning node type is not a rule or a at-rule
146
147       if (!selector) {
148         return;
149       }
150
151       // Return early before parse if no pseudos for performance
152
153       if (selector.indexOf(":") === -1) {
154         return;
155       }
156
157       check(selector, result, node);
158     });
159   };
160 };
161
162 rule.ruleName = ruleName;
163 rule.messages = messages;
164 module.exports = rule;