@html-eslint/eslint-plugin 0.31.1 → 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.
Files changed (135) hide show
  1. package/lib/rules/attrs-newline.js +3 -5
  2. package/lib/rules/element-newline.js +11 -9
  3. package/lib/rules/id-naming-convention.js +5 -5
  4. package/lib/rules/indent/indent.js +121 -69
  5. package/lib/rules/index.js +20 -0
  6. package/lib/rules/lowercase.js +7 -8
  7. package/lib/rules/max-element-depth.js +96 -0
  8. package/lib/rules/no-abstract-roles.js +4 -4
  9. package/lib/rules/no-accesskey-attrs.js +4 -4
  10. package/lib/rules/no-duplicate-attrs.js +4 -4
  11. package/lib/rules/no-duplicate-id.js +7 -7
  12. package/lib/rules/no-extra-spacing-attrs.js +14 -14
  13. package/lib/rules/no-extra-spacing-text.js +9 -10
  14. package/lib/rules/no-heading-inside-button.js +54 -0
  15. package/lib/rules/no-inline-styles.js +0 -1
  16. package/lib/rules/no-invalid-role.js +287 -0
  17. package/lib/rules/no-multiple-empty-lines.js +5 -5
  18. package/lib/rules/no-multiple-h1.js +2 -2
  19. package/lib/rules/no-nested-interactive.js +120 -0
  20. package/lib/rules/no-positive-tabindex.js +4 -4
  21. package/lib/rules/no-restricted-attr-values.js +6 -6
  22. package/lib/rules/no-restricted-attrs.js +6 -6
  23. package/lib/rules/no-script-style-type.js +4 -4
  24. package/lib/rules/no-skip-heading-levels.js +2 -2
  25. package/lib/rules/no-trailing-spaces.js +3 -3
  26. package/lib/rules/prefer-https.js +106 -0
  27. package/lib/rules/quotes.js +8 -8
  28. package/lib/rules/require-attrs.js +14 -6
  29. package/lib/rules/require-closing-tags.js +4 -4
  30. package/lib/rules/require-explicit-size.js +122 -0
  31. package/lib/rules/require-form-method.js +81 -0
  32. package/lib/rules/require-img-alt.js +2 -3
  33. package/lib/rules/require-input-label.js +77 -0
  34. package/lib/rules/require-meta-charset.js +3 -3
  35. package/lib/rules/require-meta-description.js +3 -3
  36. package/lib/rules/require-meta-viewport.js +3 -3
  37. package/lib/rules/require-open-graph-protocol.js +3 -3
  38. package/lib/rules/require-title.js +5 -5
  39. package/lib/rules/sort-attrs.js +12 -12
  40. package/lib/rules/utils/node.js +72 -32
  41. package/lib/rules/utils/settings.js +2 -2
  42. package/lib/rules/utils/visitors.js +1 -1
  43. package/lib/types/ast.d.ts +204 -0
  44. package/lib/types/index.d.ts +3 -0
  45. package/lib/types/rule.d.ts +83 -0
  46. package/lib/types/settings.ts +13 -0
  47. package/package.json +4 -4
  48. package/types/rules/attrs-newline.d.ts +2 -3
  49. package/types/rules/attrs-newline.d.ts.map +1 -1
  50. package/types/rules/element-newline.d.ts +8 -9
  51. package/types/rules/element-newline.d.ts.map +1 -1
  52. package/types/rules/id-naming-convention.d.ts +4 -4
  53. package/types/rules/id-naming-convention.d.ts.map +1 -1
  54. package/types/rules/indent/indent.d.ts +12 -5
  55. package/types/rules/indent/indent.d.ts.map +1 -1
  56. package/types/rules/index.d.ts +8 -0
  57. package/types/rules/lowercase.d.ts +4 -5
  58. package/types/rules/lowercase.d.ts.map +1 -1
  59. package/types/rules/max-element-depth.d.ts +10 -0
  60. package/types/rules/max-element-depth.d.ts.map +1 -0
  61. package/types/rules/no-abstract-roles.d.ts +4 -4
  62. package/types/rules/no-abstract-roles.d.ts.map +1 -1
  63. package/types/rules/no-accesskey-attrs.d.ts +4 -4
  64. package/types/rules/no-accesskey-attrs.d.ts.map +1 -1
  65. package/types/rules/no-duplicate-attrs.d.ts +4 -4
  66. package/types/rules/no-duplicate-attrs.d.ts.map +1 -1
  67. package/types/rules/no-duplicate-id.d.ts +5 -5
  68. package/types/rules/no-duplicate-id.d.ts.map +1 -1
  69. package/types/rules/no-extra-spacing-attrs.d.ts +11 -11
  70. package/types/rules/no-extra-spacing-attrs.d.ts.map +1 -1
  71. package/types/rules/no-extra-spacing-text.d.ts +7 -8
  72. package/types/rules/no-extra-spacing-text.d.ts.map +1 -1
  73. package/types/rules/no-heading-inside-button.d.ts +7 -0
  74. package/types/rules/no-heading-inside-button.d.ts.map +1 -0
  75. package/types/rules/no-inline-styles.d.ts +1 -2
  76. package/types/rules/no-inline-styles.d.ts.map +1 -1
  77. package/types/rules/no-invalid-role.d.ts +7 -0
  78. package/types/rules/no-invalid-role.d.ts.map +1 -0
  79. package/types/rules/no-multiple-empty-lines.d.ts +5 -5
  80. package/types/rules/no-multiple-empty-lines.d.ts.map +1 -1
  81. package/types/rules/no-multiple-h1.d.ts +2 -2
  82. package/types/rules/no-multiple-h1.d.ts.map +1 -1
  83. package/types/rules/no-nested-interactive.d.ts +8 -0
  84. package/types/rules/no-nested-interactive.d.ts.map +1 -0
  85. package/types/rules/no-positive-tabindex.d.ts +4 -4
  86. package/types/rules/no-positive-tabindex.d.ts.map +1 -1
  87. package/types/rules/no-restricted-attr-values.d.ts +5 -5
  88. package/types/rules/no-restricted-attr-values.d.ts.map +1 -1
  89. package/types/rules/no-restricted-attrs.d.ts +5 -5
  90. package/types/rules/no-restricted-attrs.d.ts.map +1 -1
  91. package/types/rules/no-script-style-type.d.ts +4 -4
  92. package/types/rules/no-script-style-type.d.ts.map +1 -1
  93. package/types/rules/no-skip-heading-levels.d.ts +2 -2
  94. package/types/rules/no-skip-heading-levels.d.ts.map +1 -1
  95. package/types/rules/no-trailing-spaces.d.ts +3 -3
  96. package/types/rules/no-trailing-spaces.d.ts.map +1 -1
  97. package/types/rules/prefer-https.d.ts +11 -0
  98. package/types/rules/prefer-https.d.ts.map +1 -0
  99. package/types/rules/quotes.d.ts +6 -6
  100. package/types/rules/quotes.d.ts.map +1 -1
  101. package/types/rules/require-attrs.d.ts +9 -4
  102. package/types/rules/require-attrs.d.ts.map +1 -1
  103. package/types/rules/require-closing-tags.d.ts +2 -2
  104. package/types/rules/require-closing-tags.d.ts.map +1 -1
  105. package/types/rules/require-explicit-size.d.ts +9 -0
  106. package/types/rules/require-explicit-size.d.ts.map +1 -0
  107. package/types/rules/require-form-method.d.ts +7 -0
  108. package/types/rules/require-form-method.d.ts.map +1 -0
  109. package/types/rules/require-img-alt.d.ts +2 -2
  110. package/types/rules/require-img-alt.d.ts.map +1 -1
  111. package/types/rules/require-input-label.d.ts +8 -0
  112. package/types/rules/require-input-label.d.ts.map +1 -0
  113. package/types/rules/require-meta-charset.d.ts +3 -3
  114. package/types/rules/require-meta-charset.d.ts.map +1 -1
  115. package/types/rules/require-meta-description.d.ts +3 -3
  116. package/types/rules/require-meta-description.d.ts.map +1 -1
  117. package/types/rules/require-meta-viewport.d.ts +3 -3
  118. package/types/rules/require-meta-viewport.d.ts.map +1 -1
  119. package/types/rules/require-open-graph-protocol.d.ts +3 -3
  120. package/types/rules/require-open-graph-protocol.d.ts.map +1 -1
  121. package/types/rules/require-title.d.ts +4 -4
  122. package/types/rules/require-title.d.ts.map +1 -1
  123. package/types/rules/sort-attrs.d.ts +4 -4
  124. package/types/rules/sort-attrs.d.ts.map +1 -1
  125. package/types/rules/utils/node.d.ts +56 -37
  126. package/types/rules/utils/node.d.ts.map +1 -1
  127. package/types/rules/utils/settings.d.ts +2 -2
  128. package/types/rules/utils/settings.d.ts.map +1 -1
  129. package/types/rules/utils/source-code.d.ts +1 -1
  130. package/types/rules/utils/source-code.d.ts.map +1 -1
  131. package/types/rules/utils/visitors.d.ts +1 -1
  132. package/types/rules/utils/visitors.d.ts.map +1 -1
  133. package/types/types/settings.d.ts +13 -0
  134. package/types/types/settings.d.ts.map +1 -0
  135. package/lib/types.d.ts +0 -289
@@ -1,9 +1,8 @@
1
1
  /**
2
- * @typedef { import("../types").RuleFixer } RuleFixer
2
+ * @typedef { import("eslint").Rule.RuleFixer } RuleFixer
3
3
  * @typedef { import("../types").RuleModule } RuleModule
4
- * @typedef { import("../types").TagNode } TagNode
5
- * @typedef {import("../types").RuleListener}
6
- * @typedef {Object} MessageId
4
+ *
5
+ * @typedef {Object } MessageId
7
6
  * @property {"closeStyleWrong"} CLOSE_STYLE_WRONG
8
7
  * @property {"newlineMissing"} NEWLINE_MISSING
9
8
  * @property {"newlineUnexpected"} NEWLINE_UNEXPECTED
@@ -15,7 +14,6 @@ const { createVisitors } = require("./utils/visitors");
15
14
  /**
16
15
  * @type {MessageId}
17
16
  */
18
-
19
17
  const MESSAGE_ID = {
20
18
  CLOSE_STYLE_WRONG: "closeStyleWrong",
21
19
  NEWLINE_MISSING: "newlineMissing",
@@ -1,13 +1,12 @@
1
1
  /**
2
2
  * @typedef { import("../types").RuleModule } RuleModule
3
- * @typedef { import("../types").TagNode } TagNode
4
- * @typedef { import("../types").BaseNode } BaseNode
5
- * @typedef { import("../types").CommentNode } CommentNode
6
- * @typedef { import("../types").DoctypeNode } DoctypeNode
7
- * @typedef { import("../types").ScriptTagNode } ScriptTagNode
8
- * @typedef { import("../types").StyleTagNode } StyleTagNode
9
- * @typedef { import("../types").TextNode } TextNode
10
- * @typedef { CommentNode | DoctypeNode | ScriptTagNode | StyleTagNode | TagNode | TextNode } NewlineNode
3
+ * @typedef { import("../types").Tag } Tag
4
+ * @typedef { import("../types").Comment } Comment
5
+ * @typedef { import("../types").Doctype } Doctype
6
+ * @typedef { import("../types").ScriptTag } ScriptTag
7
+ * @typedef { import("../types").StyleTag } StyleTag
8
+ * @typedef { import("../types").Text } Text
9
+ * @typedef { Tag | Doctype | ScriptTag | StyleTag | Text } NewlineNode
11
10
  * @typedef {{
12
11
  * childFirst: NewlineNode | null;
13
12
  * childLast: NewlineNode | null;
@@ -188,7 +187,10 @@ module.exports = {
188
187
  }
189
188
  }
190
189
 
191
- if (nodeMeta.childLast.loc.end.line === node.close.loc.start.line) {
190
+ if (
191
+ node.close &&
192
+ nodeMeta.childLast.loc.end.line === node.close.loc.start.line
193
+ ) {
192
194
  if (isNotNewlineEnd(nodeMeta.childLast)) {
193
195
  context.report({
194
196
  node: node,
@@ -1,8 +1,8 @@
1
1
  /**
2
2
  * @typedef { import("../types").RuleModule } RuleModule
3
- * @typedef { import("../types").TagNode } TagNode
4
- * @typedef { import("../types").ScriptTagNode } ScriptTagNode
5
- * @typedef { import("../types").StyleTagNode } StyleTagNode
3
+ * @typedef { import("../types").Tag } Tag
4
+ * @typedef { import("../types").ScriptTag } ScriptTag
5
+ * @typedef { import("../types").StyleTag } StyleTag
6
6
  */
7
7
 
8
8
  const { RULE_CATEGORY } = require("../constants");
@@ -87,7 +87,7 @@ module.exports = {
87
87
  : CONVENTION_CHECKERS[convention];
88
88
 
89
89
  /**
90
- * @param {TagNode | ScriptTagNode | StyleTagNode} node
90
+ * @param {Tag | ScriptTag | StyleTag} node
91
91
  */
92
92
  function check(node) {
93
93
  if (isAttributesEmpty(node)) {
@@ -107,7 +107,7 @@ module.exports = {
107
107
  }
108
108
 
109
109
  /**
110
- * @param {TagNode | ScriptTagNode | StyleTagNode} node
110
+ * @param {Tag | ScriptTag | StyleTag} node
111
111
  */
112
112
  function checkInTemplate(node) {
113
113
  if (isAttributesEmpty(node)) {
@@ -1,23 +1,31 @@
1
1
  /**
2
2
  * @typedef { import("../../types").RuleModule } RuleModule
3
3
  * @typedef { import("../../types").AnyNode } AnyNode
4
- * @typedef { import("../../types").LineNode } LineNode
5
- * @typedef { import("../../types").BaseNode } BaseNode
6
- * @typedef { import("../../types").TagNode } TagNode
4
+ * @typedef { import("../../types").Line } Line
5
+ * @typedef { import("../../types").Tag } Tag
7
6
  * @typedef { import("../../types").RuleListener } RuleListener
7
+ * @typedef { import("../../types").Context } Context
8
8
  * @typedef { import("eslint").AST.Token } Token
9
9
  * @typedef { import("eslint").SourceCode } SourceCode
10
- * @typedef { import("estree").TemplateLiteral } TemplateLiteral
10
+ * @typedef { import("eslint").AST.Range } Range
11
+ * @typedef { import("eslint").AST.SourceLocation } SourceLocation
12
+ * @typedef { import("../../types").TemplateLiteral } TemplateLiteral
13
+ *
14
+ *
11
15
  * @typedef {Object} IndentType
12
16
  * @property {"tab"} TAB
13
17
  * @property {"space"} SPACE
14
18
  * @typedef {Object} MessageId
15
19
  * @property {"wrongIndent"} WRONG_INDENT
20
+ * @typedef {Object} IndentOptionInfo
21
+ * @property {IndentType["TAB"] | IndentType["SPACE"]} indentType
22
+ * @property {number} indentSize
23
+ * @property {string} indentChar
16
24
  */
17
25
 
18
26
  const { parse } = require("@html-eslint/template-parser");
19
27
  const { RULE_CATEGORY } = require("../../constants");
20
- const { splitToLineNodes } = require("../utils/node");
28
+ const { splitToLineNodes, isLine, isTag } = require("../utils/node");
21
29
  const {
22
30
  shouldCheckTaggedTemplateExpression,
23
31
  shouldCheckTemplateLiteral,
@@ -72,6 +80,17 @@ module.exports = {
72
80
  minimum: 1,
73
81
  default: 1,
74
82
  },
83
+ tagChildrenIndent: {
84
+ default: {},
85
+ type: "object",
86
+ patternProperties: {
87
+ "^[a-z]+$": {
88
+ type: "integer",
89
+ minimum: 0,
90
+ },
91
+ },
92
+ additionalProperties: false,
93
+ },
75
94
  },
76
95
  },
77
96
  ],
@@ -84,39 +103,44 @@ module.exports = {
84
103
  const sourceCode = getSourceCode(context);
85
104
  const indentLevelOptions = (context.options && context.options[1]) || {};
86
105
  const lines = sourceCode.getLines();
87
- const { indentType, indentSize, indentChar } = (function () {
88
- const options = context.options;
89
- /**
90
- * @type {IndentType['SPACE'] | IndentType['TAB']}
91
- */
92
- let indentType = INDENT_TYPES.SPACE;
93
- let indentSize = 4;
94
- if (options.length) {
95
- if (options[0] === INDENT_TYPES.TAB) {
96
- indentType = INDENT_TYPES.TAB;
97
- } else {
98
- indentSize = options[0];
99
- }
100
- }
101
- const indentChar =
102
- indentType === INDENT_TYPES.SPACE ? " ".repeat(indentSize) : "\t";
103
- return { indentType, indentSize, indentChar };
104
- })();
106
+ const { indentType, indentSize, indentChar } = getIndentOptionInfo(context);
105
107
 
106
108
  /**
107
- * @param {string} str
108
- * @returns {number}
109
+ * @param {Tag} node
110
+ * @return {number}
109
111
  */
110
- function countLeftPadding(str) {
111
- return str.length - str.replace(/^[\s\t]+/, "").length;
112
+ function getTagIncreasingLevel(node) {
113
+ if (
114
+ node.parent &&
115
+ isTag(node.parent) &&
116
+ indentLevelOptions &&
117
+ typeof indentLevelOptions.tagChildrenIndent === "object" &&
118
+ indentLevelOptions.tagChildrenIndent
119
+ ) {
120
+ const option =
121
+ indentLevelOptions.tagChildrenIndent[node.parent.name.toLowerCase()];
122
+ if (typeof option === "number") {
123
+ return option;
124
+ }
125
+ }
126
+
127
+ return 1;
112
128
  }
113
129
 
114
130
  /**
115
131
  * @param {AnyNode} node
116
- * @returns {node is LineNode}
132
+ * @return {number}
117
133
  */
118
- function isLineNode(node) {
119
- return node.type === "Line";
134
+ function getIncreasingLevel(node) {
135
+ if (isLine(node)) {
136
+ return 1;
137
+ }
138
+ if (isTag(node)) {
139
+ return getTagIncreasingLevel(node);
140
+ }
141
+ return typeof indentLevelOptions[node.type] === "number"
142
+ ? indentLevelOptions[node.type]
143
+ : 1;
120
144
  }
121
145
 
122
146
  /**
@@ -142,18 +166,14 @@ module.exports = {
142
166
  */
143
167
  function createIndentVisitor(baseLevel) {
144
168
  const indentLevel = new IndentLevel({
145
- getIncreasingLevel(node) {
146
- return typeof indentLevelOptions[node.type] === "number"
147
- ? indentLevelOptions[node.type]
148
- : 1;
149
- },
169
+ getIncreasingLevel,
150
170
  });
151
171
  indentLevel.setBase(baseLevel);
152
172
 
153
173
  let parentIgnoringChildCount = 0;
154
174
 
155
175
  /**
156
- * @param {AnyNode} node
176
+ * @param {AnyNode | Line} node
157
177
  * @returns {string}
158
178
  */
159
179
  function getActualIndent(node) {
@@ -161,7 +181,7 @@ module.exports = {
161
181
  const line = lines[node.loc.start.line - 1];
162
182
  let column = node.loc.start.column;
163
183
 
164
- if (isLineNode(node)) {
184
+ if (isLine(node)) {
165
185
  column += countLeftPadding(node.value);
166
186
  }
167
187
 
@@ -175,33 +195,6 @@ module.exports = {
175
195
  return indentChar.repeat(indentLevel.value());
176
196
  }
177
197
 
178
- /**
179
- * @param {AnyNode} node
180
- * @param {string} actualIndent
181
- * @return {BaseNode}
182
- */
183
- function getIndentNodeToReport(node, actualIndent) {
184
- let rangeStart = node.range[0];
185
-
186
- if (node.type !== "Line") {
187
- rangeStart -= actualIndent.length;
188
- }
189
-
190
- return {
191
- range: [rangeStart, rangeStart + actualIndent.length],
192
- loc: {
193
- start: {
194
- column: 0,
195
- line: node.loc.start.line,
196
- },
197
- end: {
198
- column: actualIndent.length,
199
- line: node.loc.start.line,
200
- },
201
- },
202
- };
203
- }
204
-
205
198
  /**
206
199
  * @param {string} actualIndent
207
200
  * @param {number} expectedIndentSize
@@ -235,7 +228,7 @@ module.exports = {
235
228
  }
236
229
 
237
230
  /**
238
- * @param {AnyNode} node
231
+ * @param {AnyNode | Line} node
239
232
  */
240
233
  function checkIndent(node) {
241
234
  if (parentIgnoringChildCount > 0) {
@@ -278,6 +271,7 @@ module.exports = {
278
271
  },
279
272
  OpenScriptTagStart: checkIndent,
280
273
  OpenScriptTagEnd: checkIndent,
274
+ CloseScriptTag: checkIndent,
281
275
  StyleTag(node) {
282
276
  indentLevel.indent(node);
283
277
  },
@@ -286,8 +280,11 @@ module.exports = {
286
280
  },
287
281
  OpenStyleTagStart: checkIndent,
288
282
  OpenStyleTagEnd: checkIndent,
283
+ CloseStyleTag: checkIndent,
289
284
  OpenTagStart: checkIndent,
290
- OpenTagEnd: checkIndent,
285
+ OpenTagEnd(node) {
286
+ checkIndent(node);
287
+ },
291
288
  CloseTag: checkIndent,
292
289
  "Tag:exit"(node) {
293
290
  if (IGNORING_NODES.includes(node.name)) {
@@ -296,7 +293,6 @@ module.exports = {
296
293
  indentLevel.dedent(node);
297
294
  },
298
295
 
299
- // Attribute
300
296
  Attribute(node) {
301
297
  indentLevel.indent(node);
302
298
  },
@@ -305,8 +301,6 @@ module.exports = {
305
301
  "Attribute:exit"(node) {
306
302
  indentLevel.dedent(node);
307
303
  },
308
-
309
- // Text
310
304
  Text(node) {
311
305
  indentLevel.indent(node);
312
306
  const lineNodes = splitToLineNodes(node);
@@ -367,3 +361,61 @@ module.exports = {
367
361
  };
368
362
  },
369
363
  };
364
+
365
+ /**
366
+ * @param {AnyNode | Line} node
367
+ * @param {string} actualIndent
368
+ * @return {{range: Range; loc: SourceLocation}}
369
+ */
370
+ function getIndentNodeToReport(node, actualIndent) {
371
+ let rangeStart = node.range[0];
372
+
373
+ if (!isLine(node)) {
374
+ rangeStart -= actualIndent.length;
375
+ }
376
+
377
+ return {
378
+ range: [rangeStart, rangeStart + actualIndent.length],
379
+ loc: {
380
+ start: {
381
+ column: 0,
382
+ line: node.loc.start.line,
383
+ },
384
+ end: {
385
+ column: actualIndent.length,
386
+ line: node.loc.start.line,
387
+ },
388
+ },
389
+ };
390
+ }
391
+
392
+ /**
393
+ * @param {string} str
394
+ * @returns {number}
395
+ */
396
+ function countLeftPadding(str) {
397
+ return str.length - str.replace(/^[\s\t]+/, "").length;
398
+ }
399
+
400
+ /**
401
+ * @param {Context} context
402
+ * @return {IndentOptionInfo}
403
+ */
404
+ function getIndentOptionInfo(context) {
405
+ const options = context.options;
406
+ /**
407
+ * @type {IndentType['SPACE'] | IndentType['TAB']}
408
+ */
409
+ let indentType = INDENT_TYPES.SPACE;
410
+ let indentSize = 4;
411
+ if (options.length) {
412
+ if (options[0] === INDENT_TYPES.TAB) {
413
+ indentType = INDENT_TYPES.TAB;
414
+ } else {
415
+ indentSize = options[0];
416
+ }
417
+ }
418
+ const indentChar =
419
+ indentType === INDENT_TYPES.SPACE ? " ".repeat(indentSize) : "\t";
420
+ return { indentType, indentSize, indentChar };
421
+ }
@@ -37,6 +37,16 @@ const noScriptStyleType = require("./no-script-style-type");
37
37
  const lowercase = require("./lowercase");
38
38
  const requireOpenGraphProtocol = require("./require-open-graph-protocol");
39
39
  const sortAttrs = require("./sort-attrs");
40
+ const preferHttps = require("./prefer-https");
41
+ const requireInputLabel = require("./require-input-label");
42
+ const requireFormMethod = require("./require-form-method");
43
+ const noHeadingInsideButton = require("./no-heading-inside-button");
44
+ const noInvalidRole = require("./no-invalid-role");
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
40
50
 
41
51
  module.exports = {
42
52
  "require-lang": requireLang,
@@ -75,7 +85,17 @@ module.exports = {
75
85
  "no-trailing-spaces": noTrailingSpaces,
76
86
  "no-restricted-attr-values": noRestrictedAttrValues,
77
87
  "no-script-style-type": noScriptStyleType,
88
+ "no-heading-inside-button": noHeadingInsideButton,
89
+ "no-invalid-role": noInvalidRole,
90
+ "no-nested-interactive": noNestedInteractive,
78
91
  lowercase: lowercase,
79
92
  "require-open-graph-protocol": requireOpenGraphProtocol,
93
+ "require-form-method": requireFormMethod,
80
94
  "sort-attrs": sortAttrs,
95
+ "prefer-https": preferHttps,
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
81
101
  };
@@ -1,9 +1,8 @@
1
1
  /**
2
2
  * @typedef { import("../types").RuleModule } RuleModule
3
- * @typedef { import("../types").TagNode } TagNode
4
- * @typedef { import("../types").StyleTagNode } StyleTagNode
5
- * @typedef { import("../types").ScriptTagNode } ScriptTagNode
6
- * @typedef { import("../types").RuleListener } RuleListener
3
+ * @typedef { import("../types").Tag } Tag
4
+ * @typedef { import("../types").StyleTag } StyleTag
5
+ * @typedef { import("../types").ScriptTag } ScriptTag
7
6
  */
8
7
 
9
8
  const { NODE_TYPES } = require("@html-eslint/parser");
@@ -38,12 +37,12 @@ module.exports = {
38
37
  create(context) {
39
38
  const allowedAttrKeySet = new Set(SVG_CAMEL_CASE_ATTRIBUTES);
40
39
  /**
41
- * @type {TagNode[]}
40
+ * @type {Tag[]}
42
41
  */
43
42
  const svgStack = [];
44
43
 
45
44
  /**
46
- * @param {TagNode} node
45
+ * @param {Tag} node
47
46
  */
48
47
  function enterSvg(node) {
49
48
  svgStack.push(node);
@@ -62,7 +61,7 @@ module.exports = {
62
61
  }
63
62
 
64
63
  /**
65
- * @param {TagNode | StyleTagNode | ScriptTagNode} node
64
+ * @param {Tag | StyleTag | ScriptTag} node
66
65
  */
67
66
  function nameOf(node) {
68
67
  if (node.type === NODE_TYPES.ScriptTag) return "script";
@@ -71,7 +70,7 @@ module.exports = {
71
70
  }
72
71
 
73
72
  /**
74
- * @param {TagNode | StyleTagNode | ScriptTagNode} node
73
+ * @param {Tag | StyleTag | ScriptTag} node
75
74
  */
76
75
  function check(node) {
77
76
  const raw = node.openStart.value.slice(1);
@@ -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
+ };
@@ -1,8 +1,8 @@
1
1
  /**
2
2
  * @typedef { import("../types").RuleModule } RuleModule
3
- * @typedef { import("../types").TagNode } TagNode
4
- * @typedef { import("../types").StyleTagNode } StyleTagNode
5
- * @typedef { import("../types").ScriptTagNode } ScriptTagNode
3
+ * @typedef { import("../types").Tag } Tag
4
+ * @typedef { import("../types").StyleTag } StyleTag
5
+ * @typedef { import("../types").ScriptTag } ScriptTag
6
6
  */
7
7
 
8
8
  const { RULE_CATEGORY } = require("../constants");
@@ -50,7 +50,7 @@ module.exports = {
50
50
 
51
51
  create(context) {
52
52
  /**
53
- * @param {TagNode | ScriptTagNode | StyleTagNode} node
53
+ * @param {Tag | ScriptTag | StyleTag} node
54
54
  */
55
55
  function check(node) {
56
56
  const roleAttr = findAttr(node, "role");
@@ -1,8 +1,8 @@
1
1
  /**
2
2
  * @typedef { import("../types").RuleModule } RuleModule
3
- * @typedef { import("../types").TagNode } TagNode
4
- * @typedef { import("../types").StyleTagNode } StyleTagNode
5
- * @typedef { import("../types").ScriptTagNode } ScriptTagNode
3
+ * @typedef { import("../types").Tag } Tag
4
+ * @typedef { import("../types").StyleTag } StyleTag
5
+ * @typedef { import("../types").ScriptTag } ScriptTag
6
6
  */
7
7
 
8
8
  const { RULE_CATEGORY } = require("../constants");
@@ -35,7 +35,7 @@ module.exports = {
35
35
 
36
36
  create(context) {
37
37
  /**
38
- * @param {TagNode | ScriptTagNode | StyleTagNode} node
38
+ * @param {Tag | ScriptTag | StyleTag} node
39
39
  */
40
40
  function check(node) {
41
41
  const accessKeyAttr = findAttr(node, "accesskey");
@@ -1,8 +1,8 @@
1
1
  /**
2
2
  * @typedef { import("../types").RuleModule } RuleModule
3
- * @typedef { import("../types").TagNode } TagNode
4
- * @typedef { import("../types").StyleTagNode } StyleTagNode
5
- * @typedef { import("../types").ScriptTagNode } ScriptTagNode
3
+ * @typedef { import("../types").Tag } Tag
4
+ * @typedef { import("../types").StyleTag } StyleTag
5
+ * @typedef { import("../types").ScriptTag } ScriptTag
6
6
  */
7
7
 
8
8
  const { RULE_CATEGORY } = require("../constants");
@@ -35,7 +35,7 @@ module.exports = {
35
35
 
36
36
  create(context) {
37
37
  /**
38
- * @param {TagNode | StyleTagNode | ScriptTagNode} node
38
+ * @param {Tag | StyleTag | ScriptTag} node
39
39
  */
40
40
  function check(node) {
41
41
  if (Array.isArray(node.attributes)) {
@@ -1,9 +1,9 @@
1
1
  /**
2
2
  * @typedef { import("../types").RuleModule } RuleModule
3
- * @typedef { import("../types").TagNode } TagNode
4
- * @typedef { import("../types").StyleTagNode } StyleTagNode
5
- * @typedef { import("../types").ScriptTagNode } ScriptTagNode
6
- * @typedef { import("es-html-parser").AttributeValueNode } AttributeValueNode
3
+ * @typedef { import("../types").Tag } Tag
4
+ * @typedef { import("../types").StyleTag } StyleTag
5
+ * @typedef { import("../types").ScriptTag } ScriptTag
6
+ * @typedef { import("../types").AttributeValue } AttributeValue
7
7
  */
8
8
 
9
9
  const { parse } = require("@html-eslint/template-parser");
@@ -42,11 +42,11 @@ module.exports = {
42
42
  create(context) {
43
43
  const htmlIdAttrsMap = new Map();
44
44
  /**
45
- * @param {Map<string, AttributeValueNode[]>} map
45
+ * @param {Map<string, AttributeValue[]>} map
46
46
  */
47
47
  function createTagVisitor(map) {
48
48
  /**
49
- * @param {TagNode} node
49
+ * @param {Tag} node
50
50
  */
51
51
  return function (node) {
52
52
  if (!node.attributes || node.attributes.length <= 0) {
@@ -67,7 +67,7 @@ module.exports = {
67
67
 
68
68
  /**
69
69
  *
70
- * @param {Map<string, AttributeValueNode[]>} map
70
+ * @param {Map<string, AttributeValue[]>} map
71
71
  */
72
72
  function report(map) {
73
73
  map.forEach((attrs) => {