@herb-tools/linter 0.4.0 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/README.md +1 -1
  2. package/dist/herb-lint.js +161 -101
  3. package/dist/herb-lint.js.map +1 -1
  4. package/dist/index.cjs +215 -67
  5. package/dist/index.cjs.map +1 -1
  6. package/dist/index.js +213 -68
  7. package/dist/index.js.map +1 -1
  8. package/dist/package.json +4 -4
  9. package/dist/src/default-rules.js +8 -2
  10. package/dist/src/default-rules.js.map +1 -1
  11. package/dist/src/rules/html-aria-attribute-must-be-valid.js +24 -0
  12. package/dist/src/rules/html-aria-attribute-must-be-valid.js.map +1 -0
  13. package/dist/src/rules/html-aria-role-must-be-valid.js +21 -0
  14. package/dist/src/rules/html-aria-role-must-be-valid.js.map +1 -0
  15. package/dist/src/rules/html-no-duplicate-ids.js +25 -0
  16. package/dist/src/rules/html-no-duplicate-ids.js.map +1 -0
  17. package/dist/src/rules/index.js +3 -0
  18. package/dist/src/rules/index.js.map +1 -1
  19. package/dist/src/rules/rule-utils.js +83 -8
  20. package/dist/src/rules/rule-utils.js.map +1 -1
  21. package/dist/tsconfig.tsbuildinfo +1 -1
  22. package/dist/types/rules/html-aria-attribute-must-be-valid.d.ts +6 -0
  23. package/dist/types/rules/html-aria-role-must-be-valid.d.ts +6 -0
  24. package/dist/types/rules/html-no-duplicate-ids.d.ts +6 -0
  25. package/dist/types/rules/index.d.ts +3 -0
  26. package/dist/types/rules/rule-utils.d.ts +2 -0
  27. package/dist/types/src/rules/html-aria-attribute-must-be-valid.d.ts +6 -0
  28. package/dist/types/src/rules/html-aria-role-must-be-valid.d.ts +6 -0
  29. package/dist/types/src/rules/html-no-duplicate-ids.d.ts +6 -0
  30. package/dist/types/src/rules/index.d.ts +3 -0
  31. package/dist/types/src/rules/rule-utils.d.ts +2 -0
  32. package/docs/rules/README.md +4 -0
  33. package/docs/rules/html-aria-attribute-must-be-valid.md +45 -0
  34. package/docs/rules/html-aria-role-must-be-valid.md +45 -0
  35. package/docs/rules/html-no-duplicate-ids.md +49 -0
  36. package/package.json +4 -4
  37. package/src/default-rules.ts +8 -2
  38. package/src/rules/html-aria-attribute-must-be-valid.ts +42 -0
  39. package/src/rules/html-aria-role-must-be-valid.ts +30 -0
  40. package/src/rules/html-no-duplicate-ids.ts +39 -0
  41. package/src/rules/index.ts +3 -0
  42. package/src/rules/rule-utils.ts +98 -17
@@ -2,16 +2,15 @@ import {
2
2
  Visitor
3
3
  } from "@herb-tools/core"
4
4
 
5
- import type {
6
- ERBNode,
5
+ import type {
6
+ ERBNode,
7
7
  HTMLAttributeNameNode,
8
- HTMLAttributeNode,
9
- HTMLAttributeValueNode,
10
- HTMLOpenTagNode,
11
- HTMLSelfCloseTagNode,
12
- LiteralNode,
13
- Location,
14
- Node
8
+ HTMLAttributeNode,
9
+ HTMLAttributeValueNode,
10
+ HTMLOpenTagNode,
11
+ HTMLSelfCloseTagNode,
12
+ LiteralNode,
13
+ Location
15
14
  } from "@herb-tools/core"
16
15
  import type { LintOffense, LintSeverity, } from "../types.js"
17
16
 
@@ -83,18 +82,36 @@ export function getAttributeName(attributeNode: HTMLAttributeNode): string | nul
83
82
  * Gets the attribute value content from an HTMLAttributeValueNode
84
83
  */
85
84
  export function getAttributeValue(attributeNode: HTMLAttributeNode): string | null {
86
- if (attributeNode.value?.type === "AST_HTML_ATTRIBUTE_VALUE_NODE") {
87
- const valueNode = attributeNode.value as HTMLAttributeValueNode
85
+ const valueNode: HTMLAttributeValueNode | null = attributeNode.value as HTMLAttributeValueNode
86
+
87
+ if (valueNode === null) return null
88
+
89
+ if (valueNode.type !== "AST_HTML_ATTRIBUTE_VALUE_NODE" || !valueNode.children?.length) {
90
+ return null
91
+ }
92
+
93
+ let result = ""
94
+
95
+ for (const child of valueNode.children) {
96
+ switch (child.type) {
97
+ case "AST_ERB_CONTENT_NODE": {
98
+ const erbNode = child as ERBNode
88
99
 
89
- if (valueNode.children && valueNode.children.length > 0) {
90
- return valueNode.children
91
- .filter(child => child.type === "AST_LITERAL_NODE")
92
- .map(child => (child as LiteralNode).content)
93
- .join("")
100
+ if (erbNode.content) {
101
+ result += `${erbNode.tag_opening?.value}${erbNode.content.value}${erbNode.tag_closing?.value}`
102
+ }
103
+
104
+ break
105
+ }
106
+
107
+ case "AST_LITERAL_NODE": {
108
+ result += (child as LiteralNode).content
109
+ break
110
+ }
94
111
  }
95
112
  }
96
113
 
97
- return null
114
+ return result
98
115
  }
99
116
 
100
117
  /**
@@ -171,6 +188,70 @@ export const HTML_BOOLEAN_ATTRIBUTES = new Set([
171
188
 
172
189
  export const HEADING_TAGS = new Set(["h1", "h2", "h3", "h4", "h5", "h6"])
173
190
 
191
+ export const VALID_ARIA_ROLES = new Set([
192
+ "banner", "complementary", "contentinfo", "form", "main", "navigation", "region", "search",
193
+ "article", "cell", "columnheader", "definition", "directory", "document", "feed", "figure",
194
+ "group", "heading", "img", "list", "listitem", "math", "none", "note", "presentation",
195
+ "row", "rowgroup", "rowheader", "separator", "table", "term", "tooltip",
196
+ "alert", "alertdialog", "button", "checkbox", "combobox", "dialog", "grid", "gridcell", "link",
197
+ "listbox", "menu", "menubar", "menuitem", "menuitemcheckbox", "menuitemradio", "option",
198
+ "progressbar", "radio", "radiogroup", "scrollbar", "searchbox", "slider", "spinbutton",
199
+ "status", "switch", "tab", "tablist", "tabpanel", "textbox", "timer", "toolbar", "tree",
200
+ "treegrid", "treeitem",
201
+ "log", "marquee"
202
+ ]);
203
+
204
+ export const ARIA_ATTRIBUTES = new Set([
205
+ 'aria-activedescendant',
206
+ 'aria-atomic',
207
+ 'aria-autocomplete',
208
+ 'aria-busy',
209
+ 'aria-checked',
210
+ 'aria-colcount',
211
+ 'aria-colindex',
212
+ 'aria-colspan',
213
+ 'aria-controls',
214
+ 'aria-current',
215
+ 'aria-describedby',
216
+ 'aria-details',
217
+ 'aria-disabled',
218
+ 'aria-dropeffect',
219
+ 'aria-errormessage',
220
+ 'aria-expanded',
221
+ 'aria-flowto',
222
+ 'aria-grabbed',
223
+ 'aria-haspopup',
224
+ 'aria-hidden',
225
+ 'aria-invalid',
226
+ 'aria-keyshortcuts',
227
+ 'aria-label',
228
+ 'aria-labelledby',
229
+ 'aria-level',
230
+ 'aria-live',
231
+ 'aria-modal',
232
+ 'aria-multiline',
233
+ 'aria-multiselectable',
234
+ 'aria-orientation',
235
+ 'aria-owns',
236
+ 'aria-placeholder',
237
+ 'aria-posinset',
238
+ 'aria-pressed',
239
+ 'aria-readonly',
240
+ 'aria-relevant',
241
+ 'aria-required',
242
+ 'aria-roledescription',
243
+ 'aria-rowcount',
244
+ 'aria-rowindex',
245
+ 'aria-rowspan',
246
+ 'aria-selected',
247
+ 'aria-setsize',
248
+ 'aria-sort',
249
+ 'aria-valuemax',
250
+ 'aria-valuemin',
251
+ 'aria-valuenow',
252
+ 'aria-valuetext',
253
+ ])
254
+
174
255
  /**
175
256
  * Checks if an element is inline
176
257
  */