@html-eslint/eslint-plugin 0.32.0 → 0.33.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/indent/indent.js +2 -0
- package/lib/rules/index.js +8 -0
- package/lib/rules/max-element-depth.js +96 -0
- package/lib/rules/require-explicit-size.js +122 -0
- package/package.json +4 -4
- package/types/rules/index.d.ts +2 -0
- package/types/rules/max-element-depth.d.ts +10 -0
- package/types/rules/max-element-depth.d.ts.map +1 -0
- package/types/rules/require-explicit-size.d.ts +9 -0
- package/types/rules/require-explicit-size.d.ts.map +1 -0
|
@@ -271,6 +271,7 @@ module.exports = {
|
|
|
271
271
|
},
|
|
272
272
|
OpenScriptTagStart: checkIndent,
|
|
273
273
|
OpenScriptTagEnd: checkIndent,
|
|
274
|
+
CloseScriptTag: checkIndent,
|
|
274
275
|
StyleTag(node) {
|
|
275
276
|
indentLevel.indent(node);
|
|
276
277
|
},
|
|
@@ -279,6 +280,7 @@ module.exports = {
|
|
|
279
280
|
},
|
|
280
281
|
OpenStyleTagStart: checkIndent,
|
|
281
282
|
OpenStyleTagEnd: checkIndent,
|
|
283
|
+
CloseStyleTag: checkIndent,
|
|
282
284
|
OpenTagStart: checkIndent,
|
|
283
285
|
OpenTagEnd(node) {
|
|
284
286
|
checkIndent(node);
|
package/lib/rules/index.js
CHANGED
|
@@ -43,6 +43,10 @@ const requireFormMethod = require("./require-form-method");
|
|
|
43
43
|
const noHeadingInsideButton = require("./no-heading-inside-button");
|
|
44
44
|
const noInvalidRole = require("./no-invalid-role");
|
|
45
45
|
const noNestedInteractive = require("./no-nested-interactive");
|
|
46
|
+
const maxElementDepth = require("./max-element-depth");
|
|
47
|
+
const requireExplicitSize = require("./require-explicit-size");
|
|
48
|
+
// import new rule here ↑
|
|
49
|
+
// DO NOT REMOVE THIS COMMENT
|
|
46
50
|
|
|
47
51
|
module.exports = {
|
|
48
52
|
"require-lang": requireLang,
|
|
@@ -90,4 +94,8 @@ module.exports = {
|
|
|
90
94
|
"sort-attrs": sortAttrs,
|
|
91
95
|
"prefer-https": preferHttps,
|
|
92
96
|
"require-input-label": requireInputLabel,
|
|
97
|
+
"max-element-depth": maxElementDepth,
|
|
98
|
+
"require-explicit-size": requireExplicitSize,
|
|
99
|
+
// export new rule here ↑
|
|
100
|
+
// DO NOT REMOVE THIS COMMENT
|
|
93
101
|
};
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @typedef { import("../types").RuleModule } RuleModule
|
|
3
|
+
* @typedef { import("../types").Tag } Tag
|
|
4
|
+
* @typedef { import("../types").StyleTag } StyleTag
|
|
5
|
+
* @typedef { import("../types").ScriptTag } ScriptTag
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const { RULE_CATEGORY } = require("../constants");
|
|
9
|
+
const { createVisitors } = require("./utils/visitors");
|
|
10
|
+
|
|
11
|
+
const MESSAGE_IDS = {
|
|
12
|
+
MAX_DEPTH_EXCEEDED: "maxDepthExceeded",
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* @type {RuleModule}
|
|
17
|
+
*/
|
|
18
|
+
module.exports = {
|
|
19
|
+
meta: {
|
|
20
|
+
type: "code",
|
|
21
|
+
|
|
22
|
+
docs: {
|
|
23
|
+
description: "Enforce element maximum depth",
|
|
24
|
+
category: RULE_CATEGORY.STYLE,
|
|
25
|
+
recommended: false,
|
|
26
|
+
},
|
|
27
|
+
|
|
28
|
+
fixable: null,
|
|
29
|
+
schema: [
|
|
30
|
+
{
|
|
31
|
+
type: "object",
|
|
32
|
+
properties: {
|
|
33
|
+
max: {
|
|
34
|
+
type: "integer",
|
|
35
|
+
minimum: 1,
|
|
36
|
+
default: 32,
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
required: ["max"],
|
|
40
|
+
additionalProperties: false,
|
|
41
|
+
},
|
|
42
|
+
],
|
|
43
|
+
messages: {
|
|
44
|
+
[MESSAGE_IDS.MAX_DEPTH_EXCEEDED]:
|
|
45
|
+
"Expected the depth of nested elements to be <= {{needed}}, but found {{found}}",
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
|
|
49
|
+
create(context) {
|
|
50
|
+
const maxDepth =
|
|
51
|
+
context.options &&
|
|
52
|
+
context.options[0] &&
|
|
53
|
+
typeof context.options[0].max === "number"
|
|
54
|
+
? context.options[0].max
|
|
55
|
+
: 32;
|
|
56
|
+
|
|
57
|
+
let depth = 0;
|
|
58
|
+
|
|
59
|
+
function resetDepth() {
|
|
60
|
+
depth = 0;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
*
|
|
65
|
+
* @param {Tag | ScriptTag | StyleTag} node
|
|
66
|
+
*/
|
|
67
|
+
function increaseDepth(node) {
|
|
68
|
+
depth++;
|
|
69
|
+
if (depth > maxDepth) {
|
|
70
|
+
context.report({
|
|
71
|
+
node,
|
|
72
|
+
messageId: MESSAGE_IDS.MAX_DEPTH_EXCEEDED,
|
|
73
|
+
data: {
|
|
74
|
+
needed: maxDepth,
|
|
75
|
+
found: String(depth),
|
|
76
|
+
},
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function decreaseDepth() {
|
|
82
|
+
depth--;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return createVisitors(context, {
|
|
86
|
+
Document: resetDepth,
|
|
87
|
+
"Document:exit": resetDepth,
|
|
88
|
+
Tag: increaseDepth,
|
|
89
|
+
"Tag:exit": decreaseDepth,
|
|
90
|
+
ScriptTag: increaseDepth,
|
|
91
|
+
"ScriptTag:exit": decreaseDepth,
|
|
92
|
+
StyleTag: increaseDepth,
|
|
93
|
+
"StyleTag:exit": decreaseDepth,
|
|
94
|
+
});
|
|
95
|
+
},
|
|
96
|
+
};
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @typedef { import("../types").RuleModule } RuleModule
|
|
3
|
+
* @typedef { import("../types").Tag } Tag
|
|
4
|
+
* @typedef { import("../types").AnyNode } AnyNode
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const { RULE_CATEGORY } = require("../constants");
|
|
8
|
+
const { findAttr } = require("./utils/node");
|
|
9
|
+
const { createVisitors } = require("./utils/visitors");
|
|
10
|
+
|
|
11
|
+
const MESSAGE_IDS = {
|
|
12
|
+
MISSING_HEIGHT: "missingHeight",
|
|
13
|
+
MISSING_WIDTH: "missingWidth",
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
const TARGET_ELEMENTS = ["img", "iframe"];
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* @type {RuleModule}
|
|
20
|
+
*/
|
|
21
|
+
module.exports = {
|
|
22
|
+
meta: {
|
|
23
|
+
type: "code",
|
|
24
|
+
|
|
25
|
+
docs: {
|
|
26
|
+
description:
|
|
27
|
+
"Enforces that some elements (img, iframe) have explicitly defined width and height attributes.",
|
|
28
|
+
category: RULE_CATEGORY.BEST_PRACTICE,
|
|
29
|
+
recommended: false,
|
|
30
|
+
},
|
|
31
|
+
|
|
32
|
+
fixable: null,
|
|
33
|
+
schema: [
|
|
34
|
+
{
|
|
35
|
+
type: "object",
|
|
36
|
+
properties: {
|
|
37
|
+
allowClass: {
|
|
38
|
+
type: "array",
|
|
39
|
+
items: {
|
|
40
|
+
type: "string",
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
allowId: {
|
|
44
|
+
type: "array",
|
|
45
|
+
items: {
|
|
46
|
+
type: "string",
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
additionalProperties: false,
|
|
51
|
+
},
|
|
52
|
+
],
|
|
53
|
+
messages: {
|
|
54
|
+
[MESSAGE_IDS.MISSING_HEIGHT]: "Missing `width` attribute for <{{name}}>",
|
|
55
|
+
[MESSAGE_IDS.MISSING_WIDTH]: "Missing `height` attribute for <{{name}}>",
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
|
|
59
|
+
create(context) {
|
|
60
|
+
const allowClass =
|
|
61
|
+
(context.options &&
|
|
62
|
+
context.options[0] &&
|
|
63
|
+
context.options[0].allowClass) ||
|
|
64
|
+
[];
|
|
65
|
+
const allowId =
|
|
66
|
+
(context.options && context.options[0] && context.options[0].allowId) ||
|
|
67
|
+
[];
|
|
68
|
+
|
|
69
|
+
const allowClassSet = new Set(allowClass);
|
|
70
|
+
const allowIdSet = new Set(allowId);
|
|
71
|
+
return createVisitors(context, {
|
|
72
|
+
Tag(node) {
|
|
73
|
+
if (
|
|
74
|
+
!TARGET_ELEMENTS.some(
|
|
75
|
+
(element) => element === node.name.toLowerCase()
|
|
76
|
+
)
|
|
77
|
+
) {
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
const classAttr = findAttr(node, "class");
|
|
81
|
+
if (
|
|
82
|
+
classAttr &&
|
|
83
|
+
classAttr.value &&
|
|
84
|
+
classAttr.value.value.split(" ").some((cls) => allowClassSet.has(cls))
|
|
85
|
+
) {
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
const idAttr = findAttr(node, "id");
|
|
89
|
+
if (
|
|
90
|
+
idAttr &&
|
|
91
|
+
idAttr.value &&
|
|
92
|
+
idAttr.value.value.split(" ").some((id) => allowIdSet.has(id))
|
|
93
|
+
) {
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const width = findAttr(node, "width");
|
|
98
|
+
const height = findAttr(node, "height");
|
|
99
|
+
|
|
100
|
+
if (!height || !height.value) {
|
|
101
|
+
context.report({
|
|
102
|
+
node: node.openStart,
|
|
103
|
+
messageId: MESSAGE_IDS.MISSING_HEIGHT,
|
|
104
|
+
data: {
|
|
105
|
+
name: node.name,
|
|
106
|
+
},
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
if (!width || !width.value) {
|
|
111
|
+
context.report({
|
|
112
|
+
node: node.openStart,
|
|
113
|
+
messageId: MESSAGE_IDS.MISSING_WIDTH,
|
|
114
|
+
data: {
|
|
115
|
+
name: node.name,
|
|
116
|
+
},
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
},
|
|
120
|
+
});
|
|
121
|
+
},
|
|
122
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@html-eslint/eslint-plugin",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.33.0",
|
|
4
4
|
"description": "ESLint plugin for html",
|
|
5
5
|
"author": "yeonjuan",
|
|
6
6
|
"homepage": "https://github.com/yeonjuan/html-eslint#readme",
|
|
@@ -45,15 +45,15 @@
|
|
|
45
45
|
"accessibility"
|
|
46
46
|
],
|
|
47
47
|
"dependencies": {
|
|
48
|
-
"@html-eslint/template-parser": "^0.
|
|
48
|
+
"@html-eslint/template-parser": "^0.33.0"
|
|
49
49
|
},
|
|
50
50
|
"devDependencies": {
|
|
51
|
-
"@html-eslint/parser": "^0.
|
|
51
|
+
"@html-eslint/parser": "^0.33.0",
|
|
52
52
|
"@types/eslint": "^9.6.1",
|
|
53
53
|
"@types/estree": "^0.0.47",
|
|
54
54
|
"es-html-parser": "^1.0.0-alpha.4",
|
|
55
55
|
"espree": "^10.3.0",
|
|
56
56
|
"typescript": "^5.7.2"
|
|
57
57
|
},
|
|
58
|
-
"gitHead": "
|
|
58
|
+
"gitHead": "4a0ee932a671f8c54bf1a86849fe886e9628b777"
|
|
59
59
|
}
|
package/types/rules/index.d.ts
CHANGED
|
@@ -44,6 +44,8 @@ declare const _exports: {
|
|
|
44
44
|
"sort-attrs": import("../types").RuleModule;
|
|
45
45
|
"prefer-https": import("../types").RuleModule;
|
|
46
46
|
"require-input-label": import("../types").RuleModule;
|
|
47
|
+
"max-element-depth": import("../types").RuleModule;
|
|
48
|
+
"require-explicit-size": import("../types").RuleModule;
|
|
47
49
|
};
|
|
48
50
|
export = _exports;
|
|
49
51
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
declare namespace _exports {
|
|
2
|
+
export { RuleModule, Tag, StyleTag, ScriptTag };
|
|
3
|
+
}
|
|
4
|
+
declare const _exports: RuleModule;
|
|
5
|
+
export = _exports;
|
|
6
|
+
type RuleModule = import("../types").RuleModule;
|
|
7
|
+
type Tag = import("../types").Tag;
|
|
8
|
+
type StyleTag = import("../types").StyleTag;
|
|
9
|
+
type ScriptTag = import("../types").ScriptTag;
|
|
10
|
+
//# sourceMappingURL=max-element-depth.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"max-element-depth.d.ts","sourceRoot":"","sources":["../../lib/rules/max-element-depth.js"],"names":[],"mappings":";;;wBAeU,UAAU;;kBAdN,OAAO,UAAU,EAAE,UAAU;WAC7B,OAAO,UAAU,EAAE,GAAG;gBACtB,OAAO,UAAU,EAAE,QAAQ;iBAC3B,OAAO,UAAU,EAAE,SAAS"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
declare namespace _exports {
|
|
2
|
+
export { RuleModule, Tag, AnyNode };
|
|
3
|
+
}
|
|
4
|
+
declare const _exports: RuleModule;
|
|
5
|
+
export = _exports;
|
|
6
|
+
type RuleModule = import("../types").RuleModule;
|
|
7
|
+
type Tag = import("../types").Tag;
|
|
8
|
+
type AnyNode = import("../types").AnyNode;
|
|
9
|
+
//# sourceMappingURL=require-explicit-size.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"require-explicit-size.d.ts","sourceRoot":"","sources":["../../lib/rules/require-explicit-size.js"],"names":[],"mappings":";;;wBAkBU,UAAU;;kBAjBN,OAAO,UAAU,EAAE,UAAU;WAC7B,OAAO,UAAU,EAAE,GAAG;eACtB,OAAO,UAAU,EAAE,OAAO"}
|