@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.
Files changed (395) hide show
  1. package/README.md +253 -13
  2. package/dist/herb-lint.js +26087 -3414
  3. package/dist/herb-lint.js.map +1 -1
  4. package/dist/index.cjs +5783 -1568
  5. package/dist/index.cjs.map +1 -1
  6. package/dist/index.js +5749 -1569
  7. package/dist/index.js.map +1 -1
  8. package/dist/loader.cjs +17010 -0
  9. package/dist/loader.cjs.map +1 -0
  10. package/dist/loader.js +16879 -0
  11. package/dist/loader.js.map +1 -0
  12. package/dist/package.json +13 -5
  13. package/dist/src/cli/argument-parser.js +42 -35
  14. package/dist/src/cli/argument-parser.js.map +1 -1
  15. package/dist/src/cli/file-processor.js +124 -23
  16. package/dist/src/cli/file-processor.js.map +1 -1
  17. package/dist/src/cli/formatters/detailed-formatter.js +18 -3
  18. package/dist/src/cli/formatters/detailed-formatter.js.map +1 -1
  19. package/dist/src/cli/formatters/github-actions-formatter.js +15 -1
  20. package/dist/src/cli/formatters/github-actions-formatter.js.map +1 -1
  21. package/dist/src/cli/formatters/json-formatter.js +3 -0
  22. package/dist/src/cli/formatters/json-formatter.js.map +1 -1
  23. package/dist/src/cli/formatters/simple-formatter.js +20 -7
  24. package/dist/src/cli/formatters/simple-formatter.js.map +1 -1
  25. package/dist/src/cli/output-manager.js +22 -3
  26. package/dist/src/cli/output-manager.js.map +1 -1
  27. package/dist/src/cli/summary-reporter.js +26 -3
  28. package/dist/src/cli/summary-reporter.js.map +1 -1
  29. package/dist/src/cli.js +109 -43
  30. package/dist/src/cli.js.map +1 -1
  31. package/dist/src/custom-rule-loader.js +139 -0
  32. package/dist/src/custom-rule-loader.js.map +1 -0
  33. package/dist/src/herb-disable-comment-utils.js +129 -0
  34. package/dist/src/herb-disable-comment-utils.js.map +1 -0
  35. package/dist/src/index.js +1 -0
  36. package/dist/src/index.js.map +1 -1
  37. package/dist/src/linter.js +369 -34
  38. package/dist/src/linter.js.map +1 -1
  39. package/dist/src/loader.js +17 -0
  40. package/dist/src/loader.js.map +1 -0
  41. package/dist/src/rules/erb-comment-syntax.js +48 -0
  42. package/dist/src/rules/erb-comment-syntax.js.map +1 -0
  43. package/dist/src/rules/erb-no-case-node-children.js +52 -0
  44. package/dist/src/rules/erb-no-case-node-children.js.map +1 -0
  45. package/dist/src/rules/erb-no-empty-tags.js +7 -1
  46. package/dist/src/rules/erb-no-empty-tags.js.map +1 -1
  47. package/dist/src/rules/erb-no-extra-newline.js +65 -0
  48. package/dist/src/rules/erb-no-extra-newline.js.map +1 -0
  49. package/dist/src/rules/erb-no-extra-whitespace-inside-tags.js +95 -0
  50. package/dist/src/rules/erb-no-extra-whitespace-inside-tags.js.map +1 -0
  51. package/dist/src/rules/erb-no-output-control-flow.js +7 -1
  52. package/dist/src/rules/erb-no-output-control-flow.js.map +1 -1
  53. package/dist/src/rules/erb-no-silent-tag-in-attribute-name.js +7 -1
  54. package/dist/src/rules/erb-no-silent-tag-in-attribute-name.js.map +1 -1
  55. package/dist/src/rules/erb-prefer-image-tag-helper.js +7 -1
  56. package/dist/src/rules/erb-prefer-image-tag-helper.js.map +1 -1
  57. package/dist/src/rules/erb-require-trailing-newline.js +35 -0
  58. package/dist/src/rules/erb-require-trailing-newline.js.map +1 -0
  59. package/dist/src/rules/erb-require-whitespace-inside-tags.js +70 -20
  60. package/dist/src/rules/erb-require-whitespace-inside-tags.js.map +1 -1
  61. package/dist/src/rules/erb-right-trim.js +45 -0
  62. package/dist/src/rules/erb-right-trim.js.map +1 -0
  63. package/dist/src/rules/herb-disable-comment-base.js +51 -0
  64. package/dist/src/rules/herb-disable-comment-base.js.map +1 -0
  65. package/dist/src/rules/herb-disable-comment-malformed.js +51 -0
  66. package/dist/src/rules/herb-disable-comment-malformed.js.map +1 -0
  67. package/dist/src/rules/herb-disable-comment-missing-rules.js +29 -0
  68. package/dist/src/rules/herb-disable-comment-missing-rules.js.map +1 -0
  69. package/dist/src/rules/herb-disable-comment-no-duplicate-rules.js +32 -0
  70. package/dist/src/rules/herb-disable-comment-no-duplicate-rules.js.map +1 -0
  71. package/dist/src/rules/herb-disable-comment-no-redundant-all.js +31 -0
  72. package/dist/src/rules/herb-disable-comment-no-redundant-all.js.map +1 -0
  73. package/dist/src/rules/herb-disable-comment-unnecessary.js +65 -0
  74. package/dist/src/rules/herb-disable-comment-unnecessary.js.map +1 -0
  75. package/dist/src/rules/herb-disable-comment-valid-rule-name.js +44 -0
  76. package/dist/src/rules/herb-disable-comment-valid-rule-name.js.map +1 -0
  77. package/dist/src/rules/html-anchor-require-href.js +7 -1
  78. package/dist/src/rules/html-anchor-require-href.js.map +1 -1
  79. package/dist/src/rules/html-aria-attribute-must-be-valid.js +7 -1
  80. package/dist/src/rules/html-aria-attribute-must-be-valid.js.map +1 -1
  81. package/dist/src/rules/html-aria-label-is-well-formatted.js +9 -3
  82. package/dist/src/rules/html-aria-label-is-well-formatted.js.map +1 -1
  83. package/dist/src/rules/html-aria-level-must-be-valid.js +6 -0
  84. package/dist/src/rules/html-aria-level-must-be-valid.js.map +1 -1
  85. package/dist/src/rules/html-aria-role-heading-requires-level.js +7 -1
  86. package/dist/src/rules/html-aria-role-heading-requires-level.js.map +1 -1
  87. package/dist/src/rules/html-aria-role-must-be-valid.js +7 -1
  88. package/dist/src/rules/html-aria-role-must-be-valid.js.map +1 -1
  89. package/dist/src/rules/html-attribute-double-quotes.js +29 -2
  90. package/dist/src/rules/html-attribute-double-quotes.js.map +1 -1
  91. package/dist/src/rules/html-attribute-equals-spacing.js +18 -2
  92. package/dist/src/rules/html-attribute-equals-spacing.js.map +1 -1
  93. package/dist/src/rules/html-attribute-values-require-quotes.js +39 -3
  94. package/dist/src/rules/html-attribute-values-require-quotes.js.map +1 -1
  95. package/dist/src/rules/html-avoid-both-disabled-and-aria-disabled.js +7 -1
  96. package/dist/src/rules/html-avoid-both-disabled-and-aria-disabled.js.map +1 -1
  97. package/dist/src/rules/html-body-only-elements.js +46 -0
  98. package/dist/src/rules/html-body-only-elements.js.map +1 -0
  99. package/dist/src/rules/html-boolean-attributes-no-value.js +18 -1
  100. package/dist/src/rules/html-boolean-attributes-no-value.js.map +1 -1
  101. package/dist/src/rules/html-head-only-elements.js +51 -0
  102. package/dist/src/rules/html-head-only-elements.js.map +1 -0
  103. package/dist/src/rules/html-iframe-has-title.js +8 -2
  104. package/dist/src/rules/html-iframe-has-title.js.map +1 -1
  105. package/dist/src/rules/html-img-require-alt.js +7 -1
  106. package/dist/src/rules/html-img-require-alt.js.map +1 -1
  107. package/dist/src/rules/html-input-require-autocomplete.js +70 -0
  108. package/dist/src/rules/html-input-require-autocomplete.js.map +1 -0
  109. package/dist/src/rules/html-navigation-has-label.js +7 -1
  110. package/dist/src/rules/html-navigation-has-label.js.map +1 -1
  111. package/dist/src/rules/html-no-aria-hidden-on-focusable.js +7 -1
  112. package/dist/src/rules/html-no-aria-hidden-on-focusable.js.map +1 -1
  113. package/dist/src/rules/html-no-block-inside-inline.js +7 -1
  114. package/dist/src/rules/html-no-block-inside-inline.js.map +1 -1
  115. package/dist/src/rules/html-no-duplicate-attributes.js +7 -1
  116. package/dist/src/rules/html-no-duplicate-attributes.js.map +1 -1
  117. package/dist/src/rules/html-no-duplicate-ids.js +9 -3
  118. package/dist/src/rules/html-no-duplicate-ids.js.map +1 -1
  119. package/dist/src/rules/html-no-duplicate-meta-names.js +136 -0
  120. package/dist/src/rules/html-no-duplicate-meta-names.js.map +1 -0
  121. package/dist/src/rules/html-no-empty-attributes.js +45 -7
  122. package/dist/src/rules/html-no-empty-attributes.js.map +1 -1
  123. package/dist/src/rules/html-no-empty-headings.js +7 -6
  124. package/dist/src/rules/html-no-empty-headings.js.map +1 -1
  125. package/dist/src/rules/html-no-nested-links.js +7 -1
  126. package/dist/src/rules/html-no-nested-links.js.map +1 -1
  127. package/dist/src/rules/html-no-positive-tab-index.js +7 -1
  128. package/dist/src/rules/html-no-positive-tab-index.js.map +1 -1
  129. package/dist/src/rules/html-no-self-closing.js +48 -3
  130. package/dist/src/rules/html-no-self-closing.js.map +1 -1
  131. package/dist/src/rules/html-no-space-in-tag.js +173 -0
  132. package/dist/src/rules/html-no-space-in-tag.js.map +1 -0
  133. package/dist/src/rules/html-no-title-attribute.js +7 -1
  134. package/dist/src/rules/html-no-title-attribute.js.map +1 -1
  135. package/dist/src/rules/html-no-underscores-in-attribute-names.js +7 -1
  136. package/dist/src/rules/html-no-underscores-in-attribute-names.js.map +1 -1
  137. package/dist/src/rules/html-tag-name-lowercase.js +23 -5
  138. package/dist/src/rules/html-tag-name-lowercase.js.map +1 -1
  139. package/dist/src/rules/index.js +20 -2
  140. package/dist/src/rules/index.js.map +1 -1
  141. package/dist/src/rules/parser-no-errors.js +6 -0
  142. package/dist/src/rules/parser-no-errors.js.map +1 -1
  143. package/dist/src/rules/rule-utils.js +211 -31
  144. package/dist/src/rules/rule-utils.js.map +1 -1
  145. package/dist/src/rules/svg-tag-name-capitalization.js +22 -2
  146. package/dist/src/rules/svg-tag-name-capitalization.js.map +1 -1
  147. package/dist/src/{default-rules.js → rules.js} +46 -14
  148. package/dist/src/rules.js.map +1 -0
  149. package/dist/src/types.js +34 -1
  150. package/dist/src/types.js.map +1 -1
  151. package/dist/tsconfig.tsbuildinfo +1 -1
  152. package/dist/types/cli/argument-parser.d.ts +8 -2
  153. package/dist/types/cli/file-processor.d.ts +15 -0
  154. package/dist/types/cli/formatters/json-formatter.d.ts +6 -0
  155. package/dist/types/cli/formatters/simple-formatter.d.ts +1 -0
  156. package/dist/types/cli/summary-reporter.d.ts +6 -0
  157. package/dist/types/cli.d.ts +9 -4
  158. package/dist/types/custom-rule-loader.d.ts +62 -0
  159. package/dist/types/herb-disable-comment-utils.d.ts +69 -0
  160. package/dist/types/index.d.ts +1 -0
  161. package/dist/types/linter.d.ts +99 -3
  162. package/dist/types/loader.d.ts +20 -0
  163. package/dist/types/rules/erb-comment-syntax.d.ts +14 -0
  164. package/dist/types/rules/erb-no-case-node-children.d.ts +8 -0
  165. package/dist/types/rules/erb-no-empty-tags.d.ts +3 -2
  166. package/dist/types/rules/erb-no-extra-newline.d.ts +14 -0
  167. package/dist/types/rules/erb-no-extra-whitespace-inside-tags.d.ts +18 -0
  168. package/dist/types/rules/erb-no-output-control-flow.d.ts +3 -2
  169. package/dist/types/rules/erb-no-silent-tag-in-attribute-name.d.ts +3 -2
  170. package/dist/types/rules/erb-prefer-image-tag-helper.d.ts +3 -2
  171. package/dist/types/rules/erb-require-trailing-newline.d.ts +9 -0
  172. package/dist/types/rules/erb-require-whitespace-inside-tags.d.ts +16 -5
  173. package/dist/types/rules/erb-right-trim.d.ts +14 -0
  174. package/dist/types/rules/herb-disable-comment-base.d.ts +37 -0
  175. package/dist/types/rules/herb-disable-comment-malformed.d.ts +8 -0
  176. package/dist/types/rules/herb-disable-comment-missing-rules.d.ts +8 -0
  177. package/dist/types/rules/herb-disable-comment-no-duplicate-rules.d.ts +8 -0
  178. package/dist/types/rules/herb-disable-comment-no-redundant-all.d.ts +8 -0
  179. package/dist/types/rules/herb-disable-comment-unnecessary.d.ts +8 -0
  180. package/dist/types/rules/herb-disable-comment-valid-rule-name.d.ts +8 -0
  181. package/dist/types/rules/html-anchor-require-href.d.ts +3 -2
  182. package/dist/types/rules/html-aria-attribute-must-be-valid.d.ts +3 -2
  183. package/dist/types/rules/html-aria-label-is-well-formatted.d.ts +3 -2
  184. package/dist/types/rules/html-aria-level-must-be-valid.d.ts +3 -2
  185. package/dist/types/rules/html-aria-role-heading-requires-level.d.ts +3 -2
  186. package/dist/types/rules/html-aria-role-must-be-valid.d.ts +3 -2
  187. package/dist/types/rules/html-attribute-double-quotes.d.ts +13 -5
  188. package/dist/types/rules/html-attribute-equals-spacing.d.ts +12 -5
  189. package/dist/types/rules/html-attribute-values-require-quotes.d.ts +13 -5
  190. package/dist/types/rules/html-avoid-both-disabled-and-aria-disabled.d.ts +3 -2
  191. package/dist/types/rules/html-body-only-elements.d.ts +9 -0
  192. package/dist/types/rules/html-boolean-attributes-no-value.d.ts +12 -5
  193. package/dist/types/rules/html-head-only-elements.d.ts +9 -0
  194. package/dist/types/rules/html-iframe-has-title.d.ts +3 -2
  195. package/dist/types/rules/html-img-require-alt.d.ts +3 -2
  196. package/dist/types/rules/html-input-require-autocomplete.d.ts +8 -0
  197. package/dist/types/rules/html-navigation-has-label.d.ts +3 -2
  198. package/dist/types/rules/html-no-aria-hidden-on-focusable.d.ts +3 -2
  199. package/dist/types/rules/html-no-block-inside-inline.d.ts +3 -2
  200. package/dist/types/rules/html-no-duplicate-attributes.d.ts +3 -2
  201. package/dist/types/rules/html-no-duplicate-ids.d.ts +3 -2
  202. package/dist/types/rules/html-no-duplicate-meta-names.d.ts +9 -0
  203. package/dist/types/rules/html-no-empty-attributes.d.ts +3 -2
  204. package/dist/types/rules/html-no-empty-headings.d.ts +3 -2
  205. package/dist/types/rules/html-no-nested-links.d.ts +3 -2
  206. package/dist/types/rules/html-no-positive-tab-index.d.ts +3 -2
  207. package/dist/types/rules/html-no-self-closing.d.ts +14 -5
  208. package/dist/types/rules/html-no-space-in-tag.d.ts +16 -0
  209. package/dist/types/rules/html-no-title-attribute.d.ts +3 -2
  210. package/dist/types/rules/html-no-underscores-in-attribute-names.d.ts +3 -2
  211. package/dist/types/rules/html-tag-name-lowercase.d.ts +16 -6
  212. package/dist/types/rules/index.d.ts +20 -2
  213. package/dist/types/rules/parser-no-errors.d.ts +2 -1
  214. package/dist/types/rules/rule-utils.d.ts +72 -25
  215. package/dist/types/rules/svg-tag-name-capitalization.d.ts +13 -4
  216. package/dist/types/rules.d.ts +2 -0
  217. package/dist/types/src/cli/argument-parser.d.ts +8 -2
  218. package/dist/types/src/cli/file-processor.d.ts +15 -0
  219. package/dist/types/src/cli/formatters/json-formatter.d.ts +6 -0
  220. package/dist/types/src/cli/formatters/simple-formatter.d.ts +1 -0
  221. package/dist/types/src/cli/summary-reporter.d.ts +6 -0
  222. package/dist/types/src/cli.d.ts +9 -4
  223. package/dist/types/src/custom-rule-loader.d.ts +62 -0
  224. package/dist/types/src/herb-disable-comment-utils.d.ts +69 -0
  225. package/dist/types/src/index.d.ts +1 -0
  226. package/dist/types/src/linter.d.ts +99 -3
  227. package/dist/types/src/loader.d.ts +20 -0
  228. package/dist/types/src/rules/erb-comment-syntax.d.ts +14 -0
  229. package/dist/types/src/rules/erb-no-case-node-children.d.ts +8 -0
  230. package/dist/types/src/rules/erb-no-empty-tags.d.ts +3 -2
  231. package/dist/types/src/rules/erb-no-extra-newline.d.ts +14 -0
  232. package/dist/types/src/rules/erb-no-extra-whitespace-inside-tags.d.ts +18 -0
  233. package/dist/types/src/rules/erb-no-output-control-flow.d.ts +3 -2
  234. package/dist/types/src/rules/erb-no-silent-tag-in-attribute-name.d.ts +3 -2
  235. package/dist/types/src/rules/erb-prefer-image-tag-helper.d.ts +3 -2
  236. package/dist/types/src/rules/erb-require-trailing-newline.d.ts +9 -0
  237. package/dist/types/src/rules/erb-require-whitespace-inside-tags.d.ts +16 -5
  238. package/dist/types/src/rules/erb-right-trim.d.ts +14 -0
  239. package/dist/types/src/rules/herb-disable-comment-base.d.ts +37 -0
  240. package/dist/types/src/rules/herb-disable-comment-malformed.d.ts +8 -0
  241. package/dist/types/src/rules/herb-disable-comment-missing-rules.d.ts +8 -0
  242. package/dist/types/src/rules/herb-disable-comment-no-duplicate-rules.d.ts +8 -0
  243. package/dist/types/src/rules/herb-disable-comment-no-redundant-all.d.ts +8 -0
  244. package/dist/types/src/rules/herb-disable-comment-unnecessary.d.ts +8 -0
  245. package/dist/types/src/rules/herb-disable-comment-valid-rule-name.d.ts +8 -0
  246. package/dist/types/src/rules/html-anchor-require-href.d.ts +3 -2
  247. package/dist/types/src/rules/html-aria-attribute-must-be-valid.d.ts +3 -2
  248. package/dist/types/src/rules/html-aria-label-is-well-formatted.d.ts +3 -2
  249. package/dist/types/src/rules/html-aria-level-must-be-valid.d.ts +3 -2
  250. package/dist/types/src/rules/html-aria-role-heading-requires-level.d.ts +3 -2
  251. package/dist/types/src/rules/html-aria-role-must-be-valid.d.ts +3 -2
  252. package/dist/types/src/rules/html-attribute-double-quotes.d.ts +13 -5
  253. package/dist/types/src/rules/html-attribute-equals-spacing.d.ts +12 -5
  254. package/dist/types/src/rules/html-attribute-values-require-quotes.d.ts +13 -5
  255. package/dist/types/src/rules/html-avoid-both-disabled-and-aria-disabled.d.ts +3 -2
  256. package/dist/types/src/rules/html-body-only-elements.d.ts +9 -0
  257. package/dist/types/src/rules/html-boolean-attributes-no-value.d.ts +12 -5
  258. package/dist/types/src/rules/html-head-only-elements.d.ts +9 -0
  259. package/dist/types/src/rules/html-iframe-has-title.d.ts +3 -2
  260. package/dist/types/src/rules/html-img-require-alt.d.ts +3 -2
  261. package/dist/types/src/rules/html-input-require-autocomplete.d.ts +8 -0
  262. package/dist/types/src/rules/html-navigation-has-label.d.ts +3 -2
  263. package/dist/types/src/rules/html-no-aria-hidden-on-focusable.d.ts +3 -2
  264. package/dist/types/src/rules/html-no-block-inside-inline.d.ts +3 -2
  265. package/dist/types/src/rules/html-no-duplicate-attributes.d.ts +3 -2
  266. package/dist/types/src/rules/html-no-duplicate-ids.d.ts +3 -2
  267. package/dist/types/src/rules/html-no-duplicate-meta-names.d.ts +9 -0
  268. package/dist/types/src/rules/html-no-empty-attributes.d.ts +3 -2
  269. package/dist/types/src/rules/html-no-empty-headings.d.ts +3 -2
  270. package/dist/types/src/rules/html-no-nested-links.d.ts +3 -2
  271. package/dist/types/src/rules/html-no-positive-tab-index.d.ts +3 -2
  272. package/dist/types/src/rules/html-no-self-closing.d.ts +14 -5
  273. package/dist/types/src/rules/html-no-space-in-tag.d.ts +16 -0
  274. package/dist/types/src/rules/html-no-title-attribute.d.ts +3 -2
  275. package/dist/types/src/rules/html-no-underscores-in-attribute-names.d.ts +3 -2
  276. package/dist/types/src/rules/html-tag-name-lowercase.d.ts +16 -6
  277. package/dist/types/src/rules/index.d.ts +20 -2
  278. package/dist/types/src/rules/parser-no-errors.d.ts +2 -1
  279. package/dist/types/src/rules/rule-utils.d.ts +72 -25
  280. package/dist/types/src/rules/svg-tag-name-capitalization.d.ts +13 -4
  281. package/dist/types/src/rules.d.ts +2 -0
  282. package/dist/types/src/types.d.ts +102 -11
  283. package/dist/types/types.d.ts +102 -11
  284. package/docs/rules/README.md +19 -3
  285. package/docs/rules/erb-comment-syntax.md +44 -0
  286. package/docs/rules/erb-no-case-node-children.md +50 -0
  287. package/docs/rules/erb-no-extra-newline.md +74 -0
  288. package/docs/rules/erb-no-extra-whitespace-inside-tags.md +39 -0
  289. package/docs/rules/{erb-requires-trailing-newline.md → erb-require-trailing-newline.md} +1 -1
  290. package/docs/rules/erb-right-trim.md +52 -0
  291. package/docs/rules/herb-disable-comment-malformed.md +45 -0
  292. package/docs/rules/herb-disable-comment-missing-rules.md +60 -0
  293. package/docs/rules/herb-disable-comment-no-duplicate-rules.md +49 -0
  294. package/docs/rules/herb-disable-comment-no-redundant-all.md +53 -0
  295. package/docs/rules/herb-disable-comment-unnecessary.md +44 -0
  296. package/docs/rules/herb-disable-comment-valid-rule-name.md +41 -0
  297. package/docs/rules/html-aria-attribute-must-be-valid.md +2 -5
  298. package/docs/rules/html-aria-label-is-well-formatted.md +1 -1
  299. package/docs/rules/html-attribute-double-quotes.md +2 -2
  300. package/docs/rules/html-attribute-equals-spacing.md +2 -2
  301. package/docs/rules/html-attribute-values-require-quotes.md +3 -3
  302. package/docs/rules/html-avoid-both-disabled-and-aria-disabled.md +2 -2
  303. package/docs/rules/html-body-only-elements.md +99 -0
  304. package/docs/rules/html-boolean-attributes-no-value.md +2 -2
  305. package/docs/rules/html-head-only-elements.md +81 -0
  306. package/docs/rules/html-input-require-autocomplete.md +64 -0
  307. package/docs/rules/html-no-aria-hidden-on-focusable.md +2 -2
  308. package/docs/rules/html-no-duplicate-attributes.md +2 -2
  309. package/docs/rules/html-no-duplicate-meta-names.md +64 -0
  310. package/docs/rules/html-no-empty-attributes.md +3 -3
  311. package/docs/rules/html-no-empty-headings.md +4 -26
  312. package/docs/rules/html-no-positive-tab-index.md +1 -2
  313. package/docs/rules/html-no-self-closing.md +17 -2
  314. package/docs/rules/html-no-space-in-tag.md +66 -0
  315. package/docs/rules/html-no-title-attribute.md +2 -2
  316. package/docs/rules/html-no-underscores-in-attribute-names.md +2 -2
  317. package/docs/rules/html-tag-name-lowercase.md +2 -2
  318. package/package.json +13 -5
  319. package/src/cli/argument-parser.ts +50 -39
  320. package/src/cli/file-processor.ts +159 -28
  321. package/src/cli/formatters/detailed-formatter.ts +21 -3
  322. package/src/cli/formatters/github-actions-formatter.ts +17 -1
  323. package/src/cli/formatters/json-formatter.ts +9 -0
  324. package/src/cli/formatters/simple-formatter.ts +24 -8
  325. package/src/cli/output-manager.ts +23 -3
  326. package/src/cli/summary-reporter.ts +40 -3
  327. package/src/cli.ts +137 -52
  328. package/src/custom-rule-loader.ts +189 -0
  329. package/src/herb-disable-comment-utils.ts +175 -0
  330. package/src/index.ts +2 -0
  331. package/src/linter.ts +501 -36
  332. package/src/loader.ts +30 -0
  333. package/src/rules/erb-comment-syntax.ts +73 -0
  334. package/src/rules/erb-no-case-node-children.ts +68 -0
  335. package/src/rules/erb-no-empty-tags.ts +9 -3
  336. package/src/rules/erb-no-extra-newline.ts +91 -0
  337. package/src/rules/erb-no-extra-whitespace-inside-tags.ts +147 -0
  338. package/src/rules/erb-no-output-control-flow.ts +9 -3
  339. package/src/rules/erb-no-silent-tag-in-attribute-name.ts +9 -3
  340. package/src/rules/erb-prefer-image-tag-helper.ts +9 -3
  341. package/src/rules/erb-require-trailing-newline.ts +47 -0
  342. package/src/rules/erb-require-whitespace-inside-tags.ts +96 -26
  343. package/src/rules/erb-right-trim.ts +67 -0
  344. package/src/rules/herb-disable-comment-base.ts +76 -0
  345. package/src/rules/herb-disable-comment-malformed.ts +66 -0
  346. package/src/rules/herb-disable-comment-missing-rules.ts +41 -0
  347. package/src/rules/herb-disable-comment-no-duplicate-rules.ts +46 -0
  348. package/src/rules/herb-disable-comment-no-redundant-all.ts +40 -0
  349. package/src/rules/herb-disable-comment-unnecessary.ts +103 -0
  350. package/src/rules/herb-disable-comment-valid-rule-name.ts +62 -0
  351. package/src/rules/html-anchor-require-href.ts +9 -3
  352. package/src/rules/html-aria-attribute-must-be-valid.ts +9 -3
  353. package/src/rules/html-aria-label-is-well-formatted.ts +9 -5
  354. package/src/rules/html-aria-level-must-be-valid.ts +9 -2
  355. package/src/rules/html-aria-role-heading-requires-level.ts +9 -3
  356. package/src/rules/html-aria-role-must-be-valid.ts +9 -3
  357. package/src/rules/html-attribute-double-quotes.ts +42 -8
  358. package/src/rules/html-attribute-equals-spacing.ts +31 -7
  359. package/src/rules/html-attribute-values-require-quotes.ts +56 -10
  360. package/src/rules/html-avoid-both-disabled-and-aria-disabled.ts +9 -3
  361. package/src/rules/html-body-only-elements.ts +60 -0
  362. package/src/rules/html-boolean-attributes-no-value.ts +31 -6
  363. package/src/rules/html-head-only-elements.ts +65 -0
  364. package/src/rules/html-iframe-has-title.ts +9 -4
  365. package/src/rules/html-img-require-alt.ts +10 -4
  366. package/src/rules/html-input-require-autocomplete.ts +85 -0
  367. package/src/rules/html-navigation-has-label.ts +9 -3
  368. package/src/rules/html-no-aria-hidden-on-focusable.ts +9 -3
  369. package/src/rules/html-no-block-inside-inline.ts +9 -3
  370. package/src/rules/html-no-duplicate-attributes.ts +9 -3
  371. package/src/rules/html-no-duplicate-ids.ts +11 -7
  372. package/src/rules/html-no-duplicate-meta-names.ts +188 -0
  373. package/src/rules/html-no-empty-attributes.ts +58 -10
  374. package/src/rules/html-no-empty-headings.ts +10 -8
  375. package/src/rules/html-no-nested-links.ts +10 -4
  376. package/src/rules/html-no-positive-tab-index.ts +9 -3
  377. package/src/rules/html-no-self-closing.ts +69 -9
  378. package/src/rules/html-no-space-in-tag.ts +221 -0
  379. package/src/rules/html-no-title-attribute.ts +9 -3
  380. package/src/rules/html-no-underscores-in-attribute-names.ts +12 -4
  381. package/src/rules/html-tag-name-lowercase.ts +41 -10
  382. package/src/rules/index.ts +24 -2
  383. package/src/rules/parser-no-errors.ts +8 -1
  384. package/src/rules/rule-utils.ts +250 -44
  385. package/src/rules/svg-tag-name-capitalization.ts +39 -6
  386. package/src/{default-rules.ts → rules.ts} +53 -13
  387. package/src/types.ts +133 -15
  388. package/dist/src/default-rules.js.map +0 -1
  389. package/dist/src/rules/erb-requires-trailing-newline.js +0 -22
  390. package/dist/src/rules/erb-requires-trailing-newline.js.map +0 -1
  391. package/dist/types/default-rules.d.ts +0 -2
  392. package/dist/types/rules/erb-requires-trailing-newline.d.ts +0 -6
  393. package/dist/types/src/default-rules.d.ts +0 -2
  394. package/dist/types/src/rules/erb-requires-trailing-newline.d.ts +0 -6
  395. package/src/rules/erb-requires-trailing-newline.ts +0 -29
@@ -0,0 +1,53 @@
1
+ # Linter Rule: Disallow redundant use of `all` in `herb:disable` comments
2
+
3
+ **Rule:** `herb-disable-comment-no-redundant-all`
4
+
5
+ ## Description
6
+
7
+ Prevents using `all` together with specific rule names in `<%# herb:disable ... %>` comments, as this is redundant.
8
+
9
+ ## Rationale
10
+
11
+ When you use `all` in a `<%# herb:disable ... %>` comment, it disables every linter rule for that line. Adding specific rule names alongside `all` is redundant because `all` already covers them.
12
+
13
+ This rule helps maintain clean, concise disable comments by ensuring you either use `herb:disable all` by itself to disable all rules or lists only the specific rules you want to disable.
14
+
15
+ ## Examples
16
+
17
+ ### ✅ Good
18
+
19
+ ```erb
20
+ <DIV>test</DIV> <%# herb:disable all %>
21
+
22
+ <DIV class='value'>test</DIV> <%# herb:disable html-tag-name-lowercase, html-attribute-double-quotes %>
23
+
24
+ <DIV>test</DIV> <%# herb:disable html-tag-name-lowercase %>
25
+ ```
26
+
27
+ ### 🚫 Bad
28
+
29
+ ```erb
30
+ <DIV>test</DIV> <%# herb:disable all, html-tag-name-lowercase %>
31
+
32
+ <DIV>test</DIV> <%# herb:disable html-tag-name-lowercase, all, html-attribute-double-quotes %>
33
+
34
+ <DIV>test</DIV> <%# herb:disable all, all %>
35
+ ```
36
+
37
+ ## Fix
38
+
39
+ Remove either the `all` keyword or the specific rule names:
40
+
41
+ **Option 1:** Keep only `all`
42
+ ```erb
43
+ <DIV class='value'>test</DIV> <%# herb:disable all %>
44
+ ```
45
+
46
+ **Option 2:** Keep only specific rules
47
+ ```erb
48
+ <DIV class='value'>test</DIV> <%# herb:disable html-tag-name-lowercase, html-attribute-double-quotes %>
49
+ ```
50
+
51
+ ## References
52
+
53
+ \-
@@ -0,0 +1,44 @@
1
+ # Linter Rule: Detect unnecessary `herb:disable` comments
2
+
3
+ **Rule:** `herb-disable-comment-unnecessary`
4
+
5
+ ## Description
6
+
7
+ Warns when a `<%# herb:disable ... %>` comment doesn't actually suppress any linter offenses on that line, indicating it's unnecessary and should be removed.
8
+
9
+ ## Rationale
10
+
11
+ Unnecessary `<%# herb:disable ... %>` comments create noise in the codebase and can mislead developers about which rules are being suppressed. These comments often remain after the code has been refactored and no longer triggers the offense.
12
+
13
+ Removing unnecessary disable comments keeps the codebase clean and ensures that suppression comments accurately reflect actual rule violations being intentionally ignored.
14
+
15
+ ## Examples
16
+
17
+ ### ✅ Good
18
+
19
+ ```erb
20
+ <DIV>test</DIV> <%# herb:disable html-tag-name-lowercase %>
21
+
22
+ <DIV id='test-1'>content</DIV> <%# herb:disable html-tag-name-lowercase, html-attribute-double-quotes %>
23
+
24
+ <DIV id='test-2'>content</DIV> <%# herb:disable all %>
25
+ ```
26
+
27
+ ### 🚫 Bad
28
+
29
+ ```erb
30
+ <div>test</div> <%# herb:disable html-tag-name-lowercase %>
31
+
32
+ <div id="test">content</div> <%# herb:disable html-tag-name-lowercase, html-attribute-double-quotes %>
33
+
34
+ <div id="test-1">content</div> <%# herb:disable all %>
35
+
36
+ <DIV id='test-2'>content</DIV> <%# herb:disable html-tag-name-lowercase, html-attribute-double-quotes, html-no-empty-headings %>
37
+
38
+ <div>test</div> <%# herb:disableall %>
39
+ ```
40
+
41
+
42
+ ## References
43
+
44
+ \-
@@ -0,0 +1,41 @@
1
+ # Linter Rule: Validate rule names in `herb:disable` comments
2
+
3
+ **Rule:** `herb-disable-comment-valid-rule-name`
4
+
5
+ ## Description
6
+
7
+ Ensures that all rule names specified in `<%# herb:disable ... %>` comments are valid and exist in the linter. This catches typos, references to non-existent rules and missing comma between rule names.
8
+
9
+ ## Rationale
10
+
11
+ Using invalid or misspelled rule names in `<%# herb:disable ... %>` comments can lead to confusion and unexpected behavior. The comment won't disable anything if the rule name doesn't exist, leaving developers wondering why linter warnings persist.
12
+
13
+ By validating rule names, this rule helps catch typos early, identify removed or renamed rule and provide helpful suggestions for similar rule names using fuzzy matching.
14
+
15
+ ## Examples
16
+
17
+ ### ✅ Good
18
+
19
+ ```erb
20
+ <DIV>test</DIV> <%# herb:disable html-tag-name-lowercase %>
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 this-rule-doesnt-exist %>
31
+
32
+ <div>test</div> <%# herb:disable html-tag-lowercase %>
33
+
34
+ <DIV>test</DIV> <%# herb:disable html-tag-name-lowercase, invalid-rule-name %>
35
+
36
+ <div>test</div> <%# herb:disable html-tag-name-lowercase html-attribute-double-quotes %>
37
+ ```
38
+
39
+ ## References
40
+
41
+ \-
@@ -22,20 +22,17 @@ Validating against a known list ensures you're using correct and effective ARIA
22
22
 
23
23
  ```html
24
24
  <div role="button" aria-pressed="false">Toggle</div>
25
- <input type="text" aria-label="Search" />
25
+ <input type="text" aria-label="Search" autocomplete="off">
26
26
  <span role="heading" aria-level="2">Title</span>
27
27
  ```
28
28
 
29
29
  ### 🚫 Bad
30
30
 
31
31
  ```html
32
- <!-- typo -->
33
32
  <div role="button" aria-presed="false">Toggle</div>
34
33
 
35
- <!-- typo -->
36
- <input type="text" aria-lable="Search" />
34
+ <input type="text" aria-lable="Search" autocomplete="off">
37
35
 
38
- <!-- invalid -->
39
36
  <span aria-size="large" role="heading" aria-level="2">Title</span>
40
37
  ```
41
38
 
@@ -16,7 +16,7 @@ The `aria-label` attribute provides an accessible name for elements that will be
16
16
 
17
17
  ```erb
18
18
  <button aria-label="Close dialog">X</button>
19
- <input aria-label="Search products" type="search">
19
+ <input aria-label="Search products" type="search" autocomplete="off">
20
20
  <button aria-label="Page 2 of 10">2</button>
21
21
  ```
22
22
 
@@ -17,7 +17,7 @@ Double quotes are the most widely used and expected style for HTML attributes. C
17
17
  ### ✅ Good
18
18
 
19
19
  ```html
20
- <input type="text">
20
+ <input type="text" autocomplete="off">
21
21
 
22
22
  <a href="/profile">Profile</a>
23
23
 
@@ -31,7 +31,7 @@ Double quotes are the most widely used and expected style for HTML attributes. C
31
31
  ### 🚫 Bad
32
32
 
33
33
  ```html
34
- <input type='text'>
34
+ <input type='text' autocomplete="off">
35
35
 
36
36
  <a href='/profile'>Profile</a>
37
37
 
@@ -17,7 +17,7 @@ Extra whitespace around the `=` in HTML attribute assignments is unnecessary, in
17
17
  ```erb
18
18
  <div class="container"></div>
19
19
  <img src="/logo.png" alt="Logo">
20
- <input type="text" value="<%= @value %>">
20
+ <input type="text" value="<%= @value %>" autocomplete="off">
21
21
  ```
22
22
 
23
23
  ### 🚫 Bad
@@ -27,7 +27,7 @@ Extra whitespace around the `=` in HTML attribute assignments is unnecessary, in
27
27
 
28
28
  <img src= "/logo.png" alt="Logo">
29
29
 
30
- <input type = "text">
30
+ <input type = "text" autocomplete="off">
31
31
  ```
32
32
 
33
33
  ## References
@@ -23,7 +23,7 @@ Additionally, always quoting is the common convention in most HTML formatters, l
23
23
  ```html
24
24
  <div id="hello"></div>
25
25
 
26
- <input type="text">
26
+ <input type="text" autocomplete="off">
27
27
 
28
28
  <a href="/profile">Profile</a>
29
29
  ```
@@ -33,9 +33,9 @@ Additionally, always quoting is the common convention in most HTML formatters, l
33
33
  ```html
34
34
  <div id=hello></div>
35
35
 
36
- <input type=text>
36
+ <input type=text autocomplete="off">
37
37
 
38
- <a href=/profile></a>
38
+ <a href=profile></a>
39
39
  ```
40
40
 
41
41
  ## References
@@ -19,7 +19,7 @@ Elements that support the native `disabled` attribute include: `button`, `fields
19
19
  ```erb
20
20
  <!-- Use only the native disabled attribute -->
21
21
  <button disabled>Submit</button>
22
- <input type="text" disabled>
22
+ <input type="text" autocomplete="off" disabled>
23
23
 
24
24
  <!-- Use only aria-disabled for custom elements -->
25
25
  <div role="button" aria-disabled="true">Custom Button</div>
@@ -34,7 +34,7 @@ Elements that support the native `disabled` attribute include: `button`, `fields
34
34
  <!-- Both disabled and aria-disabled -->
35
35
  <button disabled aria-disabled="true">Submit</button>
36
36
 
37
- <input type="text" disabled aria-disabled="true">
37
+ <input type="text" autocomplete="off" disabled aria-disabled="true">
38
38
 
39
39
  <select disabled aria-disabled="true">
40
40
  <option>Option 1</option>
@@ -0,0 +1,99 @@
1
+ # Linter Rule: Require content elements inside `<body>`
2
+
3
+ **Rule:** `html-body-only-elements`
4
+
5
+ ## Description
6
+
7
+ Enforce that specific HTML elements are only placed within the `<body>` tag.
8
+
9
+ ## Rationale
10
+
11
+ According to the HTML specification, certain elements are meant to contain content and should only appear within the `<body>` section of an HTML document. Placing content-bearing or interactive elements in the `<head>` section or outside the HTML structure can lead to:
12
+
13
+ - Unpredictable browser rendering behavior
14
+ - Accessibility issues for screen readers and assistive technologies
15
+ - SEO problems as search engines may not properly index misplaced content
16
+ - Validation errors and non-compliant HTML
17
+
18
+ This rule enforces proper document structure by ensuring semantic and content elements are correctly placed within the `<body>` element.
19
+
20
+ ## Examples
21
+
22
+ ### ✅ Good
23
+
24
+ ```erb
25
+ <html>
26
+ <head>
27
+ <title>Page Title</title>
28
+ <meta charset="utf-8">
29
+ </head>
30
+
31
+ <body>
32
+ <header>
33
+ <h1>Welcome</h1>
34
+ <nav>
35
+ <ul>
36
+ <li>Home</li>
37
+ </ul>
38
+ </nav>
39
+ </header>
40
+
41
+ <main>
42
+ <article>
43
+ <section>
44
+ <p>This is valid content.</p>
45
+ <table>
46
+ <tr><td>Data</td></tr>
47
+ </table>
48
+ </section>
49
+ </article>
50
+ <aside>
51
+ <form>
52
+ <input type="text" autocomplete="on">
53
+ </form>
54
+ </aside>
55
+ </main>
56
+
57
+ <footer>
58
+ <h2>Footer</h2>
59
+ </footer>
60
+ </body>
61
+ </html>
62
+ ```
63
+
64
+ ### 🚫 Bad
65
+
66
+ ```erb
67
+ <html>
68
+ <head>
69
+ <title>Page Title</title>
70
+ <h1>Welcome</h1>
71
+
72
+ <p>This should not be here.</p>
73
+
74
+ </head>
75
+
76
+ <body>
77
+ <main>Valid content</main>
78
+ </body>
79
+ </html>
80
+ ```
81
+
82
+ ```erb
83
+ <html>
84
+ <head>
85
+ <nav>Navigation</nav>
86
+
87
+ <form>Form</form>
88
+
89
+ </head>
90
+
91
+ <body>
92
+ </body>
93
+ </html>
94
+ ```
95
+
96
+ ## References
97
+
98
+ - [HTML Living Standard - The `body` element](https://html.spec.whatwg.org/multipage/sections.html#the-body-element)
99
+ - [MDN: HTML `document` structure](https://developer.mozilla.org/en-US/docs/Learn/HTML/Introduction_to_HTML/Document_and_website_structure)
@@ -21,7 +21,7 @@ For example, instead of writing `disabled="disabled"` or `disabled="true"`, simp
21
21
 
22
22
  <button disabled>Submit</button>
23
23
 
24
- <select multiple>
24
+ <select multiple></select>
25
25
  ```
26
26
 
27
27
  ### 🚫 Bad
@@ -31,7 +31,7 @@ For example, instead of writing `disabled="disabled"` or `disabled="true"`, simp
31
31
 
32
32
  <button disabled="true">Submit</button>
33
33
 
34
- <select multiple="multiple">
34
+ <select multiple="multiple"></select>
35
35
  ```
36
36
 
37
37
  ## References
@@ -0,0 +1,81 @@
1
+ # Linter Rule: Require head-scoped elements inside `<head>`
2
+
3
+ **Rule:** `html-head-only-elements`
4
+
5
+ ## Description
6
+
7
+ Enforce that certain elements only appear inside the `<head>` section of the document.
8
+
9
+ Elements like `<title>`, `<meta>`, `<base>`, `<link>`, and `<style>` are permitted only inside the `<head>` element. They must not appear inside `<body>` or outside of `<html>`. Placing them elsewhere produces invalid HTML and relies on browser error correction.
10
+
11
+ > [!NOTE] Exception
12
+ > `<title>` elements are allowed inside `<svg>` elements for accessibility purposes.
13
+
14
+ ## Rationale
15
+
16
+ The HTML specification requires certain elements to appear only in the `<head>` section because they affect document metadata, resource loading, or global behavior:
17
+
18
+ Placing these elements outside `<head>` leads to invalid HTML and undefined behavior across browsers.
19
+
20
+
21
+ ## Examples
22
+
23
+ ### ✅ Good
24
+
25
+ ```erb
26
+ <head>
27
+ <title>My Page</title>
28
+ <meta charset="UTF-8">
29
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
30
+ <link rel="stylesheet" href="/styles.css">
31
+ </head>
32
+
33
+ <body>
34
+ <h1>Welcome</h1>
35
+ </body>
36
+ ```
37
+
38
+ ```erb
39
+ <head>
40
+ <%= csrf_meta_tags %>
41
+ <%= csp_meta_tag %>
42
+ <%= favicon_link_tag 'favicon.ico' %>
43
+ <%= stylesheet_link_tag "application", "data-turbo-track": "reload" %>
44
+ <%= javascript_include_tag "application", "data-turbo-track": "reload", defer: true %>
45
+
46
+ <title><%= content_for?(:title) ? yield(:title) : "Default Title" %></title>
47
+ </head>
48
+ ```
49
+
50
+ ```erb
51
+ <body>
52
+ <svg>
53
+ <title>Chart Title</title>
54
+ <rect width="100" height="100" />
55
+ </svg>
56
+ </body>
57
+ ```
58
+
59
+ ### 🚫 Bad
60
+
61
+ ```erb
62
+ <body>
63
+ <title>My Page</title>
64
+
65
+ <meta charset="UTF-8">
66
+
67
+ <link rel="stylesheet" href="/styles.css">
68
+
69
+ <h1>Welcome</h1>
70
+ </body>
71
+ ```
72
+
73
+ ```erb
74
+ <body>
75
+ <title><%= content_for?(:title) ? yield(:title) : "Default Title" %></title>
76
+ </body>
77
+ ```
78
+
79
+ ## References
80
+
81
+ * [HTML Living Standard - The `head` element](https://html.spec.whatwg.org/multipage/semantics.html#the-head-element)
@@ -0,0 +1,64 @@
1
+ # Linter Rule: Require `autocomplete` attributes on `<input>` tags
2
+
3
+ **Rule:** `html-input-require-autocomplete`
4
+
5
+ ## Description
6
+
7
+ Require an `autocomplete` attribute on `<input>` elements with types that support autocomplete functionality. This rule ensures that developers explicitly declare autocomplete behavior for form inputs.
8
+
9
+
10
+ ## Rationale
11
+
12
+ The HTML `autocomplete` attribute helps users complete forms by using data stored in the browser. This is particularly useful for people with motor disabilities or cognitive impairment who may have difficulties filling out forms online. Without an explicit `autocomplete` attribute, behavior varies across browsers and can lead to inconsistent user experiences.
13
+
14
+ If you prefer not to specify a specific autocomplete value, use `autocomplete="on"` to enable browser defaults or `autocomplete="off"` to explicitly disable it.
15
+
16
+ ## Affected Input Types
17
+
18
+ This rule applies to the following input types:
19
+
20
+ - `color`
21
+ - `date`
22
+ - `datetime-local`
23
+ - `email`
24
+ - `month`
25
+ - `number`
26
+ - `password`
27
+ - `range`
28
+ - `search`
29
+ - `tel`
30
+ - `text`
31
+ - `time`
32
+ - `url`
33
+ - `week`
34
+
35
+
36
+ ## Examples
37
+
38
+ ### ✅ Good
39
+
40
+ ```erb
41
+ <input type="email" autocomplete="email">
42
+
43
+ <input type="url" autocomplete="off">
44
+
45
+ <input type="password" autocomplete="on">
46
+ ```
47
+
48
+
49
+ ### 🚫 Bad
50
+
51
+ ```erb
52
+ <input type="email">
53
+
54
+ <input type="url">
55
+
56
+ <input type="password">
57
+ ```
58
+
59
+ ## References
60
+
61
+ * [Inspiration: ERB Lint `RequireInputAutocomplete` rule](https://github.com/shopify/erb_lint?tab=readme-ov-file#requireinputautocomplete)
62
+ * [HTML attribute: autocomplete](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/autocomplete)
63
+ * [WCAG: Using HTML autocomplete attributes](https://www.w3.org/WAI/WCAG21/Techniques/html/H98)
64
+ * [HTML Specification: Autofill](https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofill)
@@ -17,7 +17,7 @@ Elements with `aria-hidden="true"` are completely hidden from assistive technolo
17
17
  ```erb
18
18
  <button>Submit</button>
19
19
  <a href="/link">Link</a>
20
- <input type="text">
20
+ <input type="text" autocomplete="off">
21
21
  <textarea></textarea>
22
22
 
23
23
  <div aria-hidden="true">Decorative content</div>
@@ -33,7 +33,7 @@ Elements with `aria-hidden="true"` are completely hidden from assistive technolo
33
33
 
34
34
  <a href="/link" aria-hidden="true">Link</a>
35
35
 
36
- <input type="text" aria-hidden="true">
36
+ <input type="text" autocomplete="off" aria-hidden="true">
37
37
 
38
38
  <textarea aria-hidden="true"></textarea>
39
39
 
@@ -17,7 +17,7 @@ Catching duplicates early helps prevent subtle bugs, improves code correctness,
17
17
  ### ✅ Good
18
18
 
19
19
  ```erb
20
- <input type="text" name="username" id="user-id">
20
+ <input type="text" name="username" id="user-id" autocomplete="off">
21
21
 
22
22
  <button type="submit" disabled>Submit</button>
23
23
  ```
@@ -25,7 +25,7 @@ Catching duplicates early helps prevent subtle bugs, improves code correctness,
25
25
  ### 🚫 Bad
26
26
 
27
27
  ```erb
28
- <input type="text" type="password" name="username">
28
+ <input type="text" type="password" name="username" autocomplete="off">
29
29
 
30
30
  <button type="submit" type="button" disabled>Submit</button>
31
31
  ```
@@ -0,0 +1,64 @@
1
+ # Linter Rule: Duplicate `<meta>` name attributes are not allowed
2
+
3
+ **Rule:** `html-no-duplicate-meta-names`
4
+
5
+ ## Description
6
+
7
+ Warn when multiple `<meta>` tags share the same `name` or `http-equiv` attribute within the same `<head>` block, unless they are wrapped in conditional comments.
8
+
9
+ ## Rationale
10
+
11
+ In HTML, duplicate `<meta>` tags with the same `name` or `http-equiv` can cause unexpected behavior. For example, search engines or social sharing tools may use the wrong value. These duplicates are often the result of copy-paste or partial rendering logic and should be avoided.
12
+
13
+ ## Examples
14
+
15
+ ### ✅ Good
16
+
17
+ ```erb
18
+ <head>
19
+ <meta name="description" content="Welcome to our site">
20
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
21
+ </head>
22
+ ```
23
+
24
+ ```erb
25
+ <head>
26
+ <% if mobile? %>
27
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
28
+ <% else %>
29
+ <meta name="viewport" content="width=1024">
30
+ <% end %>
31
+ </head>
32
+ ```
33
+
34
+ ### 🚫 Bad
35
+
36
+ ```erb
37
+ <head>
38
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
39
+ <meta name="viewport" content="width=1024">
40
+ </head>
41
+ ```
42
+
43
+ ```erb
44
+ <head>
45
+ <meta http-equiv="X-UA-Compatible" content="IE=edge">
46
+ <meta http-equiv="X-UA-Compatible" content="chrome=1">
47
+ </head>
48
+ ```
49
+
50
+ ```erb
51
+ <head>
52
+ <meta name="viewport" content="width=1024">
53
+
54
+ <% if mobile? %>
55
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
56
+ <% else %>
57
+ <meta http-equiv="refresh" content="30">
58
+ <% end %>
59
+ </head>
60
+ ```
61
+
62
+ ## References
63
+
64
+ \-
@@ -40,7 +40,7 @@ This rule helps ensure that required attributes are only added when they are pop
40
40
  ```erb
41
41
  <div id="header"></div>
42
42
  <img src="/logo.png" alt="Company logo">
43
- <input type="text" name="email">
43
+ <input type="text" name="email" autocomplete="off">
44
44
 
45
45
  <!-- Dynamic attributes with meaningful values -->
46
46
  <div data-<%= key %>="<%= value %>" aria-<%= prop %>="<%= description %>">
@@ -55,8 +55,8 @@ This rule helps ensure that required attributes are only added when they are pop
55
55
 
56
56
  ```erb
57
57
  <div id=""></div>
58
- <img src="">
59
- <input name="">
58
+ <img src="" alt="Company logo">
59
+ <input name="" autocomplete="off">
60
60
 
61
61
  <div data-config="">Content</div>
62
62
  <button aria-label="">×</button>