@codelaw/rules-html 0.0.0-stage → 0.1.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 (103) hide show
  1. package/LICENSE +23 -0
  2. package/NOTICE +24 -0
  3. package/README.md +162 -2
  4. package/codelaw-pack.toml +6 -0
  5. package/data/html/elements.json +4892 -0
  6. package/data/html/entities.json +1 -0
  7. package/data/html/input-attributes.json +227 -0
  8. package/package.json +14 -4
  9. package/presets/html/a11y.toml +29 -0
  10. package/presets/html/conventions.toml +6 -0
  11. package/presets/html/document.toml +8 -0
  12. package/presets/html/recommended.toml +67 -0
  13. package/rules/html/area-alt.md +48 -0
  14. package/rules/html/aria-hidden-body.md +39 -0
  15. package/rules/html/aria-label-misuse.md +42 -0
  16. package/rules/html/attribute-allowed-values.cases.md +31 -0
  17. package/rules/html/attribute-allowed-values.md +41 -0
  18. package/rules/html/attribute-misuse.md +39 -0
  19. package/rules/html/autocomplete-password.md +41 -0
  20. package/rules/html/button-type.cases.md +28 -0
  21. package/rules/html/button-type.md +35 -0
  22. package/rules/html/close-attr.md +33 -0
  23. package/rules/html/close-order.cases.md +38 -0
  24. package/rules/html/close-order.md +47 -0
  25. package/rules/html/deprecated.md +39 -0
  26. package/rules/html/doctype-html.md +36 -0
  27. package/rules/html/element-name.cases.md +21 -0
  28. package/rules/html/element-name.md +42 -0
  29. package/rules/html/element-permitted-content.cases.md +54 -0
  30. package/rules/html/element-permitted-content.md +45 -0
  31. package/rules/html/element-permitted-occurrences.md +45 -0
  32. package/rules/html/element-permitted-order.md +44 -0
  33. package/rules/html/element-permitted-parent.cases.md +11 -0
  34. package/rules/html/element-permitted-parent.md +43 -0
  35. package/rules/html/element-required-ancestor.md +45 -0
  36. package/rules/html/element-required-attributes.md +44 -0
  37. package/rules/html/element-required-content.cases.md +23 -0
  38. package/rules/html/element-required-content.md +43 -0
  39. package/rules/html/empty-heading.md +40 -0
  40. package/rules/html/empty-title.md +39 -0
  41. package/rules/html/fieldset-legend.md +44 -0
  42. package/rules/html/form-dup-name.cases.md +38 -0
  43. package/rules/html/form-dup-name.md +48 -0
  44. package/rules/html/form-submit.md +44 -0
  45. package/rules/html/heading-level.cases.md +26 -0
  46. package/rules/html/heading-level.md +44 -0
  47. package/rules/html/hidden-focusable.cases.md +23 -0
  48. package/rules/html/hidden-focusable.md +40 -0
  49. package/rules/html/img-alt.cases.md +22 -0
  50. package/rules/html/img-alt.md +44 -0
  51. package/rules/html/img-title.md +40 -0
  52. package/rules/html/input-attributes.md +34 -0
  53. package/rules/html/input-image-alt.md +39 -0
  54. package/rules/html/input-missing-label.md +40 -0
  55. package/rules/html/link-text.md +39 -0
  56. package/rules/html/long-title.md +40 -0
  57. package/rules/html/map-dup-name.md +40 -0
  58. package/rules/html/map-id-name.md +38 -0
  59. package/rules/html/meta-refresh.md +42 -0
  60. package/rules/html/missing-doctype.cases.md +24 -0
  61. package/rules/html/missing-doctype.md +43 -0
  62. package/rules/html/multiple-labeled-controls.md +40 -0
  63. package/rules/html/no-abstract-role.md +39 -0
  64. package/rules/html/no-autoplay.md +37 -0
  65. package/rules/html/no-conditional-comment.md +39 -0
  66. package/rules/html/no-deprecated-attr.md +39 -0
  67. package/rules/html/no-dup-attr.md +37 -0
  68. package/rules/html/no-dup-class.md +33 -0
  69. package/rules/html/no-duplicate-id.cases.md +23 -0
  70. package/rules/html/no-duplicate-id.md +42 -0
  71. package/rules/html/no-implicit-close.cases.md +38 -0
  72. package/rules/html/no-implicit-close.md +40 -0
  73. package/rules/html/no-implicit-input-type.md +34 -0
  74. package/rules/html/no-inline-script.md +42 -0
  75. package/rules/html/no-inline-style.cases.md +12 -0
  76. package/rules/html/no-inline-style.md +42 -0
  77. package/rules/html/no-missing-references.md +39 -0
  78. package/rules/html/no-multiple-main.md +40 -0
  79. package/rules/html/no-raw-characters.cases.md +84 -0
  80. package/rules/html/no-raw-characters.md +35 -0
  81. package/rules/html/no-redundant-aria-label.md +36 -0
  82. package/rules/html/no-redundant-for.md +34 -0
  83. package/rules/html/no-redundant-role.md +42 -0
  84. package/rules/html/no-utf8-bom.md +45 -0
  85. package/rules/html/prefer-button.md +39 -0
  86. package/rules/html/prefer-native-element.md +40 -0
  87. package/rules/html/prefer-tbody.md +41 -0
  88. package/rules/html/require-sri.md +41 -0
  89. package/rules/html/script-element.md +36 -0
  90. package/rules/html/script-type.md +33 -0
  91. package/rules/html/target-blank-rel.cases.md +35 -0
  92. package/rules/html/target-blank-rel.md +32 -0
  93. package/rules/html/tel-non-breaking.md +37 -0
  94. package/rules/html/text-content.md +39 -0
  95. package/rules/html/th-scope.md +47 -0
  96. package/rules/html/unique-landmark.md +41 -0
  97. package/rules/html/unrecognized-char-ref.cases.md +41 -0
  98. package/rules/html/unrecognized-char-ref.md +42 -0
  99. package/rules/html/valid-autocomplete.cases.md +42 -0
  100. package/rules/html/valid-autocomplete.md +42 -0
  101. package/rules/html/valid-for.md +40 -0
  102. package/rules/html/valid-id.md +40 -0
  103. package/rules/html/void-content.md +34 -0
package/LICENSE ADDED
@@ -0,0 +1,23 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Arpit Arya
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+
23
+ SPDX-License-Identifier: MIT
package/NOTICE ADDED
@@ -0,0 +1,24 @@
1
+ @codelaw/rules-html / codelaw-rules-html
2
+
3
+ data/html/elements.json is derived from the html5 element metadata of
4
+ html-validate, version 11.16.4, https://html-validate.org — Copyright (c) 2017
5
+ David Sveningsson <ext@sidvind.com>, released under the MIT License. Its
6
+ JavaScript functions are rewritten as JSON conditions; the element, attribute
7
+ and content-model data are otherwise unchanged.
8
+
9
+ data/html/entities.json is the list of named character references shipped
10
+ with html-validate 11.16.4 (MIT License, as above). That list follows the
11
+ named character reference table of the WHATWG HTML Living Standard,
12
+ https://html.spec.whatwg.org/multipage/named-characters.html — Copyright (c)
13
+ WHATWG (Apple, Google, Mozilla, Microsoft), published under the Creative
14
+ Commons Attribution 4.0 International License; this pack takes it from
15
+ html-validate, not from the Standard.
16
+
17
+ data/html/input-attributes.json is derived from the table of html-validate
18
+ 11.16.4's `input-attributes` rule (MIT License, as above).
19
+
20
+ The rules are reimplementations written for codelaw. Their `ported_from:`
21
+ fields name the html-validate rules (https://html-validate.org, MIT License)
22
+ and HTMLHint rules (https://htmlhint.com, MIT License) whose documented
23
+ behaviour they reproduce; no html-validate or HTMLHint code or documentation
24
+ text is included.
package/README.md CHANGED
@@ -1,3 +1,163 @@
1
- # Temporary Holding Version
1
+ # @codelaw/rules-html · codelaw-rules-html
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ codelaw's rules for HTML — one of the five first-party rule packs
4
+ ([SR-RULE-PACKS](../../records/0101_rule-packs.md)). The same files ship on npm
5
+ as `@codelaw/rules-html` and on PyPI as `codelaw-rules-html`.
6
+
7
+ ```toml
8
+ # codelaw.toml
9
+ extends = ["codelaw:html/recommended"]
10
+ preview = true # every rule is `preview` until a corpus run promotes it
11
+ ```
12
+
13
+ ## Presets
14
+
15
+ | preset | rules | ported from |
16
+ |---|---|---|
17
+ | `html/recommended` | 64 | html-validate 11.16.4 `html-validate:recommended`, without its layout rules and without the cosmetic rules its `prettier` and `browser` presets switch off (see below) |
18
+ | `html/a11y` | 26 | html-validate 11.16.4 `html-validate:a11y`: every rule it turns on |
19
+ | `html/document` | 5 | html-validate 11.16.4 `html-validate:document`: checks that only make sense for a complete page |
20
+ | `html/conventions` | 3 | opt-in: the starter rule `html/target-blank-rel`, and HTMLHint's `inline-style-disabled` and `inline-script-disabled` |
21
+
22
+ `html/a11y` is a subset of `html/recommended`, as upstream; turn it on alone
23
+ for an accessibility-only check. `html/document` adds to `html/recommended`.
24
+
25
+ Every rule is **reimplemented**, not vendored: the checks, messages and docs are
26
+ written fresh, and each rule's `ported_from:` names the source rule. Every rule
27
+ is a `native:` rule, sharing one model of the document
28
+ (`crates/codelaw-native/src/html_dom.rs`): tree-sitter-html knows only a few of
29
+ HTML's implied end tags, so the model rebuilds the element tree the way a
30
+ browser (and html-validate) does, from the element table in `data/`.
31
+
32
+ Fix classes: 10 `auto`, 11 `suggest`, 51 `manual`.
33
+
34
+ ## Rules
35
+
36
+ | rule | fix | ported from | presets |
37
+ |---|---|---|---|
38
+ | `html/area-alt` | manual | html-validate/area-alt | recommended, a11y |
39
+ | `html/aria-hidden-body` | suggest | html-validate/aria-hidden-body | recommended, a11y |
40
+ | `html/aria-label-misuse` | manual | html-validate/aria-label-misuse | recommended, a11y |
41
+ | `html/attribute-allowed-values` | manual | html-validate/attribute-allowed-values, htmlhint/src-not-empty | recommended |
42
+ | `html/attribute-misuse` | manual | html-validate/attribute-misuse | recommended |
43
+ | `html/autocomplete-password` | manual | html-validate/autocomplete-password | recommended |
44
+ | `html/button-type` | suggest | html-validate/no-implicit-button-type, htmlhint/button-type-require | recommended, a11y |
45
+ | `html/close-attr` | auto | html-validate/close-attr | recommended |
46
+ | `html/close-order` | manual | html-validate/close-order, htmlhint/tag-pair | recommended |
47
+ | `html/deprecated` | manual | html-validate/deprecated, htmlhint/tag-no-obsolete | recommended |
48
+ | `html/doctype-html` | suggest | html-validate/doctype-html, htmlhint/doctype-html5 | recommended |
49
+ | `html/element-name` | manual | html-validate/element-name | recommended |
50
+ | `html/element-permitted-content` | manual | html-validate/element-permitted-content | recommended |
51
+ | `html/element-permitted-occurrences` | manual | html-validate/element-permitted-occurrences | recommended |
52
+ | `html/element-permitted-order` | manual | html-validate/element-permitted-order | recommended |
53
+ | `html/element-permitted-parent` | manual | html-validate/element-permitted-parent | recommended |
54
+ | `html/element-required-ancestor` | manual | html-validate/element-required-ancestor | recommended |
55
+ | `html/element-required-attributes` | manual | html-validate/element-required-attributes, htmlhint/html-lang-require | recommended |
56
+ | `html/element-required-content` | manual | html-validate/element-required-content, htmlhint/title-require | recommended |
57
+ | `html/empty-heading` | manual | html-validate/empty-heading | recommended, a11y |
58
+ | `html/empty-title` | manual | html-validate/empty-title | recommended, a11y |
59
+ | `html/fieldset-legend` | manual | html-validate/wcag/h71 | recommended, a11y |
60
+ | `html/form-dup-name` | manual | html-validate/form-dup-name | recommended |
61
+ | `html/form-submit` | manual | html-validate/wcag/h32 | recommended, a11y |
62
+ | `html/hidden-focusable` | manual | html-validate/hidden-focusable | recommended, a11y |
63
+ | `html/img-alt` | manual | html-validate/wcag/h37, htmlhint/alt-require | recommended, a11y |
64
+ | `html/img-title` | manual | html-validate/wcag/h67 | recommended, a11y |
65
+ | `html/input-attributes` | suggest | html-validate/input-attributes | recommended |
66
+ | `html/input-image-alt` | manual | html-validate/wcag/h36 | recommended, a11y |
67
+ | `html/link-text` | manual | html-validate/wcag/h30 | recommended, a11y |
68
+ | `html/long-title` | manual | html-validate/long-title | recommended |
69
+ | `html/map-dup-name` | manual | html-validate/map-dup-name | recommended |
70
+ | `html/map-id-name` | manual | html-validate/map-id-name | recommended |
71
+ | `html/meta-refresh` | manual | html-validate/meta-refresh | recommended, a11y |
72
+ | `html/multiple-labeled-controls` | manual | html-validate/multiple-labeled-controls | recommended, a11y |
73
+ | `html/no-abstract-role` | manual | html-validate/no-abstract-role | recommended, a11y |
74
+ | `html/no-autoplay` | suggest | html-validate/no-autoplay | recommended, a11y |
75
+ | `html/no-conditional-comment` | manual | html-validate/no-conditional-comment | recommended |
76
+ | `html/no-deprecated-attr` | manual | html-validate/no-deprecated-attr | recommended |
77
+ | `html/no-dup-attr` | auto | html-validate/no-dup-attr, htmlhint/attr-no-duplication | recommended |
78
+ | `html/no-dup-class` | auto | html-validate/no-dup-class | recommended |
79
+ | `html/no-duplicate-id` | manual | html-validate/no-dup-id, htmlhint/id-unique | recommended, a11y |
80
+ | `html/no-implicit-close` | suggest | html-validate/no-implicit-close | recommended |
81
+ | `html/no-implicit-input-type` | suggest | html-validate/no-implicit-input-type | recommended |
82
+ | `html/no-multiple-main` | manual | html-validate/no-multiple-main | recommended |
83
+ | `html/no-utf8-bom` | manual | html-validate/no-utf8-bom | recommended |
84
+ | `html/no-raw-characters` | auto | html-validate/no-raw-characters, htmlhint/spec-char-escape | recommended |
85
+ | `html/no-redundant-aria-label` | auto | html-validate/no-redundant-aria-label | recommended, a11y |
86
+ | `html/no-redundant-for` | auto | html-validate/no-redundant-for | recommended, a11y |
87
+ | `html/no-redundant-role` | auto | html-validate/no-redundant-role | recommended, a11y |
88
+ | `html/prefer-button` | manual | html-validate/prefer-button | recommended |
89
+ | `html/prefer-native-element` | manual | html-validate/prefer-native-element | recommended, a11y |
90
+ | `html/prefer-tbody` | auto | html-validate/prefer-tbody | recommended |
91
+ | `html/script-element` | suggest | html-validate/script-element | recommended |
92
+ | `html/script-type` | auto | html-validate/script-type | recommended |
93
+ | `html/tel-non-breaking` | suggest | html-validate/tel-non-breaking | recommended |
94
+ | `html/text-content` | manual | html-validate/text-content | recommended, a11y |
95
+ | `html/th-scope` | manual | html-validate/wcag/h63 | recommended, a11y |
96
+ | `html/unique-landmark` | manual | html-validate/unique-landmark | recommended, a11y |
97
+ | `html/unrecognized-char-ref` | manual | html-validate/unrecognized-char-ref | recommended |
98
+ | `html/valid-autocomplete` | manual | html-validate/valid-autocomplete | recommended, a11y |
99
+ | `html/valid-for` | manual | html-validate/valid-for | recommended |
100
+ | `html/valid-id` | manual | html-validate/valid-id | recommended |
101
+ | `html/void-content` | suggest | html-validate/void-content | recommended |
102
+ | `html/heading-level` | manual | html-validate/heading-level | document |
103
+ | `html/input-missing-label` | manual | html-validate/input-missing-label, htmlhint/input-requires-label | document |
104
+ | `html/missing-doctype` | suggest | html-validate/missing-doctype | document |
105
+ | `html/no-missing-references` | manual | html-validate/no-missing-references | document |
106
+ | `html/require-sri` | manual | html-validate/require-sri | document |
107
+ | `html/target-blank-rel` | auto | — (starter rule) | conventions |
108
+ | `html/no-inline-style` | manual | html-validate/no-inline-style, htmlhint/inline-style-disabled | conventions |
109
+ | `html/no-inline-script` | manual | htmlhint/inline-script-disabled | conventions |
110
+
111
+ The four starter-catalogue rules ([SR-RULE-PACKS](../../records/0101_rule-packs.md)
112
+ decision 8): `html/img-alt` (↔ `wcag/h37`), `html/no-duplicate-id` (↔ `no-dup-id`)
113
+ and `html/button-type` (↔ `no-implicit-button-type`) match html-validate rules
114
+ and sit in `html/recommended`; `html/target-blank-rel` matches none and forms
115
+ `html/conventions`. The other ported rules keep html-validate's names, except
116
+ its WCAG technique rules, which are named for what they check
117
+ (`wcag/h30` → `html/link-text`, `h32` → `form-submit`, `h36` → `input-image-alt`,
118
+ `h63` → `th-scope`, `h67` → `img-title`, `h71` → `fieldset-legend`).
119
+
120
+ ## Not ported, and why
121
+
122
+ | upstream rule | why |
123
+ |---|---|
124
+ | html-validate `attr-case`, `element-case` | never: layout — case-only style belongs to the formatter |
125
+ | html-validate `attr-delimiter`, `attr-spacing`, `no-trailing-whitespace` | never: layout — whitespace belongs to the formatter |
126
+ | html-validate `attr-quotes`, `doctype-style` | never: layout — quoting and the doctype's case belong to the formatter (also switched off by its `prettier` preset) |
127
+ | html-validate `attribute-boolean-style`, `attribute-empty-style`, `void-style`, `no-self-closing` | never: cosmetic — how `disabled`, `alt=""` and void tags are spelled is the formatter's call (switched off by its `browser` and `prettier` presets) |
128
+ | html-validate `deprecated-rule`, `no-unused-disable` | about html-validate's own configuration and inline directives; codelaw reports its own |
129
+ | html-validate `svg-focusable` | switched off in every upstream preset (it only matters for Internet Explorer) |
130
+ | html-validate `no-inline-style` in `recommended` | moved to the opt-in `html/conventions`: its `browser` preset switches it off, and it is a style policy, not a correctness check |
131
+ | HTMLHint `attr-lowercase`, `tagname-lowercase`, `attr-value-double-quotes`, `attr-value-single-quotes`, `attr-whitespace`, `attr-no-unnecessary-whitespace`, `space-tab-mixed-disabled`, `tag-self-close`, `empty-tag-not-self-closed`, `attr-sorted` | never: layout |
132
+ | HTMLHint `head-script-disabled`, `script-disabled`, `style-disabled`, `id-class-ad-disabled`, `id-class-value`, `href-abs-or-rel`, `attr-unsafe-chars`, `attr-value-not-empty`, `attr-value-no-duplication`, `tagname-specialchars`, `tags-check` | house policy without a correctness reason, or covered by a ported rule (`tags-check` by the content-model rules, `tagname-specialchars` by `html/element-name`) |
133
+ | HTMLHint `h1-require`, `main-require`, `meta-charset-require`, `meta-description-require`, `meta-viewport-require`, `link-rel-canonical-require`, `frame-title-require`, `form-method-require` | page-level SEO or policy checks html-validate's presets don't have; candidates for a later `html/strict` |
134
+
135
+ ## How the ports differ
136
+
137
+ | rule | difference |
138
+ |---|---|
139
+ | all | the document model is rebuilt from tree-sitter-html's tokens with html-validate's implied-end-tag and implied-element rules; markup tree-sitter can't parse at all (a raw `<` in text) is treated as text |
140
+ | all | attribute values holding template code (`{{ }}`, `<% %>`, `${ }`, `{% %}`) are treated as unknown and not checked, as html-validate does for its framework transforms |
141
+ | `html/element-permitted-content` | obsolete elements are left to `html/deprecated` instead of being reported again wherever they appear |
142
+ | `html/close-order` | reports unclosed elements and stray end tags; html-validate also reports the end tag that closed past them, which repeats the first finding |
143
+ | `html/missing-doctype` | only files with an `<html>` element are checked; fragments and partials are not documents |
144
+ | `html/no-implicit-close` | the `suggest` fix writes the end tag after the element's last content |
145
+ | `html/prefer-tbody` | the fix wraps the rows when they are next to each other; otherwise the rule only reports |
146
+ | `html/heading-level` | sectioning roots are matched by tag or `[attr="value"]` selectors only |
147
+ | `html/require-sri` | no `include`/`exclude` URL options yet |
148
+ | `html/no-utf8-bom` | `manual`: the mark is in the file's bytes, outside the text a fix edits; only the file itself is checked, not an HTML region of another file |
149
+
150
+ ## Data
151
+
152
+ | table | source |
153
+ |---|---|
154
+ | `data/html/elements.json` | html-validate 11.16.4's `html5` element metadata (MIT): content categories, content models, permitted parents and order, required and deprecated attributes, attribute value enumerations, implied end tags, ARIA implicit roles. Its JavaScript callbacks are rewritten as JSON conditions (`{"attr": "href"}`, `{"ancestor": ["map"]}`, `{"if": …, "then": …, "else": …}`) that `html_dom.rs` evaluates. |
155
+ | `data/html/entities.json` | the named character references html-validate 11.16.4 ships (MIT), following the WHATWG table |
156
+ | `data/html/input-attributes.json` | which `<input>` types each attribute applies to, from html-validate 11.16.4's `input-attributes` rule (MIT) |
157
+
158
+ See `NOTICE`.
159
+
160
+ ## Upstream versions
161
+
162
+ - html-validate **11.16.4** (MIT) — presets `recommended`, `a11y`, `document`, `prettier`, `browser`; rule docs at https://html-validate.org/rules/.
163
+ - HTMLHint **1.9.2** (MIT) — cross-checked for rules html-validate lacks.
@@ -0,0 +1,6 @@
1
+ name = "@codelaw/rules-html"
2
+ version = "0.1.0"
3
+ min_codelaw = "0.1.0"
4
+ languages = ["html"]
5
+ presets = ["html/recommended", "html/a11y", "html/document", "html/conventions"]
6
+ description = "codelaw's rules for HTML (SR-RULE-PACKS)"