@herb-tools/linter 0.7.4 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +253 -13
- package/dist/herb-lint.js +26087 -3414
- package/dist/herb-lint.js.map +1 -1
- package/dist/index.cjs +5783 -1568
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +5749 -1569
- package/dist/index.js.map +1 -1
- package/dist/loader.cjs +17010 -0
- package/dist/loader.cjs.map +1 -0
- package/dist/loader.js +16879 -0
- package/dist/loader.js.map +1 -0
- package/dist/package.json +13 -5
- package/dist/src/cli/argument-parser.js +42 -35
- package/dist/src/cli/argument-parser.js.map +1 -1
- package/dist/src/cli/file-processor.js +124 -23
- package/dist/src/cli/file-processor.js.map +1 -1
- package/dist/src/cli/formatters/detailed-formatter.js +18 -3
- package/dist/src/cli/formatters/detailed-formatter.js.map +1 -1
- package/dist/src/cli/formatters/github-actions-formatter.js +15 -1
- package/dist/src/cli/formatters/github-actions-formatter.js.map +1 -1
- package/dist/src/cli/formatters/json-formatter.js +3 -0
- package/dist/src/cli/formatters/json-formatter.js.map +1 -1
- package/dist/src/cli/formatters/simple-formatter.js +20 -7
- package/dist/src/cli/formatters/simple-formatter.js.map +1 -1
- package/dist/src/cli/output-manager.js +22 -3
- package/dist/src/cli/output-manager.js.map +1 -1
- package/dist/src/cli/summary-reporter.js +26 -3
- package/dist/src/cli/summary-reporter.js.map +1 -1
- package/dist/src/cli.js +109 -43
- package/dist/src/cli.js.map +1 -1
- package/dist/src/custom-rule-loader.js +139 -0
- package/dist/src/custom-rule-loader.js.map +1 -0
- package/dist/src/herb-disable-comment-utils.js +129 -0
- package/dist/src/herb-disable-comment-utils.js.map +1 -0
- package/dist/src/index.js +1 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/linter.js +369 -34
- package/dist/src/linter.js.map +1 -1
- package/dist/src/loader.js +17 -0
- package/dist/src/loader.js.map +1 -0
- package/dist/src/rules/erb-comment-syntax.js +48 -0
- package/dist/src/rules/erb-comment-syntax.js.map +1 -0
- package/dist/src/rules/erb-no-case-node-children.js +52 -0
- package/dist/src/rules/erb-no-case-node-children.js.map +1 -0
- package/dist/src/rules/erb-no-empty-tags.js +7 -1
- package/dist/src/rules/erb-no-empty-tags.js.map +1 -1
- package/dist/src/rules/erb-no-extra-newline.js +65 -0
- package/dist/src/rules/erb-no-extra-newline.js.map +1 -0
- package/dist/src/rules/erb-no-extra-whitespace-inside-tags.js +95 -0
- package/dist/src/rules/erb-no-extra-whitespace-inside-tags.js.map +1 -0
- package/dist/src/rules/erb-no-output-control-flow.js +7 -1
- package/dist/src/rules/erb-no-output-control-flow.js.map +1 -1
- package/dist/src/rules/erb-no-silent-tag-in-attribute-name.js +7 -1
- package/dist/src/rules/erb-no-silent-tag-in-attribute-name.js.map +1 -1
- package/dist/src/rules/erb-prefer-image-tag-helper.js +7 -1
- package/dist/src/rules/erb-prefer-image-tag-helper.js.map +1 -1
- package/dist/src/rules/erb-require-trailing-newline.js +35 -0
- package/dist/src/rules/erb-require-trailing-newline.js.map +1 -0
- package/dist/src/rules/erb-require-whitespace-inside-tags.js +70 -20
- package/dist/src/rules/erb-require-whitespace-inside-tags.js.map +1 -1
- package/dist/src/rules/erb-right-trim.js +45 -0
- package/dist/src/rules/erb-right-trim.js.map +1 -0
- package/dist/src/rules/herb-disable-comment-base.js +51 -0
- package/dist/src/rules/herb-disable-comment-base.js.map +1 -0
- package/dist/src/rules/herb-disable-comment-malformed.js +51 -0
- package/dist/src/rules/herb-disable-comment-malformed.js.map +1 -0
- package/dist/src/rules/herb-disable-comment-missing-rules.js +29 -0
- package/dist/src/rules/herb-disable-comment-missing-rules.js.map +1 -0
- package/dist/src/rules/herb-disable-comment-no-duplicate-rules.js +32 -0
- package/dist/src/rules/herb-disable-comment-no-duplicate-rules.js.map +1 -0
- package/dist/src/rules/herb-disable-comment-no-redundant-all.js +31 -0
- package/dist/src/rules/herb-disable-comment-no-redundant-all.js.map +1 -0
- package/dist/src/rules/herb-disable-comment-unnecessary.js +65 -0
- package/dist/src/rules/herb-disable-comment-unnecessary.js.map +1 -0
- package/dist/src/rules/herb-disable-comment-valid-rule-name.js +44 -0
- package/dist/src/rules/herb-disable-comment-valid-rule-name.js.map +1 -0
- package/dist/src/rules/html-anchor-require-href.js +7 -1
- package/dist/src/rules/html-anchor-require-href.js.map +1 -1
- package/dist/src/rules/html-aria-attribute-must-be-valid.js +7 -1
- 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 +9 -3
- package/dist/src/rules/html-aria-label-is-well-formatted.js.map +1 -1
- package/dist/src/rules/html-aria-level-must-be-valid.js +6 -0
- 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 -1
- 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 +7 -1
- package/dist/src/rules/html-aria-role-must-be-valid.js.map +1 -1
- package/dist/src/rules/html-attribute-double-quotes.js +29 -2
- package/dist/src/rules/html-attribute-double-quotes.js.map +1 -1
- package/dist/src/rules/html-attribute-equals-spacing.js +18 -2
- package/dist/src/rules/html-attribute-equals-spacing.js.map +1 -1
- package/dist/src/rules/html-attribute-values-require-quotes.js +39 -3
- 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 +7 -1
- package/dist/src/rules/html-avoid-both-disabled-and-aria-disabled.js.map +1 -1
- package/dist/src/rules/html-body-only-elements.js +46 -0
- package/dist/src/rules/html-body-only-elements.js.map +1 -0
- package/dist/src/rules/html-boolean-attributes-no-value.js +18 -1
- package/dist/src/rules/html-boolean-attributes-no-value.js.map +1 -1
- package/dist/src/rules/html-head-only-elements.js +51 -0
- package/dist/src/rules/html-head-only-elements.js.map +1 -0
- package/dist/src/rules/html-iframe-has-title.js +8 -2
- package/dist/src/rules/html-iframe-has-title.js.map +1 -1
- package/dist/src/rules/html-img-require-alt.js +7 -1
- package/dist/src/rules/html-img-require-alt.js.map +1 -1
- package/dist/src/rules/html-input-require-autocomplete.js +70 -0
- package/dist/src/rules/html-input-require-autocomplete.js.map +1 -0
- package/dist/src/rules/html-navigation-has-label.js +7 -1
- package/dist/src/rules/html-navigation-has-label.js.map +1 -1
- package/dist/src/rules/html-no-aria-hidden-on-focusable.js +7 -1
- package/dist/src/rules/html-no-aria-hidden-on-focusable.js.map +1 -1
- package/dist/src/rules/html-no-block-inside-inline.js +7 -1
- package/dist/src/rules/html-no-block-inside-inline.js.map +1 -1
- package/dist/src/rules/html-no-duplicate-attributes.js +7 -1
- package/dist/src/rules/html-no-duplicate-attributes.js.map +1 -1
- package/dist/src/rules/html-no-duplicate-ids.js +9 -3
- package/dist/src/rules/html-no-duplicate-ids.js.map +1 -1
- package/dist/src/rules/html-no-duplicate-meta-names.js +136 -0
- package/dist/src/rules/html-no-duplicate-meta-names.js.map +1 -0
- package/dist/src/rules/html-no-empty-attributes.js +45 -7
- package/dist/src/rules/html-no-empty-attributes.js.map +1 -1
- package/dist/src/rules/html-no-empty-headings.js +7 -6
- package/dist/src/rules/html-no-empty-headings.js.map +1 -1
- package/dist/src/rules/html-no-nested-links.js +7 -1
- package/dist/src/rules/html-no-nested-links.js.map +1 -1
- package/dist/src/rules/html-no-positive-tab-index.js +7 -1
- package/dist/src/rules/html-no-positive-tab-index.js.map +1 -1
- package/dist/src/rules/html-no-self-closing.js +48 -3
- package/dist/src/rules/html-no-self-closing.js.map +1 -1
- package/dist/src/rules/html-no-space-in-tag.js +173 -0
- package/dist/src/rules/html-no-space-in-tag.js.map +1 -0
- package/dist/src/rules/html-no-title-attribute.js +7 -1
- package/dist/src/rules/html-no-title-attribute.js.map +1 -1
- package/dist/src/rules/html-no-underscores-in-attribute-names.js +7 -1
- package/dist/src/rules/html-no-underscores-in-attribute-names.js.map +1 -1
- package/dist/src/rules/html-tag-name-lowercase.js +23 -5
- package/dist/src/rules/html-tag-name-lowercase.js.map +1 -1
- package/dist/src/rules/index.js +20 -2
- package/dist/src/rules/index.js.map +1 -1
- package/dist/src/rules/parser-no-errors.js +6 -0
- package/dist/src/rules/parser-no-errors.js.map +1 -1
- package/dist/src/rules/rule-utils.js +211 -31
- package/dist/src/rules/rule-utils.js.map +1 -1
- package/dist/src/rules/svg-tag-name-capitalization.js +22 -2
- package/dist/src/rules/svg-tag-name-capitalization.js.map +1 -1
- package/dist/src/{default-rules.js → rules.js} +46 -14
- package/dist/src/rules.js.map +1 -0
- package/dist/src/types.js +34 -1
- package/dist/src/types.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/types/cli/argument-parser.d.ts +8 -2
- package/dist/types/cli/file-processor.d.ts +15 -0
- package/dist/types/cli/formatters/json-formatter.d.ts +6 -0
- package/dist/types/cli/formatters/simple-formatter.d.ts +1 -0
- package/dist/types/cli/summary-reporter.d.ts +6 -0
- package/dist/types/cli.d.ts +9 -4
- package/dist/types/custom-rule-loader.d.ts +62 -0
- package/dist/types/herb-disable-comment-utils.d.ts +69 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types/linter.d.ts +99 -3
- package/dist/types/loader.d.ts +20 -0
- package/dist/types/rules/erb-comment-syntax.d.ts +14 -0
- package/dist/types/rules/erb-no-case-node-children.d.ts +8 -0
- package/dist/types/rules/erb-no-empty-tags.d.ts +3 -2
- package/dist/types/rules/erb-no-extra-newline.d.ts +14 -0
- package/dist/types/rules/erb-no-extra-whitespace-inside-tags.d.ts +18 -0
- package/dist/types/rules/erb-no-output-control-flow.d.ts +3 -2
- package/dist/types/rules/erb-no-silent-tag-in-attribute-name.d.ts +3 -2
- package/dist/types/rules/erb-prefer-image-tag-helper.d.ts +3 -2
- package/dist/types/rules/erb-require-trailing-newline.d.ts +9 -0
- package/dist/types/rules/erb-require-whitespace-inside-tags.d.ts +16 -5
- package/dist/types/rules/erb-right-trim.d.ts +14 -0
- package/dist/types/rules/herb-disable-comment-base.d.ts +37 -0
- package/dist/types/rules/herb-disable-comment-malformed.d.ts +8 -0
- package/dist/types/rules/herb-disable-comment-missing-rules.d.ts +8 -0
- package/dist/types/rules/herb-disable-comment-no-duplicate-rules.d.ts +8 -0
- package/dist/types/rules/herb-disable-comment-no-redundant-all.d.ts +8 -0
- package/dist/types/rules/herb-disable-comment-unnecessary.d.ts +8 -0
- package/dist/types/rules/herb-disable-comment-valid-rule-name.d.ts +8 -0
- package/dist/types/rules/html-anchor-require-href.d.ts +3 -2
- package/dist/types/rules/html-aria-attribute-must-be-valid.d.ts +3 -2
- package/dist/types/rules/html-aria-label-is-well-formatted.d.ts +3 -2
- package/dist/types/rules/html-aria-level-must-be-valid.d.ts +3 -2
- package/dist/types/rules/html-aria-role-heading-requires-level.d.ts +3 -2
- package/dist/types/rules/html-aria-role-must-be-valid.d.ts +3 -2
- package/dist/types/rules/html-attribute-double-quotes.d.ts +13 -5
- package/dist/types/rules/html-attribute-equals-spacing.d.ts +12 -5
- package/dist/types/rules/html-attribute-values-require-quotes.d.ts +13 -5
- package/dist/types/rules/html-avoid-both-disabled-and-aria-disabled.d.ts +3 -2
- package/dist/types/rules/html-body-only-elements.d.ts +9 -0
- package/dist/types/rules/html-boolean-attributes-no-value.d.ts +12 -5
- package/dist/types/rules/html-head-only-elements.d.ts +9 -0
- package/dist/types/rules/html-iframe-has-title.d.ts +3 -2
- package/dist/types/rules/html-img-require-alt.d.ts +3 -2
- package/dist/types/rules/html-input-require-autocomplete.d.ts +8 -0
- package/dist/types/rules/html-navigation-has-label.d.ts +3 -2
- package/dist/types/rules/html-no-aria-hidden-on-focusable.d.ts +3 -2
- package/dist/types/rules/html-no-block-inside-inline.d.ts +3 -2
- package/dist/types/rules/html-no-duplicate-attributes.d.ts +3 -2
- package/dist/types/rules/html-no-duplicate-ids.d.ts +3 -2
- package/dist/types/rules/html-no-duplicate-meta-names.d.ts +9 -0
- package/dist/types/rules/html-no-empty-attributes.d.ts +3 -2
- package/dist/types/rules/html-no-empty-headings.d.ts +3 -2
- package/dist/types/rules/html-no-nested-links.d.ts +3 -2
- package/dist/types/rules/html-no-positive-tab-index.d.ts +3 -2
- package/dist/types/rules/html-no-self-closing.d.ts +14 -5
- package/dist/types/rules/html-no-space-in-tag.d.ts +16 -0
- package/dist/types/rules/html-no-title-attribute.d.ts +3 -2
- package/dist/types/rules/html-no-underscores-in-attribute-names.d.ts +3 -2
- package/dist/types/rules/html-tag-name-lowercase.d.ts +16 -6
- package/dist/types/rules/index.d.ts +20 -2
- package/dist/types/rules/parser-no-errors.d.ts +2 -1
- package/dist/types/rules/rule-utils.d.ts +72 -25
- package/dist/types/rules/svg-tag-name-capitalization.d.ts +13 -4
- package/dist/types/rules.d.ts +2 -0
- package/dist/types/src/cli/argument-parser.d.ts +8 -2
- package/dist/types/src/cli/file-processor.d.ts +15 -0
- package/dist/types/src/cli/formatters/json-formatter.d.ts +6 -0
- package/dist/types/src/cli/formatters/simple-formatter.d.ts +1 -0
- package/dist/types/src/cli/summary-reporter.d.ts +6 -0
- package/dist/types/src/cli.d.ts +9 -4
- package/dist/types/src/custom-rule-loader.d.ts +62 -0
- package/dist/types/src/herb-disable-comment-utils.d.ts +69 -0
- package/dist/types/src/index.d.ts +1 -0
- package/dist/types/src/linter.d.ts +99 -3
- package/dist/types/src/loader.d.ts +20 -0
- package/dist/types/src/rules/erb-comment-syntax.d.ts +14 -0
- package/dist/types/src/rules/erb-no-case-node-children.d.ts +8 -0
- package/dist/types/src/rules/erb-no-empty-tags.d.ts +3 -2
- package/dist/types/src/rules/erb-no-extra-newline.d.ts +14 -0
- package/dist/types/src/rules/erb-no-extra-whitespace-inside-tags.d.ts +18 -0
- package/dist/types/src/rules/erb-no-output-control-flow.d.ts +3 -2
- package/dist/types/src/rules/erb-no-silent-tag-in-attribute-name.d.ts +3 -2
- package/dist/types/src/rules/erb-prefer-image-tag-helper.d.ts +3 -2
- package/dist/types/src/rules/erb-require-trailing-newline.d.ts +9 -0
- package/dist/types/src/rules/erb-require-whitespace-inside-tags.d.ts +16 -5
- package/dist/types/src/rules/erb-right-trim.d.ts +14 -0
- package/dist/types/src/rules/herb-disable-comment-base.d.ts +37 -0
- package/dist/types/src/rules/herb-disable-comment-malformed.d.ts +8 -0
- package/dist/types/src/rules/herb-disable-comment-missing-rules.d.ts +8 -0
- package/dist/types/src/rules/herb-disable-comment-no-duplicate-rules.d.ts +8 -0
- package/dist/types/src/rules/herb-disable-comment-no-redundant-all.d.ts +8 -0
- package/dist/types/src/rules/herb-disable-comment-unnecessary.d.ts +8 -0
- package/dist/types/src/rules/herb-disable-comment-valid-rule-name.d.ts +8 -0
- package/dist/types/src/rules/html-anchor-require-href.d.ts +3 -2
- package/dist/types/src/rules/html-aria-attribute-must-be-valid.d.ts +3 -2
- package/dist/types/src/rules/html-aria-label-is-well-formatted.d.ts +3 -2
- package/dist/types/src/rules/html-aria-level-must-be-valid.d.ts +3 -2
- package/dist/types/src/rules/html-aria-role-heading-requires-level.d.ts +3 -2
- package/dist/types/src/rules/html-aria-role-must-be-valid.d.ts +3 -2
- package/dist/types/src/rules/html-attribute-double-quotes.d.ts +13 -5
- package/dist/types/src/rules/html-attribute-equals-spacing.d.ts +12 -5
- package/dist/types/src/rules/html-attribute-values-require-quotes.d.ts +13 -5
- package/dist/types/src/rules/html-avoid-both-disabled-and-aria-disabled.d.ts +3 -2
- package/dist/types/src/rules/html-body-only-elements.d.ts +9 -0
- package/dist/types/src/rules/html-boolean-attributes-no-value.d.ts +12 -5
- package/dist/types/src/rules/html-head-only-elements.d.ts +9 -0
- package/dist/types/src/rules/html-iframe-has-title.d.ts +3 -2
- package/dist/types/src/rules/html-img-require-alt.d.ts +3 -2
- package/dist/types/src/rules/html-input-require-autocomplete.d.ts +8 -0
- package/dist/types/src/rules/html-navigation-has-label.d.ts +3 -2
- package/dist/types/src/rules/html-no-aria-hidden-on-focusable.d.ts +3 -2
- package/dist/types/src/rules/html-no-block-inside-inline.d.ts +3 -2
- package/dist/types/src/rules/html-no-duplicate-attributes.d.ts +3 -2
- package/dist/types/src/rules/html-no-duplicate-ids.d.ts +3 -2
- package/dist/types/src/rules/html-no-duplicate-meta-names.d.ts +9 -0
- package/dist/types/src/rules/html-no-empty-attributes.d.ts +3 -2
- package/dist/types/src/rules/html-no-empty-headings.d.ts +3 -2
- package/dist/types/src/rules/html-no-nested-links.d.ts +3 -2
- package/dist/types/src/rules/html-no-positive-tab-index.d.ts +3 -2
- package/dist/types/src/rules/html-no-self-closing.d.ts +14 -5
- package/dist/types/src/rules/html-no-space-in-tag.d.ts +16 -0
- package/dist/types/src/rules/html-no-title-attribute.d.ts +3 -2
- package/dist/types/src/rules/html-no-underscores-in-attribute-names.d.ts +3 -2
- package/dist/types/src/rules/html-tag-name-lowercase.d.ts +16 -6
- package/dist/types/src/rules/index.d.ts +20 -2
- package/dist/types/src/rules/parser-no-errors.d.ts +2 -1
- package/dist/types/src/rules/rule-utils.d.ts +72 -25
- package/dist/types/src/rules/svg-tag-name-capitalization.d.ts +13 -4
- package/dist/types/src/rules.d.ts +2 -0
- package/dist/types/src/types.d.ts +102 -11
- package/dist/types/types.d.ts +102 -11
- package/docs/rules/README.md +19 -3
- package/docs/rules/erb-comment-syntax.md +44 -0
- package/docs/rules/erb-no-case-node-children.md +50 -0
- package/docs/rules/erb-no-extra-newline.md +74 -0
- package/docs/rules/erb-no-extra-whitespace-inside-tags.md +39 -0
- package/docs/rules/{erb-requires-trailing-newline.md → erb-require-trailing-newline.md} +1 -1
- package/docs/rules/erb-right-trim.md +52 -0
- package/docs/rules/herb-disable-comment-malformed.md +45 -0
- package/docs/rules/herb-disable-comment-missing-rules.md +60 -0
- package/docs/rules/herb-disable-comment-no-duplicate-rules.md +49 -0
- package/docs/rules/herb-disable-comment-no-redundant-all.md +53 -0
- package/docs/rules/herb-disable-comment-unnecessary.md +44 -0
- package/docs/rules/herb-disable-comment-valid-rule-name.md +41 -0
- package/docs/rules/html-aria-attribute-must-be-valid.md +2 -5
- package/docs/rules/html-aria-label-is-well-formatted.md +1 -1
- package/docs/rules/html-attribute-double-quotes.md +2 -2
- package/docs/rules/html-attribute-equals-spacing.md +2 -2
- package/docs/rules/html-attribute-values-require-quotes.md +3 -3
- package/docs/rules/html-avoid-both-disabled-and-aria-disabled.md +2 -2
- package/docs/rules/html-body-only-elements.md +99 -0
- package/docs/rules/html-boolean-attributes-no-value.md +2 -2
- package/docs/rules/html-head-only-elements.md +81 -0
- package/docs/rules/html-input-require-autocomplete.md +64 -0
- package/docs/rules/html-no-aria-hidden-on-focusable.md +2 -2
- package/docs/rules/html-no-duplicate-attributes.md +2 -2
- package/docs/rules/html-no-duplicate-meta-names.md +64 -0
- package/docs/rules/html-no-empty-attributes.md +3 -3
- package/docs/rules/html-no-empty-headings.md +4 -26
- package/docs/rules/html-no-positive-tab-index.md +1 -2
- package/docs/rules/html-no-self-closing.md +17 -2
- package/docs/rules/html-no-space-in-tag.md +66 -0
- package/docs/rules/html-no-title-attribute.md +2 -2
- package/docs/rules/html-no-underscores-in-attribute-names.md +2 -2
- package/docs/rules/html-tag-name-lowercase.md +2 -2
- package/package.json +13 -5
- package/src/cli/argument-parser.ts +50 -39
- package/src/cli/file-processor.ts +159 -28
- package/src/cli/formatters/detailed-formatter.ts +21 -3
- package/src/cli/formatters/github-actions-formatter.ts +17 -1
- package/src/cli/formatters/json-formatter.ts +9 -0
- package/src/cli/formatters/simple-formatter.ts +24 -8
- package/src/cli/output-manager.ts +23 -3
- package/src/cli/summary-reporter.ts +40 -3
- package/src/cli.ts +137 -52
- package/src/custom-rule-loader.ts +189 -0
- package/src/herb-disable-comment-utils.ts +175 -0
- package/src/index.ts +2 -0
- package/src/linter.ts +501 -36
- package/src/loader.ts +30 -0
- package/src/rules/erb-comment-syntax.ts +73 -0
- package/src/rules/erb-no-case-node-children.ts +68 -0
- package/src/rules/erb-no-empty-tags.ts +9 -3
- package/src/rules/erb-no-extra-newline.ts +91 -0
- package/src/rules/erb-no-extra-whitespace-inside-tags.ts +147 -0
- package/src/rules/erb-no-output-control-flow.ts +9 -3
- package/src/rules/erb-no-silent-tag-in-attribute-name.ts +9 -3
- package/src/rules/erb-prefer-image-tag-helper.ts +9 -3
- package/src/rules/erb-require-trailing-newline.ts +47 -0
- package/src/rules/erb-require-whitespace-inside-tags.ts +96 -26
- package/src/rules/erb-right-trim.ts +67 -0
- package/src/rules/herb-disable-comment-base.ts +76 -0
- package/src/rules/herb-disable-comment-malformed.ts +66 -0
- package/src/rules/herb-disable-comment-missing-rules.ts +41 -0
- package/src/rules/herb-disable-comment-no-duplicate-rules.ts +46 -0
- package/src/rules/herb-disable-comment-no-redundant-all.ts +40 -0
- package/src/rules/herb-disable-comment-unnecessary.ts +103 -0
- package/src/rules/herb-disable-comment-valid-rule-name.ts +62 -0
- package/src/rules/html-anchor-require-href.ts +9 -3
- package/src/rules/html-aria-attribute-must-be-valid.ts +9 -3
- package/src/rules/html-aria-label-is-well-formatted.ts +9 -5
- package/src/rules/html-aria-level-must-be-valid.ts +9 -2
- package/src/rules/html-aria-role-heading-requires-level.ts +9 -3
- package/src/rules/html-aria-role-must-be-valid.ts +9 -3
- package/src/rules/html-attribute-double-quotes.ts +42 -8
- package/src/rules/html-attribute-equals-spacing.ts +31 -7
- package/src/rules/html-attribute-values-require-quotes.ts +56 -10
- package/src/rules/html-avoid-both-disabled-and-aria-disabled.ts +9 -3
- package/src/rules/html-body-only-elements.ts +60 -0
- package/src/rules/html-boolean-attributes-no-value.ts +31 -6
- package/src/rules/html-head-only-elements.ts +65 -0
- package/src/rules/html-iframe-has-title.ts +9 -4
- package/src/rules/html-img-require-alt.ts +10 -4
- package/src/rules/html-input-require-autocomplete.ts +85 -0
- package/src/rules/html-navigation-has-label.ts +9 -3
- package/src/rules/html-no-aria-hidden-on-focusable.ts +9 -3
- package/src/rules/html-no-block-inside-inline.ts +9 -3
- package/src/rules/html-no-duplicate-attributes.ts +9 -3
- package/src/rules/html-no-duplicate-ids.ts +11 -7
- package/src/rules/html-no-duplicate-meta-names.ts +188 -0
- package/src/rules/html-no-empty-attributes.ts +58 -10
- package/src/rules/html-no-empty-headings.ts +10 -8
- package/src/rules/html-no-nested-links.ts +10 -4
- package/src/rules/html-no-positive-tab-index.ts +9 -3
- package/src/rules/html-no-self-closing.ts +69 -9
- package/src/rules/html-no-space-in-tag.ts +221 -0
- package/src/rules/html-no-title-attribute.ts +9 -3
- package/src/rules/html-no-underscores-in-attribute-names.ts +12 -4
- package/src/rules/html-tag-name-lowercase.ts +41 -10
- package/src/rules/index.ts +24 -2
- package/src/rules/parser-no-errors.ts +8 -1
- package/src/rules/rule-utils.ts +250 -44
- package/src/rules/svg-tag-name-capitalization.ts +39 -6
- package/src/{default-rules.ts → rules.ts} +53 -13
- package/src/types.ts +133 -15
- package/dist/src/default-rules.js.map +0 -1
- package/dist/src/rules/erb-requires-trailing-newline.js +0 -22
- package/dist/src/rules/erb-requires-trailing-newline.js.map +0 -1
- package/dist/types/default-rules.d.ts +0 -2
- package/dist/types/rules/erb-requires-trailing-newline.d.ts +0 -6
- package/dist/types/src/default-rules.d.ts +0 -2
- package/dist/types/src/rules/erb-requires-trailing-newline.d.ts +0 -6
- package/src/rules/erb-requires-trailing-newline.ts +0 -29
package/dist/types/types.d.ts
CHANGED
|
@@ -1,24 +1,76 @@
|
|
|
1
1
|
import { Diagnostic, LexResult, ParseResult } from "@herb-tools/core";
|
|
2
|
-
import type {
|
|
2
|
+
import type { rules } from "./rules.js";
|
|
3
|
+
import type { Node } from "@herb-tools/core";
|
|
4
|
+
import type { RuleConfig } from "@herb-tools/config";
|
|
5
|
+
import type { Mutable } from "@herb-tools/rewriter";
|
|
6
|
+
export type { Mutable } from "@herb-tools/rewriter";
|
|
3
7
|
export type LintSeverity = "error" | "warning" | "info" | "hint";
|
|
8
|
+
export type FullRuleConfig = Required<Pick<RuleConfig, 'enabled' | 'severity'>> & Omit<RuleConfig, 'enabled' | 'severity'>;
|
|
4
9
|
/**
|
|
5
10
|
* Automatically inferred union type of all available linter rule names.
|
|
6
11
|
* This type extracts the 'name' property from each rule class instance.
|
|
7
12
|
*/
|
|
8
|
-
export type LinterRule = InstanceType<typeof
|
|
9
|
-
|
|
13
|
+
export type LinterRule = InstanceType<typeof rules[number]>['name'];
|
|
14
|
+
/**
|
|
15
|
+
* Base context for autofix operations. Contains the offending node.
|
|
16
|
+
* Rules can extend this interface to include rule-specific autofix data.
|
|
17
|
+
* Note: The node is typed as Mutable to allow direct mutation in autofix methods.
|
|
18
|
+
*/
|
|
19
|
+
export interface BaseAutofixContext {
|
|
20
|
+
/** The AST node, token, or data structure that caused the offense (mutable) */
|
|
21
|
+
node: Mutable<Node>;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* A lint offense without severity bound. Rules produce these, and the Linter
|
|
25
|
+
* binds severity based on the rule's defaultConfig and user config overrides.
|
|
26
|
+
*/
|
|
27
|
+
export interface UnboundLintOffense<TAutofixContext extends BaseAutofixContext = BaseAutofixContext> extends Omit<Diagnostic, 'severity'> {
|
|
10
28
|
rule: LinterRule;
|
|
29
|
+
/** Context data for autofix, including the offending node and rule-specific data */
|
|
30
|
+
autofixContext?: TAutofixContext;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* A lint offense with severity bound. The Linter produces these by binding
|
|
34
|
+
* severity to UnboundLintOffenses based on rule configuration.
|
|
35
|
+
*/
|
|
36
|
+
export interface LintOffense<TAutofixContext extends BaseAutofixContext = BaseAutofixContext> extends UnboundLintOffense<TAutofixContext> {
|
|
11
37
|
severity: LintSeverity;
|
|
12
38
|
}
|
|
13
|
-
export interface LintResult {
|
|
14
|
-
offenses: LintOffense[];
|
|
39
|
+
export interface LintResult<TAutofixContext extends BaseAutofixContext = BaseAutofixContext> {
|
|
40
|
+
offenses: LintOffense<TAutofixContext>[];
|
|
15
41
|
errors: number;
|
|
16
42
|
warnings: number;
|
|
43
|
+
info: number;
|
|
44
|
+
hints: number;
|
|
45
|
+
ignored: number;
|
|
46
|
+
wouldBeIgnored?: number;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Result of applying autofixes to source code
|
|
50
|
+
*/
|
|
51
|
+
export interface AutofixResult<TAutofixContext extends BaseAutofixContext = BaseAutofixContext> {
|
|
52
|
+
/** The corrected source code with all fixes applied */
|
|
53
|
+
source: string;
|
|
54
|
+
/** Offenses that were successfully fixed */
|
|
55
|
+
fixed: LintOffense<TAutofixContext>[];
|
|
56
|
+
/** Offenses that could not be automatically fixed */
|
|
57
|
+
unfixed: LintOffense<TAutofixContext>[];
|
|
17
58
|
}
|
|
18
|
-
|
|
59
|
+
/**
|
|
60
|
+
* Default configuration for rules when defaultConfig is not specified.
|
|
61
|
+
* Custom rules can omit defaultConfig and will use these defaults.
|
|
62
|
+
*/
|
|
63
|
+
export declare const DEFAULT_RULE_CONFIG: FullRuleConfig;
|
|
64
|
+
/**
|
|
65
|
+
* Base class for parser rules.
|
|
66
|
+
*/
|
|
67
|
+
export declare abstract class ParserRule<TAutofixContext extends BaseAutofixContext = BaseAutofixContext> {
|
|
19
68
|
static type: "parser";
|
|
69
|
+
/** Indicates whether this rule supports autofix. Defaults to false. */
|
|
70
|
+
static autocorrectable: boolean;
|
|
20
71
|
abstract name: string;
|
|
21
|
-
|
|
72
|
+
get defaultConfig(): FullRuleConfig;
|
|
73
|
+
abstract check(result: ParseResult, context?: Partial<LintContext>): UnboundLintOffense<TAutofixContext>[];
|
|
22
74
|
/**
|
|
23
75
|
* Optional method to determine if this rule should run.
|
|
24
76
|
* If not implemented, rule is always enabled.
|
|
@@ -27,11 +79,26 @@ export declare abstract class ParserRule {
|
|
|
27
79
|
* @returns true if rule should run, false to skip
|
|
28
80
|
*/
|
|
29
81
|
isEnabled?(result: ParseResult, context?: Partial<LintContext>): boolean;
|
|
82
|
+
/**
|
|
83
|
+
* Optional method to automatically fix an offense by mutating the AST.
|
|
84
|
+
* If not implemented, the rule does not support autofix.
|
|
85
|
+
* @param offense - The offense to fix (includes autofixContext with node and rule-specific data)
|
|
86
|
+
* @param result - The parse result containing the AST (mutate it directly and return it)
|
|
87
|
+
* @param context - Optional context for linting
|
|
88
|
+
* @returns The mutated ParseResult if fixed, or null if the offense could not be fixed
|
|
89
|
+
*/
|
|
90
|
+
autofix?(offense: LintOffense<TAutofixContext>, result: ParseResult, context?: Partial<LintContext>): ParseResult | null;
|
|
30
91
|
}
|
|
31
|
-
|
|
92
|
+
/**
|
|
93
|
+
* Base class for lexer rules.
|
|
94
|
+
*/
|
|
95
|
+
export declare abstract class LexerRule<TAutofixContext extends BaseAutofixContext = BaseAutofixContext> {
|
|
32
96
|
static type: "lexer";
|
|
97
|
+
/** Indicates whether this rule supports autofix. Defaults to false. */
|
|
98
|
+
static autocorrectable: boolean;
|
|
33
99
|
abstract name: string;
|
|
34
|
-
|
|
100
|
+
get defaultConfig(): FullRuleConfig;
|
|
101
|
+
abstract check(lexResult: LexResult, context?: Partial<LintContext>): UnboundLintOffense<TAutofixContext>[];
|
|
35
102
|
/**
|
|
36
103
|
* Optional method to determine if this rule should run.
|
|
37
104
|
* If not implemented, rule is always enabled.
|
|
@@ -40,6 +107,15 @@ export declare abstract class LexerRule {
|
|
|
40
107
|
* @returns true if rule should run, false to skip
|
|
41
108
|
*/
|
|
42
109
|
isEnabled?(lexResult: LexResult, context?: Partial<LintContext>): boolean;
|
|
110
|
+
/**
|
|
111
|
+
* Optional method to automatically fix an offense by mutating tokens.
|
|
112
|
+
* If not implemented, the rule does not support autofix.
|
|
113
|
+
* @param offense - The offense to fix (includes autofixContext with node and rule-specific data)
|
|
114
|
+
* @param lexResult - The lex result containing tokens (mutate them directly and return)
|
|
115
|
+
* @param context - Optional context for linting
|
|
116
|
+
* @returns The mutated LexResult if fixed, or null if the offense could not be fixed
|
|
117
|
+
*/
|
|
118
|
+
autofix?(offense: LintOffense<TAutofixContext>, lexResult: LexResult, context?: Partial<LintContext>): LexResult | null;
|
|
43
119
|
}
|
|
44
120
|
export interface LexerRuleConstructor {
|
|
45
121
|
type: "lexer";
|
|
@@ -51,15 +127,21 @@ export interface LexerRuleConstructor {
|
|
|
51
127
|
*/
|
|
52
128
|
export interface LintContext {
|
|
53
129
|
fileName: string | undefined;
|
|
130
|
+
validRuleNames: string[] | undefined;
|
|
131
|
+
ignoredOffensesByLine: Map<number, Set<string>> | undefined;
|
|
132
|
+
ignoreDisableComments: boolean | undefined;
|
|
54
133
|
}
|
|
55
134
|
/**
|
|
56
135
|
* Default context object with all keys defined but set to undefined
|
|
57
136
|
*/
|
|
58
137
|
export declare const DEFAULT_LINT_CONTEXT: LintContext;
|
|
59
|
-
export declare abstract class SourceRule {
|
|
138
|
+
export declare abstract class SourceRule<TAutofixContext extends BaseAutofixContext = BaseAutofixContext> {
|
|
60
139
|
static type: "source";
|
|
140
|
+
/** Indicates whether this rule supports autofix. Defaults to false. */
|
|
141
|
+
static autocorrectable: boolean;
|
|
61
142
|
abstract name: string;
|
|
62
|
-
|
|
143
|
+
get defaultConfig(): FullRuleConfig;
|
|
144
|
+
abstract check(source: string, context?: Partial<LintContext>): UnboundLintOffense<TAutofixContext>[];
|
|
63
145
|
/**
|
|
64
146
|
* Optional method to determine if this rule should run.
|
|
65
147
|
* If not implemented, rule is always enabled.
|
|
@@ -68,6 +150,15 @@ export declare abstract class SourceRule {
|
|
|
68
150
|
* @returns true if rule should run, false to skip
|
|
69
151
|
*/
|
|
70
152
|
isEnabled?(source: string, context?: Partial<LintContext>): boolean;
|
|
153
|
+
/**
|
|
154
|
+
* Optional method to automatically fix an offense.
|
|
155
|
+
* If not implemented, the rule does not support autofix.
|
|
156
|
+
* @param offense - The offense to fix (includes autofixContext with node and rule-specific data)
|
|
157
|
+
* @param source - The original source code
|
|
158
|
+
* @param context - Optional context for linting
|
|
159
|
+
* @returns The corrected source if the offense can be fixed, null otherwise
|
|
160
|
+
*/
|
|
161
|
+
autofix?(offense: LintOffense<TAutofixContext>, source: string, context?: Partial<LintContext>): string | null;
|
|
71
162
|
}
|
|
72
163
|
export interface SourceRuleConstructor {
|
|
73
164
|
type: "source";
|
package/docs/rules/README.md
CHANGED
|
@@ -4,12 +4,23 @@ This page contains documentation for all Herb Linter rules.
|
|
|
4
4
|
|
|
5
5
|
## Available Rules
|
|
6
6
|
|
|
7
|
+
- [`erb-comment-syntax`](./erb-comment-syntax.md) - Disallow Ruby comments immediately after ERB tags
|
|
8
|
+
- [`erb-no-case-node-children`](./erb-no-case-node-children.md) - Don't use `children` for `case/when` and `case/in` nodes
|
|
7
9
|
- [`erb-no-empty-tags`](./erb-no-empty-tags.md) - Disallow empty ERB tags
|
|
10
|
+
- [`erb-no-extra-newline`](./erb-no-extra-newline.md) - Disallow extra newlines.
|
|
11
|
+
- [`erb-no-extra-whitespace-inside-tags`](./erb-no-extra-whitespace-inside-tags.md) - Disallow multiple consecutive spaces inside ERB tags
|
|
8
12
|
- [`erb-no-output-control-flow`](./erb-no-output-control-flow.md) - Prevents outputting control flow blocks
|
|
9
13
|
- [`erb-no-silent-tag-in-attribute-name`](./erb-no-silent-tag-in-attribute-name.md) - Disallow ERB silent tags in HTML attribute names
|
|
10
14
|
- [`erb-prefer-image-tag-helper`](./erb-prefer-image-tag-helper.md) - Prefer `image_tag` helper over `<img>` with ERB expressions
|
|
11
15
|
- [`erb-require-whitespace-inside-tags`](./erb-require-whitespace-inside-tags.md) - Requires whitespace around ERB tags
|
|
12
|
-
- [`erb-
|
|
16
|
+
- [`erb-require-trailing-newline`](./erb-require-trailing-newline.md) - Enforces that all HTML+ERB template files end with exactly one trailing newline character.
|
|
17
|
+
- [`erb-right-trim`](./erb-right-trim.md) - Enforce consistent right-trimming syntax.
|
|
18
|
+
- [`herb-disable-comment-malformed`](./herb-disable-comment-malformed.md) - Detect malformed `herb:disable` comments.
|
|
19
|
+
- [`herb-disable-comment-missing-rules`](./herb-disable-comment-missing-rules.md) - Require rule names in `herb:disable` comments.
|
|
20
|
+
- [`herb-disable-comment-no-duplicate-rules`](./herb-disable-comment-no-duplicate-rules.md) - Disallow duplicate rule names in `herb:disable` comments.
|
|
21
|
+
- [`herb-disable-comment-no-redundant-all`](./herb-disable-comment-no-redundant-all.md) - Disallow redundant use of `all` in `herb:disable` comments.
|
|
22
|
+
- [`herb-disable-comment-unnecessary`](./herb-disable-comment-unnecessary.md) - Detect unnecessary `herb:disable` comments.
|
|
23
|
+
- [`herb-disable-comment-valid-rule-name`](./herb-disable-comment-valid-rule-name.md) - Validate rule names in `herb:disable` comments.
|
|
13
24
|
- [`html-anchor-require-href`](./html-anchor-require-href.md) - Requires an href attribute on anchor tags
|
|
14
25
|
- [`html-aria-attribute-must-be-valid`](./html-aria-attribute-must-be-valid.md) - Disallow invalid or unknown `aria-*` attributes.
|
|
15
26
|
- [`html-aria-label-is-well-formatted`](./html-aria-label-is-well-formatted.md) - `aria-label` must be well-formatted
|
|
@@ -20,21 +31,26 @@ This page contains documentation for all Herb Linter rules.
|
|
|
20
31
|
- [`html-attribute-equals-spacing`](./html-attribute-equals-spacing.md) - No whitespace around `=` in HTML attributes
|
|
21
32
|
- [`html-attribute-values-require-quotes`](./html-attribute-values-require-quotes.md) - Requires quotes around attribute values
|
|
22
33
|
- [`html-avoid-both-disabled-and-aria-disabled`](./html-avoid-both-disabled-and-aria-disabled.md) - Avoid using both `disabled` and `aria-disabled` attributes
|
|
34
|
+
- [`html-body-only-elements`](./html-body-only-elements.md) - Require content elements inside `<body>`.
|
|
23
35
|
- [`html-boolean-attributes-no-value`](./html-boolean-attributes-no-value.md) - Prevents values on boolean attributes
|
|
36
|
+
- [`html-head-only-elements`](./html-head-only-elements.md) - Require head-scoped elements inside `<head>`.
|
|
24
37
|
- [`html-iframe-has-title`](./html-iframe-has-title.md) - `iframe` elements must have a `title` attribute
|
|
38
|
+
- [`html-input-require-autocomplete`](./html-input-require-autocomplete.md) - Require `autocomplete` attributes on `<input>` tags.
|
|
25
39
|
- [`html-img-require-alt`](./html-img-require-alt.md) - Requires `alt` attributes on `<img>` tags
|
|
26
40
|
- [`html-navigation-has-label`](./html-navigation-has-label.md) - Navigation landmarks must have accessible labels
|
|
27
41
|
- [`html-no-aria-hidden-on-focusable`](./html-no-aria-hidden-on-focusable.md) - Focusable elements should not have `aria-hidden="true"`
|
|
28
42
|
- [`html-no-block-inside-inline`](./html-no-block-inside-inline.md) - Prevents block-level elements inside inline elements
|
|
29
43
|
- [`html-no-duplicate-attributes`](./html-no-duplicate-attributes.md) - Prevents duplicate attributes on HTML elements
|
|
30
44
|
- [`html-no-duplicate-ids`](./html-no-duplicate-ids.md) - Prevents duplicate IDs within a document
|
|
45
|
+
- [`html-no-duplicate-meta-names`](./html-no-duplicate-meta-names.md) - Duplicate `<meta>` name attributes are not allowed.
|
|
31
46
|
- [`html-no-empty-attributes`](./html-no-empty-attributes.md) - Attributes must not have empty values
|
|
32
47
|
- [`html-no-nested-links`](./html-no-nested-links.md) - Prevents nested anchor tags
|
|
33
48
|
- [`html-no-positive-tab-index`](./html-no-positive-tab-index.md) - Avoid positive `tabindex` values
|
|
34
|
-
- [`html-no-self-closing`](./html-no-self-closing.md
|
|
49
|
+
- [`html-no-self-closing`](./html-no-self-closing.md) - Disallow self closing tags
|
|
50
|
+
- [`html-no-space-in-tag`](./html-no-space-in-tag.md) - Disallow spaces in HTML tags
|
|
35
51
|
- [`html-no-title-attribute`](./html-no-title-attribute.md) - Avoid using the `title` attribute
|
|
36
|
-
- [`html-tag-name-lowercase`](./html-tag-name-lowercase.md) - Enforces lowercase tag names in HTML
|
|
37
52
|
- [`html-no-underscores-in-attribute-names`](./html-no-underscores-in-attribute-names.md) - Disallow underscores in HTML attribute names
|
|
53
|
+
- [`html-tag-name-lowercase`](./html-tag-name-lowercase.md) - Enforces lowercase tag names in HTML
|
|
38
54
|
- [`parser-no-errors`](./parser-no-errors.md) - Disallow parser errors in HTML+ERB documents
|
|
39
55
|
- [`svg-tag-name-capitalization`](./svg-tag-name-capitalization.md) - Enforces proper camelCase capitalization for SVG elements
|
|
40
56
|
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# Linter Rule: Disallow Ruby comments immediately after ERB tags
|
|
2
|
+
|
|
3
|
+
**Rule:** `erb-comment-syntax`
|
|
4
|
+
|
|
5
|
+
## Description
|
|
6
|
+
|
|
7
|
+
Disallow ERB tags that start with `<% #` (with a space before the `#`). Use the ERB comment syntax `<%#` instead.
|
|
8
|
+
|
|
9
|
+
## Rationale
|
|
10
|
+
|
|
11
|
+
Ruby comments starting immediately after an ERB tag opening (e.g., `<% # comment %>`) can cause parsing issues in some contexts. The proper ERB comment syntax `<%# comment %>` is more reliable and explicitly designed for comments in templates.
|
|
12
|
+
|
|
13
|
+
For multi-line comments or actual Ruby code with comments, ensure the content starts on a new line after the opening tag.
|
|
14
|
+
|
|
15
|
+
## Examples
|
|
16
|
+
|
|
17
|
+
### ✅ Good
|
|
18
|
+
|
|
19
|
+
```erb
|
|
20
|
+
<%# This is a proper ERB comment %>
|
|
21
|
+
|
|
22
|
+
<%
|
|
23
|
+
# This is a proper ERB comment
|
|
24
|
+
%>
|
|
25
|
+
|
|
26
|
+
<%
|
|
27
|
+
# Multi-line Ruby comment
|
|
28
|
+
# spanning multiple lines
|
|
29
|
+
%>
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### 🚫 Bad
|
|
33
|
+
|
|
34
|
+
```erb
|
|
35
|
+
<% # This should be an ERB comment %>
|
|
36
|
+
|
|
37
|
+
<%= # This should also be an ERB comment %>
|
|
38
|
+
|
|
39
|
+
<%== # This should also be an ERB comment %>
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## References
|
|
43
|
+
|
|
44
|
+
- [Inspiration: ERB Lint `CommentSyntax` rule](https://github.com/shopify/erb_lint?tab=readme-ov-file#commentsyntax)
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# Linter Rule: Don't use `children` for `case/when` and `case/in` nodes
|
|
2
|
+
|
|
3
|
+
**Rule:** `erb-no-case-node-children`
|
|
4
|
+
|
|
5
|
+
## Description
|
|
6
|
+
|
|
7
|
+
Disallow placing content or expressions directly between the opening `<% case %>` and the first `<% when %>` or `<% in %>` clause in an HTML+ERB template.
|
|
8
|
+
|
|
9
|
+
In Ruby and ERB, `case` expressions are intended to branch execution. Any content placed between the `case` and its `when`/`in` clauses is not executed as part of the branching logic, and may lead to confusion, orphaned output, or silent bugs.
|
|
10
|
+
|
|
11
|
+
## Rationale
|
|
12
|
+
|
|
13
|
+
Including content directly inside a `case block` is likely unintended and often leads to unclear or broken rendering logic.
|
|
14
|
+
|
|
15
|
+
Most developers expect that nothing happens until the first `when`/`in` matches. Content in that location is often a copy/paste or indentation mistake and should be flagged to maintain clarity and correctness in templates.
|
|
16
|
+
|
|
17
|
+
This mirrors how `case` works in Ruby itself and helps avoid surprising output.
|
|
18
|
+
|
|
19
|
+
## Examples
|
|
20
|
+
|
|
21
|
+
### ✅ Good
|
|
22
|
+
|
|
23
|
+
```erb
|
|
24
|
+
<% case variable %>
|
|
25
|
+
<% when "a" %>
|
|
26
|
+
A
|
|
27
|
+
<% when "b" %>
|
|
28
|
+
B
|
|
29
|
+
<% else %>
|
|
30
|
+
C
|
|
31
|
+
<% end %>
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### 🚫 Bad
|
|
35
|
+
|
|
36
|
+
```erb
|
|
37
|
+
<% case variable %>
|
|
38
|
+
This content is outside of any when/in/else block!
|
|
39
|
+
<% when "a" %>
|
|
40
|
+
A
|
|
41
|
+
<% when "b" %>
|
|
42
|
+
B
|
|
43
|
+
<% else %>
|
|
44
|
+
C
|
|
45
|
+
<% end %>
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## References
|
|
49
|
+
|
|
50
|
+
\-
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# Linter Rule: Disallow extra newlines
|
|
2
|
+
|
|
3
|
+
**Rule:** `erb-no-extra-newline`
|
|
4
|
+
|
|
5
|
+
## Description
|
|
6
|
+
|
|
7
|
+
Disallow more than two consecutive blank lines in ERB templates. This rule enforces a maximum of two blank lines between content to maintain consistent vertical spacing throughout your templates.
|
|
8
|
+
|
|
9
|
+
## Rationale
|
|
10
|
+
|
|
11
|
+
Excessive blank lines can make templates harder to read and maintain. While some vertical spacing improves readability by visually separating logical sections, too many blank lines create unnecessary whitespace that:
|
|
12
|
+
|
|
13
|
+
* Makes it harder to see related code on the same screen
|
|
14
|
+
* Creates inconsistent visual rhythm in the codebase
|
|
15
|
+
* Can accidentally accumulate through merge conflicts or refactoring
|
|
16
|
+
* Provides no additional clarity beyond what 1-2 blank lines already achieve
|
|
17
|
+
|
|
18
|
+
Limiting to two consecutive blank lines strikes a balance between allowing clear section separation while maintaining code density and readability.
|
|
19
|
+
|
|
20
|
+
## Examples
|
|
21
|
+
|
|
22
|
+
### ✅ Good
|
|
23
|
+
|
|
24
|
+
```html
|
|
25
|
+
line 1
|
|
26
|
+
|
|
27
|
+
line 3
|
|
28
|
+
|
|
29
|
+
<div>
|
|
30
|
+
<h1>Title</h1>
|
|
31
|
+
</div>
|
|
32
|
+
|
|
33
|
+
<div>
|
|
34
|
+
<h1>Section 1</h1>
|
|
35
|
+
|
|
36
|
+
<p>Content here</p>
|
|
37
|
+
</div>
|
|
38
|
+
|
|
39
|
+
<div>
|
|
40
|
+
<h1>Section 1</h1>
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
<h1>Section 2</h1>
|
|
44
|
+
</div>
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### 🚫 Bad
|
|
48
|
+
|
|
49
|
+
```erb
|
|
50
|
+
line 1
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
line 3
|
|
55
|
+
|
|
56
|
+
<div>
|
|
57
|
+
<h1>Title</h1>
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
<p>Content</p>
|
|
62
|
+
</div>
|
|
63
|
+
|
|
64
|
+
<%= user.name %>
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
<%= user.email %>
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## References
|
|
73
|
+
|
|
74
|
+
- [Inspiration: ERB Lint `ExtraNewline` rule](https://github.com/Shopify/erb_lint/blob/main/README.md)
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# Linter Rule: Avoid extra whitespace inside ERB tags
|
|
2
|
+
|
|
3
|
+
**Rule:** `erb-no-extra-whitespace-inside-tags`
|
|
4
|
+
|
|
5
|
+
## Description
|
|
6
|
+
|
|
7
|
+
This rule disallows **multiple consecutive spaces** immediately inside ERB tags (`<%`, `<%=`) or before the closing delimiter (`%>`). It ensures that ERB code is consistently and cleanly formatted, with exactly one space after the opening tag and one space before the closing tag (when appropriate).
|
|
8
|
+
|
|
9
|
+
## Rationale
|
|
10
|
+
|
|
11
|
+
Excess whitespace inside ERB tags can lead to inconsistent formatting and untidy templates. By enforcing a consistent amount of whitespace inside ERB tags, this rule improves code readability, aligns with the formatter and style guide expectations, and avoids unnecessary visual noise.
|
|
12
|
+
|
|
13
|
+
## Examples
|
|
14
|
+
|
|
15
|
+
### ✅ Good
|
|
16
|
+
|
|
17
|
+
```erb
|
|
18
|
+
<%= output %>
|
|
19
|
+
|
|
20
|
+
<% if condition %>
|
|
21
|
+
True
|
|
22
|
+
<% end %>
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
### 🚫 Bad
|
|
26
|
+
|
|
27
|
+
```erb
|
|
28
|
+
<%= output %>
|
|
29
|
+
|
|
30
|
+
<%= output %>
|
|
31
|
+
|
|
32
|
+
<% if condition %>
|
|
33
|
+
True
|
|
34
|
+
<% end %>
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## References
|
|
38
|
+
|
|
39
|
+
\-
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# Linter Rule: Enforce consistent right-trimming syntax
|
|
2
|
+
|
|
3
|
+
**Rule:** `erb-right-trim`
|
|
4
|
+
|
|
5
|
+
## Description
|
|
6
|
+
|
|
7
|
+
This rule enforces the use of `-%>` for right-trimming ERB output tags (like `<%= %>`) instead of `=%>`.
|
|
8
|
+
|
|
9
|
+
## Rationale
|
|
10
|
+
|
|
11
|
+
While `=%>` can be used for right-trimming whitespace in some ERB engines (like Erubi), it is an obscure and not well-defined syntax that lacks consistent support across most ERB implementations.
|
|
12
|
+
|
|
13
|
+
The `-%>` syntax is the standard, well-documented approach for right-trimming that is universally supported and consistent with left-trimming syntax (`<%-`). Using `-%>` ensures compatibility across different ERB engines, improves code clarity, and aligns with established Rails and ERB conventions.
|
|
14
|
+
|
|
15
|
+
## Examples
|
|
16
|
+
|
|
17
|
+
### ✅ Good
|
|
18
|
+
|
|
19
|
+
```erb
|
|
20
|
+
<%= title -%>
|
|
21
|
+
|
|
22
|
+
<% if condition? %>
|
|
23
|
+
<h1>Content</h1>
|
|
24
|
+
<% end %>
|
|
25
|
+
|
|
26
|
+
<% items.each do |item| %>
|
|
27
|
+
<li><%= item -%></li>
|
|
28
|
+
<% end %>
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### 🚫 Bad
|
|
32
|
+
|
|
33
|
+
```erb
|
|
34
|
+
<%= title =%>
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
<% title =%>
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
<% if true =%>
|
|
41
|
+
<h1>Content</h1>
|
|
42
|
+
<% end %>
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
<% items.each do |item| =%>
|
|
46
|
+
<li><%= item %></li>
|
|
47
|
+
<% end %>
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## References
|
|
51
|
+
|
|
52
|
+
- [Inspiration: ERB Lint `RightTrim` rule](https://github.com/Shopify/erb_lint/blob/main/README.md#righttrim)
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# Linter Rule: Detect malformed `herb:disable` comments
|
|
2
|
+
|
|
3
|
+
**Rule:** `herb-disable-comment-malformed`
|
|
4
|
+
|
|
5
|
+
## Description
|
|
6
|
+
|
|
7
|
+
Detects malformed `<%# herb:disable ... %>` comments that have syntax errors like trailing commas, leading commas, consecutive commas, or missing spaces after `herb:disable`.
|
|
8
|
+
|
|
9
|
+
## Rationale
|
|
10
|
+
|
|
11
|
+
Malformed `<%# herb:disable ... %>` comments can fail to parse correctly, leading to unexpected behavior where rules aren't actually disabled. This rule catches common syntax errors to ensure your disable comments work as intended.
|
|
12
|
+
|
|
13
|
+
## Examples
|
|
14
|
+
|
|
15
|
+
### ✅ Good
|
|
16
|
+
|
|
17
|
+
```erb
|
|
18
|
+
<DIV>test</DIV> <%# herb:disable html-tag-name-lowercase %>
|
|
19
|
+
|
|
20
|
+
<DIV class='value'>test</DIV> <%# herb:disable html-tag-name-lowercase, html-attribute-double-quotes %>
|
|
21
|
+
|
|
22
|
+
<DIV class='value'>test</DIV> <%# herb:disable html-tag-name-lowercase , html-attribute-double-quotes %>
|
|
23
|
+
|
|
24
|
+
<DIV>test</DIV> <%# herb:disable all %>
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
### 🚫 Bad
|
|
28
|
+
|
|
29
|
+
```erb
|
|
30
|
+
<div>test</div> <%# herb:disable html-tag-name-lowercase, %>
|
|
31
|
+
|
|
32
|
+
<div>test</div> <%# herb:disable , html-tag-name-lowercase %>
|
|
33
|
+
|
|
34
|
+
<div>test</div> <%# herb:disable html-tag-name-lowercase,, html-attribute-double-quotes %>
|
|
35
|
+
|
|
36
|
+
<div>test</div> <%# herb:disable html-tag-name-lowercase,, %>
|
|
37
|
+
|
|
38
|
+
<DIV>test</DIV> <%# herb:disableall %>
|
|
39
|
+
|
|
40
|
+
<DIV>test</DIV> <%# herb:disablehtml-tag-name-lowercase %>
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## References
|
|
44
|
+
|
|
45
|
+
\-
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# Linter Rule: Require rule names in `herb:disable` comments
|
|
2
|
+
|
|
3
|
+
**Rule:** `herb-disable-comment-missing-rules`
|
|
4
|
+
|
|
5
|
+
## Description
|
|
6
|
+
|
|
7
|
+
Requires that `<%# herb:disable %>` comments specify either `all` or at least one specific rule name.
|
|
8
|
+
|
|
9
|
+
## Rationale
|
|
10
|
+
|
|
11
|
+
A `<%# herb:disable %>` comment without any rule names serves no purpose and likely indicates an incomplete edit or mistake. The developer either:
|
|
12
|
+
|
|
13
|
+
- Forgot to specify which rules to disable
|
|
14
|
+
- Intended to use `herb:disable all` but forgot to add `all`
|
|
15
|
+
- Started typing a comment but didn't finish
|
|
16
|
+
|
|
17
|
+
This rule ensures all `<%# herb:disable %>` comments are complete and functional.
|
|
18
|
+
|
|
19
|
+
## Examples
|
|
20
|
+
|
|
21
|
+
### ✅ Good
|
|
22
|
+
|
|
23
|
+
```erb
|
|
24
|
+
<DIV class='value'>test</DIV> <%# herb:disable all %>
|
|
25
|
+
|
|
26
|
+
<DIV>test</DIV> <%# herb:disable html-tag-name-lowercase %>
|
|
27
|
+
|
|
28
|
+
<DIV class='value'>test</DIV> <%# herb:disable html-tag-name-lowercase, html-attribute-double-quotes %>
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### 🚫 Bad
|
|
32
|
+
|
|
33
|
+
```erb
|
|
34
|
+
<div>test</div> <%# herb:disable %>
|
|
35
|
+
|
|
36
|
+
<div>test</div> <%# herb:disable %>
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Fix
|
|
40
|
+
|
|
41
|
+
Add either `all` or specific rule names:
|
|
42
|
+
|
|
43
|
+
**Option 1:** Disable all rules
|
|
44
|
+
```erb
|
|
45
|
+
<DIV>test</DIV> <%# herb:disable all %>
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
**Option 2:** Disable specific rules
|
|
49
|
+
```erb
|
|
50
|
+
<DIV>test</DIV> <%# herb:disable html-tag-name-lowercase %>
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
**Option 3:** Remove the comment if it's not needed
|
|
54
|
+
```erb
|
|
55
|
+
<div>test</div>
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## References
|
|
59
|
+
|
|
60
|
+
\-
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# Linter Rule: Disallow duplicate rule names in `herb:disable` comments
|
|
2
|
+
|
|
3
|
+
**Rule:** `herb-disable-comment-no-duplicate-rules`
|
|
4
|
+
|
|
5
|
+
## Description
|
|
6
|
+
|
|
7
|
+
Prevents listing the same rule name multiple times in a `<%# herb:disable ... %>` comment.
|
|
8
|
+
|
|
9
|
+
## Rationale
|
|
10
|
+
|
|
11
|
+
Listing a rule name more than once in a `<%# herb:disable ... %>` comment is unnecessary and likely indicates a copy-paste error or mistake. Each rule only needs to be mentioned once to be disabled.
|
|
12
|
+
|
|
13
|
+
This rule helps keep disable comments clean and prevents confusion about which rules are being disabled.
|
|
14
|
+
|
|
15
|
+
## Examples
|
|
16
|
+
|
|
17
|
+
### ✅ Good
|
|
18
|
+
|
|
19
|
+
```erb
|
|
20
|
+
<DIV class='value'>test</DIV> <%# herb:disable html-tag-name-lowercase, html-attribute-double-quotes %>
|
|
21
|
+
|
|
22
|
+
<DIV>test</DIV> <%# herb:disable html-tag-name-lowercase %>
|
|
23
|
+
|
|
24
|
+
<DIV>test</DIV> <%# herb:disable all %>
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
### 🚫 Bad
|
|
28
|
+
|
|
29
|
+
```erb
|
|
30
|
+
<DIV>test</DIV> <%# herb:disable html-tag-name-lowercase, html-tag-name-lowercase %>
|
|
31
|
+
|
|
32
|
+
<DIV class='value'>test</DIV> <%# herb:disable html-attribute-double-quotes, html-tag-name-lowercase, html-tag-name-lowercase %>
|
|
33
|
+
|
|
34
|
+
<DIV class='value'>test</DIV> <%# herb:disable html-tag-name-lowercase, html-tag-name-lowercase, html-attribute-double-quotes, html-attribute-double-quotes %>
|
|
35
|
+
|
|
36
|
+
<DIV>test</DIV> <%# herb:disable all, all %>
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Fix
|
|
40
|
+
|
|
41
|
+
Remove the duplicate rule names, keeping only one instance of each:
|
|
42
|
+
|
|
43
|
+
```erb
|
|
44
|
+
<DIV class='value'>test</DIV> <%# herb:disable html-tag-name-lowercase, html-attribute-double-quotes %>
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## References
|
|
48
|
+
|
|
49
|
+
\-
|