@markuplint/ml-spec 4.10.1 → 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.
Files changed (111) hide show
  1. package/ARCHITECTURE.ja.md +267 -0
  2. package/ARCHITECTURE.md +267 -0
  3. package/CHANGELOG.md +20 -2
  4. package/README.md +6 -188
  5. package/SKILL.md +116 -0
  6. package/docs/aria-algorithms.ja.md +798 -0
  7. package/docs/aria-algorithms.md +800 -0
  8. package/docs/html-algorithms.ja.md +469 -0
  9. package/docs/html-algorithms.md +469 -0
  10. package/docs/maintenance.ja.md +331 -0
  11. package/docs/maintenance.md +331 -0
  12. package/docs/spec-resolution.ja.md +568 -0
  13. package/docs/spec-resolution.md +580 -0
  14. package/docs/type-definitions.ja.md +565 -0
  15. package/docs/type-definitions.md +565 -0
  16. package/lib/algorithm/aria/accname/__tests__/test-helpers.d.ts +45 -0
  17. package/lib/algorithm/aria/accname/__tests__/test-helpers.js +120 -0
  18. package/lib/algorithm/aria/accname/aria-steps.d.ts +51 -0
  19. package/lib/algorithm/aria/accname/aria-steps.js +104 -0
  20. package/lib/algorithm/aria/accname/compute.d.ts +51 -0
  21. package/lib/algorithm/aria/accname/compute.js +101 -0
  22. package/lib/algorithm/aria/accname/element-names.d.ts +36 -0
  23. package/lib/algorithm/aria/accname/element-names.js +342 -0
  24. package/lib/algorithm/aria/accname/helpers.d.ts +98 -0
  25. package/lib/algorithm/aria/accname/helpers.js +330 -0
  26. package/lib/algorithm/aria/accname/index.d.ts +4 -0
  27. package/lib/algorithm/aria/accname/index.js +3 -0
  28. package/lib/algorithm/aria/accname/label-steps.d.ts +25 -0
  29. package/lib/algorithm/aria/accname/label-steps.js +66 -0
  30. package/lib/algorithm/aria/accname/svg-helpers.d.ts +17 -0
  31. package/lib/algorithm/aria/accname/svg-helpers.js +30 -0
  32. package/lib/algorithm/aria/accname/types.d.ts +70 -0
  33. package/lib/algorithm/aria/accname/types.js +2 -0
  34. package/lib/algorithm/aria/accname-computation.d.ts +19 -1
  35. package/lib/algorithm/aria/accname-computation.js +136 -6
  36. package/lib/algorithm/aria/aria-specs.d.ts +8 -0
  37. package/lib/algorithm/aria/aria-specs.js +7 -0
  38. package/lib/algorithm/aria/get-aria.d.ts +12 -0
  39. package/lib/algorithm/aria/get-aria.js +42 -4
  40. package/lib/algorithm/aria/get-computed-aria-props.d.ts +22 -0
  41. package/lib/algorithm/aria/get-computed-aria-props.js +10 -0
  42. package/lib/algorithm/aria/get-computed-role.d.ts +12 -0
  43. package/lib/algorithm/aria/get-computed-role.js +118 -26
  44. package/lib/algorithm/aria/get-explicit-role.d.ts +12 -0
  45. package/lib/algorithm/aria/get-explicit-role.js +12 -0
  46. package/lib/algorithm/aria/get-implicit-role.d.ts +18 -0
  47. package/lib/algorithm/aria/get-implicit-role.js +18 -0
  48. package/lib/algorithm/aria/get-non-presentational-ancestor.d.ts +12 -0
  49. package/lib/algorithm/aria/get-non-presentational-ancestor.js +14 -2
  50. package/lib/algorithm/aria/get-permitted-roles-spec.d.ts +8 -4
  51. package/lib/algorithm/aria/get-permitted-roles-spec.js +19 -6
  52. package/lib/algorithm/aria/get-permitted-roles.d.ts +9 -0
  53. package/lib/algorithm/aria/get-permitted-roles.js +9 -0
  54. package/lib/algorithm/aria/get-role-spec.d.ts +11 -0
  55. package/lib/algorithm/aria/get-role-spec.js +21 -3
  56. package/lib/algorithm/aria/has-required-owned-elements.d.ts +24 -0
  57. package/lib/algorithm/aria/has-required-owned-elements.js +40 -14
  58. package/lib/algorithm/aria/is-exposed.d.ts +7 -4
  59. package/lib/algorithm/aria/is-exposed.js +7 -4
  60. package/lib/algorithm/aria/is-presentational.d.ts +32 -0
  61. package/lib/algorithm/aria/is-presentational.js +39 -0
  62. package/lib/algorithm/aria/matches-context-role.d.ts +19 -0
  63. package/lib/algorithm/aria/matches-context-role.js +46 -2
  64. package/lib/algorithm/html/content-model-category-to-tag-names.d.ts +9 -0
  65. package/lib/algorithm/html/content-model-category-to-tag-names.js +10 -1
  66. package/lib/algorithm/html/get-content-model.d.ts +12 -1
  67. package/lib/algorithm/html/get-content-model.js +14 -6
  68. package/lib/algorithm/html/get-selectors-by-content-model-category.d.ts +8 -0
  69. package/lib/algorithm/html/get-selectors-by-content-model-category.js +8 -0
  70. package/lib/algorithm/html/is-nothing-content-model.d.ts +7 -0
  71. package/lib/algorithm/html/is-nothing-content-model.js +7 -0
  72. package/lib/algorithm/html/is-palpable-elements.d.ts +13 -0
  73. package/lib/algorithm/html/is-palpable-elements.js +13 -0
  74. package/lib/algorithm/html/is-void-element.d.ts +9 -0
  75. package/lib/algorithm/html/is-void-element.js +9 -0
  76. package/lib/algorithm/html/may-be-focusable.d.ts +10 -0
  77. package/lib/algorithm/html/may-be-focusable.js +10 -0
  78. package/lib/const/accname.d.ts +29 -0
  79. package/lib/const/accname.js +76 -0
  80. package/lib/const/dom.d.ts +8 -0
  81. package/lib/const/dom.js +8 -0
  82. package/lib/const/index.d.ts +2 -0
  83. package/lib/const/index.js +2 -0
  84. package/lib/index.d.ts +3 -0
  85. package/lib/index.js +4 -0
  86. package/lib/types/index.d.ts +119 -0
  87. package/lib/utils/aria-version.d.ts +6 -0
  88. package/lib/utils/aria-version.js +6 -0
  89. package/lib/utils/directive-resolver.d.ts +23 -0
  90. package/lib/utils/directive-resolver.js +50 -0
  91. package/lib/utils/get-attr-specs-spec.d.ts +18 -0
  92. package/lib/utils/get-attr-specs-spec.js +22 -3
  93. package/lib/utils/get-attr-specs.d.ts +9 -0
  94. package/lib/utils/get-attr-specs.js +9 -0
  95. package/lib/utils/get-ns.d.ts +7 -0
  96. package/lib/utils/get-ns.js +7 -0
  97. package/lib/utils/get-spec-by-tag-name.d.ts +12 -1
  98. package/lib/utils/get-spec-by-tag-name.js +11 -0
  99. package/lib/utils/get-spec.d.ts +11 -1
  100. package/lib/utils/get-spec.js +10 -0
  101. package/lib/utils/merge-array.d.ts +10 -0
  102. package/lib/utils/merge-array.js +10 -0
  103. package/lib/utils/resolve-namespace.d.ts +13 -0
  104. package/lib/utils/resolve-namespace.js +10 -0
  105. package/lib/utils/resolve-version.d.ts +11 -0
  106. package/lib/utils/resolve-version.js +11 -0
  107. package/lib/utils/schema-to-spec.d.ts +7 -2
  108. package/lib/utils/schema-to-spec.js +20 -6
  109. package/lib/utils/validate-aria-version.d.ts +7 -0
  110. package/lib/utils/validate-aria-version.js +7 -0
  111. package/package.json +9 -7
@@ -0,0 +1,565 @@
1
+ # Type Definitions Reference
2
+
3
+ This document describes the type definitions and JSON schemas used by `@markuplint/ml-spec`.
4
+
5
+ ## Overview
6
+
7
+ `@markuplint/ml-spec` employs a two-layer type system:
8
+
9
+ 1. **Hand-written types** in `src/types/index.ts` -- define the runtime interfaces used throughout markuplint for element specs, ARIA roles, attributes, and role computation results.
10
+ 2. **Generated types** from JSON schemas -- define schema-validated structures that are auto-generated from `.schema.json` files using `json-schema-to-typescript`. These files carry "DO NOT MODIFY" headers.
11
+
12
+ Hand-written types import and extend generated types where needed (for example, `Attribute` extends `AttributeJSON`), creating a clean separation between the schema-validated data layer and the runtime API layer.
13
+
14
+ ## Core Specification Types
15
+
16
+ These types are defined in `src/types/index.ts` and form the backbone of markuplint's spec system.
17
+
18
+ ### `MLMLSpec`
19
+
20
+ The root specification type representing a complete markup language spec.
21
+
22
+ ```ts
23
+ interface MLMLSpec {
24
+ readonly cites: Cites; // Reference URLs (readonly string[])
25
+ readonly def: SpecDefs; // Internal definitions (global attrs, ARIA, content models)
26
+ readonly specs: readonly ElementSpec[]; // Element specifications array
27
+ }
28
+ ```
29
+
30
+ ### `ExtendedSpec`
31
+
32
+ A partial specification used by framework-specific packages to extend or customize the base spec. Used by `@markuplint/vue-spec`, `@markuplint/react-spec`, and similar packages.
33
+
34
+ ```ts
35
+ type ExtendedSpec = {
36
+ readonly cites?: Cites;
37
+ readonly def?: Partial<SpecDefs>;
38
+ readonly specs?: readonly ExtendedElementSpec[];
39
+ };
40
+ ```
41
+
42
+ `ExtendedElementSpec` is a partial version of `ElementSpec` where only `name` is required. All other properties are optional overrides. Attributes use `Partial<Attribute>` to allow specifying only changed fields:
43
+
44
+ ```ts
45
+ type ExtendedElementSpec = Partial<Omit<ElementSpec, 'name' | 'attributes'>> & {
46
+ readonly name: ElementSpec['name'];
47
+ readonly attributes?: Readonly<Record<string, Partial<Attribute>>>;
48
+ };
49
+ ```
50
+
51
+ ### `SpecDefs`
52
+
53
+ Internal definition data within a markup language spec, containing global attributes, ARIA role/property definitions, and content model category mappings.
54
+
55
+ ```ts
56
+ type SpecDefs = {
57
+ readonly '#globalAttrs': {
58
+ readonly [category: string]: Readonly<Record<string, Partial<Attribute>>>;
59
+ };
60
+ readonly '#aria': {
61
+ readonly '1.3': ARIASpec;
62
+ readonly '1.2': ARIASpec;
63
+ readonly '1.1': ARIASpec;
64
+ };
65
+ readonly '#contentModels': {
66
+ readonly [model in Category]?: readonly string[];
67
+ };
68
+ };
69
+ ```
70
+
71
+ - **`#globalAttrs`** -- Category-keyed attribute definitions. Each category (e.g., `#HTMLGlobalAttrs`, `#ARIAAttrs`) maps to a record of partial attribute definitions.
72
+ - **`#aria`** -- ARIA role/property definitions for each specification version (1.1, 1.2, 1.3). Each version contains `roles`, `graphicsRoles`, `dpubRoles`, and `props` arrays.
73
+ - **`#contentModels`** -- Content model category to selector array mappings. Maps `Category` values (like `#flow`, `#phrasing`) to arrays of CSS selectors that match elements belonging to that category.
74
+
75
+ ### `ElementSpec`
76
+
77
+ A complete element specification describing all aspects of a single HTML or SVG element.
78
+
79
+ ```ts
80
+ type ElementSpec = {
81
+ readonly name: string; // Tag name
82
+ readonly namespace?: NamespaceURI; // XML namespace URI
83
+ readonly cite: string; // Reference URL
84
+ readonly description?: string; // Human-readable description
85
+
86
+ // Status flags
87
+ readonly experimental?: true; // Experimental technology
88
+ readonly obsolete?: true | { readonly alt: string }; // Obsolete (optionally with alternative)
89
+ readonly deprecated?: true; // Deprecated
90
+ readonly nonStandard?: true; // Non-standard
91
+
92
+ // Structural properties
93
+ readonly categories: readonly Category[]; // Element categories
94
+ readonly contentModel: ReadonlyDeep<ContentModel>; // Permitted content patterns
95
+ readonly omission: ElementSpecOmission; // Tag omission rules
96
+
97
+ // Attributes and ARIA
98
+ readonly globalAttrs: ReadonlyDeep<GlobalAttributes>; // Global attribute selection
99
+ readonly attributes: Readonly<Record<string, Attribute>>; // Element-specific attributes
100
+ readonly aria: ReadonlyDeep<ARIA>; // WAI-ARIA role and property mappings
101
+
102
+ // Template engine support
103
+ readonly possibleToAddProperties?: true; // Allow arbitrary properties (for template engines)
104
+ };
105
+ ```
106
+
107
+ `ElementSpecOmission` is either `false` (no omission allowed) or an object with `startTag` and `endTag` fields indicating whether tag omission is permitted.
108
+
109
+ ### `Attribute`
110
+
111
+ Describes a single HTML/SVG attribute with its type, description, and status flags.
112
+
113
+ ```ts
114
+ type Attribute = {
115
+ readonly name: string;
116
+ readonly type: ReadonlyDeep<AttributeType> | readonly ReadonlyDeep<AttributeType>[];
117
+ readonly description?: string;
118
+ readonly caseSensitive?: true;
119
+ readonly experimental?: boolean;
120
+ readonly obsolete?: true;
121
+ readonly deprecated?: boolean;
122
+ readonly nonStandard?: true;
123
+ } & ExtendableAttributeSpec;
124
+ ```
125
+
126
+ The `& ExtendableAttributeSpec` intersection adds fields from the generated `AttributeJSON` type (excluding `type`, which is overridden with the `ReadonlyDeep` wrapper): `defaultValue`, `required`, `requiredEither`, `noUse`, `condition`, `ineffective`, `animatable`.
127
+
128
+ ## ARIA Types
129
+
130
+ ### `ARIARole`
131
+
132
+ A fully resolved ARIA role with all its properties, requirements, and naming constraints.
133
+
134
+ ```ts
135
+ type ARIARole = {
136
+ readonly name: string; // Role name (e.g., 'button', 'navigation')
137
+ readonly isAbstract: boolean; // Whether this is an abstract role
138
+ readonly deprecated: boolean; // Whether this role is deprecated
139
+
140
+ // Context requirements (ARIA 1.3 names)
141
+ readonly requiredAccessibilityParentRole: readonly string[];
142
+ readonly allowedAccessibilityChildRoles: readonly string[];
143
+
144
+ // Backward compatibility (ARIA 1.2 names, deprecated)
145
+ readonly requiredContextRole: readonly string[]; // @deprecated
146
+ readonly requiredOwnedElements: readonly string[]; // @deprecated
147
+
148
+ // Accessible name constraints
149
+ readonly accessibleNameRequired: boolean; // Must have an accessible name
150
+ readonly accessibleNameFromAuthor: boolean; // Name can come from author (aria-label, etc.)
151
+ readonly accessibleNameFromContent: boolean; // Name can come from element content
152
+ readonly accessibleNameProhibited: boolean; // Name is prohibited
153
+
154
+ // Properties
155
+ readonly childrenPresentational: boolean; // Children are presentational
156
+ readonly ownedProperties: readonly ARIARoleOwnedProperties[];
157
+ readonly prohibitedProperties: readonly string[];
158
+ };
159
+ ```
160
+
161
+ ### `ARIARoleInSchema`
162
+
163
+ An ARIA role as defined in the raw schema data. All properties are optional except `name`, since the schema may provide only partial role information. Also includes optional `description` and `generalization` (super-class roles) fields.
164
+
165
+ ```ts
166
+ type ARIARoleInSchema = Partial<
167
+ ARIARole & {
168
+ readonly description: string;
169
+ readonly generalization: readonly string[];
170
+ }
171
+ > & {
172
+ readonly name: string;
173
+ };
174
+ ```
175
+
176
+ ### `ARIARoleOwnedProperties`
177
+
178
+ Describes a property owned by an ARIA role, including whether it is inherited, required, or deprecated.
179
+
180
+ ```ts
181
+ type ARIARoleOwnedProperties = {
182
+ readonly name: string; // Property name (e.g., 'aria-expanded')
183
+ readonly inherited?: true; // Inherited from a superclass role
184
+ readonly required?: true; // Required for this role
185
+ readonly deprecated?: true; // Deprecated for this role
186
+ };
187
+ ```
188
+
189
+ ### `ARIAProperty`
190
+
191
+ Describes an ARIA property or state, including its value type, enumeration values, and equivalent HTML attributes.
192
+
193
+ ```ts
194
+ type ARIAProperty = {
195
+ readonly name: string; // Property name (e.g., 'aria-hidden')
196
+ readonly type: 'property' | 'state'; // Whether this is a property or state
197
+ readonly deprecated?: true;
198
+ readonly isGlobal?: true; // Whether this is a global ARIA attribute
199
+ readonly value: ARIAAttributeValue; // Value type
200
+ readonly conditionalValue?: readonly {
201
+ // Role-specific value overrides
202
+ readonly role: readonly string[];
203
+ readonly value: ARIAAttributeValue;
204
+ }[];
205
+ readonly enum: readonly string[]; // Allowed token values
206
+ readonly defaultValue?: string;
207
+ readonly equivalentHtmlAttrs?: readonly EquivalentHtmlAttr[];
208
+ readonly valueDescriptions?: Readonly<Record<string, string>>;
209
+ };
210
+ ```
211
+
212
+ ### `ARIAAttributeValue`
213
+
214
+ The possible value types for ARIA attributes, as defined by the WAI-ARIA specification.
215
+
216
+ ```ts
217
+ type ARIAAttributeValue =
218
+ | 'true/false'
219
+ | 'tristate'
220
+ | 'true/false/undefined'
221
+ | 'ID reference'
222
+ | 'ID reference list'
223
+ | 'integer'
224
+ | 'number'
225
+ | 'string'
226
+ | 'token'
227
+ | 'token list'
228
+ | 'URI';
229
+ ```
230
+
231
+ ### `ARIAVersion`
232
+
233
+ A union type of supported ARIA specification version strings, derived from the `ariaVersions` tuple (`['1.1', '1.2', '1.3'] as const`).
234
+
235
+ ```ts
236
+ type ARIAVersion = '1.1' | '1.2' | '1.3';
237
+ ```
238
+
239
+ The recommended default version is `'1.2'` (defined as `ARIA_RECOMMENDED_VERSION` in `src/utils/aria-version.ts`).
240
+
241
+ ### `ComputedRole`
242
+
243
+ The result of computing an element's ARIA role.
244
+
245
+ ```ts
246
+ type ComputedRole = {
247
+ readonly el: Element;
248
+ readonly role:
249
+ | (ARIARole & {
250
+ readonly superClassRoles: readonly ARIARoleInSchema[];
251
+ readonly isImplicit?: boolean;
252
+ })
253
+ | null;
254
+ readonly errorType?: RoleComputationError;
255
+ };
256
+ ```
257
+
258
+ - **`el`** -- The DOM element reference.
259
+ - **`role`** -- The resolved role (with super-class chain and implicit flag), or `null` if no role applies.
260
+ - **`errorType`** -- Optional error code indicating issues during role computation.
261
+
262
+ ### `RoleComputationError`
263
+
264
+ Error codes that may arise during ARIA role computation, indicating specific issues such as abstract roles, invalid context, or presentational conflicts.
265
+
266
+ | Error Code | Description |
267
+ | --------------------------------------------------- | ------------------------------------------------------------------------ |
268
+ | `ABSTRACT` | An abstract role was assigned (abstract roles must not be used directly) |
269
+ | `GLOBAL_PROP_MUST_NOT_BE_PRESENTATIONAL` | Element with global ARIA properties must not be presentational |
270
+ | `IMPLICIT_ROLE_NAMESPACE_ERROR` | Implicit role does not match the element's namespace |
271
+ | `INTERACTIVE_ELEMENT_MUST_NOT_BE_PRESENTATIONAL` | Interactive element must not be presentational |
272
+ | `INVALID_LANDMARK` | Invalid landmark role usage |
273
+ | `INVALID_REQUIRED_CONTEXT_ROLE` | Required context role is not satisfied |
274
+ | `NO_EXPLICIT` | No explicit role was assigned |
275
+ | `NO_OWNER` | No owning element found for required context |
276
+ | `NO_PERMITTED` | The role is not permitted on this element |
277
+ | `REQUIRED_OWNED_ELEMENT_MUST_NOT_BE_PRESENTATIONAL` | Required owned element must not be presentational |
278
+ | `ROLE_NO_EXISTS` | The specified role does not exist |
279
+
280
+ ## Utility Types
281
+
282
+ ### `Matches`
283
+
284
+ A function type that tests whether an element matches a given CSS selector string. Typically bound to `Element.prototype.matches`.
285
+
286
+ ```ts
287
+ type Matches = (selector: string) => boolean;
288
+ ```
289
+
290
+ ### `Cites`
291
+
292
+ Reference URL array type used throughout the spec.
293
+
294
+ ```ts
295
+ type Cites = readonly string[];
296
+ ```
297
+
298
+ ### `EquivalentHtmlAttr`
299
+
300
+ Describes an HTML attribute that is semantically equivalent to an ARIA property, enabling automatic mapping from HTML attributes to ARIA states/properties.
301
+
302
+ ```ts
303
+ type EquivalentHtmlAttr = {
304
+ readonly htmlAttrName: string;
305
+ readonly isNotStrictEquivalent?: true;
306
+ readonly value: string | null;
307
+ };
308
+ ```
309
+
310
+ ## Generated Types
311
+
312
+ These types are automatically generated from JSON schema files by `json-schema-to-typescript`. They carry "DO NOT MODIFY" headers and should not be edited directly.
313
+
314
+ ### From `aria.schema.json` -- `src/types/aria.ts`
315
+
316
+ **`ARIA`** -- Element-level ARIA specification with conditions and version overrides.
317
+
318
+ ```ts
319
+ interface ARIA {
320
+ implicitRole: ImplicitRole;
321
+ permittedRoles: PermittedRoles;
322
+ namingProhibited?: true;
323
+ implicitProperties?: ImplicitProperties;
324
+ properties?: PermittedARIAProperties;
325
+ conditions?: {
326
+ [selector: string]: {
327
+ /* per-condition overrides */
328
+ };
329
+ };
330
+ '1.3'?: {
331
+ /* version-specific overrides */
332
+ };
333
+ '1.2'?: {
334
+ /* version-specific overrides */
335
+ };
336
+ '1.1'?: {
337
+ /* version-specific overrides */
338
+ };
339
+ }
340
+ ```
341
+
342
+ **`ImplicitRole`** -- The element's implicit (default) role.
343
+
344
+ ```ts
345
+ type ImplicitRole = false | string; // false means "No corresponding role"
346
+ ```
347
+
348
+ **`PermittedRoles`** -- Which roles are permitted on the element.
349
+
350
+ ```ts
351
+ type PermittedRoles =
352
+ | boolean // true = "Any role", false = "No role"
353
+ | (string | { name: string; deprecated?: true })[] // Specific role list
354
+ | PermittedARIAAAMInfo; // AAM-delegated (core-aam or graphics-aam)
355
+ ```
356
+
357
+ **`PermittedARIAProperties`** -- ARIA property constraints for an element.
358
+
359
+ ```ts
360
+ type PermittedARIAProperties =
361
+ | false // "No role or aria-* attributes"
362
+ | {
363
+ global?: true; // Allow global ARIA properties
364
+ role?: true | string | [string, ...string[]]; // Properties applicable to allowed roles
365
+ only?: [
366
+ /* specific properties */
367
+ ]; // Whitelist of allowed properties
368
+ without?: [
369
+ /* prohibited properties with severity */
370
+ ]; // Blacklist with severity levels
371
+ };
372
+ ```
373
+
374
+ **`ImplicitProperties`** -- Default ARIA property values (keys matching `^aria-.+`).
375
+
376
+ ```ts
377
+ interface ImplicitProperties {
378
+ [ariaProperty: string]: string; // e.g., { 'aria-checked': 'false' }
379
+ }
380
+ ```
381
+
382
+ ### From `attributes.schema.json` -- `src/types/attributes.ts`
383
+
384
+ **`AttributeType`** -- A large union type covering all recognized attribute value types. Includes:
385
+
386
+ - **CSS property names**: `<'color'>`, `<'display'>`, `<'font-size'>`, etc. (hundreds of standard, vendor-prefixed, and deprecated CSS properties)
387
+ - **CSS value types**: `<color>`, `<length>`, `<number>`, `<url>`, `<integer>`, etc.
388
+ - **SVG-specific types**: `<svg-path>`, `<view-box>`, `<preserve-aspect-ratio>`, etc.
389
+ - **markuplint custom types**: `DOMID`, `URL`, `BCP47`, `MIMEType`, `DateTime`, `AutoComplete`, `Int`, `Uint`, `Number`, `Boolean`, `Any`, `JSON`, `FunctionBody`, etc.
390
+ - **Structured type variants**: `List`, `Enum`, `Number`, `Directive`
391
+
392
+ **`GlobalAttributes`** -- Attribute category selection specifying which global attribute categories apply to an element.
393
+
394
+ ```ts
395
+ interface GlobalAttributes {
396
+ '#HTMLGlobalAttrs'?: boolean;
397
+ '#GlobalEventAttrs'?: boolean | string[];
398
+ '#HTMLLinkAndFetchingAttrs'?: string[];
399
+ '#HTMLEmbededAndMediaContentAttrs'?: string[];
400
+ '#HTMLFormControlElementAttrs'?: string[];
401
+ '#HTMLTableCellElementAttrs'?: string[];
402
+ '#ARIAAttrs'?: boolean;
403
+ '#SVGAnimationAdditionAttrs'?: string[];
404
+ '#SVGAnimationAttributeTargetAttrs'?: string[];
405
+ '#SVGAnimationEventAttrs'?: string[];
406
+ '#SVGAnimationTargetElementAttrs'?: string[];
407
+ '#SVGAnimationTimingAttrs'?: string[];
408
+ '#SVGAnimationValueAttrs'?: string[];
409
+ '#SVGConditionalProcessingAttrs'?: string[];
410
+ '#SVGCoreAttrs'?: string[];
411
+ '#SVGFilterPrimitiveAttrs'?: string[];
412
+ '#SVGPresentationAttrs'?: string[];
413
+ '#SVGTransferFunctionAttrs'?: string[];
414
+ '#XLinkAttrs'?: string[];
415
+ }
416
+ ```
417
+
418
+ **`AttributeJSON`** -- Raw attribute definition with type, conditions, and flags.
419
+
420
+ ```ts
421
+ interface AttributeJSON {
422
+ type?: AttributeType | [AttributeType, ...AttributeType[]];
423
+ defaultValue?: string;
424
+ deprecated?: boolean;
425
+ required?: boolean | AttributeCondition;
426
+ requiredEither?: string[];
427
+ noUse?: boolean;
428
+ condition?: AttributeCondition;
429
+ ineffective?: AttributeCondition;
430
+ animatable?: boolean;
431
+ experimental?: boolean;
432
+ }
433
+ ```
434
+
435
+ **`List`** -- Structured type for space-separated or comma-separated token lists.
436
+
437
+ ```ts
438
+ interface List {
439
+ token: string | Enum; // Token type or enum definition
440
+ separator: 'space' | 'comma'; // Separator type
441
+ disallowToSurroundBySpaces?: boolean;
442
+ allowEmpty?: boolean;
443
+ ordered?: boolean;
444
+ unique?: boolean;
445
+ caseInsensitive?: boolean;
446
+ number?: ('zeroOrMore' | 'oneOrMore') | { min: number; max: number };
447
+ }
448
+ ```
449
+
450
+ **`Enum`** -- Enumerated attribute values.
451
+
452
+ ```ts
453
+ interface Enum {
454
+ enum: [string, ...string[]]; // At least one value required
455
+ disallowToSurroundBySpaces?: boolean;
456
+ caseInsensitive?: boolean;
457
+ invalidValueDefault?: string; // Default when value is invalid
458
+ missingValueDefault?: string; // Default when attribute is missing
459
+ sameStates?: { [k: string]: unknown };
460
+ }
461
+ ```
462
+
463
+ **`Number`** -- Numeric attribute constraints.
464
+
465
+ ```ts
466
+ interface Number {
467
+ type: 'float' | 'integer';
468
+ gt?: number; // Greater than
469
+ gte?: number; // Greater than or equal
470
+ lt?: number; // Less than
471
+ lte?: number; // Less than or equal
472
+ clampable?: boolean;
473
+ }
474
+ ```
475
+
476
+ **`Directive`** -- Directive-based attribute validation for complex attributes containing both directives and tokens.
477
+
478
+ ```ts
479
+ interface Directive {
480
+ directive: [string, ...string[]]; // At least one directive
481
+ token: AttributeType; // Token type to validate
482
+ ref?: string; // Reference URL
483
+ }
484
+ ```
485
+
486
+ ### From `content-models.schema.json` -- `src/types/permitted-structures.ts`
487
+
488
+ **`PermittedContentPattern`** -- A union of all content model pattern types.
489
+
490
+ ```ts
491
+ type PermittedContentPattern =
492
+ | PermittedContentRequire // Required content
493
+ | PermittedContentOptional // Optional content
494
+ | PermittedContentOneOrMore // One or more occurrences
495
+ | PermittedContentZeroOrMore // Zero or more occurrences
496
+ | PermittedContentChoice // Choice between content alternatives
497
+ | PermittedContentTransparent; // Transparent content model
498
+ ```
499
+
500
+ Each pattern variant (except `PermittedContentTransparent`) accepts either a `Model` or a nested `PermittedContentPattern[]` and supports an optional `max` count.
501
+
502
+ **`ContentModel`** -- Complete content model for an element.
503
+
504
+ ```ts
505
+ interface ContentModel {
506
+ contents: PermittedContentPattern[] | boolean; // Content patterns or boolean
507
+ descendantOf?: string; // Context restriction
508
+ conditional?: {
509
+ // Condition-dependent content
510
+ condition: string;
511
+ contents: PermittedContentPattern[] | boolean;
512
+ }[];
513
+ }
514
+ ```
515
+
516
+ **`Category`** -- Content model category. Includes 13 HTML categories and 19 SVG categories.
517
+
518
+ HTML categories:
519
+
520
+ - `#text`, `#phrasing`, `#flow`, `#interactive`, `#heading`
521
+ - `#sectioning`, `#metadata`, `#embedded`, `#palpable`, `#script-supporting`
522
+
523
+ SVG categories:
524
+
525
+ - `#SVGAnimation`, `#SVGBasicShapes`, `#SVGContainer`, `#SVGDescriptive`
526
+ - `#SVGFilterPrimitive`, `#SVGFont`, `#SVGGradient`, `#SVGGraphics`
527
+ - `#SVGGraphicsReferencing`, `#SVGLightSource`, `#SVGNeverRendered`
528
+ - `#SVGNone`, `#SVGPaintServer`, `#SVGRenderable`, `#SVGShape`
529
+ - `#SVGStructural`, `#SVGStructurallyExternal`, `#SVGTextContent`, `#SVGTextContentChild`
530
+
531
+ **`Model`** and **`ContentType`**:
532
+
533
+ ```ts
534
+ type Model = ContentType | ContentType[];
535
+ type ContentType = string | Category;
536
+ ```
537
+
538
+ ## JSON Schema Files
539
+
540
+ The following JSON schema files are located in the `schemas/` directory.
541
+
542
+ | Schema File | Lines | Description |
543
+ | ------------------------------- | ----- | ------------------------------------------------------------------------------------------------------------------- |
544
+ | `element.schema.json` | 11 | Top-level element schema combining `$ref` pointers to content models, attributes, global attributes, and ARIA |
545
+ | `aria.schema.json` | 291 | ARIA role/property definitions including implicit roles, permitted roles, properties, and version overrides |
546
+ | `attributes.schema.json` | 190 | Attribute type unions, attribute JSON definitions, global attribute category selection, and attribute name patterns |
547
+ | `content-models.schema.json` | 215 | Content model patterns (require, optional, oneOrMore, zeroOrMore, choice, transparent) and category definitions |
548
+ | `global-attributes.schema.json` | 787 | Global attribute categories for HTML and SVG (auto-generated from `gen/global-attribute.data.ts`) |
549
+
550
+ ## Schema Generation Workflow
551
+
552
+ The schema generation pipeline works as follows:
553
+
554
+ 1. **`gen/global-attribute.data.ts`** defines the source-of-truth data for global attribute categories, listing all attribute names per category.
555
+
556
+ 2. **`gen/gen.ts`** reads the global attribute data and generates two schema files:
557
+ - `schemas/global-attributes.schema.json` -- The full global attributes schema with category definitions and per-category enums.
558
+ - `schemas/attributes.schema.json` -- The attributes schema including `GlobalAttributes` type with category-specific property selectors.
559
+
560
+ 3. **`json-schema-to-typescript`** converts each `.schema.json` file into corresponding TypeScript files:
561
+ - `schemas/aria.schema.json` --> `src/types/aria.ts`
562
+ - `schemas/attributes.schema.json` --> `src/types/attributes.ts`
563
+ - `schemas/content-models.schema.json` --> `src/types/permitted-structures.ts`
564
+
565
+ 4. Generated TypeScript files include "DO NOT MODIFY" headers. To update generated types, modify the source JSON schema (or the generation script for auto-generated schemas), then re-run the generation pipeline.
@@ -0,0 +1,45 @@
1
+ import type { AccnameElement, AccnameNode, AccnameResolver } from '../types.js';
2
+ interface ElementOptions {
3
+ readonly attrs?: Record<string, string>;
4
+ readonly children?: readonly (AccnameElement | AccnameNode)[];
5
+ readonly parentElement?: AccnameElement | null;
6
+ readonly namespaceURI?: string | null;
7
+ }
8
+ /**
9
+ * Creates a test AccnameElement (plain object).
10
+ *
11
+ * **Note:** `textContent` is computed eagerly at creation time from the initial
12
+ * `children`. Adding children after creation will NOT update `textContent`.
13
+ * Build the full child tree before calling this function.
14
+ *
15
+ * @param localName - The local tag name of the element
16
+ * @param options - Configuration for attributes, children, parent, and namespace
17
+ * @returns A plain object implementing the AccnameElement interface
18
+ */
19
+ export declare function element(localName: string, options?: ElementOptions): AccnameElement;
20
+ /**
21
+ * Creates a test text node.
22
+ *
23
+ * @param text - The text content of the node
24
+ * @returns A plain object implementing the AccnameNode interface
25
+ */
26
+ export declare function textNode(text: string): AccnameNode;
27
+ interface ResolverOptions {
28
+ readonly elements?: Map<string, AccnameElement>;
29
+ readonly labels?: Map<string, readonly AccnameElement[]>;
30
+ readonly nameFromContent?: Set<string>;
31
+ readonly hiddenIds?: Set<string>;
32
+ readonly allowsNameFromContentFn?: (el: AccnameElement) => boolean;
33
+ readonly isHiddenFn?: (el: AccnameElement) => boolean;
34
+ readonly embeddedControlRoles?: Set<string>;
35
+ readonly isEmbeddedControlFn?: (el: AccnameElement) => boolean;
36
+ readonly getPrecomputedNameFn?: (el: AccnameElement) => string | null;
37
+ }
38
+ /**
39
+ * Creates a test AccnameResolver.
40
+ *
41
+ * @param options - Configuration for element lookups, label associations, and behavior overrides
42
+ * @returns A resolver implementing the AccnameResolver interface for testing
43
+ */
44
+ export declare function createTestResolver(options?: ResolverOptions): AccnameResolver;
45
+ export {};