UNPKG

3.01 kBJavaScriptView Raw
1// @ts-nocheck
2
3'use strict';
4
5const isKeyframeRule = require('../../utils/isKeyframeRule');
6const isStandardSyntaxRule = require('../../utils/isStandardSyntaxRule');
7const isStandardSyntaxSelector = require('../../utils/isStandardSyntaxSelector');
8const optionsMatches = require('../../utils/optionsMatches');
9const parseSelector = require('../../utils/parseSelector');
10const report = require('../../utils/report');
11const resolvedNestedSelector = require('postcss-resolve-nested-selector');
12const ruleMessages = require('../../utils/ruleMessages');
13const validateOptions = require('../../utils/validateOptions');
14
15const ruleName = 'selector-no-qualifying-type';
16
17const messages = ruleMessages(ruleName, {
18 rejected: 'Unexpected qualifying type selector',
19});
20
21const selectorCharacters = ['#', '.', '['];
22
23function isSelectorCharacters(value) {
24 return selectorCharacters.some((char) => value.includes(char));
25}
26
27function getRightNodes(node) {
28 const result = [];
29 let rightNode = node;
30
31 while ((rightNode = rightNode.next())) {
32 if (rightNode.type === 'combinator') {
33 break;
34 }
35
36 if (rightNode.type !== 'id' && rightNode.type !== 'class' && rightNode.type !== 'attribute') {
37 continue;
38 }
39
40 result.push(rightNode);
41 }
42
43 return result;
44}
45
46function rule(enabled, options) {
47 return (root, result) => {
48 const validOptions = validateOptions(
49 result,
50 ruleName,
51 {
52 actual: enabled,
53 possible: [true, false],
54 },
55 {
56 actual: options,
57 possible: {
58 ignore: ['attribute', 'class', 'id'],
59 },
60 optional: true,
61 },
62 );
63
64 if (!validOptions) {
65 return;
66 }
67
68 root.walkRules((rule) => {
69 if (!isStandardSyntaxRule(rule)) {
70 return;
71 }
72
73 if (isKeyframeRule(rule)) {
74 return;
75 }
76
77 if (!isSelectorCharacters(rule.selector)) {
78 return;
79 }
80
81 function checkSelector(selectorAST) {
82 selectorAST.walkTags((selector) => {
83 const selectorParent = selector.parent;
84
85 if (selectorParent.nodes.length === 1) {
86 return;
87 }
88
89 const selectorNodes = getRightNodes(selector);
90 const index = selector.sourceIndex;
91
92 selectorNodes.forEach((selectorNode) => {
93 if (selectorNode.type === 'id' && !optionsMatches(options, 'ignore', 'id')) {
94 complain(index);
95 }
96
97 if (selectorNode.type === 'class' && !optionsMatches(options, 'ignore', 'class')) {
98 complain(index);
99 }
100
101 if (
102 selectorNode.type === 'attribute' &&
103 !optionsMatches(options, 'ignore', 'attribute')
104 ) {
105 complain(index);
106 }
107 });
108 });
109 }
110
111 resolvedNestedSelector(rule.selector, rule).forEach((resolvedSelector) => {
112 if (!isStandardSyntaxSelector(resolvedSelector)) {
113 return;
114 }
115
116 parseSelector(resolvedSelector, result, rule, checkSelector);
117 });
118
119 function complain(index) {
120 report({
121 ruleName,
122 result,
123 node: rule,
124 message: messages.rejected,
125 index,
126 });
127 }
128 });
129 };
130}
131
132rule.ruleName = ruleName;
133rule.messages = messages;
134module.exports = rule;