@herb-tools/linter 0.5.0 → 0.6.1
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/dist/herb-lint.js +6627 -1937
- package/dist/herb-lint.js.map +1 -1
- package/dist/index.cjs +1574 -210
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1566 -212
- package/dist/index.js.map +1 -1
- package/dist/package.json +5 -4
- package/dist/src/cli/argument-parser.js +0 -4
- package/dist/src/cli/argument-parser.js.map +1 -1
- package/dist/src/default-rules.js +20 -0
- package/dist/src/default-rules.js.map +1 -1
- package/dist/src/linter.js +29 -4
- package/dist/src/linter.js.map +1 -1
- package/dist/src/rules/erb-no-silent-tag-in-attribute-name.js +26 -0
- package/dist/src/rules/erb-no-silent-tag-in-attribute-name.js.map +1 -0
- package/dist/src/rules/erb-prefer-image-tag-helper.js +50 -64
- package/dist/src/rules/erb-prefer-image-tag-helper.js.map +1 -1
- package/dist/src/rules/html-aria-attribute-must-be-valid.js +11 -10
- package/dist/src/rules/html-aria-attribute-must-be-valid.js.map +1 -1
- package/dist/src/rules/html-aria-label-is-well-formatted.js +33 -0
- package/dist/src/rules/html-aria-label-is-well-formatted.js.map +1 -0
- package/dist/src/rules/html-aria-level-must-be-valid.js +26 -4
- package/dist/src/rules/html-aria-level-must-be-valid.js.map +1 -1
- package/dist/src/rules/html-aria-role-heading-requires-level.js +7 -13
- package/dist/src/rules/html-aria-role-heading-requires-level.js.map +1 -1
- package/dist/src/rules/html-aria-role-must-be-valid.js +3 -3
- package/dist/src/rules/html-aria-role-must-be-valid.js.map +1 -1
- package/dist/src/rules/html-attribute-double-quotes.js +14 -4
- package/dist/src/rules/html-attribute-double-quotes.js.map +1 -1
- package/dist/src/rules/html-attribute-equals-spacing.js +24 -0
- package/dist/src/rules/html-attribute-equals-spacing.js.map +1 -0
- package/dist/src/rules/html-attribute-values-require-quotes.js +19 -8
- package/dist/src/rules/html-attribute-values-require-quotes.js.map +1 -1
- package/dist/src/rules/html-avoid-both-disabled-and-aria-disabled.js +47 -0
- package/dist/src/rules/html-avoid-both-disabled-and-aria-disabled.js.map +1 -0
- package/dist/src/rules/html-boolean-attributes-no-value.js +9 -2
- package/dist/src/rules/html-boolean-attributes-no-value.js.map +1 -1
- package/dist/src/rules/html-iframe-has-title.js +39 -0
- package/dist/src/rules/html-iframe-has-title.js.map +1 -0
- package/dist/src/rules/html-img-require-alt.js +0 -4
- package/dist/src/rules/html-img-require-alt.js.map +1 -1
- package/dist/src/rules/html-navigation-has-label.js +43 -0
- package/dist/src/rules/html-navigation-has-label.js.map +1 -0
- package/dist/src/rules/html-no-aria-hidden-on-focusable.js +67 -0
- package/dist/src/rules/html-no-aria-hidden-on-focusable.js.map +1 -0
- package/dist/src/rules/html-no-duplicate-attributes.js +22 -25
- package/dist/src/rules/html-no-duplicate-attributes.js.map +1 -1
- package/dist/src/rules/html-no-duplicate-ids.js +134 -9
- package/dist/src/rules/html-no-duplicate-ids.js.map +1 -1
- package/dist/src/rules/html-no-empty-headings.js +0 -21
- package/dist/src/rules/html-no-empty-headings.js.map +1 -1
- package/dist/src/rules/html-no-positive-tab-index.js +21 -0
- package/dist/src/rules/html-no-positive-tab-index.js.map +1 -0
- package/dist/src/rules/html-no-self-closing.js +29 -0
- package/dist/src/rules/html-no-self-closing.js.map +1 -0
- package/dist/src/rules/html-no-title-attribute.js +27 -0
- package/dist/src/rules/html-no-title-attribute.js.map +1 -0
- package/dist/src/rules/html-tag-name-lowercase.js +35 -23
- package/dist/src/rules/html-tag-name-lowercase.js.map +1 -1
- package/dist/src/rules/index.js +10 -0
- package/dist/src/rules/index.js.map +1 -1
- package/dist/src/rules/rule-utils.js +245 -22
- package/dist/src/rules/rule-utils.js.map +1 -1
- package/dist/src/rules/svg-tag-name-capitalization.js +0 -8
- package/dist/src/rules/svg-tag-name-capitalization.js.map +1 -1
- package/dist/src/types.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/types/cli/index.d.ts +4 -0
- package/dist/types/rules/erb-no-silent-tag-in-attribute-name.d.ts +7 -0
- package/dist/types/rules/html-aria-label-is-well-formatted.d.ts +7 -0
- package/dist/types/rules/html-attribute-equals-spacing.d.ts +7 -0
- package/dist/types/rules/html-avoid-both-disabled-and-aria-disabled.d.ts +7 -0
- package/dist/types/rules/html-iframe-has-title.d.ts +7 -0
- package/dist/types/rules/html-navigation-has-label.d.ts +7 -0
- package/dist/types/rules/html-no-aria-hidden-on-focusable.d.ts +7 -0
- package/dist/types/rules/html-no-positive-tab-index.d.ts +7 -0
- package/dist/types/rules/html-no-self-closing.d.ts +7 -0
- package/dist/types/rules/html-no-title-attribute.d.ts +7 -0
- package/dist/types/rules/html-tag-name-lowercase.d.ts +2 -1
- package/dist/types/rules/index.d.ts +10 -0
- package/dist/types/rules/rule-utils.d.ts +146 -13
- package/dist/types/src/rules/erb-no-silent-tag-in-attribute-name.d.ts +7 -0
- package/dist/types/src/rules/html-aria-label-is-well-formatted.d.ts +7 -0
- package/dist/types/src/rules/html-attribute-equals-spacing.d.ts +7 -0
- package/dist/types/src/rules/html-avoid-both-disabled-and-aria-disabled.d.ts +7 -0
- package/dist/types/src/rules/html-iframe-has-title.d.ts +7 -0
- package/dist/types/src/rules/html-navigation-has-label.d.ts +7 -0
- package/dist/types/src/rules/html-no-aria-hidden-on-focusable.d.ts +7 -0
- package/dist/types/src/rules/html-no-positive-tab-index.d.ts +7 -0
- package/dist/types/src/rules/html-no-self-closing.d.ts +7 -0
- package/dist/types/src/rules/html-no-title-attribute.d.ts +7 -0
- package/dist/types/src/rules/html-tag-name-lowercase.d.ts +2 -1
- package/dist/types/src/rules/index.d.ts +10 -0
- package/dist/types/src/rules/rule-utils.d.ts +146 -13
- package/dist/types/src/types.d.ts +24 -0
- package/dist/types/types.d.ts +24 -0
- package/docs/rules/README.md +12 -2
- package/docs/rules/erb-no-silent-tag-in-attribute-name.md +34 -0
- package/docs/rules/html-aria-label-is-well-formatted.md +49 -0
- package/docs/rules/html-attribute-equals-spacing.md +35 -0
- package/docs/rules/html-avoid-both-disabled-and-aria-disabled.md +48 -0
- package/docs/rules/html-iframe-has-title.md +43 -0
- package/docs/rules/html-navigation-has-label.md +61 -0
- package/docs/rules/html-no-aria-hidden-on-focusable.md +54 -0
- package/docs/rules/html-no-positive-tab-index.md +55 -0
- package/docs/rules/html-no-self-closing.md +65 -0
- package/docs/rules/html-no-title-attribute.md +69 -0
- package/docs/rules/html-tag-name-lowercase.md +16 -3
- package/package.json +5 -4
- package/src/cli/argument-parser.ts +0 -5
- package/src/default-rules.ts +20 -0
- package/src/linter.ts +30 -4
- package/src/rules/erb-no-silent-tag-in-attribute-name.ts +40 -0
- package/src/rules/erb-prefer-image-tag-helper.ts +53 -76
- package/src/rules/html-aria-attribute-must-be-valid.ts +28 -32
- package/src/rules/html-aria-label-is-well-formatted.ts +59 -0
- package/src/rules/html-aria-level-must-be-valid.ts +38 -5
- package/src/rules/html-aria-role-heading-requires-level.ts +16 -28
- package/src/rules/html-aria-role-must-be-valid.ts +5 -5
- package/src/rules/html-attribute-double-quotes.ts +21 -6
- package/src/rules/html-attribute-equals-spacing.ts +41 -0
- package/src/rules/html-attribute-values-require-quotes.ts +29 -9
- package/src/rules/html-avoid-both-disabled-and-aria-disabled.ts +66 -0
- package/src/rules/html-boolean-attributes-no-value.ts +17 -4
- package/src/rules/html-iframe-has-title.ts +62 -0
- package/src/rules/html-img-require-alt.ts +2 -7
- package/src/rules/html-navigation-has-label.ts +64 -0
- package/src/rules/html-no-aria-hidden-on-focusable.ts +90 -0
- package/src/rules/html-no-duplicate-attributes.ts +28 -28
- package/src/rules/html-no-duplicate-ids.ts +189 -14
- package/src/rules/html-no-empty-headings.ts +2 -31
- package/src/rules/html-no-positive-tab-index.ts +33 -0
- package/src/rules/html-no-self-closing.ts +41 -0
- package/src/rules/html-no-title-attribute.ts +42 -0
- package/src/rules/html-tag-name-lowercase.ts +42 -29
- package/src/rules/index.ts +10 -0
- package/src/rules/rule-utils.ts +357 -39
- package/src/rules/svg-tag-name-capitalization.ts +2 -9
- package/src/types.ts +27 -0
package/dist/types/types.d.ts
CHANGED
|
@@ -19,11 +19,27 @@ export declare abstract class ParserRule {
|
|
|
19
19
|
static type: "parser";
|
|
20
20
|
abstract name: string;
|
|
21
21
|
abstract check(result: ParseResult, context?: Partial<LintContext>): LintOffense[];
|
|
22
|
+
/**
|
|
23
|
+
* Optional method to determine if this rule should run.
|
|
24
|
+
* If not implemented, rule is always enabled.
|
|
25
|
+
* @param result - The parse result to analyze
|
|
26
|
+
* @param context - Optional context for linting
|
|
27
|
+
* @returns true if rule should run, false to skip
|
|
28
|
+
*/
|
|
29
|
+
isEnabled?(result: ParseResult, context?: Partial<LintContext>): boolean;
|
|
22
30
|
}
|
|
23
31
|
export declare abstract class LexerRule {
|
|
24
32
|
static type: "lexer";
|
|
25
33
|
abstract name: string;
|
|
26
34
|
abstract check(lexResult: LexResult, context?: Partial<LintContext>): LintOffense[];
|
|
35
|
+
/**
|
|
36
|
+
* Optional method to determine if this rule should run.
|
|
37
|
+
* If not implemented, rule is always enabled.
|
|
38
|
+
* @param lexResult - The lex result to analyze
|
|
39
|
+
* @param context - Optional context for linting
|
|
40
|
+
* @returns true if rule should run, false to skip
|
|
41
|
+
*/
|
|
42
|
+
isEnabled?(lexResult: LexResult, context?: Partial<LintContext>): boolean;
|
|
27
43
|
}
|
|
28
44
|
export interface LexerRuleConstructor {
|
|
29
45
|
type: "lexer";
|
|
@@ -44,6 +60,14 @@ export declare abstract class SourceRule {
|
|
|
44
60
|
static type: "source";
|
|
45
61
|
abstract name: string;
|
|
46
62
|
abstract check(source: string, context?: Partial<LintContext>): LintOffense[];
|
|
63
|
+
/**
|
|
64
|
+
* Optional method to determine if this rule should run.
|
|
65
|
+
* If not implemented, rule is always enabled.
|
|
66
|
+
* @param source - The source code to analyze
|
|
67
|
+
* @param context - Optional context for linting
|
|
68
|
+
* @returns true if rule should run, false to skip
|
|
69
|
+
*/
|
|
70
|
+
isEnabled?(source: string, context?: Partial<LintContext>): boolean;
|
|
47
71
|
}
|
|
48
72
|
export interface SourceRuleConstructor {
|
|
49
73
|
type: "source";
|
package/docs/rules/README.md
CHANGED
|
@@ -6,22 +6,32 @@ This page contains documentation for all Herb Linter rules.
|
|
|
6
6
|
|
|
7
7
|
- [`erb-no-empty-tags`](./erb-no-empty-tags.md) - Disallow empty ERB tags
|
|
8
8
|
- [`erb-no-output-control-flow`](./erb-no-output-control-flow.md) - Prevents outputting control flow blocks
|
|
9
|
+
- [`erb-no-silent-tag-in-attribute-name`](./erb-no-silent-tag-in-attribute-name.md) - Disallow ERB silent tags in HTML attribute names
|
|
9
10
|
- [`erb-prefer-image-tag-helper`](./erb-prefer-image-tag-helper.md) - Prefer `image_tag` helper over `<img>` with ERB expressions
|
|
10
|
-
- [`erb-require-whitespace-inside-tags`](./erb-require-whitespace-inside-tags.md) - Requires whitespace around
|
|
11
|
+
- [`erb-require-whitespace-inside-tags`](./erb-require-whitespace-inside-tags.md) - Requires whitespace around ERB tags
|
|
11
12
|
- [`erb-requires-trailing-newline`](./erb-requires-trailing-newline.md) - Enforces that all HTML+ERB template files end with exactly one trailing newline character.
|
|
12
13
|
- [`html-anchor-require-href`](./html-anchor-require-href.md) - Requires an href attribute on anchor tags
|
|
13
14
|
- [`html-aria-attribute-must-be-valid`](./html-aria-attribute-must-be-valid.md) - Disallow invalid or unknown `aria-*` attributes.
|
|
15
|
+
- [`html-aria-label-is-well-formatted`](./html-aria-label-is-well-formatted.md) - `aria-label` must be well-formatted
|
|
14
16
|
- [`html-aria-level-must-be-valid`](./html-aria-level-must-be-valid.md) - `aria-level` must be between 1 and 6
|
|
15
17
|
- [`html-aria-role-heading-requires-level`](./html-aria-role-heading-requires-level.md) - Requires `aria-level` when supplying a `role`
|
|
16
18
|
- [`html-aria-role-must-be-valid`](./html-aria-role-must-be-valid.md) - The `role` attribute must have a valid WAI-ARIA Role.
|
|
17
19
|
- [`html-attribute-double-quotes`](./html-attribute-double-quotes.md) - Enforces double quotes for attribute values
|
|
20
|
+
- [`html-attribute-equals-spacing`](./html-attribute-equals-spacing.md) - No whitespace around `=` in HTML attributes
|
|
18
21
|
- [`html-attribute-values-require-quotes`](./html-attribute-values-require-quotes.md) - Requires quotes around attribute values
|
|
22
|
+
- [`html-avoid-both-disabled-and-aria-disabled`](./html-avoid-both-disabled-and-aria-disabled.md) - Avoid using both `disabled` and `aria-disabled` attributes
|
|
19
23
|
- [`html-boolean-attributes-no-value`](./html-boolean-attributes-no-value.md) - Prevents values on boolean attributes
|
|
20
|
-
- [`html-
|
|
24
|
+
- [`html-iframe-has-title`](./html-iframe-has-title.md) - `iframe` elements must have a `title` attribute
|
|
25
|
+
- [`html-img-require-alt`](./html-img-require-alt.md) - Requires `alt` attributes on `<img>` tags
|
|
26
|
+
- [`html-navigation-has-label`](./html-navigation-has-label.md) - Navigation landmarks must have accessible labels
|
|
27
|
+
- [`html-no-aria-hidden-on-focusable`](./html-no-aria-hidden-on-focusable.md) - Focusable elements should not have `aria-hidden="true"`
|
|
21
28
|
- [`html-no-block-inside-inline`](./html-no-block-inside-inline.md) - Prevents block-level elements inside inline elements
|
|
22
29
|
- [`html-no-duplicate-attributes`](./html-no-duplicate-attributes.md) - Prevents duplicate attributes on HTML elements
|
|
23
30
|
- [`html-no-duplicate-ids`](./html-no-duplicate-ids.md) - Prevents duplicate IDs within a document
|
|
24
31
|
- [`html-no-nested-links`](./html-no-nested-links.md) - Prevents nested anchor tags
|
|
32
|
+
- [`html-no-positive-tab-index`](./html-no-positive-tab-index.md) - Avoid positive `tabindex` values
|
|
33
|
+
- [`html-no-self-closing`](./html-no-self-closing.md.md) - Disallow self closing tags
|
|
34
|
+
- [`html-no-title-attribute`](./html-no-title-attribute.md) - Avoid using the `title` attribute
|
|
25
35
|
- [`html-tag-name-lowercase`](./html-tag-name-lowercase.md) - Enforces lowercase tag names in HTML
|
|
26
36
|
- [`parser-no-errors`](./parser-no-errors.md) - Disallow parser errors in HTML+ERB documents
|
|
27
37
|
- [`svg-tag-name-capitalization`](./svg-tag-name-capitalization.md) - Enforces proper camelCase capitalization for SVG elements
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Linter Rule: Disallow ERB silent tags in HTML attribute names
|
|
2
|
+
|
|
3
|
+
**Rule:** `erb-no-silent-tag-in-attribute-name`
|
|
4
|
+
|
|
5
|
+
## Description
|
|
6
|
+
|
|
7
|
+
Disallow the use of ERB silent tags (`<% ... %>`) inside HTML attribute names. These tags introduce Ruby logic that does not output anything, and placing them in attribute names leads to malformed HTML or completely unpredictable rendering.
|
|
8
|
+
|
|
9
|
+
## Rationale
|
|
10
|
+
|
|
11
|
+
HTML attribute names, ideally, must be valid, statically defined strings. Placing ERB silent tags (`<% ... %>`) that don't output anything inside attribute names might result in invalid HTML and is confusing. These cases are rarely intentional and almost always indicate a mistake or misuse of ERB templating.
|
|
12
|
+
|
|
13
|
+
## Examples
|
|
14
|
+
|
|
15
|
+
### ✅ Good
|
|
16
|
+
|
|
17
|
+
```erb
|
|
18
|
+
<div data-<%= key %>-target="value"></div>
|
|
19
|
+
<div <%= data_attributes_for(user) %>></div>
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
### 🚫 Bad
|
|
23
|
+
|
|
24
|
+
```erb
|
|
25
|
+
<div data-<% key %>-id="value"></div>
|
|
26
|
+
|
|
27
|
+
<div data-<%# key %>-id="thing"></div>
|
|
28
|
+
|
|
29
|
+
<div data-<%- key -%>-id="thing"></div>
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## References
|
|
33
|
+
|
|
34
|
+
\-
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# Linter Rule: `aria-label` must be well-formatted
|
|
2
|
+
|
|
3
|
+
**Rule:** `html-aria-label-is-well-formatted`
|
|
4
|
+
|
|
5
|
+
## Description
|
|
6
|
+
|
|
7
|
+
Ensure that the value of the `aria-label` attribute is formatted like natural, visual text. The text should use sentence case (capitalize the first letter), avoid line breaks, and not look like an ID or code identifier.
|
|
8
|
+
|
|
9
|
+
## Rationale
|
|
10
|
+
|
|
11
|
+
The `aria-label` attribute provides an accessible name for elements that will be read aloud by screen readers. The text should be formatted like natural language that users would expect to hear, not like technical identifiers. Using proper sentence case and avoiding formatting that looks like code (snake_case, kebab-case, camelCase) ensures a better user experience for assistive technology users.
|
|
12
|
+
|
|
13
|
+
## Examples
|
|
14
|
+
|
|
15
|
+
### ✅ Good
|
|
16
|
+
|
|
17
|
+
```erb
|
|
18
|
+
<button aria-label="Close dialog">X</button>
|
|
19
|
+
<input aria-label="Search products" type="search">
|
|
20
|
+
<button aria-label="Page 2 of 10">2</button>
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
### 🚫 Bad
|
|
24
|
+
|
|
25
|
+
```erb
|
|
26
|
+
<!-- Starts with lowercase -->
|
|
27
|
+
<button aria-label="close dialog">X</button>
|
|
28
|
+
|
|
29
|
+
<!-- Contains line breaks -->
|
|
30
|
+
<button aria-label="Close
|
|
31
|
+
dialog">X</button>
|
|
32
|
+
|
|
33
|
+
<!-- Looks like an ID (snake_case) -->
|
|
34
|
+
<button aria-label="close_dialog">X</button>
|
|
35
|
+
|
|
36
|
+
<!-- Looks like an ID (kebab-case) -->
|
|
37
|
+
<button aria-label="close-dialog">X</button>
|
|
38
|
+
|
|
39
|
+
<!-- Looks like an ID (camelCase) -->
|
|
40
|
+
<button aria-label="closeDialog">X</button>
|
|
41
|
+
|
|
42
|
+
<!-- HTML entity line breaks -->
|
|
43
|
+
<button aria-label="Close dialog">X</button>
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## References
|
|
47
|
+
|
|
48
|
+
- [ARIA: `aria-label` attribute](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Reference/Attributes/aria-label)
|
|
49
|
+
- [erblint-github: GitHub::Accessibility::AriaLabelIsWellFormatted](https://github.com/github/erblint-github/blob/main/docs/rules/accessibility/aria-label-is-well-formatted.md)
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# Linter Rule: No whitespace around `=` in HTML attributes
|
|
2
|
+
|
|
3
|
+
**Rule:** `html-attribute-equals-spacing`
|
|
4
|
+
|
|
5
|
+
## Description
|
|
6
|
+
|
|
7
|
+
Disallow whitespace before or after the equals sign (`=`) for attribute values in HTML. Attributes must follow the canonical format (`name="value"`) with no spaces between the attribute name, the equals sign, or the opening quote.
|
|
8
|
+
|
|
9
|
+
## Rationale
|
|
10
|
+
|
|
11
|
+
Extra whitespace around the `=` in HTML attribute assignments is unnecessary, inconsistent, and not idiomatic. While browsers are usually forgiving, it can lead to confusing diffs, poor formatting, or inconsistent parsing in tools.
|
|
12
|
+
|
|
13
|
+
## Examples
|
|
14
|
+
|
|
15
|
+
### ✅ Good
|
|
16
|
+
|
|
17
|
+
```erb
|
|
18
|
+
<div class="container"></div>
|
|
19
|
+
<img src="/logo.png" alt="Logo">
|
|
20
|
+
<input type="text" value="<%= @value %>">
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
### 🚫 Bad
|
|
24
|
+
|
|
25
|
+
```erb
|
|
26
|
+
<div class ="container"></div>
|
|
27
|
+
|
|
28
|
+
<img src= "/logo.png" alt="Logo">
|
|
29
|
+
|
|
30
|
+
<input type = "text">
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## References
|
|
34
|
+
|
|
35
|
+
\-
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# Linter Rule: Avoid using both `disabled` and `aria-disabled` attributes
|
|
2
|
+
|
|
3
|
+
**Rule:** `html-avoid-both-disabled-and-aria-disabled`
|
|
4
|
+
|
|
5
|
+
## Description
|
|
6
|
+
|
|
7
|
+
Prevent using both the native `disabled` attribute and the `aria-disabled` attribute on the same HTML element. Elements should use either the native `disabled` attribute or `aria-disabled`, but not both.
|
|
8
|
+
|
|
9
|
+
## Rationale
|
|
10
|
+
|
|
11
|
+
Using both `disabled` and `aria-disabled` on the same element creates redundancy and potential confusion for assistive technologies. The native `disabled` attribute provides both visual and functional disabling, while `aria-disabled` only provides semantic information without preventing interaction. Having both can lead to inconsistent behavior and unclear expectations for users.
|
|
12
|
+
|
|
13
|
+
Elements that support the native `disabled` attribute include: `button`, `fieldset`, `input`, `optgroup`, `option`, `select`, and `textarea`.
|
|
14
|
+
|
|
15
|
+
## Examples
|
|
16
|
+
|
|
17
|
+
### ✅ Good
|
|
18
|
+
|
|
19
|
+
```erb
|
|
20
|
+
<!-- Use only the native disabled attribute -->
|
|
21
|
+
<button disabled>Submit</button>
|
|
22
|
+
<input type="text" disabled>
|
|
23
|
+
|
|
24
|
+
<!-- Use only aria-disabled for custom elements -->
|
|
25
|
+
<div role="button" aria-disabled="true">Custom Button</div>
|
|
26
|
+
|
|
27
|
+
<!-- Use only aria-disabled -->
|
|
28
|
+
<button aria-disabled="true">Submit</button>
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### 🚫 Bad
|
|
32
|
+
|
|
33
|
+
```erb
|
|
34
|
+
<!-- Both disabled and aria-disabled -->
|
|
35
|
+
<button disabled aria-disabled="true">Submit</button>
|
|
36
|
+
|
|
37
|
+
<input type="text" disabled aria-disabled="true">
|
|
38
|
+
|
|
39
|
+
<select disabled aria-disabled="true">
|
|
40
|
+
<option>Option 1</option>
|
|
41
|
+
</select>
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## References
|
|
45
|
+
|
|
46
|
+
- [HTML: `disabled` attribute](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/disabled)
|
|
47
|
+
- [ARIA: `aria-disabled` attribute](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Reference/Attributes/aria-disabled)
|
|
48
|
+
- [erblint-github: GitHub::Accessibility::AvoidBothDisabledAndAriaDisabled](https://github.com/github/erblint-github/blob/main/docs/rules/accessibility/avoid-both-disabled-and-aria-disabled.md)
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# Linter Rule: `iframe` elements must have a `title` attribute
|
|
2
|
+
|
|
3
|
+
**Rule:** `html-iframe-has-title`
|
|
4
|
+
|
|
5
|
+
## Description
|
|
6
|
+
|
|
7
|
+
Ensure that all `iframe` elements have a meaningful `title` attribute that describes the content of the frame. The title should not be empty or contain only whitespace.
|
|
8
|
+
|
|
9
|
+
## Rationale
|
|
10
|
+
|
|
11
|
+
The `title` attribute on `iframe` elements provides essential context for screen reader users about what content the frame contains. Without this information, users of assistive technology cannot understand the purpose or content of the embedded frame, creating significant accessibility barriers.
|
|
12
|
+
|
|
13
|
+
::: tip Note
|
|
14
|
+
`<iframe>`'s with `aria-hidden="true"` are exempt from this requirement as they are hidden from assistive technologies.
|
|
15
|
+
:::
|
|
16
|
+
|
|
17
|
+
## Examples
|
|
18
|
+
|
|
19
|
+
### ✅ Good
|
|
20
|
+
|
|
21
|
+
```erb
|
|
22
|
+
<iframe src="https://youtube.com/embed/123" title="Product demonstration video"></iframe>
|
|
23
|
+
<iframe src="https://example.com" title="Example website content"></iframe>
|
|
24
|
+
|
|
25
|
+
<!-- Hidden from screen readers -->
|
|
26
|
+
<iframe aria-hidden="true"></iframe>
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
### 🚫 Bad
|
|
30
|
+
|
|
31
|
+
```erb
|
|
32
|
+
<iframe src="https://example.com"></iframe>
|
|
33
|
+
|
|
34
|
+
<iframe src="https://example.com" title=""></iframe>
|
|
35
|
+
|
|
36
|
+
<iframe src="https://example.com" title=" "></iframe>
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## References
|
|
40
|
+
|
|
41
|
+
- [HTML: `iframe` element](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe)
|
|
42
|
+
- [HTML: `title` attribute](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/title)
|
|
43
|
+
- [erblint-github: GitHub::Accessibility::IframeHasTitle](https://github.com/github/erblint-github/blob/main/docs/rules/accessibility/iframe-has-title.md)
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# Linter Rule: Navigation landmarks must have accessible labels
|
|
2
|
+
|
|
3
|
+
**Rule:** `html-navigation-has-label`
|
|
4
|
+
|
|
5
|
+
## Description
|
|
6
|
+
|
|
7
|
+
Ensure that navigation landmarks have a unique accessible name via `aria-label` or `aria-labelledby` attributes. This applies to both `<nav>` elements and elements with `role="navigation"`.
|
|
8
|
+
|
|
9
|
+
## Rationale
|
|
10
|
+
|
|
11
|
+
Navigation landmarks help users of assistive technology quickly understand and navigate to different sections of a website. When multiple navigation landmarks exist on a page, each needs a unique accessible name so users can distinguish between them (e.g., "Main navigation", "Footer links", "Breadcrumb navigation").
|
|
12
|
+
|
|
13
|
+
## Examples
|
|
14
|
+
|
|
15
|
+
### ✅ Good
|
|
16
|
+
|
|
17
|
+
```erb
|
|
18
|
+
<nav aria-label="Main navigation">
|
|
19
|
+
<ul>
|
|
20
|
+
<li><a href="/">Home</a></li>
|
|
21
|
+
<li><a href="/about">About</a></li>
|
|
22
|
+
</ul>
|
|
23
|
+
</nav>
|
|
24
|
+
|
|
25
|
+
<nav aria-labelledby="breadcrumb-title">
|
|
26
|
+
<h2 id="breadcrumb-title">Breadcrumb</h2>
|
|
27
|
+
<ol>
|
|
28
|
+
<li><a href="/">Home</a></li>
|
|
29
|
+
<li>Current Page</li>
|
|
30
|
+
</ol>
|
|
31
|
+
</nav>
|
|
32
|
+
|
|
33
|
+
<div role="navigation" aria-label="Footer links">
|
|
34
|
+
<a href="/privacy">Privacy</a>
|
|
35
|
+
<a href="/terms">Terms</a>
|
|
36
|
+
</div>
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### 🚫 Bad
|
|
40
|
+
|
|
41
|
+
```erb
|
|
42
|
+
<nav>
|
|
43
|
+
<ul>
|
|
44
|
+
<li><a href="/">Home</a></li>
|
|
45
|
+
<li><a href="/about">About</a></li>
|
|
46
|
+
</ul>
|
|
47
|
+
</nav>
|
|
48
|
+
|
|
49
|
+
<div role="navigation">
|
|
50
|
+
<a href="/privacy">Privacy</a>
|
|
51
|
+
<a href="/terms">Terms</a>
|
|
52
|
+
</div>
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## References
|
|
56
|
+
|
|
57
|
+
- [ARIA: `navigation` role](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Reference/Roles/navigation_role)
|
|
58
|
+
- [HTML: `nav` element](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/nav)
|
|
59
|
+
- [ARIA: `aria-label` attribute](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Reference/Attributes/aria-label)
|
|
60
|
+
- [ARIA: `aria-labelledby` attribute](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Reference/Attributes/aria-labelledby)
|
|
61
|
+
- [erblint-github: GitHub::Accessibility::NavigationHasLabel](https://github.com/github/erblint-github/blob/main/docs/rules/accessibility/navigation-has-label.md)
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# Linter Rule: Focusable elements should not have `aria-hidden="true"`
|
|
2
|
+
|
|
3
|
+
**Rule:** `html-no-aria-hidden-on-focusable`
|
|
4
|
+
|
|
5
|
+
## Description
|
|
6
|
+
|
|
7
|
+
Prevent using `aria-hidden="true"` on elements that can receive keyboard focus. When an element is focusable but hidden from screen readers, it creates a confusing experience where keyboard users can tab to "invisible" elements.
|
|
8
|
+
|
|
9
|
+
## Rationale
|
|
10
|
+
|
|
11
|
+
Elements with `aria-hidden="true"` are completely hidden from assistive technologies, but they remain visible and interactive for mouse and keyboard users. If a focusable element is hidden from screen readers, keyboard-only users (especially those using screen readers) will encounter focused elements that provide no accessible information, creating a broken user experience.
|
|
12
|
+
|
|
13
|
+
## Examples
|
|
14
|
+
|
|
15
|
+
### ✅ Good
|
|
16
|
+
|
|
17
|
+
```erb
|
|
18
|
+
<button>Submit</button>
|
|
19
|
+
<a href="/link">Link</a>
|
|
20
|
+
<input type="text">
|
|
21
|
+
<textarea></textarea>
|
|
22
|
+
|
|
23
|
+
<div aria-hidden="true">Decorative content</div>
|
|
24
|
+
<span aria-hidden="true">🎉</span>
|
|
25
|
+
|
|
26
|
+
<button tabindex="-1" aria-hidden="true">Hidden button</button>
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
### 🚫 Bad
|
|
30
|
+
|
|
31
|
+
```erb
|
|
32
|
+
<button aria-hidden="true">Submit</button>
|
|
33
|
+
|
|
34
|
+
<a href="/link" aria-hidden="true">Link</a>
|
|
35
|
+
|
|
36
|
+
<input type="text" aria-hidden="true">
|
|
37
|
+
|
|
38
|
+
<textarea aria-hidden="true"></textarea>
|
|
39
|
+
|
|
40
|
+
<select aria-hidden="true">
|
|
41
|
+
<option>Option</option>
|
|
42
|
+
</select>
|
|
43
|
+
|
|
44
|
+
<div tabindex="0" aria-hidden="true">Focusable div</div>
|
|
45
|
+
|
|
46
|
+
<a href="/link" aria-hidden="true">Hidden link</a>
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## References
|
|
50
|
+
|
|
51
|
+
- [ARIA: `aria-hidden` attribute](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Reference/Attributes/aria-hidden)
|
|
52
|
+
- [HTML: `tabindex` attribute](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/tabindex)
|
|
53
|
+
- [WebAIM: Keyboard Accessibility](https://webaim.org/techniques/keyboard/)
|
|
54
|
+
- [erblint-github: GitHub::Accessibility::NoAriaHiddenOnFocusable](https://github.com/github/erblint-github/blob/main/docs/rules/accessibility/no-aria-hidden-on-focusable.md)
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# Linter Rule: Avoid positive `tabindex` values
|
|
2
|
+
|
|
3
|
+
**Rule:** `html-no-positive-tab-index`
|
|
4
|
+
|
|
5
|
+
## Description
|
|
6
|
+
|
|
7
|
+
Prevent using positive values for the `tabindex` attribute. Only `tabindex="0"` (to make elements focusable) and `tabindex="-1"` (to remove from tab order) should be used.
|
|
8
|
+
|
|
9
|
+
## Rationale
|
|
10
|
+
|
|
11
|
+
Positive `tabindex` values create a custom tab order that can be confusing and unpredictable for keyboard users. They override the natural document flow and can cause elements to be focused in an unexpected sequence. This breaks the logical reading order and creates usability issues, especially for screen reader users who rely on a predictable navigation pattern.
|
|
12
|
+
|
|
13
|
+
The recommended approach is to structure your HTML in the correct tab order and use `tabindex="0"` only when you need to make non-interactive elements focusable, or `tabindex="-1"` to remove elements from the tab sequence while keeping them programmatically focusable.
|
|
14
|
+
|
|
15
|
+
## Examples
|
|
16
|
+
|
|
17
|
+
### ✅ Good
|
|
18
|
+
|
|
19
|
+
```erb
|
|
20
|
+
<!-- Natural tab order (no tabindex needed) -->
|
|
21
|
+
<button>First</button>
|
|
22
|
+
<button>Second</button>
|
|
23
|
+
<button>Third</button>
|
|
24
|
+
|
|
25
|
+
<!-- Make non-interactive element focusable -->
|
|
26
|
+
<div tabindex="0" role="button">Custom button</div>
|
|
27
|
+
|
|
28
|
+
<!-- Remove from tab order but keep programmatically focusable -->
|
|
29
|
+
<button tabindex="-1">Skip this in tab order</button>
|
|
30
|
+
|
|
31
|
+
<!-- Zero tabindex to ensure focusability -->
|
|
32
|
+
<span tabindex="0" role="button">Focusable span</span>
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### 🚫 Bad
|
|
36
|
+
|
|
37
|
+
```erb
|
|
38
|
+
<button tabindex="3">Third in tab order</button>
|
|
39
|
+
|
|
40
|
+
<button tabindex="1">First in tab order</button>
|
|
41
|
+
|
|
42
|
+
<button tabindex="2">Second in tab order</button>
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
<input tabindex="5" type="text">
|
|
46
|
+
|
|
47
|
+
<button tabindex="10">Submit</button>
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## References
|
|
51
|
+
|
|
52
|
+
- [HTML: `tabindex` attribute](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/tabindex)
|
|
53
|
+
- [WebAIM: Keyboard Accessibility](https://webaim.org/techniques/keyboard/tabindex)
|
|
54
|
+
- [WCAG: Focus Order](https://www.w3.org/WAI/WCAG21/Understanding/focus-order.html)
|
|
55
|
+
- [erblint-github: GitHub::Accessibility::NoPositiveTabIndex](https://github.com/github/erblint-github/blob/main/docs/rules/accessibility/no-positive-tab-index.md)
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# Linter Rule: Disallow self-closing tag syntax for void elements
|
|
2
|
+
|
|
3
|
+
**Rule:** `html-no-self-closing`
|
|
4
|
+
|
|
5
|
+
## Description
|
|
6
|
+
|
|
7
|
+
Disallow self-closing syntax (`<tag />`) in HTML for all elements.
|
|
8
|
+
|
|
9
|
+
In HTML5, the trailing slash in a start tag is obsolete and has no effect.
|
|
10
|
+
Non-void elements require explicit end tags, and void elements are
|
|
11
|
+
self-contained without the slash.
|
|
12
|
+
|
|
13
|
+
## Rationale
|
|
14
|
+
|
|
15
|
+
Self-closing syntax is an XHTML artifact. In HTML:
|
|
16
|
+
|
|
17
|
+
- On **non-void** elements, it’s a parse error and produces invalid markup
|
|
18
|
+
(`<div />` is invalid).
|
|
19
|
+
- On **void elements**, the slash is ignored and unnecessary (`<input />` is
|
|
20
|
+
equivalent to `<input>`).
|
|
21
|
+
|
|
22
|
+
Removing the slash ensures HTML5-compliant, cleaner markup and avoids mixing
|
|
23
|
+
XHTML and HTML styles.
|
|
24
|
+
|
|
25
|
+
## Examples
|
|
26
|
+
|
|
27
|
+
### ✅ Good
|
|
28
|
+
|
|
29
|
+
```html
|
|
30
|
+
<span></span>
|
|
31
|
+
<div></div>
|
|
32
|
+
<section></section>
|
|
33
|
+
<custom-element></custom-element>
|
|
34
|
+
|
|
35
|
+
<img src="/logo.png" alt="Logo">
|
|
36
|
+
<input type="text">
|
|
37
|
+
<br>
|
|
38
|
+
<hr>
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### 🚫 Bad
|
|
42
|
+
|
|
43
|
+
```html
|
|
44
|
+
<span />
|
|
45
|
+
|
|
46
|
+
<div />
|
|
47
|
+
|
|
48
|
+
<section />
|
|
49
|
+
|
|
50
|
+
<custom-element />
|
|
51
|
+
|
|
52
|
+
<img src="/logo.png" alt="Logo" />
|
|
53
|
+
|
|
54
|
+
<input type="text" />
|
|
55
|
+
|
|
56
|
+
<br />
|
|
57
|
+
|
|
58
|
+
<hr />
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## References
|
|
62
|
+
|
|
63
|
+
- [HTML Living Standard: Void Elements](https://html.spec.whatwg.org/multipage/syntax.html#void-elements)
|
|
64
|
+
- [MDN: Void element](https://developer.mozilla.org/en-US/docs/Glossary/Void_element)
|
|
65
|
+
- [erb_lint: SelfClosingTag](https://github.com/Shopify/erb_lint#selfclosingtag)
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# Linter Rule: Avoid using the `title` attribute
|
|
2
|
+
|
|
3
|
+
**Rule:** `html-no-title-attribute`
|
|
4
|
+
|
|
5
|
+
## Description
|
|
6
|
+
|
|
7
|
+
Discourage the use of the `title` attribute on most HTML elements, as it provides poor accessibility and user experience. The `title` attribute is only accessible via mouse hover and is not reliably exposed to screen readers or keyboard users.
|
|
8
|
+
|
|
9
|
+
## Rationale
|
|
10
|
+
|
|
11
|
+
The `title` attribute has several accessibility problems:
|
|
12
|
+
- It's only visible on mouse hover, making it inaccessible to keyboard and touch users
|
|
13
|
+
- Screen readers don't consistently announce title attributes
|
|
14
|
+
- Mobile devices don't show title tooltips
|
|
15
|
+
- The visual presentation is inconsistent across browsers and operating systems
|
|
16
|
+
|
|
17
|
+
Instead of relying on `title`, use visible text, `aria-label`, `aria-describedby`, or other accessible alternatives.
|
|
18
|
+
|
|
19
|
+
::: warning Exceptions
|
|
20
|
+
This rule allows `title` on `<iframe>` and `<link>` elements where it serves specific accessibility purposes.
|
|
21
|
+
:::
|
|
22
|
+
|
|
23
|
+
## Examples
|
|
24
|
+
|
|
25
|
+
### ✅ Good
|
|
26
|
+
|
|
27
|
+
```erb
|
|
28
|
+
<!-- Use visible text instead of title -->
|
|
29
|
+
<button>Save document</button>
|
|
30
|
+
<span class="help-text">Click to save your changes</span>
|
|
31
|
+
|
|
32
|
+
<!-- Use aria-label for accessible names -->
|
|
33
|
+
<button aria-label="Close dialog">×</button>
|
|
34
|
+
|
|
35
|
+
<!-- Use aria-describedby for additional context -->
|
|
36
|
+
<input type="password" aria-describedby="pwd-help">
|
|
37
|
+
<div id="pwd-help">Password must be at least 8 characters</div>
|
|
38
|
+
|
|
39
|
+
<!-- Exceptions: title allowed on iframe and links -->
|
|
40
|
+
<iframe src="https://example.com" title="Example website content"></iframe>
|
|
41
|
+
<link href="default.css" rel="stylesheet" title="Default Style">
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### 🚫 Bad
|
|
45
|
+
|
|
46
|
+
```erb
|
|
47
|
+
<!-- Don't use title for essential information -->
|
|
48
|
+
<button title="Save your changes">Save</button>
|
|
49
|
+
|
|
50
|
+
<div title="This is important information">Content</div>
|
|
51
|
+
|
|
52
|
+
<span title="Required field">*</span>
|
|
53
|
+
|
|
54
|
+
<!-- Don't use title on form elements -->
|
|
55
|
+
<input type="text" title="Enter your name">
|
|
56
|
+
|
|
57
|
+
<select title="Choose your country">
|
|
58
|
+
<option>US</option>
|
|
59
|
+
<option>CA</option>
|
|
60
|
+
</select>
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## References
|
|
64
|
+
|
|
65
|
+
- [HTML: `title` attribute](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/title)
|
|
66
|
+
- [WebAIM: Accessible Forms](https://webaim.org/techniques/forms/)
|
|
67
|
+
- [ARIA: `aria-label` attribute](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Reference/Attributes/aria-label)
|
|
68
|
+
- [ARIA: `aria-describedby` attribute](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Reference/Attributes/aria-describedby)
|
|
69
|
+
- [erblint-github: GitHub::Accessibility::NoTitleAttribute](https://github.com/github/erblint-github/blob/main/docs/rules/accessibility/no-title-attribute.md)
|
|
@@ -12,15 +12,28 @@ HTML is case-insensitive for tag names, but lowercase is the widely accepted con
|
|
|
12
12
|
|
|
13
13
|
Writing tags in uppercase or mixed case can lead to inconsistent code and unnecessary diffs during reviews and merges.
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
### Notes
|
|
16
|
+
|
|
17
|
+
::: tip XML Documents
|
|
18
|
+
This rule is automatically disabled for XML documents and XML+ERB templates. XML allows uppercase tag names and follows different naming conventions than HTML.
|
|
19
|
+
|
|
20
|
+
The rule will be disabled when:
|
|
21
|
+
- The document contains an XML declaration (`<?xml version="1.0" ?>`)
|
|
22
|
+
- The file extension is `.xml` or `.xml.erb`
|
|
23
|
+
:::
|
|
16
24
|
|
|
25
|
+
::: tip SVG Elements
|
|
26
|
+
This rule does not apply to child elements within `<svg>` tags, as SVG element names are case-sensitive and may require specific capitalization (e.g., `linearGradient`, `clipPath`). However, the rule still applies to the `<svg>` element itself.
|
|
27
|
+
:::
|
|
28
|
+
|
|
29
|
+
## Examples
|
|
17
30
|
|
|
18
31
|
### ✅ Good
|
|
19
32
|
|
|
20
33
|
```erb
|
|
21
34
|
<div class="container"></div>
|
|
22
35
|
|
|
23
|
-
<input type="text" name="username"
|
|
36
|
+
<input type="text" name="username">
|
|
24
37
|
|
|
25
38
|
<span>Label</span>
|
|
26
39
|
|
|
@@ -32,7 +45,7 @@ Writing tags in uppercase or mixed case can lead to inconsistent code and unnece
|
|
|
32
45
|
```erb
|
|
33
46
|
<DIV class="container"></DIV>
|
|
34
47
|
|
|
35
|
-
<Input type="text" name="username"
|
|
48
|
+
<Input type="text" name="username">
|
|
36
49
|
|
|
37
50
|
<Span>Label</Span>
|
|
38
51
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@herb-tools/linter",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.1",
|
|
4
4
|
"description": "HTML+ERB linter for validating HTML structure and enforcing best practices",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"homepage": "https://herb-tools.dev",
|
|
@@ -33,9 +33,10 @@
|
|
|
33
33
|
}
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"@herb-tools/core": "0.
|
|
37
|
-
"@herb-tools/highlighter": "0.
|
|
38
|
-
"@herb-tools/node-wasm": "0.
|
|
36
|
+
"@herb-tools/core": "0.6.1",
|
|
37
|
+
"@herb-tools/highlighter": "0.6.1",
|
|
38
|
+
"@herb-tools/node-wasm": "0.6.1",
|
|
39
|
+
"@herb-tools/printer": "0.6.1",
|
|
39
40
|
"glob": "^11.0.3"
|
|
40
41
|
},
|
|
41
42
|
"files": [
|