@herb-tools/linter 0.4.2 → 0.5.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 (202) hide show
  1. package/README.md +221 -10
  2. package/dist/herb-lint.js +817 -292
  3. package/dist/herb-lint.js.map +1 -1
  4. package/dist/index.cjs +360 -81
  5. package/dist/index.cjs.map +1 -1
  6. package/dist/index.js +355 -83
  7. package/dist/index.js.map +1 -1
  8. package/dist/package.json +4 -4
  9. package/dist/src/cli/argument-parser.js +28 -18
  10. package/dist/src/cli/argument-parser.js.map +1 -1
  11. package/dist/src/cli/file-processor.js +21 -17
  12. package/dist/src/cli/file-processor.js.map +1 -1
  13. package/dist/src/cli/formatters/detailed-formatter.js +9 -9
  14. package/dist/src/cli/formatters/detailed-formatter.js.map +1 -1
  15. package/dist/src/cli/formatters/github-actions-formatter.js +50 -0
  16. package/dist/src/cli/formatters/github-actions-formatter.js.map +1 -0
  17. package/dist/src/cli/formatters/index.js +2 -0
  18. package/dist/src/cli/formatters/index.js.map +1 -1
  19. package/dist/src/cli/formatters/json-formatter.js +58 -0
  20. package/dist/src/cli/formatters/json-formatter.js.map +1 -0
  21. package/dist/src/cli/formatters/simple-formatter.js +15 -15
  22. package/dist/src/cli/formatters/simple-formatter.js.map +1 -1
  23. package/dist/src/cli/output-manager.js +120 -0
  24. package/dist/src/cli/output-manager.js.map +1 -0
  25. package/dist/src/cli/summary-reporter.js +22 -22
  26. package/dist/src/cli/summary-reporter.js.map +1 -1
  27. package/dist/src/cli.js +41 -26
  28. package/dist/src/cli.js.map +1 -1
  29. package/dist/src/default-rules.js +8 -0
  30. package/dist/src/default-rules.js.map +1 -1
  31. package/dist/src/linter.js +37 -6
  32. package/dist/src/linter.js.map +1 -1
  33. package/dist/src/rules/erb-no-empty-tags.js +5 -4
  34. package/dist/src/rules/erb-no-empty-tags.js.map +1 -1
  35. package/dist/src/rules/erb-no-output-control-flow.js +5 -4
  36. package/dist/src/rules/erb-no-output-control-flow.js.map +1 -1
  37. package/dist/src/rules/erb-prefer-image-tag-helper.js +93 -0
  38. package/dist/src/rules/erb-prefer-image-tag-helper.js.map +1 -0
  39. package/dist/src/rules/erb-require-whitespace-inside-tags.js +5 -4
  40. package/dist/src/rules/erb-require-whitespace-inside-tags.js.map +1 -1
  41. package/dist/src/rules/erb-requires-trailing-newline.js +22 -0
  42. package/dist/src/rules/erb-requires-trailing-newline.js.map +1 -0
  43. package/dist/src/rules/html-anchor-require-href.js +5 -4
  44. package/dist/src/rules/html-anchor-require-href.js.map +1 -1
  45. package/dist/src/rules/html-aria-attribute-must-be-valid.js +5 -4
  46. package/dist/src/rules/html-aria-attribute-must-be-valid.js.map +1 -1
  47. package/dist/src/rules/html-aria-level-must-be-valid.js +27 -0
  48. package/dist/src/rules/html-aria-level-must-be-valid.js.map +1 -0
  49. package/dist/src/rules/html-aria-role-heading-requires-level.js +5 -4
  50. package/dist/src/rules/html-aria-role-heading-requires-level.js.map +1 -1
  51. package/dist/src/rules/html-aria-role-must-be-valid.js +5 -4
  52. package/dist/src/rules/html-aria-role-must-be-valid.js.map +1 -1
  53. package/dist/src/rules/html-attribute-double-quotes.js +5 -4
  54. package/dist/src/rules/html-attribute-double-quotes.js.map +1 -1
  55. package/dist/src/rules/html-attribute-values-require-quotes.js +5 -4
  56. package/dist/src/rules/html-attribute-values-require-quotes.js.map +1 -1
  57. package/dist/src/rules/html-boolean-attributes-no-value.js +5 -4
  58. package/dist/src/rules/html-boolean-attributes-no-value.js.map +1 -1
  59. package/dist/src/rules/html-img-require-alt.js +5 -4
  60. package/dist/src/rules/html-img-require-alt.js.map +1 -1
  61. package/dist/src/rules/html-no-block-inside-inline.js +7 -6
  62. package/dist/src/rules/html-no-block-inside-inline.js.map +1 -1
  63. package/dist/src/rules/html-no-duplicate-attributes.js +5 -4
  64. package/dist/src/rules/html-no-duplicate-attributes.js.map +1 -1
  65. package/dist/src/rules/html-no-duplicate-ids.js +5 -4
  66. package/dist/src/rules/html-no-duplicate-ids.js.map +1 -1
  67. package/dist/src/rules/html-no-empty-headings.js +5 -4
  68. package/dist/src/rules/html-no-empty-headings.js.map +1 -1
  69. package/dist/src/rules/html-no-nested-links.js +5 -4
  70. package/dist/src/rules/html-no-nested-links.js.map +1 -1
  71. package/dist/src/rules/html-tag-name-lowercase.js +5 -4
  72. package/dist/src/rules/html-tag-name-lowercase.js.map +1 -1
  73. package/dist/src/rules/index.js +3 -0
  74. package/dist/src/rules/index.js.map +1 -1
  75. package/dist/src/rules/parser-no-errors.js +18 -0
  76. package/dist/src/rules/parser-no-errors.js.map +1 -0
  77. package/dist/src/rules/rule-utils.js +125 -2
  78. package/dist/src/rules/rule-utils.js.map +1 -1
  79. package/dist/src/rules/svg-tag-name-capitalization.js +5 -4
  80. package/dist/src/rules/svg-tag-name-capitalization.js.map +1 -1
  81. package/dist/src/types.js +15 -1
  82. package/dist/src/types.js.map +1 -1
  83. package/dist/tsconfig.tsbuildinfo +1 -1
  84. package/dist/types/cli/argument-parser.d.ts +2 -1
  85. package/dist/types/cli/file-processor.d.ts +6 -5
  86. package/dist/types/cli/formatters/base-formatter.d.ts +2 -2
  87. package/dist/types/cli/formatters/detailed-formatter.d.ts +2 -2
  88. package/dist/types/cli/formatters/github-actions-formatter.d.ts +12 -0
  89. package/dist/types/cli/formatters/index.d.ts +2 -0
  90. package/dist/types/cli/formatters/json-formatter.d.ts +42 -0
  91. package/dist/types/cli/formatters/simple-formatter.d.ts +2 -2
  92. package/dist/types/cli/output-manager.d.ts +31 -0
  93. package/dist/types/cli/summary-reporter.d.ts +3 -3
  94. package/dist/types/cli.d.ts +3 -1
  95. package/dist/types/linter.d.ts +20 -5
  96. package/dist/types/rules/erb-no-empty-tags.d.ts +5 -4
  97. package/dist/types/rules/erb-no-output-control-flow.d.ts +5 -4
  98. package/dist/types/rules/erb-prefer-image-tag-helper.d.ts +7 -0
  99. package/dist/types/rules/erb-require-whitespace-inside-tags.d.ts +5 -4
  100. package/dist/types/rules/erb-requires-trailing-newline.d.ts +6 -0
  101. package/dist/types/rules/html-anchor-require-href.d.ts +5 -4
  102. package/dist/types/rules/html-aria-attribute-must-be-valid.d.ts +5 -4
  103. package/dist/types/rules/html-aria-level-must-be-valid.d.ts +7 -0
  104. package/dist/types/rules/html-aria-role-heading-requires-level.d.ts +5 -4
  105. package/dist/types/rules/html-aria-role-must-be-valid.d.ts +5 -4
  106. package/dist/types/rules/html-attribute-double-quotes.d.ts +5 -4
  107. package/dist/types/rules/html-attribute-values-require-quotes.d.ts +5 -4
  108. package/dist/types/rules/html-boolean-attributes-no-value.d.ts +5 -4
  109. package/dist/types/rules/html-img-require-alt.d.ts +5 -4
  110. package/dist/types/rules/html-no-block-inside-inline.d.ts +5 -4
  111. package/dist/types/rules/html-no-duplicate-attributes.d.ts +5 -4
  112. package/dist/types/rules/html-no-duplicate-ids.d.ts +5 -4
  113. package/dist/types/rules/html-no-empty-headings.d.ts +5 -4
  114. package/dist/types/rules/html-no-nested-links.d.ts +5 -4
  115. package/dist/types/rules/html-tag-name-lowercase.d.ts +5 -4
  116. package/dist/types/rules/index.d.ts +3 -0
  117. package/dist/types/rules/parser-no-errors.d.ts +8 -0
  118. package/dist/types/rules/rule-utils.d.ts +73 -4
  119. package/dist/types/rules/svg-tag-name-capitalization.d.ts +5 -4
  120. package/dist/types/src/cli/argument-parser.d.ts +2 -1
  121. package/dist/types/src/cli/file-processor.d.ts +6 -5
  122. package/dist/types/src/cli/formatters/base-formatter.d.ts +2 -2
  123. package/dist/types/src/cli/formatters/detailed-formatter.d.ts +2 -2
  124. package/dist/types/src/cli/formatters/github-actions-formatter.d.ts +12 -0
  125. package/dist/types/src/cli/formatters/index.d.ts +2 -0
  126. package/dist/types/src/cli/formatters/json-formatter.d.ts +42 -0
  127. package/dist/types/src/cli/formatters/simple-formatter.d.ts +2 -2
  128. package/dist/types/src/cli/output-manager.d.ts +31 -0
  129. package/dist/types/src/cli/summary-reporter.d.ts +3 -3
  130. package/dist/types/src/cli.d.ts +3 -1
  131. package/dist/types/src/linter.d.ts +20 -5
  132. package/dist/types/src/rules/erb-no-empty-tags.d.ts +5 -4
  133. package/dist/types/src/rules/erb-no-output-control-flow.d.ts +5 -4
  134. package/dist/types/src/rules/erb-prefer-image-tag-helper.d.ts +7 -0
  135. package/dist/types/src/rules/erb-require-whitespace-inside-tags.d.ts +5 -4
  136. package/dist/types/src/rules/erb-requires-trailing-newline.d.ts +6 -0
  137. package/dist/types/src/rules/html-anchor-require-href.d.ts +5 -4
  138. package/dist/types/src/rules/html-aria-attribute-must-be-valid.d.ts +5 -4
  139. package/dist/types/src/rules/html-aria-level-must-be-valid.d.ts +7 -0
  140. package/dist/types/src/rules/html-aria-role-heading-requires-level.d.ts +5 -4
  141. package/dist/types/src/rules/html-aria-role-must-be-valid.d.ts +5 -4
  142. package/dist/types/src/rules/html-attribute-double-quotes.d.ts +5 -4
  143. package/dist/types/src/rules/html-attribute-values-require-quotes.d.ts +5 -4
  144. package/dist/types/src/rules/html-boolean-attributes-no-value.d.ts +5 -4
  145. package/dist/types/src/rules/html-img-require-alt.d.ts +5 -4
  146. package/dist/types/src/rules/html-no-block-inside-inline.d.ts +5 -4
  147. package/dist/types/src/rules/html-no-duplicate-attributes.d.ts +5 -4
  148. package/dist/types/src/rules/html-no-duplicate-ids.d.ts +5 -4
  149. package/dist/types/src/rules/html-no-empty-headings.d.ts +5 -4
  150. package/dist/types/src/rules/html-no-nested-links.d.ts +5 -4
  151. package/dist/types/src/rules/html-tag-name-lowercase.d.ts +5 -4
  152. package/dist/types/src/rules/index.d.ts +3 -0
  153. package/dist/types/src/rules/parser-no-errors.d.ts +8 -0
  154. package/dist/types/src/rules/rule-utils.d.ts +73 -4
  155. package/dist/types/src/rules/svg-tag-name-capitalization.d.ts +5 -4
  156. package/dist/types/src/types.d.ts +50 -7
  157. package/dist/types/types.d.ts +50 -7
  158. package/docs/rules/README.md +5 -1
  159. package/docs/rules/erb-prefer-image-tag-helper.md +65 -0
  160. package/docs/rules/erb-requires-trailing-newline.md +37 -0
  161. package/docs/rules/html-anchor-require-href.md +1 -1
  162. package/docs/rules/html-aria-level-must-be-valid.md +37 -0
  163. package/docs/rules/parser-no-errors.md +84 -0
  164. package/package.json +4 -4
  165. package/src/cli/argument-parser.ts +33 -19
  166. package/src/cli/file-processor.ts +27 -21
  167. package/src/cli/formatters/base-formatter.ts +2 -2
  168. package/src/cli/formatters/detailed-formatter.ts +9 -9
  169. package/src/cli/formatters/github-actions-formatter.ts +70 -0
  170. package/src/cli/formatters/index.ts +2 -0
  171. package/src/cli/formatters/json-formatter.ts +107 -0
  172. package/src/cli/formatters/simple-formatter.ts +15 -15
  173. package/src/cli/output-manager.ts +143 -0
  174. package/src/cli/summary-reporter.ts +24 -24
  175. package/src/cli.ts +48 -31
  176. package/src/default-rules.ts +8 -0
  177. package/src/linter.ts +42 -8
  178. package/src/rules/erb-no-empty-tags.ts +7 -6
  179. package/src/rules/erb-no-output-control-flow.ts +8 -6
  180. package/src/rules/erb-prefer-image-tag-helper.ts +124 -0
  181. package/src/rules/erb-require-whitespace-inside-tags.ts +7 -6
  182. package/src/rules/erb-requires-trailing-newline.ts +29 -0
  183. package/src/rules/html-anchor-require-href.ts +7 -6
  184. package/src/rules/html-aria-attribute-must-be-valid.ts +7 -7
  185. package/src/rules/html-aria-level-must-be-valid.ts +42 -0
  186. package/src/rules/html-aria-role-heading-requires-level.ts +7 -6
  187. package/src/rules/html-aria-role-must-be-valid.ts +7 -6
  188. package/src/rules/html-attribute-double-quotes.ts +7 -6
  189. package/src/rules/html-attribute-values-require-quotes.ts +7 -6
  190. package/src/rules/html-boolean-attributes-no-value.ts +7 -6
  191. package/src/rules/html-img-require-alt.ts +7 -6
  192. package/src/rules/html-no-block-inside-inline.ts +9 -8
  193. package/src/rules/html-no-duplicate-attributes.ts +7 -6
  194. package/src/rules/html-no-duplicate-ids.ts +7 -7
  195. package/src/rules/html-no-empty-headings.ts +7 -6
  196. package/src/rules/html-no-nested-links.ts +7 -6
  197. package/src/rules/html-tag-name-lowercase.ts +7 -6
  198. package/src/rules/index.ts +3 -0
  199. package/src/rules/parser-no-errors.ts +25 -0
  200. package/src/rules/rule-utils.ts +156 -4
  201. package/src/rules/svg-tag-name-capitalization.ts +7 -6
  202. package/src/types.ts +61 -7
package/README.md CHANGED
@@ -6,27 +6,238 @@
6
6
 
7
7
  The Herb Linter provides comprehensive HTML+ERB validation with a set of configurable rules to enforce best practices and catch common errors.
8
8
 
9
+ ## Installation
10
+
11
+ ### Global Installation
12
+
13
+ :::code-group
14
+
15
+ ```shell [npm]
16
+ npm install -g @herb-tools/linter
17
+ ```
18
+
19
+ ```shell [pnpm]
20
+ pnpm add -g @herb-tools/linter
21
+ ```
22
+
23
+ ```shell [yarn]
24
+ yarn global add @herb-tools/linter
25
+ ```
26
+
27
+ ```shell [bun]
28
+ bun add -g @herb-tools/linter
29
+ ```
30
+
31
+ :::
32
+
33
+ Then run directly:
34
+ ```bash
35
+ herb-lint template.html.erb
36
+ ```
37
+
38
+ ### One-time Usage
39
+ For occasional use without installing:
40
+ ```bash
41
+ npx @herb-tools/linter template.html.erb
42
+ ```
43
+
44
+ ### Project Installation
45
+
46
+ :::code-group
47
+
48
+ ```shell [npm]
49
+ npm add -D @herb-tools/linter
50
+ ```
51
+
52
+ ```shell [pnpm]
53
+ pnpm add -D @herb-tools/linter
54
+ ```
55
+
56
+ ```shell [yarn]
57
+ yarn add -D @herb-tools/linter
58
+ ```
59
+
60
+ ```shell [bun]
61
+ bun add -D @herb-tools/linter
62
+ ```
63
+
64
+ :::
65
+
66
+ After installing as a dev dependency, add a lint NPM script to your `package.json`:
67
+ ```json
68
+ {
69
+ "scripts": {
70
+ "herb:lint": "herb-lint '**/*.html.erb'"
71
+ }
72
+ }
73
+ ```
74
+
75
+ Then run the scripts:
76
+
77
+ :::code-group
78
+
79
+ ```shell [npm]
80
+ npm run herb:lint
81
+ ```
82
+
83
+ ```shell [pnpm]
84
+ pnpm herb:lint
85
+ ```
86
+
87
+ ```shell [yarn]
88
+ yarn herb:lint
89
+ ```
90
+
91
+ ```shell [bun]
92
+ bun run herb:lint
93
+ ```
94
+
95
+ :::
96
+
9
97
  ## Usage
10
98
 
11
99
  ### Command Line
100
+
101
+ Basic usage:
12
102
  ```bash
13
103
  npx @herb-tools/linter template.html.erb
104
+ npx @herb-tools/linter "**/*.html.erb"
105
+ npx @herb-tools/linter app/
14
106
  ```
15
107
 
16
- ### Language Server Integration
108
+ #### Options
17
109
 
18
- The linter is automatically integrated into the [Herb Language Server](https://herb-tools.dev/projects/language-server), providing real-time validation in supported editors like VS Code, Zed, and Neovim.
110
+ **Output Format:**
111
+ ```bash
112
+ # Use detailed output (default)
113
+ npx @herb-tools/linter template.html.erb --format detailed
19
114
 
20
- ## Configuration
115
+ # Use simple output format
116
+ npx @herb-tools/linter template.html.erb --simple
117
+ # or
118
+ npx @herb-tools/linter template.html.erb --format simple
119
+
120
+ # Use JSON output format
121
+ npx @herb-tools/linter template.html.erb --json
122
+ # or
123
+ npx @herb-tools/linter template.html.erb --format json
124
+
125
+ # Use GitHub Actions output format
126
+ npx @herb-tools/linter template.html.erb --github
127
+ # or
128
+ npx @herb-tools/linter template.html.erb --format github
129
+ ```
130
+
131
+ **Display Options:**
132
+ ```bash
133
+ # Disable colored output
134
+ npx @herb-tools/linter template.html.erb --no-color
21
135
 
22
- By default, all rules are enabled. You can customize the rules by passing a custom set to the Linter constructor:
136
+ # Set syntax highlighting theme
137
+ npx @herb-tools/linter template.html.erb --theme github-dark
23
138
 
24
- ```typescript
25
- import { Linter, HTMLTagNameLowercaseRule } from "@herb-tools/linter"
139
+ # Disable timing information
140
+ npx @herb-tools/linter template.html.erb --no-timing
26
141
 
27
- // Only run specific rules
28
- const linter = new Linter([HTMLTagNameLowercaseRule])
142
+ # Disable line wrapping
143
+ npx @herb-tools/linter template.html.erb --no-wrap-lines
29
144
 
30
- // Run with no rules (disabled)
31
- const linter = new Linter([])
145
+ # Enable line truncation (mutually exclusive with line wrapping)
146
+ npx @herb-tools/linter template.html.erb --truncate-lines --no-wrap-lines
32
147
  ```
148
+
149
+ **Help and Version:**
150
+ ```bash
151
+ # Show help
152
+ npx @herb-tools/linter --help
153
+
154
+ # Show version information
155
+ npx @herb-tools/linter --version
156
+ ```
157
+
158
+ #### GitHub Actions Output Format
159
+
160
+ The linter supports GitHub Actions annotation format with the `--github` flag, which outputs errors and warnings in a format that GitHub Actions can parse to create inline annotations in pull requests:
161
+
162
+ ```bash
163
+ npx @herb-tools/linter "**/*.html.erb" --github
164
+ ```
165
+
166
+ Example output:
167
+ ```
168
+ ::error file=template.html.erb,line=5,col=5::File must end with trailing newline [erb-requires-trailing-newline]
169
+ ::warning file=template.html.erb,line=3,col=10::Consider using semantic HTML tags [html-semantic-tags]
170
+ ```
171
+
172
+ This format is ideal for CI/CD workflows in GitHub Actions:
173
+
174
+ ```yaml [.github/workflows/herb-lint.yml]
175
+ name: Herb Lint
176
+ on: [push, pull_request]
177
+
178
+ jobs:
179
+ lint:
180
+ runs-on: ubuntu-latest
181
+ steps:
182
+ - uses: actions/checkout@v4
183
+ - uses: actions/setup-node@v4
184
+ - run: npx @herb-tools/linter "**/*.html.erb" --github
185
+ ```
186
+
187
+ #### JSON Output Format
188
+
189
+ The linter supports structured JSON output with the `--json` flag, useful for programmatic consumption:
190
+
191
+ ```bash
192
+ npx @herb-tools/linter template.html.erb --json
193
+ ```
194
+
195
+ <details>
196
+ <summary>Example output:</summary>
197
+
198
+ ```json
199
+ {
200
+ "offenses": [
201
+ {
202
+ "filename": "template.html.erb",
203
+ "message": "File must end with trailing newline",
204
+ "location": {
205
+ "start": { "line": 1, "column": 21 },
206
+ "end": { "line": 1, "column": 22 }
207
+ },
208
+ "severity": "error",
209
+ "code": "erb-requires-trailing-newline",
210
+ "source": "Herb Linter"
211
+ }
212
+ ],
213
+ "summary": {
214
+ "filesChecked": 1,
215
+ "filesWithOffenses": 1,
216
+ "totalErrors": 1,
217
+ "totalWarnings": 0,
218
+ "totalOffenses": 1,
219
+ "ruleCount": 21
220
+ },
221
+ "timing": {
222
+ "startTime": "2025-08-14T16:00:48.845Z",
223
+ "duration": 27
224
+ },
225
+ "completed": true,
226
+ "clean": false,
227
+ "message": null
228
+ }
229
+ ```
230
+
231
+ </details>
232
+
233
+ JSON output fields:
234
+ - `offenses`: Array of linting offenses with location and severity
235
+ - `summary`: Statistics about the linting run (null on errors)
236
+ - `timing`: Timing information with ISO timestamp (null with `--no-timing`)
237
+ - `completed`: Whether the linter ran successfully on files
238
+ - `clean`: Whether there were no offenses (null when `completed=false`)
239
+ - `message`: Error or informational message (null on success)
240
+
241
+ ### Language Server Integration
242
+
243
+ The linter is automatically integrated into the [Herb Language Server](https://herb-tools.dev/projects/language-server), providing real-time validation in supported editors like VS Code, Zed, and Neovim.