@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.
- package/CHANGELOG.md +98 -0
- package/CLAUDE.md +31 -2
- package/lib/{wai-aria-deprecated-role → aria-prop-requires-role}/index.d.ts +0 -1
- package/lib/{wai-aria-no-global-prop → aria-prop-requires-role}/index.js +0 -1
- package/lib/attr-check.d.ts +0 -48
- package/lib/attr-check.js +0 -36
- package/lib/attr-eligibility.d.ts +41 -0
- package/lib/attr-eligibility.js +60 -0
- package/lib/attr-value-quotes/index.d.ts +0 -7
- package/lib/attr-value-quotes/index.js +0 -7
- package/lib/attr-value-quotes/meta.d.ts +0 -1
- package/lib/attr-value-quotes/meta.js +0 -1
- package/lib/case-sensitive-attr-name/index.d.ts +0 -8
- package/lib/case-sensitive-attr-name/index.js +0 -8
- package/lib/case-sensitive-attr-name/meta.d.ts +0 -1
- package/lib/case-sensitive-attr-name/meta.js +0 -1
- package/lib/case-sensitive-tag-name/index.d.ts +0 -8
- package/lib/case-sensitive-tag-name/index.js +0 -8
- package/lib/case-sensitive-tag-name/meta.d.ts +0 -1
- package/lib/case-sensitive-tag-name/meta.js +0 -1
- package/lib/class-naming/index.d.ts +0 -8
- package/lib/class-naming/index.js +0 -8
- package/lib/class-naming/meta.d.ts +1 -2
- package/lib/class-naming/meta.js +1 -2
- package/lib/consistent-table-row-length/index.d.ts +14 -0
- package/lib/consistent-table-row-length/index.js +69 -0
- package/lib/consistent-table-row-length/meta.d.ts +4 -0
- package/lib/consistent-table-row-length/meta.js +3 -0
- package/lib/create-message.d.ts +2 -25
- package/lib/create-message.js +2 -53
- package/lib/debug.d.ts +1 -9
- package/lib/debug.js +1 -5
- package/lib/element-supports-aria-prop/index.d.ts +12 -0
- package/lib/element-supports-aria-prop/index.js +38 -0
- package/lib/form-attr-references-form/index.d.ts +12 -0
- package/lib/form-attr-references-form/index.js +64 -0
- package/lib/{correct-aspect-ratio → form-attr-references-form}/meta.d.ts +1 -1
- package/lib/form-attr-references-form/meta.js +3 -0
- package/lib/head-element-order/meta.d.ts +1 -1
- package/lib/head-element-order/meta.js +1 -1
- package/lib/helpers.d.ts +8 -138
- package/lib/helpers.js +24 -165
- package/lib/index.d.ts +135 -78
- package/lib/index.js +167 -82
- package/lib/input-list-references-datalist/index.d.ts +13 -0
- package/lib/input-list-references-datalist/index.js +46 -0
- package/lib/input-list-references-datalist/meta.d.ts +4 -0
- package/lib/input-list-references-datalist/meta.js +3 -0
- package/lib/itemprop-requires-itemscope/index.d.ts +21 -0
- package/lib/itemprop-requires-itemscope/index.js +53 -0
- package/lib/itemprop-requires-itemscope/meta.d.ts +4 -0
- package/lib/itemprop-requires-itemscope/meta.js +3 -0
- package/lib/label-for-references-labelable/index.d.ts +12 -0
- package/lib/label-for-references-labelable/index.js +68 -0
- package/lib/label-for-references-labelable/meta.d.ts +4 -0
- package/lib/label-for-references-labelable/meta.js +3 -0
- package/lib/label-has-control/index.d.ts +5 -5
- package/lib/label-has-control/index.js +5 -18
- package/lib/label-has-control/meta.d.ts +0 -1
- package/lib/label-has-control/meta.js +0 -1
- package/lib/label-no-multiple-controls/index.d.ts +31 -0
- package/lib/label-no-multiple-controls/index.js +104 -0
- package/lib/label-no-multiple-controls/meta.d.ts +4 -0
- package/lib/label-no-multiple-controls/meta.js +3 -0
- package/lib/landmark-roles/roles.d.ts +32 -0
- package/lib/landmark-roles/roles.js +73 -0
- package/lib/link-types/index.d.ts +0 -5
- package/lib/link-types/index.js +5 -6
- package/lib/link-types/meta.d.ts +1 -2
- package/lib/link-types/meta.js +1 -2
- package/lib/map-id-name-match/index.d.ts +10 -0
- package/lib/map-id-name-match/index.js +39 -0
- package/lib/map-id-name-match/meta.d.ts +4 -0
- package/lib/map-id-name-match/meta.js +3 -0
- package/lib/meta-charset-position/index.d.ts +15 -0
- package/lib/meta-charset-position/index.js +31 -0
- package/lib/meta-charset-position/meta.d.ts +4 -0
- package/lib/meta-charset-position/meta.js +3 -0
- package/lib/meter-value-bounds/index.d.ts +10 -0
- package/lib/meter-value-bounds/index.js +123 -0
- package/lib/meter-value-bounds/meta.d.ts +4 -0
- package/lib/meter-value-bounds/meta.js +3 -0
- package/lib/{wai-aria-required-props → no-abstract-role}/index.d.ts +0 -1
- package/lib/{wai-aria-abstract-role → no-abstract-role}/index.js +0 -1
- package/lib/no-always-matching-source/index.d.ts +13 -0
- package/lib/no-always-matching-source/index.js +100 -0
- package/lib/no-always-matching-source/meta.d.ts +4 -0
- package/lib/no-always-matching-source/meta.js +3 -0
- package/lib/no-ambiguous-navigable-target-names/index.d.ts +0 -8
- package/lib/no-ambiguous-navigable-target-names/index.js +0 -8
- package/lib/no-ambiguous-navigable-target-names/meta.d.ts +1 -2
- package/lib/no-ambiguous-navigable-target-names/meta.js +1 -2
- package/lib/{wai-aria-required-owned-elements → no-aria-on-presentational-children}/index.d.ts +0 -1
- package/lib/{wai-aria-presentational-children → no-aria-on-presentational-children}/index.js +0 -1
- package/lib/no-aria-on-unsupported-element/index.d.ts +11 -0
- package/lib/no-aria-on-unsupported-element/index.js +35 -0
- package/lib/no-aria-on-unsupported-element/meta.d.ts +9 -0
- package/lib/no-aria-on-unsupported-element/meta.js +8 -0
- package/lib/no-boolean-attr-value/index.d.ts +0 -7
- package/lib/no-boolean-attr-value/index.js +0 -7
- package/lib/no-boolean-attr-value/meta.d.ts +0 -1
- package/lib/no-boolean-attr-value/meta.js +0 -1
- package/lib/no-broken-fragment-link/index.d.ts +15 -0
- package/lib/no-broken-fragment-link/index.js +93 -0
- package/lib/no-broken-fragment-link/meta.d.ts +4 -0
- package/lib/no-broken-fragment-link/meta.js +3 -0
- package/lib/no-consecutive-br/index.d.ts +0 -8
- package/lib/no-consecutive-br/index.js +0 -8
- package/lib/no-consecutive-br/meta.d.ts +0 -1
- package/lib/no-consecutive-br/meta.js +0 -1
- package/lib/no-content-after-body/index.d.ts +25 -0
- package/lib/no-content-after-body/index.js +51 -0
- package/lib/no-content-after-body/meta.d.ts +4 -0
- package/lib/no-content-after-body/meta.js +3 -0
- package/lib/no-contradictory-aria-prop/index.d.ts +10 -0
- package/lib/no-contradictory-aria-prop/index.js +34 -0
- package/lib/{wai-aria-abstract-role → no-default-aria-value}/index.d.ts +0 -1
- package/lib/{wai-aria-default-value → no-default-aria-value}/index.js +0 -1
- package/lib/no-default-value/index.d.ts +0 -7
- package/lib/no-default-value/index.js +0 -7
- package/lib/no-default-value/meta.d.ts +0 -1
- package/lib/no-default-value/meta.js +0 -1
- package/lib/no-deprecated-aria-prop/index.d.ts +3 -0
- package/lib/{wai-aria-deprecated-props → no-deprecated-aria-prop}/index.js +0 -1
- package/lib/no-deprecated-attr/index.d.ts +2 -0
- package/lib/{deprecated-attr → no-deprecated-attr}/index.js +5 -9
- package/lib/no-deprecated-attr/meta.d.ts +4 -0
- package/lib/no-deprecated-attr/meta.js +3 -0
- package/lib/no-deprecated-element/index.d.ts +2 -0
- package/lib/no-deprecated-element/index.js +27 -0
- package/lib/no-deprecated-element/meta.d.ts +4 -0
- package/lib/no-deprecated-element/meta.js +3 -0
- package/lib/no-deprecated-role/index.d.ts +3 -0
- package/lib/{wai-aria-deprecated-role → no-deprecated-role}/index.js +0 -1
- package/lib/no-disallowed-ancestor/index.d.ts +2 -0
- package/lib/no-disallowed-ancestor/index.js +25 -0
- package/lib/no-disallowed-ancestor/meta.d.ts +4 -0
- package/lib/no-disallowed-ancestor/meta.js +3 -0
- package/lib/no-disallowed-attr/index.d.ts +28 -0
- package/lib/no-disallowed-attr/index.js +77 -0
- package/lib/no-disallowed-attr/meta.d.ts +4 -0
- package/lib/no-disallowed-attr/meta.js +3 -0
- package/lib/no-duplicate-attr/index.d.ts +2 -0
- package/lib/{attr-duplication → no-duplicate-attr}/index.js +0 -7
- package/lib/no-duplicate-attr/meta.d.ts +6 -0
- package/lib/no-duplicate-attr/meta.js +10 -0
- package/lib/no-duplicate-autofocus/index.d.ts +0 -5
- package/lib/no-duplicate-autofocus/index.js +20 -6
- package/lib/no-duplicate-autofocus/meta.d.ts +1 -1
- package/lib/no-duplicate-autofocus/meta.js +1 -1
- package/lib/no-duplicate-dt/index.d.ts +0 -6
- package/lib/no-duplicate-dt/index.js +1 -6
- package/lib/no-duplicate-dt/meta.d.ts +1 -2
- package/lib/no-duplicate-dt/meta.js +1 -2
- package/lib/no-duplicate-h1/index.d.ts +18 -0
- package/lib/no-duplicate-h1/index.js +41 -0
- package/lib/no-duplicate-h1/meta.d.ts +4 -0
- package/lib/no-duplicate-h1/meta.js +3 -0
- package/lib/no-duplicate-id/index.d.ts +2 -0
- package/lib/{id-duplication → no-duplicate-id}/index.js +0 -7
- package/lib/no-duplicate-id/meta.d.ts +4 -0
- package/lib/no-duplicate-id/meta.js +3 -0
- package/lib/no-duplicate-sibling-attr/index.d.ts +2 -0
- package/lib/no-duplicate-sibling-attr/index.js +35 -0
- package/lib/no-duplicate-sibling-attr/meta.d.ts +4 -0
- package/lib/no-duplicate-sibling-attr/meta.js +3 -0
- package/lib/no-duplicate-visible-main/index.d.ts +0 -1
- package/lib/no-duplicate-visible-main/index.js +0 -1
- package/lib/no-duplicate-visible-main/meta.d.ts +1 -1
- package/lib/no-duplicate-visible-main/meta.js +1 -1
- package/lib/no-empty-palpable-content/index.d.ts +0 -8
- package/lib/no-empty-palpable-content/index.js +0 -8
- package/lib/no-empty-palpable-content/meta.d.ts +1 -2
- package/lib/no-empty-palpable-content/meta.js +1 -2
- package/lib/no-empty-table-track/index.d.ts +12 -0
- package/lib/no-empty-table-track/index.js +42 -0
- package/lib/no-empty-table-track/meta.d.ts +4 -0
- package/lib/no-empty-table-track/meta.js +3 -0
- package/lib/no-event-handler-attr/index.d.ts +7 -0
- package/lib/{no-use-event-handler-attr → no-event-handler-attr}/index.js +0 -11
- package/lib/no-event-handler-attr/meta.d.ts +4 -0
- package/lib/no-event-handler-attr/meta.js +3 -0
- package/lib/no-experimental-features/index.d.ts +9 -0
- package/lib/no-experimental-features/index.js +53 -0
- package/lib/no-experimental-features/meta.d.ts +4 -0
- package/lib/no-experimental-features/meta.js +3 -0
- package/lib/no-extra-selected-options/index.d.ts +10 -0
- package/lib/no-extra-selected-options/index.js +37 -0
- package/lib/no-extra-selected-options/meta.d.ts +4 -0
- package/lib/no-extra-selected-options/meta.js +3 -0
- package/lib/no-focusable-in-aria-hidden/index.d.ts +3 -0
- package/lib/{wai-aria-interaction-in-hidden → no-focusable-in-aria-hidden}/index.js +0 -1
- package/lib/no-focusable-in-aria-hidden/meta.d.ts +4 -0
- package/lib/no-focusable-in-aria-hidden/meta.js +3 -0
- package/lib/no-hardcoded-id/index.d.ts +2 -0
- package/lib/{no-hard-code-id → no-hardcoded-id}/index.js +0 -8
- package/lib/no-hardcoded-id/meta.d.ts +4 -0
- package/lib/no-hardcoded-id/meta.js +3 -0
- package/lib/no-ineffective-attr/index.d.ts +2 -0
- package/lib/{ineffective-attr → no-ineffective-attr}/index.js +0 -7
- package/lib/no-ineffective-attr/meta.d.ts +5 -0
- package/lib/no-ineffective-attr/meta.js +4 -0
- package/lib/no-input-file-value/index.d.ts +10 -0
- package/lib/no-input-file-value/index.js +41 -0
- package/lib/no-input-file-value/meta.d.ts +4 -0
- package/lib/no-input-file-value/meta.js +3 -0
- package/lib/no-invalid-aria-prop-value/index.d.ts +3 -0
- package/lib/{wai-aria-value → no-invalid-aria-prop-value}/index.js +0 -1
- package/lib/no-invalid-aria-prop-value/meta.d.ts +4 -0
- package/lib/no-invalid-aria-prop-value/meta.js +3 -0
- package/lib/no-invalid-attr-value/index.d.ts +27 -0
- package/lib/no-invalid-attr-value/index.js +83 -0
- package/lib/no-invalid-attr-value/meta.d.ts +4 -0
- package/lib/no-invalid-attr-value/meta.js +3 -0
- package/lib/no-malformed-character-reference/index.d.ts +2 -0
- package/lib/no-malformed-character-reference/index.js +38 -0
- package/lib/no-malformed-character-reference/meta.d.ts +5 -0
- package/lib/no-malformed-character-reference/meta.js +20 -0
- package/lib/{correct-aspect-ratio → no-mismatched-aspect-ratio}/index.js +13 -3
- package/lib/no-mismatched-aspect-ratio/meta.d.ts +4 -0
- package/lib/no-mismatched-aspect-ratio/meta.js +3 -0
- package/lib/{correct-aspect-ratio → no-mismatched-aspect-ratio}/resolve-image-size.js +8 -2
- package/lib/no-mixed-srcset-descriptors/index.d.ts +12 -0
- package/lib/no-mixed-srcset-descriptors/index.js +47 -0
- package/lib/no-mixed-srcset-descriptors/meta.d.ts +4 -0
- package/lib/no-mixed-srcset-descriptors/meta.js +3 -0
- package/lib/no-nested-top-level-landmark/index.d.ts +10 -0
- package/lib/no-nested-top-level-landmark/index.js +52 -0
- package/lib/no-nested-top-level-landmark/meta.d.ts +4 -0
- package/lib/no-nested-top-level-landmark/meta.js +3 -0
- package/lib/no-nonstandard-features/index.d.ts +9 -0
- package/lib/no-nonstandard-features/index.js +53 -0
- package/lib/no-nonstandard-features/meta.d.ts +4 -0
- package/lib/no-nonstandard-features/meta.js +3 -0
- package/lib/no-obsolete-attr/index.d.ts +2 -0
- package/lib/no-obsolete-attr/index.js +27 -0
- package/lib/no-obsolete-attr/meta.d.ts +4 -0
- package/lib/no-obsolete-attr/meta.js +3 -0
- package/lib/no-obsolete-doctype/index.d.ts +2 -0
- package/lib/{doctype → no-obsolete-doctype}/index.js +9 -16
- package/lib/no-obsolete-doctype/meta.d.ts +4 -0
- package/lib/no-obsolete-doctype/meta.js +3 -0
- package/lib/no-obsolete-element/index.d.ts +2 -0
- package/lib/{deprecated-element → no-obsolete-element}/index.js +6 -10
- package/lib/no-obsolete-element/meta.d.ts +4 -0
- package/lib/no-obsolete-element/meta.js +3 -0
- package/lib/no-orphaned-end-tag/index.d.ts +0 -7
- package/lib/no-orphaned-end-tag/index.js +0 -7
- package/lib/no-orphaned-end-tag/meta.d.ts +2 -2
- package/lib/no-orphaned-end-tag/meta.js +5 -2
- package/lib/no-prohibited-naming/index.d.ts +8 -0
- package/lib/no-prohibited-naming/index.js +36 -0
- package/lib/no-prohibited-naming/meta.d.ts +4 -0
- package/lib/no-prohibited-naming/meta.js +3 -0
- package/lib/{use-list → no-pseudo-list}/index.d.ts +1 -8
- package/lib/{use-list → no-pseudo-list}/index.js +0 -7
- package/lib/no-pseudo-list/meta.d.ts +4 -0
- package/lib/no-pseudo-list/meta.js +3 -0
- package/lib/{redundant-accessible-name → no-redundant-accessible-name}/index.d.ts +0 -4
- package/lib/{redundant-accessible-name → no-redundant-accessible-name}/index.js +0 -4
- package/lib/no-redundant-accessible-name/meta.d.ts +4 -0
- package/lib/no-redundant-accessible-name/meta.js +3 -0
- package/lib/no-redundant-aria-prop/index.d.ts +10 -0
- package/lib/{wai-aria-implicit-props → no-redundant-aria-prop}/index.js +9 -3
- package/lib/no-redundant-aria-prop/meta.d.ts +4 -0
- package/lib/no-redundant-aria-prop/meta.js +3 -0
- package/lib/no-redundant-role/index.d.ts +3 -0
- package/lib/{wai-aria-implicit-role → no-redundant-role}/index.js +0 -1
- package/lib/no-redundant-role/meta.d.ts +4 -0
- package/lib/no-redundant-role/meta.js +3 -0
- package/lib/no-refer-to-non-existent-id/index.d.ts +0 -9
- package/lib/no-refer-to-non-existent-id/index.js +1 -62
- package/lib/no-refer-to-non-existent-id/meta.d.ts +1 -2
- package/lib/no-refer-to-non-existent-id/meta.js +1 -2
- package/lib/no-restricted-attr/index.d.ts +27 -0
- package/lib/no-restricted-attr/index.js +96 -0
- package/lib/no-restricted-attr/meta.d.ts +4 -0
- package/lib/no-restricted-attr/meta.js +3 -0
- package/lib/no-restricted-element/index.d.ts +2 -0
- package/lib/{disallowed-element → no-restricted-element}/index.js +7 -8
- package/lib/no-restricted-element/meta.d.ts +4 -0
- package/lib/no-restricted-element/meta.js +3 -0
- package/lib/no-skipped-heading-level/index.d.ts +13 -0
- package/lib/{heading-levels → no-skipped-heading-level}/index.js +10 -5
- package/lib/no-skipped-heading-level/meta.d.ts +4 -0
- package/lib/no-skipped-heading-level/meta.js +3 -0
- package/lib/no-stray-head-or-body-tag/index.d.ts +28 -0
- package/lib/no-stray-head-or-body-tag/index.js +61 -0
- package/lib/no-stray-head-or-body-tag/meta.d.ts +4 -0
- package/lib/no-stray-head-or-body-tag/meta.js +3 -0
- package/lib/no-table-cell-overlap/index.d.ts +12 -0
- package/lib/no-table-cell-overlap/index.js +30 -0
- package/lib/no-table-cell-overlap/meta.d.ts +4 -0
- package/lib/no-table-cell-overlap/meta.js +3 -0
- package/lib/no-table-span-overflow/index.d.ts +12 -0
- package/lib/no-table-span-overflow/index.js +37 -0
- package/lib/no-table-span-overflow/meta.d.ts +4 -0
- package/lib/no-table-span-overflow/meta.js +3 -0
- package/lib/no-unclosed-element-at-eof/index.d.ts +2 -0
- package/lib/no-unclosed-element-at-eof/index.js +86 -0
- package/lib/no-unclosed-element-at-eof/meta.d.ts +4 -0
- package/lib/no-unclosed-element-at-eof/meta.js +3 -0
- package/lib/no-unescaped-char/index.d.ts +14 -0
- package/lib/{character-reference → no-unescaped-char}/index.js +31 -20
- package/lib/no-unescaped-char/meta.d.ts +4 -0
- package/lib/no-unescaped-char/meta.js +3 -0
- package/lib/{invalid-attr → no-unknown-attr}/index.d.ts +4 -19
- package/lib/no-unknown-attr/index.js +91 -0
- package/lib/no-unknown-attr/meta.d.ts +4 -0
- package/lib/no-unknown-attr/meta.js +3 -0
- package/lib/no-unknown-role/index.d.ts +3 -0
- package/lib/{wai-aria-non-existent-role → no-unknown-role}/index.js +0 -1
- package/lib/no-unknown-role/meta.d.ts +4 -0
- package/lib/no-unknown-role/meta.js +3 -0
- package/lib/no-unpaired-srcset-sizes/index.d.ts +12 -0
- package/lib/no-unpaired-srcset-sizes/index.js +77 -0
- package/lib/no-unpaired-srcset-sizes/meta.d.ts +4 -0
- package/lib/no-unpaired-srcset-sizes/meta.js +3 -0
- package/lib/{no-unsupported-features → no-unsupported-browser-features}/index.d.ts +1 -10
- package/lib/no-unsupported-browser-features/index.js +81 -0
- package/lib/no-unsupported-browser-features/meta.d.ts +4 -0
- package/lib/no-unsupported-browser-features/meta.js +3 -0
- package/lib/permitted-contents/index.d.ts +0 -18
- package/lib/permitted-contents/index.js +0 -78
- package/lib/permitted-contents/meta.d.ts +1 -2
- package/lib/permitted-contents/meta.js +1 -2
- package/lib/permitted-contents/represent-transparent-nodes.js +15 -6
- package/lib/permitted-roles/index.d.ts +3 -0
- package/lib/{wai-aria-permitted-roles → permitted-roles}/index.js +0 -1
- package/lib/permitted-roles/meta.d.ts +4 -0
- package/lib/permitted-roles/meta.js +3 -0
- package/lib/placeholder-label-option/index.d.ts +10 -4
- package/lib/placeholder-label-option/index.js +30 -17
- package/lib/placeholder-label-option/meta.d.ts +1 -2
- package/lib/placeholder-label-option/meta.js +1 -2
- package/lib/progress-value-bounds/index.d.ts +10 -0
- package/lib/progress-value-bounds/index.js +59 -0
- package/lib/progress-value-bounds/meta.d.ts +4 -0
- package/lib/progress-value-bounds/meta.js +3 -0
- package/lib/require-accessible-name/index.d.ts +0 -7
- package/lib/require-accessible-name/index.js +0 -7
- package/lib/require-accessible-name/meta.d.ts +0 -1
- package/lib/require-accessible-name/meta.js +0 -1
- package/lib/require-adjacent-popover/index.d.ts +2 -0
- package/lib/{neighbor-popovers → require-adjacent-popover}/index.js +1 -8
- package/lib/require-adjacent-popover/meta.d.ts +4 -0
- package/lib/require-adjacent-popover/meta.js +3 -0
- package/lib/require-ancestor/index.d.ts +2 -0
- package/lib/require-ancestor/index.js +29 -0
- package/lib/require-ancestor/meta.d.ts +4 -0
- package/lib/require-ancestor/meta.js +3 -0
- package/lib/require-aria-prop/index.d.ts +3 -0
- package/lib/{wai-aria-required-props → require-aria-prop}/index.js +0 -1
- package/lib/require-aria-prop/meta.d.ts +4 -0
- package/lib/require-aria-prop/meta.js +3 -0
- package/lib/{required-attr → require-attr}/index.d.ts +2 -9
- package/lib/{required-attr → require-attr}/index.js +0 -7
- package/lib/require-attr/meta.d.ts +4 -0
- package/lib/require-attr/meta.js +3 -0
- package/lib/require-datetime/index.d.ts +0 -8
- package/lib/require-datetime/index.js +0 -8
- package/lib/require-datetime/meta.d.ts +1 -2
- package/lib/require-datetime/meta.js +1 -2
- package/lib/require-dialog-autofocus/index.d.ts +0 -10
- package/lib/require-dialog-autofocus/index.js +0 -10
- package/lib/require-dialog-autofocus/meta.d.ts +0 -1
- package/lib/require-dialog-autofocus/meta.js +0 -1
- package/lib/require-doctype/index.d.ts +2 -0
- package/lib/require-doctype/index.js +19 -0
- package/lib/require-doctype/meta.d.ts +5 -0
- package/lib/require-doctype/meta.js +10 -0
- package/lib/{required-element → require-element}/index.d.ts +1 -9
- package/lib/{required-element → require-element}/index.js +0 -8
- package/lib/require-element/meta.d.ts +4 -0
- package/lib/require-element/meta.js +3 -0
- package/lib/require-end-tag/index.d.ts +2 -0
- package/lib/{end-tag → require-end-tag}/index.js +0 -7
- package/lib/require-end-tag/meta.d.ts +4 -0
- package/lib/require-end-tag/meta.js +3 -0
- package/lib/require-h1/index.d.ts +17 -0
- package/lib/{required-h1 → require-h1}/index.js +6 -14
- package/lib/require-h1/meta.d.ts +4 -0
- package/lib/require-h1/meta.js +3 -0
- package/lib/require-landmark-label/index.d.ts +11 -0
- package/lib/require-landmark-label/index.js +55 -0
- package/lib/require-landmark-label/meta.d.ts +4 -0
- package/lib/require-landmark-label/meta.js +3 -0
- package/lib/require-owned-elements/index.d.ts +3 -0
- package/lib/{wai-aria-required-owned-elements → require-owned-elements}/index.js +0 -2
- package/lib/require-owned-elements/meta.d.ts +4 -0
- package/lib/require-owned-elements/meta.js +3 -0
- package/lib/require-parent-role/index.d.ts +3 -0
- package/lib/{wai-aria-required-parent-role → require-parent-role}/index.js +0 -1
- package/lib/require-parent-role/meta.d.ts +4 -0
- package/lib/require-parent-role/meta.js +3 -0
- package/lib/role-supports-aria-prop/index.d.ts +8 -0
- package/lib/{wai-aria-disallowed-props → role-supports-aria-prop}/index.js +11 -10
- package/lib/role-supports-aria-prop/meta.d.ts +4 -0
- package/lib/role-supports-aria-prop/meta.js +3 -0
- package/lib/rule-aliases.d.ts +2 -0
- package/lib/rule-aliases.js +325 -0
- package/lib/sizes-auto-requires-lazy-loading/index.d.ts +14 -0
- package/lib/sizes-auto-requires-lazy-loading/index.js +68 -0
- package/lib/sizes-auto-requires-lazy-loading/meta.d.ts +4 -0
- package/lib/sizes-auto-requires-lazy-loading/meta.js +3 -0
- package/lib/srcset-sizes-constraint/parse-srcset.d.ts +6 -0
- package/lib/srcset-sizes-constraint/parse-srcset.js +6 -0
- package/lib/srcset-sizes-constraint/sibling-helpers.d.ts +21 -0
- package/lib/srcset-sizes-constraint/sibling-helpers.js +37 -0
- package/lib/tab-requires-tabpanel/index.d.ts +3 -0
- package/lib/tab-requires-tabpanel/index.js +21 -0
- package/lib/tab-requires-tabpanel/meta.d.ts +4 -0
- package/lib/tab-requires-tabpanel/meta.js +3 -0
- package/lib/table-row-column-alignment/grid.d.ts +108 -52
- package/lib/table-row-column-alignment/grid.js +276 -203
- package/lib/table-row-column-alignment/types.d.ts +6 -8
- package/lib/usemap-references-map/index.d.ts +14 -0
- package/lib/usemap-references-map/index.js +46 -0
- package/lib/usemap-references-map/meta.d.ts +4 -0
- package/lib/usemap-references-map/meta.js +3 -0
- package/lib/valid-importmap/index.d.ts +2 -0
- package/lib/valid-importmap/index.js +176 -0
- package/lib/valid-importmap/meta.d.ts +4 -0
- package/lib/valid-importmap/meta.js +3 -0
- package/lib/valid-speculation-rules/index.d.ts +2 -0
- package/lib/valid-speculation-rules/index.js +292 -0
- package/lib/valid-speculation-rules/meta.d.ts +4 -0
- package/lib/valid-speculation-rules/meta.js +3 -0
- package/lib/wai-aria/checkings/contradictory-aria-prop.d.ts +23 -0
- package/lib/wai-aria/checkings/{implicit-props.js → contradictory-aria-prop.js} +22 -14
- package/lib/wai-aria/checkings/element-supports-aria-prop.d.ts +20 -0
- package/lib/wai-aria/checkings/element-supports-aria-prop.js +83 -0
- package/lib/wai-aria/checkings/prohibited-naming.d.ts +35 -0
- package/lib/wai-aria/checkings/prohibited-naming.js +64 -0
- package/lib/wai-aria/checkings/redundant-aria-prop.d.ts +23 -0
- package/lib/wai-aria/checkings/redundant-aria-prop.js +53 -0
- package/lib/wai-aria/checkings/required-prop.d.ts +4 -0
- package/lib/wai-aria/checkings/required-prop.js +16 -3
- package/lib/wai-aria/checkings/role-supports-aria-prop.d.ts +20 -0
- package/lib/wai-aria/checkings/role-supports-aria-prop.js +30 -0
- package/lib/wai-aria/checkings/tab-requires-tabpanel.d.ts +19 -0
- package/lib/wai-aria/checkings/tab-requires-tabpanel.js +56 -0
- package/lib/wai-aria/default-options.js +1 -0
- package/lib/wai-aria/types.d.ts +2 -0
- package/package.json +11 -10
- package/schema.json +275 -59
- package/SKILL.md +0 -77
- package/lib/attr-duplication/index.d.ts +0 -9
- package/lib/attr-duplication/meta.d.ts +0 -6
- package/lib/attr-duplication/meta.js +0 -5
- package/lib/character-reference/index.d.ts +0 -12
- package/lib/character-reference/meta.d.ts +0 -5
- package/lib/character-reference/meta.js +0 -4
- package/lib/correct-aspect-ratio/meta.js +0 -3
- package/lib/deprecated-attr/index.d.ts +0 -8
- package/lib/deprecated-attr/meta.d.ts +0 -5
- package/lib/deprecated-attr/meta.js +0 -4
- package/lib/deprecated-element/index.d.ts +0 -8
- package/lib/deprecated-element/meta.d.ts +0 -5
- package/lib/deprecated-element/meta.js +0 -4
- package/lib/disallowed-element/index.d.ts +0 -9
- package/lib/disallowed-element/meta.d.ts +0 -5
- package/lib/disallowed-element/meta.js +0 -4
- package/lib/doctype/index.d.ts +0 -15
- package/lib/doctype/meta.d.ts +0 -5
- package/lib/doctype/meta.js +0 -4
- package/lib/end-tag/index.d.ts +0 -9
- package/lib/end-tag/meta.d.ts +0 -5
- package/lib/end-tag/meta.js +0 -4
- package/lib/heading-levels/index.d.ts +0 -8
- package/lib/heading-levels/meta.d.ts +0 -5
- package/lib/heading-levels/meta.js +0 -4
- package/lib/id-duplication/index.d.ts +0 -9
- package/lib/id-duplication/meta.d.ts +0 -5
- package/lib/id-duplication/meta.js +0 -4
- package/lib/ineffective-attr/index.d.ts +0 -9
- package/lib/ineffective-attr/meta.d.ts +0 -6
- package/lib/ineffective-attr/meta.js +0 -5
- package/lib/invalid-attr/index.js +0 -207
- package/lib/invalid-attr/meta.d.ts +0 -5
- package/lib/invalid-attr/meta.js +0 -4
- package/lib/landmark-roles/index.d.ts +0 -22
- package/lib/landmark-roles/index.js +0 -142
- package/lib/landmark-roles/meta.d.ts +0 -5
- package/lib/landmark-roles/meta.js +0 -4
- package/lib/neighbor-popovers/index.d.ts +0 -10
- package/lib/neighbor-popovers/meta.d.ts +0 -5
- package/lib/neighbor-popovers/meta.js +0 -4
- package/lib/no-hard-code-id/index.d.ts +0 -10
- package/lib/no-hard-code-id/meta.d.ts +0 -5
- package/lib/no-hard-code-id/meta.js +0 -4
- package/lib/no-unsupported-features/index.js +0 -139
- package/lib/no-unsupported-features/meta.d.ts +0 -5
- package/lib/no-unsupported-features/meta.js +0 -4
- package/lib/no-use-event-handler-attr/index.d.ts +0 -18
- package/lib/no-use-event-handler-attr/meta.d.ts +0 -5
- package/lib/no-use-event-handler-attr/meta.js +0 -4
- package/lib/redundant-accessible-name/meta.d.ts +0 -5
- package/lib/redundant-accessible-name/meta.js +0 -4
- package/lib/required-attr/meta.d.ts +0 -5
- package/lib/required-attr/meta.js +0 -4
- package/lib/required-element/meta.d.ts +0 -5
- package/lib/required-element/meta.js +0 -4
- package/lib/required-h1/index.d.ts +0 -18
- package/lib/required-h1/meta.d.ts +0 -5
- package/lib/required-h1/meta.js +0 -4
- package/lib/srcset-sizes-constraint/index.d.ts +0 -6
- package/lib/srcset-sizes-constraint/index.js +0 -108
- package/lib/srcset-sizes-constraint/meta.d.ts +0 -5
- package/lib/srcset-sizes-constraint/meta.js +0 -4
- package/lib/table-row-column-alignment/index.d.ts +0 -10
- package/lib/table-row-column-alignment/index.js +0 -97
- package/lib/table-row-column-alignment/meta.d.ts +0 -5
- package/lib/table-row-column-alignment/meta.js +0 -4
- package/lib/use-list/meta.d.ts +0 -5
- package/lib/use-list/meta.js +0 -4
- package/lib/wai-aria/checkings/disallowed-prop.d.ts +0 -23
- package/lib/wai-aria/checkings/disallowed-prop.js +0 -84
- package/lib/wai-aria/checkings/implicit-props.d.ts +0 -20
- package/lib/wai-aria/index.d.ts +0 -13
- package/lib/wai-aria/index.js +0 -115
- package/lib/wai-aria/meta.d.ts +0 -5
- package/lib/wai-aria/meta.js +0 -4
- package/lib/wai-aria-default-value/index.d.ts +0 -4
- package/lib/wai-aria-default-value/meta.d.ts +0 -5
- package/lib/wai-aria-default-value/meta.js +0 -4
- package/lib/wai-aria-deprecated-props/index.d.ts +0 -4
- package/lib/wai-aria-deprecated-props/meta.d.ts +0 -5
- package/lib/wai-aria-deprecated-props/meta.js +0 -4
- package/lib/wai-aria-disallowed-props/index.d.ts +0 -4
- package/lib/wai-aria-disallowed-props/meta.d.ts +0 -5
- package/lib/wai-aria-disallowed-props/meta.js +0 -4
- package/lib/wai-aria-implicit-props/index.d.ts +0 -4
- package/lib/wai-aria-implicit-props/meta.d.ts +0 -5
- package/lib/wai-aria-implicit-props/meta.js +0 -4
- package/lib/wai-aria-implicit-role/index.d.ts +0 -4
- package/lib/wai-aria-interaction-in-hidden/index.d.ts +0 -4
- package/lib/wai-aria-interaction-in-hidden/meta.d.ts +0 -5
- package/lib/wai-aria-interaction-in-hidden/meta.js +0 -4
- package/lib/wai-aria-no-global-prop/index.d.ts +0 -4
- package/lib/wai-aria-no-global-prop/meta.d.ts +0 -5
- package/lib/wai-aria-no-global-prop/meta.js +0 -4
- package/lib/wai-aria-non-existent-role/index.d.ts +0 -4
- package/lib/wai-aria-permitted-roles/index.d.ts +0 -4
- package/lib/wai-aria-presentational-children/index.d.ts +0 -4
- package/lib/wai-aria-presentational-children/meta.d.ts +0 -5
- package/lib/wai-aria-presentational-children/meta.js +0 -4
- package/lib/wai-aria-required-parent-role/index.d.ts +0 -4
- package/lib/wai-aria-value/index.d.ts +0 -4
- package/lib/wai-aria-value/meta.d.ts +0 -5
- package/lib/wai-aria-value/meta.js +0 -4
- /package/lib/{wai-aria-abstract-role → aria-prop-requires-role}/meta.d.ts +0 -0
- /package/lib/{wai-aria-abstract-role → aria-prop-requires-role}/meta.js +0 -0
- /package/lib/{wai-aria-deprecated-role → element-supports-aria-prop}/meta.d.ts +0 -0
- /package/lib/{wai-aria-deprecated-role → element-supports-aria-prop}/meta.js +0 -0
- /package/lib/{wai-aria-implicit-role → no-abstract-role}/meta.d.ts +0 -0
- /package/lib/{wai-aria-implicit-role → no-abstract-role}/meta.js +0 -0
- /package/lib/{wai-aria-non-existent-role → no-aria-on-presentational-children}/meta.d.ts +0 -0
- /package/lib/{wai-aria-non-existent-role → no-aria-on-presentational-children}/meta.js +0 -0
- /package/lib/{wai-aria-permitted-roles → no-contradictory-aria-prop}/meta.d.ts +0 -0
- /package/lib/{wai-aria-permitted-roles → no-contradictory-aria-prop}/meta.js +0 -0
- /package/lib/{wai-aria-required-owned-elements → no-default-aria-value}/meta.d.ts +0 -0
- /package/lib/{wai-aria-required-owned-elements → no-default-aria-value}/meta.js +0 -0
- /package/lib/{wai-aria-required-parent-role → no-deprecated-aria-prop}/meta.d.ts +0 -0
- /package/lib/{wai-aria-required-parent-role → no-deprecated-aria-prop}/meta.js +0 -0
- /package/lib/{wai-aria-required-props → no-deprecated-role}/meta.d.ts +0 -0
- /package/lib/{wai-aria-required-props → no-deprecated-role}/meta.js +0 -0
- /package/lib/{correct-aspect-ratio → no-mismatched-aspect-ratio}/index.d.ts +0 -0
- /package/lib/{correct-aspect-ratio → no-mismatched-aspect-ratio}/resolve-image-size.d.ts +0 -0
- /package/lib/{no-unsupported-features → no-unsupported-browser-features}/compat-data.d.ts +0 -0
- /package/lib/{no-unsupported-features → no-unsupported-browser-features}/compat-data.js +0 -0
- /package/lib/{no-unsupported-features → no-unsupported-browser-features}/resolve-browsers.d.ts +0 -0
- /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,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,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 {
|
|
1
|
+
import { resolveAttrEligibility } from '../../attr-eligibility.js';
|
|
2
2
|
/**
|
|
3
|
-
* Checks whether an ARIA property
|
|
4
|
-
*
|
|
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`
|
|
7
|
-
*
|
|
8
|
-
*
|
|
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
|
|
16
|
+
* @returns A violation if the ARIA property contradicts an equivalent HTML attribute.
|
|
14
17
|
*/
|
|
15
|
-
export const
|
|
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
|
|
29
|
-
|
|
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
|
-
|
|
38
|
-
|
|
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
|
+
}>;
|