@html-eslint/eslint-plugin 0.49.0 → 0.50.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.
@@ -19,6 +19,7 @@
19
19
  * @property {number} [Option2.Attribute]
20
20
  * @property {Record<string, number>} [Option2.tagChildrenIndent]
21
21
  * @property {boolean} [Option2.ignoreComment]
22
+ * @property {"first" | "templateTag"} [Option2.templateIndentBase]
22
23
  */
23
24
 
24
25
  const { parseTemplateLiteral } = require("../utils/template-literal");
@@ -102,6 +103,11 @@ module.exports = {
102
103
  type: "boolean",
103
104
  default: false,
104
105
  },
106
+ templateIndentBase: {
107
+ type: "string",
108
+ enum: ["first", "templateTag"],
109
+ default: "templateTag",
110
+ },
105
111
  },
106
112
  additionalProperties: false,
107
113
  },
@@ -116,6 +122,7 @@ module.exports = {
116
122
  const indentLevelOptions = (context.options && context.options[1]) || {};
117
123
  const lines = sourceCode.getLines();
118
124
  const ignoreComment = indentLevelOptions.ignoreComment === true;
125
+ const autoBaseIndent = indentLevelOptions.templateIndentBase === "first";
119
126
  const { indentType, indentSize, indentChar } = getIndentOptionInfo(context);
120
127
 
121
128
  /**
@@ -161,12 +168,35 @@ module.exports = {
161
168
  return 1;
162
169
  }
163
170
 
171
+ /**
172
+ * @param {TemplateLiteral} node
173
+ * @returns {number}
174
+ */
175
+ function getAutoBaseSpaces(node) {
176
+ if (!autoBaseIndent) {
177
+ return 0;
178
+ }
179
+ const startLineIndex = node.loc.start.line;
180
+ const endLineIndex = node.loc.end.line - 1;
181
+ const templateLines = lines.slice(startLineIndex, endLineIndex);
182
+ for (let i = 0; i < templateLines.length; i++) {
183
+ const line = templateLines[i];
184
+ if (line.trim()) {
185
+ return countLeftPadding(line);
186
+ }
187
+ }
188
+ return 0;
189
+ }
190
+
164
191
  /**
165
192
  *
166
193
  * @param {TemplateLiteral} node
167
194
  * @returns {number}
168
195
  */
169
196
  function getTemplateLiteralBaseIndentLevel(node) {
197
+ if (autoBaseIndent) {
198
+ return 0;
199
+ }
170
200
  // @ts-ignore
171
201
  const lineIndex = node.loc.start.line - 1;
172
202
  const line = lines[lineIndex];
@@ -181,8 +211,9 @@ module.exports = {
181
211
 
182
212
  /**
183
213
  * @param {number} baseLevel
214
+ * @param {number} baseSpaces
184
215
  */
185
- function createIndentVisitor(baseLevel) {
216
+ function createIndentVisitor(baseLevel, baseSpaces) {
186
217
  const indentLevel = new IndentLevel({
187
218
  getIncreasingLevel,
188
219
  });
@@ -210,7 +241,14 @@ module.exports = {
210
241
  * @returns {string}
211
242
  */
212
243
  function getExpectedIndent() {
213
- return indentChar.repeat(indentLevel.value());
244
+ let base = "";
245
+ if (indentType === "space") {
246
+ base = " ".repeat(baseSpaces);
247
+ } else {
248
+ base = indentChar.repeat(baseSpaces);
249
+ }
250
+
251
+ return base + indentChar.repeat(indentLevel.value());
214
252
  }
215
253
 
216
254
  /**
@@ -396,24 +434,26 @@ module.exports = {
396
434
  }
397
435
 
398
436
  return {
399
- ...createIndentVisitor(0),
437
+ ...createIndentVisitor(0, 0),
400
438
  TaggedTemplateExpression(node) {
401
439
  if (shouldCheckTaggedTemplateExpression(node, context)) {
402
440
  const base = getTemplateLiteralBaseIndentLevel(node.quasi);
441
+ const baseSpaces = getAutoBaseSpaces(node.quasi);
403
442
  parseTemplateLiteral(
404
443
  node.quasi,
405
444
  getSourceCode(context),
406
- createIndentVisitor(base)
445
+ createIndentVisitor(base, baseSpaces)
407
446
  );
408
447
  }
409
448
  },
410
449
  TemplateLiteral(node) {
411
450
  if (shouldCheckTemplateLiteral(node, context)) {
412
451
  const base = getTemplateLiteralBaseIndentLevel(node);
452
+ const baseSpaces = getAutoBaseSpaces(node);
413
453
  parseTemplateLiteral(
414
454
  node,
415
455
  getSourceCode(context),
416
- createIndentVisitor(base)
456
+ createIndentVisitor(base, baseSpaces)
417
457
  );
418
458
  }
419
459
  },
@@ -36,18 +36,33 @@ function isRoleHeading(node) {
36
36
  return !!roleAttr && !!roleAttr.value && roleAttr.value.value === "heading";
37
37
  }
38
38
 
39
+ /**
40
+ * @param {Tag} node
41
+ * @returns {string}
42
+ */
43
+ function getAltText(node) {
44
+ if (node.name.toLowerCase() === "img") {
45
+ const altAttr = findAttr(node, "alt");
46
+ if (altAttr && altAttr.value && altAttr.value.value) {
47
+ return altAttr.value.value;
48
+ }
49
+ }
50
+ return "";
51
+ }
52
+
39
53
  /**
40
54
  * @param {Text | Tag} node
41
55
  * @returns {string}
42
56
  */
43
57
  function getAllText(node) {
44
- if (!isTag(node) || !node.children.length) return "";
58
+ if (!isTag(node)) return "";
59
+
45
60
  let text = "";
46
61
  for (const child of node.children) {
47
62
  if (isText(child)) {
48
63
  text += child.value.trim();
49
64
  } else if (isTag(child)) {
50
- text += getAllText(child);
65
+ text += getAllText(child) || getAltText(child);
51
66
  }
52
67
  }
53
68
  return text;
@@ -64,7 +79,7 @@ function getAccessibleText(node) {
64
79
  if (isText(child)) {
65
80
  text += child.value.trim();
66
81
  } else if (isTag(child) && !isAriaHidden(child)) {
67
- text += getAccessibleText(child);
82
+ text += getAccessibleText(child) || getAltText(child);
68
83
  }
69
84
  }
70
85
  return text;
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @import {Tag} from "@html-eslint/types";
2
+ * @import {ScriptTag, StyleTag, Tag} from "@html-eslint/types";
3
3
  * @import {RuleModule} from "../types";
4
4
  *
5
5
  * @typedef {Object} Option
@@ -10,6 +10,7 @@
10
10
  const { RULE_CATEGORY, VOID_ELEMENTS } = require("../constants");
11
11
  const { createVisitors } = require("./utils/visitors");
12
12
  const { getRuleUrl } = require("./utils/rule");
13
+ const { getNameOf } = require("./utils/node");
13
14
 
14
15
  const VOID_ELEMENTS_SET = new Set(VOID_ELEMENTS);
15
16
 
@@ -76,14 +77,15 @@ module.exports = {
76
77
  );
77
78
 
78
79
  /**
79
- * @param {Tag} node
80
+ * @param {Tag | ScriptTag | StyleTag} node
80
81
  */
81
- function checkClosingTag(node) {
82
+ function checkClosing(node) {
83
+ const name = getNameOf(node);
82
84
  if (!node.close) {
83
85
  context.report({
84
86
  node: node,
85
87
  data: {
86
- tag: node.name,
88
+ tag: name,
87
89
  },
88
90
  messageId: MESSAGE_IDS.MISSING,
89
91
  });
@@ -151,7 +153,7 @@ module.exports = {
151
153
  if (node.selfClosing || canSelfClose) {
152
154
  checkVoidElement(node, shouldSelfClose, canSelfClose);
153
155
  } else if (node.openEnd.value !== "/>") {
154
- checkClosingTag(node);
156
+ checkClosing(node);
155
157
  }
156
158
  if (["svg", "math"].includes(node.name)) foreignContext.push(node.name);
157
159
  },
@@ -163,6 +165,16 @@ module.exports = {
163
165
  foreignContext.pop();
164
166
  }
165
167
  },
168
+ ScriptTag(node) {
169
+ if (!node.close) {
170
+ checkClosing(node);
171
+ }
172
+ },
173
+ StyleTag(node) {
174
+ if (!node.close) {
175
+ checkClosing(node);
176
+ }
177
+ },
166
178
  });
167
179
  },
168
180
  };
@@ -247,6 +247,20 @@ function getTemplateTokens(tokens) {
247
247
  );
248
248
  }
249
249
 
250
+ /**
251
+ * @param {Tag | ScriptTag | StyleTag} node
252
+ * @returns {string}
253
+ */
254
+ function getNameOf(node) {
255
+ if (isScript(node)) {
256
+ return "script";
257
+ }
258
+ if (isStyle(node)) {
259
+ return "style";
260
+ }
261
+ return node.name;
262
+ }
263
+
250
264
  module.exports = {
251
265
  findAttr,
252
266
  isAttributesEmpty,
@@ -266,4 +280,5 @@ module.exports = {
266
280
  getTemplateTokens,
267
281
  hasTemplate,
268
282
  hasAttr,
283
+ getNameOf,
269
284
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@html-eslint/eslint-plugin",
3
- "version": "0.49.0",
3
+ "version": "0.50.0",
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.4.1",
43
- "@html-eslint/parser": "^0.49.0",
44
- "@html-eslint/template-parser": "^0.49.0",
45
- "@html-eslint/template-syntax-parser": "^0.49.0",
46
- "@html-eslint/types": "^0.49.0"
43
+ "@html-eslint/parser": "^0.50.0",
44
+ "@html-eslint/template-parser": "^0.50.0",
45
+ "@html-eslint/template-syntax-parser": "^0.50.0",
46
+ "@html-eslint/types": "^0.50.0"
47
47
  },
48
48
  "peerDependencies": {
49
49
  "eslint": "^8.0.0 || ^9.0.0"
@@ -59,5 +59,5 @@
59
59
  "engines": {
60
60
  "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
61
61
  },
62
- "gitHead": "56d2df10793aa5014065a94815e865b753ccc76b"
62
+ "gitHead": "68100e43c5da0e3edb3d288f428a18d729d981d3"
63
63
  }
@@ -21,6 +21,7 @@ type Option2 = {
21
21
  Attribute?: number | undefined;
22
22
  tagChildrenIndent?: Record<string, number> | undefined;
23
23
  ignoreComment?: boolean | undefined;
24
+ templateIndentBase?: "first" | "templateTag" | undefined;
24
25
  };
25
26
  import type { RuleModule } from "../../types";
26
27
  import type { AnyNode } from "@html-eslint/types";
@@ -1 +1 @@
1
- {"version":3,"file":"indent.d.ts","sourceRoot":"","sources":["../../../lib/rules/indent/indent.js"],"names":[],"mappings":";;;wBAwDU,WAAW,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;;qBAnD3B,OAAO,GAAG,IAAI;;SAEb,KAAK;WACL,OAAO;;;kBAEP,aAAa;;;gBAEb,UAAU,CAAC,KAAK,CAAC,GAAG,UAAU,CAAC,OAAO,CAAC;gBACvC,MAAM;gBACN,MAAM;;eAEP,KAAK,GAAG,MAAM;;;;;;gCAd+B,aAAa;6BAD+C,oBAAoB;0BAChF,aAAa"}
1
+ {"version":3,"file":"indent.d.ts","sourceRoot":"","sources":["../../../lib/rules/indent/indent.js"],"names":[],"mappings":";;;wBAyDU,WAAW,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;;qBApD3B,OAAO,GAAG,IAAI;;SAEb,KAAK;WACL,OAAO;;;kBAEP,aAAa;;;gBAEb,UAAU,CAAC,KAAK,CAAC,GAAG,UAAU,CAAC,OAAO,CAAC;gBACvC,MAAM;gBACN,MAAM;;eAEP,KAAK,GAAG,MAAM;;;;;;;gCAd+B,aAAa;6BAD+C,oBAAoB;0BAChF,aAAa"}
@@ -1 +1 @@
1
- {"version":3,"file":"no-empty-headings.d.ts","sourceRoot":"","sources":["../../lib/rules/no-empty-headings.js"],"names":[],"mappings":"wBAyEU,WAAW,EAAE,CAAC;;gCAvEK,UAAU"}
1
+ {"version":3,"file":"no-empty-headings.d.ts","sourceRoot":"","sources":["../../lib/rules/no-empty-headings.js"],"names":[],"mappings":"wBAwFU,WAAW,EAAE,CAAC;;gCAtFK,UAAU"}
@@ -1 +1 @@
1
- {"version":3,"file":"require-closing-tags.d.ts","sourceRoot":"","sources":["../../lib/rules/require-closing-tags.js"],"names":[],"mappings":";;;wBAsBU,WAAW,CAAC,MAAM,CAAC,CAAC;;;;;;gCApBD,UAAU"}
1
+ {"version":3,"file":"require-closing-tags.d.ts","sourceRoot":"","sources":["../../lib/rules/require-closing-tags.js"],"names":[],"mappings":";;;wBAuBU,WAAW,CAAC,MAAM,CAAC,CAAC;;;;;;gCArBD,UAAU"}
@@ -104,6 +104,11 @@ export function hasTemplate(node: AttributeKey | AttributeValue | Text | Comment
104
104
  * @returns {boolean}
105
105
  */
106
106
  export function hasAttr(node: Tag | ScriptTag, attrName: string): boolean;
107
+ /**
108
+ * @param {Tag | ScriptTag | StyleTag} node
109
+ * @returns {string}
110
+ */
111
+ export function getNameOf(node: Tag | ScriptTag | StyleTag): string;
107
112
  import type { Tag } from "@html-eslint/types";
108
113
  import type { ScriptTag } from "@html-eslint/types";
109
114
  import type { StyleTag } from "@html-eslint/types";
@@ -1 +1 @@
1
- {"version":3,"file":"node.d.ts","sourceRoot":"","sources":["../../../lib/rules/utils/node.js"],"names":[],"mappings":"AAQA;;;;GAIG;AACH,+BAJW,GAAG,GAAG,SAAS,GAAG,QAAQ,OAC1B,MAAM,GACJ,SAAS,GAAG,SAAS,CAMjC;AAaD;;;;GAIG;AACH,wCAHW,GAAG,GAAG,SAAS,GAAG,QAAQ,GACxB,OAAO,CAInB;AAED;;;;GAIG;AACH,6CAHW,OAAO,GACL,OAAO,CAInB;AA+BD;;;;GAIG;AACH,uCAHW,IAAI,GAAG,cAAc,GACnB,IAAI,EAAE,CAwDlB;AAED;;;;;GAKG;AACH,sCAJW;IAAC,GAAG,EAAE,kBAAkB,CAAA;CAAC,SACzB;IAAC,GAAG,EAAE,kBAAkB,CAAA;CAAC,GACvB,kBAAkB,CAO9B;AA4DD;;;;GAIG;AACH,iCAJW,OAAO,aACP,CAAC,IAAI,EAAE,OAAO,KAAK,OAAO,GACxB,IAAI,GAAG,OAAO,CAiB1B;AA9ED;;;GAGG;AACH,4BAHW,QAAQ,GACN,IAAI,IAAI,GAAG,CAIvB;AAkBD;;;GAGG;AACH,gCAHW,QAAQ,GACN,IAAI,IAAI,OAAO,CAI3B;AAED;;;GAGG;AACH,6BAHW,QAAQ,GACN,IAAI,IAAI,IAAI,CAIxB;AAED;;;GAGG;AACH,6BAHW,QAAQ,GACN,IAAI,IAAI,IAAI,CAIxB;AAtCD;;;GAGG;AACH,+BAHW,QAAQ,GACN,IAAI,IAAI,SAAS,CAI7B;AAED;;;GAGG;AACH,8BAHW,QAAQ,GACN,IAAI,IAAI,QAAQ,CAI5B;AAnHD;;;;GAIG;AACH,8CAJW,CAAC,IAAI,GAAG,cAAc,CAAC,CAAC,OAAO,CAAC,SAChC,SAAS,GACP,OAAO,CAMnB;AAsID;;;GAGG;AACH,oCAHW,MAAM,GACJ,MAAM,EAAE,CAIpB;AA/JD;;;;;GAKG;AACH,wCAJW,SAAS,UACT,SAAS,GACP,OAAO,CAInB;AA+KD;;;;GAIG;AACH,0CAHW,QAAQ,EAAE,GACR,CAAC,CAAC,cAAc,GAAG,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,CAaxD;AAlLD;;;GAGG;AACH,kCAHW,YAAY,GAAG,cAAc,GAAG,IAAI,GAAG,cAAc,GACnD,OAAO,CAInB;AAxDD;;;;GAIG;AACH,8BAJW,GAAG,GAAG,SAAS,YACf,MAAM,GACJ,OAAO,CAMnB;yBA3BqI,oBAAoB;+BAApB,oBAAoB;8BAApB,oBAAoB;+BAApB,oBAAoB;6BAApB,oBAAoB;0BAApB,oBAAoB;oCAApB,oBAAoB;0BACzH,aAAa;yBACxB,QAAQ;8BADG,aAAa;6BADwF,oBAAoB;8BAApB,oBAAoB;kCAApB,oBAAoB;oCAApB,oBAAoB"}
1
+ {"version":3,"file":"node.d.ts","sourceRoot":"","sources":["../../../lib/rules/utils/node.js"],"names":[],"mappings":"AAQA;;;;GAIG;AACH,+BAJW,GAAG,GAAG,SAAS,GAAG,QAAQ,OAC1B,MAAM,GACJ,SAAS,GAAG,SAAS,CAMjC;AAaD;;;;GAIG;AACH,wCAHW,GAAG,GAAG,SAAS,GAAG,QAAQ,GACxB,OAAO,CAInB;AAED;;;;GAIG;AACH,6CAHW,OAAO,GACL,OAAO,CAInB;AA+BD;;;;GAIG;AACH,uCAHW,IAAI,GAAG,cAAc,GACnB,IAAI,EAAE,CAwDlB;AAED;;;;;GAKG;AACH,sCAJW;IAAC,GAAG,EAAE,kBAAkB,CAAA;CAAC,SACzB;IAAC,GAAG,EAAE,kBAAkB,CAAA;CAAC,GACvB,kBAAkB,CAO9B;AA4DD;;;;GAIG;AACH,iCAJW,OAAO,aACP,CAAC,IAAI,EAAE,OAAO,KAAK,OAAO,GACxB,IAAI,GAAG,OAAO,CAiB1B;AA9ED;;;GAGG;AACH,4BAHW,QAAQ,GACN,IAAI,IAAI,GAAG,CAIvB;AAkBD;;;GAGG;AACH,gCAHW,QAAQ,GACN,IAAI,IAAI,OAAO,CAI3B;AAED;;;GAGG;AACH,6BAHW,QAAQ,GACN,IAAI,IAAI,IAAI,CAIxB;AAED;;;GAGG;AACH,6BAHW,QAAQ,GACN,IAAI,IAAI,IAAI,CAIxB;AAtCD;;;GAGG;AACH,+BAHW,QAAQ,GACN,IAAI,IAAI,SAAS,CAI7B;AAED;;;GAGG;AACH,8BAHW,QAAQ,GACN,IAAI,IAAI,QAAQ,CAI5B;AAnHD;;;;GAIG;AACH,8CAJW,CAAC,IAAI,GAAG,cAAc,CAAC,CAAC,OAAO,CAAC,SAChC,SAAS,GACP,OAAO,CAMnB;AAsID;;;GAGG;AACH,oCAHW,MAAM,GACJ,MAAM,EAAE,CAIpB;AA/JD;;;;;GAKG;AACH,wCAJW,SAAS,UACT,SAAS,GACP,OAAO,CAInB;AA+KD;;;;GAIG;AACH,0CAHW,QAAQ,EAAE,GACR,CAAC,CAAC,cAAc,GAAG,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,CAaxD;AAlLD;;;GAGG;AACH,kCAHW,YAAY,GAAG,cAAc,GAAG,IAAI,GAAG,cAAc,GACnD,OAAO,CAInB;AAxDD;;;;GAIG;AACH,8BAJW,GAAG,GAAG,SAAS,YACf,MAAM,GACJ,OAAO,CAMnB;AA6ND;;;GAGG;AACH,gCAHW,GAAG,GAAG,SAAS,GAAG,QAAQ,GACxB,MAAM,CAUlB;yBApQqI,oBAAoB;+BAApB,oBAAoB;8BAApB,oBAAoB;+BAApB,oBAAoB;6BAApB,oBAAoB;0BAApB,oBAAoB;oCAApB,oBAAoB;0BACzH,aAAa;yBACxB,QAAQ;8BADG,aAAa;6BADwF,oBAAoB;8BAApB,oBAAoB;kCAApB,oBAAoB;oCAApB,oBAAoB"}