@html-eslint/eslint-plugin 0.19.1 → 0.21.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 (47) hide show
  1. package/lib/constants/index.js +0 -2
  2. package/lib/rules/element-newline.js +30 -11
  3. package/lib/rules/id-naming-convention.js +17 -11
  4. package/lib/rules/indent.js +7 -10
  5. package/lib/rules/index.js +10 -0
  6. package/lib/rules/lowercase.js +93 -0
  7. package/lib/rules/no-abstract-roles.js +15 -13
  8. package/lib/rules/no-accesskey-attrs.js +5 -6
  9. package/lib/rules/no-aria-hidden-body.js +2 -6
  10. package/lib/rules/no-duplicate-attrs.js +3 -4
  11. package/lib/rules/no-duplicate-id.js +7 -7
  12. package/lib/rules/no-extra-spacing-attrs.js +29 -9
  13. package/lib/rules/no-inline-styles.js +5 -2
  14. package/lib/rules/no-multiple-empty-lines.js +3 -4
  15. package/lib/rules/no-multiple-h1.js +3 -4
  16. package/lib/rules/no-non-scalable-viewport.js +3 -7
  17. package/lib/rules/no-obsolete-tags.js +4 -2
  18. package/lib/rules/no-positive-tabindex.js +5 -6
  19. package/lib/rules/no-restricted-attr-values.js +147 -0
  20. package/lib/rules/no-restricted-attrs.js +13 -2
  21. package/lib/rules/no-script-style-type.js +69 -0
  22. package/lib/rules/no-skip-heading-levels.js +4 -5
  23. package/lib/rules/no-target-blank.js +5 -9
  24. package/lib/rules/no-trailing-spaces.js +0 -4
  25. package/lib/rules/quotes.js +24 -1
  26. package/lib/rules/require-attrs.js +18 -7
  27. package/lib/rules/require-button-type.js +2 -6
  28. package/lib/rules/require-closing-tags.js +8 -5
  29. package/lib/rules/require-doctype.js +4 -5
  30. package/lib/rules/require-frame-title.js +5 -2
  31. package/lib/rules/require-img-alt.js +10 -0
  32. package/lib/rules/require-lang.js +5 -6
  33. package/lib/rules/require-li-container.js +9 -2
  34. package/lib/rules/require-meta-charset.js +19 -13
  35. package/lib/rules/require-meta-description.js +9 -12
  36. package/lib/rules/require-meta-viewport.js +19 -20
  37. package/lib/rules/require-open-graph-protocol.js +135 -0
  38. package/lib/rules/require-title.js +19 -25
  39. package/lib/rules/sort-attrs.js +158 -0
  40. package/lib/rules/utils/array.js +26 -0
  41. package/lib/rules/utils/node.js +70 -0
  42. package/lib/types.d.ts +262 -246
  43. package/package.json +6 -5
  44. package/lib/constants/node-types.js +0 -13
  45. package/lib/rules/utils/index.js +0 -7
  46. package/lib/rules/utils/node-utils.js +0 -112
  47. /package/lib/rules/utils/{naming-utils.js → naming.js} +0 -0
@@ -1,10 +1,8 @@
1
- const NODE_TYPES = require("./node-types");
2
1
  const RULE_CATEGORY = require("./rule-category");
3
2
  const OBSOLETE_TAGS = require("./obsolete-tags");
4
3
  const VOID_ELEMENTS = require("./void-elements");
5
4
 
6
5
  module.exports = {
7
- NODE_TYPES,
8
6
  RULE_CATEGORY,
9
7
  OBSOLETE_TAGS,
10
8
  VOID_ELEMENTS,
@@ -5,6 +5,9 @@ const MESSAGE_IDS = {
5
5
  EXPECT_NEW_LINE_BEFORE: "expectBefore",
6
6
  };
7
7
 
8
+ /**
9
+ * @type {Rule}
10
+ */
8
11
  module.exports = {
9
12
  meta: {
10
13
  type: "code",
@@ -40,9 +43,10 @@ module.exports = {
40
43
  create(context) {
41
44
  const option = context.options[0] || { skip: [] };
42
45
  const skipTags = option.skip;
43
-
44
- let isInSkipTags = false;
45
-
46
+ let skipTagCount = 0;
47
+ /**
48
+ * @param {ChildType<TagNode | ProgramNode>[]} siblings
49
+ */
46
50
  function checkSiblings(siblings) {
47
51
  siblings
48
52
  .filter((node) => node.type !== "Text")
@@ -53,6 +57,7 @@ module.exports = {
53
57
  context.report({
54
58
  node: current,
55
59
  messageId: MESSAGE_IDS.EXPECT_NEW_LINE_AFTER,
60
+ // @ts-ignore
56
61
  data: { tag: `<${current.name}>` },
57
62
  fix(fixer) {
58
63
  return fixer.insertTextAfter(current, "\n");
@@ -63,6 +68,10 @@ module.exports = {
63
68
  });
64
69
  }
65
70
 
71
+ /**
72
+ * @param {TagNode} node
73
+ * @param {ChildType<TagNode>[]} children
74
+ */
66
75
  function checkChild(node, children) {
67
76
  const targetChildren = children.filter((n) => n.type !== "Text");
68
77
  const first = targetChildren[0];
@@ -94,22 +103,27 @@ module.exports = {
94
103
  }
95
104
  }
96
105
  return {
97
- [["Tag", "Program"].join(",")](node) {
98
- if (isInSkipTags) {
106
+ Program(node) {
107
+ checkSiblings(node.body);
108
+ },
109
+ Tag(node) {
110
+ if (skipTagCount > 0) {
99
111
  return;
100
112
  }
101
-
102
- const children = node.type === "Program" ? node.body : node.children;
103
- checkSiblings(children);
104
113
  if (skipTags.includes(node.name)) {
105
- isInSkipTags = true;
114
+ skipTagCount++;
106
115
  return;
107
116
  }
108
- checkChild(node, children);
117
+ checkSiblings(node.children);
118
+ checkChild(node, node.children);
109
119
  },
120
+ /**
121
+ * @param {TagNode} node
122
+ * @returns
123
+ */
110
124
  "Tag:exit"(node) {
111
125
  if (skipTags.includes(node.name)) {
112
- isInSkipTags = false;
126
+ skipTagCount--;
113
127
  return;
114
128
  }
115
129
  },
@@ -117,6 +131,11 @@ module.exports = {
117
131
  },
118
132
  };
119
133
 
134
+ /**
135
+ * @param {BaseNode} nodeBefore
136
+ * @param {BaseNode} nodeAfter
137
+ * @returns
138
+ */
120
139
  function isOnTheSameLine(nodeBefore, nodeAfter) {
121
140
  if (nodeBefore && nodeAfter) {
122
141
  return nodeBefore.loc.end.line === nodeAfter.loc.start.line;
@@ -1,9 +1,11 @@
1
- /**
2
- * @typedef {import("../types").Rule} Rule
3
- */
4
-
5
1
  const { RULE_CATEGORY } = require("../constants");
6
- const { NamingUtils, NodeUtils } = require("./utils");
2
+ const {
3
+ isCamelCase,
4
+ isSnakeCase,
5
+ isPascalCase,
6
+ isKebabCase,
7
+ } = require("./utils/naming");
8
+ const { findAttr } = require("./utils/node");
7
9
 
8
10
  const MESSAGE_IDS = {
9
11
  WRONG: "wrong",
@@ -17,10 +19,10 @@ const CONVENTIONS = {
17
19
  };
18
20
 
19
21
  const CONVENTION_CHECKERS = {
20
- [CONVENTIONS.CAMEL_CASE]: NamingUtils.isCamelCase,
21
- [CONVENTIONS.SNAKE_CASE]: NamingUtils.isSnakeCase,
22
- [CONVENTIONS.PASCAL_CASE]: NamingUtils.isPascalCase,
23
- [CONVENTIONS.KEBAB_CASE]: NamingUtils.isKebabCase,
22
+ [CONVENTIONS.CAMEL_CASE]: isCamelCase,
23
+ [CONVENTIONS.SNAKE_CASE]: isSnakeCase,
24
+ [CONVENTIONS.PASCAL_CASE]: isPascalCase,
25
+ [CONVENTIONS.KEBAB_CASE]: isKebabCase,
24
26
  };
25
27
 
26
28
  /**
@@ -57,11 +59,15 @@ module.exports = {
57
59
  const checkNaming = CONVENTION_CHECKERS[convention];
58
60
 
59
61
  return {
60
- "*"(node) {
62
+ /**
63
+ * @param {TagNode | ScriptTagNode | StyleTagNode} node
64
+ * @returns
65
+ */
66
+ [["Tag", "ScriptTag", "StyleTag"].join(",")](node) {
61
67
  if (!node.attributes || node.attributes.length <= 0) {
62
68
  return;
63
69
  }
64
- const idAttr = NodeUtils.findAttr(node, "id");
70
+ const idAttr = findAttr(node, "id");
65
71
  if (idAttr && idAttr.value && !checkNaming(idAttr.value.value)) {
66
72
  context.report({
67
73
  node: idAttr,
@@ -1,11 +1,4 @@
1
1
  /**
2
- * @typedef {import("../types").Rule} Rule
3
- * @typedef {import("../types").TagNode} TagNode
4
- * @typedef {import("../types").BaseNode} BaseNode
5
- * @typedef {import("../types").OpenTagStartNode} OpenTagStartNode
6
- * @typedef {import("../types").CloseTagNode} CloseTagNode
7
- * @typedef {import("../types").LineNode} LineNode
8
- *@typedef {import("../types").AnyNode} AnyNode
9
2
  * @typedef {Object} IndentType
10
3
  * @property {"tab"} TAB
11
4
  * @property {"space"} SPACE
@@ -13,8 +6,9 @@
13
6
  * @typedef {Object} MessageId
14
7
  * @property {"wrongIndent"} WRONG_INDENT
15
8
  */
9
+
16
10
  const { RULE_CATEGORY } = require("../constants");
17
- const { NodeUtils } = require("./utils");
11
+ const { splitToLineNodes } = require("./utils/node");
18
12
 
19
13
  /** @type {MessageId} */
20
14
  const MESSAGE_ID = {
@@ -234,6 +228,9 @@ module.exports = {
234
228
  OpenTagStart: checkIndent,
235
229
  OpenTagEnd: checkIndent,
236
230
  CloseTag: checkIndent,
231
+ /**
232
+ * @param {TagNode} node
233
+ */
237
234
  "Tag:exit"(node) {
238
235
  if (IGNORING_NODES.includes(node.name)) {
239
236
  parentIgnoringChildCount--;
@@ -250,7 +247,7 @@ module.exports = {
250
247
  // Text
251
248
  Text(node) {
252
249
  indent();
253
- const lineNodes = NodeUtils.splitToLineNodes(node);
250
+ const lineNodes = splitToLineNodes(node);
254
251
  lineNodes.forEach((lineNode) => {
255
252
  if (lineNode.value.trim().length) {
256
253
  checkIndent(lineNode);
@@ -264,7 +261,7 @@ module.exports = {
264
261
  CommentOpen: checkIndent,
265
262
  CommentContent(node) {
266
263
  indent();
267
- const lineNodes = NodeUtils.splitToLineNodes(node);
264
+ const lineNodes = splitToLineNodes(node);
268
265
  lineNodes.forEach((lineNode) => {
269
266
  if (lineNode.value.trim().length) {
270
267
  checkIndent(lineNode);
@@ -30,6 +30,11 @@ const noAccesskeyAttrs = require("./no-accesskey-attrs");
30
30
  const noRestrictedAttrs = require("./no-restricted-attrs");
31
31
  const noTrailingSpaces = require("./no-trailing-spaces");
32
32
  const requireAttrs = require("./require-attrs");
33
+ const noRestrictedAttrValues = require("./no-restricted-attr-values");
34
+ const noScriptStyleType = require("./no-script-style-type");
35
+ const lowercase = require("./lowercase");
36
+ const requireOpenGraphProtocol = require("./require-open-graph-protocol");
37
+ const sortAttrs = require("./sort-attrs");
33
38
 
34
39
  module.exports = {
35
40
  "require-lang": requireLang,
@@ -64,4 +69,9 @@ module.exports = {
64
69
  "no-accesskey-attrs": noAccesskeyAttrs,
65
70
  "no-restricted-attrs": noRestrictedAttrs,
66
71
  "no-trailing-spaces": noTrailingSpaces,
72
+ "no-restricted-attr-values": noRestrictedAttrValues,
73
+ "no-script-style-type": noScriptStyleType,
74
+ lowercase: lowercase,
75
+ "require-open-graph-protocol": requireOpenGraphProtocol,
76
+ "sort-attrs": sortAttrs,
67
77
  };
@@ -0,0 +1,93 @@
1
+ const { NODE_TYPES } = require("@html-eslint/parser");
2
+ const { RULE_CATEGORY } = require("../constants");
3
+
4
+ const MESSAGE_IDS = {
5
+ UNEXPECTED: "unexpected",
6
+ };
7
+
8
+ /**
9
+ * @type {Rule}
10
+ */
11
+ module.exports = {
12
+ meta: {
13
+ type: "suggestion",
14
+
15
+ docs: {
16
+ description: "Enforce to use lowercase for tag and attribute names.",
17
+ category: RULE_CATEGORY.STYLE,
18
+ recommended: false,
19
+ },
20
+
21
+ fixable: "code",
22
+ schema: [],
23
+ messages: {
24
+ [MESSAGE_IDS.UNEXPECTED]: "'{{name}}' is not in lowercase.",
25
+ },
26
+ },
27
+
28
+ create(context) {
29
+ /**
30
+ * @param {TagNode | StyleTagNode | ScriptTagNode} node
31
+ */
32
+ function nameOf(node) {
33
+ if (node.type === NODE_TYPES.ScriptTag) return "script";
34
+ if (node.type === NODE_TYPES.StyleTag) return "style";
35
+ return node.name;
36
+ }
37
+
38
+ /**
39
+ * @param {TagNode | StyleTagNode | ScriptTagNode} node
40
+ */
41
+ function check(node) {
42
+ const raw = node.openStart.value.slice(1);
43
+ if (nameOf(node) !== raw) {
44
+ context.report({
45
+ node: node.openStart,
46
+ messageId: MESSAGE_IDS.UNEXPECTED,
47
+ data: {
48
+ name: raw,
49
+ },
50
+ fix(fixer) {
51
+ const name = nameOf(node);
52
+ const fixes = [
53
+ fixer.replaceTextRange(node.openStart.range, `<${name}`),
54
+ ];
55
+
56
+ if (node.close) {
57
+ fixes.push(
58
+ fixer.replaceTextRange(node.close.range, `</${name}>`)
59
+ );
60
+ }
61
+
62
+ return fixes;
63
+ },
64
+ });
65
+ }
66
+ if (node.attributes && node.attributes.length) {
67
+ node.attributes.forEach((attribute) => {
68
+ if (attribute.key.value !== attribute.key.value.toLowerCase()) {
69
+ context.report({
70
+ node: attribute.key,
71
+ messageId: MESSAGE_IDS.UNEXPECTED,
72
+ data: {
73
+ name: attribute.key.value,
74
+ },
75
+ fix(fixer) {
76
+ return fixer.replaceText(
77
+ attribute.key,
78
+ attribute.key.value.toLowerCase()
79
+ );
80
+ },
81
+ });
82
+ }
83
+ });
84
+ }
85
+ }
86
+
87
+ return {
88
+ Tag: check,
89
+ StyleTag: check,
90
+ ScriptTag: check,
91
+ };
92
+ },
93
+ };
@@ -1,9 +1,5 @@
1
- /**
2
- * @typedef {import("../types").Rule} Rule
3
- */
4
-
5
1
  const { RULE_CATEGORY } = require("../constants");
6
- const { NodeUtils } = require("./utils");
2
+ const { findAttr } = require("./utils/node");
7
3
 
8
4
  const MESSAGE_IDS = {
9
5
  UNEXPECTED: "unexpected",
@@ -46,15 +42,21 @@ module.exports = {
46
42
 
47
43
  create(context) {
48
44
  return {
45
+ /**
46
+ *
47
+ * @param {TagNode | ScriptTagNode | StyleTagNode} node
48
+ */
49
49
  [["Tag", "ScriptTag", "StyleTag"].join(",")](node) {
50
- const roleAttr = NodeUtils.findAttr(node, "role");
51
- if (roleAttr) {
52
- if (roleAttr.value && ABSTRACT_ROLE_SET.has(roleAttr.value.value)) {
53
- context.report({
54
- messageId: MESSAGE_IDS.UNEXPECTED,
55
- node: roleAttr,
56
- });
57
- }
50
+ const roleAttr = findAttr(node, "role");
51
+ if (
52
+ roleAttr &&
53
+ roleAttr.value &&
54
+ ABSTRACT_ROLE_SET.has(roleAttr.value.value)
55
+ ) {
56
+ context.report({
57
+ messageId: MESSAGE_IDS.UNEXPECTED,
58
+ node: roleAttr,
59
+ });
58
60
  }
59
61
  },
60
62
  };
@@ -1,9 +1,5 @@
1
- /**
2
- * @typedef {import("../types").Rule} Rule
3
- */
4
-
5
1
  const { RULE_CATEGORY } = require("../constants");
6
- const { NodeUtils } = require("./utils");
2
+ const { findAttr } = require("./utils/node");
7
3
 
8
4
  const MESSAGE_IDS = {
9
5
  UNEXPECTED: "unexpected",
@@ -31,8 +27,11 @@ module.exports = {
31
27
 
32
28
  create(context) {
33
29
  return {
30
+ /**
31
+ * @param {TagNode | ScriptTagNode | StyleTagNode} node
32
+ */
34
33
  [["Tag", "ScriptTag", "StyleTag"].join(",")](node) {
35
- const accessKeyAttr = NodeUtils.findAttr(node, "accesskey");
34
+ const accessKeyAttr = findAttr(node, "accesskey");
36
35
  if (accessKeyAttr) {
37
36
  context.report({
38
37
  node: accessKeyAttr,
@@ -1,9 +1,5 @@
1
- /**
2
- * @typedef {import("../types").Rule} Rule
3
- */
4
-
5
1
  const { RULE_CATEGORY } = require("../constants");
6
- const { NodeUtils } = require("./utils");
2
+ const { findAttr } = require("./utils/node");
7
3
 
8
4
  const MESSAGE_IDS = {
9
5
  UNEXPECTED: "unexpected",
@@ -36,7 +32,7 @@ module.exports = {
36
32
  if (node.name !== "body") {
37
33
  return;
38
34
  }
39
- const ariaHiddenAttr = NodeUtils.findAttr(node, "aria-hidden");
35
+ const ariaHiddenAttr = findAttr(node, "aria-hidden");
40
36
  if (ariaHiddenAttr) {
41
37
  if (
42
38
  (ariaHiddenAttr.value && ariaHiddenAttr.value.value !== "false") ||
@@ -1,7 +1,3 @@
1
- /**
2
- * @typedef {import("../types").Rule} Rule
3
- */
4
-
5
1
  const { RULE_CATEGORY } = require("../constants");
6
2
 
7
3
  const MESSAGE_IDS = {
@@ -31,6 +27,9 @@ module.exports = {
31
27
 
32
28
  create(context) {
33
29
  return {
30
+ /**
31
+ * @param {TagNode | StyleTagNode | ScriptTagNode} node
32
+ */
34
33
  [["Tag", "StyleTag", "ScriptTag"].join(",")](node) {
35
34
  if (Array.isArray(node.attributes)) {
36
35
  const attrsSet = new Set();
@@ -1,9 +1,5 @@
1
- /**
2
- * @typedef {import("../types").Rule} Rule
3
- */
4
-
5
1
  const { RULE_CATEGORY } = require("../constants");
6
- const { NodeUtils } = require("./utils");
2
+ const { findAttr } = require("./utils/node");
7
3
 
8
4
  const MESSAGE_IDS = {
9
5
  DUPLICATE_ID: "duplicateId",
@@ -32,11 +28,15 @@ module.exports = {
32
28
  create(context) {
33
29
  const IdAttrsMap = new Map();
34
30
  return {
35
- "*"(node) {
31
+ /**
32
+ * @param {TagNode | ScriptTagNode | StyleTagNode} node
33
+ * @returns
34
+ */
35
+ Tag(node) {
36
36
  if (!node.attributes || node.attributes.length <= 0) {
37
37
  return;
38
38
  }
39
- const idAttr = NodeUtils.findAttr(node, "id");
39
+ const idAttr = findAttr(node, "id");
40
40
  if (idAttr && idAttr.value) {
41
41
  if (!IdAttrsMap.has(idAttr.value.value)) {
42
42
  IdAttrsMap.set(idAttr.value.value, []);
@@ -1,8 +1,5 @@
1
- /**
2
- * @typedef {import("../types").Rule} Rule
3
- */
4
1
  const { RULE_CATEGORY } = require("../constants");
5
- const { NodeUtils } = require("./utils");
2
+ const { getLocBetween } = require("./utils/node");
6
3
 
7
4
  const MESSAGE_IDS = {
8
5
  EXTRA_BETWEEN: "unexpectedBetween",
@@ -56,6 +53,9 @@ module.exports = {
56
53
  .enforceBeforeSelfClose;
57
54
  const disallowMissing = !!(context.options[0] || {}).disallowMissing;
58
55
 
56
+ /**
57
+ * @param {AttributeNode[]} attrs
58
+ */
59
59
  function checkExtraSpacesBetweenAttrs(attrs) {
60
60
  attrs.forEach((current, index, attrs) => {
61
61
  if (index >= attrs.length - 1) {
@@ -69,7 +69,7 @@ module.exports = {
69
69
  const spacesBetween = after.loc.start.column - current.loc.end.column;
70
70
  if (spacesBetween > 1) {
71
71
  context.report({
72
- loc: NodeUtils.getLocBetween(current, after),
72
+ loc: getLocBetween(current, after),
73
73
  messageId: MESSAGE_IDS.EXTRA_BETWEEN,
74
74
  fix(fixer) {
75
75
  return fixer.removeRange([current.range[1] + 1, after.range[0]]);
@@ -87,6 +87,12 @@ module.exports = {
87
87
  });
88
88
  }
89
89
 
90
+ /**
91
+ * @param {OpenTagEndNode | OpenScriptTagEndNode | OpenStyleTagEndNode} openEnd
92
+ * @param {AttributeNode} lastAttr
93
+ * @param {boolean} isSelfClosed
94
+ * @returns {void}
95
+ */
90
96
  function checkExtraSpaceAfter(openEnd, lastAttr, isSelfClosed) {
91
97
  if (openEnd.loc.end.line !== lastAttr.loc.end.line) {
92
98
  // skip the attribute on the different line with the start tag
@@ -97,7 +103,7 @@ module.exports = {
97
103
 
98
104
  if (spacesBetween > limit) {
99
105
  context.report({
100
- loc: NodeUtils.getLocBetween(lastAttr, openEnd),
106
+ loc: getLocBetween(lastAttr, openEnd),
101
107
  messageId: MESSAGE_IDS.EXTRA_AFTER,
102
108
  fix(fixer) {
103
109
  return fixer.removeRange([
@@ -110,7 +116,7 @@ module.exports = {
110
116
 
111
117
  if (isSelfClosed && enforceBeforeSelfClose && spacesBetween < 1) {
112
118
  context.report({
113
- loc: NodeUtils.getLocBetween(lastAttr, openEnd),
119
+ loc: getLocBetween(lastAttr, openEnd),
114
120
  messageId: MESSAGE_IDS.MISSING_BEFORE_SELF_CLOSE,
115
121
  fix(fixer) {
116
122
  return fixer.insertTextAfter(lastAttr, " ");
@@ -119,6 +125,11 @@ module.exports = {
119
125
  }
120
126
  }
121
127
 
128
+ /**
129
+ * @param {OpenScriptTagStartNode | OpenTagStartNode | OpenStyleTagStartNode} node
130
+ * @param {AttributeNode} firstAttr
131
+ * @returns
132
+ */
122
133
  function checkExtraSpaceBefore(node, firstAttr) {
123
134
  if (node.loc.start.line !== firstAttr.loc.start.line) {
124
135
  // skip the attribute on the different line with the start tag
@@ -128,7 +139,7 @@ module.exports = {
128
139
  const spacesBetween = firstAttr.loc.start.column - node.loc.end.column;
129
140
  if (spacesBetween >= 2) {
130
141
  context.report({
131
- loc: NodeUtils.getLocBetween(node, firstAttr),
142
+ loc: getLocBetween(node, firstAttr),
132
143
 
133
144
  messageId: MESSAGE_IDS.EXTRA_BEFORE,
134
145
  fix(fixer) {
@@ -141,6 +152,11 @@ module.exports = {
141
152
  }
142
153
  }
143
154
 
155
+ /**
156
+ * @param {AnyNode} beforeSelfClosing
157
+ * @param {OpenTagEndNode | OpenScriptTagEndNode | OpenStyleTagEndNode} openEnd
158
+ * @returns
159
+ */
144
160
  function checkSpaceBeforeSelfClosing(beforeSelfClosing, openEnd) {
145
161
  if (beforeSelfClosing.loc.start.line !== openEnd.loc.start.line) {
146
162
  // skip the attribute on the different line with the start tag
@@ -148,7 +164,7 @@ module.exports = {
148
164
  }
149
165
  const spacesBetween =
150
166
  openEnd.loc.start.column - beforeSelfClosing.loc.end.column;
151
- const locBetween = NodeUtils.getLocBetween(beforeSelfClosing, openEnd);
167
+ const locBetween = getLocBetween(beforeSelfClosing, openEnd);
152
168
 
153
169
  if (spacesBetween > 1) {
154
170
  context.report({
@@ -173,6 +189,10 @@ module.exports = {
173
189
  }
174
190
 
175
191
  return {
192
+ /**
193
+ * @param {TagNode | StyleTagNode | ScriptTagNode} node
194
+ * @returns
195
+ */
176
196
  [["Tag", "StyleTag", "ScriptTag"].join(",")](node) {
177
197
  if (!node.attributes) {
178
198
  return;
@@ -1,10 +1,13 @@
1
1
  const { RULE_CATEGORY } = require("../constants");
2
- const { NodeUtils } = require("./utils");
2
+ const { findAttr } = require("./utils/node");
3
3
 
4
4
  const MESSAGE_IDS = {
5
5
  INLINE_STYLE: "unexpectedInlineStyle",
6
6
  };
7
7
 
8
+ /**
9
+ * @type {Rule}
10
+ */
8
11
  module.exports = {
9
12
  meta: {
10
13
  type: "code",
@@ -25,7 +28,7 @@ module.exports = {
25
28
  create(context) {
26
29
  return {
27
30
  Tag(node) {
28
- const styleAttr = NodeUtils.findAttr(node, "style");
31
+ const styleAttr = findAttr(node, "style");
29
32
  if (styleAttr) {
30
33
  context.report({
31
34
  node: styleAttr,
@@ -1,7 +1,3 @@
1
- /**
2
- * @typedef {import("../types").Rule} Rule
3
- */
4
-
5
1
  const { RULE_CATEGORY } = require("../constants");
6
2
 
7
3
  const MESSAGE_IDS = {
@@ -45,6 +41,9 @@ module.exports = {
45
41
  const lines = sourceCode.lines;
46
42
  const max = context.options.length ? context.options[0].max : 2;
47
43
  return {
44
+ /**
45
+ * @param {ProgramNode} node
46
+ */
48
47
  "Program:exit"(node) {
49
48
  /** @type {number[]} */
50
49
  const nonEmptyLineNumbers = [];
@@ -1,7 +1,3 @@
1
- /**
2
- * @typedef {import("../types").Rule} Rule
3
- */
4
-
5
1
  const { RULE_CATEGORY } = require("../constants");
6
2
 
7
3
  const MESSAGE_IDS = {
@@ -29,6 +25,9 @@ module.exports = {
29
25
  },
30
26
 
31
27
  create(context) {
28
+ /**
29
+ * @type {TagNode[]}
30
+ */
32
31
  const h1s = [];
33
32
 
34
33
  return {
@@ -1,9 +1,5 @@
1
- /**
2
- * @typedef {import("../types").Rule} Rule
3
- */
4
-
5
1
  const { RULE_CATEGORY } = require("../constants");
6
- const { NodeUtils } = require("./utils");
2
+ const { findAttr } = require("./utils/node");
7
3
 
8
4
  const MESSAGE_IDS = {
9
5
  UNEXPECTED: "unexpected",
@@ -36,8 +32,8 @@ module.exports = {
36
32
  if (node.name !== "meta") {
37
33
  return;
38
34
  }
39
- const nameAttr = NodeUtils.findAttr(node, "name");
40
- const contentAttr = NodeUtils.findAttr(node, "content");
35
+ const nameAttr = findAttr(node, "name");
36
+ const contentAttr = findAttr(node, "content");
41
37
  if (
42
38
  nameAttr &&
43
39
  nameAttr.value &&
@@ -1,5 +1,4 @@
1
- const { RULE_CATEGORY } = require("../constants");
2
- const { OBSOLETE_TAGS } = require("../constants");
1
+ const { RULE_CATEGORY, OBSOLETE_TAGS } = require("../constants");
3
2
 
4
3
  const OBSOLETE_TAGS_SET = new Set(OBSOLETE_TAGS);
5
4
 
@@ -7,6 +6,9 @@ const MESSAGE_IDS = {
7
6
  UNEXPECTED: "unexpected",
8
7
  };
9
8
 
9
+ /**
10
+ * @type {Rule}
11
+ */
10
12
  module.exports = {
11
13
  meta: {
12
14
  type: "code",
@@ -1,9 +1,5 @@
1
- /**
2
- * @typedef {import("../types").Rule} Rule
3
- */
4
-
5
1
  const { RULE_CATEGORY } = require("../constants");
6
- const { NodeUtils } = require("./utils");
2
+ const { findAttr } = require("./utils/node");
7
3
 
8
4
  const MESSAGE_IDS = {
9
5
  UNEXPECTED: "unexpected",
@@ -31,8 +27,11 @@ module.exports = {
31
27
 
32
28
  create(context) {
33
29
  return {
30
+ /**
31
+ * @param {TagNode | StyleTagNode | ScriptTagNode} node
32
+ */
34
33
  [["Tag", "StyleTag", "ScriptTag"].join(",")](node) {
35
- const tabIndexAttr = NodeUtils.findAttr(node, "tabindex");
34
+ const tabIndexAttr = findAttr(node, "tabindex");
36
35
  if (
37
36
  tabIndexAttr &&
38
37
  tabIndexAttr.value &&