@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,16 @@
1
+ import { WhitespaceNode } from "@herb-tools/core";
2
+ import { ParserRule, BaseAutofixContext } from "../types.js";
3
+ import type { ParseResult, HTMLOpenTagNode } from "@herb-tools/core";
4
+ import type { UnboundLintOffense, LintOffense, LintContext, FullRuleConfig } from "../types.js";
5
+ interface HTMLNoSpaceInTagAutofixContext extends BaseAutofixContext {
6
+ node: WhitespaceNode | HTMLOpenTagNode;
7
+ message: string;
8
+ }
9
+ export declare class HTMLNoSpaceInTagRule extends ParserRule<HTMLNoSpaceInTagAutofixContext> {
10
+ static autocorrectable: boolean;
11
+ name: string;
12
+ get defaultConfig(): FullRuleConfig;
13
+ check(result: ParseResult, context?: Partial<LintContext>): UnboundLintOffense<HTMLNoSpaceInTagAutofixContext>[];
14
+ autofix(offense: LintOffense<HTMLNoSpaceInTagAutofixContext>, result: ParseResult, _context?: Partial<LintContext>): ParseResult | null;
15
+ }
16
+ export {};
@@ -1,7 +1,8 @@
1
1
  import { ParserRule } from "../types.js";
2
- import type { LintOffense, LintContext } from "../types.js";
2
+ import type { UnboundLintOffense, LintContext, FullRuleConfig } from "../types.js";
3
3
  import type { ParseResult } from "@herb-tools/core";
4
4
  export declare class HTMLNoTitleAttributeRule extends ParserRule {
5
5
  name: string;
6
- check(result: ParseResult, context?: Partial<LintContext>): LintOffense[];
6
+ get defaultConfig(): FullRuleConfig;
7
+ check(result: ParseResult, context?: Partial<LintContext>): UnboundLintOffense[];
7
8
  }
@@ -1,7 +1,8 @@
1
1
  import { ParserRule } from "../types.js";
2
- import type { LintContext, LintOffense } from "../types.js";
2
+ import type { UnboundLintOffense, LintContext, FullRuleConfig } from "../types.js";
3
3
  import type { ParseResult } from "@herb-tools/core";
4
4
  export declare class HTMLNoUnderscoresInAttributeNamesRule extends ParserRule {
5
5
  name: string;
6
- check(result: ParseResult, context?: Partial<LintContext>): LintOffense[];
6
+ get defaultConfig(): FullRuleConfig;
7
+ check(result: ParseResult, context?: Partial<LintContext>): UnboundLintOffense[];
7
8
  }
@@ -1,8 +1,18 @@
1
- import { ParserRule } from "../types.js";
2
- import { ParseResult } from "@herb-tools/core";
3
- import type { LintOffense, LintContext } from "../types.js";
4
- export declare class HTMLTagNameLowercaseRule extends ParserRule {
1
+ import { ParserRule, BaseAutofixContext, Mutable } from "../types.js";
2
+ import { HTMLOpenTagNode } from "@herb-tools/core";
3
+ import type { UnboundLintOffense, LintOffense, LintContext, FullRuleConfig } from "../types.js";
4
+ import type { HTMLCloseTagNode, ParseResult } from "@herb-tools/core";
5
+ interface TagNameAutofixContext extends BaseAutofixContext {
6
+ node: Mutable<HTMLOpenTagNode | HTMLCloseTagNode>;
7
+ tagName: string;
8
+ correctedTagName: string;
9
+ }
10
+ export declare class HTMLTagNameLowercaseRule extends ParserRule<TagNameAutofixContext> {
11
+ static autocorrectable: boolean;
5
12
  name: string;
6
- isEnabled(result: ParseResult, context?: Partial<LintContext>): boolean;
7
- check(result: ParseResult, context?: Partial<LintContext>): LintOffense[];
13
+ get defaultConfig(): FullRuleConfig;
14
+ isEnabled(result: ParseResult, _context?: Partial<LintContext>): boolean;
15
+ check(result: ParseResult, context?: Partial<LintContext>): UnboundLintOffense<TagNameAutofixContext>[];
16
+ autofix(offense: LintOffense<TagNameAutofixContext>, result: ParseResult, _context?: Partial<LintContext>): ParseResult | null;
8
17
  }
18
+ export {};
@@ -1,9 +1,22 @@
1
1
  export * from "./rule-utils.js";
2
+ export * from "./herb-disable-comment-base.js";
3
+ export * from "./erb-comment-syntax.js";
4
+ export * from "./erb-no-case-node-children.js";
2
5
  export * from "./erb-no-empty-tags.js";
6
+ export * from "./erb-no-extra-newline.js";
7
+ export * from "./erb-no-extra-whitespace-inside-tags.js";
3
8
  export * from "./erb-no-output-control-flow.js";
4
9
  export * from "./erb-no-silent-tag-in-attribute-name.js";
5
10
  export * from "./erb-prefer-image-tag-helper.js";
6
- export * from "./erb-requires-trailing-newline.js";
11
+ export * from "./erb-require-trailing-newline.js";
12
+ export * from "./erb-require-whitespace-inside-tags.js";
13
+ export * from "./erb-right-trim.js";
14
+ export * from "./herb-disable-comment-valid-rule-name.js";
15
+ export * from "./herb-disable-comment-no-redundant-all.js";
16
+ export * from "./herb-disable-comment-no-duplicate-rules.js";
17
+ export * from "./herb-disable-comment-missing-rules.js";
18
+ export * from "./herb-disable-comment-malformed.js";
19
+ export * from "./herb-disable-comment-unnecessary.js";
7
20
  export * from "./html-anchor-require-href.js";
8
21
  export * from "./html-aria-label-is-well-formatted.js";
9
22
  export * from "./html-aria-level-must-be-valid.js";
@@ -13,20 +26,25 @@ export * from "./html-attribute-double-quotes.js";
13
26
  export * from "./html-attribute-equals-spacing.js";
14
27
  export * from "./html-attribute-values-require-quotes.js";
15
28
  export * from "./html-avoid-both-disabled-and-aria-disabled.js";
29
+ export * from "./html-body-only-elements.js";
16
30
  export * from "./html-boolean-attributes-no-value.js";
31
+ export * from "./html-head-only-elements.js";
17
32
  export * from "./html-iframe-has-title.js";
18
33
  export * from "./html-img-require-alt.js";
34
+ export * from "./html-input-require-autocomplete.js";
19
35
  export * from "./html-navigation-has-label.js";
20
36
  export * from "./html-no-aria-hidden-on-focusable.js";
21
37
  export * from "./html-no-block-inside-inline.js";
22
38
  export * from "./html-no-duplicate-attributes.js";
23
39
  export * from "./html-no-duplicate-ids.js";
40
+ export * from "./html-no-duplicate-meta-names.js";
24
41
  export * from "./html-no-empty-attributes.js";
25
42
  export * from "./html-no-empty-headings.js";
26
43
  export * from "./html-no-nested-links.js";
27
44
  export * from "./html-no-positive-tab-index.js";
28
45
  export * from "./html-no-self-closing.js";
46
+ export * from "./html-no-space-in-tag.js";
29
47
  export * from "./html-no-title-attribute.js";
48
+ export * from "./html-no-underscores-in-attribute-names.js";
30
49
  export * from "./html-tag-name-lowercase.js";
31
50
  export * from "./svg-tag-name-capitalization.js";
32
- export * from "./html-no-underscores-in-attribute-names.js";
@@ -1,8 +1,9 @@
1
1
  import { ParserRule } from "../types.js";
2
- import type { LintOffense } from "../types.js";
2
+ import type { LintOffense, FullRuleConfig } from "../types.js";
3
3
  import type { ParseResult } from "@herb-tools/core";
4
4
  export declare class ParserNoErrorsRule extends ParserRule {
5
5
  name: string;
6
+ get defaultConfig(): FullRuleConfig;
6
7
  check(result: ParseResult): LintOffense[];
7
8
  private herbErrorToLintOffense;
8
9
  }
@@ -1,7 +1,7 @@
1
1
  import { Visitor, Location } from "@herb-tools/core";
2
- import type { HTMLAttributeNode, HTMLAttributeValueNode, HTMLOpenTagNode, LexResult, Token, Node } from "@herb-tools/core";
2
+ import type { HTMLAttributeNode, HTMLAttributeValueNode, HTMLElementNode, HTMLOpenTagNode, LexResult, Token, Node } from "@herb-tools/core";
3
3
  import type * as Nodes from "@herb-tools/core";
4
- import type { LintOffense, LintSeverity, LintContext } from "../types.js";
4
+ import type { UnboundLintOffense, LintContext, BaseAutofixContext } from "../types.js";
5
5
  export declare enum ControlFlowType {
6
6
  CONDITIONAL = 0,
7
7
  LOOP = 1
@@ -9,35 +9,37 @@ export declare enum ControlFlowType {
9
9
  /**
10
10
  * Base visitor class that provides common functionality for rule visitors
11
11
  */
12
- export declare abstract class BaseRuleVisitor extends Visitor {
13
- readonly offenses: LintOffense[];
12
+ export declare abstract class BaseRuleVisitor<TAutofixContext extends BaseAutofixContext = BaseAutofixContext> extends Visitor {
13
+ readonly offenses: UnboundLintOffense<TAutofixContext>[];
14
14
  protected ruleName: string;
15
15
  protected context: LintContext;
16
16
  constructor(ruleName: string, context?: Partial<LintContext>);
17
17
  /**
18
- * Helper method to create a lint offense
18
+ * Helper method to create an unbound lint offense (without severity).
19
+ * The Linter will bind severity based on the rule's config.
19
20
  */
20
- protected createOffense(message: string, location: Location, severity?: LintSeverity): LintOffense;
21
+ protected createOffense(message: string, location: Location, autofixContext?: TAutofixContext): UnboundLintOffense<TAutofixContext>;
21
22
  /**
22
23
  * Helper method to add an offense to the offenses array
23
24
  */
24
- protected addOffense(message: string, location: Location, severity?: LintSeverity): void;
25
+ protected addOffense(message: string, location: Location, autofixContext?: TAutofixContext): void;
25
26
  }
26
27
  /**
27
28
  * Mixin that adds control flow tracking capabilities to rule visitors
28
29
  * This allows rules to track state across different control flow structures
29
30
  * like if/else branches, loops, etc.
30
31
  *
32
+ * @template TAutofixContext - Type for autofix context (node + custom data)
31
33
  * @template TControlFlowState - Type for state passed between onEnterControlFlow and onExitControlFlow
32
34
  * @template TBranchState - Type for state passed between onEnterBranch and onExitBranch
33
35
  */
34
- export declare abstract class ControlFlowTrackingVisitor<TControlFlowState = any, TBranchState = any> extends BaseRuleVisitor {
36
+ export declare abstract class ControlFlowTrackingVisitor<TAutofixContext extends BaseAutofixContext = BaseAutofixContext, TControlFlowState = any, TBranchState = any> extends BaseRuleVisitor<TAutofixContext> {
35
37
  protected isInControlFlow: boolean;
36
38
  protected currentControlFlowType: ControlFlowType | null;
37
39
  /**
38
40
  * Handle visiting a control flow node with proper scope management
39
41
  */
40
- protected handleControlFlowNode(node: Node, controlFlowType: ControlFlowType, visitChildren: () => void): void;
42
+ protected handleControlFlowNode(_node: Node, controlFlowType: ControlFlowType, visitChildren: () => void): void;
41
43
  /**
42
44
  * Handle visiting a branch node (like else, when) with proper scope management
43
45
  */
@@ -64,7 +66,7 @@ export declare function getAttributes(node: HTMLOpenTagNode): HTMLAttributeNode[
64
66
  /**
65
67
  * Gets the tag name from an HTML tag node (lowercased)
66
68
  */
67
- export declare function getTagName(node: HTMLOpenTagNode): string | null;
69
+ export declare function getTagName(node: HTMLElementNode | HTMLOpenTagNode | null | undefined): string | null;
68
70
  /**
69
71
  * Gets the attribute name from an HTMLAttributeNode (lowercased)
70
72
  * Returns null if the attribute name contains dynamic content (ERB)
@@ -210,7 +212,7 @@ export declare function isBooleanAttribute(attributeName: string): boolean;
210
212
  * - checkDynamicAttributeStaticValue() - name="data-<%= key %>" value="foo"
211
213
  * - checkDynamicAttributeDynamicValue() - name="data-<%= key %>" value="<%= value %>"
212
214
  */
213
- export declare abstract class AttributeVisitorMixin extends BaseRuleVisitor {
215
+ export declare abstract class AttributeVisitorMixin<TAutofixContext extends BaseAutofixContext = BaseAutofixContext> extends BaseRuleVisitor<TAutofixContext> {
214
216
  constructor(ruleName: string, context?: Partial<LintContext>);
215
217
  visitHTMLOpenTagNode(node: HTMLOpenTagNode): void;
216
218
  private checkAttributesOnNode;
@@ -242,19 +244,20 @@ export declare function forEachAttribute(node: HTMLOpenTagNode, callback: (attri
242
244
  /**
243
245
  * Base lexer visitor class that provides common functionality for lexer-based rule visitors
244
246
  */
245
- export declare abstract class BaseLexerRuleVisitor {
246
- readonly offenses: LintOffense[];
247
+ export declare abstract class BaseLexerRuleVisitor<TAutofixContext extends BaseAutofixContext = BaseAutofixContext> {
248
+ readonly offenses: UnboundLintOffense<TAutofixContext>[];
247
249
  protected ruleName: string;
248
250
  protected context: LintContext;
249
251
  constructor(ruleName: string, context?: Partial<LintContext>);
250
252
  /**
251
- * Helper method to create a lint offense for lexer rules
253
+ * Helper method to create an unbound lint offense (without severity).
254
+ * The Linter will bind severity based on the rule's config.
252
255
  */
253
- protected createOffense(message: string, location: Location, severity?: LintSeverity): LintOffense;
256
+ protected createOffense(message: string, location: Location, autofixContext?: TAutofixContext): UnboundLintOffense<TAutofixContext>;
254
257
  /**
255
258
  * Helper method to add an offense to the offenses array
256
259
  */
257
- protected addOffense(message: string, location: Location, severity?: LintSeverity): void;
260
+ protected addOffense(message: string, location: Location, autofixContext?: TAutofixContext): void;
258
261
  /**
259
262
  * Main entry point for lexer rule visitors
260
263
  * @param lexResult - The lexer result containing tokens and source
@@ -274,19 +277,20 @@ export declare abstract class BaseLexerRuleVisitor {
274
277
  /**
275
278
  * Base source visitor class that provides common functionality for source-based rule visitors
276
279
  */
277
- export declare abstract class BaseSourceRuleVisitor {
278
- readonly offenses: LintOffense[];
280
+ export declare abstract class BaseSourceRuleVisitor<TAutofixContext extends BaseAutofixContext = BaseAutofixContext> {
281
+ readonly offenses: UnboundLintOffense<TAutofixContext>[];
279
282
  protected ruleName: string;
280
283
  protected context: LintContext;
281
284
  constructor(ruleName: string, context?: Partial<LintContext>);
282
285
  /**
283
- * Helper method to create a lint offense for source rules
286
+ * Helper method to create an unbound lint offense (without severity).
287
+ * The Linter will bind severity based on the rule's config.
284
288
  */
285
- protected createOffense(message: string, location: Location, severity?: LintSeverity): LintOffense;
289
+ protected createOffense(message: string, location: Location, autofixContext?: TAutofixContext): UnboundLintOffense<TAutofixContext>;
286
290
  /**
287
291
  * Helper method to add an offense to the offenses array
288
292
  */
289
- protected addOffense(message: string, location: Location, severity?: LintSeverity): void;
293
+ protected addOffense(message: string, location: Location, autofixContext?: TAutofixContext): void;
290
294
  /**
291
295
  * Main entry point for source rule visitors
292
296
  * @param source - The raw source code
@@ -297,8 +301,51 @@ export declare abstract class BaseSourceRuleVisitor {
297
301
  * Override this method to implement source-level checks
298
302
  */
299
303
  protected abstract visitSource(source: string): void;
300
- /**
301
- * Helper method to create a location for a specific position in the source
302
- */
303
- protected createLocationAt(source: string, position: number): Location;
304
304
  }
305
+ /**
306
+ * Autofix utilities for applying string replacements
307
+ */
308
+ /**
309
+ * Checks if two locations are equal
310
+ * @param a - First location
311
+ * @param b - Second location
312
+ * @returns true if locations are equal
313
+ */
314
+ export declare function locationsEqual(a: Location, b: Location): boolean;
315
+ /**
316
+ * Finds a node in the AST that has a specific location
317
+ * Uses direct recursive traversal for reliability
318
+ * @param root - The root node to search from
319
+ * @param location - The location to match
320
+ * @param predicate - Optional predicate function to filter nodes (e.g., isERBNode)
321
+ * @returns The matching node or null if not found
322
+ */
323
+ export declare function findNodeByLocation(root: Node, location: Location, predicate?: (node: Node) => boolean): any;
324
+ /**
325
+ * AST Navigation Utilities
326
+ * These utilities help navigate the AST tree for complex autofix operations
327
+ */
328
+ /**
329
+ * Finds the parent node of a given child node in the AST
330
+ * @param root - The root node to search from (typically the document node)
331
+ * @param target - The child node to find the parent of
332
+ * @returns The parent node, or null if not found
333
+ *
334
+ * @example
335
+ * const parent = findParent(result.value, offense.autofixContext.node)
336
+ * if (parent?.type === "AST_HTML_ELEMENT_NODE") {
337
+ * // Modify parent...
338
+ * }
339
+ */
340
+ export declare function findParent(root: Node, target: Node): Node | null;
341
+ export declare const DOCUMENT_ONLY_TAG_NAMES: Set<string>;
342
+ export declare const HTML_ONLY_TAG_NAMES: Set<string>;
343
+ export declare const HEAD_ONLY_TAG_NAMES: Set<string>;
344
+ export declare const HEAD_AND_BODY_TAG_NAMES: Set<string>;
345
+ export declare function isDocumentOnlyTag(tagName: string): boolean;
346
+ export declare function isHtmlOnlyTag(tagName: string): boolean;
347
+ export declare function isHeadOnlyTag(tagName: string): boolean;
348
+ export declare function isHeadAndBodyTag(tagName: string): boolean;
349
+ export declare function isBodyOnlyTag(tagName: string): boolean;
350
+ export declare function isBodyTag(tagName: string): boolean;
351
+ export declare function isHeadTag(tagName: string): boolean;
@@ -1,7 +1,16 @@
1
1
  import { ParserRule } from "../types.js";
2
- import type { LintOffense, LintContext } from "../types.js";
3
- import type { ParseResult } from "@herb-tools/core";
4
- export declare class SVGTagNameCapitalizationRule extends ParserRule {
2
+ import type { UnboundLintOffense, LintOffense, LintContext, BaseAutofixContext, Mutable, FullRuleConfig } from "../types.js";
3
+ import type { HTMLOpenTagNode, HTMLCloseTagNode, ParseResult } from "@herb-tools/core";
4
+ interface SVGTagNameCapitalizationAutofixContext extends BaseAutofixContext {
5
+ node: Mutable<HTMLOpenTagNode | HTMLCloseTagNode>;
6
+ currentTagName: string;
7
+ correctCamelCase: string;
8
+ }
9
+ export declare class SVGTagNameCapitalizationRule extends ParserRule<SVGTagNameCapitalizationAutofixContext> {
10
+ static autocorrectable: boolean;
5
11
  name: string;
6
- check(result: ParseResult, context?: Partial<LintContext>): LintOffense[];
12
+ get defaultConfig(): FullRuleConfig;
13
+ check(result: ParseResult, context?: Partial<LintContext>): UnboundLintOffense<SVGTagNameCapitalizationAutofixContext>[];
14
+ autofix(offense: LintOffense<SVGTagNameCapitalizationAutofixContext>, result: ParseResult, _context?: Partial<LintContext>): ParseResult | null;
7
15
  }
16
+ export {};
@@ -0,0 +1,2 @@
1
+ import type { RuleClass } from "./types.js";
2
+ export declare const rules: RuleClass[];
@@ -1,24 +1,76 @@
1
1
  import { Diagnostic, LexResult, ParseResult } from "@herb-tools/core";
2
- import type { defaultRules } from "./default-rules.js";
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 defaultRules[number]>['name'];
9
- export interface LintOffense extends Diagnostic {
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
- export declare abstract class ParserRule {
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
- abstract check(result: ParseResult, context?: Partial<LintContext>): LintOffense[];
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
- export declare abstract class LexerRule {
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
- abstract check(lexResult: LexResult, context?: Partial<LintContext>): LintOffense[];
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
- abstract check(source: string, context?: Partial<LintContext>): LintOffense[];
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";