@markuplint/html-spec 4.16.1 → 4.17.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/README.md CHANGED
@@ -16,8 +16,6 @@ This package serves as the data layer in markuplint's specification system, depe
16
16
 
17
17
  ## Package Architecture
18
18
 
19
- This package serves as the data layer in markuplint's specification system:
20
-
21
19
  ```
22
20
  @markuplint/ml-spec (Foundation Layer)
23
21
  ↓ provides types, algorithms, schemas
@@ -34,69 +32,17 @@ Core packages (Application Layer)
34
32
  ### Generated Output (DO NOT EDIT)
35
33
 
36
34
  - **`index.json`** - Consolidated specification data (48K+ lines)
37
- - All HTML elements with complete specifications
38
- - Global attribute definitions (`#HTMLGlobalAttrs`, `#ARIAAttrs`)
39
- - ARIA role and property definitions (`#aria`)
40
- - Content model macros (`#contentModels`)
41
- - Citation references to authoritative sources
42
35
 
43
36
  ### Source Files (EDIT THESE)
44
37
 
45
- - **`src/spec-*.json`** - Individual element specifications
46
- - `src/spec.div.json` `<div>` element specification
47
- - `src/spec.table.json` `<table>` element specification
48
- - `src/spec.svg_text.json` → `<svg:text>` element specification
49
- - **`src/spec-common.attributes.json`** - Shared attribute definitions
50
- - **`src/spec-common.contents.json`** - Reusable content model macros
38
+ - **`src/spec.*.json`** - Individual element specifications (177 files)
39
+ - **`src/spec-common.attributes.json`** - Global attribute category definitions (19 categories)
40
+ - **`src/spec-common.contents.json`** - Content model category macros (HTML 10 + SVG 19 categories)
51
41
 
52
- ### Build Process
42
+ ### Build System
53
43
 
54
44
  - **`build.mjs`** - Generation script that invokes `@markuplint/spec-generator`
55
- - **External data sources**:
56
- - **MDN Web Docs** - Element descriptions, compatibility data, attribute metadata
57
- - **W3C ARIA specifications** - Role definitions, property mappings (1.1/1.2/1.3)
58
- - **HTML Living Standard** - Obsolete element definitions
59
- - **SVG specifications** - SVG element definitions and categories
60
-
61
- ## Data Structure
62
-
63
- The generated `index.json` follows this structure:
64
-
65
- ```typescript
66
- {
67
- cites: Cites; // Reference citations to external specs
68
- def: { // Global definitions
69
- "#HTMLGlobalAttrs": GlobalAttributes;
70
- "#ARIAAttrs": ARIAAttributes;
71
- "#aria": ARIASpecification;
72
- "#contentModels": ContentModelMacros;
73
- };
74
- specs: ElementSpec[]; // Individual element specifications
75
- }
76
- ```
77
-
78
- ### Element Specification Format
79
-
80
- Each element specification includes:
81
-
82
- ```typescript
83
- {
84
- name: string; // Element name (e.g., "table", "tr")
85
- cite: string; // MDN reference URL
86
- description: string; // Human-readable description
87
- categories: string[]; // Content categories (flow, phrasing, etc.)
88
- contentModel: ContentModel; // Permitted child elements
89
- globalAttrs: GlobalAttrSets; // Applicable global attributes
90
- attributes: AttributeSpecs; // Element-specific attributes
91
- aria: { // ARIA integration
92
- implicitRole: string | null; // Default ARIA role
93
- permittedRoles: string[] | boolean; // Allowed ARIA roles
94
- namingProhibited?: boolean; // Accessible name constraints
95
- conditions?: ConditionalARIA; // Context-specific ARIA rules
96
- };
97
- omission?: TagOmissionRules; // Start/end tag omission rules
98
- }
99
- ```
45
+ - Fetches live data from MDN, W3C ARIA specs, and HTML Living Standard
100
46
 
101
47
  ## Relationship to @markuplint/ml-spec
102
48
 
@@ -105,190 +51,12 @@ Each element specification includes:
105
51
  - **Type definitions** (`ElementSpec`, `ExtendedSpec`, `MLMLSpec`) that structure this data
106
52
  - **JSON schemas** that validate the specification format
107
53
  - **Algorithms** that process and compute values from this specification data
108
- - **Runtime utilities** that consume this consolidated specification data
109
54
 
110
55
  **@markuplint/html-spec** (this package) provides:
111
56
 
112
57
  - **Canonical HTML data** following the type definitions from `@markuplint/ml-spec`
113
58
  - **External data enrichment** from MDN and W3C specifications
114
59
  - **Build automation** that keeps data synchronized with external sources
115
- - **Single consolidated dataset** optimized for runtime consumption
116
-
117
- This separation enables:
118
-
119
- - **Independent data updates** without affecting type definitions or algorithms
120
- - **Algorithm improvements** without requiring data regeneration
121
- - **Framework extensions** that can augment this base HTML data
122
-
123
- ## Development Workflow
124
-
125
- ### Adding or Editing HTML Elements
126
-
127
- 1. **Edit source specifications**
128
- - Add new file: `src/spec.<element>.json` (e.g., `src/spec.dialog.json`)
129
- - Edit existing: Update relevant `src/spec-*.json` file
130
- - For SVG elements: Use pattern `src/spec.svg_<local>.json`
131
-
132
- 2. **Regenerate the dataset**
133
-
134
- ```bash
135
- # From repository root (recommended)
136
- yarn up:gen
137
-
138
- # Or for this package only
139
- yarn workspace @markuplint/html-spec run gen
140
- ```
141
-
142
- 3. **Verify output**
143
- - Check `index.json` for expected changes
144
- - Ensure no unintended modifications to other elements
145
-
146
- ### Element Specification Guide
147
-
148
- **Minimal element specification**:
149
-
150
- ```json
151
- {
152
- "contentModel": {
153
- "contents": [{ "require": "#phrasing" }]
154
- },
155
- "globalAttrs": {
156
- "#HTMLGlobalAttrs": true,
157
- "#ARIAAttrs": true
158
- },
159
- "attributes": {
160
- "custom-attr": { "type": "String" }
161
- },
162
- "aria": {
163
- "implicitRole": "button",
164
- "permittedRoles": ["link", "tab"]
165
- }
166
- }
167
- ```
168
-
169
- **Key principles**:
170
-
171
- - Only specify what differs from defaults or overrides MDN data
172
- - Use references to global attribute sets when possible
173
- - Define content models using semantic categories (`#flow`, `#phrasing`)
174
- - Include ARIA specifications following HTML-ARIA mapping guidelines
175
-
176
- ### Common Editing Patterns
177
-
178
- **Adding element-specific attributes**:
179
-
180
- ```json
181
- {
182
- "attributes": {
183
- "href": {
184
- "type": "URL",
185
- "required": false,
186
- "description": "Target URL for navigation"
187
- },
188
- "download": {
189
- "type": "String",
190
- "experimental": true
191
- }
192
- }
193
- }
194
- ```
195
-
196
- **Conditional ARIA rules**:
197
-
198
- ```json
199
- {
200
- "aria": {
201
- "implicitRole": "link",
202
- "permittedRoles": ["button", "menuitem"],
203
- "conditions": {
204
- ":not([href])": {
205
- "implicitRole": "generic",
206
- "namingProhibited": true
207
- }
208
- }
209
- }
210
- }
211
- ```
212
-
213
- **Complex content models**:
214
-
215
- ```json
216
- {
217
- "contentModel": {
218
- "contents": [{ "transparent": ":not(:model(interactive), a, [tabindex])" }]
219
- }
220
- }
221
- ```
222
-
223
- ## Build Process Details
224
-
225
- ### What `yarn up:gen` does
226
-
227
- 1. **Invokes spec-generator** with inputs:
228
- - HTML spec sources: `src/spec-*.json`
229
- - Common attributes: `src/spec-common.attributes.json`
230
- - Common content models: `src/spec-common.contents.json`
231
-
232
- 2. **External data enrichment**:
233
- - **MDN scraping**: Fetches descriptions, categories, attribute metadata
234
- - **ARIA integration**: Downloads W3C ARIA specifications (1.1/1.2/1.3)
235
- - **Obsolete elements**: Adds deprecated elements from HTML Living Standard
236
- - **SVG specifications**: Includes SVG element definitions and categories
237
-
238
- 3. **Data consolidation**:
239
- - Merges manual specifications with fetched data
240
- - Resolves conflicts (manual data takes precedence)
241
- - Validates against JSON schemas from `@markuplint/ml-spec`
242
- - Generates citations and references
243
-
244
- 4. **Output generation**:
245
- - Writes consolidated `index.json`
246
- - Formats with Prettier
247
- - Validates structural integrity
248
-
249
- ### External Data Sources
250
-
251
- **MDN Web Docs** (`developer.mozilla.org`):
252
-
253
- - Element descriptions and usage guidance
254
- - Compatibility tables and browser support
255
- - Attribute metadata (deprecated, experimental, obsolete)
256
- - Tag omission rules and semantic information
257
-
258
- **W3C ARIA Specifications**:
259
-
260
- - **ARIA 1.1**: `https://www.w3.org/TR/wai-aria-1.1/`
261
- - **ARIA 1.2**: `https://www.w3.org/TR/wai-aria-1.2/`
262
- - **ARIA 1.3**: `https://w3c.github.io/aria/`
263
- - **HTML-ARIA**: `https://www.w3.org/TR/html-aria/`
264
-
265
- **HTML Living Standard** (`https://html.spec.whatwg.org/`):
266
-
267
- - Obsolete element definitions
268
- - Semantic category classifications
269
- - Content model specifications
270
-
271
- ### Caching and Performance
272
-
273
- - **External fetches are cached** to prevent unnecessary network requests during development
274
- - **CI/CD builds** refresh external data to stay current with specification changes
275
- - **Generated output is optimized** for runtime consumption (single file, pre-resolved references)
276
-
277
- ## File Naming Conventions
278
-
279
- **HTML elements**: `src/spec.<tag>.json`
280
-
281
- - Examples: `spec.div.json`, `spec.table.json`, `spec.input.json`
282
-
283
- **SVG elements**: `src/spec.svg_<local>.json`
284
-
285
- - Examples: `spec.svg_text.json`, `spec.svg_circle.json`
286
- - Element name inferred as `svg:<local>` (e.g., `svg:text`)
287
-
288
- **Special files**:
289
-
290
- - `spec-common.attributes.json` - Global attribute category definitions
291
- - `spec-common.contents.json` - Reusable content model macros
292
60
 
293
61
  ## Install
294
62
 
@@ -305,30 +73,14 @@ $ yarn add @markuplint/html-spec
305
73
 
306
74
  </details>
307
75
 
308
- ## Important Notes
309
-
310
- ### Do Not Edit Generated Files
311
-
312
- - **Never modify `index.json` directly** - it will be overwritten
313
- - Always update source files in `src/` and regenerate
314
-
315
- ### Manual Data Takes Precedence
316
-
317
- - Your specifications in `src/spec-*.json` override scraped MDN data
318
- - Use this to correct inaccuracies or add missing information
319
- - External data fills gaps but doesn't override manual specifications
320
-
321
- ### Specification Compliance
322
-
323
- - ARIA mappings should follow W3C HTML-ARIA mapping guidelines
324
- - Content models should align with HTML Living Standard definitions
325
- - Attribute types should reference `@markuplint/types` definitions
76
+ ## Contributing
326
77
 
327
- ### Framework Integration
78
+ For detailed documentation, see:
328
79
 
329
- - This package provides base HTML specifications
330
- - Framework-specific packages (Vue, React, Svelte) extend this base data
331
- - Extensions are merged at runtime using `@markuplint/ml-spec` utilities
80
+ - [Architecture](ARCHITECTURE.md) -- Package structure, data flow, and integration points
81
+ - [Element Specification Format](docs/element-spec-format.md) -- JSON spec file reference, content models, ARIA integration
82
+ - [Build Pipeline](docs/build-pipeline.md) -- Build process, external data sources, spec-generator modules
83
+ - [Maintenance Guide](docs/maintenance.md) -- Common recipes, testing, troubleshooting
332
84
 
333
85
  ## License
334
86
 
package/SKILL.md ADDED
@@ -0,0 +1,358 @@
1
+ ---
2
+ description: Perform maintenance tasks for @markuplint/html-spec
3
+ ---
4
+
5
+ # html-spec-maintenance
6
+
7
+ Perform maintenance tasks for `@markuplint/html-spec`: regenerate specification data,
8
+ review upstream changes, update manual spec files, and ensure cross-package consistency.
9
+
10
+ ## Input
11
+
12
+ `$ARGUMENTS` specifies the task. Supported tasks:
13
+
14
+ | Task | Description |
15
+ | ------------------------------------- | ------------------------------------------------------ |
16
+ | `update` | Regenerate `index.json` and review upstream changes |
17
+ | `add-element <name>` | Add a new HTML element specification |
18
+ | `add-svg-element <name>` | Add a new SVG element specification |
19
+ | `add-attribute <element> <attr>` | Add an attribute to an element |
20
+ | `remove-attribute <element> <attr>` | Remove an attribute from an element |
21
+ | `obsolete-element <name>` | Mark an element as obsolete |
22
+ | `obsolete-attribute <element> <attr>` | Mark an attribute as deprecated |
23
+ | `change-flag <element> <attr> <flag>` | Change `experimental`/`deprecated`/`nonStandard` flags |
24
+ | `check` | Verify cross-package consistency |
25
+
26
+ If omitted, defaults to `update`.
27
+
28
+ ## Reference
29
+
30
+ Before executing any task, read `docs/maintenance.md` (or `docs/maintenance.ja.md`)
31
+ for the full guide. The recipes there are the source of truth for procedures.
32
+
33
+ Also read:
34
+
35
+ - `docs/element-spec-format.md` -- JSON spec file format reference
36
+ - `docs/build-pipeline.md` -- Build pipeline and data precedence rules
37
+
38
+ ## Task: update
39
+
40
+ The primary maintenance workflow. Regenerate `index.json` with the latest MDN/W3C data
41
+ and review what has changed.
42
+
43
+ ### Step 1: Regenerate
44
+
45
+ ```bash
46
+ yarn up:gen
47
+ ```
48
+
49
+ This runs `@markuplint/spec-generator`, which scrapes live MDN data and merges it with
50
+ the manual spec files in `src/`. The result is written to `index.json`.
51
+
52
+ ### Step 2: Review the diff
53
+
54
+ ```bash
55
+ git diff packages/@markuplint/html-spec/index.json
56
+ ```
57
+
58
+ Categorize each change:
59
+
60
+ | Category | Examples | Action |
61
+ | ------------------------------- | ------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------- |
62
+ | **Minor description rewording** | MDN refines role/element/attribute descriptions | Commit as-is |
63
+ | **New attributes** | `interestfor`, `switch` added by MDN | Commit as-is (MDN-sourced, no manual spec change needed) |
64
+ | **Flag transitions** | `experimental` → `deprecated`, `nonStandard` added/removed | Commit as-is |
65
+ | **Significant spec changes** | ARIA property `required` → `inherited`, content model restructured | Requires manual spec update (go to Step 3) |
66
+ | **ARIA 1.3 updates** | New/revised role definitions, property requirement changes | WAI-ARIA 1.3 is a Working Draft -- expect ongoing changes. 1.1 and 1.2 are finalized Recommendations and will not change. |
67
+
68
+ > **Caution -- ARIA version duplication:** `index.json` contains role definitions for
69
+ > WAI-ARIA 1.1, 1.2, and 1.3, so many strings appear three times. When editing
70
+ > descriptions or properties, **do not use `replace_all`** -- it will modify all three
71
+ > versions simultaneously. Always target the specific version block you intend to change.
72
+
73
+ ### Step 3: Handle significant changes (if any)
74
+
75
+ If the diff contains substantive changes to element behavior, ARIA mappings, or
76
+ content models:
77
+
78
+ 1. Identify the affected elements
79
+ 2. Determine which source files need updating:
80
+ - `src/spec.<element>.json` for element-specific changes
81
+ - `src/spec-common.contents.json` for content model category changes
82
+ - `src/spec-common.attributes.json` for global attribute changes
83
+ - In rare cases, `@markuplint/ml-spec` schemas or types may need updating
84
+ 3. Make the changes, referencing the authoritative specification:
85
+ - HTML Living Standard: https://html.spec.whatwg.org/multipage/
86
+ - HTML-ARIA: https://w3c.github.io/html-aria/
87
+ - WAI-ARIA: https://w3c.github.io/aria/
88
+ 4. Regenerate to incorporate manual spec changes:
89
+ ```bash
90
+ yarn up:gen
91
+ ```
92
+ 5. Verify the final diff is correct
93
+
94
+ ### Step 3b: Idempotency verification (when spec files are modified)
95
+
96
+ When you modify `src/spec.*.json` files, verify that your changes produce stable output
97
+ before committing. This ensures the generated `index.json` does not contain unintended
98
+ drift:
99
+
100
+ ```bash
101
+ # 1. Stage spec files and index.json
102
+ git add packages/@markuplint/html-spec/src/spec.*.json packages/@markuplint/html-spec/index.json
103
+
104
+ # 2. Regenerate
105
+ yarn up:gen
106
+
107
+ # 3. Check that the attributes you changed are NOT in the diff (= stable output)
108
+ git diff packages/@markuplint/html-spec/index.json | grep '"your-attr"'
109
+
110
+ # 4. If stable, discard the regenerated file and use the staged version
111
+ git checkout packages/@markuplint/html-spec/index.json
112
+
113
+ # 5. Proceed to commit
114
+ ```
115
+
116
+ If the diff shows unexpected changes for your attribute, it means the spec file and
117
+ the generator produce different values -- investigate before committing.
118
+
119
+ ### Step 4: Test and commit
120
+
121
+ ```bash
122
+ yarn workspace @markuplint/html-spec run test
123
+ ```
124
+
125
+ Stage and commit `index.json` and any modified `src/` files.
126
+
127
+ ## Task: add-element
128
+
129
+ Add a new HTML element specification. Follow recipe #1 in `docs/maintenance.md`.
130
+
131
+ 1. Read `src/spec.a.json` as a reference for a typical element
132
+ 2. Create `src/spec.<name>.json` with required fields:
133
+ - `contentModel` with `contents`
134
+ - `globalAttrs` (`#HTMLGlobalAttrs`, `#GlobalEventAttrs`, `#ARIAAttrs` set to `true`)
135
+ - `attributes` (element-specific, can be `{}`)
136
+ - `aria` with `implicitRole` and `permittedRoles`
137
+ 3. Add spec URL comments at the top (`//` format)
138
+ 4. **Cross-package step**: If the element belongs to content categories (flow, phrasing, etc.),
139
+ add it to the appropriate categories in `src/spec-common.contents.json`.
140
+ Without this, `@markuplint/rules`' `permitted-contents` rule will flag the element
141
+ as invalid content in parent elements that allow those categories.
142
+ 5. Regenerate: `yarn workspace @markuplint/html-spec run gen`
143
+ 6. Verify the element appears in `index.json`
144
+ 7. Run tests: `yarn workspace @markuplint/html-spec run test`
145
+
146
+ ## Task: add-svg-element
147
+
148
+ Add a new SVG element specification. Follow recipe #3 in `docs/maintenance.md`.
149
+
150
+ 1. Read `src/spec.svg_circle.json` as a reference for a typical SVG element
151
+ 2. Create `src/spec.svg_<name>.json` (the `svg_` prefix maps to namespace `svg:<name>`)
152
+ 3. Use SVG-specific global attribute categories (`#SVGCoreAttrs`, `#SVGPresentationAttrs`)
153
+ 4. For ARIA, use AAM references: `{ "core-aam": true, "graphics-aam": true }`
154
+ 5. Regenerate: `yarn workspace @markuplint/html-spec run gen`
155
+ 6. Run tests: `yarn workspace @markuplint/html-spec run test`
156
+
157
+ ## Task: add-attribute
158
+
159
+ Add an attribute to an element. Follow recipe #2 in `docs/maintenance.md`.
160
+
161
+ 1. Open `src/spec.<element>.json`
162
+ 2. Add the attribute entry to the `attributes` object. See `docs/element-spec-format.md`
163
+ for the full attribute definition format. Common patterns:
164
+ - Simple typed attribute: `"href": { "type": "URL" }`
165
+ - Conditional attribute: `"accept": { "type": ..., "condition": "[type='file' i]" }`
166
+ - Boolean attribute: `"disabled": { "type": "Boolean" }`
167
+ 3. For a **global** attribute (applies to all elements), edit
168
+ `src/spec-common.attributes.json` instead, adding the attribute to the
169
+ appropriate category (e.g., `#HTMLGlobalAttrs`)
170
+ 4. Regenerate: `yarn workspace @markuplint/html-spec run gen`
171
+ 5. Verify the attribute appears in `index.json` with correct metadata
172
+ 6. Run tests: `yarn workspace @markuplint/html-spec run test`
173
+
174
+ ## Task: remove-attribute
175
+
176
+ Remove an attribute from an element's manual specification.
177
+
178
+ 1. Open `src/spec.<element>.json`
179
+ 2. Remove the attribute entry from the `attributes` object
180
+ 3. For a **global** attribute, edit `src/spec-common.attributes.json` instead
181
+ 4. Regenerate: `yarn workspace @markuplint/html-spec run gen`
182
+ 5. Verify the attribute no longer appears in `index.json` for the element.
183
+ **Note**: If the attribute also exists in MDN data, it will still appear in
184
+ `index.json` from the MDN source. To fully suppress an MDN-sourced attribute,
185
+ you may need to override it in the manual spec rather than simply removing it.
186
+ 6. Run tests: `yarn workspace @markuplint/html-spec run test`
187
+
188
+ ## Task: obsolete-element
189
+
190
+ Mark an element as obsolete. Follow recipe #8 in `docs/maintenance.md`.
191
+
192
+ There are two approaches:
193
+
194
+ - **Via spec-generator's hardcoded list** (preferred for standard obsolete elements):
195
+ Add the element name to the `obsoleteList` array in
196
+ `packages/@markuplint/spec-generator/src/html-elements.ts`
197
+ - **Via manual spec file**: Set `"obsolete": true` in the element's
198
+ `src/spec.<element>.json`
199
+
200
+ Obsolete elements automatically get:
201
+
202
+ - `cite` pointing to the HTML spec obsolete features section
203
+ - `contents: true` (any content allowed)
204
+ - `permittedRoles: true`, `implicitRole: false`
205
+
206
+ After making the change:
207
+
208
+ 1. Regenerate: `yarn up:gen`
209
+ 2. Verify the element appears in `index.json` with `"obsolete": true`
210
+ 3. Run tests: `yarn workspace @markuplint/html-spec run test`
211
+
212
+ ## Task: obsolete-attribute
213
+
214
+ Mark an attribute as deprecated in an element's specification.
215
+
216
+ 1. Open `src/spec.<element>.json`
217
+ 2. Add `"deprecated": true` to the attribute definition:
218
+ ```json
219
+ "align": {
220
+ "deprecated": true
221
+ }
222
+ ```
223
+ If the attribute already has other fields (`type`, `condition`, etc.),
224
+ simply add `"deprecated": true` alongside them.
225
+ 3. For a **global** attribute, edit `src/spec-common.attributes.json` instead
226
+ 4. Regenerate: `yarn workspace @markuplint/html-spec run gen`
227
+ 5. Verify the attribute shows `"deprecated": true` in `index.json`
228
+ 6. Run tests: `yarn workspace @markuplint/html-spec run test`
229
+
230
+ ## Task: change-flag
231
+
232
+ Change the `experimental`, `deprecated`, or `nonStandard` flag on an attribute.
233
+
234
+ These boolean flags indicate the standardization status of an attribute:
235
+
236
+ | Flag | Meaning |
237
+ | -------------- | ----------------------------------------------------------------- |
238
+ | `experimental` | The attribute is part of an emerging specification not yet stable |
239
+ | `deprecated` | The attribute is obsolete and should not be used |
240
+ | `nonStandard` | The attribute is not part of any standard |
241
+
242
+ 1. Open `src/spec.<element>.json` (or `src/spec-common.attributes.json` for globals)
243
+ 2. Add, change, or remove the flag on the target attribute:
244
+ ```json
245
+ "attributionsrc": {
246
+ "deprecated": true
247
+ }
248
+ ```
249
+ To remove a flag, delete the property entirely.
250
+ 3. **Note**: Flags from MDN scraping also appear in `index.json`. Manual spec flags
251
+ take precedence, so setting a flag in the manual spec will override the MDN value.
252
+ However, MDN-only attributes (not defined in manual specs) can only be overridden
253
+ by adding an entry for that attribute in the manual spec.
254
+ 4. Regenerate: `yarn workspace @markuplint/html-spec run gen`
255
+ 5. Verify the flag change in `index.json`
256
+ 6. Run tests: `yarn workspace @markuplint/html-spec run test`
257
+
258
+ ## ARIA Version System
259
+
260
+ ### Resolution Logic
261
+
262
+ `resolveVersion()` (`@markuplint/ml-spec/src/utils/resolve-version.ts`) checks
263
+ `aria[version]` first, falls back to top-level `aria`. The runtime default is
264
+ `ARIA_RECOMMENDED_VERSION = '1.2'` (`@markuplint/ml-spec/src/utils/aria-version.ts`).
265
+
266
+ ### Key Placement Rules
267
+
268
+ | Key | Meaning | Mutability |
269
+ | ---------------- | --------------------------------------------------------- | -------------------------------------------- |
270
+ | Top-level `aria` | Default / latest. Fallback for versions without overrides | Mutable — update to match current W3C Rec |
271
+ | `"1.1"` | ARIA 1.1 snapshot | **Frozen** — never add new roles |
272
+ | `"1.2"` | ARIA 1.2 snapshot (rarely needed) | Only create when top-level diverges from 1.2 |
273
+
274
+ ### Decision: Where to add new permittedRoles
275
+
276
+ 1. Is the role in the W3C Recommendation "ARIA in HTML" (ARIA 1.2 based, Aug 2025)?
277
+ → Add to **top-level only**
278
+ 2. Is the role ARIA 1.3 draft-only (not in W3C Rec)?
279
+ → Add to **top-level**, AND create `"1.2"` key with the current 1.2 list to freeze it
280
+ 3. Was the role in the original ARIA 1.1 spec for this element?
281
+ → It should already be in `"1.1"`. **Never add new roles to `"1.1"`**.
282
+
283
+ ### permittedRoles Quick Reference
284
+
285
+ | Pattern | Meaning |
286
+ | ---------------------------------------- | ----------------------------------- |
287
+ | `true` | Any role allowed |
288
+ | `false` | No roles allowed |
289
+ | `["role1", "role2"]` | Specific roles (alphabetical order) |
290
+ | `[{"name": "role", "deprecated": true}]` | Deprecated role |
291
+
292
+ ## Task: check
293
+
294
+ Verify cross-package consistency between `@markuplint/html-spec` and related packages.
295
+
296
+ 1. **Content model categories**: Verify that category names in `src/spec-common.contents.json`
297
+ match the `Category` enum in `@markuplint/ml-spec/schemas/content-models.schema.json`
298
+ 2. **Element membership**: Verify that elements listed in content categories have
299
+ corresponding `src/spec.<element>.json` files and consistent `contentModel` definitions
300
+ 3. **Attribute types**: Check that attribute type references (e.g., `"URL"`, `"<color>"`)
301
+ exist in `@markuplint/types`' definitions registry
302
+ 4. **Schema validation**: Run `yarn workspace @markuplint/html-spec run test` to validate
303
+ all source JSON files against `@markuplint/ml-spec` schemas
304
+
305
+ Report results as:
306
+
307
+ ```
308
+ | # | Check | Status | Notes |
309
+ ```
310
+
311
+ ## Testing Requirements for Spec Changes
312
+
313
+ Spec data changes propagate to multiple test suites. Always run `yarn test`
314
+ (full suite) before committing.
315
+
316
+ ### Test Matrix
317
+
318
+ | Change type | Primary test file | Also check |
319
+ | ----------------------------------- | -------------------------------------------- | ------------------------------------------------------------- |
320
+ | ARIA (implicitRole, permittedRoles) | `rules/src/wai-aria/index.spec.ts` | `ml-spec/src/algorithm/aria/get-permitted-roles-spec.spec.ts` |
321
+ | Attributes (new/changed) | `rules/src/invalid-attr/index.spec.ts` | Existing tests with changed enum error messages |
322
+ | Content model | `rules/src/permitted-contents/index.spec.ts` | — |
323
+
324
+ ### Cross-Package Impact
325
+
326
+ - **Hardcoded role arrays**: `ml-spec/.../get-permitted-roles-spec.spec.ts` has
327
+ hardcoded `permittedRoles` for img, button, input, form, etc. Update these
328
+ when changing `permittedRoles` in html-spec.
329
+ - **Enum error messages**: Adding a value to an enum (e.g., button `command`)
330
+ changes the error message string in existing `invalid-attr` tests.
331
+
332
+ ### Test Conventions
333
+
334
+ - `toStrictEqual` with exact `{ severity, line, col, message, raw }` — never `toBeGreaterThan(0)`
335
+ - Always include both valid (empty violations) and invalid (exact violation) cases
336
+ - ARIA version in tests: `{ rule: { options: { version: '1.1' } } }`
337
+ - Some roles require ARIA attributes: focusable `separator` → `aria-valuenow`,
338
+ `meter` → `aria-valuenow`
339
+
340
+ ## Rules
341
+
342
+ 1. **`index.json` is generated -- never edit it directly.** Always modify `src/` files and regenerate.
343
+ 2. **Manual spec data takes precedence over MDN data.** Attributes defined in `src/spec.*.json` override same-named MDN-sourced attributes. Use this to correct inaccurate MDN data.
344
+ 3. **Minor MDN description changes should be committed as-is.** Do not attempt to override cosmetic upstream improvements.
345
+ 4. **Content model category membership is critical.** A missing element in a category causes `permitted-contents` rule false positives in downstream linting.
346
+ 5. **Always run tests after changes.** Schema validation catches structural errors before they propagate to downstream packages.
347
+ 6. **Reference authoritative specs for significant changes.** Use WebSearch to verify against HTML Living Standard, WAI-ARIA, and HTML-ARIA before modifying manual spec files.
348
+ 7. **Use conventional commit prefixes based on the nature of the change:**
349
+
350
+ | Change type | Prefix | Example |
351
+ | ------------------------ | ------- | ------------------------------------------------- |
352
+ | Description updates only | `chore` | `chore(html-spec): update role descriptions` |
353
+ | Attribute/spec additions | `feat` | `feat(html-spec): add input switch attribute` |
354
+ | Spec data corrections | `fix` | `fix(html-spec): correct ARIA mapping for button` |
355
+
356
+ 8. **Separate spec changes into individual PRs.** Each specification change (new attribute, ARIA mapping fix, etc.) should be on its own branch and PR. Description-only updates can be batched into a single PR.
357
+ 9. **Run `yarn test` (full suite) before committing.** Spec changes affect `@markuplint/rules` and `@markuplint/ml-spec` tests.
358
+ 10. **Keep `permittedRoles` arrays in alphabetical order.**