@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,176 @@
1
+ import { createRule } from '@markuplint/ml-core';
2
+ import meta from './meta.js';
3
+ /**
4
+ * Per HTML LS § Parse an import map string, only `imports`, `scopes`, and
5
+ * `integrity` are recognised top-level keys. Other keys trigger a warning;
6
+ * we report them as violations so authors can drop dead configuration.
7
+ *
8
+ * When HTML LS adds a new top-level key, update three places: this set,
9
+ * the "not allowed" message string below, and the rule README table.
10
+ *
11
+ * @see https://html.spec.whatwg.org/multipage/webappapis.html#parse-an-import-map-string
12
+ */
13
+ const ALLOWED_TOP_LEVEL_KEYS = new Set(['imports', 'scopes', 'integrity']);
14
+ function isPlainObject(value) {
15
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
16
+ }
17
+ /**
18
+ * Resolve a URL-like module specifier per HTML LS. Returns `true` if the
19
+ * specifier either starts with one of `/`, `./`, `../` (resolvable against
20
+ * a base URL) or parses as an absolute URL on its own.
21
+ *
22
+ * @see https://html.spec.whatwg.org/multipage/webappapis.html#resolving-a-url-like-module-specifier
23
+ */
24
+ function resolvesAsURLLikeSpecifier(specifier) {
25
+ if (specifier.startsWith('/') || specifier.startsWith('./') || specifier.startsWith('../')) {
26
+ return true;
27
+ }
28
+ try {
29
+ new URL(specifier);
30
+ return true;
31
+ }
32
+ catch (error) {
33
+ if (error instanceof TypeError) {
34
+ return false;
35
+ }
36
+ throw error;
37
+ }
38
+ }
39
+ export default createRule({
40
+ meta: meta,
41
+ defaultValue: true,
42
+ defaultOptions: null,
43
+ async verify({ document, report, t }) {
44
+ // markuplint's HTML parser does not retain raw text children of `<script>`
45
+ // (the content is JavaScript, not HTML, so the AST drops it). To inspect
46
+ // the inline body we extract the slice of the document source between the
47
+ // open tag's end and the close tag's start.
48
+ const sourceCode = document.raw;
49
+ await document.walkOn('Element', el => {
50
+ if (el.localName !== 'script')
51
+ return;
52
+ if (el.getAttribute('type')?.toLowerCase() !== 'importmap')
53
+ return;
54
+ if (el.pretenderContext?.type === 'pretender' && !el.hasAttribute('as'))
55
+ return;
56
+ if (!el.closeTag)
57
+ return;
58
+ const rawContent = sourceCode.slice(el.endOffset, el.closeTag.startOffset);
59
+ const trimmed = rawContent.trim();
60
+ const reportAt = (message) => {
61
+ report({
62
+ scope: el,
63
+ line: el.startLine,
64
+ col: el.startCol,
65
+ raw: el.raw,
66
+ message: message,
67
+ });
68
+ };
69
+ if (trimmed === '') {
70
+ reportAt(t('{0} must contain a JSON object', 'Import map'));
71
+ return;
72
+ }
73
+ let parsed;
74
+ try {
75
+ parsed = JSON.parse(trimmed);
76
+ }
77
+ catch (error) {
78
+ if (!(error instanceof SyntaxError)) {
79
+ throw error;
80
+ }
81
+ reportAt(t('{0} must be valid JSON', 'Import map'));
82
+ return;
83
+ }
84
+ if (!isPlainObject(parsed)) {
85
+ reportAt(t('{0} must be a JSON object', 'Import map'));
86
+ return;
87
+ }
88
+ verifyImportMap(parsed, reportAt, t);
89
+ });
90
+ },
91
+ });
92
+ function verifyImportMap(
93
+ // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
94
+ parsed, reportAt, t) {
95
+ for (const key of Object.keys(parsed)) {
96
+ if (!ALLOWED_TOP_LEVEL_KEYS.has(key)) {
97
+ reportAt(t('{0} is {1:c}', t('the import map top-level key "{0*}"', key), 'not allowed (use "imports", "scopes", or "integrity")'));
98
+ }
99
+ }
100
+ const imports = parsed.imports;
101
+ if (imports !== undefined) {
102
+ if (isPlainObject(imports)) {
103
+ validateSpecifierMap(imports, 'imports', reportAt, t);
104
+ }
105
+ else {
106
+ reportAt(t('{0} must be {1}', t('the "{0*}" top-level key of an import map', 'imports'), 'a JSON object'));
107
+ }
108
+ }
109
+ const scopes = parsed.scopes;
110
+ if (scopes !== undefined) {
111
+ if (isPlainObject(scopes)) {
112
+ for (const [scopeKey, scopeValue] of Object.entries(scopes)) {
113
+ if (isPlainObject(scopeValue)) {
114
+ validateSpecifierMap(scopeValue, `scopes["${scopeKey}"]`, reportAt, t);
115
+ }
116
+ else {
117
+ reportAt(t('{0} must be {1}', t('the value of the scope "{0*}"', scopeKey), 'a JSON object'));
118
+ }
119
+ }
120
+ }
121
+ else {
122
+ reportAt(t('{0} must be {1}', t('the "{0*}" top-level key of an import map', 'scopes'), 'a JSON object'));
123
+ }
124
+ }
125
+ const integrity = parsed.integrity;
126
+ if (integrity !== undefined) {
127
+ if (isPlainObject(integrity)) {
128
+ validateIntegrityMap(integrity, reportAt, t);
129
+ }
130
+ else {
131
+ reportAt(t('{0} must be {1}', t('the "{0*}" top-level key of an import map', 'integrity'), 'a JSON object'));
132
+ }
133
+ }
134
+ }
135
+ /**
136
+ * Per HTML LS § normalizing a module integrity map, each entry's key is
137
+ * resolved as a URL-like module specifier (warning if null) and the value
138
+ * must be a string (warning if not). Unlike specifier maps, there is no
139
+ * slash-suffix invariant — values are SRI hashes, not URLs.
140
+ *
141
+ * @see https://html.spec.whatwg.org/multipage/webappapis.html#normalizing-a-module-integrity-map
142
+ */
143
+ function validateIntegrityMap(
144
+ // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
145
+ map, reportAt, t) {
146
+ for (const [key, value] of Object.entries(map)) {
147
+ if (!resolvesAsURLLikeSpecifier(key)) {
148
+ reportAt(t('{0} must be {1}', t('the integrity key "{0*}"', key), 'a URL-like specifier (starts with "/", "./", "../", or is an absolute URL)'));
149
+ continue;
150
+ }
151
+ if (typeof value !== 'string') {
152
+ reportAt(t('{0} must be {1}', t('the value of "{0*}" in "integrity"', key), 'a string'));
153
+ }
154
+ }
155
+ }
156
+ function validateSpecifierMap(
157
+ // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
158
+ map, mapLabel, reportAt, t) {
159
+ for (const [key, value] of Object.entries(map)) {
160
+ if (key === '') {
161
+ reportAt(t('{0} must not be {1}', t('the specifier key in "{0*}"', mapLabel), 'empty'));
162
+ continue;
163
+ }
164
+ if (typeof value !== 'string') {
165
+ reportAt(t('{0} must be {1}', t('the value of "{0*}" in "{1*}"', key, mapLabel), 'a string'));
166
+ continue;
167
+ }
168
+ if (!resolvesAsURLLikeSpecifier(value)) {
169
+ reportAt(t('{0} must be {1}', t('the address "{0*}" of "{1*}" in "{2*}"', value, key, mapLabel), 'a URL-like specifier (starts with "/", "./", "../", or is an absolute URL)'));
170
+ continue;
171
+ }
172
+ if (key.endsWith('/') && !value.endsWith('/')) {
173
+ reportAt(t('{0} ends with "/" so {1} must end with "/" as well', t('the specifier key "{0*}" in "{1*}"', key, mapLabel), t('the address "{0*}"', value)));
174
+ }
175
+ }
176
+ }
@@ -0,0 +1,4 @@
1
+ declare const _default: {
2
+ readonly category: "syntax";
3
+ };
4
+ export default _default;
@@ -0,0 +1,3 @@
1
+ export default {
2
+ category: 'syntax',
3
+ };
@@ -0,0 +1,2 @@
1
+ declare const _default: Readonly<import("@markuplint/ml-core").RuleSeed<boolean, null>>;
2
+ export default _default;
@@ -0,0 +1,292 @@
1
+ import { createRule } from '@markuplint/ml-core';
2
+ import meta from './meta.js';
3
+ function isPlainObject(value) {
4
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
5
+ }
6
+ /**
7
+ * Validate the body of a `<script type="speculationrules">` element.
8
+ *
9
+ * Spec status: Speculation Rules is now part of the HTML Living Standard
10
+ * (§7.6 Speculation rules; the "parse a speculation rule" algorithm is §7.6.1.2).
11
+ * It originated as the WICG `nav-speculation` draft, which is now a stub that
12
+ * redirects to the HTML Standard — check the HTML Standard for the latest schema.
13
+ *
14
+ * markuplint also mirrors nu-validator's strictness (e.g. unknown keys, empty
15
+ * `urls`, exactly-one `where` predicate) so the two agree on the conformance
16
+ * corpus. When the spec changes, update this set/the SR_* sets below, the error
17
+ * message strings, and the README tables.
18
+ *
19
+ * @see https://html.spec.whatwg.org/multipage/speculative-loading.html
20
+ */
21
+ // Valid keys per HTML LS § 7.6.1.2 "parse a speculation rule" / the rule-set
22
+ // object grammar. Unknown keys are rejected by the spec (the rule returns null),
23
+ // so reporting them is conformant. We accept the full key set to avoid flagging
24
+ // valid rules that use fields beyond the common `source`/`urls`/`where` —
25
+ // value-level validation of the extra fields is intentionally not implemented.
26
+ const SR_TOP_LEVEL_KEYS = new Set(['tag', 'prefetch', 'prerender']);
27
+ const SR_RULE_KEYS = new Set([
28
+ 'source',
29
+ 'urls',
30
+ 'where',
31
+ 'relative_to',
32
+ 'eagerness',
33
+ 'referrer_policy',
34
+ 'tag',
35
+ 'requires',
36
+ 'expects_no_vary_search',
37
+ 'target_hint',
38
+ ]);
39
+ const SR_SOURCES = new Set(['list', 'document']);
40
+ const SR_EAGERNESS = new Set(['immediate', 'eager', 'moderate', 'conservative']);
41
+ const SR_PREDICATE_KEYS = new Set(['and', 'or', 'not', 'href_matches', 'selector_matches']);
42
+ export default createRule({
43
+ meta: meta,
44
+ defaultValue: true,
45
+ defaultOptions: null,
46
+ async verify({ document, report, t }) {
47
+ // markuplint's HTML parser does not retain raw text children of `<script>`
48
+ // (the content is JavaScript, not HTML, so the AST drops it). To inspect
49
+ // the inline body we extract the slice of the document source between the
50
+ // open tag's end and the close tag's start.
51
+ const sourceCode = document.raw;
52
+ await document.walkOn('Element', el => {
53
+ if (el.localName !== 'script')
54
+ return;
55
+ if (el.getAttribute('type')?.toLowerCase() !== 'speculationrules')
56
+ return;
57
+ if (el.pretenderContext?.type === 'pretender' && !el.hasAttribute('as'))
58
+ return;
59
+ if (!el.closeTag)
60
+ return;
61
+ const rawContent = sourceCode.slice(el.endOffset, el.closeTag.startOffset);
62
+ const trimmed = rawContent.trim();
63
+ const reportAt = (message) => {
64
+ report({
65
+ scope: el,
66
+ line: el.startLine,
67
+ col: el.startCol,
68
+ raw: el.raw,
69
+ message: message,
70
+ });
71
+ };
72
+ if (trimmed === '') {
73
+ reportAt(t('{0} must contain a JSON object', 'Speculation rules'));
74
+ return;
75
+ }
76
+ let parsed;
77
+ try {
78
+ parsed = JSON.parse(trimmed);
79
+ }
80
+ catch (error) {
81
+ if (!(error instanceof SyntaxError)) {
82
+ throw error;
83
+ }
84
+ reportAt(t('{0} must be valid JSON', 'Speculation rules'));
85
+ return;
86
+ }
87
+ if (!isPlainObject(parsed)) {
88
+ reportAt(t('{0} must be a JSON object', 'Speculation rules'));
89
+ return;
90
+ }
91
+ verifySpeculationRules(parsed, reportAt, t);
92
+ });
93
+ },
94
+ });
95
+ function verifySpeculationRules(
96
+ // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
97
+ parsed, reportAt, t) {
98
+ let hasRuleSet = false;
99
+ for (const key of Object.keys(parsed)) {
100
+ if (!SR_TOP_LEVEL_KEYS.has(key)) {
101
+ reportAt(t('{0} is {1:c}', t('the speculation rules top-level key "{0*}"', key), 'not allowed (use "tag", "prefetch", or "prerender")'));
102
+ continue;
103
+ }
104
+ // `tag` is a ruleset label, not a list of rules; it does not satisfy the
105
+ // "needs prefetch or prerender" requirement and is not an array of rules.
106
+ if (key === 'tag')
107
+ continue;
108
+ hasRuleSet = true;
109
+ const ruleSet = parsed[key];
110
+ if (!Array.isArray(ruleSet)) {
111
+ reportAt(t('{0} must be {1}', t('the "{0*}" property of speculation rules', key), 'a JSON array'));
112
+ continue;
113
+ }
114
+ for (let i = 0; i < ruleSet.length; i++) {
115
+ validateSpeculationRule(ruleSet[i], `${key}[${i}]`, reportAt, t);
116
+ }
117
+ }
118
+ if (!hasRuleSet) {
119
+ reportAt(t('{0} must be {1}', 'Speculation rules', 'an object with a "prefetch" or "prerender" property'));
120
+ }
121
+ }
122
+ function validateSpeculationRule(rule, label, reportAt, t) {
123
+ if (!isPlainObject(rule)) {
124
+ reportAt(t('{0} must be {1}', t('the speculation rule {0*}', label), 'a JSON object'));
125
+ return;
126
+ }
127
+ for (const key of Object.keys(rule)) {
128
+ if (!SR_RULE_KEYS.has(key)) {
129
+ reportAt(t('{0} is {1:c}', t('the speculation rule key "{0*}"', key), 'not allowed (use "source", "urls", "where", "relative_to", "eagerness", "referrer_policy", "tag", "requires", "expects_no_vary_search", or "target_hint")'));
130
+ }
131
+ }
132
+ const sourceProvided = rule.source !== undefined;
133
+ let validSource;
134
+ if (sourceProvided) {
135
+ if (typeof rule.source !== 'string') {
136
+ reportAt(t('{0} must be {1}', t('the "source" of {0*}', label), 'a string'));
137
+ }
138
+ else if (SR_SOURCES.has(rule.source)) {
139
+ validSource = rule.source;
140
+ }
141
+ else {
142
+ reportAt(t('{0} is {1:c}', t('the "source" value "{0*}"', rule.source), 'not allowed (use "list" or "document")'));
143
+ }
144
+ }
145
+ if (rule.eagerness !== undefined) {
146
+ if (typeof rule.eagerness !== 'string') {
147
+ reportAt(t('{0} must be {1}', t('the "eagerness" of {0*}', label), 'a string'));
148
+ }
149
+ else if (!SR_EAGERNESS.has(rule.eagerness)) {
150
+ reportAt(t('{0} is {1:c}', t('the "eagerness" value "{0*}"', rule.eagerness), 'not allowed (use "immediate", "eager", "moderate", or "conservative")'));
151
+ }
152
+ }
153
+ const hasUrls = rule.urls !== undefined;
154
+ if (hasUrls) {
155
+ validateUrls(rule.urls, label, reportAt, t);
156
+ }
157
+ const hasWhere = rule.where !== undefined;
158
+ if (hasWhere) {
159
+ validatePredicate(rule.where, t('the "where" condition of {0*}', label), reportAt, t);
160
+ }
161
+ // Resolve the effective source: an explicit valid `source`, otherwise
162
+ // inferred from exactly one of `urls` (→ list) or `where` (→ document) being
163
+ // present. Per spec the inference is mutually exclusive: when neither or both
164
+ // are present (and no explicit source), the source cannot be inferred and the
165
+ // rule is invalid.
166
+ let effectiveSource = validSource;
167
+ if (effectiveSource === undefined && !sourceProvided) {
168
+ if (hasUrls && !hasWhere) {
169
+ effectiveSource = 'list';
170
+ }
171
+ else if (hasWhere && !hasUrls) {
172
+ effectiveSource = 'document';
173
+ }
174
+ }
175
+ if (effectiveSource === 'list') {
176
+ if (!hasUrls) {
177
+ reportAt(t('{0} must have {1}', t('the list rule {0*}', label), 'a "urls" property'));
178
+ }
179
+ if (hasWhere) {
180
+ reportAt(t('{0} must not have {1}', t('the list rule {0*}', label), 'a "where" property'));
181
+ }
182
+ }
183
+ else if (effectiveSource === 'document') {
184
+ if (!hasWhere) {
185
+ reportAt(t('{0} must have {1}', t('the document rule {0*}', label), 'a "where" property'));
186
+ }
187
+ if (hasUrls) {
188
+ reportAt(t('{0} must not have {1}', t('the document rule {0*}', label), 'a "urls" property'));
189
+ }
190
+ }
191
+ else if (!sourceProvided) {
192
+ // No explicit source and inference failed (neither `urls`/`where`, or both).
193
+ reportAt(t('{0} must have {1}', t('the speculation rule {0*}', label), 'a "source", or exactly one of "urls" or "where"'));
194
+ }
195
+ }
196
+ function validateUrls(urls, label, reportAt, t) {
197
+ if (!Array.isArray(urls)) {
198
+ reportAt(t('{0} must be {1}', t('the "urls" of {0*}', label), 'a JSON array'));
199
+ return;
200
+ }
201
+ if (urls.length === 0) {
202
+ reportAt(t('{0} must not be {1}', t('the "urls" of {0*}', label), 'empty'));
203
+ return;
204
+ }
205
+ for (let i = 0; i < urls.length; i++) {
206
+ const url = urls[i];
207
+ if (typeof url !== 'string') {
208
+ reportAt(t('{0} must be {1}', t('the URL at index {0*} in "urls"', i), 'a string'));
209
+ }
210
+ else if (url === '') {
211
+ reportAt(t('{0} must not be {1}', t('the URL at index {0*} in "urls"', i), 'empty'));
212
+ }
213
+ }
214
+ }
215
+ /**
216
+ * Validate a document-rule `where` predicate. A predicate object must contain
217
+ * exactly one of `and` / `or` / `not` / `href_matches` / `selector_matches`.
218
+ *
219
+ * @see https://wicg.github.io/nav-speculation/speculation-rules.html#document-rule-predicates
220
+ */
221
+ function validatePredicate(predicate, label, reportAt, t) {
222
+ if (!isPlainObject(predicate)) {
223
+ reportAt(t('{0} must be {1}', label, 'a JSON object'));
224
+ return;
225
+ }
226
+ const keys = Object.keys(predicate);
227
+ const predicateKeys = [];
228
+ for (const key of keys) {
229
+ if (SR_PREDICATE_KEYS.has(key)) {
230
+ predicateKeys.push(key);
231
+ }
232
+ else {
233
+ reportAt(t('{0} is {1:c}', t('the predicate key "{0*}"', key), 'not allowed (use "and", "or", "not", "href_matches", or "selector_matches")'));
234
+ }
235
+ }
236
+ if (predicateKeys.length === 0) {
237
+ if (keys.length === 0) {
238
+ reportAt(t('{0} must have {1}', label, 'exactly one predicate ("and", "or", "not", "href_matches", or "selector_matches")'));
239
+ }
240
+ return;
241
+ }
242
+ if (predicateKeys.length > 1) {
243
+ reportAt(t('{0} must have {1}', label, 'exactly one predicate, but has multiple'));
244
+ }
245
+ for (const key of predicateKeys) {
246
+ const value = predicate[key];
247
+ if (key === 'and' || key === 'or') {
248
+ if (!Array.isArray(value)) {
249
+ reportAt(t('{0} must be {1}', t('the "{0*}" predicate', key), 'a JSON array'));
250
+ continue;
251
+ }
252
+ if (value.length === 0) {
253
+ reportAt(t('{0} must not be {1}', t('the "{0*}" predicate', key), 'empty'));
254
+ continue;
255
+ }
256
+ for (let i = 0; i < value.length; i++) {
257
+ validatePredicate(value[i], t('the "{0*}" predicate item [{1*}]', key, i), reportAt, t);
258
+ }
259
+ }
260
+ else if (key === 'not') {
261
+ validatePredicate(value, t('the "not" predicate'), reportAt, t);
262
+ }
263
+ else {
264
+ validatePatternValue(value, key, reportAt, t);
265
+ }
266
+ }
267
+ }
268
+ function validatePatternValue(value, key, reportAt, t) {
269
+ if (typeof value === 'string') {
270
+ if (value === '') {
271
+ reportAt(t('{0} must not be {1}', t('the "{0*}" pattern', key), 'empty'));
272
+ }
273
+ return;
274
+ }
275
+ if (Array.isArray(value)) {
276
+ if (value.length === 0) {
277
+ reportAt(t('{0} must not be {1}', t('the "{0*}" pattern', key), 'empty'));
278
+ return;
279
+ }
280
+ for (let i = 0; i < value.length; i++) {
281
+ const item = value[i];
282
+ if (typeof item !== 'string') {
283
+ reportAt(t('{0} must be {1}', t('item [{0*}] of the "{1*}" pattern', i, key), 'a string'));
284
+ }
285
+ else if (item === '') {
286
+ reportAt(t('{0} must not be {1}', t('item [{0*}] of the "{1*}" pattern', i, key), 'empty'));
287
+ }
288
+ }
289
+ return;
290
+ }
291
+ reportAt(t('{0} must be {1}', t('the "{0*}" pattern', key), 'a string or an array of strings'));
292
+ }
@@ -0,0 +1,4 @@
1
+ declare const _default: {
2
+ readonly category: "syntax";
3
+ };
4
+ export default _default;
@@ -0,0 +1,3 @@
1
+ export default {
2
+ category: 'syntax',
3
+ };
@@ -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's value contradicts an equivalent native
6
+ * HTML attribute's current or implicit value.
7
+ *
8
+ * Many ARIA properties have equivalent HTML attributes (e.g., `aria-required`
9
+ * and `required`). ARIA in HTML §6 conformance requires native HTML
10
+ * attributes to take precedence over their ARIA equivalents, so a
11
+ * contradicting `aria-*` value is a conformance violation, not merely a
12
+ * style preference (contrast `checkingRedundantAriaProp`, which is should-
13
+ * level).
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 contradicts an equivalent HTML attribute.
19
+ */
20
+ export declare const checkingContradictoryAriaProp: AttrChecker<boolean, Options, {
21
+ propSpecs: readonly ARIAProperty[];
22
+ attrSpecs: readonly Attribute[] | null;
23
+ }>;
@@ -1,18 +1,21 @@
1
- import { isValidAttr } from '../../helpers.js';
1
+ import { resolveAttrEligibility } from '../../attr-eligibility.js';
2
2
  /**
3
- * Checks whether an ARIA property duplicates or contradicts semantics already
4
- * provided by an equivalent native HTML attribute.
3
+ * Checks whether an ARIA property's value contradicts an equivalent native
4
+ * HTML attribute's current or implicit value.
5
5
  *
6
- * Many ARIA properties have equivalent HTML attributes (e.g., `aria-required` and `required`).
7
- * This checker reports when an ARIA property is redundant because the native attribute
8
- * already conveys the same semantics, or when the ARIA value contradicts the native attribute.
6
+ * Many ARIA properties have equivalent HTML attributes (e.g., `aria-required`
7
+ * and `required`). ARIA in HTML §6 conformance requires native HTML
8
+ * attributes to take precedence over their ARIA equivalents, so a
9
+ * contradicting `aria-*` value is a conformance violation, not merely a
10
+ * style preference (contrast `checkingRedundantAriaProp`, which is should-
11
+ * level).
9
12
  *
10
13
  * @param attr - The ARIA attribute node to inspect.
11
14
  * @param propSpecs - The list of ARIA property specifications for equivalence lookup.
12
15
  * @param attrSpecs - The HTML attribute specifications for the element.
13
- * @returns A violation if the ARIA property duplicates or contradicts an equivalent HTML attribute.
16
+ * @returns A violation if the ARIA property contradicts an equivalent HTML attribute.
14
17
  */
15
- export const checkingImplicitProps = ({ attr, propSpecs, attrSpecs }) => t => {
18
+ export const checkingContradictoryAriaProp = ({ attr, propSpecs, attrSpecs }) => t => {
16
19
  if (!attrSpecs) {
17
20
  return;
18
21
  }
@@ -25,8 +28,15 @@ export const checkingImplicitProps = ({ attr, propSpecs, attrSpecs }) => t => {
25
28
  }
26
29
  for (const equivalentHtmlAttr of propSpec.equivalentHtmlAttrs) {
27
30
  const htmlAttrSpec = attrSpecs.find(a => a.name === equivalentHtmlAttr.htmlAttrName);
28
- const isValid = isValidAttr(t, equivalentHtmlAttr.htmlAttrName, equivalentHtmlAttr.value ?? '', false, attr.ownerElement, attrSpecs);
29
- if (isValid !== false && !Array.isArray(isValid) && isValid.invalidType === 'non-existent') {
31
+ const eligibility = resolveAttrEligibility(equivalentHtmlAttr.htmlAttrName, attr.ownerElement, attrSpecs);
32
+ // Skip only when the native attribute doesn't apply to this element at all
33
+ // (unknown name, case mismatch, or an unmet condition) — mirrors the old
34
+ // `invalidType === 'non-existent'` check. `noUse` still proceeds: an
35
+ // explicitly-forbidden native attribute can still be "implicit" for
36
+ // equivalence purposes.
37
+ if (eligibility.status === 'unknown' ||
38
+ eligibility.status === 'case-mismatch' ||
39
+ eligibility.status === 'condition-not-met') {
30
40
  continue;
31
41
  }
32
42
  const value = attr.value.trim().toLowerCase();
@@ -34,10 +44,8 @@ export const checkingImplicitProps = ({ attr, propSpecs, attrSpecs }) => t => {
34
44
  const targetAttrValue = attr.ownerElement.getAttribute(equivalentHtmlAttr.htmlAttrName);
35
45
  if ((equivalentHtmlAttr.value == null && targetAttrValue === value) ||
36
46
  equivalentHtmlAttr.value === value) {
37
- return {
38
- scope: attr,
39
- 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')))),
40
- };
47
+ // Redundant, not contradictory — `checkingRedundantAriaProp`'s concern.
48
+ continue;
41
49
  }
42
50
  if (htmlAttrSpec?.type === 'Boolean' && value !== 'false') {
43
51
  continue;
@@ -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 the ARIA in HTML element-specific `aria-*` restrictions: spec data
6
+ * may forbid every `aria-*` attribute on an element with no implicit role
7
+ * (`properties: false`, e.g. `input[type=hidden]`), whitelist a small set
8
+ * (`properties: { only: [...] }`, e.g. `<br>`/`<wbr>` accept only
9
+ * `aria-hidden`), or blacklist specific properties with a suggested
10
+ * alternative (`properties: { without: [...] }`).
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 element-specific restriction disallows the property.
16
+ */
17
+ export declare const checkingElementSupportsAriaProp: AttrChecker<boolean, Options, {
18
+ role: ARIARole | null;
19
+ propSpecs: readonly ARIAProperty[];
20
+ }>;