@html-eslint/eslint-plugin 0.41.0-alpha.0 → 0.42.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.
@@ -2,7 +2,7 @@
2
2
  * @typedef { import("@html-eslint/types").Tag } Tag
3
3
  *
4
4
  * @typedef {Object} Option
5
- * @property {string[]} [Option.substitute]
5
+ * @property {string[]} [substitute]
6
6
  *
7
7
  * @typedef { import("../types").RuleModule<[Option]> } RuleModule
8
8
  */
@@ -13,6 +13,7 @@ const { getRuleUrl } = require("./utils/rule");
13
13
 
14
14
  const MESSAGE_IDS = {
15
15
  MISSING_ALT: "missingAlt",
16
+ INSERT_ALT: "insertAlt",
16
17
  };
17
18
 
18
19
  /**
@@ -20,7 +21,7 @@ const MESSAGE_IDS = {
20
21
  */
21
22
  module.exports = {
22
23
  meta: {
23
- type: "code",
24
+ type: "suggestion",
24
25
 
25
26
  docs: {
26
27
  description: "Require `alt` attribute at `<img>` tag",
@@ -30,6 +31,7 @@ module.exports = {
30
31
  },
31
32
 
32
33
  fixable: null,
34
+ hasSuggestions: true,
33
35
  schema: [
34
36
  {
35
37
  type: "object",
@@ -45,6 +47,7 @@ module.exports = {
45
47
  ],
46
48
  messages: {
47
49
  [MESSAGE_IDS.MISSING_ALT]: "Missing `alt` attribute at `<img>` tag",
50
+ [MESSAGE_IDS.INSERT_ALT]: 'Insert `alt=""` at `<img>` tag',
48
51
  },
49
52
  },
50
53
 
@@ -60,13 +63,27 @@ module.exports = {
60
63
  if (node.name !== "img") {
61
64
  return;
62
65
  }
63
- if (!hasAltAttrAndValue(node, substitute)) {
66
+
67
+ const hasAlt = hasValidAltOrSubstitute(node, substitute);
68
+ const hasSubstituteOption = substitute.length > 0;
69
+
70
+ if (!hasAlt) {
64
71
  context.report({
65
72
  loc: {
66
73
  start: node.openStart.loc.start,
67
74
  end: node.openEnd.loc.end,
68
75
  },
69
76
  messageId: MESSAGE_IDS.MISSING_ALT,
77
+ suggest: hasSubstituteOption
78
+ ? null
79
+ : [
80
+ {
81
+ messageId: MESSAGE_IDS.INSERT_ALT,
82
+ fix(fixer) {
83
+ return fixer.insertTextBefore(node.openEnd, ' alt=""');
84
+ },
85
+ },
86
+ ],
70
87
  });
71
88
  }
72
89
  },
@@ -77,16 +94,22 @@ module.exports = {
77
94
  /**
78
95
  * @param {Tag} node
79
96
  * @param {string[]} substitute
80
- * @returns
97
+ * @returns {boolean}
81
98
  */
82
- function hasAltAttrAndValue(node, substitute = []) {
83
- return node.attributes.some((attr) => {
84
- if (attr.key && attr.value) {
85
- return (
86
- (attr.key.value === "alt" || substitute.includes(attr.key.value)) &&
87
- typeof attr.value.value === "string"
88
- );
99
+ function hasValidAltOrSubstitute(node, substitute) {
100
+ let hasAnyAlt = false;
101
+
102
+ for (const attr of node.attributes) {
103
+ if (attr.key && attr.key.value) {
104
+ const isAltAttr = attr.key.value === "alt";
105
+ const isSubstituteAttr = substitute.includes(attr.key.value);
106
+
107
+ if (isAltAttr || isSubstituteAttr) {
108
+ hasAnyAlt = true;
109
+ break;
110
+ }
89
111
  }
90
- return false;
91
- });
112
+ }
113
+
114
+ return hasAnyAlt;
92
115
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@html-eslint/eslint-plugin",
3
- "version": "0.41.0-alpha.0",
3
+ "version": "0.42.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.41.0-alpha.0",
44
- "@html-eslint/template-parser": "^0.41.0-alpha.0",
45
- "@html-eslint/template-syntax-parser": "^0.41.0-alpha.0"
43
+ "@html-eslint/parser": "^0.42.0",
44
+ "@html-eslint/template-parser": "^0.42.0",
45
+ "@html-eslint/template-syntax-parser": "^0.42.0"
46
46
  },
47
47
  "peerDependencies": {
48
48
  "eslint": "^8.0.0 || ^9.0.0"
49
49
  },
50
50
  "devDependencies": {
51
51
  "@eslint/core": "^0.14.0",
52
- "@html-eslint/types": "^0.41.0-alpha.0",
52
+ "@html-eslint/types": "^0.42.0",
53
53
  "@types/estree": "^0.0.47",
54
54
  "es-html-parser": "0.2.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": "a1d2d99f91d5adc86184ea15151b5c04bd53ea8d"
62
+ "gitHead": "30e536dad0fef8ea04b8ef383024f203a3f2655f"
63
63
  }
@@ -17,5 +17,6 @@ export let rules: {
17
17
  "@html-eslint/require-closing-tags": "error";
18
18
  "@html-eslint/no-duplicate-attrs": "error";
19
19
  "@html-eslint/use-baseline": "error";
20
+ "@html-eslint/no-duplicate-in-head": "error";
20
21
  };
21
22
  //# sourceMappingURL=recommended.d.ts.map
package/types/index.d.ts CHANGED
@@ -29,6 +29,7 @@ export declare let configs: {
29
29
  "@html-eslint/require-closing-tags": "error";
30
30
  "@html-eslint/no-duplicate-attrs": "error";
31
31
  "@html-eslint/use-baseline": "error";
32
+ "@html-eslint/no-duplicate-in-head": "error";
32
33
  };
33
34
  };
34
35
  "flat/recommended": {
@@ -58,6 +59,7 @@ export declare let configs: {
58
59
  "@html-eslint/require-closing-tags": "error";
59
60
  "@html-eslint/no-duplicate-attrs": "error";
60
61
  "@html-eslint/use-baseline": "error";
62
+ "@html-eslint/no-duplicate-in-head": "error";
61
63
  };
62
64
  };
63
65
  };
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../lib/index.js"],"names":[],"mappings":";;4BAO2B,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YAgB3B,4BAA4B;qCAAjB,aAAa"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../lib/index.js"],"names":[],"mappings":";;4BAO2B,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YAgB3B,4BAA4B;qCAAjB,aAAa"}
@@ -1 +1 @@
1
- {"version":3,"file":"lowercase.d.ts","sourceRoot":"","sources":["../../lib/rules/lowercase.js"],"names":[],"mappings":";;;wBAmBU,UAAU;;WAlBN,OAAO,oBAAoB,EAAE,GAAG;gBAChC,OAAO,oBAAoB,EAAE,QAAQ;iBACrC,OAAO,oBAAoB,EAAE,SAAS;kBACtC,OAAO,UAAU,EAAE,UAAU,CAAC,EAAE,CAAC"}
1
+ {"version":3,"file":"lowercase.d.ts","sourceRoot":"","sources":["../../lib/rules/lowercase.js"],"names":[],"mappings":";;;wBAkBU,UAAU;;WAjBN,OAAO,oBAAoB,EAAE,GAAG;gBAChC,OAAO,oBAAoB,EAAE,QAAQ;iBACrC,OAAO,oBAAoB,EAAE,SAAS;kBACtC,OAAO,UAAU,EAAE,UAAU,CAAC,EAAE,CAAC"}
@@ -0,0 +1,8 @@
1
+ declare namespace _exports {
2
+ export { RuleModule, Tag };
3
+ }
4
+ declare const _exports: RuleModule;
5
+ export = _exports;
6
+ type RuleModule = import("../types").RuleModule<[]>;
7
+ type Tag = import("@html-eslint/types").Tag;
8
+ //# sourceMappingURL=no-aria-hidden-on-focusable.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"no-aria-hidden-on-focusable.d.ts","sourceRoot":"","sources":["../../lib/rules/no-aria-hidden-on-focusable.js"],"names":[],"mappings":";;;wBA8BU,UAAU;;kBA7BN,OAAO,UAAU,EAAE,UAAU,CAAC,EAAE,CAAC;WACjC,OAAO,oBAAoB,EAAE,GAAG"}
@@ -0,0 +1,11 @@
1
+ declare namespace _exports {
2
+ export { Tag, StyleTag, ScriptTag, AttributeValue, RuleModule };
3
+ }
4
+ declare const _exports: RuleModule;
5
+ export = _exports;
6
+ type Tag = import("@html-eslint/types").Tag;
7
+ type StyleTag = import("@html-eslint/types").StyleTag;
8
+ type ScriptTag = import("@html-eslint/types").ScriptTag;
9
+ type AttributeValue = import("@html-eslint/types").AttributeValue;
10
+ type RuleModule = import("../types").RuleModule<[]>;
11
+ //# sourceMappingURL=no-duplicate-in-head.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"no-duplicate-in-head.d.ts","sourceRoot":"","sources":["../../lib/rules/no-duplicate-in-head.js"],"names":[],"mappings":";;;wBAgEU,UAAU;;WA/DN,OAAO,oBAAoB,EAAE,GAAG;gBAChC,OAAO,oBAAoB,EAAE,QAAQ;iBACrC,OAAO,oBAAoB,EAAE,SAAS;sBACtC,OAAO,oBAAoB,EAAE,cAAc;kBAC3C,OAAO,UAAU,EAAE,UAAU,CAAC,EAAE,CAAC"}
@@ -0,0 +1,9 @@
1
+ declare namespace _exports {
2
+ export { RuleModule, Tag, Text };
3
+ }
4
+ declare const _exports: RuleModule;
5
+ export = _exports;
6
+ type RuleModule = import("../types").RuleModule<[]>;
7
+ type Tag = import("@html-eslint/types").Tag;
8
+ type Text = import("@html-eslint/types").Text;
9
+ //# sourceMappingURL=no-empty-headings.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"no-empty-headings.d.ts","sourceRoot":"","sources":["../../lib/rules/no-empty-headings.js"],"names":[],"mappings":";;;wBA0EU,UAAU;;kBAzEN,OAAO,UAAU,EAAE,UAAU,CAAC,EAAE,CAAC;WACjC,OAAO,oBAAoB,EAAE,GAAG;YAChC,OAAO,oBAAoB,EAAE,IAAI"}
@@ -0,0 +1,13 @@
1
+ declare namespace _exports {
2
+ export { RuleModule, SuggestionReportDescriptor, Text, EntityData };
3
+ }
4
+ declare const _exports: RuleModule;
5
+ export = _exports;
6
+ type RuleModule = import("../types").RuleModule<[]>;
7
+ type SuggestionReportDescriptor = import("../types").SuggestionReportDescriptor;
8
+ type Text = import("@html-eslint/types").Text;
9
+ type EntityData = {
10
+ codepoints: number[];
11
+ characters: string;
12
+ };
13
+ //# sourceMappingURL=no-invalid-entity.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"no-invalid-entity.d.ts","sourceRoot":"","sources":["../../lib/rules/no-invalid-entity.js"],"names":[],"mappings":";;;wBAyBU,UAAU;;kBAxBN,OAAO,UAAU,EAAE,UAAU,CAAC,EAAE,CAAC;kCACjC,OAAO,UAAU,EAAE,0BAA0B;YAC7C,OAAO,oBAAoB,EAAE,IAAI;;gBAMjC,MAAM,EAAE;gBACR,MAAM"}
@@ -1 +1 @@
1
- {"version":3,"file":"require-img-alt.d.ts","sourceRoot":"","sources":["../../lib/rules/require-img-alt.js"],"names":[],"mappings":";;;wBAkBU,UAAU;;WAjBN,OAAO,oBAAoB,EAAE,GAAG;;;;kBAKhC,OAAO,UAAU,EAAE,UAAU,CAAC,CAAC,MAAM,CAAC,CAAC"}
1
+ {"version":3,"file":"require-img-alt.d.ts","sourceRoot":"","sources":["../../lib/rules/require-img-alt.js"],"names":[],"mappings":";;;wBAmBU,UAAU;;WAlBN,OAAO,oBAAoB,EAAE,GAAG;;;;kBAKhC,OAAO,UAAU,EAAE,UAAU,CAAC,CAAC,MAAM,CAAC,CAAC"}