@html-eslint/eslint-plugin 0.46.2 → 0.47.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/rules/index.js +2 -0
- package/lib/rules/no-restricted-tags.js +138 -0
- package/lib/rules/no-skip-heading-levels.js +1 -1
- package/lib/rules/utils/baseline.js +11 -10
- package/package.json +7 -7
- package/types/rules/no-restricted-tags.d.ts +11 -0
- package/types/rules/no-restricted-tags.d.ts.map +1 -0
- package/types/rules/utils/baseline.d.ts.map +1 -1
package/lib/rules/index.js
CHANGED
|
@@ -52,6 +52,7 @@ const noEmptyHeadings = require("./no-empty-headings");
|
|
|
52
52
|
const noInvalidEntity = require("./no-invalid-entity");
|
|
53
53
|
const noDuplicateInHead = require("./no-duplicate-in-head");
|
|
54
54
|
const noIneffectiveAttrs = require("./no-ineffective-attrs");
|
|
55
|
+
const noRestrictedTags = require("./no-restricted-tags");
|
|
55
56
|
// import new rule here ↑
|
|
56
57
|
// DO NOT REMOVE THIS COMMENT
|
|
57
58
|
|
|
@@ -110,6 +111,7 @@ const rules = {
|
|
|
110
111
|
"no-invalid-entity": noInvalidEntity,
|
|
111
112
|
"no-duplicate-in-head": noDuplicateInHead,
|
|
112
113
|
"no-ineffective-attrs": noIneffectiveAttrs,
|
|
114
|
+
"no-restricted-tags": noRestrictedTags,
|
|
113
115
|
// export new rule here ↑
|
|
114
116
|
// DO NOT REMOVE THIS COMMENT
|
|
115
117
|
};
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @import {StyleTag, Tag, ScriptTag} from "@html-eslint/types";
|
|
3
|
+
* @import {RuleModule} from "../types";
|
|
4
|
+
* @typedef {{tagPatterns: string[], message?: string}[]} Options
|
|
5
|
+
*
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const { NODE_TYPES } = require("@html-eslint/parser");
|
|
9
|
+
const { RULE_CATEGORY } = require("../constants");
|
|
10
|
+
const { createVisitors } = require("./utils/visitors");
|
|
11
|
+
const { getRuleUrl } = require("./utils/rule");
|
|
12
|
+
|
|
13
|
+
const MESSAGE_IDS = {
|
|
14
|
+
RESTRICTED: "restricted",
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* @type {RuleModule<Options>}
|
|
19
|
+
*/
|
|
20
|
+
module.exports = {
|
|
21
|
+
meta: {
|
|
22
|
+
type: "code",
|
|
23
|
+
|
|
24
|
+
docs: {
|
|
25
|
+
description: "Disallow specified tags",
|
|
26
|
+
category: RULE_CATEGORY.BEST_PRACTICE,
|
|
27
|
+
recommended: false,
|
|
28
|
+
url: getRuleUrl("no-restricted-tags"),
|
|
29
|
+
},
|
|
30
|
+
|
|
31
|
+
fixable: null,
|
|
32
|
+
schema: {
|
|
33
|
+
type: "array",
|
|
34
|
+
|
|
35
|
+
items: {
|
|
36
|
+
type: "object",
|
|
37
|
+
required: ["tagPatterns"],
|
|
38
|
+
properties: {
|
|
39
|
+
tagPatterns: {
|
|
40
|
+
type: "array",
|
|
41
|
+
items: {
|
|
42
|
+
type: "string",
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
message: {
|
|
46
|
+
type: "string",
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
additionalProperties: false,
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
messages: {
|
|
53
|
+
[MESSAGE_IDS.RESTRICTED]: "'{{tag}}' tag is restricted from being used.",
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
|
|
57
|
+
create(context) {
|
|
58
|
+
/**
|
|
59
|
+
* @type {Options}
|
|
60
|
+
*/
|
|
61
|
+
const options = context.options;
|
|
62
|
+
const checkers = options.map((option) => new PatternChecker(option));
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* @param {Tag | StyleTag | ScriptTag} node
|
|
66
|
+
*/
|
|
67
|
+
function check(node) {
|
|
68
|
+
const tagName =
|
|
69
|
+
node.type === NODE_TYPES.Tag
|
|
70
|
+
? node.name
|
|
71
|
+
: node.type === NODE_TYPES.ScriptTag
|
|
72
|
+
? "script"
|
|
73
|
+
: "style";
|
|
74
|
+
|
|
75
|
+
const matched = checkers.find((checker) => checker.test(tagName));
|
|
76
|
+
|
|
77
|
+
if (!matched) {
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* @type {{node: Tag | StyleTag | ScriptTag, message: string, messageId?: string}}
|
|
83
|
+
*/
|
|
84
|
+
const result = {
|
|
85
|
+
node: node,
|
|
86
|
+
message: "",
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
const customMessage = matched.getMessage();
|
|
90
|
+
|
|
91
|
+
if (customMessage) {
|
|
92
|
+
result.message = customMessage;
|
|
93
|
+
} else {
|
|
94
|
+
result.messageId = MESSAGE_IDS.RESTRICTED;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
context.report({
|
|
98
|
+
...result,
|
|
99
|
+
data: { tag: tagName },
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
return createVisitors(context, {
|
|
104
|
+
Tag: check,
|
|
105
|
+
StyleTag: check,
|
|
106
|
+
ScriptTag: check,
|
|
107
|
+
});
|
|
108
|
+
},
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
class PatternChecker {
|
|
112
|
+
/**
|
|
113
|
+
* @param {Options[number]} option
|
|
114
|
+
*/
|
|
115
|
+
constructor(option) {
|
|
116
|
+
this.option = option;
|
|
117
|
+
this.tagRegExps = option.tagPatterns.map(
|
|
118
|
+
(pattern) => new RegExp(pattern, "u")
|
|
119
|
+
);
|
|
120
|
+
this.message = option.message;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* @param {string} tagName
|
|
125
|
+
* @returns {boolean}
|
|
126
|
+
*/
|
|
127
|
+
test(tagName) {
|
|
128
|
+
const result = this.tagRegExps.some((exp) => exp.test(tagName));
|
|
129
|
+
return result;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* @returns {string}
|
|
134
|
+
*/
|
|
135
|
+
getMessage() {
|
|
136
|
+
return this.message || "";
|
|
137
|
+
}
|
|
138
|
+
}
|
|
@@ -49,7 +49,6 @@ const elements = new Map([
|
|
|
49
49
|
["article", "10:2015"],
|
|
50
50
|
["aside", "10:2015"],
|
|
51
51
|
["audio", "10:2015"],
|
|
52
|
-
["audio.autoplay", "0:"],
|
|
53
52
|
["audio.controls", "10:2015"],
|
|
54
53
|
["audio.controlslist", "0:"],
|
|
55
54
|
["audio.crossorigin", "10:2020"],
|
|
@@ -72,6 +71,7 @@ const elements = new Map([
|
|
|
72
71
|
["br", "10:2015"],
|
|
73
72
|
["button", "10:2015"],
|
|
74
73
|
["button.command", "0:"],
|
|
74
|
+
["button.command.request-close", "0:"],
|
|
75
75
|
["button.commandfor", "0:"],
|
|
76
76
|
["button.disabled", "10:2015"],
|
|
77
77
|
["button.form", "10:2017"],
|
|
@@ -97,7 +97,7 @@ const elements = new Map([
|
|
|
97
97
|
["col.align", "0:"],
|
|
98
98
|
["col.char", "0:"],
|
|
99
99
|
["col.charoff", "0:"],
|
|
100
|
-
["col.span", "
|
|
100
|
+
["col.span", "0:"],
|
|
101
101
|
["col.valign", "0:"],
|
|
102
102
|
["col.width", "0:"],
|
|
103
103
|
["colgroup", "10:2015"],
|
|
@@ -149,7 +149,7 @@ const elements = new Map([
|
|
|
149
149
|
["form.method", "10:2015"],
|
|
150
150
|
["form.name", "10:2015"],
|
|
151
151
|
["form.novalidate", "10:2017"],
|
|
152
|
-
["form.rel", "
|
|
152
|
+
["form.rel", "10:2023"],
|
|
153
153
|
["form.target", "10:2015"],
|
|
154
154
|
["h1", "10:2015"],
|
|
155
155
|
["h1.no_ua_styles_in_article_aside_nav_section", "0:"],
|
|
@@ -329,7 +329,7 @@ const elements = new Map([
|
|
|
329
329
|
["link.rel", "10:2015"],
|
|
330
330
|
["link.rel.alternate_stylesheet", "0:"],
|
|
331
331
|
["link.rel.compression-dictionary", "0:"],
|
|
332
|
-
["link.rel.dns-prefetch", "
|
|
332
|
+
["link.rel.dns-prefetch", "5:2025"],
|
|
333
333
|
["link.rel.expect", "0:"],
|
|
334
334
|
["link.rel.manifest", "0:"],
|
|
335
335
|
["link.rel.modulepreload", "5:2023"],
|
|
@@ -421,7 +421,7 @@ const elements = new Map([
|
|
|
421
421
|
["script.referrerpolicy.unsafe-url", "0:"],
|
|
422
422
|
["script.src", "10:2015"],
|
|
423
423
|
["script.type", "10:2015"],
|
|
424
|
-
["script.type.importmap", "
|
|
424
|
+
["script.type.importmap", "10:2023"],
|
|
425
425
|
["script.type.module", "10:2018"],
|
|
426
426
|
["script.type.speculationrules", "0:"],
|
|
427
427
|
["script.type.speculationrules.eagerness", "0:"],
|
|
@@ -502,8 +502,8 @@ const elements = new Map([
|
|
|
502
502
|
["td.valign", "0:"],
|
|
503
503
|
["td.width", "0:"],
|
|
504
504
|
["template", "10:2015"],
|
|
505
|
-
["template.shadowrootclonable", "
|
|
506
|
-
["template.shadowrootdelegatesfocus", "
|
|
505
|
+
["template.shadowrootclonable", "5:2024"],
|
|
506
|
+
["template.shadowrootdelegatesfocus", "5:2024"],
|
|
507
507
|
["template.shadowrootmode", "5:2024"],
|
|
508
508
|
["template.shadowrootserializable", "0:"],
|
|
509
509
|
["textarea", "10:2015"],
|
|
@@ -577,6 +577,7 @@ const elements = new Map([
|
|
|
577
577
|
["video.height", "10:2015"],
|
|
578
578
|
["video.loop", "10:2015"],
|
|
579
579
|
["video.muted", "10:2015"],
|
|
580
|
+
["video.playsinline", "0:"],
|
|
580
581
|
["video.poster", "10:2015"],
|
|
581
582
|
["video.preload", "10:2015"],
|
|
582
583
|
["video.src", "10:2015"],
|
|
@@ -587,12 +588,12 @@ const globalAttributes = new Map([
|
|
|
587
588
|
["accesskey", "10:2015"],
|
|
588
589
|
["autocapitalize", "0:"],
|
|
589
590
|
["autocorrect", "0:"],
|
|
590
|
-
["autofocus", "
|
|
591
|
+
["autofocus", "10:2023"],
|
|
591
592
|
["contenteditable", "10:2015"],
|
|
592
593
|
["contenteditable.plaintext-only", "5:2025"],
|
|
593
594
|
["enterkeyhint", "10:2021"],
|
|
594
595
|
["exportparts", "10:2020"],
|
|
595
|
-
["inert", "
|
|
596
|
+
["inert", "10:2023"],
|
|
596
597
|
["inert.ignores_find_in_page", "0:"],
|
|
597
598
|
["inputmode", "10:2021"],
|
|
598
599
|
["is", "0:"],
|
|
@@ -608,7 +609,7 @@ const globalAttributes = new Map([
|
|
|
608
609
|
["tabindex", "10:2015"],
|
|
609
610
|
["title", "10:2015"],
|
|
610
611
|
["title.multi-line_titles", "10:2018"],
|
|
611
|
-
["translate", "
|
|
612
|
+
["translate", "10:2023"],
|
|
612
613
|
["virtualkeyboardpolicy", "0:"],
|
|
613
614
|
["writingsuggestions", "0:"],
|
|
614
615
|
]);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@html-eslint/eslint-plugin",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.47.1",
|
|
4
4
|
"type": "commonjs",
|
|
5
5
|
"description": "ESLint plugin for HTML",
|
|
6
6
|
"author": "yeonjuan",
|
|
@@ -40,10 +40,10 @@
|
|
|
40
40
|
],
|
|
41
41
|
"dependencies": {
|
|
42
42
|
"@eslint/plugin-kit": "^0.3.1",
|
|
43
|
-
"@html-eslint/parser": "^0.
|
|
44
|
-
"@html-eslint/template-parser": "^0.
|
|
45
|
-
"@html-eslint/template-syntax-parser": "^0.
|
|
46
|
-
"@html-eslint/types": "^0.
|
|
43
|
+
"@html-eslint/parser": "^0.47.1",
|
|
44
|
+
"@html-eslint/template-parser": "^0.47.1",
|
|
45
|
+
"@html-eslint/template-syntax-parser": "^0.47.1",
|
|
46
|
+
"@html-eslint/types": "^0.47.1"
|
|
47
47
|
},
|
|
48
48
|
"peerDependencies": {
|
|
49
49
|
"eslint": "^8.0.0 || ^9.0.0"
|
|
@@ -51,7 +51,7 @@
|
|
|
51
51
|
"devDependencies": {
|
|
52
52
|
"@eslint/core": "^0.14.0",
|
|
53
53
|
"@types/estree": "^0.0.47",
|
|
54
|
-
"es-html-parser": "0.3.
|
|
54
|
+
"es-html-parser": "0.3.1",
|
|
55
55
|
"eslint": "^9.27.0",
|
|
56
56
|
"espree": "^10.3.0",
|
|
57
57
|
"typescript": "^5.8.3"
|
|
@@ -59,5 +59,5 @@
|
|
|
59
59
|
"engines": {
|
|
60
60
|
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
|
61
61
|
},
|
|
62
|
-
"gitHead": "
|
|
62
|
+
"gitHead": "9f998c473f62f6e86b8c1d8cc30015bea04ddac4"
|
|
63
63
|
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
declare namespace _exports {
|
|
2
|
+
export { Options };
|
|
3
|
+
}
|
|
4
|
+
declare const _exports: RuleModule<Options>;
|
|
5
|
+
export = _exports;
|
|
6
|
+
type Options = {
|
|
7
|
+
tagPatterns: string[];
|
|
8
|
+
message?: string;
|
|
9
|
+
}[];
|
|
10
|
+
import type { RuleModule } from "../types";
|
|
11
|
+
//# sourceMappingURL=no-restricted-tags.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"no-restricted-tags.d.ts","sourceRoot":"","sources":["../../lib/rules/no-restricted-tags.js"],"names":[],"mappings":";;;wBAiBU,WAAW,OAAO,CAAC;;eAdhB;IAAC,WAAW,EAAE,MAAM,EAAE,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAC,EAAE;gCAD3B,UAAU"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"baseline.d.ts","sourceRoot":"","sources":["../../../lib/rules/utils/baseline.js"],"names":[],"mappings":"AAOA,
|
|
1
|
+
{"version":3,"file":"baseline.d.ts","sourceRoot":"","sources":["../../../lib/rules/utils/baseline.js"],"names":[],"mappings":"AAOA,2CAkkBG;AACH,mDA4BG;AAtmBH;;GAEG;AACH,4BAAsB,EAAE,CAAC;AACzB,2BAAqB,CAAC,CAAC;AACvB,6BAAuB,CAAC,CAAC"}
|