UNPKG

2.88 kBJavaScriptView Raw
1'use strict';
2
3const _ = require('lodash');
4const htmlTags = require('html-tags');
5const isCustomElement = require('../../utils/isCustomElement');
6const isKeyframeSelector = require('../../utils/isKeyframeSelector');
7const isStandardSyntaxRule = require('../../utils/isStandardSyntaxRule');
8const isStandardSyntaxTypeSelector = require('../../utils/isStandardSyntaxTypeSelector');
9const keywordSets = require('../../reference/keywordSets');
10const mathMLTags = require('mathml-tag-names');
11const optionsMatches = require('../../utils/optionsMatches');
12const parseSelector = require('../../utils/parseSelector');
13const report = require('../../utils/report');
14const ruleMessages = require('../../utils/ruleMessages');
15const svgTags = require('svg-tags');
16const validateOptions = require('../../utils/validateOptions');
17
18const ruleName = 'selector-type-no-unknown';
19
20const messages = ruleMessages(ruleName, {
21 rejected: (selector) => `Unexpected unknown type selector "${selector}"`,
22});
23
24function rule(actual, options) {
25 return (root, result) => {
26 const validOptions = validateOptions(
27 result,
28 ruleName,
29 { actual },
30 {
31 actual: options,
32 possible: {
33 ignore: ['custom-elements', 'default-namespace'],
34 ignoreNamespaces: [_.isString, _.isRegExp],
35 ignoreTypes: [_.isString, _.isRegExp],
36 },
37 optional: true,
38 },
39 );
40
41 if (!validOptions) {
42 return;
43 }
44
45 root.walkRules((rule) => {
46 const selector = rule.selector;
47 const selectors = rule.selectors;
48
49 if (!isStandardSyntaxRule(rule)) {
50 return;
51 }
52
53 if (selectors.some((s) => isKeyframeSelector(s))) {
54 return;
55 }
56
57 parseSelector(selector, result, rule, (selectorTree) => {
58 selectorTree.walkTags((tagNode) => {
59 if (!isStandardSyntaxTypeSelector(tagNode)) {
60 return;
61 }
62
63 if (
64 optionsMatches(options, 'ignore', 'custom-elements') &&
65 isCustomElement(tagNode.value)
66 ) {
67 return;
68 }
69
70 if (
71 optionsMatches(options, 'ignore', 'default-namespace') &&
72 !(typeof tagNode.namespace === 'string')
73 ) {
74 return;
75 }
76
77 if (optionsMatches(options, 'ignoreNamespaces', tagNode.namespace)) {
78 return;
79 }
80
81 if (optionsMatches(options, 'ignoreTypes', tagNode.value)) {
82 return;
83 }
84
85 const tagName = tagNode.value;
86 const tagNameLowerCase = tagName.toLowerCase();
87
88 if (
89 htmlTags.includes(tagNameLowerCase) ||
90 // SVG tags are case-sensitive
91 svgTags.includes(tagName) ||
92 keywordSets.nonStandardHtmlTags.has(tagNameLowerCase) ||
93 mathMLTags.includes(tagNameLowerCase)
94 ) {
95 return;
96 }
97
98 report({
99 message: messages.rejected(tagName),
100 node: rule,
101 index: tagNode.sourceIndex,
102 ruleName,
103 result,
104 });
105 });
106 });
107 });
108 };
109}
110
111rule.ruleName = ruleName;
112rule.messages = messages;
113module.exports = rule;