@html-eslint/eslint-plugin 0.41.0 → 0.43.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/configs/recommended.js +1 -0
- package/lib/data/entities.json +2299 -0
- package/lib/languages/html-language.js +3 -3
- package/lib/languages/html-source-code.js +9 -11
- package/lib/languages/html-traversal-step.js +4 -3
- package/lib/rules/attrs-newline.js +3 -4
- package/lib/rules/element-newline.js +4 -14
- package/lib/rules/id-naming-convention.js +3 -6
- package/lib/rules/indent/indent-level.js +1 -1
- package/lib/rules/indent/indent.js +18 -23
- package/lib/rules/index.js +8 -0
- package/lib/rules/lowercase.js +11 -10
- package/lib/rules/max-element-depth.js +4 -6
- package/lib/rules/no-abstract-roles.js +3 -5
- package/lib/rules/no-accesskey-attrs.js +3 -5
- package/lib/rules/no-aria-hidden-body.js +2 -2
- package/lib/rules/no-aria-hidden-on-focusable.js +118 -0
- package/lib/rules/no-duplicate-attrs.js +3 -7
- package/lib/rules/no-duplicate-class.js +3 -6
- package/lib/rules/no-duplicate-id.js +6 -9
- package/lib/rules/no-duplicate-in-head.js +188 -0
- package/lib/rules/no-empty-headings.js +121 -0
- package/lib/rules/no-extra-spacing-attrs.js +4 -14
- package/lib/rules/no-extra-spacing-text.js +4 -10
- package/lib/rules/no-heading-inside-button.js +2 -2
- package/lib/rules/no-inline-styles.js +2 -2
- package/lib/rules/no-invalid-entity.js +107 -0
- package/lib/rules/no-invalid-role.js +2 -2
- package/lib/rules/no-multiple-empty-lines.js +10 -11
- package/lib/rules/no-multiple-h1.js +3 -3
- package/lib/rules/no-nested-interactive.js +3 -3
- package/lib/rules/no-non-scalable-viewport.js +2 -2
- package/lib/rules/no-obsolete-tags.js +2 -2
- package/lib/rules/no-positive-tabindex.js +3 -5
- package/lib/rules/no-restricted-attr-values.js +4 -6
- package/lib/rules/no-restricted-attrs.js +4 -6
- package/lib/rules/no-script-style-type.js +3 -5
- package/lib/rules/no-skip-heading-levels.js +3 -3
- package/lib/rules/no-target-blank.js +2 -2
- package/lib/rules/no-trailing-spaces.js +10 -9
- package/lib/rules/prefer-https.js +3 -6
- package/lib/rules/quotes.js +25 -10
- package/lib/rules/require-attrs.js +3 -8
- package/lib/rules/require-button-type.js +3 -4
- package/lib/rules/require-closing-tags.js +3 -3
- package/lib/rules/require-doctype.js +2 -2
- package/lib/rules/require-explicit-size.js +2 -5
- package/lib/rules/require-form-method.js +2 -2
- package/lib/rules/require-frame-title.js +2 -2
- package/lib/rules/require-img-alt.js +40 -17
- package/lib/rules/require-input-label.js +3 -3
- package/lib/rules/require-lang.js +2 -2
- package/lib/rules/require-li-container.js +2 -2
- package/lib/rules/require-meta-charset.js +3 -4
- package/lib/rules/require-meta-description.js +3 -4
- package/lib/rules/require-meta-viewport.js +3 -4
- package/lib/rules/require-open-graph-protocol.js +3 -6
- package/lib/rules/require-title.js +3 -5
- package/lib/rules/sort-attrs.js +4 -5
- package/lib/rules/use-baseline.js +3 -6
- package/lib/rules/utils/baseline.js +7 -4
- package/lib/rules/utils/node.js +11 -26
- package/lib/rules/utils/settings.js +4 -7
- package/lib/rules/utils/source-code.js +2 -2
- package/lib/rules/utils/template-literal.js +43 -0
- package/lib/rules/utils/visitors.js +6 -7
- package/package.json +6 -6
- package/types/configs/recommended.d.ts +1 -0
- package/types/index.d.ts +2 -0
- package/types/index.d.ts.map +1 -1
- package/types/languages/html-language.d.ts +0 -5
- package/types/languages/html-language.d.ts.map +1 -1
- package/types/languages/html-source-code.d.ts +13 -14
- package/types/languages/html-source-code.d.ts.map +1 -1
- package/types/languages/html-traversal-step.d.ts +5 -5
- package/types/languages/html-traversal-step.d.ts.map +1 -1
- package/types/rules/attrs-newline.d.ts +3 -4
- package/types/rules/attrs-newline.d.ts.map +1 -1
- package/types/rules/element-newline.d.ts +5 -13
- package/types/rules/element-newline.d.ts.map +1 -1
- package/types/rules/id-naming-convention.d.ts +3 -6
- package/types/rules/id-naming-convention.d.ts.map +1 -1
- package/types/rules/indent/indent-level.d.ts +3 -3
- package/types/rules/indent/indent-level.d.ts.map +1 -1
- package/types/rules/indent/indent.d.ts +5 -18
- package/types/rules/indent/indent.d.ts.map +1 -1
- package/types/rules/lowercase.d.ts +2 -8
- package/types/rules/lowercase.d.ts.map +1 -1
- package/types/rules/max-element-depth.d.ts +3 -6
- package/types/rules/max-element-depth.d.ts.map +1 -1
- package/types/rules/no-abstract-roles.d.ts +2 -8
- package/types/rules/no-abstract-roles.d.ts.map +1 -1
- package/types/rules/no-accesskey-attrs.d.ts +2 -8
- package/types/rules/no-accesskey-attrs.d.ts.map +1 -1
- package/types/rules/no-aria-hidden-body.d.ts +2 -5
- package/types/rules/no-aria-hidden-body.d.ts.map +1 -1
- package/types/rules/no-aria-hidden-on-focusable.d.ts +4 -0
- package/types/rules/no-aria-hidden-on-focusable.d.ts.map +1 -0
- package/types/rules/no-duplicate-attrs.d.ts +2 -10
- package/types/rules/no-duplicate-attrs.d.ts.map +1 -1
- package/types/rules/no-duplicate-class.d.ts +3 -7
- package/types/rules/no-duplicate-class.d.ts.map +1 -1
- package/types/rules/no-duplicate-id.d.ts +2 -9
- package/types/rules/no-duplicate-id.d.ts.map +1 -1
- package/types/rules/no-duplicate-in-head.d.ts +4 -0
- package/types/rules/no-duplicate-in-head.d.ts.map +1 -0
- package/types/rules/no-empty-headings.d.ts +4 -0
- package/types/rules/no-empty-headings.d.ts.map +1 -0
- package/types/rules/no-extra-spacing-attrs.d.ts +3 -14
- package/types/rules/no-extra-spacing-attrs.d.ts.map +1 -1
- package/types/rules/no-extra-spacing-text.d.ts +3 -9
- package/types/rules/no-extra-spacing-text.d.ts.map +1 -1
- package/types/rules/no-heading-inside-button.d.ts +2 -5
- package/types/rules/no-heading-inside-button.d.ts.map +1 -1
- package/types/rules/no-inline-styles.d.ts +2 -5
- package/types/rules/no-inline-styles.d.ts.map +1 -1
- package/types/rules/no-invalid-entity.d.ts +11 -0
- package/types/rules/no-invalid-entity.d.ts.map +1 -0
- package/types/rules/no-invalid-role.d.ts +2 -5
- package/types/rules/no-invalid-role.d.ts.map +1 -1
- package/types/rules/no-multiple-empty-lines.d.ts +3 -7
- package/types/rules/no-multiple-empty-lines.d.ts.map +1 -1
- package/types/rules/no-multiple-h1.d.ts +2 -6
- package/types/rules/no-multiple-h1.d.ts.map +1 -1
- package/types/rules/no-nested-interactive.d.ts +2 -6
- package/types/rules/no-nested-interactive.d.ts.map +1 -1
- package/types/rules/no-non-scalable-viewport.d.ts +2 -5
- package/types/rules/no-non-scalable-viewport.d.ts.map +1 -1
- package/types/rules/no-obsolete-tags.d.ts +2 -5
- package/types/rules/no-obsolete-tags.d.ts.map +1 -1
- package/types/rules/no-positive-tabindex.d.ts +2 -8
- package/types/rules/no-positive-tabindex.d.ts.map +1 -1
- package/types/rules/no-restricted-attr-values.d.ts +3 -7
- package/types/rules/no-restricted-attr-values.d.ts.map +1 -1
- package/types/rules/no-restricted-attrs.d.ts +3 -7
- package/types/rules/no-restricted-attrs.d.ts.map +1 -1
- package/types/rules/no-script-style-type.d.ts +2 -8
- package/types/rules/no-script-style-type.d.ts.map +1 -1
- package/types/rules/no-skip-heading-levels.d.ts +2 -6
- package/types/rules/no-skip-heading-levels.d.ts.map +1 -1
- package/types/rules/no-target-blank.d.ts +2 -5
- package/types/rules/no-target-blank.d.ts.map +1 -1
- package/types/rules/no-trailing-spaces.d.ts +2 -7
- package/types/rules/no-trailing-spaces.d.ts.map +1 -1
- package/types/rules/prefer-https.d.ts +2 -9
- package/types/rules/prefer-https.d.ts.map +1 -1
- package/types/rules/quotes.d.ts +7 -9
- package/types/rules/quotes.d.ts.map +1 -1
- package/types/rules/require-attrs.d.ts +3 -8
- package/types/rules/require-attrs.d.ts.map +1 -1
- package/types/rules/require-button-type.d.ts +2 -7
- package/types/rules/require-button-type.d.ts.map +1 -1
- package/types/rules/require-closing-tags.d.ts +3 -4
- package/types/rules/require-closing-tags.d.ts.map +1 -1
- package/types/rules/require-doctype.d.ts +2 -5
- package/types/rules/require-doctype.d.ts.map +1 -1
- package/types/rules/require-explicit-size.d.ts +3 -5
- package/types/rules/require-explicit-size.d.ts.map +1 -1
- package/types/rules/require-form-method.d.ts +2 -5
- package/types/rules/require-form-method.d.ts.map +1 -1
- package/types/rules/require-frame-title.d.ts +2 -5
- package/types/rules/require-frame-title.d.ts.map +1 -1
- package/types/rules/require-img-alt.d.ts +3 -4
- package/types/rules/require-img-alt.d.ts.map +1 -1
- package/types/rules/require-input-label.d.ts +2 -6
- package/types/rules/require-input-label.d.ts.map +1 -1
- package/types/rules/require-lang.d.ts +2 -5
- package/types/rules/require-lang.d.ts.map +1 -1
- package/types/rules/require-li-container.d.ts +2 -5
- package/types/rules/require-li-container.d.ts.map +1 -1
- package/types/rules/require-meta-charset.d.ts +2 -7
- package/types/rules/require-meta-charset.d.ts.map +1 -1
- package/types/rules/require-meta-description.d.ts +2 -7
- package/types/rules/require-meta-description.d.ts.map +1 -1
- package/types/rules/require-meta-viewport.d.ts +2 -7
- package/types/rules/require-meta-viewport.d.ts.map +1 -1
- package/types/rules/require-open-graph-protocol.d.ts +3 -5
- package/types/rules/require-open-graph-protocol.d.ts.map +1 -1
- package/types/rules/require-title.d.ts +2 -8
- package/types/rules/require-title.d.ts.map +1 -1
- package/types/rules/sort-attrs.d.ts +3 -6
- package/types/rules/sort-attrs.d.ts.map +1 -1
- package/types/rules/use-baseline.d.ts +3 -7
- package/types/rules/use-baseline.d.ts.map +1 -1
- package/types/rules/utils/baseline.d.ts.map +1 -1
- package/types/rules/utils/node.d.ts +25 -29
- package/types/rules/utils/node.d.ts.map +1 -1
- package/types/rules/utils/settings.d.ts +7 -9
- package/types/rules/utils/settings.d.ts.map +1 -1
- package/types/rules/utils/source-code.d.ts +4 -4
- package/types/rules/utils/source-code.d.ts.map +1 -1
- package/types/rules/utils/template-literal.d.ts +18 -0
- package/types/rules/utils/template-literal.d.ts.map +1 -0
- package/types/rules/utils/visitors.d.ts +4 -4
- package/types/rules/utils/visitors.d.ts.map +1 -1
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
const { visitorKeys, parseForESLint } = require("@html-eslint/parser");
|
|
2
|
-
const { HTMLSourceCode } = require("./html-source-code");
|
|
3
|
-
|
|
4
1
|
/**
|
|
5
2
|
* @import { Language, ParseResult, File, FileError, OkParseResult } from "@eslint/core";
|
|
6
3
|
* @import { ParserOptions } from "@html-eslint/parser";
|
|
7
4
|
* @import { AST } from "eslint";
|
|
8
5
|
*/
|
|
9
6
|
|
|
7
|
+
const { visitorKeys, parseForESLint } = require("@html-eslint/parser");
|
|
8
|
+
const { HTMLSourceCode } = require("./html-source-code");
|
|
9
|
+
|
|
10
10
|
/**
|
|
11
11
|
* @implements {Language<{ LangOptions: ParserOptions; Code: HTMLSourceCode; RootNode: AST.Program; Node: {}}>}
|
|
12
12
|
*/
|
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* @typedef {import("@html-eslint/types").AnyHTMLNode} AnyHTMLNode
|
|
8
|
-
* @typedef {import("@eslint/core").Position} Position
|
|
9
|
-
* @typedef {import("../types").BaseNode} BaseNode
|
|
2
|
+
* @import {AST} from 'eslint';
|
|
3
|
+
* @import {SourceLocation, DirectiveType} from '@eslint/plugin-kit';
|
|
4
|
+
* @import {TraversalStep, Position} from '@eslint/core';
|
|
5
|
+
* @import {CommentContent, AnyHTMLNode} from '@html-eslint/types';
|
|
6
|
+
* @import {BaseNode} from '../types';
|
|
10
7
|
*/
|
|
8
|
+
|
|
11
9
|
const {
|
|
12
10
|
TextSourceCodeBase,
|
|
13
11
|
ConfigCommentParser,
|
|
@@ -29,7 +27,7 @@ const commentParser = new ConfigCommentParser();
|
|
|
29
27
|
|
|
30
28
|
class HTMLSourceCode extends TextSourceCodeBase {
|
|
31
29
|
/**
|
|
32
|
-
* @param {{ast: Program, text: string, comments: CommentContent[]}} config
|
|
30
|
+
* @param {{ast: AST.Program, text: string, comments: CommentContent[]}} config
|
|
33
31
|
*/
|
|
34
32
|
constructor({ ast, text, comments }) {
|
|
35
33
|
super({ ast, text });
|
|
@@ -219,8 +217,8 @@ class HTMLSourceCode extends TextSourceCodeBase {
|
|
|
219
217
|
|
|
220
218
|
/**
|
|
221
219
|
*
|
|
222
|
-
* @param {AnyHTMLNode | Program} node
|
|
223
|
-
* @param {AnyHTMLNode | Program | null} parent
|
|
220
|
+
* @param {AnyHTMLNode | AST.Program} node
|
|
221
|
+
* @param {AnyHTMLNode | AST.Program | null} parent
|
|
224
222
|
*/
|
|
225
223
|
const visit = (node, parent) => {
|
|
226
224
|
this.parentsMap.set(node, parent);
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
* @
|
|
2
|
+
* @import {AST} from 'eslint';
|
|
3
|
+
* @import {AnyHTMLNode} from '@html-eslint/types';
|
|
4
4
|
*/
|
|
5
|
+
|
|
5
6
|
const { VisitNodeStep } = require("@eslint/plugin-kit");
|
|
6
7
|
|
|
7
8
|
const STEP_PHASE = {
|
|
@@ -18,7 +19,7 @@ const STEP_PHASE = {
|
|
|
18
19
|
class HTMLTraversalStep extends VisitNodeStep {
|
|
19
20
|
/**
|
|
20
21
|
* @param {Object} options
|
|
21
|
-
* @param {AnyHTMLNode | Program} options.target
|
|
22
|
+
* @param {AnyHTMLNode | AST.Program} options.target
|
|
22
23
|
* @param {1|2} options.phase
|
|
23
24
|
* @param {Array<any>} options.args
|
|
24
25
|
*/
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @
|
|
2
|
+
* @import { RuleFixer, RuleModule } from '../types';
|
|
3
3
|
*
|
|
4
4
|
* @typedef {Object} MessageId
|
|
5
5
|
* @property {"closeStyleWrong"} CLOSE_STYLE_WRONG
|
|
@@ -8,8 +8,6 @@
|
|
|
8
8
|
* @typedef {Object} Option
|
|
9
9
|
* @property {"sameline" | "newline"} [option.closeStyle]
|
|
10
10
|
* @property {number} [options.ifAttrsMoreThan]
|
|
11
|
-
*
|
|
12
|
-
* @typedef { import("../types").RuleModule<[Option]> } RuleModule
|
|
13
11
|
*/
|
|
14
12
|
|
|
15
13
|
const { RULE_CATEGORY } = require("../constants");
|
|
@@ -25,7 +23,7 @@ const MESSAGE_ID = {
|
|
|
25
23
|
};
|
|
26
24
|
|
|
27
25
|
/**
|
|
28
|
-
* @type {RuleModule}
|
|
26
|
+
* @type {RuleModule<[Option]>}
|
|
29
27
|
*/
|
|
30
28
|
module.exports = {
|
|
31
29
|
meta: {
|
|
@@ -50,6 +48,7 @@ module.exports = {
|
|
|
50
48
|
type: "integer",
|
|
51
49
|
},
|
|
52
50
|
},
|
|
51
|
+
additionalProperties: false,
|
|
53
52
|
},
|
|
54
53
|
],
|
|
55
54
|
messages: {
|
|
@@ -1,21 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @
|
|
3
|
-
* @
|
|
4
|
-
* @typedef { import("@html-eslint/types").Doctype } Doctype
|
|
5
|
-
* @typedef { import("@html-eslint/types").ScriptTag } ScriptTag
|
|
6
|
-
* @typedef { import("@html-eslint/types").StyleTag } StyleTag
|
|
7
|
-
* @typedef { import("@html-eslint/types").Text } Text
|
|
8
|
-
* @typedef { import("@html-eslint/types").AnyNode } AnyNode
|
|
9
|
-
* @typedef { import("@html-eslint/types").OpenTagEnd } OpenTagEnd
|
|
10
|
-
* @typedef { import("@html-eslint/types").CloseTag } CloseTag
|
|
11
|
-
* @typedef { import("../types").Line } Line
|
|
2
|
+
* @import { Text, AnyNode, OpenTagEnd, CloseTag } from '@html-eslint/types';
|
|
3
|
+
* @import { Line, RuleModule } from '../types';
|
|
12
4
|
* @typedef { AnyNode | Line } AnyNodeOrLine
|
|
13
|
-
*
|
|
14
5
|
* @typedef {Object} Option
|
|
15
6
|
* @property {string[]} [Option.skip]
|
|
16
7
|
* @property {string[]} [Option.inline]
|
|
17
|
-
*
|
|
18
|
-
* @typedef { import("../types").RuleModule<[Option]> } RuleModule
|
|
19
8
|
*/
|
|
20
9
|
|
|
21
10
|
const { RULE_CATEGORY } = require("../constants");
|
|
@@ -76,7 +65,7 @@ wbr
|
|
|
76
65
|
};
|
|
77
66
|
|
|
78
67
|
/**
|
|
79
|
-
* @type {RuleModule}
|
|
68
|
+
* @type {RuleModule<[Option]>}
|
|
80
69
|
*/
|
|
81
70
|
module.exports = {
|
|
82
71
|
meta: {
|
|
@@ -108,6 +97,7 @@ module.exports = {
|
|
|
108
97
|
},
|
|
109
98
|
},
|
|
110
99
|
},
|
|
100
|
+
additionalProperties: false,
|
|
111
101
|
},
|
|
112
102
|
],
|
|
113
103
|
messages: {
|
|
@@ -1,14 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @
|
|
3
|
-
* @
|
|
4
|
-
* @typedef { import("@html-eslint/types").StyleTag } StyleTag
|
|
2
|
+
* @import {Tag, ScriptTag, StyleTag} from "@html-eslint/types";
|
|
3
|
+
* @import {RuleModule} from "../types";
|
|
5
4
|
*
|
|
6
5
|
* @typedef {"camelCase" | "snake_case" | "PascalCase" | "kebab-case" | "regex"} Option1
|
|
7
6
|
* @typedef {Object} Option2
|
|
8
7
|
* @property {string} pattern
|
|
9
8
|
* @property {string} [flags]
|
|
10
|
-
*
|
|
11
|
-
* @typedef { import("../types").RuleModule<[Option1, Option2]> } RuleModule
|
|
12
9
|
*/
|
|
13
10
|
|
|
14
11
|
const { RULE_CATEGORY } = require("../constants");
|
|
@@ -42,7 +39,7 @@ const CONVENTION_CHECKERS = {
|
|
|
42
39
|
};
|
|
43
40
|
|
|
44
41
|
/**
|
|
45
|
-
* @type {RuleModule}
|
|
42
|
+
* @type {RuleModule<[Option1, Option2]>}
|
|
46
43
|
*/
|
|
47
44
|
module.exports = {
|
|
48
45
|
meta: {
|
|
@@ -1,19 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @
|
|
3
|
-
* @
|
|
4
|
-
* @
|
|
5
|
-
* @typedef { import("../../types").RuleListener } RuleListener
|
|
6
|
-
* @typedef { import("../../types").Context<any[]> } Context
|
|
7
|
-
* @typedef { import("@html-eslint/types").TemplateText } TemplateText
|
|
8
|
-
* @typedef { import("eslint").AST.Token } Token
|
|
9
|
-
* @typedef { import("eslint").SourceCode } SourceCode
|
|
10
|
-
* @typedef { import("eslint").AST.Range } Range
|
|
11
|
-
* @typedef { import("eslint").AST.SourceLocation } SourceLocation
|
|
12
|
-
* @typedef { import("@html-eslint/types").TemplateLiteral } TemplateLiteral
|
|
13
|
-
* @typedef { import("@html-eslint/types").OpenTemplate } OpenTemplate
|
|
14
|
-
* @typedef { import("@html-eslint/types").CloseTemplate } CloseTemplate
|
|
15
|
-
* @typedef { import("@html-eslint/types").ScriptTag } ScriptTag
|
|
16
|
-
* @typedef { import("@html-eslint/types").StyleTag } StyleTag
|
|
2
|
+
* @import {AnyNode, Tag, TemplateText, TemplateLiteral, OpenTemplate, CloseTemplate, ScriptTag, StyleTag} from "@html-eslint/types";
|
|
3
|
+
* @import {Line, RuleListener, Context, RuleModule} from "../../types";
|
|
4
|
+
* @import {AST} from "eslint";
|
|
17
5
|
*
|
|
18
6
|
* @typedef {AnyNode | Line} AnyNodeOrLine
|
|
19
7
|
* @typedef {Object} IndentType
|
|
@@ -30,11 +18,9 @@
|
|
|
30
18
|
* @typedef {Object} Option2
|
|
31
19
|
* @property {number} [Option2.Attribute]
|
|
32
20
|
* @property {Record<string, number>} [Option2.tagChildrenIndent]
|
|
33
|
-
*
|
|
34
|
-
* @typedef { import("../../types").RuleModule<[Option1, Option2]> } RuleModule
|
|
35
21
|
*/
|
|
36
22
|
|
|
37
|
-
const {
|
|
23
|
+
const { parseTemplateLiteral } = require("../utils/template-literal");
|
|
38
24
|
const { NODE_TYPES } = require("@html-eslint/parser");
|
|
39
25
|
const { RULE_CATEGORY } = require("../../constants");
|
|
40
26
|
const {
|
|
@@ -66,7 +52,7 @@ const INDENT_TYPES = {
|
|
|
66
52
|
const IGNORING_NODES = ["pre", "xmp"];
|
|
67
53
|
|
|
68
54
|
/**
|
|
69
|
-
* @type {RuleModule}
|
|
55
|
+
* @type {RuleModule<[Option1, Option2]>}
|
|
70
56
|
*/
|
|
71
57
|
module.exports = {
|
|
72
58
|
meta: {
|
|
@@ -111,6 +97,7 @@ module.exports = {
|
|
|
111
97
|
additionalProperties: false,
|
|
112
98
|
},
|
|
113
99
|
},
|
|
100
|
+
additionalProperties: false,
|
|
114
101
|
},
|
|
115
102
|
],
|
|
116
103
|
messages: {
|
|
@@ -399,13 +386,21 @@ module.exports = {
|
|
|
399
386
|
TaggedTemplateExpression(node) {
|
|
400
387
|
if (shouldCheckTaggedTemplateExpression(node, context)) {
|
|
401
388
|
const base = getTemplateLiteralBaseIndentLevel(node.quasi);
|
|
402
|
-
|
|
389
|
+
parseTemplateLiteral(
|
|
390
|
+
node.quasi,
|
|
391
|
+
getSourceCode(context),
|
|
392
|
+
createIndentVisitor(base)
|
|
393
|
+
);
|
|
403
394
|
}
|
|
404
395
|
},
|
|
405
396
|
TemplateLiteral(node) {
|
|
406
397
|
if (shouldCheckTemplateLiteral(node, context)) {
|
|
407
398
|
const base = getTemplateLiteralBaseIndentLevel(node);
|
|
408
|
-
|
|
399
|
+
parseTemplateLiteral(
|
|
400
|
+
node,
|
|
401
|
+
getSourceCode(context),
|
|
402
|
+
createIndentVisitor(base)
|
|
403
|
+
);
|
|
409
404
|
}
|
|
410
405
|
},
|
|
411
406
|
};
|
|
@@ -415,7 +410,7 @@ module.exports = {
|
|
|
415
410
|
/**
|
|
416
411
|
* @param {AnyNodeOrLine | TemplateText | OpenTemplate | CloseTemplate} node
|
|
417
412
|
* @param {string} actualIndent
|
|
418
|
-
* @return {{range: Range; loc: SourceLocation}}
|
|
413
|
+
* @return {{range: AST.Range; loc: AST.SourceLocation}}
|
|
419
414
|
*/
|
|
420
415
|
function getIndentNodeToReport(node, actualIndent) {
|
|
421
416
|
let rangeStart = node.range[0];
|
|
@@ -448,7 +443,7 @@ function countLeftPadding(str) {
|
|
|
448
443
|
}
|
|
449
444
|
|
|
450
445
|
/**
|
|
451
|
-
* @param {Context} context
|
|
446
|
+
* @param {Context<any[]>} context
|
|
452
447
|
* @return {IndentOptionInfo}
|
|
453
448
|
*/
|
|
454
449
|
function getIndentOptionInfo(context) {
|
package/lib/rules/index.js
CHANGED
|
@@ -27,6 +27,7 @@ const noDuplicateAttrs = require("./no-duplicate-attrs");
|
|
|
27
27
|
const noAbstractRoles = require("./no-abstract-roles");
|
|
28
28
|
const requireButtonType = require("./require-button-type");
|
|
29
29
|
const noAriaHiddenBody = require("./no-aria-hidden-body");
|
|
30
|
+
const noAriaHiddenOnFocusable = require("./no-aria-hidden-on-focusable");
|
|
30
31
|
const noMultipleEmptyLines = require("./no-multiple-empty-lines");
|
|
31
32
|
const noAccesskeyAttrs = require("./no-accesskey-attrs");
|
|
32
33
|
const noRestrictedAttrs = require("./no-restricted-attrs");
|
|
@@ -47,6 +48,9 @@ const maxElementDepth = require("./max-element-depth");
|
|
|
47
48
|
const requireExplicitSize = require("./require-explicit-size");
|
|
48
49
|
const useBaseLine = require("./use-baseline");
|
|
49
50
|
const noDuplicateClass = require("./no-duplicate-class");
|
|
51
|
+
const noEmptyHeadings = require("./no-empty-headings");
|
|
52
|
+
const noInvalidEntity = require("./no-invalid-entity");
|
|
53
|
+
const noDuplicateInHead = require("./no-duplicate-in-head");
|
|
50
54
|
// import new rule here ↑
|
|
51
55
|
// DO NOT REMOVE THIS COMMENT
|
|
52
56
|
|
|
@@ -81,6 +85,7 @@ const rules = {
|
|
|
81
85
|
"no-abstract-roles": noAbstractRoles,
|
|
82
86
|
"require-button-type": requireButtonType,
|
|
83
87
|
"no-aria-hidden-body": noAriaHiddenBody,
|
|
88
|
+
"no-aria-hidden-on-focusable": noAriaHiddenOnFocusable,
|
|
84
89
|
"no-multiple-empty-lines": noMultipleEmptyLines,
|
|
85
90
|
"no-accesskey-attrs": noAccesskeyAttrs,
|
|
86
91
|
"no-restricted-attrs": noRestrictedAttrs,
|
|
@@ -100,6 +105,9 @@ const rules = {
|
|
|
100
105
|
"require-explicit-size": requireExplicitSize,
|
|
101
106
|
"use-baseline": useBaseLine,
|
|
102
107
|
"no-duplicate-class": noDuplicateClass,
|
|
108
|
+
"no-empty-headings": noEmptyHeadings,
|
|
109
|
+
"no-invalid-entity": noInvalidEntity,
|
|
110
|
+
"no-duplicate-in-head": noDuplicateInHead,
|
|
103
111
|
// export new rule here ↑
|
|
104
112
|
// DO NOT REMOVE THIS COMMENT
|
|
105
113
|
};
|
package/lib/rules/lowercase.js
CHANGED
|
@@ -1,15 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @
|
|
3
|
-
* @
|
|
4
|
-
* @typedef { import("@html-eslint/types").ScriptTag } ScriptTag
|
|
5
|
-
* @typedef { import("../types").RuleModule<[]> } RuleModule
|
|
2
|
+
* @import {Tag, StyleTag, ScriptTag} from "@html-eslint/types";
|
|
3
|
+
* @import {RuleModule} from "../types";
|
|
6
4
|
*/
|
|
7
5
|
|
|
8
|
-
const { NODE_TYPES } = require("@html-eslint/parser");
|
|
9
6
|
const { RULE_CATEGORY } = require("../constants");
|
|
10
7
|
const SVG_CAMEL_CASE_ATTRIBUTES = require("../constants/svg-camel-case-attributes");
|
|
11
8
|
const { createVisitors } = require("./utils/visitors");
|
|
12
|
-
const { hasTemplate } = require("./utils/node");
|
|
9
|
+
const { hasTemplate, isScript, isStyle } = require("./utils/node");
|
|
13
10
|
const { getRuleUrl } = require("./utils/rule");
|
|
14
11
|
|
|
15
12
|
const MESSAGE_IDS = {
|
|
@@ -17,7 +14,7 @@ const MESSAGE_IDS = {
|
|
|
17
14
|
};
|
|
18
15
|
|
|
19
16
|
/**
|
|
20
|
-
* @type {RuleModule}
|
|
17
|
+
* @type {RuleModule<[]>}
|
|
21
18
|
*/
|
|
22
19
|
module.exports = {
|
|
23
20
|
meta: {
|
|
@@ -67,8 +64,8 @@ module.exports = {
|
|
|
67
64
|
* @param {Tag | StyleTag | ScriptTag} node
|
|
68
65
|
*/
|
|
69
66
|
function nameOf(node) {
|
|
70
|
-
if (node
|
|
71
|
-
if (node
|
|
67
|
+
if (isScript(node)) return "script";
|
|
68
|
+
if (isStyle(node)) return "style";
|
|
72
69
|
return node.name;
|
|
73
70
|
}
|
|
74
71
|
|
|
@@ -77,7 +74,11 @@ module.exports = {
|
|
|
77
74
|
*/
|
|
78
75
|
function check(node) {
|
|
79
76
|
const raw = node.openStart.value.slice(1);
|
|
80
|
-
|
|
77
|
+
const name = nameOf(node);
|
|
78
|
+
if (
|
|
79
|
+
name !== raw &&
|
|
80
|
+
(svgStack.length === 0 || name.toLowerCase() === "svg")
|
|
81
|
+
) {
|
|
81
82
|
context.report({
|
|
82
83
|
node: node.openStart,
|
|
83
84
|
messageId: MESSAGE_IDS.UNEXPECTED,
|
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @
|
|
3
|
-
* @
|
|
4
|
-
* @typedef { import("@html-eslint/types").ScriptTag } ScriptTag
|
|
2
|
+
* @import {Tag, StyleTag, ScriptTag} from "@html-eslint/types";
|
|
3
|
+
* @import {RuleModule} from "../types";
|
|
5
4
|
*
|
|
6
5
|
* @typedef {Object} Option
|
|
7
6
|
* @property {number} [Option.max]
|
|
8
|
-
* @typedef { import("../types").RuleModule<[Option]> } RuleModule
|
|
9
7
|
*/
|
|
10
8
|
|
|
11
9
|
const { RULE_CATEGORY } = require("../constants");
|
|
@@ -17,7 +15,7 @@ const MESSAGE_IDS = {
|
|
|
17
15
|
};
|
|
18
16
|
|
|
19
17
|
/**
|
|
20
|
-
* @type {RuleModule}
|
|
18
|
+
* @type {RuleModule<[Option]>}
|
|
21
19
|
*/
|
|
22
20
|
module.exports = {
|
|
23
21
|
meta: {
|
|
@@ -25,7 +23,7 @@ module.exports = {
|
|
|
25
23
|
|
|
26
24
|
docs: {
|
|
27
25
|
description: "Enforce element maximum depth",
|
|
28
|
-
category: RULE_CATEGORY.
|
|
26
|
+
category: RULE_CATEGORY.BEST_PRACTICE,
|
|
29
27
|
recommended: false,
|
|
30
28
|
url: getRuleUrl("max-element-depth"),
|
|
31
29
|
},
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @
|
|
3
|
-
* @
|
|
4
|
-
* @typedef { import("@html-eslint/types").ScriptTag } ScriptTag
|
|
5
|
-
* @typedef { import("../types").RuleModule<[]> } RuleModule
|
|
2
|
+
* @import {Tag, StyleTag, ScriptTag} from "@html-eslint/types";
|
|
3
|
+
* @import {RuleModule} from "../types";
|
|
6
4
|
*/
|
|
7
5
|
|
|
8
6
|
const { RULE_CATEGORY } = require("../constants");
|
|
@@ -30,7 +28,7 @@ const ABSTRACT_ROLE_SET = new Set([
|
|
|
30
28
|
]);
|
|
31
29
|
|
|
32
30
|
/**
|
|
33
|
-
* @type {RuleModule}
|
|
31
|
+
* @type {RuleModule<[]>}
|
|
34
32
|
*/
|
|
35
33
|
module.exports = {
|
|
36
34
|
meta: {
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @
|
|
3
|
-
* @
|
|
4
|
-
* @typedef { import("@html-eslint/types").ScriptTag } ScriptTag
|
|
5
|
-
* @typedef { import("../types").RuleModule<[]> } RuleModule
|
|
2
|
+
* @import {Tag, StyleTag, ScriptTag} from "@html-eslint/types";
|
|
3
|
+
* @import {RuleModule} from "../types";
|
|
6
4
|
*/
|
|
7
5
|
|
|
8
6
|
const { RULE_CATEGORY } = require("../constants");
|
|
@@ -15,7 +13,7 @@ const MESSAGE_IDS = {
|
|
|
15
13
|
};
|
|
16
14
|
|
|
17
15
|
/**
|
|
18
|
-
* @type {RuleModule}
|
|
16
|
+
* @type {RuleModule<[]>}
|
|
19
17
|
*/
|
|
20
18
|
module.exports = {
|
|
21
19
|
meta: {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @
|
|
2
|
+
* @import {RuleModule} from "../types";
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
const { RULE_CATEGORY } = require("../constants");
|
|
@@ -12,7 +12,7 @@ const MESSAGE_IDS = {
|
|
|
12
12
|
};
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
|
-
* @type {RuleModule}
|
|
15
|
+
* @type {RuleModule<[]>}
|
|
16
16
|
*/
|
|
17
17
|
module.exports = {
|
|
18
18
|
meta: {
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @import {Tag} from "@html-eslint/types";
|
|
3
|
+
* @import {RuleModule} from "../types";
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const { RULE_CATEGORY } = require("../constants");
|
|
7
|
+
const { findAttr } = require("./utils/node");
|
|
8
|
+
const { createVisitors } = require("./utils/visitors");
|
|
9
|
+
const { getRuleUrl } = require("./utils/rule");
|
|
10
|
+
|
|
11
|
+
const MESSAGE_IDS = {
|
|
12
|
+
UNEXPECTED: "unexpected",
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
// List of elements that are inherently focusable
|
|
16
|
+
const FOCUSABLE_ELEMENTS = new Set([
|
|
17
|
+
"a", // if href is present
|
|
18
|
+
"button",
|
|
19
|
+
"input",
|
|
20
|
+
"select",
|
|
21
|
+
"textarea",
|
|
22
|
+
"video", // if controls is present
|
|
23
|
+
"audio", // if controls is present
|
|
24
|
+
"details",
|
|
25
|
+
"embed",
|
|
26
|
+
"iframe",
|
|
27
|
+
"summary",
|
|
28
|
+
]);
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* @type {RuleModule<[]>}
|
|
32
|
+
*/
|
|
33
|
+
module.exports = {
|
|
34
|
+
meta: {
|
|
35
|
+
type: "code",
|
|
36
|
+
|
|
37
|
+
docs: {
|
|
38
|
+
description: 'Disallow aria-hidden="true" on focusable elements',
|
|
39
|
+
category: RULE_CATEGORY.ACCESSIBILITY,
|
|
40
|
+
recommended: false,
|
|
41
|
+
url: getRuleUrl("no-aria-hidden-on-focusable"),
|
|
42
|
+
},
|
|
43
|
+
|
|
44
|
+
fixable: null,
|
|
45
|
+
schema: [],
|
|
46
|
+
messages: {
|
|
47
|
+
[MESSAGE_IDS.UNEXPECTED]:
|
|
48
|
+
'Unexpected aria-hidden="true" on focusable element.',
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
|
|
52
|
+
create(context) {
|
|
53
|
+
/**
|
|
54
|
+
* Checks if an element is focusable
|
|
55
|
+
* @param {Tag} node
|
|
56
|
+
* @returns {boolean}
|
|
57
|
+
*/
|
|
58
|
+
function isFocusable(node) {
|
|
59
|
+
const tagName = node.name.toLowerCase();
|
|
60
|
+
|
|
61
|
+
const contentEditableAttr = findAttr(node, "contenteditable");
|
|
62
|
+
if (contentEditableAttr) {
|
|
63
|
+
const value = contentEditableAttr.value
|
|
64
|
+
? contentEditableAttr.value.value.toLowerCase()
|
|
65
|
+
: "";
|
|
66
|
+
if (value === "" || value === "true" || value === "plaintext-only") {
|
|
67
|
+
return true;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Check for tabindex attribute
|
|
72
|
+
const tabIndexAttr = findAttr(node, "tabindex");
|
|
73
|
+
if (tabIndexAttr && tabIndexAttr.value) {
|
|
74
|
+
const tabIndexValue = tabIndexAttr.value.value;
|
|
75
|
+
// If tabindex is -1, the element is not focusable
|
|
76
|
+
if (tabIndexValue === "-1") {
|
|
77
|
+
return false;
|
|
78
|
+
}
|
|
79
|
+
// If tabindex is present and not -1, the element is focusable
|
|
80
|
+
return true;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Special cases for elements that are only focusable with certain attributes
|
|
84
|
+
if (tagName === "a") {
|
|
85
|
+
return !!findAttr(node, "href");
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (tagName === "audio" || tagName === "video") {
|
|
89
|
+
return !!findAttr(node, "controls");
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// Check if element is inherently focusable
|
|
93
|
+
return FOCUSABLE_ELEMENTS.has(tagName);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return createVisitors(context, {
|
|
97
|
+
Tag(node) {
|
|
98
|
+
const ariaHiddenAttr = findAttr(node, "aria-hidden");
|
|
99
|
+
if (!ariaHiddenAttr || !ariaHiddenAttr.value) {
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Only check for aria-hidden="true"
|
|
104
|
+
if (ariaHiddenAttr.value.value !== "true") {
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Check if the element is focusable
|
|
109
|
+
if (isFocusable(node)) {
|
|
110
|
+
context.report({
|
|
111
|
+
node: ariaHiddenAttr,
|
|
112
|
+
messageId: MESSAGE_IDS.UNEXPECTED,
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
},
|
|
116
|
+
});
|
|
117
|
+
},
|
|
118
|
+
};
|
|
@@ -1,10 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @
|
|
3
|
-
* @
|
|
4
|
-
* @typedef { import("@html-eslint/types").ScriptTag } ScriptTag
|
|
5
|
-
* @typedef { import("../types").RuleModule<[]> } RuleModule
|
|
6
|
-
* @typedef { import("@html-eslint/types").Attribute } Attribute
|
|
7
|
-
* @typedef { import("../types").SuggestionReportDescriptor } SuggestionReportDescriptor
|
|
2
|
+
* @import {Tag, StyleTag, ScriptTag, Attribute} from "@html-eslint/types";
|
|
3
|
+
* @import {RuleModule, SuggestionReportDescriptor} from "../types";
|
|
8
4
|
*/
|
|
9
5
|
|
|
10
6
|
const { RULE_CATEGORY } = require("../constants");
|
|
@@ -17,7 +13,7 @@ const MESSAGE_IDS = {
|
|
|
17
13
|
};
|
|
18
14
|
|
|
19
15
|
/**
|
|
20
|
-
* @type {RuleModule}
|
|
16
|
+
* @type {RuleModule<[]>}
|
|
21
17
|
*/
|
|
22
18
|
module.exports = {
|
|
23
19
|
meta: {
|
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @
|
|
3
|
-
* @
|
|
4
|
-
* @typedef { import("@html-eslint/types").ScriptTag } ScriptTag
|
|
5
|
-
* @typedef { import("@html-eslint/types").AttributeValue } AttributeValue
|
|
6
|
-
* @typedef { import("../types").RuleModule<[]> } RuleModule
|
|
2
|
+
* @import {AttributeValue} from "@html-eslint/types";
|
|
3
|
+
* @import {RuleModule} from "../types";
|
|
7
4
|
* @typedef {Object} ClassInfo
|
|
8
5
|
* @property {string} name
|
|
9
6
|
* @property {import("@html-eslint/types").AnyNode['loc']} loc
|
|
@@ -20,7 +17,7 @@ const MESSAGE_IDS = {
|
|
|
20
17
|
};
|
|
21
18
|
|
|
22
19
|
/**
|
|
23
|
-
* @type {RuleModule}
|
|
20
|
+
* @type {RuleModule<[]>}
|
|
24
21
|
*/
|
|
25
22
|
module.exports = {
|
|
26
23
|
meta: {
|
|
@@ -1,12 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @
|
|
3
|
-
* @
|
|
4
|
-
* @typedef { import("@html-eslint/types").ScriptTag } ScriptTag
|
|
5
|
-
* @typedef { import("@html-eslint/types").AttributeValue } AttributeValue
|
|
6
|
-
* @typedef { import("../types").RuleModule<[]> } RuleModule
|
|
2
|
+
* @import {Tag, AttributeValue} from "@html-eslint/types";
|
|
3
|
+
* @import {RuleModule} from "../types";
|
|
7
4
|
*/
|
|
8
5
|
|
|
9
|
-
const {
|
|
6
|
+
const { parseTemplateLiteral } = require("./utils/template-literal");
|
|
10
7
|
const { RULE_CATEGORY } = require("../constants");
|
|
11
8
|
const { findAttr } = require("./utils/node");
|
|
12
9
|
const {
|
|
@@ -21,7 +18,7 @@ const MESSAGE_IDS = {
|
|
|
21
18
|
};
|
|
22
19
|
|
|
23
20
|
/**
|
|
24
|
-
* @type {RuleModule}
|
|
21
|
+
* @type {RuleModule<[]>}
|
|
25
22
|
*/
|
|
26
23
|
module.exports = {
|
|
27
24
|
meta: {
|
|
@@ -93,7 +90,7 @@ module.exports = {
|
|
|
93
90
|
TaggedTemplateExpression(node) {
|
|
94
91
|
const idAttrsMap = new Map();
|
|
95
92
|
if (shouldCheckTaggedTemplateExpression(node, context)) {
|
|
96
|
-
|
|
93
|
+
parseTemplateLiteral(node.quasi, getSourceCode(context), {
|
|
97
94
|
Tag: createTagVisitor(idAttrsMap),
|
|
98
95
|
});
|
|
99
96
|
}
|
|
@@ -102,7 +99,7 @@ module.exports = {
|
|
|
102
99
|
TemplateLiteral(node) {
|
|
103
100
|
const idAttrsMap = new Map();
|
|
104
101
|
if (shouldCheckTemplateLiteral(node, context)) {
|
|
105
|
-
|
|
102
|
+
parseTemplateLiteral(node, getSourceCode(context), {
|
|
106
103
|
Tag: createTagVisitor(idAttrsMap),
|
|
107
104
|
});
|
|
108
105
|
}
|