@herb-tools/linter 0.8.10 → 0.9.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/README.md +5 -5
- package/dist/{src/cli → cli}/argument-parser.js +15 -2
- package/dist/cli/argument-parser.js.map +1 -0
- package/dist/{src/cli → cli}/file-processor.js +155 -9
- package/dist/cli/file-processor.js.map +1 -0
- package/dist/cli/file-url.js +6 -0
- package/dist/cli/file-url.js.map +1 -0
- package/dist/cli/formatters/base-formatter.js.map +1 -0
- package/dist/{src/cli → cli}/formatters/detailed-formatter.js +16 -19
- package/dist/cli/formatters/detailed-formatter.js.map +1 -0
- package/dist/cli/formatters/github-actions-formatter.js.map +1 -0
- package/dist/cli/formatters/index.js.map +1 -0
- package/dist/cli/formatters/json-formatter.js.map +1 -0
- package/dist/cli/formatters/simple-formatter.js +54 -0
- package/dist/cli/formatters/simple-formatter.js.map +1 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/lint-worker.js +143 -0
- package/dist/cli/lint-worker.js.map +1 -0
- package/dist/cli/output-manager.js.map +1 -0
- package/dist/{src/cli → cli}/summary-reporter.js +13 -16
- package/dist/cli/summary-reporter.js.map +1 -0
- package/dist/{src/cli.js → cli.js} +5 -3
- package/dist/cli.js.map +1 -0
- package/dist/{src/custom-rule-loader.js → custom-rule-loader.js} +20 -4
- package/dist/custom-rule-loader.js.map +1 -0
- package/dist/herb-disable-comment-utils.js.map +1 -0
- package/dist/herb-lint.js +61834 -17340
- package/dist/herb-lint.js.map +1 -1
- package/dist/index.cjs +3109 -956
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +2969 -897
- package/dist/index.js.map +1 -1
- package/dist/lint-worker.js +72889 -0
- package/dist/lint-worker.js.map +1 -0
- package/dist/linter-ignore.js.map +1 -0
- package/dist/{src/linter.js → linter.js} +89 -74
- package/dist/linter.js.map +1 -0
- package/dist/loader.cjs +32163 -7842
- package/dist/loader.cjs.map +1 -1
- package/dist/loader.js +32121 -7828
- package/dist/loader.js.map +1 -1
- package/dist/parse-cache.js +30 -0
- package/dist/parse-cache.js.map +1 -0
- package/dist/rules/actionview-no-silent-helper.js +45 -0
- package/dist/rules/actionview-no-silent-helper.js.map +1 -0
- package/dist/rules/actionview-no-silent-render.js +31 -0
- package/dist/rules/actionview-no-silent-render.js.map +1 -0
- package/dist/{src/rules → rules}/erb-comment-syntax.js +2 -2
- package/dist/rules/erb-comment-syntax.js.map +1 -0
- package/dist/{src/rules → rules}/erb-no-case-node-children.js +5 -3
- package/dist/rules/erb-no-case-node-children.js.map +1 -0
- package/dist/rules/erb-no-conditional-html-element.js +38 -0
- package/dist/rules/erb-no-conditional-html-element.js.map +1 -0
- package/dist/rules/erb-no-conditional-open-tag.js +24 -0
- package/dist/rules/erb-no-conditional-open-tag.js.map +1 -0
- package/dist/rules/erb-no-duplicate-branch-elements.js +329 -0
- package/dist/rules/erb-no-duplicate-branch-elements.js.map +1 -0
- package/dist/rules/erb-no-empty-control-flow.js +190 -0
- package/dist/rules/erb-no-empty-control-flow.js.map +1 -0
- package/dist/{src/rules → rules}/erb-no-empty-tags.js +2 -2
- package/dist/rules/erb-no-empty-tags.js.map +1 -0
- package/dist/{src/rules → rules}/erb-no-extra-newline.js +4 -21
- package/dist/rules/erb-no-extra-newline.js.map +1 -0
- package/dist/{src/rules → rules}/erb-no-extra-whitespace-inside-tags.js +39 -13
- package/dist/rules/erb-no-extra-whitespace-inside-tags.js.map +1 -0
- package/dist/rules/erb-no-inline-case-conditions.js +40 -0
- package/dist/rules/erb-no-inline-case-conditions.js.map +1 -0
- package/dist/rules/erb-no-instance-variables-in-partials.js +67 -0
- package/dist/rules/erb-no-instance-variables-in-partials.js.map +1 -0
- package/dist/rules/erb-no-interpolated-class-names.js +47 -0
- package/dist/rules/erb-no-interpolated-class-names.js.map +1 -0
- package/dist/rules/erb-no-javascript-tag-helper.js +34 -0
- package/dist/rules/erb-no-javascript-tag-helper.js.map +1 -0
- package/dist/{src/rules → rules}/erb-no-output-control-flow.js +9 -12
- package/dist/rules/erb-no-output-control-flow.js.map +1 -0
- package/dist/rules/erb-no-output-in-attribute-name.js +30 -0
- package/dist/rules/erb-no-output-in-attribute-name.js.map +1 -0
- package/dist/rules/erb-no-output-in-attribute-position.js +30 -0
- package/dist/rules/erb-no-output-in-attribute-position.js.map +1 -0
- package/dist/rules/erb-no-raw-output-in-attribute-value.js +35 -0
- package/dist/rules/erb-no-raw-output-in-attribute-value.js.map +1 -0
- package/dist/rules/erb-no-silent-statement.js +44 -0
- package/dist/rules/erb-no-silent-statement.js.map +1 -0
- package/dist/{src/rules → rules}/erb-no-silent-tag-in-attribute-name.js +2 -2
- package/dist/rules/erb-no-silent-tag-in-attribute-name.js.map +1 -0
- package/dist/rules/erb-no-statement-in-script.js +58 -0
- package/dist/rules/erb-no-statement-in-script.js.map +1 -0
- package/dist/rules/erb-no-then-in-control-flow.js +45 -0
- package/dist/rules/erb-no-then-in-control-flow.js.map +1 -0
- package/dist/rules/erb-no-trailing-whitespace.js +138 -0
- package/dist/rules/erb-no-trailing-whitespace.js.map +1 -0
- package/dist/rules/erb-no-unsafe-js-attribute.js +36 -0
- package/dist/rules/erb-no-unsafe-js-attribute.js.map +1 -0
- package/dist/rules/erb-no-unsafe-raw.js +63 -0
- package/dist/rules/erb-no-unsafe-raw.js.map +1 -0
- package/dist/rules/erb-no-unsafe-script-interpolation.js +88 -0
- package/dist/rules/erb-no-unsafe-script-interpolation.js.map +1 -0
- package/dist/{src/rules → rules}/erb-prefer-image-tag-helper.js +5 -4
- package/dist/rules/erb-prefer-image-tag-helper.js.map +1 -0
- package/dist/{src/rules → rules}/erb-require-trailing-newline.js +2 -2
- package/dist/rules/erb-require-trailing-newline.js.map +1 -0
- package/dist/{src/rules → rules}/erb-require-whitespace-inside-tags.js +39 -15
- package/dist/rules/erb-require-whitespace-inside-tags.js.map +1 -0
- package/dist/{src/rules → rules}/erb-right-trim.js +2 -2
- package/dist/rules/erb-right-trim.js.map +1 -0
- package/dist/{src/rules → rules}/erb-strict-locals-comment-syntax.js +4 -4
- package/dist/rules/erb-strict-locals-comment-syntax.js.map +1 -0
- package/dist/{src/rules → rules}/erb-strict-locals-required.js +2 -2
- package/dist/rules/erb-strict-locals-required.js.map +1 -0
- package/dist/rules/file-utils.js.map +1 -0
- package/dist/rules/herb-disable-comment-base.js.map +1 -0
- package/dist/{src/rules → rules}/herb-disable-comment-malformed.js +2 -2
- package/dist/rules/herb-disable-comment-malformed.js.map +1 -0
- package/dist/{src/rules → rules}/herb-disable-comment-missing-rules.js +2 -2
- package/dist/rules/herb-disable-comment-missing-rules.js.map +1 -0
- package/dist/{src/rules → rules}/herb-disable-comment-no-duplicate-rules.js +2 -2
- package/dist/rules/herb-disable-comment-no-duplicate-rules.js.map +1 -0
- package/dist/{src/rules → rules}/herb-disable-comment-no-redundant-all.js +2 -2
- package/dist/rules/herb-disable-comment-no-redundant-all.js.map +1 -0
- package/dist/{src/rules → rules}/herb-disable-comment-unnecessary.js +2 -2
- package/dist/rules/herb-disable-comment-unnecessary.js.map +1 -0
- package/dist/{src/rules → rules}/herb-disable-comment-valid-rule-name.js +2 -2
- package/dist/rules/herb-disable-comment-valid-rule-name.js.map +1 -0
- package/dist/rules/html-allowed-script-type.js +57 -0
- package/dist/rules/html-allowed-script-type.js.map +1 -0
- package/dist/rules/html-anchor-require-href.js +68 -0
- package/dist/rules/html-anchor-require-href.js.map +1 -0
- package/dist/{src/rules → rules}/html-aria-attribute-must-be-valid.js +3 -3
- package/dist/rules/html-aria-attribute-must-be-valid.js.map +1 -0
- package/dist/{src/rules → rules}/html-aria-label-is-well-formatted.js +3 -3
- package/dist/rules/html-aria-label-is-well-formatted.js.map +1 -0
- package/dist/{src/rules → rules}/html-aria-level-must-be-valid.js +3 -3
- package/dist/rules/html-aria-level-must-be-valid.js.map +1 -0
- package/dist/{src/rules → rules}/html-aria-role-heading-requires-level.js +5 -4
- package/dist/rules/html-aria-role-heading-requires-level.js.map +1 -0
- package/dist/{src/rules → rules}/html-aria-role-must-be-valid.js +3 -3
- package/dist/rules/html-aria-role-must-be-valid.js.map +1 -0
- package/dist/{src/rules → rules}/html-attribute-double-quotes.js +4 -4
- package/dist/rules/html-attribute-double-quotes.js.map +1 -0
- package/dist/{src/rules → rules}/html-attribute-equals-spacing.js +2 -2
- package/dist/rules/html-attribute-equals-spacing.js.map +1 -0
- package/dist/{src/rules → rules}/html-attribute-values-require-quotes.js +2 -2
- package/dist/rules/html-attribute-values-require-quotes.js.map +1 -0
- package/dist/{src/rules → rules}/html-avoid-both-disabled-and-aria-disabled.js +9 -9
- package/dist/rules/html-avoid-both-disabled-and-aria-disabled.js.map +1 -0
- package/dist/{src/rules → rules}/html-body-only-elements.js +5 -4
- package/dist/rules/html-body-only-elements.js.map +1 -0
- package/dist/{src/rules → rules}/html-boolean-attributes-no-value.js +4 -3
- package/dist/rules/html-boolean-attributes-no-value.js.map +1 -0
- package/dist/rules/html-details-has-summary.js +52 -0
- package/dist/rules/html-details-has-summary.js.map +1 -0
- package/dist/{src/rules → rules}/html-head-only-elements.js +6 -5
- package/dist/rules/html-head-only-elements.js.map +1 -0
- package/dist/{src/rules → rules}/html-iframe-has-title.js +8 -11
- package/dist/rules/html-iframe-has-title.js.map +1 -0
- package/dist/{src/rules → rules}/html-img-require-alt.js +11 -5
- package/dist/rules/html-img-require-alt.js.map +1 -0
- package/dist/{src/rules → rules}/html-input-require-autocomplete.js +7 -10
- package/dist/rules/html-input-require-autocomplete.js.map +1 -0
- package/dist/{src/rules → rules}/html-navigation-has-label.js +6 -5
- package/dist/rules/html-navigation-has-label.js.map +1 -0
- package/dist/rules/html-no-abstract-roles.js +29 -0
- package/dist/rules/html-no-abstract-roles.js.map +1 -0
- package/dist/rules/html-no-aria-hidden-on-body.js +42 -0
- package/dist/rules/html-no-aria-hidden-on-body.js.map +1 -0
- package/dist/{src/rules → rules}/html-no-aria-hidden-on-focusable.js +6 -5
- package/dist/rules/html-no-aria-hidden-on-focusable.js.map +1 -0
- package/dist/{src/rules → rules}/html-no-block-inside-inline.js +6 -9
- package/dist/rules/html-no-block-inside-inline.js.map +1 -0
- package/dist/{src/rules → rules}/html-no-duplicate-attributes.js +4 -3
- package/dist/rules/html-no-duplicate-attributes.js.map +1 -0
- package/dist/{src/rules → rules}/html-no-duplicate-ids.js +14 -11
- package/dist/rules/html-no-duplicate-ids.js.map +1 -0
- package/dist/{src/rules → rules}/html-no-duplicate-meta-names.js +22 -20
- package/dist/rules/html-no-duplicate-meta-names.js.map +1 -0
- package/dist/{src/rules → rules}/html-no-empty-attributes.js +2 -2
- package/dist/rules/html-no-empty-attributes.js.map +1 -0
- package/dist/rules/html-no-empty-headings.js +98 -0
- package/dist/rules/html-no-empty-headings.js.map +1 -0
- package/dist/{src/rules → rules}/html-no-nested-links.js +23 -15
- package/dist/rules/html-no-nested-links.js.map +1 -0
- package/dist/{src/rules → rules}/html-no-positive-tab-index.js +3 -3
- package/dist/rules/html-no-positive-tab-index.js.map +1 -0
- package/dist/{src/rules → rules}/html-no-self-closing.js +4 -4
- package/dist/rules/html-no-self-closing.js.map +1 -0
- package/dist/{src/rules → rules}/html-no-space-in-tag.js +4 -6
- package/dist/rules/html-no-space-in-tag.js.map +1 -0
- package/dist/{src/rules → rules}/html-no-title-attribute.js +6 -5
- package/dist/rules/html-no-title-attribute.js.map +1 -0
- package/dist/{src/rules → rules}/html-no-underscores-in-attribute-names.js +2 -2
- package/dist/rules/html-no-underscores-in-attribute-names.js.map +1 -0
- package/dist/rules/html-require-closing-tags.js +29 -0
- package/dist/rules/html-require-closing-tags.js.map +1 -0
- package/dist/{src/rules → rules}/html-tag-name-lowercase.js +13 -9
- package/dist/rules/html-tag-name-lowercase.js.map +1 -0
- package/dist/{src/rules → rules}/index.js +27 -4
- package/dist/rules/index.js.map +1 -0
- package/dist/{src/rules → rules}/parser-no-errors.js +3 -3
- package/dist/rules/parser-no-errors.js.map +1 -0
- package/dist/{src/rules → rules}/rule-utils.js +144 -219
- package/dist/rules/rule-utils.js.map +1 -0
- package/dist/rules/string-utils.js.map +1 -0
- package/dist/{src/rules → rules}/svg-tag-name-capitalization.js +7 -6
- package/dist/rules/svg-tag-name-capitalization.js.map +1 -0
- package/dist/rules/turbo-permanent-require-id.js +34 -0
- package/dist/rules/turbo-permanent-require-id.js.map +1 -0
- package/dist/{src/rules.js → rules.js} +62 -10
- package/dist/rules.js.map +1 -0
- package/dist/types/cli/argument-parser.d.ts +1 -0
- package/dist/types/cli/file-processor.d.ts +13 -0
- package/dist/types/cli/file-url.d.ts +1 -0
- package/dist/types/cli/index.d.ts +1 -0
- package/dist/types/cli/lint-worker.d.ts +34 -0
- package/dist/types/custom-rule-loader.d.ts +4 -0
- package/dist/types/index.d.ts +2 -0
- package/dist/types/linter.d.ts +13 -6
- package/dist/types/parse-cache.d.ts +9 -0
- package/dist/types/{src/rules/html-aria-level-must-be-valid.d.ts → rules/actionview-no-silent-helper.d.ts} +4 -3
- package/dist/types/rules/actionview-no-silent-render.d.ts +9 -0
- package/dist/types/rules/erb-comment-syntax.d.ts +1 -1
- package/dist/types/rules/erb-no-case-node-children.d.ts +1 -1
- package/dist/types/{src/rules/herb-disable-comment-malformed.d.ts → rules/erb-no-conditional-html-element.d.ts} +3 -3
- package/dist/types/{src/rules/erb-prefer-image-tag-helper.d.ts → rules/erb-no-conditional-open-tag.d.ts} +3 -3
- package/dist/types/rules/erb-no-duplicate-branch-elements.d.ts +18 -0
- package/dist/types/{src/rules/html-anchor-require-href.d.ts → rules/erb-no-empty-control-flow.d.ts} +2 -2
- package/dist/types/rules/erb-no-empty-tags.d.ts +1 -1
- package/dist/types/rules/erb-no-extra-newline.d.ts +1 -1
- package/dist/types/rules/erb-no-extra-whitespace-inside-tags.d.ts +1 -1
- package/dist/types/{src/rules/html-no-duplicate-attributes.d.ts → rules/erb-no-inline-case-conditions.d.ts} +4 -3
- package/dist/types/rules/erb-no-instance-variables-in-partials.d.ts +10 -0
- package/dist/types/{src/rules/html-no-aria-hidden-on-focusable.d.ts → rules/erb-no-interpolated-class-names.d.ts} +2 -2
- package/dist/types/{src/rules/html-aria-attribute-must-be-valid.d.ts → rules/erb-no-javascript-tag-helper.d.ts} +2 -2
- package/dist/types/rules/erb-no-output-control-flow.d.ts +1 -1
- package/dist/types/{src/rules/erb-no-silent-tag-in-attribute-name.d.ts → rules/erb-no-output-in-attribute-name.d.ts} +2 -2
- package/dist/types/{src/rules/herb-disable-comment-missing-rules.d.ts → rules/erb-no-output-in-attribute-position.d.ts} +2 -2
- package/dist/types/{src/rules/erb-no-empty-tags.d.ts → rules/erb-no-raw-output-in-attribute-value.d.ts} +2 -2
- package/dist/types/{src/rules/html-no-title-attribute.d.ts → rules/erb-no-silent-statement.d.ts} +4 -3
- package/dist/types/rules/erb-no-silent-tag-in-attribute-name.d.ts +1 -1
- package/dist/types/{src/rules/html-navigation-has-label.d.ts → rules/erb-no-statement-in-script.d.ts} +2 -2
- package/dist/types/rules/erb-no-then-in-control-flow.d.ts +9 -0
- package/dist/types/rules/erb-no-trailing-whitespace.d.ts +19 -0
- package/dist/types/{src/rules/html-no-positive-tab-index.d.ts → rules/erb-no-unsafe-js-attribute.d.ts} +2 -2
- package/dist/types/{src/rules/erb-no-case-node-children.d.ts → rules/erb-no-unsafe-raw.d.ts} +2 -2
- package/dist/types/rules/erb-no-unsafe-script-interpolation.d.ts +9 -0
- package/dist/types/rules/erb-prefer-image-tag-helper.d.ts +1 -1
- package/dist/types/rules/erb-require-trailing-newline.d.ts +1 -1
- package/dist/types/rules/erb-require-whitespace-inside-tags.d.ts +1 -1
- package/dist/types/rules/erb-right-trim.d.ts +1 -1
- package/dist/types/rules/erb-strict-locals-comment-syntax.d.ts +1 -1
- package/dist/types/rules/erb-strict-locals-required.d.ts +1 -1
- package/dist/types/rules/herb-disable-comment-malformed.d.ts +1 -1
- package/dist/types/rules/herb-disable-comment-missing-rules.d.ts +1 -1
- package/dist/types/rules/herb-disable-comment-no-duplicate-rules.d.ts +1 -1
- package/dist/types/rules/herb-disable-comment-no-redundant-all.d.ts +1 -1
- package/dist/types/rules/herb-disable-comment-unnecessary.d.ts +1 -1
- package/dist/types/rules/herb-disable-comment-valid-rule-name.d.ts +1 -1
- package/dist/types/{src/rules/html-no-empty-attributes.d.ts → rules/html-allowed-script-type.d.ts} +2 -2
- package/dist/types/rules/html-anchor-require-href.d.ts +3 -2
- package/dist/types/rules/html-aria-attribute-must-be-valid.d.ts +1 -1
- package/dist/types/rules/html-aria-label-is-well-formatted.d.ts +1 -1
- package/dist/types/rules/html-aria-level-must-be-valid.d.ts +1 -1
- package/dist/types/rules/html-aria-role-heading-requires-level.d.ts +1 -1
- package/dist/types/rules/html-aria-role-must-be-valid.d.ts +1 -1
- package/dist/types/rules/html-attribute-double-quotes.d.ts +1 -1
- package/dist/types/rules/html-attribute-equals-spacing.d.ts +1 -1
- package/dist/types/rules/html-attribute-values-require-quotes.d.ts +1 -1
- package/dist/types/rules/html-avoid-both-disabled-and-aria-disabled.d.ts +1 -1
- package/dist/types/rules/html-body-only-elements.d.ts +1 -1
- package/dist/types/rules/html-boolean-attributes-no-value.d.ts +1 -1
- package/dist/types/rules/html-details-has-summary.d.ts +9 -0
- package/dist/types/rules/html-head-only-elements.d.ts +1 -1
- package/dist/types/rules/html-iframe-has-title.d.ts +1 -1
- package/dist/types/rules/html-img-require-alt.d.ts +1 -1
- package/dist/types/rules/html-input-require-autocomplete.d.ts +1 -1
- package/dist/types/rules/html-navigation-has-label.d.ts +1 -1
- package/dist/types/{src/rules/html-no-empty-headings.d.ts → rules/html-no-abstract-roles.d.ts} +2 -2
- package/dist/types/{src/rules/erb-no-output-control-flow.d.ts → rules/html-no-aria-hidden-on-body.d.ts} +3 -3
- package/dist/types/rules/html-no-aria-hidden-on-focusable.d.ts +1 -1
- package/dist/types/rules/html-no-block-inside-inline.d.ts +1 -1
- package/dist/types/rules/html-no-duplicate-attributes.d.ts +1 -1
- package/dist/types/rules/html-no-duplicate-ids.d.ts +1 -1
- package/dist/types/rules/html-no-duplicate-meta-names.d.ts +1 -1
- package/dist/types/rules/html-no-empty-attributes.d.ts +1 -1
- package/dist/types/rules/html-no-empty-headings.d.ts +1 -1
- package/dist/types/rules/html-no-nested-links.d.ts +1 -1
- package/dist/types/rules/html-no-positive-tab-index.d.ts +1 -1
- package/dist/types/rules/html-no-self-closing.d.ts +1 -1
- package/dist/types/rules/html-no-space-in-tag.d.ts +1 -1
- package/dist/types/rules/html-no-title-attribute.d.ts +1 -1
- package/dist/types/rules/html-no-underscores-in-attribute-names.d.ts +1 -1
- package/dist/types/{src/rules/html-body-only-elements.d.ts → rules/html-require-closing-tags.d.ts} +4 -3
- package/dist/types/rules/html-tag-name-lowercase.d.ts +1 -1
- package/dist/types/rules/index.d.ts +27 -4
- package/dist/types/rules/parser-no-errors.d.ts +1 -1
- package/dist/types/rules/rule-utils.d.ts +36 -88
- package/dist/types/rules/svg-tag-name-capitalization.d.ts +1 -1
- package/dist/types/{src/rules/html-aria-role-must-be-valid.d.ts → rules/turbo-permanent-require-id.d.ts} +2 -2
- package/dist/types/types.d.ts +26 -7
- package/dist/types/urls.d.ts +1 -0
- package/dist/{src/types.js → types.js} +56 -0
- package/dist/types.js.map +1 -0
- package/dist/urls.js +5 -0
- package/dist/urls.js.map +1 -0
- package/docs/rules/README.md +26 -2
- package/docs/rules/actionview-no-silent-helper.md +57 -0
- package/docs/rules/actionview-no-silent-render.md +47 -0
- package/docs/rules/erb-no-conditional-html-element.md +90 -0
- package/docs/rules/erb-no-conditional-open-tag.md +130 -0
- package/docs/rules/erb-no-duplicate-branch-elements.md +98 -0
- package/docs/rules/erb-no-empty-control-flow.md +83 -0
- package/docs/rules/erb-no-inline-case-conditions.md +85 -0
- package/docs/rules/erb-no-instance-variables-in-partials.md +43 -0
- package/docs/rules/erb-no-interpolated-class-names.md +57 -0
- package/docs/rules/erb-no-javascript-tag-helper.md +33 -0
- package/docs/rules/erb-no-output-in-attribute-name.md +38 -0
- package/docs/rules/erb-no-output-in-attribute-position.md +60 -0
- package/docs/rules/erb-no-raw-output-in-attribute-value.md +37 -0
- package/docs/rules/erb-no-silent-statement.md +53 -0
- package/docs/rules/erb-no-statement-in-script.md +68 -0
- package/docs/rules/erb-no-then-in-control-flow.md +86 -0
- package/docs/rules/erb-no-trailing-whitespace.md +69 -0
- package/docs/rules/erb-no-unsafe-js-attribute.md +41 -0
- package/docs/rules/erb-no-unsafe-raw.md +47 -0
- package/docs/rules/erb-no-unsafe-script-interpolation.md +140 -0
- package/docs/rules/html-allowed-script-type.md +59 -0
- package/docs/rules/html-anchor-require-href.md +19 -6
- package/docs/rules/html-details-has-summary.md +46 -0
- package/docs/rules/html-img-require-alt.md +5 -3
- package/docs/rules/html-no-abstract-roles.md +74 -0
- package/docs/rules/html-no-aria-hidden-on-body.md +44 -0
- package/docs/rules/html-require-closing-tags.md +142 -0
- package/docs/rules/parser-no-errors.md +4 -17
- package/docs/rules/turbo-permanent-require-id.md +41 -0
- package/package.json +11 -10
- package/src/cli/argument-parser.ts +20 -2
- package/src/cli/file-processor.ts +189 -10
- package/src/cli/file-url.ts +6 -0
- package/src/cli/formatters/detailed-formatter.ts +19 -21
- package/src/cli/formatters/simple-formatter.ts +23 -13
- package/src/cli/index.ts +2 -0
- package/src/cli/lint-worker.ts +208 -0
- package/src/cli/summary-reporter.ts +14 -15
- package/src/cli.ts +5 -3
- package/src/custom-rule-loader.ts +20 -5
- package/src/herb-disable-comment-utils.ts +0 -3
- package/src/index.ts +22 -0
- package/src/linter.ts +98 -79
- package/src/parse-cache.ts +39 -0
- package/src/rules/actionview-no-silent-helper.ts +58 -0
- package/src/rules/actionview-no-silent-render.ts +44 -0
- package/src/rules/erb-comment-syntax.ts +2 -2
- package/src/rules/erb-no-case-node-children.ts +5 -3
- package/src/rules/erb-no-conditional-html-element.ts +53 -0
- package/src/rules/erb-no-conditional-open-tag.ts +37 -0
- package/src/rules/erb-no-duplicate-branch-elements.ts +436 -0
- package/src/rules/erb-no-empty-control-flow.ts +255 -0
- package/src/rules/erb-no-empty-tags.ts +2 -2
- package/src/rules/erb-no-extra-newline.ts +5 -25
- package/src/rules/erb-no-extra-whitespace-inside-tags.ts +45 -15
- package/src/rules/erb-no-inline-case-conditions.ts +54 -0
- package/src/rules/erb-no-instance-variables-in-partials.ts +101 -0
- package/src/rules/erb-no-interpolated-class-names.ts +65 -0
- package/src/rules/erb-no-javascript-tag-helper.ts +47 -0
- package/src/rules/erb-no-output-control-flow.ts +10 -10
- package/src/rules/erb-no-output-in-attribute-name.ts +39 -0
- package/src/rules/erb-no-output-in-attribute-position.ts +39 -0
- package/src/rules/erb-no-raw-output-in-attribute-value.ts +47 -0
- package/src/rules/erb-no-silent-statement.ts +58 -0
- package/src/rules/erb-no-silent-tag-in-attribute-name.ts +2 -2
- package/src/rules/erb-no-statement-in-script.ts +82 -0
- package/src/rules/erb-no-then-in-control-flow.ts +62 -0
- package/src/rules/erb-no-trailing-whitespace.ts +187 -0
- package/src/rules/erb-no-unsafe-js-attribute.ts +47 -0
- package/src/rules/erb-no-unsafe-raw.ts +83 -0
- package/src/rules/erb-no-unsafe-script-interpolation.ts +122 -0
- package/src/rules/erb-prefer-image-tag-helper.ts +5 -4
- package/src/rules/erb-require-trailing-newline.ts +2 -2
- package/src/rules/erb-require-whitespace-inside-tags.ts +42 -18
- package/src/rules/erb-right-trim.ts +2 -2
- package/src/rules/erb-strict-locals-comment-syntax.ts +4 -4
- package/src/rules/erb-strict-locals-required.ts +2 -2
- package/src/rules/herb-disable-comment-malformed.ts +2 -2
- package/src/rules/herb-disable-comment-missing-rules.ts +2 -2
- package/src/rules/herb-disable-comment-no-duplicate-rules.ts +2 -2
- package/src/rules/herb-disable-comment-no-redundant-all.ts +2 -2
- package/src/rules/herb-disable-comment-unnecessary.ts +2 -2
- package/src/rules/herb-disable-comment-valid-rule-name.ts +2 -2
- package/src/rules/html-allowed-script-type.ts +84 -0
- package/src/rules/html-anchor-require-href.ts +73 -11
- package/src/rules/html-aria-attribute-must-be-valid.ts +3 -3
- package/src/rules/html-aria-label-is-well-formatted.ts +3 -3
- package/src/rules/html-aria-level-must-be-valid.ts +3 -3
- package/src/rules/html-aria-role-heading-requires-level.ts +5 -4
- package/src/rules/html-aria-role-must-be-valid.ts +3 -3
- package/src/rules/html-attribute-double-quotes.ts +4 -4
- package/src/rules/html-attribute-equals-spacing.ts +2 -2
- package/src/rules/html-attribute-values-require-quotes.ts +2 -2
- package/src/rules/html-avoid-both-disabled-and-aria-disabled.ts +10 -11
- package/src/rules/html-body-only-elements.ts +5 -4
- package/src/rules/html-boolean-attributes-no-value.ts +4 -3
- package/src/rules/html-details-has-summary.ts +69 -0
- package/src/rules/html-head-only-elements.ts +6 -5
- package/src/rules/html-iframe-has-title.ts +8 -11
- package/src/rules/html-img-require-alt.ts +16 -5
- package/src/rules/html-input-require-autocomplete.ts +7 -10
- package/src/rules/html-navigation-has-label.ts +6 -5
- package/src/rules/html-no-abstract-roles.ts +40 -0
- package/src/rules/html-no-aria-hidden-on-body.ts +58 -0
- package/src/rules/html-no-aria-hidden-on-focusable.ts +6 -5
- package/src/rules/html-no-block-inside-inline.ts +7 -13
- package/src/rules/html-no-duplicate-attributes.ts +4 -3
- package/src/rules/html-no-duplicate-ids.ts +16 -13
- package/src/rules/html-no-duplicate-meta-names.ts +20 -19
- package/src/rules/html-no-empty-attributes.ts +2 -2
- package/src/rules/html-no-empty-headings.ts +44 -58
- package/src/rules/html-no-nested-links.ts +25 -16
- package/src/rules/html-no-positive-tab-index.ts +3 -3
- package/src/rules/html-no-self-closing.ts +5 -5
- package/src/rules/html-no-space-in-tag.ts +5 -8
- package/src/rules/html-no-title-attribute.ts +6 -5
- package/src/rules/html-no-underscores-in-attribute-names.ts +2 -2
- package/src/rules/html-require-closing-tags.ts +41 -0
- package/src/rules/html-tag-name-lowercase.ts +14 -9
- package/src/rules/index.ts +28 -4
- package/src/rules/parser-no-errors.ts +3 -3
- package/src/rules/rule-utils.ts +166 -279
- package/src/rules/svg-tag-name-capitalization.ts +10 -10
- package/src/rules/turbo-permanent-require-id.ts +49 -0
- package/src/rules.ts +66 -10
- package/src/types.ts +80 -7
- package/src/urls.ts +5 -0
- package/dist/package.json +0 -65
- package/dist/src/cli/argument-parser.js.map +0 -1
- package/dist/src/cli/file-processor.js.map +0 -1
- package/dist/src/cli/formatters/base-formatter.js.map +0 -1
- package/dist/src/cli/formatters/detailed-formatter.js.map +0 -1
- package/dist/src/cli/formatters/github-actions-formatter.js.map +0 -1
- package/dist/src/cli/formatters/index.js.map +0 -1
- package/dist/src/cli/formatters/json-formatter.js.map +0 -1
- package/dist/src/cli/formatters/simple-formatter.js +0 -44
- package/dist/src/cli/formatters/simple-formatter.js.map +0 -1
- package/dist/src/cli/index.js.map +0 -1
- package/dist/src/cli/output-manager.js.map +0 -1
- package/dist/src/cli/summary-reporter.js.map +0 -1
- package/dist/src/cli.js.map +0 -1
- package/dist/src/custom-rule-loader.js.map +0 -1
- package/dist/src/herb-disable-comment-utils.js.map +0 -1
- package/dist/src/herb-lint.js +0 -5
- package/dist/src/herb-lint.js.map +0 -1
- package/dist/src/index.js +0 -5
- package/dist/src/index.js.map +0 -1
- package/dist/src/linter-ignore.js.map +0 -1
- package/dist/src/linter.js.map +0 -1
- package/dist/src/loader.js +0 -17
- package/dist/src/loader.js.map +0 -1
- package/dist/src/rules/erb-comment-syntax.js.map +0 -1
- package/dist/src/rules/erb-no-case-node-children.js.map +0 -1
- package/dist/src/rules/erb-no-empty-tags.js.map +0 -1
- package/dist/src/rules/erb-no-extra-newline.js.map +0 -1
- package/dist/src/rules/erb-no-extra-whitespace-inside-tags.js.map +0 -1
- package/dist/src/rules/erb-no-output-control-flow.js.map +0 -1
- package/dist/src/rules/erb-no-silent-tag-in-attribute-name.js.map +0 -1
- package/dist/src/rules/erb-prefer-image-tag-helper.js.map +0 -1
- package/dist/src/rules/erb-require-trailing-newline.js.map +0 -1
- package/dist/src/rules/erb-require-whitespace-inside-tags.js.map +0 -1
- package/dist/src/rules/erb-right-trim.js.map +0 -1
- package/dist/src/rules/erb-strict-locals-comment-syntax.js.map +0 -1
- package/dist/src/rules/erb-strict-locals-required.js.map +0 -1
- package/dist/src/rules/file-utils.js.map +0 -1
- package/dist/src/rules/herb-disable-comment-base.js.map +0 -1
- package/dist/src/rules/herb-disable-comment-malformed.js.map +0 -1
- package/dist/src/rules/herb-disable-comment-missing-rules.js.map +0 -1
- package/dist/src/rules/herb-disable-comment-no-duplicate-rules.js.map +0 -1
- package/dist/src/rules/herb-disable-comment-no-redundant-all.js.map +0 -1
- package/dist/src/rules/herb-disable-comment-unnecessary.js.map +0 -1
- package/dist/src/rules/herb-disable-comment-valid-rule-name.js.map +0 -1
- package/dist/src/rules/html-anchor-require-href.js +0 -32
- package/dist/src/rules/html-anchor-require-href.js.map +0 -1
- package/dist/src/rules/html-aria-attribute-must-be-valid.js.map +0 -1
- package/dist/src/rules/html-aria-label-is-well-formatted.js.map +0 -1
- package/dist/src/rules/html-aria-level-must-be-valid.js.map +0 -1
- package/dist/src/rules/html-aria-role-heading-requires-level.js.map +0 -1
- package/dist/src/rules/html-aria-role-must-be-valid.js.map +0 -1
- package/dist/src/rules/html-attribute-double-quotes.js.map +0 -1
- package/dist/src/rules/html-attribute-equals-spacing.js.map +0 -1
- package/dist/src/rules/html-attribute-values-require-quotes.js.map +0 -1
- package/dist/src/rules/html-avoid-both-disabled-and-aria-disabled.js.map +0 -1
- package/dist/src/rules/html-body-only-elements.js.map +0 -1
- package/dist/src/rules/html-boolean-attributes-no-value.js.map +0 -1
- package/dist/src/rules/html-head-only-elements.js.map +0 -1
- package/dist/src/rules/html-iframe-has-title.js.map +0 -1
- package/dist/src/rules/html-img-require-alt.js.map +0 -1
- package/dist/src/rules/html-input-require-autocomplete.js.map +0 -1
- package/dist/src/rules/html-navigation-has-label.js.map +0 -1
- package/dist/src/rules/html-no-aria-hidden-on-focusable.js.map +0 -1
- package/dist/src/rules/html-no-block-inside-inline.js.map +0 -1
- package/dist/src/rules/html-no-duplicate-attributes.js.map +0 -1
- package/dist/src/rules/html-no-duplicate-ids.js.map +0 -1
- package/dist/src/rules/html-no-duplicate-meta-names.js.map +0 -1
- package/dist/src/rules/html-no-empty-attributes.js.map +0 -1
- package/dist/src/rules/html-no-empty-headings.js +0 -115
- package/dist/src/rules/html-no-empty-headings.js.map +0 -1
- package/dist/src/rules/html-no-nested-links.js.map +0 -1
- package/dist/src/rules/html-no-positive-tab-index.js.map +0 -1
- package/dist/src/rules/html-no-self-closing.js.map +0 -1
- package/dist/src/rules/html-no-space-in-tag.js.map +0 -1
- package/dist/src/rules/html-no-title-attribute.js.map +0 -1
- package/dist/src/rules/html-no-underscores-in-attribute-names.js.map +0 -1
- package/dist/src/rules/html-tag-name-lowercase.js.map +0 -1
- package/dist/src/rules/index.js.map +0 -1
- package/dist/src/rules/parser-no-errors.js.map +0 -1
- package/dist/src/rules/rule-utils.js.map +0 -1
- package/dist/src/rules/string-utils.js.map +0 -1
- package/dist/src/rules/svg-tag-name-capitalization.js.map +0 -1
- package/dist/src/rules.js.map +0 -1
- package/dist/src/types.js.map +0 -1
- package/dist/tsconfig.tsbuildinfo +0 -1
- package/dist/types/src/cli/argument-parser.d.ts +0 -25
- package/dist/types/src/cli/file-processor.d.ts +0 -43
- package/dist/types/src/cli/formatters/base-formatter.d.ts +0 -6
- package/dist/types/src/cli/formatters/detailed-formatter.d.ts +0 -13
- package/dist/types/src/cli/formatters/github-actions-formatter.d.ts +0 -17
- package/dist/types/src/cli/formatters/index.d.ts +0 -5
- package/dist/types/src/cli/formatters/json-formatter.d.ts +0 -48
- package/dist/types/src/cli/formatters/simple-formatter.d.ts +0 -8
- package/dist/types/src/cli/index.d.ts +0 -5
- package/dist/types/src/cli/output-manager.d.ts +0 -32
- package/dist/types/src/cli/summary-reporter.d.ts +0 -28
- package/dist/types/src/cli.d.ts +0 -28
- package/dist/types/src/custom-rule-loader.d.ts +0 -62
- package/dist/types/src/herb-disable-comment-utils.d.ts +0 -69
- package/dist/types/src/herb-lint.d.ts +0 -2
- package/dist/types/src/index.d.ts +0 -4
- package/dist/types/src/linter-ignore.d.ts +0 -12
- package/dist/types/src/linter.d.ts +0 -133
- package/dist/types/src/loader.d.ts +0 -20
- package/dist/types/src/rules/erb-comment-syntax.d.ts +0 -14
- package/dist/types/src/rules/erb-no-extra-newline.d.ts +0 -14
- package/dist/types/src/rules/erb-no-extra-whitespace-inside-tags.d.ts +0 -18
- package/dist/types/src/rules/erb-require-trailing-newline.d.ts +0 -9
- package/dist/types/src/rules/erb-require-whitespace-inside-tags.d.ts +0 -18
- package/dist/types/src/rules/erb-right-trim.d.ts +0 -14
- package/dist/types/src/rules/erb-strict-locals-comment-syntax.d.ts +0 -9
- package/dist/types/src/rules/erb-strict-locals-required.d.ts +0 -9
- package/dist/types/src/rules/file-utils.d.ts +0 -13
- package/dist/types/src/rules/herb-disable-comment-base.d.ts +0 -37
- package/dist/types/src/rules/herb-disable-comment-no-duplicate-rules.d.ts +0 -8
- package/dist/types/src/rules/herb-disable-comment-no-redundant-all.d.ts +0 -8
- package/dist/types/src/rules/herb-disable-comment-unnecessary.d.ts +0 -8
- package/dist/types/src/rules/herb-disable-comment-valid-rule-name.d.ts +0 -8
- package/dist/types/src/rules/html-aria-label-is-well-formatted.d.ts +0 -8
- package/dist/types/src/rules/html-aria-role-heading-requires-level.d.ts +0 -8
- package/dist/types/src/rules/html-attribute-double-quotes.d.ts +0 -15
- package/dist/types/src/rules/html-attribute-equals-spacing.d.ts +0 -14
- package/dist/types/src/rules/html-attribute-values-require-quotes.d.ts +0 -15
- package/dist/types/src/rules/html-avoid-both-disabled-and-aria-disabled.d.ts +0 -8
- package/dist/types/src/rules/html-boolean-attributes-no-value.d.ts +0 -14
- package/dist/types/src/rules/html-head-only-elements.d.ts +0 -9
- package/dist/types/src/rules/html-iframe-has-title.d.ts +0 -8
- package/dist/types/src/rules/html-img-require-alt.d.ts +0 -8
- package/dist/types/src/rules/html-input-require-autocomplete.d.ts +0 -8
- package/dist/types/src/rules/html-no-block-inside-inline.d.ts +0 -8
- package/dist/types/src/rules/html-no-duplicate-ids.d.ts +0 -8
- package/dist/types/src/rules/html-no-duplicate-meta-names.d.ts +0 -9
- package/dist/types/src/rules/html-no-nested-links.d.ts +0 -8
- package/dist/types/src/rules/html-no-self-closing.d.ts +0 -16
- package/dist/types/src/rules/html-no-space-in-tag.d.ts +0 -16
- package/dist/types/src/rules/html-no-underscores-in-attribute-names.d.ts +0 -8
- package/dist/types/src/rules/html-tag-name-lowercase.d.ts +0 -18
- package/dist/types/src/rules/index.d.ts +0 -54
- package/dist/types/src/rules/parser-no-errors.d.ts +0 -9
- package/dist/types/src/rules/rule-utils.d.ts +0 -351
- package/dist/types/src/rules/string-utils.d.ts +0 -15
- package/dist/types/src/rules/svg-tag-name-capitalization.d.ts +0 -16
- package/dist/types/src/rules.d.ts +0 -2
- package/dist/types/src/types.d.ts +0 -190
- /package/dist/{src/cli → cli}/formatters/base-formatter.js +0 -0
- /package/dist/{src/cli → cli}/formatters/github-actions-formatter.js +0 -0
- /package/dist/{src/cli → cli}/formatters/index.js +0 -0
- /package/dist/{src/cli → cli}/formatters/json-formatter.js +0 -0
- /package/dist/{src/cli → cli}/index.js +0 -0
- /package/dist/{src/cli → cli}/output-manager.js +0 -0
- /package/dist/{src/herb-disable-comment-utils.js → herb-disable-comment-utils.js} +0 -0
- /package/dist/{src/linter-ignore.js → linter-ignore.js} +0 -0
- /package/dist/{src/rules → rules}/file-utils.js +0 -0
- /package/dist/{src/rules → rules}/herb-disable-comment-base.js +0 -0
- /package/dist/{src/rules → rules}/string-utils.js +0 -0
|
@@ -4,11 +4,11 @@
|
|
|
4
4
|
|
|
5
5
|
## Description
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
An `<a>` element that has an `href` attribute represents a hyperlink (a hypertext anchor) labeled by its contents. Links should go somewhere. If you want to perform an action without navigating the user to a new URL, use a `<button>` instead.
|
|
8
8
|
|
|
9
9
|
## Rationale
|
|
10
10
|
|
|
11
|
-
Anchor tags without href are
|
|
11
|
+
Anchor tags without an `href` attribute are not focusable via keyboard navigation and are not visible to screen readers. This makes them inaccessible to users who rely on assistive technologies.
|
|
12
12
|
|
|
13
13
|
## Examples
|
|
14
14
|
|
|
@@ -20,13 +20,26 @@ Anchor tags without href are unfocusable if user is using keyboard navigation, o
|
|
|
20
20
|
|
|
21
21
|
### 🚫 Bad
|
|
22
22
|
|
|
23
|
+
```erb
|
|
24
|
+
<a>Go to Page</a>
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
```erb
|
|
28
|
+
<a href="#">Go to Page</a>
|
|
29
|
+
```
|
|
30
|
+
|
|
23
31
|
```erb
|
|
24
32
|
<a data-action="click->doSomething">I'm a fake link</a>
|
|
25
33
|
```
|
|
26
34
|
|
|
27
35
|
## References
|
|
28
36
|
|
|
29
|
-
* https://
|
|
30
|
-
* https://
|
|
31
|
-
* https://
|
|
32
|
-
* https://
|
|
37
|
+
* [MDN: The Anchor element](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a)
|
|
38
|
+
* [HTML Spec: The `a` element](https://html.spec.whatwg.org/multipage/text-level-semantics.html#the-a-element)
|
|
39
|
+
* [WAI-ARIA 1.2: `link` role](https://www.w3.org/TR/wai-aria-1.2/#link)
|
|
40
|
+
* [Primer: Links](https://primer.style/design/accessibility/links)
|
|
41
|
+
* [Links vs. Buttons in Modern Web Applications](https://marcysutton.com/links-vs-buttons-in-modern-web-applications)
|
|
42
|
+
* [Button vs. Link](https://a11y-101.com/design/button-vs-link)
|
|
43
|
+
* [MDN: ARIA button role](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/button_role)
|
|
44
|
+
* [Disabled Links](https://www.scottohara.me/blog/2021/05/28/disabled-links.html)
|
|
45
|
+
* [`erblint-github`: `LinkHasHref`](https://github.com/github/erblint-github/blob/main/docs/rules/accessibility/link-has-href.md)
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# Linter Rule: `<details>` elements must have a `<summary>` child
|
|
2
|
+
|
|
3
|
+
**Rule:** `html-details-has-summary`
|
|
4
|
+
|
|
5
|
+
## Description
|
|
6
|
+
|
|
7
|
+
Ensure that all `<details>` elements have a direct `<summary>` child element that describes what the disclosure widget will expand.
|
|
8
|
+
|
|
9
|
+
## Rationale
|
|
10
|
+
|
|
11
|
+
The `<summary>` element provides a visible label for the `<details>` disclosure widget, hinting to the user what they'll be expanding. Screen reader users rely on `<summary>` elements to understand the purpose of the expandable content. If a developer omits the `<summary>`, the user agent adds a default one with no meaningful context. The `<summary>` must be a direct child of `<details>` to function correctly — nesting it inside another element will not work as intended.
|
|
12
|
+
|
|
13
|
+
## Examples
|
|
14
|
+
|
|
15
|
+
### ✅ Good
|
|
16
|
+
|
|
17
|
+
```erb
|
|
18
|
+
<details>
|
|
19
|
+
<summary>Expand me!</summary>
|
|
20
|
+
I do have a summary tag!
|
|
21
|
+
</details>
|
|
22
|
+
|
|
23
|
+
<details>
|
|
24
|
+
I do have a summary tag!
|
|
25
|
+
<summary>Expand me!</summary>
|
|
26
|
+
</details>
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
### 🚫 Bad
|
|
30
|
+
|
|
31
|
+
```erb
|
|
32
|
+
<details>
|
|
33
|
+
I don't have a summary tag!
|
|
34
|
+
</details>
|
|
35
|
+
|
|
36
|
+
<details>
|
|
37
|
+
<div><summary>Expand me!</summary></div>
|
|
38
|
+
The summary tag needs to be a direct child of the details tag.
|
|
39
|
+
</details>
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## References
|
|
43
|
+
|
|
44
|
+
- [HTML: `details` element](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/details)
|
|
45
|
+
- [HTML: `summary` element](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/summary)
|
|
46
|
+
- [erblint-github: GitHub::Accessibility::DetailsHasSummary](https://github.com/github/erblint-github/pull/23)
|
|
@@ -31,12 +31,14 @@ Omitting the `alt` attribute entirely leads to poor accessibility and can negati
|
|
|
31
31
|
```erb
|
|
32
32
|
<img src="/logo.png">
|
|
33
33
|
|
|
34
|
-
<img src="/avatar.jpg" alt>
|
|
34
|
+
<img src="/avatar.jpg" alt>
|
|
35
35
|
|
|
36
36
|
<%= image_tag image_path("logo.png") %> <!-- TODO -->
|
|
37
37
|
```
|
|
38
38
|
|
|
39
39
|
## References
|
|
40
40
|
|
|
41
|
-
|
|
42
|
-
|
|
41
|
+
- [W3C WAI Images Tutorial](https://www.w3.org/WAI/tutorials/images/)
|
|
42
|
+
- [WCAG 2.1: Non-text Content](https://www.w3.org/WAI/WCAG22/quickref/?versions=2.1#non-text-content)
|
|
43
|
+
- [Primer: Alternative text for images](https://primer.style/accessibility/design-guidance/alternative-text-for-images/)
|
|
44
|
+
- [erblint-github: `GitHub::Accessibility::ImageHasAlt`](https://github.com/github/erblint-github/blob/main/docs/rules/accessibility/image-has-alt.md)
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# Linter Rule: No abstract ARIA roles
|
|
2
|
+
|
|
3
|
+
**Rule:** `html-no-abstract-roles`
|
|
4
|
+
|
|
5
|
+
## Description
|
|
6
|
+
|
|
7
|
+
Prevent usage of WAI-ARIA abstract roles in the `role` attribute.
|
|
8
|
+
|
|
9
|
+
## Rationale
|
|
10
|
+
|
|
11
|
+
The WAI-ARIA specification defines a set of abstract roles that are used to support the ARIA Roles Model for the purpose of defining general role concepts.
|
|
12
|
+
|
|
13
|
+
Abstract roles are used for the ontology only. They exist to help organize the hierarchy of roles and define shared characteristics, but they are not meant to be used by authors directly. Using abstract roles in content provides no semantic meaning to assistive technologies and can lead to accessibility issues.
|
|
14
|
+
|
|
15
|
+
Authors **MUST NOT** use abstract roles in content. Instead, use one of the concrete roles that inherit from these abstract roles. For example, use `button` instead of `command`, or `navigation` instead of `landmark`.
|
|
16
|
+
|
|
17
|
+
The following abstract roles must not be used:
|
|
18
|
+
|
|
19
|
+
- `command`
|
|
20
|
+
- `composite`
|
|
21
|
+
- `input`
|
|
22
|
+
- `landmark`
|
|
23
|
+
- `range`
|
|
24
|
+
- `roletype`
|
|
25
|
+
- `section`
|
|
26
|
+
- `sectionhead`
|
|
27
|
+
- `select`
|
|
28
|
+
- `structure`
|
|
29
|
+
- `widget`
|
|
30
|
+
- `window`
|
|
31
|
+
|
|
32
|
+
## Examples
|
|
33
|
+
|
|
34
|
+
### ✅ Good
|
|
35
|
+
|
|
36
|
+
```erb
|
|
37
|
+
<div role="button">Push it</div>
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
```erb
|
|
41
|
+
<nav role="navigation">Menu</nav>
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
```erb
|
|
45
|
+
<div role="alert">Warning!</div>
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
```erb
|
|
49
|
+
<div role="slider" aria-valuenow="50">Volume</div>
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### 🚫 Bad
|
|
53
|
+
|
|
54
|
+
```erb
|
|
55
|
+
<div role="window">Hello, world!</div>
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
```erb
|
|
59
|
+
<div role="widget">Content</div>
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
```erb
|
|
63
|
+
<div role="command">Action</div>
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
```erb
|
|
67
|
+
<div role="landmark">Navigation</div>
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## References
|
|
71
|
+
|
|
72
|
+
- [WAI-ARIA 1.0: Abstract Roles](https://www.w3.org/TR/wai-aria-1.0/roles#abstract_roles)
|
|
73
|
+
- [WAI-ARIA 1.2: Abstract Roles](https://www.w3.org/TR/wai-aria-1.2/#abstract_roles)
|
|
74
|
+
- [ember-template-lint: no-abstract-roles](https://github.com/ember-template-lint/ember-template-lint/blob/main/docs/rule/no-abstract-roles.md)
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# Linter Rule: No `aria-hidden` on `<body>`
|
|
2
|
+
|
|
3
|
+
**Rule:** `html-no-aria-hidden-on-body`
|
|
4
|
+
|
|
5
|
+
## Description
|
|
6
|
+
|
|
7
|
+
Prevent usage of `aria-hidden` on `<body>` tags.
|
|
8
|
+
|
|
9
|
+
## Rationale
|
|
10
|
+
|
|
11
|
+
The `aria-hidden` attribute should never be present on the `<body>` element, as it hides the entire document from assistive technology users. This makes the entire page completely inaccessible to screen reader users, which is a critical accessibility violation.
|
|
12
|
+
|
|
13
|
+
## Examples
|
|
14
|
+
|
|
15
|
+
### ✅ Good
|
|
16
|
+
|
|
17
|
+
```erb
|
|
18
|
+
<body>
|
|
19
|
+
<main>Content</main>
|
|
20
|
+
</body>
|
|
21
|
+
|
|
22
|
+
<body class="app" id="main">
|
|
23
|
+
<main>Content</main>
|
|
24
|
+
</body>
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
### 🚫 Bad
|
|
28
|
+
|
|
29
|
+
```erb
|
|
30
|
+
<body aria-hidden>
|
|
31
|
+
<main>Content</main>
|
|
32
|
+
</body>
|
|
33
|
+
|
|
34
|
+
<body aria-hidden="true">
|
|
35
|
+
<main>Content</main>
|
|
36
|
+
</body>
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## References
|
|
40
|
+
|
|
41
|
+
- [Using the aria-hidden attribute](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/ARIA_Techniques/Using_the_aria-hidden_attribute)
|
|
42
|
+
- [How Lighthouse identifies hidden body elements](https://web.dev/aria-hidden-body/)
|
|
43
|
+
- [WCAG 4.1.2 - Name, Role, Value (Level A)](https://www.w3.org/TR/WCAG21/#name-role-value)
|
|
44
|
+
- [ember-template-lint: no-aria-hidden-body](https://github.com/ember-template-lint/ember-template-lint/blob/main/docs/rule/no-aria-hidden-body.md)
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
# Linter Rule: Require explicit closing tags
|
|
2
|
+
|
|
3
|
+
**Rule:** `html-require-closing-tags`
|
|
4
|
+
|
|
5
|
+
## Description
|
|
6
|
+
|
|
7
|
+
Disallow the omission of optional closing tags for HTML elements where the closing tag is technically optional according to the HTML specification. This rule flags elements that have an `HTMLOmittedCloseTagNode` as their close tag.
|
|
8
|
+
|
|
9
|
+
## Rationale
|
|
10
|
+
|
|
11
|
+
While HTML allows certain closing tags to be omitted (implicitly closed by sibling elements or parent closing), explicit closing tags improve code readability and maintainability. They make the document structure clear at a glance and reduce ambiguity about where elements end.
|
|
12
|
+
|
|
13
|
+
Explicit closing tags also:
|
|
14
|
+
|
|
15
|
+
- Make templates easier to understand for developers unfamiliar with HTML's implicit closing rules
|
|
16
|
+
- Reduce potential for subtle bugs when refactoring or moving code
|
|
17
|
+
- Improve consistency across the codebase
|
|
18
|
+
- Make diffs cleaner when adding content to elements
|
|
19
|
+
|
|
20
|
+
## Elements with Optional Closing Tags
|
|
21
|
+
|
|
22
|
+
This rule would flag elements that have omitted closing tags:
|
|
23
|
+
|
|
24
|
+
- `<li>` - list items
|
|
25
|
+
- `<dt>`, `<dd>` - definition list terms and descriptions
|
|
26
|
+
- `<p>` - paragraphs
|
|
27
|
+
- `<option>`, `<optgroup>` - select options and groups
|
|
28
|
+
- `<thead>`, `<tbody>`, `<tfoot>` - table sections
|
|
29
|
+
- `<tr>` - table rows
|
|
30
|
+
- `<td>`, `<th>` - table cells
|
|
31
|
+
- `<colgroup>` - table column groups
|
|
32
|
+
- `<rt>`, `<rp>` - ruby annotations
|
|
33
|
+
|
|
34
|
+
## Examples
|
|
35
|
+
|
|
36
|
+
### ✅ Good
|
|
37
|
+
|
|
38
|
+
Explicit closing tags:
|
|
39
|
+
|
|
40
|
+
```erb
|
|
41
|
+
<ul>
|
|
42
|
+
<li>Item 1</li>
|
|
43
|
+
<li>Item 2</li>
|
|
44
|
+
<li>Item 3</li>
|
|
45
|
+
</ul>
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
```erb
|
|
49
|
+
<dl>
|
|
50
|
+
<dt>Term 1</dt>
|
|
51
|
+
<dd>Definition 1</dd>
|
|
52
|
+
<dt>Term 2</dt>
|
|
53
|
+
<dd>Definition 2</dd>
|
|
54
|
+
</dl>
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
```erb
|
|
58
|
+
<table>
|
|
59
|
+
<thead>
|
|
60
|
+
<tr>
|
|
61
|
+
<th>Header 1</th>
|
|
62
|
+
<th>Header 2</th>
|
|
63
|
+
</tr>
|
|
64
|
+
</thead>
|
|
65
|
+
<tbody>
|
|
66
|
+
<tr>
|
|
67
|
+
<td>Cell 1</td>
|
|
68
|
+
<td>Cell 2</td>
|
|
69
|
+
</tr>
|
|
70
|
+
</tbody>
|
|
71
|
+
</table>
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
```erb
|
|
75
|
+
<select>
|
|
76
|
+
<option>Option 1</option>
|
|
77
|
+
<option>Option 2</option>
|
|
78
|
+
<option>Option 3</option>
|
|
79
|
+
</select>
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
```erb
|
|
83
|
+
<div>
|
|
84
|
+
<p>Paragraph 1</p>
|
|
85
|
+
<p>Paragraph 2</p>
|
|
86
|
+
</div>
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### 🚫 Bad
|
|
90
|
+
|
|
91
|
+
Omitted closing tags (implicitly closed):
|
|
92
|
+
|
|
93
|
+
```erb
|
|
94
|
+
<ul>
|
|
95
|
+
<li>Item 1
|
|
96
|
+
<li>Item 2
|
|
97
|
+
<li>Item 3
|
|
98
|
+
</ul>
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
```erb
|
|
102
|
+
<dl>
|
|
103
|
+
<dt>Term 1
|
|
104
|
+
<dd>Definition 1
|
|
105
|
+
<dt>Term 2
|
|
106
|
+
<dd>Definition 2
|
|
107
|
+
</dl>
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
```erb
|
|
111
|
+
<table>
|
|
112
|
+
<thead>
|
|
113
|
+
<tr>
|
|
114
|
+
<th>Header 1
|
|
115
|
+
<th>Header 2
|
|
116
|
+
<tbody>
|
|
117
|
+
<tr>
|
|
118
|
+
<td>Cell 1
|
|
119
|
+
<td>Cell 2
|
|
120
|
+
</table>
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
```erb
|
|
124
|
+
<select>
|
|
125
|
+
<option>Option 1
|
|
126
|
+
<option>Option 2
|
|
127
|
+
<option>Option 3
|
|
128
|
+
</select>
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
```erb
|
|
132
|
+
<div>
|
|
133
|
+
<p>Paragraph 1
|
|
134
|
+
<p>Paragraph 2
|
|
135
|
+
</div>
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
## References
|
|
139
|
+
|
|
140
|
+
- [HTML Spec: Optional Tags](https://html.spec.whatwg.org/multipage/syntax.html#optional-tags)
|
|
141
|
+
- [HTML Spec: Tag Omission](https://html.spec.whatwg.org/multipage/dom.html#concept-element-tag-omission)
|
|
142
|
+
- [CSS-Tricks: Fighting the Space Between Inline Block Elements](https://css-tricks.com/fighting-the-space-between-inline-block-elements/)
|
|
@@ -39,15 +39,16 @@ By surfacing parser errors through the linter, developers can catch these critic
|
|
|
39
39
|
### 🚫 Bad
|
|
40
40
|
|
|
41
41
|
```html
|
|
42
|
-
<!-- Mismatched closing tag -->
|
|
43
42
|
<h2>Welcome to our site</h3>
|
|
43
|
+
```
|
|
44
44
|
|
|
45
|
-
|
|
45
|
+
```html
|
|
46
46
|
<div>
|
|
47
47
|
<p>This paragraph is never closed
|
|
48
48
|
</div>
|
|
49
|
+
```
|
|
49
50
|
|
|
50
|
-
|
|
51
|
+
```html
|
|
51
52
|
Some content
|
|
52
53
|
</div>
|
|
53
54
|
```
|
|
@@ -63,20 +64,6 @@ Some content
|
|
|
63
64
|
<img src="image.jpg" alt="Description"></img>
|
|
64
65
|
```
|
|
65
66
|
|
|
66
|
-
## Error Types
|
|
67
|
-
|
|
68
|
-
This rule reports various parser error types:
|
|
69
|
-
|
|
70
|
-
- **`UNCLOSED_ELEMENT_ERROR`**: Elements that are opened but never closed
|
|
71
|
-
- **`MISSING_CLOSING_TAG_ERROR`**: Opening tags without matching closing tags
|
|
72
|
-
- **`MISSING_OPENING_TAG_ERROR`**: Closing tags without matching opening tags
|
|
73
|
-
- **`TAG_NAMES_MISMATCH_ERROR`**: Opening and closing tags with different names
|
|
74
|
-
- **`QUOTES_MISMATCH_ERROR`**: Mismatched quotation marks in attributes
|
|
75
|
-
- **`VOID_ELEMENT_CLOSING_TAG_ERROR`**: Void elements (like `<img>`) with closing tags
|
|
76
|
-
- **`RUBY_PARSE_ERROR`**: Invalid Ruby syntax within ERB tags
|
|
77
|
-
- **`UNEXPECTED_TOKEN_ERROR`**: Unexpected tokens during parsing
|
|
78
|
-
- **`UNEXPECTED_ERROR`**: Other unexpected parsing issues
|
|
79
|
-
|
|
80
67
|
## References
|
|
81
68
|
|
|
82
69
|
* [HTML Living Standard - Parsing](https://html.spec.whatwg.org/multipage/parsing.html)
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# Linter Rule: Require `id` attribute on elements with `data-turbo-permanent`
|
|
2
|
+
|
|
3
|
+
**Rule:** `turbo-permanent-require-id`
|
|
4
|
+
|
|
5
|
+
## Description
|
|
6
|
+
|
|
7
|
+
Ensure that all HTML elements with the `data-turbo-permanent` attribute also have an `id` attribute. Without an `id`, Turbo can't track the element across page changes and the permanent behavior won't work as expected.
|
|
8
|
+
|
|
9
|
+
## Rationale
|
|
10
|
+
|
|
11
|
+
Turbo's `data-turbo-permanent` attribute marks an element to be persisted across page navigations. Turbo uses the element's `id` to match it between the current page and the new page. If no `id` is present, Turbo has no way to identify and preserve the element, so the `data-turbo-permanent` attribute has no effect.
|
|
12
|
+
|
|
13
|
+
## Examples
|
|
14
|
+
|
|
15
|
+
### ✅ Good
|
|
16
|
+
|
|
17
|
+
```erb
|
|
18
|
+
<div id="player" data-turbo-permanent>
|
|
19
|
+
<!-- This element will persist across page navigations -->
|
|
20
|
+
</div>
|
|
21
|
+
|
|
22
|
+
<audio id="background-music" data-turbo-permanent>
|
|
23
|
+
<source src="/music.mp3" type="audio/mpeg">
|
|
24
|
+
</audio>
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
### 🚫 Bad
|
|
28
|
+
|
|
29
|
+
```erb
|
|
30
|
+
<div data-turbo-permanent>
|
|
31
|
+
<!-- Missing id: Turbo can't track this element -->
|
|
32
|
+
</div>
|
|
33
|
+
|
|
34
|
+
<audio data-turbo-permanent>
|
|
35
|
+
<source src="/music.mp3" type="audio/mpeg">
|
|
36
|
+
</audio>
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## References
|
|
40
|
+
|
|
41
|
+
- [Turbo Handbook: Persisting Elements Across Page Loads](https://turbo.hotwired.dev/handbook/building#persisting-elements-across-page-loads)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@herb-tools/linter",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.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
|
"default": "./dist/index.js"
|
|
34
34
|
},
|
|
35
35
|
"./cli": {
|
|
36
|
-
"types": "./dist/types/
|
|
37
|
-
"
|
|
38
|
-
"
|
|
36
|
+
"types": "./dist/types/cli.d.ts",
|
|
37
|
+
"import": "./dist/cli.js",
|
|
38
|
+
"require": "./dist/cli.js",
|
|
39
|
+
"default": "./dist/cli.js"
|
|
39
40
|
},
|
|
40
41
|
"./loader": {
|
|
41
42
|
"types": "./dist/types/loader.d.ts",
|
|
@@ -45,12 +46,12 @@
|
|
|
45
46
|
}
|
|
46
47
|
},
|
|
47
48
|
"dependencies": {
|
|
48
|
-
"@herb-tools/config": "0.
|
|
49
|
-
"@herb-tools/core": "0.
|
|
50
|
-
"@herb-tools/highlighter": "0.
|
|
51
|
-
"@herb-tools/node-wasm": "0.
|
|
52
|
-
"@herb-tools/printer": "0.
|
|
53
|
-
"@herb-tools/rewriter": "0.
|
|
49
|
+
"@herb-tools/config": "0.9.1",
|
|
50
|
+
"@herb-tools/core": "0.9.1",
|
|
51
|
+
"@herb-tools/highlighter": "0.9.1",
|
|
52
|
+
"@herb-tools/node-wasm": "0.9.1",
|
|
53
|
+
"@herb-tools/printer": "0.9.1",
|
|
54
|
+
"@herb-tools/rewriter": "0.9.1",
|
|
54
55
|
"picomatch": "^4.0.2",
|
|
55
56
|
"tinyglobby": "^0.2.15"
|
|
56
57
|
},
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import dedent from "dedent"
|
|
2
2
|
|
|
3
|
+
import { availableParallelism } from "node:os"
|
|
3
4
|
import { parseArgs } from "util"
|
|
4
5
|
import { Herb } from "@herb-tools/node-wasm"
|
|
5
6
|
|
|
@@ -27,6 +28,7 @@ export interface ParsedArguments {
|
|
|
27
28
|
init: boolean
|
|
28
29
|
loadCustomRules: boolean
|
|
29
30
|
failLevel?: DiagnosticSeverity
|
|
31
|
+
jobs: number
|
|
30
32
|
}
|
|
31
33
|
|
|
32
34
|
export class ArgumentParser {
|
|
@@ -53,6 +55,8 @@ export class ArgumentParser {
|
|
|
53
55
|
--github enable GitHub Actions annotations (combines with --format)
|
|
54
56
|
--no-github disable GitHub Actions annotations (even in GitHub Actions environment)
|
|
55
57
|
--no-custom-rules disable loading custom rules from project (custom rules are loaded by default from .herb/rules/**/*.{mjs,js})
|
|
58
|
+
-j, --jobs <n> number of parallel workers for linting files [default: auto]
|
|
59
|
+
use "auto" to detect based on available CPU cores
|
|
56
60
|
--theme syntax highlighting theme (${THEME_NAMES.join("|")}) or path to custom theme file [default: ${DEFAULT_THEME}]
|
|
57
61
|
--no-color disable colored output
|
|
58
62
|
--no-timing hide timing information
|
|
@@ -83,7 +87,8 @@ export class ArgumentParser {
|
|
|
83
87
|
"no-timing": { type: "boolean" },
|
|
84
88
|
"no-wrap-lines": { type: "boolean" },
|
|
85
89
|
"truncate-lines": { type: "boolean" },
|
|
86
|
-
"no-custom-rules": { type: "boolean" }
|
|
90
|
+
"no-custom-rules": { type: "boolean" },
|
|
91
|
+
jobs: { type: "string", short: "j" }
|
|
87
92
|
},
|
|
88
93
|
allowPositionals: true
|
|
89
94
|
})
|
|
@@ -163,7 +168,20 @@ export class ArgumentParser {
|
|
|
163
168
|
}
|
|
164
169
|
}
|
|
165
170
|
|
|
166
|
-
|
|
171
|
+
let jobs = availableParallelism()
|
|
172
|
+
|
|
173
|
+
if (values.jobs && values.jobs !== "auto") {
|
|
174
|
+
const parsed = parseInt(values.jobs, 10)
|
|
175
|
+
|
|
176
|
+
if (isNaN(parsed) || parsed < 1) {
|
|
177
|
+
console.error(`Error: Invalid --jobs value "${values.jobs}". Must be a positive integer or "auto".`)
|
|
178
|
+
process.exit(1)
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
jobs = parsed
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
return { patterns, configFile, formatOption, showTiming, theme, wrapLines, truncateLines, useGitHubActions, fix, fixUnsafe, ignoreDisableComments, force, init, loadCustomRules, failLevel, jobs }
|
|
167
185
|
}
|
|
168
186
|
|
|
169
187
|
private getFilePatterns(positionals: string[]): string[] {
|