@markuplint/ml-spec 5.0.0-rc.2 → 5.0.0-rc.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/README.md +0 -8
  3. package/lib/algorithm/aria/accname/aria-steps.d.ts +0 -24
  4. package/lib/algorithm/aria/accname/aria-steps.js +0 -24
  5. package/lib/algorithm/aria/accname/compute.d.ts +0 -10
  6. package/lib/algorithm/aria/accname/compute.js +0 -10
  7. package/lib/algorithm/aria/accname/element-names.d.ts +0 -23
  8. package/lib/algorithm/aria/accname/element-names.js +0 -23
  9. package/lib/algorithm/aria/accname/helpers.d.ts +2 -64
  10. package/lib/algorithm/aria/accname/helpers.js +2 -72
  11. package/lib/algorithm/aria/accname/label-steps.d.ts +2 -18
  12. package/lib/algorithm/aria/accname/label-steps.js +5 -21
  13. package/lib/algorithm/aria/accname/types.d.ts +0 -3
  14. package/lib/algorithm/aria/get-explicit-role.d.ts +1 -8
  15. package/lib/algorithm/aria/get-explicit-role.js +1 -8
  16. package/lib/algorithm/aria/get-non-presentational-ancestor.d.ts +2 -10
  17. package/lib/algorithm/aria/get-non-presentational-ancestor.js +2 -10
  18. package/lib/algorithm/aria/get-permitted-roles-spec.js +1 -0
  19. package/lib/algorithm/aria/matches-context-role.d.ts +3 -10
  20. package/lib/algorithm/aria/matches-context-role.js +3 -10
  21. package/lib/algorithm/html/content-model-category-to-tag-names.d.ts +5 -0
  22. package/lib/algorithm/html/content-model-category-to-tag-names.js +5 -0
  23. package/lib/index.d.ts +28 -0
  24. package/lib/index.js +28 -0
  25. package/lib/types/index.d.ts +35 -4
  26. package/lib/utils/schema-to-spec.d.ts +10 -0
  27. package/lib/utils/schema-to-spec.js +10 -0
  28. package/package.json +7 -7
  29. package/ARCHITECTURE.ja.md +0 -267
  30. package/ARCHITECTURE.md +0 -267
  31. package/SKILL.md +0 -116
  32. package/docs/aria-algorithms.ja.md +0 -802
  33. package/docs/aria-algorithms.md +0 -804
  34. package/docs/html-algorithms.ja.md +0 -469
  35. package/docs/html-algorithms.md +0 -469
  36. package/docs/maintenance.ja.md +0 -359
  37. package/docs/maintenance.md +0 -359
  38. package/docs/spec-resolution.ja.md +0 -575
  39. package/docs/spec-resolution.md +0 -588
  40. package/docs/type-definitions.ja.md +0 -584
  41. package/docs/type-definitions.md +0 -584
package/CHANGELOG.md CHANGED
@@ -3,6 +3,24 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ # [5.0.0-rc.5](https://github.com/markuplint/markuplint/compare/v5.0.0-rc.4...v5.0.0-rc.5) (2026-08-28)
7
+
8
+ ### Bug Fixes
9
+
10
+ - **html-spec:** div in dl allows exactly one dt+dd group per HTML LS ([6f344bb](https://github.com/markuplint/markuplint/commit/6f344bbc72bc82dbe2d1ebf05600a5fce9838de1))
11
+
12
+ ### Features
13
+
14
+ - **ml-spec:** add requiredCondition field to ARIARoleOwnedProperties ([6867215](https://github.com/markuplint/markuplint/commit/686721537b3d9b141dac12666a2796635d320151)), closes [#3682](https://github.com/markuplint/markuplint/issues/3682)
15
+
16
+ # [5.0.0-rc.4](https://github.com/markuplint/markuplint/compare/v5.0.0-rc.3...v5.0.0-rc.4) (2026-04-19)
17
+
18
+ **Note:** Version bump only for package @markuplint/ml-spec
19
+
20
+ # [5.0.0-rc.3](https://github.com/markuplint/markuplint/compare/v5.0.0-rc.2...v5.0.0-rc.3) (2026-04-19)
21
+
22
+ **Note:** Version bump only for package @markuplint/ml-spec
23
+
6
24
  # [5.0.0-rc.2](https://github.com/markuplint/markuplint/compare/v5.0.0-rc.1...v5.0.0-rc.2) (2026-04-15)
7
25
 
8
26
  ### Bug Fixes
package/README.md CHANGED
@@ -126,14 +126,6 @@ yarn add @markuplint/ml-spec
126
126
  - "HTML Schema" and "Specs" are used interchangeably in markuplint to mean the JSON Schema that
127
127
  describes HTML element specs (attributes, ARIA, content models, etc) and their TypeScript types.
128
128
 
129
- ### Contributing
130
-
131
- For schema editing workflows, generation commands, common recipes, dependency management, and troubleshooting, see the [Maintenance Guide](docs/maintenance.md).
132
-
133
- For schema merging and spec extension details, see [Spec Resolution](docs/spec-resolution.md).
134
-
135
- For content model categories and pattern format, see [HTML Algorithms](docs/html-algorithms.md).
136
-
137
129
  ### License
138
130
 
139
131
  MIT
@@ -1,25 +1,10 @@
1
1
  import type { AccnameElement, AccnameResolver, AccnameResult } from './types.js';
2
2
  /**
3
- * Resolves accessible name via `aria-labelledby` attribute.
4
- *
5
3
  * Implements AccName 1.2 §4.3.2 Step 2B:
6
4
  * "If the current node has an `aria-labelledby` attribute that contains
7
5
  * at least one valid IDREF, and the current node is not already part of
8
6
  * an ongoing `aria-labelledby` traversal, process its IDREFs [...]"
9
7
  *
10
- * Control flow:
11
- * 1. Read `aria-labelledby` attribute; return null if absent or empty.
12
- * 2. Split the attribute value by whitespace into IDREF tokens.
13
- * 3. Mark the current element's ID as visited (cycle prevention for A→B→A).
14
- * 4. For each IDREF:
15
- * a. Skip if already visited — **except** self-references (see below).
16
- * b. Resolve the referenced element via `resolver.getElementById`.
17
- * c. Recursively compute the referenced element's name with
18
- * `inLabelledbyTraversal=true` (prevents Step 2B re-entry in `compute.ts`).
19
- * d. Each IDREF branch gets its own copy of the visited set so that
20
- * one branch's traversal does not block later branches.
21
- * 5. Join all resolved parts with a space separator and flatten whitespace.
22
- *
23
8
  * **Self-reference handling** (spec-defined, not a custom extension):
24
9
  * An element may reference its own ID in `aria-labelledby` to include its
25
10
  * own content alongside other referenced elements. This is explicitly
@@ -29,23 +14,14 @@ import type { AccnameElement, AccnameResolver, AccnameResult } from './types.js'
29
14
  * visited set — `computeFn` is called with `inLabelledbyTraversal=true`,
30
15
  * which causes `compute.ts` to skip Step 2B on the referenced element.
31
16
  *
32
- * @param el - The element with a potential aria-labelledby attribute
33
- * @param resolver - Environment-dependent resolver for element lookups
34
- * @param visited - Set of element IDs already visited (cycle prevention)
35
- * @param computeFn - The recursive accessible name computation function
36
- * @returns The resolved name result, or null if aria-labelledby is not present or yields no name
37
17
  * @see https://www.w3.org/TR/accname-1.2/#comp_labelledby_traversal — AccName 1.2 §4.3.2 Step 2B
38
18
  */
39
19
  export declare function resolveAriaLabelledby(el: AccnameElement, resolver: AccnameResolver, visited: ReadonlySet<string>, computeFn: (el: AccnameElement, resolver: AccnameResolver, inLabelledbyTraversal: boolean, visited: ReadonlySet<string>) => AccnameResult): AccnameResult | null;
40
20
  /**
41
- * Resolves accessible name via `aria-label` attribute.
42
- *
43
21
  * Implements AccName 1.2 §4.3.2 Step 2D:
44
22
  * "If the current node has an `aria-label` attribute whose value is
45
23
  * not undefined, not the empty string, and not a string of whitespace [...]"
46
24
  *
47
- * @param el - The element with a potential aria-label attribute
48
- * @returns The resolved name result, or null if aria-label is not present or empty
49
25
  * @see https://www.w3.org/TR/accname-1.2/#computation-steps — AccName 1.2 §4.3.2 Step 2D
50
26
  */
51
27
  export declare function resolveAriaLabel(el: AccnameElement): AccnameResult | null;
@@ -1,26 +1,11 @@
1
1
  /* eslint-disable @typescript-eslint/prefer-readonly-parameter-types -- AccnameElement wraps mutable DOM types */
2
2
  import { flattenText, makeResult } from './helpers.js';
3
3
  /**
4
- * Resolves accessible name via `aria-labelledby` attribute.
5
- *
6
4
  * Implements AccName 1.2 §4.3.2 Step 2B:
7
5
  * "If the current node has an `aria-labelledby` attribute that contains
8
6
  * at least one valid IDREF, and the current node is not already part of
9
7
  * an ongoing `aria-labelledby` traversal, process its IDREFs [...]"
10
8
  *
11
- * Control flow:
12
- * 1. Read `aria-labelledby` attribute; return null if absent or empty.
13
- * 2. Split the attribute value by whitespace into IDREF tokens.
14
- * 3. Mark the current element's ID as visited (cycle prevention for A→B→A).
15
- * 4. For each IDREF:
16
- * a. Skip if already visited — **except** self-references (see below).
17
- * b. Resolve the referenced element via `resolver.getElementById`.
18
- * c. Recursively compute the referenced element's name with
19
- * `inLabelledbyTraversal=true` (prevents Step 2B re-entry in `compute.ts`).
20
- * d. Each IDREF branch gets its own copy of the visited set so that
21
- * one branch's traversal does not block later branches.
22
- * 5. Join all resolved parts with a space separator and flatten whitespace.
23
- *
24
9
  * **Self-reference handling** (spec-defined, not a custom extension):
25
10
  * An element may reference its own ID in `aria-labelledby` to include its
26
11
  * own content alongside other referenced elements. This is explicitly
@@ -30,11 +15,6 @@ import { flattenText, makeResult } from './helpers.js';
30
15
  * visited set — `computeFn` is called with `inLabelledbyTraversal=true`,
31
16
  * which causes `compute.ts` to skip Step 2B on the referenced element.
32
17
  *
33
- * @param el - The element with a potential aria-labelledby attribute
34
- * @param resolver - Environment-dependent resolver for element lookups
35
- * @param visited - Set of element IDs already visited (cycle prevention)
36
- * @param computeFn - The recursive accessible name computation function
37
- * @returns The resolved name result, or null if aria-labelledby is not present or yields no name
38
18
  * @see https://www.w3.org/TR/accname-1.2/#comp_labelledby_traversal — AccName 1.2 §4.3.2 Step 2B
39
19
  */
40
20
  export function resolveAriaLabelledby(el, resolver, visited, computeFn) {
@@ -84,14 +64,10 @@ export function resolveAriaLabelledby(el, resolver, visited, computeFn) {
84
64
  return null;
85
65
  }
86
66
  /**
87
- * Resolves accessible name via `aria-label` attribute.
88
- *
89
67
  * Implements AccName 1.2 §4.3.2 Step 2D:
90
68
  * "If the current node has an `aria-label` attribute whose value is
91
69
  * not undefined, not the empty string, and not a string of whitespace [...]"
92
70
  *
93
- * @param el - The element with a potential aria-label attribute
94
- * @returns The resolved name result, or null if aria-label is not present or empty
95
71
  * @see https://www.w3.org/TR/accname-1.2/#computation-steps — AccName 1.2 §4.3.2 Step 2D
96
72
  */
97
73
  export function resolveAriaLabel(el) {
@@ -33,19 +33,9 @@ import type { AccnameElement, AccnameResolver, AccnameResult } from './types.js'
33
33
  */
34
34
  export declare function computeAccessibleName(el: AccnameElement, resolver: AccnameResolver): AccnameResult;
35
35
  /**
36
- * Internal recursive entry point for accessible name computation.
37
- *
38
- * This function is the recursive core called by `resolveAriaLabelledby` (Step 2B),
39
- * `resolveLabelText` (Step 2E), and `resolveNameFromContent` (Step 2F) when they
40
- * need to compute a child or referenced element's name.
41
- *
42
- * @param el - The element to compute the accessible name for
43
- * @param resolver - Environment-dependent resolver for DOM traversal and role queries
44
36
  * @param inLabelledbyTraversal - When true, Step 2B is skipped to prevent re-entry
45
37
  * into `resolveAriaLabelledby`, and Step 2F name-from-content is enabled regardless
46
38
  * of role. This is set by Step 2B when processing each IDREF.
47
- * @param visited - Set of element IDs already visited (cycle prevention for aria-labelledby)
48
- * @returns The computed name and its source
49
39
  * @see https://www.w3.org/TR/accname-1.2/#computation-steps — AccName 1.2 §4.3.2
50
40
  */
51
41
  export declare function computeAccessibleNameInternal(el: AccnameElement, resolver: AccnameResolver, inLabelledbyTraversal: boolean, visited: ReadonlySet<string>): AccnameResult;
@@ -39,19 +39,9 @@ export function computeAccessibleName(el, resolver) {
39
39
  return computeAccessibleNameInternal(el, resolver, false, new Set());
40
40
  }
41
41
  /**
42
- * Internal recursive entry point for accessible name computation.
43
- *
44
- * This function is the recursive core called by `resolveAriaLabelledby` (Step 2B),
45
- * `resolveLabelText` (Step 2E), and `resolveNameFromContent` (Step 2F) when they
46
- * need to compute a child or referenced element's name.
47
- *
48
- * @param el - The element to compute the accessible name for
49
- * @param resolver - Environment-dependent resolver for DOM traversal and role queries
50
42
  * @param inLabelledbyTraversal - When true, Step 2B is skipped to prevent re-entry
51
43
  * into `resolveAriaLabelledby`, and Step 2F name-from-content is enabled regardless
52
44
  * of role. This is set by Step 2B when processing each IDREF.
53
- * @param visited - Set of element IDs already visited (cycle prevention for aria-labelledby)
54
- * @returns The computed name and its source
55
45
  * @see https://www.w3.org/TR/accname-1.2/#computation-steps — AccName 1.2 §4.3.2
56
46
  */
57
47
  export function computeAccessibleNameInternal(el, resolver, inLabelledbyTraversal, visited) {
@@ -1,7 +1,5 @@
1
1
  import type { AccnameElement, AccnameResolver, AccnameResult } from './types.js';
2
2
  /**
3
- * Computes element-specific accessible name per HTML-AAM §4.1.
4
- *
5
3
  * Implements AccName 1.2 §4.3.2 Step 2E: for elements that have a native
6
4
  * host language text alternative, use that alternative. The specific rules
7
5
  * for each HTML element are defined in HTML-AAM §4.1.
@@ -9,27 +7,6 @@ import type { AccnameElement, AccnameResolver, AccnameResult } from './types.js'
9
7
  * Returns null if no element-specific rule applies, letting the caller
10
8
  * fall through to name-from-content (Step 2F) or title fallback (Step 2I).
11
9
  *
12
- * Control flow (dispatches by `localName`):
13
- * - SVG elements → `handleSvgElement` (SVG-AAM: `<title>` child)
14
- * - `<input>` → `handleInput` (branches by type: text-like, button, image, hidden)
15
- * - `<textarea>`, `<select>`, `<meter>`, `<progress>`, `<output>` → `handleLabelableWithTitle`
16
- * - `<button>` → `handleButton` (label → content → title)
17
- * - `<fieldset>` → `handleFieldset` (legend → title)
18
- * - `<table>` → `handleTable` (caption → title)
19
- * - `<img>` → `handleImg` (alt → title)
20
- * - `<area>` → `handleArea` (alt → title)
21
- * - `<figure>` → `handleFigure` (title only)
22
- * - `<summary>` → `handleSummary` (content → title)
23
- * - `<a href>` → `handleAnchor` (content → title)
24
- * - `<iframe>` → `handleTitleOnly` (title only)
25
- * - All others → null (rely on caller's generic Steps 2F/2I)
26
- *
27
- * @param el - The element to compute the name for
28
- * @param resolver - Environment-dependent resolver for DOM traversal and role queries
29
- * @param visited - Set of element IDs already visited (cycle prevention)
30
- * @param computeFn - The recursive accessible name computation function
31
- * @param inLabelledbyTraversal - Whether this computation is part of an aria-labelledby traversal
32
- * @returns The computed name result, or null if no element-specific rule applies
33
10
  * @see https://www.w3.org/TR/accname-1.2/#computation-steps — AccName 1.2 §4.3.2 Step 2E
34
11
  * @see https://www.w3.org/TR/html-aam-1.0/#accessible-name-and-description-computation — HTML-AAM §4.1
35
12
  */
@@ -3,8 +3,6 @@ import { DEFAULT_IMAGE_LABEL, DEFAULT_RESET_LABEL, DEFAULT_SUBMIT_LABEL, TEXT_IN
3
3
  import { findChildByLocalName, getInputType, isSvgElement, makeResult, resolveNameFromContent } from './helpers.js';
4
4
  import { resolveLabelText } from './label-steps.js';
5
5
  /**
6
- * Computes element-specific accessible name per HTML-AAM §4.1.
7
- *
8
6
  * Implements AccName 1.2 §4.3.2 Step 2E: for elements that have a native
9
7
  * host language text alternative, use that alternative. The specific rules
10
8
  * for each HTML element are defined in HTML-AAM §4.1.
@@ -12,27 +10,6 @@ import { resolveLabelText } from './label-steps.js';
12
10
  * Returns null if no element-specific rule applies, letting the caller
13
11
  * fall through to name-from-content (Step 2F) or title fallback (Step 2I).
14
12
  *
15
- * Control flow (dispatches by `localName`):
16
- * - SVG elements → `handleSvgElement` (SVG-AAM: `<title>` child)
17
- * - `<input>` → `handleInput` (branches by type: text-like, button, image, hidden)
18
- * - `<textarea>`, `<select>`, `<meter>`, `<progress>`, `<output>` → `handleLabelableWithTitle`
19
- * - `<button>` → `handleButton` (label → content → title)
20
- * - `<fieldset>` → `handleFieldset` (legend → title)
21
- * - `<table>` → `handleTable` (caption → title)
22
- * - `<img>` → `handleImg` (alt → title)
23
- * - `<area>` → `handleArea` (alt → title)
24
- * - `<figure>` → `handleFigure` (title only)
25
- * - `<summary>` → `handleSummary` (content → title)
26
- * - `<a href>` → `handleAnchor` (content → title)
27
- * - `<iframe>` → `handleTitleOnly` (title only)
28
- * - All others → null (rely on caller's generic Steps 2F/2I)
29
- *
30
- * @param el - The element to compute the name for
31
- * @param resolver - Environment-dependent resolver for DOM traversal and role queries
32
- * @param visited - Set of element IDs already visited (cycle prevention)
33
- * @param computeFn - The recursive accessible name computation function
34
- * @param inLabelledbyTraversal - Whether this computation is part of an aria-labelledby traversal
35
- * @returns The computed name result, or null if no element-specific rule applies
36
13
  * @see https://www.w3.org/TR/accname-1.2/#computation-steps — AccName 1.2 §4.3.2 Step 2E
37
14
  * @see https://www.w3.org/TR/html-aam-1.0/#accessible-name-and-description-computation — HTML-AAM §4.1
38
15
  */
@@ -1,40 +1,16 @@
1
1
  import type { AccnameElement, AccnameResolver, AccnameResult, AccnameSource } from './types.js';
2
2
  export { EMBEDDED_CONTROL_ROLES } from '../../../const/index.js';
3
- /**
4
- * Creates an AccnameResult with a trimmed, whitespace-collapsed name.
5
- *
6
- * @param name - The raw name string to normalize
7
- * @param source - The source that provided the name, or null if the name is empty
8
- * @returns A result with the collapsed name and its source (source is null when name is empty)
9
- */
10
3
  export declare function makeResult(name: string, source: AccnameSource | null): AccnameResult;
11
- /**
12
- * Collapses internal whitespace and trims a string.
13
- *
14
- * @param text - The string to normalize
15
- * @returns The string with collapsed whitespace and trimmed
16
- */
17
4
  export declare function flattenText(text: string): string;
18
5
  /**
19
- * Collects text content from child nodes recursively for name-from-content computation.
20
- *
21
6
  * Implements AccName 1.2 §4.3.2 Steps 2F and 2C:
22
7
  *
23
8
  * - **Step 2F**: "If the current node's role allows name from content [...],
24
9
  * return the accumulated text of the current node's descendant nodes."
25
10
  * - **Step 2C (Embedded Controls)**: "If the current node is a descendant of
26
11
  * an `aria-labelledby` or `aria-label` reference AND the current node is
27
- * an embedded control, return the embedded control's value."
28
- *
29
- * Control flow for each child node:
30
- * 1. **Text node** → contribute text directly.
31
- * 2. **Embedded control** (textbox, combobox, listbox, slider, spinbutton, searchbox)
32
- * → use value via `getEmbeddedControlValue`. Per spec, `aria-label` is ignored
33
- * for embedded controls during name-from-content traversal.
34
- * 3. **Other element** → first try its full accessible name (Steps 2B–2I via `computeFn`).
35
- * If no name, fall through to `collectTextContent` for transparent traversal.
36
- *
37
- * Parts are joined with a space separator per AccName 1.2 §4.3.2 Step 2C.
12
+ * an embedded control, return the embedded control's value." Per spec,
13
+ * `aria-label` is ignored for embedded controls during this traversal.
38
14
  *
39
15
  * **Limitation:** CSS-generated content (`::before`/`::after` with the `content`
40
16
  * property) is not included. AccName 1.2 §4.3.2 Step 2G specifies that CSS
@@ -42,52 +18,14 @@ export declare function flattenText(text: string): string;
42
18
  * performs static HTML analysis without CSS processing, so this content is
43
19
  * unavailable at lint time.
44
20
  *
45
- * @param el - The element whose child nodes to collect text from
46
- * @param resolver - Environment-dependent resolver for DOM traversal and role queries
47
- * @param visited - Set of element IDs already visited (cycle prevention)
48
- * @param computeFn - The recursive accessible name computation function
49
- * @param inLabelledbyTraversal - Whether this computation is part of an aria-labelledby traversal
50
- * @returns The concatenated text content from child nodes
51
21
  * @see https://www.w3.org/TR/accname-1.2/#computation-steps — AccName 1.2 §4.3.2 Step 2F
52
22
  * @see https://www.w3.org/TR/accname-1.2/#comp_embedded_control — AccName 1.2 §4.3.2 Step 2C
53
23
  */
54
24
  export declare function resolveNameFromContent(el: AccnameElement, resolver: AccnameResolver, visited: ReadonlySet<string>, computeFn: (el: AccnameElement, resolver: AccnameResolver, inLabelledbyTraversal: boolean, visited: ReadonlySet<string>) => AccnameResult, inLabelledbyTraversal: boolean): string;
55
- /**
56
- * Finds the first child element with a matching localName.
57
- *
58
- * @param el - The parent element to search within
59
- * @param localName - The local tag name to match
60
- * @returns The first matching child element, or null if none found
61
- */
62
25
  export declare function findChildByLocalName(el: AccnameElement, localName: string): AccnameElement | null;
63
- /**
64
- * Finds the nearest ancestor label element (implicit label association).
65
- *
66
- * @param el - The element to search from
67
- * @returns The nearest ancestor label element, or null if none found
68
- */
69
26
  export declare function findAncestorLabel(el: AccnameElement): AccnameElement | null;
70
- /**
71
- * Resolves a label for an element via explicit (for=id) or implicit (ancestor) association.
72
- *
73
- * @param el - The element to find labels for
74
- * @param resolver - Environment-dependent resolver for label lookups
75
- * @returns An array of label elements associated with the element
76
- */
77
27
  export declare function resolveLabel(el: AccnameElement, resolver: AccnameResolver): readonly AccnameElement[];
78
- /**
79
- * Gets the input type, defaulting to 'text' for inputs without a type attribute.
80
- *
81
- * @param el - The element to get the input type for
82
- * @returns The lowercase input type, or an empty string if not an input element
83
- */
84
28
  export declare function getInputType(el: AccnameElement): string;
85
- /**
86
- * Checks if an element is in the SVG namespace.
87
- *
88
- * @param el - The element to check
89
- * @returns True if the element is in the SVG namespace
90
- */
91
29
  export declare function isSvgElement(el: AccnameElement): boolean;
92
30
  /**
93
31
  * Escapes a string for safe use inside a CSS selector.
@@ -1,13 +1,6 @@
1
1
  /* eslint-disable @typescript-eslint/prefer-readonly-parameter-types -- AccnameElement wraps mutable DOM types */
2
2
  import { ELEMENT_NODE, SVG_NAMESPACE, TEXT_NODE, TEXT_LIKE_INPUT_TYPES } from '../../../const/index.js';
3
3
  export { EMBEDDED_CONTROL_ROLES } from '../../../const/index.js';
4
- /**
5
- * Creates an AccnameResult with a trimmed, whitespace-collapsed name.
6
- *
7
- * @param name - The raw name string to normalize
8
- * @param source - The source that provided the name, or null if the name is empty
9
- * @returns A result with the collapsed name and its source (source is null when name is empty)
10
- */
11
4
  export function makeResult(name, source) {
12
5
  const trimmed = flattenText(name);
13
6
  return {
@@ -15,35 +8,18 @@ export function makeResult(name, source) {
15
8
  source: trimmed ? source : null,
16
9
  };
17
10
  }
18
- /**
19
- * Collapses internal whitespace and trims a string.
20
- *
21
- * @param text - The string to normalize
22
- * @returns The string with collapsed whitespace and trimmed
23
- */
24
11
  export function flattenText(text) {
25
12
  return text.replaceAll(/\s+/g, ' ').trim();
26
13
  }
27
14
  /**
28
- * Collects text content from child nodes recursively for name-from-content computation.
29
- *
30
15
  * Implements AccName 1.2 §4.3.2 Steps 2F and 2C:
31
16
  *
32
17
  * - **Step 2F**: "If the current node's role allows name from content [...],
33
18
  * return the accumulated text of the current node's descendant nodes."
34
19
  * - **Step 2C (Embedded Controls)**: "If the current node is a descendant of
35
20
  * an `aria-labelledby` or `aria-label` reference AND the current node is
36
- * an embedded control, return the embedded control's value."
37
- *
38
- * Control flow for each child node:
39
- * 1. **Text node** → contribute text directly.
40
- * 2. **Embedded control** (textbox, combobox, listbox, slider, spinbutton, searchbox)
41
- * → use value via `getEmbeddedControlValue`. Per spec, `aria-label` is ignored
42
- * for embedded controls during name-from-content traversal.
43
- * 3. **Other element** → first try its full accessible name (Steps 2B–2I via `computeFn`).
44
- * If no name, fall through to `collectTextContent` for transparent traversal.
45
- *
46
- * Parts are joined with a space separator per AccName 1.2 §4.3.2 Step 2C.
21
+ * an embedded control, return the embedded control's value." Per spec,
22
+ * `aria-label` is ignored for embedded controls during this traversal.
47
23
  *
48
24
  * **Limitation:** CSS-generated content (`::before`/`::after` with the `content`
49
25
  * property) is not included. AccName 1.2 §4.3.2 Step 2G specifies that CSS
@@ -51,12 +27,6 @@ export function flattenText(text) {
51
27
  * performs static HTML analysis without CSS processing, so this content is
52
28
  * unavailable at lint time.
53
29
  *
54
- * @param el - The element whose child nodes to collect text from
55
- * @param resolver - Environment-dependent resolver for DOM traversal and role queries
56
- * @param visited - Set of element IDs already visited (cycle prevention)
57
- * @param computeFn - The recursive accessible name computation function
58
- * @param inLabelledbyTraversal - Whether this computation is part of an aria-labelledby traversal
59
- * @returns The concatenated text content from child nodes
60
30
  * @see https://www.w3.org/TR/accname-1.2/#computation-steps — AccName 1.2 §4.3.2 Step 2F
61
31
  * @see https://www.w3.org/TR/accname-1.2/#comp_embedded_control — AccName 1.2 §4.3.2 Step 2C
62
32
  */
@@ -131,8 +101,6 @@ function collectTextContent(el, resolver, visited, computeFn, inLabelledbyTraver
131
101
  return parts.join(' ');
132
102
  }
133
103
  /**
134
- * Gets the value of an embedded control for name-from-content computation.
135
- *
136
104
  * Implements AccName 1.2 §4.3.2 Step 2C embedded control value resolution:
137
105
  * - **Range controls** (slider/spinbutton/input[range]):
138
106
  * aria-valuetext → aria-valuenow → value attr → textContent
@@ -214,9 +182,6 @@ function getSelectedOptionText(el) {
214
182
  return first?.textContent?.trim() ?? '';
215
183
  }
216
184
  /**
217
- * Collects all `<option>` descendant elements from a `<select>`,
218
- * traversing through `<optgroup>` containers.
219
- *
220
185
  * **Note (#2069):** Customizable `<select>` allows non-option children
221
186
  * (e.g., `<button>`, `<datalist>`, `<div>`). This function currently only
222
187
  * recognizes `<option>` and `<optgroup>` — it will need updating when the
@@ -240,19 +205,9 @@ function collectOptions(el) {
240
205
  }
241
206
  return result;
242
207
  }
243
- /**
244
- * Checks if an input element is a text-like type (text, search, tel, url, email, etc.).
245
- */
246
208
  function isTextLikeInput(el) {
247
209
  return TEXT_LIKE_INPUT_TYPES.has(getInputType(el));
248
210
  }
249
- /**
250
- * Finds the first child element with a matching localName.
251
- *
252
- * @param el - The parent element to search within
253
- * @param localName - The local tag name to match
254
- * @returns The first matching child element, or null if none found
255
- */
256
211
  export function findChildByLocalName(el, localName) {
257
212
  for (const child of el.children) {
258
213
  if (child.localName === localName) {
@@ -261,12 +216,6 @@ export function findChildByLocalName(el, localName) {
261
216
  }
262
217
  return null;
263
218
  }
264
- /**
265
- * Finds the nearest ancestor label element (implicit label association).
266
- *
267
- * @param el - The element to search from
268
- * @returns The nearest ancestor label element, or null if none found
269
- */
270
219
  export function findAncestorLabel(el) {
271
220
  let current = el.parentElement;
272
221
  while (current) {
@@ -277,13 +226,6 @@ export function findAncestorLabel(el) {
277
226
  }
278
227
  return null;
279
228
  }
280
- /**
281
- * Resolves a label for an element via explicit (for=id) or implicit (ancestor) association.
282
- *
283
- * @param el - The element to find labels for
284
- * @param resolver - Environment-dependent resolver for label lookups
285
- * @returns An array of label elements associated with the element
286
- */
287
229
  export function resolveLabel(el, resolver) {
288
230
  const id = el.id;
289
231
  if (id) {
@@ -298,24 +240,12 @@ export function resolveLabel(el, resolver) {
298
240
  }
299
241
  return [];
300
242
  }
301
- /**
302
- * Gets the input type, defaulting to 'text' for inputs without a type attribute.
303
- *
304
- * @param el - The element to get the input type for
305
- * @returns The lowercase input type, or an empty string if not an input element
306
- */
307
243
  export function getInputType(el) {
308
244
  if (el.localName !== 'input') {
309
245
  return '';
310
246
  }
311
247
  return (el.getAttribute('type') ?? 'text').toLowerCase();
312
248
  }
313
- /**
314
- * Checks if an element is in the SVG namespace.
315
- *
316
- * @param el - The element to check
317
- * @returns True if the element is in the SVG namespace
318
- */
319
249
  export function isSvgElement(el) {
320
250
  return el.namespaceURI === SVG_NAMESPACE;
321
251
  }
@@ -1,24 +1,8 @@
1
1
  import type { AccnameElement, AccnameResolver, AccnameResult } from './types.js';
2
2
  /**
3
- * Resolves accessible name from `<label>` element association.
3
+ * Part of AccName 1.2 §4.3.2 Step 2E — for labelable elements, the HTML label
4
+ * association is checked before other element-specific rules.
4
5
  *
5
- * Part of AccName 1.2 §4.3.2 Step 2E — for labelable elements, checks
6
- * the HTML label association before other element-specific rules.
7
- *
8
- * Control flow:
9
- * 1. Find labels via `resolveLabel`: explicit `<label for="id">` first,
10
- * then implicit ancestor `<label>`.
11
- * 2. For each label, collect its text content via `collectLabelText`,
12
- * which walks the label's children but **excludes** the labeled
13
- * element itself (prevents circular inclusion).
14
- * 3. Join all label texts with a space separator and flatten whitespace.
15
- *
16
- * @param el - The labelable element to resolve label text for
17
- * @param resolver - Environment-dependent resolver for label lookups
18
- * @param visited - Set of element IDs already visited (cycle prevention)
19
- * @param computeFn - The recursive accessible name computation function
20
- * @param inLabelledbyTraversal - Whether this computation is part of an aria-labelledby traversal
21
- * @returns The resolved name result, or null if no label provides a name
22
6
  * @see https://www.w3.org/TR/accname-1.2/#computation-steps — AccName 1.2 §4.3.2 Step 2E
23
7
  * @see https://www.w3.org/TR/html-aam-1.0/#el-input-text — HTML-AAM label association
24
8
  */
@@ -2,25 +2,9 @@
2
2
  import { ELEMENT_NODE, TEXT_NODE } from '../../../const/index.js';
3
3
  import { flattenText, makeResult, resolveLabel } from './helpers.js';
4
4
  /**
5
- * Resolves accessible name from `<label>` element association.
5
+ * Part of AccName 1.2 §4.3.2 Step 2E — for labelable elements, the HTML label
6
+ * association is checked before other element-specific rules.
6
7
  *
7
- * Part of AccName 1.2 §4.3.2 Step 2E — for labelable elements, checks
8
- * the HTML label association before other element-specific rules.
9
- *
10
- * Control flow:
11
- * 1. Find labels via `resolveLabel`: explicit `<label for="id">` first,
12
- * then implicit ancestor `<label>`.
13
- * 2. For each label, collect its text content via `collectLabelText`,
14
- * which walks the label's children but **excludes** the labeled
15
- * element itself (prevents circular inclusion).
16
- * 3. Join all label texts with a space separator and flatten whitespace.
17
- *
18
- * @param el - The labelable element to resolve label text for
19
- * @param resolver - Environment-dependent resolver for label lookups
20
- * @param visited - Set of element IDs already visited (cycle prevention)
21
- * @param computeFn - The recursive accessible name computation function
22
- * @param inLabelledbyTraversal - Whether this computation is part of an aria-labelledby traversal
23
- * @returns The resolved name result, or null if no label provides a name
24
8
  * @see https://www.w3.org/TR/accname-1.2/#computation-steps — AccName 1.2 §4.3.2 Step 2E
25
9
  * @see https://www.w3.org/TR/html-aam-1.0/#el-input-text — HTML-AAM label association
26
10
  */
@@ -43,9 +27,9 @@ export function resolveLabelText(el, resolver, visited, computeFn, inLabelledbyT
43
27
  return null;
44
28
  }
45
29
  /**
46
- * Collects text from a label element, excluding the labeled element itself.
47
- * Parts are joined with a space separator, matching the AccName 1.2
48
- * concatenation behavior for label text.
30
+ * Excludes the labeled element itself to prevent circular inclusion. Parts are
31
+ * joined with a space separator, matching the AccName 1.2 concatenation
32
+ * behavior for label text.
49
33
  */
50
34
  function collectLabelText(label, labeledElement, resolver, visited, computeFn, inLabelledbyTraversal) {
51
35
  const parts = [];
@@ -61,9 +61,6 @@ export interface AccnameResult {
61
61
  readonly name: string;
62
62
  readonly source: AccnameSource | null;
63
63
  }
64
- /**
65
- * Internal options passed through recursive calls.
66
- */
67
64
  export interface AccnameOptions {
68
65
  readonly inLabelledbyTraversal?: boolean;
69
66
  readonly visited?: ReadonlySet<string>;
@@ -1,14 +1,7 @@
1
1
  import type { ARIAVersion, ComputedRole, MLMLSpec } from '../../types/index.js';
2
2
  /**
3
- * Resolves the ARIA role from the `role` attribute value, implementing the
4
- * WAI-ARIA "Handling Author Errors" algorithm. Iterates through whitespace-separated
5
- * role tokens and returns the first one that passes all validation checks
6
- * (exists, non-abstract, permitted, valid landmark).
3
+ * Implements the WAI-ARIA "Handling Author Errors" algorithm.
7
4
  *
8
5
  * @see https://w3c.github.io/aria/#document-handling_author-errors
9
- * @param specs - The full markup language specification
10
- * @param el - The DOM element to resolve the explicit role for
11
- * @param version - The ARIA specification version to use
12
- * @returns The first valid role found as a `ComputedRole`, or `role: null` with the last encountered error type
13
6
  */
14
7
  export declare function getExplicitRole(specs: MLMLSpec, el: Element, version: ARIAVersion): ComputedRole;
@@ -2,16 +2,9 @@ import { getRoleSpec } from './get-role-spec.js';
2
2
  import { resolveNamespace } from '../../utils/resolve-namespace.js';
3
3
  import { getPermittedRoles } from './get-permitted-roles.js';
4
4
  /**
5
- * Resolves the ARIA role from the `role` attribute value, implementing the
6
- * WAI-ARIA "Handling Author Errors" algorithm. Iterates through whitespace-separated
7
- * role tokens and returns the first one that passes all validation checks
8
- * (exists, non-abstract, permitted, valid landmark).
5
+ * Implements the WAI-ARIA "Handling Author Errors" algorithm.
9
6
  *
10
7
  * @see https://w3c.github.io/aria/#document-handling_author-errors
11
- * @param specs - The full markup language specification
12
- * @param el - The DOM element to resolve the explicit role for
13
- * @param version - The ARIA specification version to use
14
- * @returns The first valid role found as a `ComputedRole`, or `role: null` with the last encountered error type
15
8
  */
16
9
  export function getExplicitRole(specs,
17
10
  // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
@@ -1,15 +1,7 @@
1
1
  import type { ARIAVersion, MLMLSpec } from '../../types/index.js';
2
2
  /**
3
- * Traverses the parent element chain to find the nearest ancestor with a
4
- * non-presentational role, skipping elements that are transparent for
5
- * ownership traversal (via `isTransparentForOwnership`).
6
- *
7
- * In ARIA 1.3, `generic` role elements are additionally transparent.
8
- *
9
- * @param el - The DOM element whose ancestors to traverse
10
- * @param specs - The full markup language specification
11
- * @param version - The ARIA specification version to use
12
- * @returns The nearest non-presentational ancestor's `ComputedRole`, or `{ el: null, role: null }` if none exists
3
+ * In ARIA 1.3, `generic` role elements are additionally transparent for
4
+ * ownership traversal.
13
5
  */
14
6
  export declare function getNonPresentationalAncestor(el: Element, specs: MLMLSpec, version: ARIAVersion): import("../../types/index.js").ComputedRole | {
15
7
  el: null;