@markuplint/rules 4.11.2 → 5.0.0-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +63 -2
- package/SKILL.md +76 -0
- package/lib/attr-check.d.ts +46 -7
- package/lib/attr-check.js +42 -8
- package/lib/attr-duplication/index.d.ts +7 -0
- package/lib/attr-duplication/index.js +7 -0
- package/lib/attr-duplication/meta.d.ts +1 -0
- package/lib/attr-duplication/meta.js +1 -0
- package/lib/attr-value-quotes/index.d.ts +10 -0
- package/lib/attr-value-quotes/index.js +10 -0
- package/lib/attr-value-quotes/meta.d.ts +1 -0
- package/lib/attr-value-quotes/meta.js +1 -0
- package/lib/case-sensitive-attr-name/index.d.ts +9 -0
- package/lib/case-sensitive-attr-name/index.js +8 -0
- package/lib/case-sensitive-attr-name/meta.d.ts +1 -0
- package/lib/case-sensitive-attr-name/meta.js +1 -0
- package/lib/case-sensitive-tag-name/index.d.ts +9 -0
- package/lib/case-sensitive-tag-name/index.js +8 -0
- package/lib/case-sensitive-tag-name/meta.d.ts +1 -0
- package/lib/case-sensitive-tag-name/meta.js +1 -0
- package/lib/character-reference/index.d.ts +9 -0
- package/lib/character-reference/index.js +20 -0
- package/lib/character-reference/meta.d.ts +1 -0
- package/lib/character-reference/meta.js +1 -0
- package/lib/class-naming/index.d.ts +9 -0
- package/lib/class-naming/index.js +8 -0
- package/lib/class-naming/meta.d.ts +1 -0
- package/lib/class-naming/meta.js +1 -0
- package/lib/correct-aspect-ratio/index.d.ts +5 -0
- package/lib/correct-aspect-ratio/index.js +80 -0
- package/lib/correct-aspect-ratio/meta.d.ts +4 -0
- package/lib/correct-aspect-ratio/meta.js +3 -0
- package/lib/correct-aspect-ratio/resolve-image-size.d.ts +24 -0
- package/lib/correct-aspect-ratio/resolve-image-size.js +165 -0
- package/lib/create-message.d.ts +29 -2
- package/lib/create-message.js +60 -2
- package/lib/debug.d.ts +9 -0
- package/lib/debug.js +5 -0
- package/lib/deprecated-attr/index.d.ts +6 -0
- package/lib/deprecated-attr/index.js +6 -0
- package/lib/deprecated-attr/meta.d.ts +1 -0
- package/lib/deprecated-attr/meta.js +1 -0
- package/lib/deprecated-element/index.d.ts +6 -0
- package/lib/deprecated-element/index.js +8 -2
- package/lib/deprecated-element/meta.d.ts +1 -0
- package/lib/deprecated-element/meta.js +1 -0
- package/lib/disallowed-element/index.d.ts +7 -0
- package/lib/disallowed-element/index.js +7 -0
- package/lib/disallowed-element/meta.d.ts +1 -0
- package/lib/disallowed-element/meta.js +1 -0
- package/lib/doctype/index.d.ts +10 -0
- package/lib/doctype/index.js +8 -0
- package/lib/doctype/meta.d.ts +1 -0
- package/lib/doctype/meta.js +1 -0
- package/lib/end-tag/index.d.ts +7 -0
- package/lib/end-tag/index.js +8 -1
- package/lib/end-tag/meta.d.ts +1 -0
- package/lib/end-tag/meta.js +1 -0
- package/lib/heading-levels/index.d.ts +6 -0
- package/lib/heading-levels/index.js +6 -1
- package/lib/heading-levels/meta.d.ts +1 -0
- package/lib/heading-levels/meta.js +1 -0
- package/lib/helpers.d.ts +105 -0
- package/lib/helpers.js +112 -16
- package/lib/id-duplication/index.d.ts +7 -0
- package/lib/id-duplication/index.js +7 -0
- package/lib/id-duplication/meta.d.ts +1 -0
- package/lib/id-duplication/meta.js +1 -0
- package/lib/index.d.ts +43 -41
- package/lib/index.js +24 -0
- package/lib/ineffective-attr/index.d.ts +7 -0
- package/lib/ineffective-attr/index.js +7 -0
- package/lib/ineffective-attr/meta.d.ts +1 -0
- package/lib/ineffective-attr/meta.js +1 -0
- package/lib/invalid-attr/index.d.ts +29 -21
- package/lib/invalid-attr/index.js +60 -109
- package/lib/invalid-attr/meta.d.ts +1 -0
- package/lib/invalid-attr/meta.js +1 -0
- package/lib/label-has-control/index.d.ts +7 -0
- package/lib/label-has-control/index.js +11 -0
- package/lib/label-has-control/meta.d.ts +1 -0
- package/lib/label-has-control/meta.js +1 -0
- package/lib/landmark-roles/index.d.ts +14 -0
- package/lib/landmark-roles/index.js +21 -0
- package/lib/landmark-roles/meta.d.ts +1 -0
- package/lib/landmark-roles/meta.js +1 -0
- package/lib/link-types/index.d.ts +10 -0
- package/lib/link-types/index.js +180 -0
- package/lib/link-types/meta.d.ts +5 -0
- package/lib/link-types/meta.js +4 -0
- package/lib/neighbor-popovers/index.d.ts +8 -0
- package/lib/neighbor-popovers/index.js +28 -6
- package/lib/neighbor-popovers/meta.d.ts +1 -0
- package/lib/neighbor-popovers/meta.js +1 -0
- package/lib/no-ambiguous-navigable-target-names/index.d.ts +8 -0
- package/lib/no-ambiguous-navigable-target-names/index.js +8 -0
- package/lib/no-ambiguous-navigable-target-names/meta.d.ts +1 -0
- package/lib/no-ambiguous-navigable-target-names/meta.js +1 -0
- package/lib/no-boolean-attr-value/index.d.ts +7 -0
- package/lib/no-boolean-attr-value/index.js +7 -0
- package/lib/no-boolean-attr-value/meta.d.ts +1 -0
- package/lib/no-boolean-attr-value/meta.js +1 -0
- package/lib/no-consecutive-br/index.d.ts +8 -0
- package/lib/no-consecutive-br/index.js +8 -0
- package/lib/no-consecutive-br/meta.d.ts +1 -0
- package/lib/no-consecutive-br/meta.js +1 -0
- package/lib/no-default-value/index.d.ts +7 -0
- package/lib/no-default-value/index.js +7 -0
- package/lib/no-default-value/meta.d.ts +1 -0
- package/lib/no-default-value/meta.js +1 -0
- package/lib/no-duplicate-dt/index.d.ts +6 -0
- package/lib/no-duplicate-dt/index.js +6 -0
- package/lib/no-duplicate-dt/meta.d.ts +1 -0
- package/lib/no-duplicate-dt/meta.js +1 -0
- package/lib/no-empty-palpable-content/index.d.ts +13 -0
- package/lib/no-empty-palpable-content/index.js +12 -0
- package/lib/no-empty-palpable-content/meta.d.ts +1 -0
- package/lib/no-empty-palpable-content/meta.js +1 -0
- package/lib/no-hard-code-id/index.d.ts +8 -0
- package/lib/no-hard-code-id/index.js +8 -0
- package/lib/no-hard-code-id/meta.d.ts +1 -0
- package/lib/no-hard-code-id/meta.js +1 -0
- package/lib/no-orphaned-end-tag/index.d.ts +7 -0
- package/lib/no-orphaned-end-tag/index.js +8 -2
- package/lib/no-orphaned-end-tag/meta.d.ts +1 -0
- package/lib/no-orphaned-end-tag/meta.js +1 -0
- package/lib/no-refer-to-non-existent-id/index.d.ts +9 -1
- package/lib/no-refer-to-non-existent-id/index.js +11 -2
- package/lib/no-refer-to-non-existent-id/meta.d.ts +1 -0
- package/lib/no-refer-to-non-existent-id/meta.js +1 -0
- package/lib/no-unsupported-features/compat-data.d.ts +71 -0
- package/lib/no-unsupported-features/compat-data.js +204 -0
- package/lib/no-unsupported-features/index.d.ts +24 -0
- package/lib/no-unsupported-features/index.js +139 -0
- package/lib/no-unsupported-features/meta.d.ts +5 -0
- package/lib/no-unsupported-features/meta.js +4 -0
- package/lib/no-unsupported-features/resolve-browsers.d.ts +30 -0
- package/lib/no-unsupported-features/resolve-browsers.js +125 -0
- package/lib/no-use-event-handler-attr/index.d.ts +10 -0
- package/lib/no-use-event-handler-attr/index.js +8 -0
- package/lib/no-use-event-handler-attr/meta.d.ts +1 -0
- package/lib/no-use-event-handler-attr/meta.js +1 -0
- package/lib/permitted-contents/choice.d.ts +17 -0
- package/lib/permitted-contents/choice.js +31 -1
- package/lib/permitted-contents/complex-branch.d.ts +11 -7
- package/lib/permitted-contents/complex-branch.js +11 -7
- package/lib/permitted-contents/content-model.d.ts +11 -0
- package/lib/permitted-contents/content-model.js +32 -0
- package/lib/permitted-contents/count-pattern.d.ts +13 -7
- package/lib/permitted-contents/count-pattern.js +24 -8
- package/lib/permitted-contents/debug.browser.d.ts +12 -0
- package/lib/permitted-contents/debug.browser.js +12 -0
- package/lib/permitted-contents/debug.d.ts +12 -0
- package/lib/permitted-contents/debug.js +12 -0
- package/lib/permitted-contents/index.d.ts +12 -0
- package/lib/permitted-contents/index.js +21 -0
- package/lib/permitted-contents/matches-selector.d.ts +19 -0
- package/lib/permitted-contents/matches-selector.js +33 -0
- package/lib/permitted-contents/meta.d.ts +1 -0
- package/lib/permitted-contents/meta.js +1 -0
- package/lib/permitted-contents/order.d.ts +14 -7
- package/lib/permitted-contents/order.js +15 -8
- package/lib/permitted-contents/recursive-branch.d.ts +17 -0
- package/lib/permitted-contents/recursive-branch.js +17 -0
- package/lib/permitted-contents/represent-transparent-nodes.d.ts +54 -0
- package/lib/permitted-contents/represent-transparent-nodes.js +119 -12
- package/lib/permitted-contents/start.d.ts +12 -6
- package/lib/permitted-contents/start.js +12 -6
- package/lib/permitted-contents/transparent.d.ts +12 -0
- package/lib/permitted-contents/transparent.js +12 -0
- package/lib/permitted-contents/types.d.ts +67 -0
- package/lib/permitted-contents/utils.d.ts +160 -0
- package/lib/permitted-contents/utils.js +216 -35
- package/lib/placeholder-label-option/index.d.ts +7 -0
- package/lib/placeholder-label-option/index.js +19 -15
- package/lib/placeholder-label-option/meta.d.ts +1 -0
- package/lib/placeholder-label-option/meta.js +1 -0
- package/lib/redundant-accessible-name/index.d.ts +10 -0
- package/lib/redundant-accessible-name/index.js +123 -0
- package/lib/redundant-accessible-name/meta.d.ts +5 -0
- package/lib/redundant-accessible-name/meta.js +4 -0
- package/lib/require-accessible-name/index.d.ts +10 -4
- package/lib/require-accessible-name/index.js +13 -5
- package/lib/require-accessible-name/meta.d.ts +1 -0
- package/lib/require-accessible-name/meta.js +1 -0
- package/lib/require-datetime/index.d.ts +12 -0
- package/lib/require-datetime/index.js +8 -0
- package/lib/require-datetime/meta.d.ts +1 -0
- package/lib/require-datetime/meta.js +1 -0
- package/lib/require-datetime/types.d.ts +7 -0
- package/lib/require-datetime/utils.d.ts +18 -5
- package/lib/require-datetime/utils.js +53 -9
- package/lib/require-dialog-autofocus/index.d.ts +22 -0
- package/lib/require-dialog-autofocus/index.js +62 -0
- package/lib/require-dialog-autofocus/meta.d.ts +5 -0
- package/lib/require-dialog-autofocus/meta.js +4 -0
- package/lib/required-attr/index.d.ts +21 -1
- package/lib/required-attr/index.js +34 -4
- package/lib/required-attr/meta.d.ts +1 -0
- package/lib/required-attr/meta.js +1 -0
- package/lib/required-element/index.d.ts +14 -0
- package/lib/required-element/index.js +14 -2
- package/lib/required-element/meta.d.ts +1 -0
- package/lib/required-element/meta.js +1 -0
- package/lib/required-h1/index.d.ts +12 -0
- package/lib/required-h1/index.js +7 -0
- package/lib/required-h1/meta.d.ts +1 -0
- package/lib/required-h1/meta.js +1 -0
- package/lib/srcset-sizes-constraint/index.d.ts +6 -0
- package/lib/srcset-sizes-constraint/index.js +108 -0
- package/lib/srcset-sizes-constraint/meta.d.ts +5 -0
- package/lib/srcset-sizes-constraint/meta.js +4 -0
- package/lib/srcset-sizes-constraint/parse-srcset.d.ts +40 -0
- package/lib/srcset-sizes-constraint/parse-srcset.js +56 -0
- package/lib/table-row-column-alignment/find-children.d.ts +10 -0
- package/lib/table-row-column-alignment/find-children.js +11 -0
- package/lib/table-row-column-alignment/grid.d.ts +60 -0
- package/lib/table-row-column-alignment/grid.js +104 -26
- package/lib/table-row-column-alignment/index.d.ts +8 -0
- package/lib/table-row-column-alignment/index.js +8 -0
- package/lib/table-row-column-alignment/meta.d.ts +1 -0
- package/lib/table-row-column-alignment/meta.js +1 -0
- package/lib/table-row-column-alignment/types.d.ts +10 -0
- package/lib/use-list/index.d.ts +16 -0
- package/lib/use-list/index.js +20 -0
- package/lib/use-list/meta.d.ts +1 -0
- package/lib/use-list/meta.js +1 -0
- package/lib/wai-aria/checkings/abstract-role.d.ts +9 -0
- package/lib/wai-aria/checkings/abstract-role.js +14 -2
- package/lib/wai-aria/checkings/default-value.d.ts +11 -0
- package/lib/wai-aria/checkings/default-value.js +11 -0
- package/lib/wai-aria/checkings/deprecated-props.d.ts +11 -0
- package/lib/wai-aria/checkings/deprecated-props.js +11 -0
- package/lib/wai-aria/checkings/deprecated-role.d.ts +10 -0
- package/lib/wai-aria/checkings/deprecated-role.js +10 -0
- package/lib/wai-aria/checkings/disallowed-prop.d.ts +14 -0
- package/lib/wai-aria/checkings/disallowed-prop.js +19 -2
- package/lib/wai-aria/checkings/implicit-props.d.ts +13 -0
- package/lib/wai-aria/checkings/implicit-props.js +13 -0
- package/lib/wai-aria/checkings/implicit-role.d.ts +9 -0
- package/lib/wai-aria/checkings/implicit-role.js +14 -2
- package/lib/wai-aria/checkings/interaction-in-hidden.d.ts +9 -0
- package/lib/wai-aria/checkings/interaction-in-hidden.js +15 -4
- package/lib/wai-aria/checkings/no-global-prop.d.ts +10 -0
- package/lib/wai-aria/checkings/no-global-prop.js +10 -0
- package/lib/wai-aria/checkings/non-existent-role.d.ts +11 -0
- package/lib/wai-aria/checkings/non-existent-role.js +19 -2
- package/lib/wai-aria/checkings/permitted-roles.d.ts +10 -0
- package/lib/wai-aria/checkings/permitted-roles.js +15 -2
- package/lib/wai-aria/checkings/presentational-children.d.ts +7 -1
- package/lib/wai-aria/checkings/presentational-children.js +17 -3
- package/lib/wai-aria/checkings/required-accessibility-parent-role.d.ts +25 -0
- package/lib/wai-aria/checkings/required-accessibility-parent-role.js +56 -0
- package/lib/wai-aria/checkings/required-owned-elements.d.ts +10 -1
- package/lib/wai-aria/checkings/required-owned-elements.js +69 -25
- package/lib/wai-aria/checkings/required-prop.d.ts +13 -0
- package/lib/wai-aria/checkings/required-prop.js +18 -2
- package/lib/wai-aria/checkings/value.d.ts +23 -0
- package/lib/wai-aria/checkings/value.js +32 -0
- package/lib/wai-aria/index.d.ts +10 -0
- package/lib/wai-aria/index.js +22 -4
- package/lib/wai-aria/meta.d.ts +1 -0
- package/lib/wai-aria/meta.js +1 -0
- package/lib/wai-aria/types.d.ts +25 -1
- package/package.json +16 -11
- package/schema.json +18 -0
|
@@ -1,3 +1,12 @@
|
|
|
1
1
|
import type { Options } from '../types.js';
|
|
2
2
|
import type { AttrChecker } from '@markuplint/ml-core';
|
|
3
|
+
/**
|
|
4
|
+
* Checks whether the `role` attribute value refers to an abstract WAI-ARIA role.
|
|
5
|
+
*
|
|
6
|
+
* Abstract roles (e.g., `widget`, `landmark`) are used for ontological purposes
|
|
7
|
+
* in the ARIA taxonomy and must not be used directly in content.
|
|
8
|
+
*
|
|
9
|
+
* @param attr - The `role` attribute node to inspect.
|
|
10
|
+
* @returns A violation if any token in the role attribute is an abstract role.
|
|
11
|
+
*/
|
|
3
12
|
export declare const checkingAbstractRole: AttrChecker<boolean, Options>;
|
|
@@ -1,6 +1,18 @@
|
|
|
1
|
-
import { ariaSpecs } from '@markuplint/ml-spec';
|
|
1
|
+
import { ARIA_RECOMMENDED_VERSION, ariaSpecs } from '@markuplint/ml-spec';
|
|
2
|
+
/**
|
|
3
|
+
* Checks whether the `role` attribute value refers to an abstract WAI-ARIA role.
|
|
4
|
+
*
|
|
5
|
+
* Abstract roles (e.g., `widget`, `landmark`) are used for ontological purposes
|
|
6
|
+
* in the ARIA taxonomy and must not be used directly in content.
|
|
7
|
+
*
|
|
8
|
+
* @param attr - The `role` attribute node to inspect.
|
|
9
|
+
* @returns A violation if any token in the role attribute is an abstract role.
|
|
10
|
+
*/
|
|
2
11
|
export const checkingAbstractRole = ({ attr }) => t => {
|
|
3
|
-
const
|
|
12
|
+
const ariaVersion = attr.rule.options?.version ??
|
|
13
|
+
attr.ownerMLDocument.ruleCommonSettings?.ariaVersion ??
|
|
14
|
+
ARIA_RECOMMENDED_VERSION;
|
|
15
|
+
const { roles } = ariaSpecs(attr.ownerMLDocument.specs, ariaVersion);
|
|
4
16
|
const tokens = attr.tokenList?.allTokens();
|
|
5
17
|
if (!tokens) {
|
|
6
18
|
return;
|
|
@@ -1,6 +1,17 @@
|
|
|
1
1
|
import type { Options } from '../types.js';
|
|
2
2
|
import type { AttrChecker } from '@markuplint/ml-core';
|
|
3
3
|
import type { ARIAProperty } from '@markuplint/ml-spec';
|
|
4
|
+
/**
|
|
5
|
+
* Checks whether an ARIA property is explicitly set to its spec-defined default value.
|
|
6
|
+
*
|
|
7
|
+
* Setting an ARIA property to its default value is redundant and may indicate
|
|
8
|
+
* a misunderstanding of the property's behavior. This checker reports such cases
|
|
9
|
+
* when the `disallowDefaultValue` option is enabled.
|
|
10
|
+
*
|
|
11
|
+
* @param attr - The ARIA attribute node to inspect.
|
|
12
|
+
* @param propSpecs - The list of ARIA property specifications for value lookup.
|
|
13
|
+
* @returns A violation if the attribute value matches the property's default value.
|
|
14
|
+
*/
|
|
4
15
|
export declare const checkingDefaultValue: AttrChecker<boolean, Options, {
|
|
5
16
|
propSpecs: readonly ARIAProperty[];
|
|
6
17
|
}>;
|
|
@@ -1,3 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Checks whether an ARIA property is explicitly set to its spec-defined default value.
|
|
3
|
+
*
|
|
4
|
+
* Setting an ARIA property to its default value is redundant and may indicate
|
|
5
|
+
* a misunderstanding of the property's behavior. This checker reports such cases
|
|
6
|
+
* when the `disallowDefaultValue` option is enabled.
|
|
7
|
+
*
|
|
8
|
+
* @param attr - The ARIA attribute node to inspect.
|
|
9
|
+
* @param propSpecs - The list of ARIA property specifications for value lookup.
|
|
10
|
+
* @returns A violation if the attribute value matches the property's default value.
|
|
11
|
+
*/
|
|
1
12
|
export const checkingDefaultValue = ({ attr, propSpecs }) => t => {
|
|
2
13
|
if (attr.isDynamicValue) {
|
|
3
14
|
return;
|
|
@@ -1,6 +1,17 @@
|
|
|
1
1
|
import type { Options } from '../types.js';
|
|
2
2
|
import type { AttrChecker } from '@markuplint/ml-core';
|
|
3
3
|
import type { ARIAProperty, ARIARole } from '@markuplint/ml-spec';
|
|
4
|
+
/**
|
|
5
|
+
* Checks whether an ARIA property or state is deprecated for the element's computed role.
|
|
6
|
+
*
|
|
7
|
+
* Some ARIA properties become deprecated on specific roles across ARIA versions.
|
|
8
|
+
* This checker reports usage of such deprecated properties.
|
|
9
|
+
*
|
|
10
|
+
* @param attr - The ARIA attribute node to inspect.
|
|
11
|
+
* @param role - The computed ARIA role of the element.
|
|
12
|
+
* @param propSpecs - The list of ARIA property specifications for type lookup.
|
|
13
|
+
* @returns A violation if the property is deprecated on the given role.
|
|
14
|
+
*/
|
|
4
15
|
export declare const checkingDeprecatedProps: AttrChecker<boolean, Options, {
|
|
5
16
|
role: ARIARole | null;
|
|
6
17
|
propSpecs: readonly ARIAProperty[];
|
|
@@ -1,3 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Checks whether an ARIA property or state is deprecated for the element's computed role.
|
|
3
|
+
*
|
|
4
|
+
* Some ARIA properties become deprecated on specific roles across ARIA versions.
|
|
5
|
+
* This checker reports usage of such deprecated properties.
|
|
6
|
+
*
|
|
7
|
+
* @param attr - The ARIA attribute node to inspect.
|
|
8
|
+
* @param role - The computed ARIA role of the element.
|
|
9
|
+
* @param propSpecs - The list of ARIA property specifications for type lookup.
|
|
10
|
+
* @returns A violation if the property is deprecated on the given role.
|
|
11
|
+
*/
|
|
1
12
|
export const checkingDeprecatedProps = ({ attr, role, propSpecs }) => t => {
|
|
2
13
|
if (!role) {
|
|
3
14
|
return;
|
|
@@ -1,6 +1,16 @@
|
|
|
1
1
|
import type { Options } from '../types.js';
|
|
2
2
|
import type { AttrChecker } from '@markuplint/ml-core';
|
|
3
3
|
import type { ARIARole } from '@markuplint/ml-spec';
|
|
4
|
+
/**
|
|
5
|
+
* Checks whether the element's computed ARIA role is deprecated in the specified ARIA version.
|
|
6
|
+
*
|
|
7
|
+
* Deprecated roles should be avoided as they may be removed in future ARIA versions
|
|
8
|
+
* and assistive technologies may not support them reliably.
|
|
9
|
+
*
|
|
10
|
+
* @param attr - The `role` attribute node to inspect.
|
|
11
|
+
* @param role - The computed ARIA role of the element.
|
|
12
|
+
* @returns A violation if the role is marked as deprecated.
|
|
13
|
+
*/
|
|
4
14
|
export declare const checkingDeprecatedRole: AttrChecker<boolean, Options, {
|
|
5
15
|
role: ARIARole | null;
|
|
6
16
|
}>;
|
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Checks whether the element's computed ARIA role is deprecated in the specified ARIA version.
|
|
3
|
+
*
|
|
4
|
+
* Deprecated roles should be avoided as they may be removed in future ARIA versions
|
|
5
|
+
* and assistive technologies may not support them reliably.
|
|
6
|
+
*
|
|
7
|
+
* @param attr - The `role` attribute node to inspect.
|
|
8
|
+
* @param role - The computed ARIA role of the element.
|
|
9
|
+
* @returns A violation if the role is marked as deprecated.
|
|
10
|
+
*/
|
|
1
11
|
export const checkingDeprecatedRole = ({ attr, role }) => t => {
|
|
2
12
|
if (!role) {
|
|
3
13
|
return;
|
|
@@ -1,6 +1,20 @@
|
|
|
1
1
|
import type { Options } from '../types.js';
|
|
2
2
|
import type { AttrChecker } from '@markuplint/ml-core';
|
|
3
3
|
import type { ARIAProperty, ARIARole } from '@markuplint/ml-spec';
|
|
4
|
+
/**
|
|
5
|
+
* Checks whether an ARIA property or state is disallowed on the element's computed role.
|
|
6
|
+
*
|
|
7
|
+
* Each ARIA role defines a set of supported states and properties. This checker reports
|
|
8
|
+
* usage of ARIA attributes that are not in that set. It also considers element-specific
|
|
9
|
+
* restrictions from the ARIA in HTML specification (e.g., properties that should not
|
|
10
|
+
* be used on certain native HTML elements).
|
|
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
|
+
* @param disallowSetImplicitProps - Whether to also enforce element-specific restrictions.
|
|
16
|
+
* @returns A violation if the property is not allowed on the given role or element.
|
|
17
|
+
*/
|
|
4
18
|
export declare const checkingDisallowedProp: AttrChecker<boolean, Options, {
|
|
5
19
|
role: ARIARole | null;
|
|
6
20
|
propSpecs: readonly ARIAProperty[];
|
|
@@ -1,4 +1,18 @@
|
|
|
1
|
-
import { getARIA } from '@markuplint/ml-spec';
|
|
1
|
+
import { ARIA_RECOMMENDED_VERSION, getARIA } from '@markuplint/ml-spec';
|
|
2
|
+
/**
|
|
3
|
+
* Checks whether an ARIA property or state is disallowed on the element's computed role.
|
|
4
|
+
*
|
|
5
|
+
* Each ARIA role defines a set of supported states and properties. This checker reports
|
|
6
|
+
* usage of ARIA attributes that are not in that set. It also considers element-specific
|
|
7
|
+
* restrictions from the ARIA in HTML specification (e.g., properties that should not
|
|
8
|
+
* be used on certain native HTML elements).
|
|
9
|
+
*
|
|
10
|
+
* @param attr - The ARIA attribute node to inspect.
|
|
11
|
+
* @param role - The computed ARIA role of the element.
|
|
12
|
+
* @param propSpecs - The list of ARIA property specifications for type lookup.
|
|
13
|
+
* @param disallowSetImplicitProps - Whether to also enforce element-specific restrictions.
|
|
14
|
+
* @returns A violation if the property is not allowed on the given role or element.
|
|
15
|
+
*/
|
|
2
16
|
export const checkingDisallowedProp = ({ attr, role, propSpecs, disallowSetImplicitProps }) => t => {
|
|
3
17
|
if (!role) {
|
|
4
18
|
return;
|
|
@@ -6,9 +20,12 @@ export const checkingDisallowedProp = ({ attr, role, propSpecs, disallowSetImpli
|
|
|
6
20
|
if (!/^aria-/i.test(attr.name)) {
|
|
7
21
|
return;
|
|
8
22
|
}
|
|
23
|
+
const ariaVersion = attr.rule.options?.version ??
|
|
24
|
+
attr.ownerMLDocument.ruleCommonSettings?.ariaVersion ??
|
|
25
|
+
ARIA_RECOMMENDED_VERSION;
|
|
9
26
|
const statesAndProp = role.ownedProperties.find(p => p.name === attr.name);
|
|
10
27
|
const propSpec = propSpecs.find(p => p.name === attr.name);
|
|
11
|
-
const elAriaSpec = getARIA(attr.ownerMLDocument.specs, attr.ownerElement.localName, attr.ownerElement.namespaceURI,
|
|
28
|
+
const elAriaSpec = getARIA(attr.ownerMLDocument.specs, attr.ownerElement.localName, attr.ownerElement.namespaceURI, ariaVersion, attr.ownerElement.matches.bind(attr.ownerElement));
|
|
12
29
|
if (disallowSetImplicitProps && elAriaSpec?.properties !== false && elAriaSpec?.properties?.without) {
|
|
13
30
|
for (const ignore of elAriaSpec.properties.without) {
|
|
14
31
|
if (ignore.name === attr.name) {
|
|
@@ -1,6 +1,19 @@
|
|
|
1
1
|
import type { Options } from '../types.js';
|
|
2
2
|
import type { AttrChecker } from '@markuplint/ml-core';
|
|
3
3
|
import type { ARIAProperty, Attribute } from '@markuplint/ml-spec';
|
|
4
|
+
/**
|
|
5
|
+
* Checks whether an ARIA property duplicates or contradicts semantics already
|
|
6
|
+
* provided by an equivalent native HTML attribute.
|
|
7
|
+
*
|
|
8
|
+
* Many ARIA properties have equivalent HTML attributes (e.g., `aria-required` and `required`).
|
|
9
|
+
* This checker reports when an ARIA property is redundant because the native attribute
|
|
10
|
+
* already conveys the same semantics, or when the ARIA value contradicts the native attribute.
|
|
11
|
+
*
|
|
12
|
+
* @param attr - The ARIA attribute node to inspect.
|
|
13
|
+
* @param propSpecs - The list of ARIA property specifications for equivalence lookup.
|
|
14
|
+
* @param attrSpecs - The HTML attribute specifications for the element.
|
|
15
|
+
* @returns A violation if the ARIA property duplicates or contradicts an equivalent HTML attribute.
|
|
16
|
+
*/
|
|
4
17
|
export declare const checkingImplicitProps: AttrChecker<boolean, Options, {
|
|
5
18
|
propSpecs: readonly ARIAProperty[];
|
|
6
19
|
attrSpecs: readonly Attribute[] | null;
|
|
@@ -1,4 +1,17 @@
|
|
|
1
1
|
import { isValidAttr } from '../../helpers.js';
|
|
2
|
+
/**
|
|
3
|
+
* Checks whether an ARIA property duplicates or contradicts semantics already
|
|
4
|
+
* provided by an equivalent native HTML attribute.
|
|
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.
|
|
9
|
+
*
|
|
10
|
+
* @param attr - The ARIA attribute node to inspect.
|
|
11
|
+
* @param propSpecs - The list of ARIA property specifications for equivalence lookup.
|
|
12
|
+
* @param attrSpecs - The HTML attribute specifications for the element.
|
|
13
|
+
* @returns A violation if the ARIA property duplicates or contradicts an equivalent HTML attribute.
|
|
14
|
+
*/
|
|
2
15
|
export const checkingImplicitProps = ({ attr, propSpecs, attrSpecs }) => t => {
|
|
3
16
|
if (!attrSpecs) {
|
|
4
17
|
return;
|
|
@@ -1,3 +1,12 @@
|
|
|
1
1
|
import type { Options } from '../types.js';
|
|
2
2
|
import type { AttrChecker } from '@markuplint/ml-core';
|
|
3
|
+
/**
|
|
4
|
+
* Checks whether the explicit `role` attribute duplicates the element's implicit (native) role.
|
|
5
|
+
*
|
|
6
|
+
* HTML elements have implicit ARIA roles (e.g., `<nav>` has an implicit role of `navigation`).
|
|
7
|
+
* Explicitly setting the same role is redundant and should be avoided.
|
|
8
|
+
*
|
|
9
|
+
* @param attr - The `role` attribute node to inspect.
|
|
10
|
+
* @returns A violation if any token in the role attribute matches the element's implicit role.
|
|
11
|
+
*/
|
|
3
12
|
export declare const checkingImplicitRole: AttrChecker<boolean, Options>;
|
|
@@ -1,10 +1,22 @@
|
|
|
1
|
-
import { getImplicitRoleName } from '@markuplint/ml-spec';
|
|
1
|
+
import { ARIA_RECOMMENDED_VERSION, getImplicitRoleName } from '@markuplint/ml-spec';
|
|
2
|
+
/**
|
|
3
|
+
* Checks whether the explicit `role` attribute duplicates the element's implicit (native) role.
|
|
4
|
+
*
|
|
5
|
+
* HTML elements have implicit ARIA roles (e.g., `<nav>` has an implicit role of `navigation`).
|
|
6
|
+
* Explicitly setting the same role is redundant and should be avoided.
|
|
7
|
+
*
|
|
8
|
+
* @param attr - The `role` attribute node to inspect.
|
|
9
|
+
* @returns A violation if any token in the role attribute matches the element's implicit role.
|
|
10
|
+
*/
|
|
2
11
|
export const checkingImplicitRole = ({ attr }) => t => {
|
|
3
12
|
const tokens = attr.tokenList?.allTokens();
|
|
4
13
|
if (!tokens) {
|
|
5
14
|
return;
|
|
6
15
|
}
|
|
7
|
-
const
|
|
16
|
+
const ariaVersion = attr.rule.options?.version ??
|
|
17
|
+
attr.ownerMLDocument.ruleCommonSettings?.ariaVersion ??
|
|
18
|
+
ARIA_RECOMMENDED_VERSION;
|
|
19
|
+
const implicitRole = getImplicitRoleName(attr.ownerElement, ariaVersion, attr.ownerMLDocument.specs);
|
|
8
20
|
for (const token of tokens) {
|
|
9
21
|
if (implicitRole === token.raw) {
|
|
10
22
|
return {
|
|
@@ -1,11 +1,20 @@
|
|
|
1
1
|
import type { Options } from '../types.js';
|
|
2
2
|
import type { ElementChecker } from '@markuplint/ml-core';
|
|
3
3
|
/**
|
|
4
|
+
* Checks whether a focusable interactive element is inside an `aria-hidden=true` subtree.
|
|
5
|
+
*
|
|
4
6
|
* Including Elements in the Accessibility Tree
|
|
5
7
|
*
|
|
6
8
|
* @see https://w3c.github.io/aria/#tree_inclusion
|
|
7
9
|
* > Elements that are not hidden and may fire an accessibility API event, including:
|
|
8
10
|
* > - Elements that are currently focused, even if the element or one of its ancestor elements has its aria-hidden attribute set to true.
|
|
9
11
|
* > - Elements that are a valid target of an aria-activedescendant attribute.
|
|
12
|
+
*
|
|
13
|
+
* When a focused element exists within an `aria-hidden=true` ancestor, it is still
|
|
14
|
+
* exposed to the accessibility tree. This situation is almost always unintentional --
|
|
15
|
+
* while not strictly invalid per spec, it requires careful attention from the developer.
|
|
16
|
+
*
|
|
17
|
+
* @param el - The element node to inspect for focusability within a hidden context.
|
|
18
|
+
* @returns A violation if the element is focusable and has `aria-hidden=true` on itself or an ancestor.
|
|
10
19
|
*/
|
|
11
20
|
export declare const checkingInteractionInHidden: ElementChecker<boolean, Options>;
|
|
@@ -1,16 +1,21 @@
|
|
|
1
1
|
import { mayBeFocusable } from '@markuplint/ml-spec';
|
|
2
2
|
/**
|
|
3
|
+
* Checks whether a focusable interactive element is inside an `aria-hidden=true` subtree.
|
|
4
|
+
*
|
|
3
5
|
* Including Elements in the Accessibility Tree
|
|
4
6
|
*
|
|
5
7
|
* @see https://w3c.github.io/aria/#tree_inclusion
|
|
6
8
|
* > Elements that are not hidden and may fire an accessibility API event, including:
|
|
7
9
|
* > - Elements that are currently focused, even if the element or one of its ancestor elements has its aria-hidden attribute set to true.
|
|
8
10
|
* > - Elements that are a valid target of an aria-activedescendant attribute.
|
|
11
|
+
*
|
|
12
|
+
* When a focused element exists within an `aria-hidden=true` ancestor, it is still
|
|
13
|
+
* exposed to the accessibility tree. This situation is almost always unintentional --
|
|
14
|
+
* while not strictly invalid per spec, it requires careful attention from the developer.
|
|
15
|
+
*
|
|
16
|
+
* @param el - The element node to inspect for focusability within a hidden context.
|
|
17
|
+
* @returns A violation if the element is focusable and has `aria-hidden=true` on itself or an ancestor.
|
|
9
18
|
*/
|
|
10
|
-
// フォーカスがあたっている場合に限り、先祖がaria-hidden=trueでもアクセシビリティツリーに提示される
|
|
11
|
-
// なので、aria-hidden=trueの子孫要素で且つインタラクティブ要素である場合、
|
|
12
|
-
// それは開発者にとってはほとんどの場合、意図しないことが多いはずなので、
|
|
13
|
-
// 仕様上不正にはならないが、十分に注意しなければならない状態である。
|
|
14
19
|
export const checkingInteractionInHidden = ({ el }) => t => {
|
|
15
20
|
if (!mayBeFocusable(el, el.ownerMLDocument.specs)) {
|
|
16
21
|
return;
|
|
@@ -30,6 +35,12 @@ export const checkingInteractionInHidden = ({ el }) => t => {
|
|
|
30
35
|
message: t('It may be focusable in spite of it has the ancestor that has aria-hidden=true'),
|
|
31
36
|
};
|
|
32
37
|
};
|
|
38
|
+
/**
|
|
39
|
+
* Traverses the element's ancestor chain to find the closest element with `aria-hidden="true"`.
|
|
40
|
+
*
|
|
41
|
+
* @param el - The element to start searching from (inclusive).
|
|
42
|
+
* @returns The `aria-hidden` attribute node if found, or `null` if no ancestor is hidden.
|
|
43
|
+
*/
|
|
33
44
|
function getClosestAriaHidden(
|
|
34
45
|
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
35
46
|
el) {
|
|
@@ -1,6 +1,16 @@
|
|
|
1
1
|
import type { Options } from '../types.js';
|
|
2
2
|
import type { AttrChecker } from '@markuplint/ml-core';
|
|
3
3
|
import type { ARIAProperty } from '@markuplint/ml-spec';
|
|
4
|
+
/**
|
|
5
|
+
* Checks whether a non-global ARIA property is used on an element without an explicit role.
|
|
6
|
+
*
|
|
7
|
+
* When no role is computed for an element, only global ARIA properties (e.g., `aria-label`,
|
|
8
|
+
* `aria-hidden`) are allowed. This checker reports non-global properties used in that context.
|
|
9
|
+
*
|
|
10
|
+
* @param attr - The ARIA attribute node to inspect.
|
|
11
|
+
* @param propSpecs - The list of ARIA property specifications for global status lookup.
|
|
12
|
+
* @returns A violation if the property is not a global ARIA property.
|
|
13
|
+
*/
|
|
4
14
|
export declare const checkingNoGlobalProp: AttrChecker<boolean, Options, {
|
|
5
15
|
propSpecs: readonly ARIAProperty[];
|
|
6
16
|
}>;
|
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Checks whether a non-global ARIA property is used on an element without an explicit role.
|
|
3
|
+
*
|
|
4
|
+
* When no role is computed for an element, only global ARIA properties (e.g., `aria-label`,
|
|
5
|
+
* `aria-hidden`) are allowed. This checker reports non-global properties used in that context.
|
|
6
|
+
*
|
|
7
|
+
* @param attr - The ARIA attribute node to inspect.
|
|
8
|
+
* @param propSpecs - The list of ARIA property specifications for global status lookup.
|
|
9
|
+
* @returns A violation if the property is not a global ARIA property.
|
|
10
|
+
*/
|
|
1
11
|
export const checkingNoGlobalProp = ({ attr, propSpecs }) => t => {
|
|
2
12
|
const propSpec = propSpecs.find(prop => prop.name === attr.name);
|
|
3
13
|
if (propSpec && !propSpec.isGlobal) {
|
|
@@ -1,3 +1,14 @@
|
|
|
1
1
|
import type { Options } from '../types.js';
|
|
2
2
|
import type { AttrChecker } from '@markuplint/ml-core';
|
|
3
|
+
/**
|
|
4
|
+
* Checks whether the `role` attribute value refers to a role that does not exist
|
|
5
|
+
* in the WAI-ARIA specification.
|
|
6
|
+
*
|
|
7
|
+
* Validates each token in the role attribute against the known ARIA roles list.
|
|
8
|
+
* For SVG elements, the WAI-ARIA Graphics Module roles are also accepted.
|
|
9
|
+
* DPub ARIA roles (Digital Publishing WAI-ARIA Module) are accepted for all elements.
|
|
10
|
+
*
|
|
11
|
+
* @param attr - The `role` attribute node to inspect.
|
|
12
|
+
* @returns A violation if any token does not correspond to a defined ARIA role.
|
|
13
|
+
*/
|
|
3
14
|
export declare const checkingNonExistentRole: AttrChecker<boolean, Options>;
|
|
@@ -1,6 +1,20 @@
|
|
|
1
|
-
import { ariaSpecs } from '@markuplint/ml-spec';
|
|
1
|
+
import { ARIA_RECOMMENDED_VERSION, ariaSpecs } from '@markuplint/ml-spec';
|
|
2
|
+
/**
|
|
3
|
+
* Checks whether the `role` attribute value refers to a role that does not exist
|
|
4
|
+
* in the WAI-ARIA specification.
|
|
5
|
+
*
|
|
6
|
+
* Validates each token in the role attribute against the known ARIA roles list.
|
|
7
|
+
* For SVG elements, the WAI-ARIA Graphics Module roles are also accepted.
|
|
8
|
+
* DPub ARIA roles (Digital Publishing WAI-ARIA Module) are accepted for all elements.
|
|
9
|
+
*
|
|
10
|
+
* @param attr - The `role` attribute node to inspect.
|
|
11
|
+
* @returns A violation if any token does not correspond to a defined ARIA role.
|
|
12
|
+
*/
|
|
2
13
|
export const checkingNonExistentRole = ({ attr }) => t => {
|
|
3
|
-
const
|
|
14
|
+
const ariaVersion = attr.rule.options?.version ??
|
|
15
|
+
attr.ownerMLDocument.ruleCommonSettings?.ariaVersion ??
|
|
16
|
+
ARIA_RECOMMENDED_VERSION;
|
|
17
|
+
const { roles, graphicsRoles, dpubRoles } = ariaSpecs(attr.ownerMLDocument.specs, ariaVersion);
|
|
4
18
|
const tokens = attr.tokenList?.allTokens();
|
|
5
19
|
if (!tokens) {
|
|
6
20
|
return;
|
|
@@ -10,6 +24,9 @@ export const checkingNonExistentRole = ({ attr }) => t => {
|
|
|
10
24
|
if (!role && attr.ownerElement.namespaceURI === 'http://www.w3.org/2000/svg') {
|
|
11
25
|
role = graphicsRoles.find(r => r.name === token.raw);
|
|
12
26
|
}
|
|
27
|
+
if (!role) {
|
|
28
|
+
role = dpubRoles.find(r => r.name === token.raw);
|
|
29
|
+
}
|
|
13
30
|
if (!role) {
|
|
14
31
|
return {
|
|
15
32
|
scope: token,
|
|
@@ -1,3 +1,13 @@
|
|
|
1
1
|
import type { Options } from '../types.js';
|
|
2
2
|
import type { AttrChecker } from '@markuplint/ml-core';
|
|
3
|
+
/**
|
|
4
|
+
* Checks whether the explicit `role` attribute value is permitted on the element
|
|
5
|
+
* according to the ARIA in HTML specification.
|
|
6
|
+
*
|
|
7
|
+
* Each HTML element defines a set of roles that may be assigned to it. Some elements
|
|
8
|
+
* (e.g., `<meta>`) do not allow any role overrides. This checker enforces those constraints.
|
|
9
|
+
*
|
|
10
|
+
* @param attr - The `role` attribute node to inspect.
|
|
11
|
+
* @returns A violation if the role is not in the element's list of permitted roles.
|
|
12
|
+
*/
|
|
3
13
|
export declare const checkingPermittedRoles: AttrChecker<boolean, Options>;
|
|
@@ -1,7 +1,20 @@
|
|
|
1
|
-
import { getPermittedRoles } from '@markuplint/ml-spec';
|
|
1
|
+
import { ARIA_RECOMMENDED_VERSION, getPermittedRoles } from '@markuplint/ml-spec';
|
|
2
|
+
/**
|
|
3
|
+
* Checks whether the explicit `role` attribute value is permitted on the element
|
|
4
|
+
* according to the ARIA in HTML specification.
|
|
5
|
+
*
|
|
6
|
+
* Each HTML element defines a set of roles that may be assigned to it. Some elements
|
|
7
|
+
* (e.g., `<meta>`) do not allow any role overrides. This checker enforces those constraints.
|
|
8
|
+
*
|
|
9
|
+
* @param attr - The `role` attribute node to inspect.
|
|
10
|
+
* @returns A violation if the role is not in the element's list of permitted roles.
|
|
11
|
+
*/
|
|
2
12
|
export const checkingPermittedRoles = ({ attr }) => t => {
|
|
13
|
+
const ariaVersion = attr.rule.options?.version ??
|
|
14
|
+
attr.ownerMLDocument.ruleCommonSettings?.ariaVersion ??
|
|
15
|
+
ARIA_RECOMMENDED_VERSION;
|
|
3
16
|
const el = attr.ownerElement;
|
|
4
|
-
const permittedRoles = getPermittedRoles(el,
|
|
17
|
+
const permittedRoles = getPermittedRoles(el, ariaVersion, attr.ownerMLDocument.specs);
|
|
5
18
|
if (permittedRoles.length === 0) {
|
|
6
19
|
return {
|
|
7
20
|
scope: attr,
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import type { Options } from '../types.js';
|
|
2
2
|
import type { ElementChecker } from '@markuplint/ml-core';
|
|
3
3
|
/**
|
|
4
|
+
* Checks whether ARIA attributes are applied to descendants of an element whose
|
|
5
|
+
* role has the `childrenArePresentational` characteristic.
|
|
6
|
+
*
|
|
4
7
|
* Presentational Children
|
|
5
8
|
*
|
|
6
9
|
* @see https://www.w3.org/TR/wai-aria/#childrenArePresentational
|
|
@@ -22,8 +25,11 @@ import type { ElementChecker } from '@markuplint/ml-core';
|
|
|
22
25
|
*
|
|
23
26
|
* @see https://w3c.github.io/aria/#tree_inclusion
|
|
24
27
|
*
|
|
25
|
-
*
|
|
28
|
+
* > Text equivalents for hidden referenced objects
|
|
26
29
|
* > may still be used in the name and description computation
|
|
27
30
|
* > even when not included in the accessibility tree.
|
|
31
|
+
*
|
|
32
|
+
* @param el - The element node to inspect for presentational ancestor context.
|
|
33
|
+
* @returns A violation if the element has ARIA attributes and an ancestor with presentational children.
|
|
28
34
|
*/
|
|
29
35
|
export declare const checkingPresentationalChildren: ElementChecker<boolean, Options>;
|
|
@@ -1,5 +1,8 @@
|
|
|
1
|
-
import { getComputedRole } from '@markuplint/ml-spec';
|
|
1
|
+
import { ARIA_RECOMMENDED_VERSION, getComputedRole } from '@markuplint/ml-spec';
|
|
2
2
|
/**
|
|
3
|
+
* Checks whether ARIA attributes are applied to descendants of an element whose
|
|
4
|
+
* role has the `childrenArePresentational` characteristic.
|
|
5
|
+
*
|
|
3
6
|
* Presentational Children
|
|
4
7
|
*
|
|
5
8
|
* @see https://www.w3.org/TR/wai-aria/#childrenArePresentational
|
|
@@ -21,9 +24,12 @@ import { getComputedRole } from '@markuplint/ml-spec';
|
|
|
21
24
|
*
|
|
22
25
|
* @see https://w3c.github.io/aria/#tree_inclusion
|
|
23
26
|
*
|
|
24
|
-
*
|
|
27
|
+
* > Text equivalents for hidden referenced objects
|
|
25
28
|
* > may still be used in the name and description computation
|
|
26
29
|
* > even when not included in the accessibility tree.
|
|
30
|
+
*
|
|
31
|
+
* @param el - The element node to inspect for presentational ancestor context.
|
|
32
|
+
* @returns A violation if the element has ARIA attributes and an ancestor with presentational children.
|
|
27
33
|
*/
|
|
28
34
|
export const checkingPresentationalChildren = ({ el }) => t => {
|
|
29
35
|
const ancestor = getAncestorHasPresentationalChildren(el);
|
|
@@ -42,12 +48,20 @@ export const checkingPresentationalChildren = ({ el }) => t => {
|
|
|
42
48
|
message: t('it may be ineffective because {0}', t("it has {0} as an ancestor that doesn't expose its descendants to the accessibility tree", t('the "{0*}" {1}', ancestor.role.name, 'role'))),
|
|
43
49
|
};
|
|
44
50
|
};
|
|
51
|
+
/**
|
|
52
|
+
* Traverses the element's ancestor chain to find one whose computed role
|
|
53
|
+
* has the `childrenArePresentational` characteristic.
|
|
54
|
+
*
|
|
55
|
+
* @param el - The element to start searching from (exclusive, starts from parent).
|
|
56
|
+
* @returns The computed role of the ancestor with presentational children, or `null` if none found.
|
|
57
|
+
*/
|
|
45
58
|
function getAncestorHasPresentationalChildren(
|
|
46
59
|
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
47
60
|
el) {
|
|
61
|
+
const ariaVersion = el.rule.options?.version ?? el.ownerMLDocument.ruleCommonSettings?.ariaVersion ?? ARIA_RECOMMENDED_VERSION;
|
|
48
62
|
let current = el.parentElement;
|
|
49
63
|
while (current) {
|
|
50
|
-
const computed = getComputedRole(el.ownerMLDocument.specs, current,
|
|
64
|
+
const computed = getComputedRole(el.ownerMLDocument.specs, current, ariaVersion);
|
|
51
65
|
if (computed.role?.childrenPresentational) {
|
|
52
66
|
return computed;
|
|
53
67
|
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { Options } from '../types.js';
|
|
2
|
+
import type { ElementChecker } from '@markuplint/ml-core';
|
|
3
|
+
import type { ComputedRole } from '@markuplint/ml-spec';
|
|
4
|
+
/**
|
|
5
|
+
* Checks whether an element with an explicit role satisfies its
|
|
6
|
+
* "Required Accessibility Parent Role" (called "Required Context Role" in ARIA 1.2).
|
|
7
|
+
*
|
|
8
|
+
* When `getComputedRole()` detects that the parent hierarchy does not include
|
|
9
|
+
* one of the required context roles, it sets `errorType` to
|
|
10
|
+
* `'INVALID_REQUIRED_CONTEXT_ROLE'` (mismatch) or `'NO_OWNER'`
|
|
11
|
+
* (no non-transparent ancestor found) and resets `role` to `null`.
|
|
12
|
+
* This checker translates either result into a user-facing violation.
|
|
13
|
+
*
|
|
14
|
+
* Only explicit roles (set via the `role` attribute) are checked;
|
|
15
|
+
* implicit roles are skipped because native HTML parent-child semantics
|
|
16
|
+
* are already guaranteed by the HTML specification.
|
|
17
|
+
*
|
|
18
|
+
* @see https://w3c.github.io/aria/#scope
|
|
19
|
+
* @param el - The element to inspect.
|
|
20
|
+
* @param computed - The computed role result from `getComputedRole()`.
|
|
21
|
+
* @returns A violation if the role's required context is not satisfied.
|
|
22
|
+
*/
|
|
23
|
+
export declare const checkingRequiredAccessibilityParentRole: ElementChecker<boolean, Options, {
|
|
24
|
+
computed?: ComputedRole;
|
|
25
|
+
}>;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { ARIA_RECOMMENDED_VERSION, ariaSpecs } from '@markuplint/ml-spec';
|
|
2
|
+
/**
|
|
3
|
+
* Checks whether an element with an explicit role satisfies its
|
|
4
|
+
* "Required Accessibility Parent Role" (called "Required Context Role" in ARIA 1.2).
|
|
5
|
+
*
|
|
6
|
+
* When `getComputedRole()` detects that the parent hierarchy does not include
|
|
7
|
+
* one of the required context roles, it sets `errorType` to
|
|
8
|
+
* `'INVALID_REQUIRED_CONTEXT_ROLE'` (mismatch) or `'NO_OWNER'`
|
|
9
|
+
* (no non-transparent ancestor found) and resets `role` to `null`.
|
|
10
|
+
* This checker translates either result into a user-facing violation.
|
|
11
|
+
*
|
|
12
|
+
* Only explicit roles (set via the `role` attribute) are checked;
|
|
13
|
+
* implicit roles are skipped because native HTML parent-child semantics
|
|
14
|
+
* are already guaranteed by the HTML specification.
|
|
15
|
+
*
|
|
16
|
+
* @see https://w3c.github.io/aria/#scope
|
|
17
|
+
* @param el - The element to inspect.
|
|
18
|
+
* @param computed - The computed role result from `getComputedRole()`.
|
|
19
|
+
* @returns A violation if the role's required context is not satisfied.
|
|
20
|
+
*/
|
|
21
|
+
export const checkingRequiredAccessibilityParentRole = ({ el, computed }) => t => {
|
|
22
|
+
if (!computed ||
|
|
23
|
+
(computed.errorType !== 'INVALID_REQUIRED_CONTEXT_ROLE' &&
|
|
24
|
+
// NO_OWNER with role: null means all ancestors were transparent
|
|
25
|
+
// and no valid context could be found. NO_OWNER with role kept
|
|
26
|
+
// (parentElement === null) is a root fragment — skip.
|
|
27
|
+
!(computed.errorType === 'NO_OWNER' && !computed.role))) {
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
const roleAttr = el.getAttributeNode('role');
|
|
31
|
+
if (!roleAttr) {
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
const ariaVersion = el.rule.options?.version ?? el.ownerMLDocument.ruleCommonSettings?.ariaVersion ?? ARIA_RECOMMENDED_VERSION;
|
|
35
|
+
const { roles } = ariaSpecs(el.ownerMLDocument.specs, ariaVersion);
|
|
36
|
+
for (const token of roleAttr.tokenList?.allTokens() ?? []) {
|
|
37
|
+
const roleSpec = roles.find(r => r.name === token.raw);
|
|
38
|
+
if (!roleSpec) {
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
// `ariaSpecs().roles` returns raw spec data where the field is always
|
|
42
|
+
// `requiredContextRole` for all versions. The fallback to
|
|
43
|
+
// `requiredAccessibilityParentRole` is a defensive guard in case
|
|
44
|
+
// the spec-generator changes the field name in the future.
|
|
45
|
+
const parentRoles = roleSpec.requiredContextRole ?? roleSpec.requiredAccessibilityParentRole;
|
|
46
|
+
if (parentRoles && parentRoles.length > 0) {
|
|
47
|
+
return {
|
|
48
|
+
scope: token,
|
|
49
|
+
message: t('{0} requires {1}', t('the "{0*}" {1}', roleSpec.name, 'role'), parentRoles.length === 1 && parentRoles[0]
|
|
50
|
+
? t('an accessibility parent with the "{0*}" {1}', parentRoles[0], 'role')
|
|
51
|
+
: t('an accessibility parent with one of the {0}', 'roles') +
|
|
52
|
+
`: ${t(parentRoles)}`),
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
};
|
|
@@ -2,9 +2,18 @@ import type { Options } from '../types.js';
|
|
|
2
2
|
import type { ElementChecker } from '@markuplint/ml-core';
|
|
3
3
|
import type { ARIARole } from '@markuplint/ml-spec';
|
|
4
4
|
/**
|
|
5
|
-
*
|
|
5
|
+
* Checks whether an element with a role that has "Allowed Accessibility Child Roles"
|
|
6
|
+
* (called "Required Owned Elements" in ARIA 1.2) actually contains children
|
|
7
|
+
* with the expected roles.
|
|
8
|
+
*
|
|
9
|
+
* For example, a `list` role must own at least one element with the `listitem` role.
|
|
10
|
+
* This checker respects `aria-busy="true"` (which signals that content is still loading),
|
|
11
|
+
* preprocessor blocks, and mutable children from template engines.
|
|
6
12
|
*
|
|
7
13
|
* @see https://w3c.github.io/aria/#mustContain
|
|
14
|
+
* @param el - The element node to inspect for allowed accessibility child roles.
|
|
15
|
+
* @param role - The computed ARIA role of the element, which defines allowed accessibility child roles.
|
|
16
|
+
* @returns A violation if the role requires owned elements and none are found.
|
|
8
17
|
*/
|
|
9
18
|
export declare const checkingRequiredOwnedElements: ElementChecker<boolean, Options, {
|
|
10
19
|
role?: ARIARole | null;
|