@html-eslint/eslint-plugin 0.46.1 → 0.47.0
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/utils/baseline.js +7 -5
- package/package.json +6 -6
- 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
|
+
}
|
|
@@ -72,6 +72,7 @@ const elements = new Map([
|
|
|
72
72
|
["br", "10:2015"],
|
|
73
73
|
["button", "10:2015"],
|
|
74
74
|
["button.command", "0:"],
|
|
75
|
+
["button.command.request-close", "0:"],
|
|
75
76
|
["button.commandfor", "0:"],
|
|
76
77
|
["button.disabled", "10:2015"],
|
|
77
78
|
["button.form", "10:2017"],
|
|
@@ -149,7 +150,7 @@ const elements = new Map([
|
|
|
149
150
|
["form.method", "10:2015"],
|
|
150
151
|
["form.name", "10:2015"],
|
|
151
152
|
["form.novalidate", "10:2017"],
|
|
152
|
-
["form.rel", "
|
|
153
|
+
["form.rel", "10:2023"],
|
|
153
154
|
["form.target", "10:2015"],
|
|
154
155
|
["h1", "10:2015"],
|
|
155
156
|
["h1.no_ua_styles_in_article_aside_nav_section", "0:"],
|
|
@@ -329,7 +330,7 @@ const elements = new Map([
|
|
|
329
330
|
["link.rel", "10:2015"],
|
|
330
331
|
["link.rel.alternate_stylesheet", "0:"],
|
|
331
332
|
["link.rel.compression-dictionary", "0:"],
|
|
332
|
-
["link.rel.dns-prefetch", "
|
|
333
|
+
["link.rel.dns-prefetch", "5:2025"],
|
|
333
334
|
["link.rel.expect", "0:"],
|
|
334
335
|
["link.rel.manifest", "0:"],
|
|
335
336
|
["link.rel.modulepreload", "5:2023"],
|
|
@@ -502,8 +503,8 @@ const elements = new Map([
|
|
|
502
503
|
["td.valign", "0:"],
|
|
503
504
|
["td.width", "0:"],
|
|
504
505
|
["template", "10:2015"],
|
|
505
|
-
["template.shadowrootclonable", "
|
|
506
|
-
["template.shadowrootdelegatesfocus", "
|
|
506
|
+
["template.shadowrootclonable", "5:2024"],
|
|
507
|
+
["template.shadowrootdelegatesfocus", "5:2024"],
|
|
507
508
|
["template.shadowrootmode", "5:2024"],
|
|
508
509
|
["template.shadowrootserializable", "0:"],
|
|
509
510
|
["textarea", "10:2015"],
|
|
@@ -577,6 +578,7 @@ const elements = new Map([
|
|
|
577
578
|
["video.height", "10:2015"],
|
|
578
579
|
["video.loop", "10:2015"],
|
|
579
580
|
["video.muted", "10:2015"],
|
|
581
|
+
["video.playsinline", "0:"],
|
|
580
582
|
["video.poster", "10:2015"],
|
|
581
583
|
["video.preload", "10:2015"],
|
|
582
584
|
["video.src", "10:2015"],
|
|
@@ -608,7 +610,7 @@ const globalAttributes = new Map([
|
|
|
608
610
|
["tabindex", "10:2015"],
|
|
609
611
|
["title", "10:2015"],
|
|
610
612
|
["title.multi-line_titles", "10:2018"],
|
|
611
|
-
["translate", "
|
|
613
|
+
["translate", "10:2023"],
|
|
612
614
|
["virtualkeyboardpolicy", "0:"],
|
|
613
615
|
["writingsuggestions", "0:"],
|
|
614
616
|
]);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@html-eslint/eslint-plugin",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.47.0",
|
|
4
4
|
"type": "commonjs",
|
|
5
5
|
"description": "ESLint plugin for HTML",
|
|
6
6
|
"author": "yeonjuan",
|
|
@@ -40,16 +40,16 @@
|
|
|
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.
|
|
43
|
+
"@html-eslint/parser": "^0.47.0",
|
|
44
|
+
"@html-eslint/template-parser": "^0.47.0",
|
|
45
|
+
"@html-eslint/template-syntax-parser": "^0.47.0",
|
|
46
|
+
"@html-eslint/types": "^0.47.0"
|
|
46
47
|
},
|
|
47
48
|
"peerDependencies": {
|
|
48
49
|
"eslint": "^8.0.0 || ^9.0.0"
|
|
49
50
|
},
|
|
50
51
|
"devDependencies": {
|
|
51
52
|
"@eslint/core": "^0.14.0",
|
|
52
|
-
"@html-eslint/types": "^0.46.0",
|
|
53
53
|
"@types/estree": "^0.0.47",
|
|
54
54
|
"es-html-parser": "0.3.0",
|
|
55
55
|
"eslint": "^9.27.0",
|
|
@@ -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": "caaddba72ff95d1f3a0aa3e4896d797b94f0c079"
|
|
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,2CAmkBG;AACH,mDA4BG;AAvmBH;;GAEG;AACH,4BAAsB,EAAE,CAAC;AACzB,2BAAqB,CAAC,CAAC;AACvB,6BAAuB,CAAC,CAAC"}
|