@markuplint/rules 5.0.0-rc.2 → 5.0.0-rc.5

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 (573) hide show
  1. package/CHANGELOG.md +98 -0
  2. package/CLAUDE.md +31 -2
  3. package/lib/{wai-aria-deprecated-role → aria-prop-requires-role}/index.d.ts +0 -1
  4. package/lib/{wai-aria-no-global-prop → aria-prop-requires-role}/index.js +0 -1
  5. package/lib/attr-check.d.ts +0 -48
  6. package/lib/attr-check.js +0 -36
  7. package/lib/attr-eligibility.d.ts +41 -0
  8. package/lib/attr-eligibility.js +60 -0
  9. package/lib/attr-value-quotes/index.d.ts +0 -7
  10. package/lib/attr-value-quotes/index.js +0 -7
  11. package/lib/attr-value-quotes/meta.d.ts +0 -1
  12. package/lib/attr-value-quotes/meta.js +0 -1
  13. package/lib/case-sensitive-attr-name/index.d.ts +0 -8
  14. package/lib/case-sensitive-attr-name/index.js +0 -8
  15. package/lib/case-sensitive-attr-name/meta.d.ts +0 -1
  16. package/lib/case-sensitive-attr-name/meta.js +0 -1
  17. package/lib/case-sensitive-tag-name/index.d.ts +0 -8
  18. package/lib/case-sensitive-tag-name/index.js +0 -8
  19. package/lib/case-sensitive-tag-name/meta.d.ts +0 -1
  20. package/lib/case-sensitive-tag-name/meta.js +0 -1
  21. package/lib/class-naming/index.d.ts +0 -8
  22. package/lib/class-naming/index.js +0 -8
  23. package/lib/class-naming/meta.d.ts +1 -2
  24. package/lib/class-naming/meta.js +1 -2
  25. package/lib/consistent-table-row-length/index.d.ts +14 -0
  26. package/lib/consistent-table-row-length/index.js +69 -0
  27. package/lib/consistent-table-row-length/meta.d.ts +4 -0
  28. package/lib/consistent-table-row-length/meta.js +3 -0
  29. package/lib/create-message.d.ts +2 -25
  30. package/lib/create-message.js +2 -53
  31. package/lib/debug.d.ts +1 -9
  32. package/lib/debug.js +1 -5
  33. package/lib/element-supports-aria-prop/index.d.ts +12 -0
  34. package/lib/element-supports-aria-prop/index.js +38 -0
  35. package/lib/form-attr-references-form/index.d.ts +12 -0
  36. package/lib/form-attr-references-form/index.js +64 -0
  37. package/lib/{correct-aspect-ratio → form-attr-references-form}/meta.d.ts +1 -1
  38. package/lib/form-attr-references-form/meta.js +3 -0
  39. package/lib/head-element-order/meta.d.ts +1 -1
  40. package/lib/head-element-order/meta.js +1 -1
  41. package/lib/helpers.d.ts +8 -138
  42. package/lib/helpers.js +24 -165
  43. package/lib/index.d.ts +135 -78
  44. package/lib/index.js +167 -82
  45. package/lib/input-list-references-datalist/index.d.ts +13 -0
  46. package/lib/input-list-references-datalist/index.js +46 -0
  47. package/lib/input-list-references-datalist/meta.d.ts +4 -0
  48. package/lib/input-list-references-datalist/meta.js +3 -0
  49. package/lib/itemprop-requires-itemscope/index.d.ts +21 -0
  50. package/lib/itemprop-requires-itemscope/index.js +53 -0
  51. package/lib/itemprop-requires-itemscope/meta.d.ts +4 -0
  52. package/lib/itemprop-requires-itemscope/meta.js +3 -0
  53. package/lib/label-for-references-labelable/index.d.ts +12 -0
  54. package/lib/label-for-references-labelable/index.js +68 -0
  55. package/lib/label-for-references-labelable/meta.d.ts +4 -0
  56. package/lib/label-for-references-labelable/meta.js +3 -0
  57. package/lib/label-has-control/index.d.ts +5 -5
  58. package/lib/label-has-control/index.js +5 -18
  59. package/lib/label-has-control/meta.d.ts +0 -1
  60. package/lib/label-has-control/meta.js +0 -1
  61. package/lib/label-no-multiple-controls/index.d.ts +31 -0
  62. package/lib/label-no-multiple-controls/index.js +104 -0
  63. package/lib/label-no-multiple-controls/meta.d.ts +4 -0
  64. package/lib/label-no-multiple-controls/meta.js +3 -0
  65. package/lib/landmark-roles/roles.d.ts +32 -0
  66. package/lib/landmark-roles/roles.js +73 -0
  67. package/lib/link-types/index.d.ts +0 -5
  68. package/lib/link-types/index.js +5 -6
  69. package/lib/link-types/meta.d.ts +1 -2
  70. package/lib/link-types/meta.js +1 -2
  71. package/lib/map-id-name-match/index.d.ts +10 -0
  72. package/lib/map-id-name-match/index.js +39 -0
  73. package/lib/map-id-name-match/meta.d.ts +4 -0
  74. package/lib/map-id-name-match/meta.js +3 -0
  75. package/lib/meta-charset-position/index.d.ts +15 -0
  76. package/lib/meta-charset-position/index.js +31 -0
  77. package/lib/meta-charset-position/meta.d.ts +4 -0
  78. package/lib/meta-charset-position/meta.js +3 -0
  79. package/lib/meter-value-bounds/index.d.ts +10 -0
  80. package/lib/meter-value-bounds/index.js +123 -0
  81. package/lib/meter-value-bounds/meta.d.ts +4 -0
  82. package/lib/meter-value-bounds/meta.js +3 -0
  83. package/lib/{wai-aria-required-props → no-abstract-role}/index.d.ts +0 -1
  84. package/lib/{wai-aria-abstract-role → no-abstract-role}/index.js +0 -1
  85. package/lib/no-always-matching-source/index.d.ts +13 -0
  86. package/lib/no-always-matching-source/index.js +100 -0
  87. package/lib/no-always-matching-source/meta.d.ts +4 -0
  88. package/lib/no-always-matching-source/meta.js +3 -0
  89. package/lib/no-ambiguous-navigable-target-names/index.d.ts +0 -8
  90. package/lib/no-ambiguous-navigable-target-names/index.js +0 -8
  91. package/lib/no-ambiguous-navigable-target-names/meta.d.ts +1 -2
  92. package/lib/no-ambiguous-navigable-target-names/meta.js +1 -2
  93. package/lib/{wai-aria-required-owned-elements → no-aria-on-presentational-children}/index.d.ts +0 -1
  94. package/lib/{wai-aria-presentational-children → no-aria-on-presentational-children}/index.js +0 -1
  95. package/lib/no-aria-on-unsupported-element/index.d.ts +11 -0
  96. package/lib/no-aria-on-unsupported-element/index.js +35 -0
  97. package/lib/no-aria-on-unsupported-element/meta.d.ts +9 -0
  98. package/lib/no-aria-on-unsupported-element/meta.js +8 -0
  99. package/lib/no-boolean-attr-value/index.d.ts +0 -7
  100. package/lib/no-boolean-attr-value/index.js +0 -7
  101. package/lib/no-boolean-attr-value/meta.d.ts +0 -1
  102. package/lib/no-boolean-attr-value/meta.js +0 -1
  103. package/lib/no-broken-fragment-link/index.d.ts +15 -0
  104. package/lib/no-broken-fragment-link/index.js +93 -0
  105. package/lib/no-broken-fragment-link/meta.d.ts +4 -0
  106. package/lib/no-broken-fragment-link/meta.js +3 -0
  107. package/lib/no-consecutive-br/index.d.ts +0 -8
  108. package/lib/no-consecutive-br/index.js +0 -8
  109. package/lib/no-consecutive-br/meta.d.ts +0 -1
  110. package/lib/no-consecutive-br/meta.js +0 -1
  111. package/lib/no-content-after-body/index.d.ts +25 -0
  112. package/lib/no-content-after-body/index.js +51 -0
  113. package/lib/no-content-after-body/meta.d.ts +4 -0
  114. package/lib/no-content-after-body/meta.js +3 -0
  115. package/lib/no-contradictory-aria-prop/index.d.ts +10 -0
  116. package/lib/no-contradictory-aria-prop/index.js +34 -0
  117. package/lib/{wai-aria-abstract-role → no-default-aria-value}/index.d.ts +0 -1
  118. package/lib/{wai-aria-default-value → no-default-aria-value}/index.js +0 -1
  119. package/lib/no-default-value/index.d.ts +0 -7
  120. package/lib/no-default-value/index.js +0 -7
  121. package/lib/no-default-value/meta.d.ts +0 -1
  122. package/lib/no-default-value/meta.js +0 -1
  123. package/lib/no-deprecated-aria-prop/index.d.ts +3 -0
  124. package/lib/{wai-aria-deprecated-props → no-deprecated-aria-prop}/index.js +0 -1
  125. package/lib/no-deprecated-attr/index.d.ts +2 -0
  126. package/lib/{deprecated-attr → no-deprecated-attr}/index.js +5 -9
  127. package/lib/no-deprecated-attr/meta.d.ts +4 -0
  128. package/lib/no-deprecated-attr/meta.js +3 -0
  129. package/lib/no-deprecated-element/index.d.ts +2 -0
  130. package/lib/no-deprecated-element/index.js +27 -0
  131. package/lib/no-deprecated-element/meta.d.ts +4 -0
  132. package/lib/no-deprecated-element/meta.js +3 -0
  133. package/lib/no-deprecated-role/index.d.ts +3 -0
  134. package/lib/{wai-aria-deprecated-role → no-deprecated-role}/index.js +0 -1
  135. package/lib/no-disallowed-ancestor/index.d.ts +2 -0
  136. package/lib/no-disallowed-ancestor/index.js +25 -0
  137. package/lib/no-disallowed-ancestor/meta.d.ts +4 -0
  138. package/lib/no-disallowed-ancestor/meta.js +3 -0
  139. package/lib/no-disallowed-attr/index.d.ts +28 -0
  140. package/lib/no-disallowed-attr/index.js +77 -0
  141. package/lib/no-disallowed-attr/meta.d.ts +4 -0
  142. package/lib/no-disallowed-attr/meta.js +3 -0
  143. package/lib/no-duplicate-attr/index.d.ts +2 -0
  144. package/lib/{attr-duplication → no-duplicate-attr}/index.js +0 -7
  145. package/lib/no-duplicate-attr/meta.d.ts +6 -0
  146. package/lib/no-duplicate-attr/meta.js +10 -0
  147. package/lib/no-duplicate-autofocus/index.d.ts +0 -5
  148. package/lib/no-duplicate-autofocus/index.js +20 -6
  149. package/lib/no-duplicate-autofocus/meta.d.ts +1 -1
  150. package/lib/no-duplicate-autofocus/meta.js +1 -1
  151. package/lib/no-duplicate-dt/index.d.ts +0 -6
  152. package/lib/no-duplicate-dt/index.js +1 -6
  153. package/lib/no-duplicate-dt/meta.d.ts +1 -2
  154. package/lib/no-duplicate-dt/meta.js +1 -2
  155. package/lib/no-duplicate-h1/index.d.ts +18 -0
  156. package/lib/no-duplicate-h1/index.js +41 -0
  157. package/lib/no-duplicate-h1/meta.d.ts +4 -0
  158. package/lib/no-duplicate-h1/meta.js +3 -0
  159. package/lib/no-duplicate-id/index.d.ts +2 -0
  160. package/lib/{id-duplication → no-duplicate-id}/index.js +0 -7
  161. package/lib/no-duplicate-id/meta.d.ts +4 -0
  162. package/lib/no-duplicate-id/meta.js +3 -0
  163. package/lib/no-duplicate-sibling-attr/index.d.ts +2 -0
  164. package/lib/no-duplicate-sibling-attr/index.js +35 -0
  165. package/lib/no-duplicate-sibling-attr/meta.d.ts +4 -0
  166. package/lib/no-duplicate-sibling-attr/meta.js +3 -0
  167. package/lib/no-duplicate-visible-main/index.d.ts +0 -1
  168. package/lib/no-duplicate-visible-main/index.js +0 -1
  169. package/lib/no-duplicate-visible-main/meta.d.ts +1 -1
  170. package/lib/no-duplicate-visible-main/meta.js +1 -1
  171. package/lib/no-empty-palpable-content/index.d.ts +0 -8
  172. package/lib/no-empty-palpable-content/index.js +0 -8
  173. package/lib/no-empty-palpable-content/meta.d.ts +1 -2
  174. package/lib/no-empty-palpable-content/meta.js +1 -2
  175. package/lib/no-empty-table-track/index.d.ts +12 -0
  176. package/lib/no-empty-table-track/index.js +42 -0
  177. package/lib/no-empty-table-track/meta.d.ts +4 -0
  178. package/lib/no-empty-table-track/meta.js +3 -0
  179. package/lib/no-event-handler-attr/index.d.ts +7 -0
  180. package/lib/{no-use-event-handler-attr → no-event-handler-attr}/index.js +0 -11
  181. package/lib/no-event-handler-attr/meta.d.ts +4 -0
  182. package/lib/no-event-handler-attr/meta.js +3 -0
  183. package/lib/no-experimental-features/index.d.ts +9 -0
  184. package/lib/no-experimental-features/index.js +53 -0
  185. package/lib/no-experimental-features/meta.d.ts +4 -0
  186. package/lib/no-experimental-features/meta.js +3 -0
  187. package/lib/no-extra-selected-options/index.d.ts +10 -0
  188. package/lib/no-extra-selected-options/index.js +37 -0
  189. package/lib/no-extra-selected-options/meta.d.ts +4 -0
  190. package/lib/no-extra-selected-options/meta.js +3 -0
  191. package/lib/no-focusable-in-aria-hidden/index.d.ts +3 -0
  192. package/lib/{wai-aria-interaction-in-hidden → no-focusable-in-aria-hidden}/index.js +0 -1
  193. package/lib/no-focusable-in-aria-hidden/meta.d.ts +4 -0
  194. package/lib/no-focusable-in-aria-hidden/meta.js +3 -0
  195. package/lib/no-hardcoded-id/index.d.ts +2 -0
  196. package/lib/{no-hard-code-id → no-hardcoded-id}/index.js +0 -8
  197. package/lib/no-hardcoded-id/meta.d.ts +4 -0
  198. package/lib/no-hardcoded-id/meta.js +3 -0
  199. package/lib/no-ineffective-attr/index.d.ts +2 -0
  200. package/lib/{ineffective-attr → no-ineffective-attr}/index.js +0 -7
  201. package/lib/no-ineffective-attr/meta.d.ts +5 -0
  202. package/lib/no-ineffective-attr/meta.js +4 -0
  203. package/lib/no-input-file-value/index.d.ts +10 -0
  204. package/lib/no-input-file-value/index.js +41 -0
  205. package/lib/no-input-file-value/meta.d.ts +4 -0
  206. package/lib/no-input-file-value/meta.js +3 -0
  207. package/lib/no-invalid-aria-prop-value/index.d.ts +3 -0
  208. package/lib/{wai-aria-value → no-invalid-aria-prop-value}/index.js +0 -1
  209. package/lib/no-invalid-aria-prop-value/meta.d.ts +4 -0
  210. package/lib/no-invalid-aria-prop-value/meta.js +3 -0
  211. package/lib/no-invalid-attr-value/index.d.ts +27 -0
  212. package/lib/no-invalid-attr-value/index.js +83 -0
  213. package/lib/no-invalid-attr-value/meta.d.ts +4 -0
  214. package/lib/no-invalid-attr-value/meta.js +3 -0
  215. package/lib/no-malformed-character-reference/index.d.ts +2 -0
  216. package/lib/no-malformed-character-reference/index.js +38 -0
  217. package/lib/no-malformed-character-reference/meta.d.ts +5 -0
  218. package/lib/no-malformed-character-reference/meta.js +20 -0
  219. package/lib/{correct-aspect-ratio → no-mismatched-aspect-ratio}/index.js +13 -3
  220. package/lib/no-mismatched-aspect-ratio/meta.d.ts +4 -0
  221. package/lib/no-mismatched-aspect-ratio/meta.js +3 -0
  222. package/lib/{correct-aspect-ratio → no-mismatched-aspect-ratio}/resolve-image-size.js +8 -2
  223. package/lib/no-mixed-srcset-descriptors/index.d.ts +12 -0
  224. package/lib/no-mixed-srcset-descriptors/index.js +47 -0
  225. package/lib/no-mixed-srcset-descriptors/meta.d.ts +4 -0
  226. package/lib/no-mixed-srcset-descriptors/meta.js +3 -0
  227. package/lib/no-nested-top-level-landmark/index.d.ts +10 -0
  228. package/lib/no-nested-top-level-landmark/index.js +52 -0
  229. package/lib/no-nested-top-level-landmark/meta.d.ts +4 -0
  230. package/lib/no-nested-top-level-landmark/meta.js +3 -0
  231. package/lib/no-nonstandard-features/index.d.ts +9 -0
  232. package/lib/no-nonstandard-features/index.js +53 -0
  233. package/lib/no-nonstandard-features/meta.d.ts +4 -0
  234. package/lib/no-nonstandard-features/meta.js +3 -0
  235. package/lib/no-obsolete-attr/index.d.ts +2 -0
  236. package/lib/no-obsolete-attr/index.js +27 -0
  237. package/lib/no-obsolete-attr/meta.d.ts +4 -0
  238. package/lib/no-obsolete-attr/meta.js +3 -0
  239. package/lib/no-obsolete-doctype/index.d.ts +2 -0
  240. package/lib/{doctype → no-obsolete-doctype}/index.js +9 -16
  241. package/lib/no-obsolete-doctype/meta.d.ts +4 -0
  242. package/lib/no-obsolete-doctype/meta.js +3 -0
  243. package/lib/no-obsolete-element/index.d.ts +2 -0
  244. package/lib/{deprecated-element → no-obsolete-element}/index.js +6 -10
  245. package/lib/no-obsolete-element/meta.d.ts +4 -0
  246. package/lib/no-obsolete-element/meta.js +3 -0
  247. package/lib/no-orphaned-end-tag/index.d.ts +0 -7
  248. package/lib/no-orphaned-end-tag/index.js +0 -7
  249. package/lib/no-orphaned-end-tag/meta.d.ts +2 -2
  250. package/lib/no-orphaned-end-tag/meta.js +5 -2
  251. package/lib/no-prohibited-naming/index.d.ts +8 -0
  252. package/lib/no-prohibited-naming/index.js +36 -0
  253. package/lib/no-prohibited-naming/meta.d.ts +4 -0
  254. package/lib/no-prohibited-naming/meta.js +3 -0
  255. package/lib/{use-list → no-pseudo-list}/index.d.ts +1 -8
  256. package/lib/{use-list → no-pseudo-list}/index.js +0 -7
  257. package/lib/no-pseudo-list/meta.d.ts +4 -0
  258. package/lib/no-pseudo-list/meta.js +3 -0
  259. package/lib/{redundant-accessible-name → no-redundant-accessible-name}/index.d.ts +0 -4
  260. package/lib/{redundant-accessible-name → no-redundant-accessible-name}/index.js +0 -4
  261. package/lib/no-redundant-accessible-name/meta.d.ts +4 -0
  262. package/lib/no-redundant-accessible-name/meta.js +3 -0
  263. package/lib/no-redundant-aria-prop/index.d.ts +10 -0
  264. package/lib/{wai-aria-implicit-props → no-redundant-aria-prop}/index.js +9 -3
  265. package/lib/no-redundant-aria-prop/meta.d.ts +4 -0
  266. package/lib/no-redundant-aria-prop/meta.js +3 -0
  267. package/lib/no-redundant-role/index.d.ts +3 -0
  268. package/lib/{wai-aria-implicit-role → no-redundant-role}/index.js +0 -1
  269. package/lib/no-redundant-role/meta.d.ts +4 -0
  270. package/lib/no-redundant-role/meta.js +3 -0
  271. package/lib/no-refer-to-non-existent-id/index.d.ts +0 -9
  272. package/lib/no-refer-to-non-existent-id/index.js +1 -62
  273. package/lib/no-refer-to-non-existent-id/meta.d.ts +1 -2
  274. package/lib/no-refer-to-non-existent-id/meta.js +1 -2
  275. package/lib/no-restricted-attr/index.d.ts +27 -0
  276. package/lib/no-restricted-attr/index.js +96 -0
  277. package/lib/no-restricted-attr/meta.d.ts +4 -0
  278. package/lib/no-restricted-attr/meta.js +3 -0
  279. package/lib/no-restricted-element/index.d.ts +2 -0
  280. package/lib/{disallowed-element → no-restricted-element}/index.js +7 -8
  281. package/lib/no-restricted-element/meta.d.ts +4 -0
  282. package/lib/no-restricted-element/meta.js +3 -0
  283. package/lib/no-skipped-heading-level/index.d.ts +13 -0
  284. package/lib/{heading-levels → no-skipped-heading-level}/index.js +10 -5
  285. package/lib/no-skipped-heading-level/meta.d.ts +4 -0
  286. package/lib/no-skipped-heading-level/meta.js +3 -0
  287. package/lib/no-stray-head-or-body-tag/index.d.ts +28 -0
  288. package/lib/no-stray-head-or-body-tag/index.js +61 -0
  289. package/lib/no-stray-head-or-body-tag/meta.d.ts +4 -0
  290. package/lib/no-stray-head-or-body-tag/meta.js +3 -0
  291. package/lib/no-table-cell-overlap/index.d.ts +12 -0
  292. package/lib/no-table-cell-overlap/index.js +30 -0
  293. package/lib/no-table-cell-overlap/meta.d.ts +4 -0
  294. package/lib/no-table-cell-overlap/meta.js +3 -0
  295. package/lib/no-table-span-overflow/index.d.ts +12 -0
  296. package/lib/no-table-span-overflow/index.js +37 -0
  297. package/lib/no-table-span-overflow/meta.d.ts +4 -0
  298. package/lib/no-table-span-overflow/meta.js +3 -0
  299. package/lib/no-unclosed-element-at-eof/index.d.ts +2 -0
  300. package/lib/no-unclosed-element-at-eof/index.js +86 -0
  301. package/lib/no-unclosed-element-at-eof/meta.d.ts +4 -0
  302. package/lib/no-unclosed-element-at-eof/meta.js +3 -0
  303. package/lib/no-unescaped-char/index.d.ts +14 -0
  304. package/lib/{character-reference → no-unescaped-char}/index.js +31 -20
  305. package/lib/no-unescaped-char/meta.d.ts +4 -0
  306. package/lib/no-unescaped-char/meta.js +3 -0
  307. package/lib/{invalid-attr → no-unknown-attr}/index.d.ts +4 -19
  308. package/lib/no-unknown-attr/index.js +91 -0
  309. package/lib/no-unknown-attr/meta.d.ts +4 -0
  310. package/lib/no-unknown-attr/meta.js +3 -0
  311. package/lib/no-unknown-role/index.d.ts +3 -0
  312. package/lib/{wai-aria-non-existent-role → no-unknown-role}/index.js +0 -1
  313. package/lib/no-unknown-role/meta.d.ts +4 -0
  314. package/lib/no-unknown-role/meta.js +3 -0
  315. package/lib/no-unpaired-srcset-sizes/index.d.ts +12 -0
  316. package/lib/no-unpaired-srcset-sizes/index.js +77 -0
  317. package/lib/no-unpaired-srcset-sizes/meta.d.ts +4 -0
  318. package/lib/no-unpaired-srcset-sizes/meta.js +3 -0
  319. package/lib/{no-unsupported-features → no-unsupported-browser-features}/index.d.ts +1 -10
  320. package/lib/no-unsupported-browser-features/index.js +81 -0
  321. package/lib/no-unsupported-browser-features/meta.d.ts +4 -0
  322. package/lib/no-unsupported-browser-features/meta.js +3 -0
  323. package/lib/permitted-contents/index.d.ts +0 -18
  324. package/lib/permitted-contents/index.js +0 -78
  325. package/lib/permitted-contents/meta.d.ts +1 -2
  326. package/lib/permitted-contents/meta.js +1 -2
  327. package/lib/permitted-contents/represent-transparent-nodes.js +15 -6
  328. package/lib/permitted-roles/index.d.ts +3 -0
  329. package/lib/{wai-aria-permitted-roles → permitted-roles}/index.js +0 -1
  330. package/lib/permitted-roles/meta.d.ts +4 -0
  331. package/lib/permitted-roles/meta.js +3 -0
  332. package/lib/placeholder-label-option/index.d.ts +10 -4
  333. package/lib/placeholder-label-option/index.js +30 -17
  334. package/lib/placeholder-label-option/meta.d.ts +1 -2
  335. package/lib/placeholder-label-option/meta.js +1 -2
  336. package/lib/progress-value-bounds/index.d.ts +10 -0
  337. package/lib/progress-value-bounds/index.js +59 -0
  338. package/lib/progress-value-bounds/meta.d.ts +4 -0
  339. package/lib/progress-value-bounds/meta.js +3 -0
  340. package/lib/require-accessible-name/index.d.ts +0 -7
  341. package/lib/require-accessible-name/index.js +0 -7
  342. package/lib/require-accessible-name/meta.d.ts +0 -1
  343. package/lib/require-accessible-name/meta.js +0 -1
  344. package/lib/require-adjacent-popover/index.d.ts +2 -0
  345. package/lib/{neighbor-popovers → require-adjacent-popover}/index.js +1 -8
  346. package/lib/require-adjacent-popover/meta.d.ts +4 -0
  347. package/lib/require-adjacent-popover/meta.js +3 -0
  348. package/lib/require-ancestor/index.d.ts +2 -0
  349. package/lib/require-ancestor/index.js +29 -0
  350. package/lib/require-ancestor/meta.d.ts +4 -0
  351. package/lib/require-ancestor/meta.js +3 -0
  352. package/lib/require-aria-prop/index.d.ts +3 -0
  353. package/lib/{wai-aria-required-props → require-aria-prop}/index.js +0 -1
  354. package/lib/require-aria-prop/meta.d.ts +4 -0
  355. package/lib/require-aria-prop/meta.js +3 -0
  356. package/lib/{required-attr → require-attr}/index.d.ts +2 -9
  357. package/lib/{required-attr → require-attr}/index.js +0 -7
  358. package/lib/require-attr/meta.d.ts +4 -0
  359. package/lib/require-attr/meta.js +3 -0
  360. package/lib/require-datetime/index.d.ts +0 -8
  361. package/lib/require-datetime/index.js +0 -8
  362. package/lib/require-datetime/meta.d.ts +1 -2
  363. package/lib/require-datetime/meta.js +1 -2
  364. package/lib/require-dialog-autofocus/index.d.ts +0 -10
  365. package/lib/require-dialog-autofocus/index.js +0 -10
  366. package/lib/require-dialog-autofocus/meta.d.ts +0 -1
  367. package/lib/require-dialog-autofocus/meta.js +0 -1
  368. package/lib/require-doctype/index.d.ts +2 -0
  369. package/lib/require-doctype/index.js +19 -0
  370. package/lib/require-doctype/meta.d.ts +5 -0
  371. package/lib/require-doctype/meta.js +10 -0
  372. package/lib/{required-element → require-element}/index.d.ts +1 -9
  373. package/lib/{required-element → require-element}/index.js +0 -8
  374. package/lib/require-element/meta.d.ts +4 -0
  375. package/lib/require-element/meta.js +3 -0
  376. package/lib/require-end-tag/index.d.ts +2 -0
  377. package/lib/{end-tag → require-end-tag}/index.js +0 -7
  378. package/lib/require-end-tag/meta.d.ts +4 -0
  379. package/lib/require-end-tag/meta.js +3 -0
  380. package/lib/require-h1/index.d.ts +17 -0
  381. package/lib/{required-h1 → require-h1}/index.js +6 -14
  382. package/lib/require-h1/meta.d.ts +4 -0
  383. package/lib/require-h1/meta.js +3 -0
  384. package/lib/require-landmark-label/index.d.ts +11 -0
  385. package/lib/require-landmark-label/index.js +55 -0
  386. package/lib/require-landmark-label/meta.d.ts +4 -0
  387. package/lib/require-landmark-label/meta.js +3 -0
  388. package/lib/require-owned-elements/index.d.ts +3 -0
  389. package/lib/{wai-aria-required-owned-elements → require-owned-elements}/index.js +0 -2
  390. package/lib/require-owned-elements/meta.d.ts +4 -0
  391. package/lib/require-owned-elements/meta.js +3 -0
  392. package/lib/require-parent-role/index.d.ts +3 -0
  393. package/lib/{wai-aria-required-parent-role → require-parent-role}/index.js +0 -1
  394. package/lib/require-parent-role/meta.d.ts +4 -0
  395. package/lib/require-parent-role/meta.js +3 -0
  396. package/lib/role-supports-aria-prop/index.d.ts +8 -0
  397. package/lib/{wai-aria-disallowed-props → role-supports-aria-prop}/index.js +11 -10
  398. package/lib/role-supports-aria-prop/meta.d.ts +4 -0
  399. package/lib/role-supports-aria-prop/meta.js +3 -0
  400. package/lib/rule-aliases.d.ts +2 -0
  401. package/lib/rule-aliases.js +325 -0
  402. package/lib/sizes-auto-requires-lazy-loading/index.d.ts +14 -0
  403. package/lib/sizes-auto-requires-lazy-loading/index.js +68 -0
  404. package/lib/sizes-auto-requires-lazy-loading/meta.d.ts +4 -0
  405. package/lib/sizes-auto-requires-lazy-loading/meta.js +3 -0
  406. package/lib/srcset-sizes-constraint/parse-srcset.d.ts +6 -0
  407. package/lib/srcset-sizes-constraint/parse-srcset.js +6 -0
  408. package/lib/srcset-sizes-constraint/sibling-helpers.d.ts +21 -0
  409. package/lib/srcset-sizes-constraint/sibling-helpers.js +37 -0
  410. package/lib/tab-requires-tabpanel/index.d.ts +3 -0
  411. package/lib/tab-requires-tabpanel/index.js +21 -0
  412. package/lib/tab-requires-tabpanel/meta.d.ts +4 -0
  413. package/lib/tab-requires-tabpanel/meta.js +3 -0
  414. package/lib/table-row-column-alignment/grid.d.ts +108 -52
  415. package/lib/table-row-column-alignment/grid.js +276 -203
  416. package/lib/table-row-column-alignment/types.d.ts +6 -8
  417. package/lib/usemap-references-map/index.d.ts +14 -0
  418. package/lib/usemap-references-map/index.js +46 -0
  419. package/lib/usemap-references-map/meta.d.ts +4 -0
  420. package/lib/usemap-references-map/meta.js +3 -0
  421. package/lib/valid-importmap/index.d.ts +2 -0
  422. package/lib/valid-importmap/index.js +176 -0
  423. package/lib/valid-importmap/meta.d.ts +4 -0
  424. package/lib/valid-importmap/meta.js +3 -0
  425. package/lib/valid-speculation-rules/index.d.ts +2 -0
  426. package/lib/valid-speculation-rules/index.js +292 -0
  427. package/lib/valid-speculation-rules/meta.d.ts +4 -0
  428. package/lib/valid-speculation-rules/meta.js +3 -0
  429. package/lib/wai-aria/checkings/contradictory-aria-prop.d.ts +23 -0
  430. package/lib/wai-aria/checkings/{implicit-props.js → contradictory-aria-prop.js} +22 -14
  431. package/lib/wai-aria/checkings/element-supports-aria-prop.d.ts +20 -0
  432. package/lib/wai-aria/checkings/element-supports-aria-prop.js +83 -0
  433. package/lib/wai-aria/checkings/prohibited-naming.d.ts +35 -0
  434. package/lib/wai-aria/checkings/prohibited-naming.js +64 -0
  435. package/lib/wai-aria/checkings/redundant-aria-prop.d.ts +23 -0
  436. package/lib/wai-aria/checkings/redundant-aria-prop.js +53 -0
  437. package/lib/wai-aria/checkings/required-prop.d.ts +4 -0
  438. package/lib/wai-aria/checkings/required-prop.js +16 -3
  439. package/lib/wai-aria/checkings/role-supports-aria-prop.d.ts +20 -0
  440. package/lib/wai-aria/checkings/role-supports-aria-prop.js +30 -0
  441. package/lib/wai-aria/checkings/tab-requires-tabpanel.d.ts +19 -0
  442. package/lib/wai-aria/checkings/tab-requires-tabpanel.js +56 -0
  443. package/lib/wai-aria/default-options.js +1 -0
  444. package/lib/wai-aria/types.d.ts +2 -0
  445. package/package.json +11 -10
  446. package/schema.json +275 -59
  447. package/SKILL.md +0 -77
  448. package/lib/attr-duplication/index.d.ts +0 -9
  449. package/lib/attr-duplication/meta.d.ts +0 -6
  450. package/lib/attr-duplication/meta.js +0 -5
  451. package/lib/character-reference/index.d.ts +0 -12
  452. package/lib/character-reference/meta.d.ts +0 -5
  453. package/lib/character-reference/meta.js +0 -4
  454. package/lib/correct-aspect-ratio/meta.js +0 -3
  455. package/lib/deprecated-attr/index.d.ts +0 -8
  456. package/lib/deprecated-attr/meta.d.ts +0 -5
  457. package/lib/deprecated-attr/meta.js +0 -4
  458. package/lib/deprecated-element/index.d.ts +0 -8
  459. package/lib/deprecated-element/meta.d.ts +0 -5
  460. package/lib/deprecated-element/meta.js +0 -4
  461. package/lib/disallowed-element/index.d.ts +0 -9
  462. package/lib/disallowed-element/meta.d.ts +0 -5
  463. package/lib/disallowed-element/meta.js +0 -4
  464. package/lib/doctype/index.d.ts +0 -15
  465. package/lib/doctype/meta.d.ts +0 -5
  466. package/lib/doctype/meta.js +0 -4
  467. package/lib/end-tag/index.d.ts +0 -9
  468. package/lib/end-tag/meta.d.ts +0 -5
  469. package/lib/end-tag/meta.js +0 -4
  470. package/lib/heading-levels/index.d.ts +0 -8
  471. package/lib/heading-levels/meta.d.ts +0 -5
  472. package/lib/heading-levels/meta.js +0 -4
  473. package/lib/id-duplication/index.d.ts +0 -9
  474. package/lib/id-duplication/meta.d.ts +0 -5
  475. package/lib/id-duplication/meta.js +0 -4
  476. package/lib/ineffective-attr/index.d.ts +0 -9
  477. package/lib/ineffective-attr/meta.d.ts +0 -6
  478. package/lib/ineffective-attr/meta.js +0 -5
  479. package/lib/invalid-attr/index.js +0 -207
  480. package/lib/invalid-attr/meta.d.ts +0 -5
  481. package/lib/invalid-attr/meta.js +0 -4
  482. package/lib/landmark-roles/index.d.ts +0 -22
  483. package/lib/landmark-roles/index.js +0 -142
  484. package/lib/landmark-roles/meta.d.ts +0 -5
  485. package/lib/landmark-roles/meta.js +0 -4
  486. package/lib/neighbor-popovers/index.d.ts +0 -10
  487. package/lib/neighbor-popovers/meta.d.ts +0 -5
  488. package/lib/neighbor-popovers/meta.js +0 -4
  489. package/lib/no-hard-code-id/index.d.ts +0 -10
  490. package/lib/no-hard-code-id/meta.d.ts +0 -5
  491. package/lib/no-hard-code-id/meta.js +0 -4
  492. package/lib/no-unsupported-features/index.js +0 -139
  493. package/lib/no-unsupported-features/meta.d.ts +0 -5
  494. package/lib/no-unsupported-features/meta.js +0 -4
  495. package/lib/no-use-event-handler-attr/index.d.ts +0 -18
  496. package/lib/no-use-event-handler-attr/meta.d.ts +0 -5
  497. package/lib/no-use-event-handler-attr/meta.js +0 -4
  498. package/lib/redundant-accessible-name/meta.d.ts +0 -5
  499. package/lib/redundant-accessible-name/meta.js +0 -4
  500. package/lib/required-attr/meta.d.ts +0 -5
  501. package/lib/required-attr/meta.js +0 -4
  502. package/lib/required-element/meta.d.ts +0 -5
  503. package/lib/required-element/meta.js +0 -4
  504. package/lib/required-h1/index.d.ts +0 -18
  505. package/lib/required-h1/meta.d.ts +0 -5
  506. package/lib/required-h1/meta.js +0 -4
  507. package/lib/srcset-sizes-constraint/index.d.ts +0 -6
  508. package/lib/srcset-sizes-constraint/index.js +0 -108
  509. package/lib/srcset-sizes-constraint/meta.d.ts +0 -5
  510. package/lib/srcset-sizes-constraint/meta.js +0 -4
  511. package/lib/table-row-column-alignment/index.d.ts +0 -10
  512. package/lib/table-row-column-alignment/index.js +0 -97
  513. package/lib/table-row-column-alignment/meta.d.ts +0 -5
  514. package/lib/table-row-column-alignment/meta.js +0 -4
  515. package/lib/use-list/meta.d.ts +0 -5
  516. package/lib/use-list/meta.js +0 -4
  517. package/lib/wai-aria/checkings/disallowed-prop.d.ts +0 -23
  518. package/lib/wai-aria/checkings/disallowed-prop.js +0 -84
  519. package/lib/wai-aria/checkings/implicit-props.d.ts +0 -20
  520. package/lib/wai-aria/index.d.ts +0 -13
  521. package/lib/wai-aria/index.js +0 -115
  522. package/lib/wai-aria/meta.d.ts +0 -5
  523. package/lib/wai-aria/meta.js +0 -4
  524. package/lib/wai-aria-default-value/index.d.ts +0 -4
  525. package/lib/wai-aria-default-value/meta.d.ts +0 -5
  526. package/lib/wai-aria-default-value/meta.js +0 -4
  527. package/lib/wai-aria-deprecated-props/index.d.ts +0 -4
  528. package/lib/wai-aria-deprecated-props/meta.d.ts +0 -5
  529. package/lib/wai-aria-deprecated-props/meta.js +0 -4
  530. package/lib/wai-aria-disallowed-props/index.d.ts +0 -4
  531. package/lib/wai-aria-disallowed-props/meta.d.ts +0 -5
  532. package/lib/wai-aria-disallowed-props/meta.js +0 -4
  533. package/lib/wai-aria-implicit-props/index.d.ts +0 -4
  534. package/lib/wai-aria-implicit-props/meta.d.ts +0 -5
  535. package/lib/wai-aria-implicit-props/meta.js +0 -4
  536. package/lib/wai-aria-implicit-role/index.d.ts +0 -4
  537. package/lib/wai-aria-interaction-in-hidden/index.d.ts +0 -4
  538. package/lib/wai-aria-interaction-in-hidden/meta.d.ts +0 -5
  539. package/lib/wai-aria-interaction-in-hidden/meta.js +0 -4
  540. package/lib/wai-aria-no-global-prop/index.d.ts +0 -4
  541. package/lib/wai-aria-no-global-prop/meta.d.ts +0 -5
  542. package/lib/wai-aria-no-global-prop/meta.js +0 -4
  543. package/lib/wai-aria-non-existent-role/index.d.ts +0 -4
  544. package/lib/wai-aria-permitted-roles/index.d.ts +0 -4
  545. package/lib/wai-aria-presentational-children/index.d.ts +0 -4
  546. package/lib/wai-aria-presentational-children/meta.d.ts +0 -5
  547. package/lib/wai-aria-presentational-children/meta.js +0 -4
  548. package/lib/wai-aria-required-parent-role/index.d.ts +0 -4
  549. package/lib/wai-aria-value/index.d.ts +0 -4
  550. package/lib/wai-aria-value/meta.d.ts +0 -5
  551. package/lib/wai-aria-value/meta.js +0 -4
  552. /package/lib/{wai-aria-abstract-role → aria-prop-requires-role}/meta.d.ts +0 -0
  553. /package/lib/{wai-aria-abstract-role → aria-prop-requires-role}/meta.js +0 -0
  554. /package/lib/{wai-aria-deprecated-role → element-supports-aria-prop}/meta.d.ts +0 -0
  555. /package/lib/{wai-aria-deprecated-role → element-supports-aria-prop}/meta.js +0 -0
  556. /package/lib/{wai-aria-implicit-role → no-abstract-role}/meta.d.ts +0 -0
  557. /package/lib/{wai-aria-implicit-role → no-abstract-role}/meta.js +0 -0
  558. /package/lib/{wai-aria-non-existent-role → no-aria-on-presentational-children}/meta.d.ts +0 -0
  559. /package/lib/{wai-aria-non-existent-role → no-aria-on-presentational-children}/meta.js +0 -0
  560. /package/lib/{wai-aria-permitted-roles → no-contradictory-aria-prop}/meta.d.ts +0 -0
  561. /package/lib/{wai-aria-permitted-roles → no-contradictory-aria-prop}/meta.js +0 -0
  562. /package/lib/{wai-aria-required-owned-elements → no-default-aria-value}/meta.d.ts +0 -0
  563. /package/lib/{wai-aria-required-owned-elements → no-default-aria-value}/meta.js +0 -0
  564. /package/lib/{wai-aria-required-parent-role → no-deprecated-aria-prop}/meta.d.ts +0 -0
  565. /package/lib/{wai-aria-required-parent-role → no-deprecated-aria-prop}/meta.js +0 -0
  566. /package/lib/{wai-aria-required-props → no-deprecated-role}/meta.d.ts +0 -0
  567. /package/lib/{wai-aria-required-props → no-deprecated-role}/meta.js +0 -0
  568. /package/lib/{correct-aspect-ratio → no-mismatched-aspect-ratio}/index.d.ts +0 -0
  569. /package/lib/{correct-aspect-ratio → no-mismatched-aspect-ratio}/resolve-image-size.d.ts +0 -0
  570. /package/lib/{no-unsupported-features → no-unsupported-browser-features}/compat-data.d.ts +0 -0
  571. /package/lib/{no-unsupported-features → no-unsupported-browser-features}/compat-data.js +0 -0
  572. /package/lib/{no-unsupported-features → no-unsupported-browser-features}/resolve-browsers.d.ts +0 -0
  573. /package/lib/{no-unsupported-features → no-unsupported-browser-features}/resolve-browsers.js +0 -0
@@ -0,0 +1,83 @@
1
+ import { ARIA_RECOMMENDED_VERSION, getARIA } from '@markuplint/ml-spec';
2
+ /**
3
+ * Checks the ARIA in HTML element-specific `aria-*` restrictions: spec data
4
+ * may forbid every `aria-*` attribute on an element with no implicit role
5
+ * (`properties: false`, e.g. `input[type=hidden]`), whitelist a small set
6
+ * (`properties: { only: [...] }`, e.g. `<br>`/`<wbr>` accept only
7
+ * `aria-hidden`), or blacklist specific properties with a suggested
8
+ * alternative (`properties: { without: [...] }`).
9
+ *
10
+ * @param attr - The ARIA attribute node to inspect.
11
+ * @param role - The computed ARIA role of the element.
12
+ * @param propSpecs - The list of ARIA property specifications for type lookup.
13
+ * @returns A violation if the element-specific restriction disallows the property.
14
+ */
15
+ export const checkingElementSupportsAriaProp = ({ attr, role, propSpecs }) => t => {
16
+ if (!/^aria-/i.test(attr.name)) {
17
+ return;
18
+ }
19
+ const ariaVersion = attr.rule.options?.version ??
20
+ attr.ownerMLDocument.ruleCommonSettings?.ariaVersion ??
21
+ ARIA_RECOMMENDED_VERSION;
22
+ const propSpec = propSpecs.find(p => p.name === attr.name);
23
+ const elAriaSpec = getARIA(attr.ownerMLDocument.specs, attr.ownerElement.localName, attr.ownerElement.namespaceURI, ariaVersion, attr.ownerElement.matches.bind(attr.ownerElement));
24
+ // Spec data may set `properties: false` to forbid every aria-* attribute on
25
+ // elements that have no implicit role and accept no explicit role
26
+ // (e.g. `input[type=hidden]`). The role-based check (`role-supports-aria-prop`)
27
+ // does not cover this because `role` is null for such elements.
28
+ // Note: when an explicit `role=` is present, `role` is non-null and this
29
+ // branch is skipped — but `permitted-roles` already rejects the
30
+ // explicit role for elements whose spec says `permittedRoles: false`,
31
+ // so the user sees a violation either way.
32
+ if (!role && elAriaSpec?.properties === false) {
33
+ return {
34
+ scope: attr,
35
+ message: t('{0:c} on {1}', t('{0} is {1:c}', t('the "{0*}" {1}', attr.name, `ARIA ${propSpec?.type ?? 'property'}`), 'disallowed'), t('the "{0*}" {1}', attr.ownerElement.localName, 'element')),
36
+ };
37
+ }
38
+ // Spec data may set `properties: { only: [...] }` to whitelist a small
39
+ // set of aria-* attributes (e.g. `<br>` / `<wbr>` accept only
40
+ // `aria-hidden`). When the attribute is outside that whitelist, the
41
+ // element-specific restriction overrides the role-derived check.
42
+ //
43
+ // The schema permits entries in either bare-name form (`"aria-hidden"`)
44
+ // or name/value pair form (`{ name, value? }`). No html-spec entry
45
+ // currently uses the value form, so we only key on the name. If the
46
+ // value form becomes necessary later, mirror the value-matching path
47
+ // already implemented in the `properties.without` branch below.
48
+ if (elAriaSpec?.properties !== false && elAriaSpec?.properties?.only) {
49
+ const onlyNames = elAriaSpec.properties.only.map(o => (typeof o === 'string' ? o : o.name));
50
+ if (!onlyNames.includes(attr.name)) {
51
+ return {
52
+ scope: attr,
53
+ message: t('{0:c} on {1}', t('{0} is {1:c}', t('the "{0*}" {1}', attr.name, `ARIA ${propSpec?.type ?? 'property'}`), 'disallowed'), t('the "{0*}" {1}', attr.ownerElement.localName, 'element')),
54
+ };
55
+ }
56
+ }
57
+ if (elAriaSpec?.properties !== false && elAriaSpec?.properties?.without) {
58
+ for (const ignore of elAriaSpec.properties.without) {
59
+ if (ignore.name === attr.name) {
60
+ const hasNativeAttr = ignore.alt?.method === 'set-attr' && attr.ownerElement.hasAttribute(ignore.alt.target);
61
+ return {
62
+ scope: attr,
63
+ message: t('{0:c} on {1}', t(ignore.type === 'must-not'
64
+ ? '{0} must not {1}'
65
+ : ignore.type === 'should-not'
66
+ ? '{0} should not {1}'
67
+ : '{0} is not recommended to {1}',
68
+ // {0}
69
+ t('the "{0*}" {1}', attr.name, `ARIA ${propSpec?.type ?? 'property'}`),
70
+ // {1}
71
+ 'use'), t('the "{0*}" {1}', attr.ownerElement.localName, 'element')) +
72
+ (hasNativeAttr
73
+ ? t('. ') +
74
+ t('As its {0} is already provided by {1}', t('state'), t('the "{0*}" {1}', ignore.alt.target, 'attribute'))
75
+ : ignore.alt
76
+ ? t('. ') +
77
+ t('{0} if you {1} {2}', t(ignore.alt.method === 'remove-attr' ? 'Remove {0}' : 'Add {0}', t('the "{0*}" {1}', ignore.alt.target, 'attribute')), 'use', t('the {0}', `ARIA ${propSpec?.type ?? 'property'}`))
78
+ : ''),
79
+ };
80
+ }
81
+ }
82
+ }
83
+ };
@@ -0,0 +1,35 @@
1
+ import type { Options } from '../types.js';
2
+ import type { AttrChecker } from '@markuplint/ml-core';
3
+ import type { ARIAProperty, ARIARole } from '@markuplint/ml-spec';
4
+ /**
5
+ * Checks the ARIA in HTML naming-prohibition constraint: elements with
6
+ * `namingProhibited=true` must not use `aria-label` / `aria-labelledby` /
7
+ * `aria-braillelabel` unless an explicit role that supports naming is set.
8
+ * When `role` is null and the element is namingProhibited, the naming attrs
9
+ * are prohibited.
10
+ *
11
+ * At time of writing, the affected elements (implicitRole=false +
12
+ * namingProhibited=true in html-spec) are:
13
+ * abbr, cite, figcaption, kbd, label, legend, mark, rt, var
14
+ * This list is not hard-coded here; it is derived from html-spec data.
15
+ *
16
+ * Autonomous custom elements (`<x-y>`, no `is=` attribute, no spec.<el>
17
+ * entry) are treated the same way: ARIA in HTML §4.4 forbids naming
18
+ * attrs unless an explicit role that supports naming is set. The
19
+ * `elementType === 'web-component'` discriminator excludes
20
+ * customised-built-in elements (`<button is="x-y">`) — those inherit
21
+ * the host element's namingProhibited flag through the regular path.
22
+ * `getComputedRole` returns null for custom elements even when a
23
+ * `role=` attribute is set (it can't validate the role against an
24
+ * unknown element's permittedRoles), so consult the raw attribute
25
+ * directly to detect "an explicit role that supports naming is set".
26
+ *
27
+ * @param attr - The ARIA attribute node to inspect.
28
+ * @param role - The computed ARIA role of the element.
29
+ * @param propSpecs - The list of ARIA property specifications for type lookup.
30
+ * @returns A violation if a naming attribute is used on a naming-prohibited element.
31
+ */
32
+ export declare const checkingProhibitedNaming: AttrChecker<boolean, Options, {
33
+ role: ARIARole | null;
34
+ propSpecs: readonly ARIAProperty[];
35
+ }>;
@@ -0,0 +1,64 @@
1
+ import { ARIA_RECOMMENDED_VERSION, getARIA } from '@markuplint/ml-spec';
2
+ /**
3
+ * ARIA naming attributes subject to the "naming prohibition" constraint
4
+ * defined by ARIA in HTML.
5
+ *
6
+ * @see https://w3c.github.io/html-aria/#dfn-naming-prohibited
7
+ */
8
+ const NAMING_ATTRS = new Set(['aria-label', 'aria-labelledby', 'aria-braillelabel']);
9
+ /**
10
+ * Checks the ARIA in HTML naming-prohibition constraint: elements with
11
+ * `namingProhibited=true` must not use `aria-label` / `aria-labelledby` /
12
+ * `aria-braillelabel` unless an explicit role that supports naming is set.
13
+ * When `role` is null and the element is namingProhibited, the naming attrs
14
+ * are prohibited.
15
+ *
16
+ * At time of writing, the affected elements (implicitRole=false +
17
+ * namingProhibited=true in html-spec) are:
18
+ * abbr, cite, figcaption, kbd, label, legend, mark, rt, var
19
+ * This list is not hard-coded here; it is derived from html-spec data.
20
+ *
21
+ * Autonomous custom elements (`<x-y>`, no `is=` attribute, no spec.<el>
22
+ * entry) are treated the same way: ARIA in HTML §4.4 forbids naming
23
+ * attrs unless an explicit role that supports naming is set. The
24
+ * `elementType === 'web-component'` discriminator excludes
25
+ * customised-built-in elements (`<button is="x-y">`) — those inherit
26
+ * the host element's namingProhibited flag through the regular path.
27
+ * `getComputedRole` returns null for custom elements even when a
28
+ * `role=` attribute is set (it can't validate the role against an
29
+ * unknown element's permittedRoles), so consult the raw attribute
30
+ * directly to detect "an explicit role that supports naming is set".
31
+ *
32
+ * @param attr - The ARIA attribute node to inspect.
33
+ * @param role - The computed ARIA role of the element.
34
+ * @param propSpecs - The list of ARIA property specifications for type lookup.
35
+ * @returns A violation if a naming attribute is used on a naming-prohibited element.
36
+ */
37
+ export const checkingProhibitedNaming = ({ attr, role, propSpecs }) => t => {
38
+ if (!/^aria-/i.test(attr.name)) {
39
+ return;
40
+ }
41
+ if (!NAMING_ATTRS.has(attr.name)) {
42
+ return;
43
+ }
44
+ if (role) {
45
+ return;
46
+ }
47
+ const ariaVersion = attr.rule.options?.version ??
48
+ attr.ownerMLDocument.ruleCommonSettings?.ariaVersion ??
49
+ ARIA_RECOMMENDED_VERSION;
50
+ const elAriaSpec = getARIA(attr.ownerMLDocument.specs, attr.ownerElement.localName, attr.ownerElement.namespaceURI, ariaVersion, attr.ownerElement.matches.bind(attr.ownerElement));
51
+ const isAutonomousCustomElement = attr.ownerElement.elementType === 'web-component' && !attr.ownerElement.hasAttribute('is');
52
+ const hasExplicitRoleAttr = isAutonomousCustomElement && (attr.ownerElement.getAttribute('role')?.trim() ?? '') !== '';
53
+ if (hasExplicitRoleAttr) {
54
+ return;
55
+ }
56
+ if (elAriaSpec?.namingProhibited !== true && !isAutonomousCustomElement) {
57
+ return;
58
+ }
59
+ const propSpec = propSpecs.find(p => p.name === attr.name);
60
+ return {
61
+ scope: attr,
62
+ message: t('{0:c} on {1}', t('{0} is {1:c}', t('the "{0*}" {1}', attr.name, `ARIA ${propSpec?.type ?? 'property'}`), 'prohibited'), t('the "{0*}" {1}', attr.ownerElement.localName, 'element')),
63
+ };
64
+ };
@@ -0,0 +1,23 @@
1
+ import type { Options } from '../types.js';
2
+ import type { AttrChecker } from '@markuplint/ml-core';
3
+ import type { ARIAProperty, Attribute } from '@markuplint/ml-spec';
4
+ /**
5
+ * Checks whether an ARIA property is redundant because an equivalent native
6
+ * HTML attribute already conveys the same semantics with the same value —
7
+ * either the current value of that attribute, or (when absent) its implicit
8
+ * default.
9
+ *
10
+ * Many ARIA properties have equivalent HTML attributes (e.g., `aria-required`
11
+ * and `required`). ARIA in HTML §6 recommends using the native attribute in
12
+ * preference to the ARIA equivalent, so restating the same value via `aria-*`
13
+ * is superfluous.
14
+ *
15
+ * @param attr - The ARIA attribute node to inspect.
16
+ * @param propSpecs - The list of ARIA property specifications for equivalence lookup.
17
+ * @param attrSpecs - The HTML attribute specifications for the element.
18
+ * @returns A violation if the ARIA property redundantly restates an equivalent HTML attribute.
19
+ */
20
+ export declare const checkingRedundantAriaProp: AttrChecker<boolean, Options, {
21
+ propSpecs: readonly ARIAProperty[];
22
+ attrSpecs: readonly Attribute[] | null;
23
+ }>;
@@ -0,0 +1,53 @@
1
+ import { resolveAttrEligibility } from '../../attr-eligibility.js';
2
+ /**
3
+ * Checks whether an ARIA property is redundant because an equivalent native
4
+ * HTML attribute already conveys the same semantics with the same value —
5
+ * either the current value of that attribute, or (when absent) its implicit
6
+ * default.
7
+ *
8
+ * Many ARIA properties have equivalent HTML attributes (e.g., `aria-required`
9
+ * and `required`). ARIA in HTML §6 recommends using the native attribute in
10
+ * preference to the ARIA equivalent, so restating the same value via `aria-*`
11
+ * is superfluous.
12
+ *
13
+ * @param attr - The ARIA attribute node to inspect.
14
+ * @param propSpecs - The list of ARIA property specifications for equivalence lookup.
15
+ * @param attrSpecs - The HTML attribute specifications for the element.
16
+ * @returns A violation if the ARIA property redundantly restates an equivalent HTML attribute.
17
+ */
18
+ export const checkingRedundantAriaProp = ({ attr, propSpecs, attrSpecs }) => t => {
19
+ if (!attrSpecs) {
20
+ return;
21
+ }
22
+ if (attr.isDynamicValue) {
23
+ return;
24
+ }
25
+ const propSpec = propSpecs.find(p => p.name === attr.name);
26
+ if (!propSpec?.equivalentHtmlAttrs) {
27
+ return;
28
+ }
29
+ for (const equivalentHtmlAttr of propSpec.equivalentHtmlAttrs) {
30
+ const eligibility = resolveAttrEligibility(equivalentHtmlAttr.htmlAttrName, attr.ownerElement, attrSpecs);
31
+ // Skip only when the native attribute doesn't apply to this element at all
32
+ // (unknown name, case mismatch, or an unmet condition) — mirrors the old
33
+ // `invalidType === 'non-existent'` check. `noUse` still proceeds: an
34
+ // explicitly-forbidden native attribute can still be "implicit" for
35
+ // equivalence purposes.
36
+ if (eligibility.status === 'unknown' ||
37
+ eligibility.status === 'case-mismatch' ||
38
+ eligibility.status === 'condition-not-met') {
39
+ continue;
40
+ }
41
+ if (!attr.ownerElement.hasAttribute(equivalentHtmlAttr.htmlAttrName)) {
42
+ continue;
43
+ }
44
+ const value = attr.value.trim().toLowerCase();
45
+ const targetAttrValue = attr.ownerElement.getAttribute(equivalentHtmlAttr.htmlAttrName);
46
+ if ((equivalentHtmlAttr.value == null && targetAttrValue === value) || equivalentHtmlAttr.value === value) {
47
+ return {
48
+ scope: attr,
49
+ message: t('{0} has {1}', t('the "{0*}" {1}', attr.name, `ARIA ${propSpec.type}`), t('the same {0} as {1}', 'semantics', t('{0} or {1}', t('the current "{0}" {1}', equivalentHtmlAttr.htmlAttrName, 'attribute'), t('the implicit "{0}" {1}', equivalentHtmlAttr.htmlAttrName, 'attribute')))),
50
+ };
51
+ }
52
+ }
53
+ };
@@ -9,6 +9,10 @@ import { type ARIAProperty, type ARIARole } from '@markuplint/ml-spec';
9
9
  * properties. Implicit roles are skipped since the browser provides default semantics.
10
10
  * Alternative native HTML attributes that satisfy the requirement are also considered.
11
11
  *
12
+ * If a property declares `requiredCondition: 'focusable'` (currently only `separator`'s
13
+ * `aria-valuenow`), the requirement is gated by `mayBeFocusable`: a non-focusable
14
+ * separator no longer reports a missing `aria-valuenow`.
15
+ *
12
16
  * @param el - The element node to inspect for required properties.
13
17
  * @param role - The computed ARIA role (with an optional `isImplicit` flag).
14
18
  * @param propSpecs - The list of ARIA property specifications for type lookup.
@@ -1,4 +1,4 @@
1
- import { ARIA_RECOMMENDED_VERSION, getARIA } from '@markuplint/ml-spec';
1
+ import { ARIA_RECOMMENDED_VERSION, getARIA, mayBeFocusable, } from '@markuplint/ml-spec';
2
2
  /**
3
3
  * Checks whether all required ARIA properties for the element's computed role are present.
4
4
  *
@@ -7,6 +7,10 @@ import { ARIA_RECOMMENDED_VERSION, getARIA } from '@markuplint/ml-spec';
7
7
  * properties. Implicit roles are skipped since the browser provides default semantics.
8
8
  * Alternative native HTML attributes that satisfy the requirement are also considered.
9
9
  *
10
+ * If a property declares `requiredCondition: 'focusable'` (currently only `separator`'s
11
+ * `aria-valuenow`), the requirement is gated by `mayBeFocusable`: a non-focusable
12
+ * separator no longer reports a missing `aria-valuenow`.
13
+ *
10
14
  * @param el - The element node to inspect for required properties.
11
15
  * @param role - The computed ARIA role (with an optional `isImplicit` flag).
12
16
  * @param propSpecs - The list of ARIA property specifications for type lookup.
@@ -19,8 +23,17 @@ export const checkingRequiredProp = ({ el, role, propSpecs }) => t => {
19
23
  if (role.isImplicit) {
20
24
  return;
21
25
  }
22
- const requiredProps = role.ownedProperties.filter(s => s.required).map(s => s.name);
23
- for (const requiredProp of requiredProps) {
26
+ const requiredProps = role.ownedProperties.filter(s => {
27
+ if (!s.required)
28
+ return false;
29
+ // `requiredCondition: 'focusable'` makes the property required only when the
30
+ // element may be focusable (e.g. `separator`'s `aria-valuenow`).
31
+ if (s.requiredCondition === 'focusable' && !mayBeFocusable(el, el.ownerMLDocument.specs)) {
32
+ return false;
33
+ }
34
+ return true;
35
+ });
36
+ for (const { name: requiredProp } of requiredProps) {
24
37
  const has = el.attributes.some(attr => {
25
38
  const attrName = attr.name.toLowerCase();
26
39
  return attrName === requiredProp;
@@ -0,0 +1,20 @@
1
+ import type { Options } from '../types.js';
2
+ import type { AttrChecker } from '@markuplint/ml-core';
3
+ import type { ARIAProperty, ARIARole } from '@markuplint/ml-spec';
4
+ /**
5
+ * Checks whether an ARIA property or state is supported by the element's
6
+ * computed role, per the role's WAI-ARIA definition (`ownedProperties`).
7
+ *
8
+ * When the element has no computed role, there is nothing to check here —
9
+ * a role-less element with `aria-*` restrictions is `element-supports-aria-prop`'s
10
+ * concern instead.
11
+ *
12
+ * @param attr - The ARIA attribute node to inspect.
13
+ * @param role - The computed ARIA role of the element.
14
+ * @param propSpecs - The list of ARIA property specifications for type lookup.
15
+ * @returns A violation if the property is not supported by the given role.
16
+ */
17
+ export declare const checkingRoleSupportsAriaProp: AttrChecker<boolean, Options, {
18
+ role: ARIARole | null;
19
+ propSpecs: readonly ARIAProperty[];
20
+ }>;
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Checks whether an ARIA property or state is supported by the element's
3
+ * computed role, per the role's WAI-ARIA definition (`ownedProperties`).
4
+ *
5
+ * When the element has no computed role, there is nothing to check here —
6
+ * a role-less element with `aria-*` restrictions is `element-supports-aria-prop`'s
7
+ * concern instead.
8
+ *
9
+ * @param attr - The ARIA attribute node to inspect.
10
+ * @param role - The computed ARIA role of the element.
11
+ * @param propSpecs - The list of ARIA property specifications for type lookup.
12
+ * @returns A violation if the property is not supported by the given role.
13
+ */
14
+ export const checkingRoleSupportsAriaProp = ({ attr, role, propSpecs }) => t => {
15
+ if (!/^aria-/i.test(attr.name)) {
16
+ return;
17
+ }
18
+ if (!role) {
19
+ return;
20
+ }
21
+ const statesAndProp = role.ownedProperties.find(p => p.name === attr.name);
22
+ if (statesAndProp) {
23
+ return;
24
+ }
25
+ const propSpec = propSpecs.find(p => p.name === attr.name);
26
+ return {
27
+ scope: attr,
28
+ message: t('{0:c} on {1}', t('{0} is {1:c}', t('the "{0*}" {1}', attr.name, `ARIA ${propSpec?.type ?? 'property'}`), 'disallowed'), t('the "{0*}" {1}', role.name, 'role')),
29
+ };
30
+ };
@@ -0,0 +1,19 @@
1
+ import type { Options } from '../types.js';
2
+ import type { ElementChecker } from '@markuplint/ml-core';
3
+ import type { ARIARole } from '@markuplint/ml-spec';
4
+ /**
5
+ * Checks that an active `tab` role element has a corresponding `tabpanel` role element.
6
+ *
7
+ * The correspondence is resolved the same way ARIA in HTML authors are expected to
8
+ * express it: the tab's `aria-controls` idref list points to a `tabpanel`, or some
9
+ * `tabpanel` element's `aria-labelledby` idref list points back at the tab's own `id`.
10
+ *
11
+ * @see https://www.w3.org/TR/wai-aria-1.3/#tab — "Authors MUST ensure that if a tab
12
+ * is active, a corresponding tabpanel that represents the active tab is rendered."
13
+ * @param el - The element node to inspect.
14
+ * @param role - The computed ARIA role of the element.
15
+ * @returns A violation if the active tab has no corresponding tabpanel.
16
+ */
17
+ export declare const checkingTabRequiresTabpanel: ElementChecker<boolean, Options, {
18
+ role?: ARIARole | null;
19
+ }>;
@@ -0,0 +1,56 @@
1
+ import { ARIA_RECOMMENDED_VERSION, getComputedRole } from '@markuplint/ml-spec';
2
+ /**
3
+ * Checks that an active `tab` role element has a corresponding `tabpanel` role element.
4
+ *
5
+ * The correspondence is resolved the same way ARIA in HTML authors are expected to
6
+ * express it: the tab's `aria-controls` idref list points to a `tabpanel`, or some
7
+ * `tabpanel` element's `aria-labelledby` idref list points back at the tab's own `id`.
8
+ *
9
+ * @see https://www.w3.org/TR/wai-aria-1.3/#tab — "Authors MUST ensure that if a tab
10
+ * is active, a corresponding tabpanel that represents the active tab is rendered."
11
+ * @param el - The element node to inspect.
12
+ * @param role - The computed ARIA role of the element.
13
+ * @returns A violation if the active tab has no corresponding tabpanel.
14
+ */
15
+ export const checkingTabRequiresTabpanel = ({ el, role }) => t => {
16
+ if (role?.name !== 'tab') {
17
+ return;
18
+ }
19
+ const selectedAttr = el.getAttributeNode('aria-selected');
20
+ if (!selectedAttr || selectedAttr.isDynamicValue || selectedAttr.value !== 'true') {
21
+ return;
22
+ }
23
+ const document = el.ownerMLDocument;
24
+ const ariaVersion = el.rule.options?.version ?? document.ruleCommonSettings?.ariaVersion ?? ARIA_RECOMMENDED_VERSION;
25
+ const isTabpanel = (candidate) => getComputedRole(document.specs, candidate, ariaVersion).role?.name === 'tabpanel';
26
+ const controlsAttr = el.getAttributeNode('aria-controls');
27
+ if (controlsAttr && !controlsAttr.isDynamicValue) {
28
+ const hasControlledTabpanel = controlsAttr.value
29
+ .split(/\s+/)
30
+ .filter(Boolean)
31
+ .some(id => {
32
+ const target = document.getElementById(id);
33
+ return !!target && isTabpanel(target);
34
+ });
35
+ if (hasControlledTabpanel) {
36
+ return;
37
+ }
38
+ }
39
+ const idAttr = el.getAttributeNode('id');
40
+ if (idAttr && !idAttr.isDynamicValue) {
41
+ const tabId = idAttr.value;
42
+ const hasLabellingTabpanel = [...document.querySelectorAll('[aria-labelledby]')].some(candidate => {
43
+ const labelledbyAttr = candidate.getAttributeNode('aria-labelledby');
44
+ if (!labelledbyAttr || labelledbyAttr.isDynamicValue)
45
+ return false;
46
+ return labelledbyAttr.value.split(/\s+/).includes(tabId) && isTabpanel(candidate);
47
+ });
48
+ if (hasLabellingTabpanel) {
49
+ return;
50
+ }
51
+ }
52
+ return {
53
+ scope: el,
54
+ message: t('{0} requires {1}', t('an active "{0*}" {1}', 'tab', 'role'), t('a corresponding "{0*}" {1}', 'tabpanel', 'role')),
55
+ };
56
+ };
@@ -9,6 +9,7 @@ export const defaultOptions = {
9
9
  checkingAllowedAccessibilityChildRoles: true,
10
10
  checkingRequiredOwnedElements: true,
11
11
  checkingRequiredAccessibilityParentRole: true,
12
+ checkingTabRequiresTabpanel: true,
12
13
  checkingPresentationalChildren: false,
13
14
  checkingInteractionInHidden: false,
14
15
  disallowSetImplicitRole: true,
@@ -23,6 +23,8 @@ export type Options = {
23
23
  checkingRequiredOwnedElements: boolean;
24
24
  /** Whether to verify "Required Accessibility Parent Role" (ARIA 1.3 name) / "Required Context Role" (ARIA 1.2 name). */
25
25
  checkingRequiredAccessibilityParentRole: boolean;
26
+ /** Whether to verify that an active `tab` role has a corresponding `tabpanel` role. */
27
+ checkingTabRequiresTabpanel: boolean;
26
28
  /** Whether to warn when ARIA attributes are set on descendants of presentational-children roles. */
27
29
  checkingPresentationalChildren: boolean;
28
30
  /** Whether to warn about focusable interactive elements hidden via `aria-hidden`. */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@markuplint/rules",
3
- "version": "5.0.0-rc.2",
3
+ "version": "5.0.0-rc.5",
4
4
  "description": "Built-in rules of markuplint",
5
5
  "repository": {
6
6
  "type": "git",
@@ -10,7 +10,7 @@
10
10
  "author": "Yusuke Hirao <yusukehirao@me.com>",
11
11
  "license": "MIT",
12
12
  "engines": {
13
- "node": ">=22"
13
+ "node": ">=24"
14
14
  },
15
15
  "type": "module",
16
16
  "exports": {
@@ -31,12 +31,13 @@
31
31
  "./lib/permitted-contents/debug.js": "./lib/permitted-contents/debug.browser.js"
32
32
  },
33
33
  "dependencies": {
34
- "@markuplint/html-spec": "5.0.0-rc.2",
35
- "@markuplint/ml-core": "5.0.0-rc.2",
36
- "@markuplint/ml-spec": "5.0.0-rc.2",
37
- "@markuplint/selector": "5.0.0-rc.2",
38
- "@markuplint/shared": "5.0.0-rc.2",
39
- "@markuplint/types": "5.0.0-rc.2",
34
+ "@markuplint/html-spec": "5.0.0-rc.5",
35
+ "@markuplint/ml-config": "5.0.0-rc.5",
36
+ "@markuplint/ml-core": "5.0.0-rc.5",
37
+ "@markuplint/ml-spec": "5.0.0-rc.5",
38
+ "@markuplint/selector": "5.0.0-rc.5",
39
+ "@markuplint/shared": "5.0.0-rc.5",
40
+ "@markuplint/types": "5.0.0-rc.5",
40
41
  "@mdn/browser-compat-data": "^7.3.2",
41
42
  "@types/debug": "4.1.13",
42
43
  "ansi-colors": "4.1.3",
@@ -44,7 +45,7 @@
44
45
  "chrono-node": "2.9.0",
45
46
  "debug": "4.4.3",
46
47
  "image-size": "^2.0.2",
47
- "type-fest": "5.5.0"
48
+ "type-fest": "5.6.0"
48
49
  },
49
- "gitHead": "e43763858d9234c417053becc73dbd088c1e7ea6"
50
+ "gitHead": "8d87463af2ff3f1b83fb28da20f1819362cf3555"
50
51
  }