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");
17 const ruleName = "selector-pseudo-class-no-unknown";
19 const messages = ruleMessages(ruleName, {
20 rejected: selector => `Unexpected unknown pseudo-class selector "${selector}"`
23 const rule = function(actual, options) {
24 return (root, result) => {
25 const validOptions = validateOptions(
32 ignorePseudoClasses: [_.isString]
41 function check(selector, result, node) {
42 parseSelector(selector, result, node, selectorTree => {
43 selectorTree.walkPseudos(pseudoNode => {
44 const value = pseudoNode.value;
46 if (!isStandardSyntaxSelector(value)) {
50 if (isCustomSelector(value)) {
54 // Ignore pseudo-elements
55 if (value.slice(0, 2) === "::") {
62 "ignorePseudoClasses",
63 pseudoNode.value.slice(1)
70 const name = value.slice(1).toLowerCase();
72 if (node.type === "atrule" && node.name === "page") {
73 if (keywordSets.atRulePagePseudoClasses.has(name)) {
77 index = atRuleParamIndex(node) + pseudoNode.sourceIndex;
80 postcss.vendor.prefix(name) ||
81 keywordSets.pseudoClasses.has(name) ||
82 keywordSets.pseudoElements.has(name)
87 const firstSelectorNode =
88 pseudoNode.parent && pseudoNode.parent.nodes
89 ? pseudoNode.parent.nodes[0]
94 firstSelectorNode.value.slice(0, 2) === "::"
96 const prevPseudoNodeValue = postcss.vendor.unprefixed(
97 firstSelectorNode.value.toLowerCase().slice(2)
101 keywordSets.webkitProprietaryPseudoElements.has(
104 keywordSets.webkitProprietaryPseudoClasses.has(name)
110 index = pseudoNode.sourceIndex;
114 message: messages.rejected(value),
127 if (node.type === "rule") {
128 if (!isStandardSyntaxRule(node)) {
132 selector = node.selector;
134 node.type === "atrule" &&
135 node.name === "page" &&
138 if (!isStandardSyntaxAtRule(node)) {
142 selector = node.params;
145 // Return if selector empty, it is meaning node type is not a rule or a at-rule
151 // Return early before parse if no pseudos for performance
153 if (selector.indexOf(":") === -1) {
157 check(selector, result, node);
162 rule.ruleName = ruleName;
163 rule.messages = messages;
164 module.exports = rule;