@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,331 @@
1
+ # メンテナンスガイド
2
+
3
+ ## 概要
4
+
5
+ このガイドでは、`@markuplint/ml-spec` の日常的な運用・メンテナンスタスクについて説明します。スキーマ生成、依存関係管理、テスト、よく使うレシピ、トラブルシューティングを対象とします。
6
+
7
+ ## ビルド・開発コマンド
8
+
9
+ | コマンド | スコープ | 説明 |
10
+ | ----------------------------------------------- | ---------- | -------------------------------------- |
11
+ | `yarn build --scope @markuplint/ml-spec` | パッケージ | TypeScript を `lib/` にコンパイル |
12
+ | `yarn workspace @markuplint/ml-spec run dev` | パッケージ | ウォッチモードコンパイル |
13
+ | `yarn workspace @markuplint/ml-spec run clean` | パッケージ | `lib/` 出力を削除 |
14
+ | `yarn workspace @markuplint/ml-spec run schema` | パッケージ | スキーマと型を再生成 |
15
+ | `yarn up:schema` | モノレポ | 全パッケージのスキーマを再生成(推奨) |
16
+ | `yarn test` | モノレポ | vitest で全テストを実行 |
17
+
18
+ ## スキーマ生成パイプライン
19
+
20
+ ### スキーマ生成が存在する理由
21
+
22
+ 本パッケージは JSON Schema ファイルを複雑な型構造(ARIA 定義、属性型、コンテンツモデル、グローバル属性)の唯一の情報源として使用しています。TypeScript 型はこれらのスキーマから `json-schema-to-typescript`(`json2ts`)によって自動生成されます。これにより:
23
+
24
+ - ランタイムで消費される JSON データファイルが、TypeScript 型と同じ構造に対して検証される。
25
+ - スキーマの変更が自動的に型定義に伝播する。
26
+ - `@markuplint/html-spec` の JSON データが型システムと一貫性を保つ。
27
+
28
+ ### 生成フロー
29
+
30
+ ```
31
+ gen/global-attribute.data.ts schemas/aria.schema.json
32
+ │ schemas/content-models.schema.json
33
+ ▼ │
34
+ gen/gen.ts │
35
+ │ │
36
+ ▼ ▼
37
+ schemas/global-attributes.schema.json │
38
+ schemas/attributes.schema.json │
39
+ │ │
40
+ └──────────┬───────────────────┘
41
+
42
+ json-schema-to-typescript
43
+
44
+ ┌──────────┼──────────────┐
45
+ ▼ ▼ ▼
46
+ types/aria.ts types/ types/permitted-
47
+ attributes.ts structures.ts
48
+
49
+
50
+ prettier + eslint
51
+ ```
52
+
53
+ ### スクリプトの内訳 (`yarn workspace @markuplint/ml-spec run schema`)
54
+
55
+ `schema` スクリプトは `run-s` による逐次パイプラインです:
56
+
57
+ ```
58
+ schema:json → schema:content-models → schema:attributes → schema:aria → schema:prettier → schema:eslint → schema:prettier
59
+ ```
60
+
61
+ | ステップ | コマンド | 入力 | 出力 |
62
+ | ----------------------- | ---------------------------------------------------------- | ------------------------------------ | ------------------------------------------------------------------------- |
63
+ | `schema:json` | `tsx ./gen/gen.ts` | `gen/global-attribute.data.ts` | `schemas/global-attributes.schema.json`, `schemas/attributes.schema.json` |
64
+ | `schema:content-models` | `json2ts ./schemas/content-models.schema.json` | `schemas/content-models.schema.json` | `src/types/permitted-structures.ts` |
65
+ | `schema:attributes` | `json2ts ./schemas/attributes.schema.json --cwd ./schemas` | `schemas/attributes.schema.json` | `src/types/attributes.ts` |
66
+ | `schema:aria` | `json2ts ./schemas/aria.schema.json --cwd ./schemas` | `schemas/aria.schema.json` | `src/types/aria.ts` |
67
+ | `schema:prettier` | `prettier --write` | `schemas/*.json`, `src/types/*.ts` | フォーマット済みファイル |
68
+ | `schema:eslint` | `eslint --fix` | `src/types/*.ts` | lint 修正済みファイル |
69
+
70
+ 注意: `schema:prettier` は **2回** 実行されます -- `schema:aria` の後に生成ファイルをフォーマットし、`schema:eslint` の後に eslint の自動修正によるフォーマット変更をクリーンアップします。
71
+
72
+ ### パッケージ間依存: `@markuplint/types`
73
+
74
+ `schemas/attributes.schema.json` は `@markuplint/types` への `$ref` を含みます:
75
+
76
+ ```json
77
+ {
78
+ "AttributeType": {
79
+ "$ref": "../../types/types.schema.json#/definitions/type"
80
+ }
81
+ }
82
+ ```
83
+
84
+ つまり、`@markuplint/types` が `@markuplint/ml-spec` **より先に**スキーマを再生成する必要があります。モノレポレベルの `yarn up:schema` はこの順序を自動的に処理します:
85
+
86
+ 1. `@markuplint/types` -- `types.schema.json` を生成し、パッケージをビルド
87
+ 2. `@markuplint/ml-spec` -- `types.schema.json` を参照するスキーマを生成
88
+ 3. `schema` スクリプトを持つその他のパッケージ
89
+
90
+ **パッケージ間参照を含むスキーマ更新時は、常にリポジトリルートから `yarn up:schema` を使用してください。**
91
+
92
+ ## ファイル分類: 編集可能 vs 生成
93
+
94
+ ### 直接編集してはいけないファイル
95
+
96
+ これらのファイルには「DO NOT MODIFY」ヘッダーがあり、生成パイプラインによって上書きされます:
97
+
98
+ | ファイル | 生成元 |
99
+ | --------------------------------------- | --------------------------------------------- |
100
+ | `src/types/aria.ts` | `schemas/aria.schema.json` |
101
+ | `src/types/attributes.ts` | `schemas/attributes.schema.json` |
102
+ | `src/types/permitted-structures.ts` | `schemas/content-models.schema.json` |
103
+ | `schemas/global-attributes.schema.json` | `gen/gen.ts` + `gen/global-attribute.data.ts` |
104
+ | `schemas/attributes.schema.json` | `gen/gen.ts` + `gen/global-attribute.data.ts` |
105
+
106
+ ### 生成出力を変更するために編集するファイル
107
+
108
+ | 変更したいもの | 編集するファイル | 実行コマンド |
109
+ | ---------------------------------------- | ---------------------------------------- | ----------------------------------------------- |
110
+ | グローバル属性カテゴリ/項目 | `gen/global-attribute.data.ts` | `yarn workspace @markuplint/ml-spec run schema` |
111
+ | `AttributeJSON` の形状(フィールド追加) | `gen/gen.ts`(`AttributeJSON` 定義部分) | `yarn workspace @markuplint/ml-spec run schema` |
112
+ | ARIA ロール/プロパティ構造 | `schemas/aria.schema.json` | `yarn workspace @markuplint/ml-spec run schema` |
113
+ | コンテンツモデルパターン | `schemas/content-models.schema.json` | `yarn workspace @markuplint/ml-spec run schema` |
114
+ | 属性値型(CSS キーワード等) | `@markuplint/types` パッケージ | `yarn up:schema`(ルートから) |
115
+
116
+ ### 直接編集するファイル(手書き)
117
+
118
+ | ファイル | 目的 |
119
+ | ----------------------------- | ---------------------------------------------------------- |
120
+ | `src/types/index.ts` | コア手書き型(`MLMLSpec`, `ElementSpec`, `ARIARole` など) |
121
+ | `src/algorithm/aria/*.ts` | ARIA アルゴリズム実装 |
122
+ | `src/algorithm/html/*.ts` | HTML アルゴリズム実装 |
123
+ | `src/utils/*.ts` | ユーティリティ関数 |
124
+ | `src/index.ts` | 公開 API エクスポート |
125
+ | `schemas/element.schema.json` | トップレベル要素スキーマ(手書き、11行) |
126
+
127
+ ## テスト
128
+
129
+ ### テストファイル
130
+
131
+ パッケージには vitest を使用する 18 のテストファイルがあります:
132
+
133
+ | ディレクトリ | テストファイル数 | カバレッジ |
134
+ | ----------------------------- | ---------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
135
+ | `src/algorithm/aria/` | 11 | `accname-computation`, `get-computed-aria-props`, `get-computed-role`, `get-implicit-role-spec`, `get-implicit-role`, `get-permitted-roles-spec`, `get-role-spec`, `has-required-owned-elements`, `is-exposed`, `matches-context-role` |
136
+ | `src/algorithm/aria/accname/` | 3 | `aria-steps`, `compute`, `element-names`, `label-steps` |
137
+ | `src/utils/` | 4 | `get-attr-specs-spec`, `get-spec-by-tag-name`, `resolve-namespace`, `resolve-version`, `schema-to-spec` |
138
+
139
+ ### テストの実行
140
+
141
+ ```bash
142
+ # モノレポ全体のテスト
143
+ yarn test
144
+
145
+ # ml-spec のテストのみ
146
+ yarn test packages/@markuplint/ml-spec
147
+
148
+ # 特定のテストファイル
149
+ yarn test packages/@markuplint/ml-spec/src/algorithm/aria/get-computed-role.spec.ts
150
+ ```
151
+
152
+ テストは `@markuplint/test-tools`(devDependency)に依存しており、テスト環境で DOM 要素を生成するための HTML パースユーティリティを提供します。
153
+
154
+ ## 依存関係管理
155
+
156
+ ### ランタイム依存
157
+
158
+ | パッケージ | バージョン | 目的 | 更新リスク |
159
+ | -------------------- | ---------- | ---------------------------------- | ------------------ |
160
+ | `@markuplint/ml-ast` | 4.4.10 | `NamespaceURI` 型 | 低(内部) |
161
+ | `@markuplint/types` | 4.8.1 | 属性値型の `Type` ユニオン | 中(スキーマ参照) |
162
+ | `is-plain-object` | 5.0.0 | AAM 情報のプレーンオブジェクト検出 | 低(安定 API) |
163
+ | `type-fest` | 4.41.0 | `ReadonlyDeep` ユーティリティ型 | 低(型のみ) |
164
+
165
+ ### 開発依存
166
+
167
+ | パッケージ | バージョン | 目的 |
168
+ | --------------------------- | ---------- | ---------------------------------- |
169
+ | `@markuplint/test-tools` | 4.5.22 | DOM 要素生成のテストユーティリティ |
170
+ | `json-schema-to-typescript` | 15.0.4 | スキーマ → TypeScript 型生成 |
171
+
172
+ ### 依存関係の更新
173
+
174
+ - **`json-schema-to-typescript`**: メジャーバージョン更新により、生成される型の出力が変わる場合があります(フォーマット、optional の扱い)。更新後は `yarn workspace @markuplint/ml-spec run schema` を実行し、`src/types/*.ts` の差分を確認してください。
175
+ - **`@markuplint/types`**: 更新後は必ず `yarn up:schema` を実行して、スキーマ参照の一貫性を確保してください。
176
+ - **`type-fest`**: 型のみの依存です。自由に更新できますが、ビルドが成功することを確認してください(`yarn build --scope @markuplint/ml-spec`)。
177
+
178
+ ## よく使うメンテナンスレシピ
179
+
180
+ ### 1. 新しいグローバル属性を追加する
181
+
182
+ `gen/global-attribute.data.ts` を編集し、適切なカテゴリ配列に属性名を追加します:
183
+
184
+ ```ts
185
+ '#HTMLGlobalAttrs': {
186
+ attrs: [
187
+ // ...既存の属性...
188
+ 'newattribute', // ← ここに追加
189
+ ],
190
+ },
191
+ ```
192
+
193
+ 再生成を実行:
194
+
195
+ ```bash
196
+ yarn workspace @markuplint/ml-spec run schema
197
+ ```
198
+
199
+ ### 2. 新しいグローバル属性カテゴリを追加する
200
+
201
+ `gen/global-attribute.data.ts` を編集し、新しいエントリを追加します:
202
+
203
+ ```ts
204
+ '#NewCategoryAttrs': {
205
+ description: '仕様リンク付きの説明',
206
+ attrs: ['attr1', 'attr2'],
207
+ },
208
+ ```
209
+
210
+ キーは `#${string}Attrs` パターンに一致する必要があります。ジェネレータ(`gen/gen.ts`)は `global-attributes.schema.json` と `attributes.schema.json` の両方で新しいカテゴリを自動的に処理します。
211
+
212
+ 再生成を実行:
213
+
214
+ ```bash
215
+ yarn workspace @markuplint/ml-spec run schema
216
+ ```
217
+
218
+ ### 3. `AttributeJSON` に新しいフィールドを追加する
219
+
220
+ `gen/gen.ts` を編集し、`AttributeJSON` 定義オブジェクト内にプロパティを追加します:
221
+
222
+ ```ts
223
+ AttributeJSON: {
224
+ properties: {
225
+ // ...既存のプロパティ...
226
+ newField: { type: 'boolean' }, // ← ここに追加
227
+ },
228
+ },
229
+ ```
230
+
231
+ 再生成すると、新しいフィールドが `src/types/attributes.ts` にオプショナルプロパティとして反映されます。
232
+
233
+ ### 4. ARIA ロール/プロパティスキーマを変更する
234
+
235
+ `schemas/aria.schema.json` を直接編集します。例えば、ロール定義に新しいフィールドを追加する場合:
236
+
237
+ ```json
238
+ {
239
+ "definitions": {
240
+ "role": {
241
+ "properties": {
242
+ "newField": { "type": "boolean" }
243
+ }
244
+ }
245
+ }
246
+ }
247
+ ```
248
+
249
+ 再生成すると、新しいフィールドが `src/types/aria.ts` に反映されます。
250
+
251
+ ### 5. 新しいコンテンツモデルカテゴリを追加する
252
+
253
+ `schemas/content-models.schema.json` を編集し、`Category` enum にカテゴリを追加してパターンを定義します。
254
+
255
+ ### 6. 新しい ARIA アルゴリズム関数を追加する
256
+
257
+ 1. `src/algorithm/aria/` に実装ファイルを作成。
258
+ 2. 対応する `.spec.ts` テストファイルを作成。
259
+ 3. `src/index.ts` から関数をエクスポート。
260
+ 4. `docs/aria-algorithms.md` と `docs/aria-algorithms.ja.md` を更新。
261
+
262
+ ### 7. W3C 仕様準拠を更新する
263
+
264
+ W3C 仕様が更新された場合(例: WAI-ARIA 1.3 が勧告になった場合):
265
+
266
+ 1. 要素レベルの ARIA マッピングが変更された場合、`@markuplint/html-spec` データを更新。
267
+ 2. アルゴリズムの動作が変更された場合、`src/algorithm/aria/*.ts` のアルゴリズム実装を更新。
268
+ 3. 新しい ARIA バージョンが追加された場合、`src/utils/aria-version.ts` を更新。
269
+ 4. `yarn up:schema` を実行して型を再生成。
270
+ 5. テストを実行して準拠を確認。
271
+
272
+ ## キャッシュの考慮事項
273
+
274
+ パッケージは複数のランタイムキャッシュを使用しており、**プロセスのライフタイム中は無効化されません**。これは markuplint の単発実行リントモデルでは安全ですが、以下の点に注意してください:
275
+
276
+ | キャッシュ場所 | スコープ | 備考 |
277
+ | --------------------------------------------- | ----------------------------------------------- | -------------------------- |
278
+ | `getARIA()` 内部キャッシュ | `Map`(`localName + namespace + version` キー) | プロセス再起動時のみクリア |
279
+ | `getSpecByTagName()` キャッシュ | `Map`(`namespace:localName` キー) | specs インスタンスごと |
280
+ | `getContentModel()` キャッシュ | `WeakMap<Element, ...>` | 要素ごと、GC セーフ |
281
+ | `contentModelCategoryToTagNames()` キャッシュ | モジュールレベル `Map<Category, string[]>` | グローバル、無効化なし |
282
+ | `getAttrSpecs()` キャッシュ | `WeakSet` + `Map`(スキーマごと) | 新しいスキーマでリセット |
283
+ | `resolveNamespace()` キャッシュ | モジュールレベル `Map` | グローバル、無効化なし |
284
+
285
+ コストの高い結果を計算する新しいアルゴリズム関数を追加する場合は、要素 + specs + version をキーとする同様のキャッシュ戦略の追加を検討してください。
286
+
287
+ ## バージョニングポリシー
288
+
289
+ - HTML Schema/Specs は markuplint の公開 API サーフェスの**一部ではありません**。
290
+ - スキーマ、生成型、アルゴリズム動作の変更は**マイナーリリース**として扱われます。
291
+ - パブリッシュは通常のリリースプロセスで Lerna によって処理されます。
292
+ - `package.json` の `version` フィールドは Lerna によって管理されます -- 手動で更新しないでください。
293
+
294
+ ## トラブルシューティング
295
+
296
+ ### スキーマ生成が `$ref` エラーで失敗する
297
+
298
+ **症状:** `json2ts` が `schema:attributes` 実行中に未解決の `$ref` を報告する。
299
+
300
+ **原因:** `../../types/types.schema.json` への `$ref` は、`@markuplint/types` が先にスキーマを生成している必要がある。
301
+
302
+ **対処:** パッケージレベルの `schema` スクリプトの代わりに、リポジトリルートから `yarn up:schema` を実行してください。
303
+
304
+ ### `json-schema-to-typescript` 更新後に生成型が異なる
305
+
306
+ **症状:** `json-schema-to-typescript` の更新後、`src/types/*.ts` に予期しない変更がある。
307
+
308
+ **原因:** 新しいバージョンがフォーマット、optional の扱い、型生成戦略を変更した可能性がある。
309
+
310
+ **対処:** 差分を注意深く確認してください。型が意味的に同等であれば、変更をコミットしてください。動作が変わった場合(例: 以前 optional だったフィールドが required になった)、`json-schema-to-typescript` のチェンジログを調査してください。
311
+
312
+ ### ビルドエラー: 生成型の不一致
313
+
314
+ **症状:** `src/types/aria.ts`、`attributes.ts`、`permitted-structures.ts` の型を参照する TypeScript ビルドエラー。
315
+
316
+ **原因:** JSON スキーマが編集されたが型が再生成されていない、またはパッケージ間のスキーマ参照が古い。
317
+
318
+ **対処:**
319
+
320
+ ```bash
321
+ yarn up:schema
322
+ yarn build --scope @markuplint/ml-spec
323
+ ```
324
+
325
+ ### 長時間実行プロセスでのキャッシュ関連の問題
326
+
327
+ **症状:** 異なる設定で複数のリント実行を同じ Node.js プロセスで再利用した際に、古いデータが返される。
328
+
329
+ **原因:** モジュールレベルのキャッシュ(`contentModelCategoryToTagNames`、`resolveNamespace`)は無効化されない。
330
+
331
+ **対処:** これは markuplint の単発実行モデルのための設計です。markuplint を長時間実行プロセス(例: 言語サーバー)に組み込む場合、スペックデータは最初のアクセス時にキャッシュされることに注意してください。プロセスの再起動で全キャッシュがクリアされます。
@@ -0,0 +1,331 @@
1
+ # Maintenance Guide
2
+
3
+ ## Overview
4
+
5
+ This guide covers the day-to-day operational and maintenance tasks for `@markuplint/ml-spec`. It focuses on schema generation, dependency management, testing, common recipes, and troubleshooting.
6
+
7
+ ## Build and Development Commands
8
+
9
+ | Command | Scope | Description |
10
+ | ----------------------------------------------- | -------- | ---------------------------------------------------- |
11
+ | `yarn build --scope @markuplint/ml-spec` | Package | Compile TypeScript to `lib/` |
12
+ | `yarn workspace @markuplint/ml-spec run dev` | Package | Watch mode compilation |
13
+ | `yarn workspace @markuplint/ml-spec run clean` | Package | Remove `lib/` output |
14
+ | `yarn workspace @markuplint/ml-spec run schema` | Package | Regenerate schemas and types |
15
+ | `yarn up:schema` | Monorepo | Regenerate schemas across all packages (recommended) |
16
+ | `yarn test` | Monorepo | Run all tests via vitest |
17
+
18
+ ## Schema Generation Pipeline
19
+
20
+ ### Why schema generation exists
21
+
22
+ The package uses JSON Schema files as a single source of truth for complex type structures (ARIA definitions, attribute types, content models, global attributes). TypeScript types are auto-generated from these schemas via `json-schema-to-typescript` (`json2ts`). This ensures that:
23
+
24
+ - JSON data files consumed at runtime are validated against the same structure as TypeScript types.
25
+ - Schema changes automatically propagate to type definitions.
26
+ - The `@markuplint/html-spec` JSON data stays consistent with the type system.
27
+
28
+ ### Generation flow
29
+
30
+ ```
31
+ gen/global-attribute.data.ts schemas/aria.schema.json
32
+ │ schemas/content-models.schema.json
33
+ ▼ │
34
+ gen/gen.ts │
35
+ │ │
36
+ ▼ ▼
37
+ schemas/global-attributes.schema.json │
38
+ schemas/attributes.schema.json │
39
+ │ │
40
+ └──────────┬───────────────────┘
41
+
42
+ json-schema-to-typescript
43
+
44
+ ┌──────────┼──────────────┐
45
+ ▼ ▼ ▼
46
+ types/aria.ts types/ types/permitted-
47
+ attributes.ts structures.ts
48
+
49
+
50
+ prettier + eslint
51
+ ```
52
+
53
+ ### Script breakdown (`yarn workspace @markuplint/ml-spec run schema`)
54
+
55
+ The `schema` script is a sequential pipeline using `run-s`:
56
+
57
+ ```
58
+ schema:json → schema:content-models → schema:attributes → schema:aria → schema:prettier → schema:eslint → schema:prettier
59
+ ```
60
+
61
+ | Step | Command | Input | Output |
62
+ | ----------------------- | ---------------------------------------------------------- | ------------------------------------ | ------------------------------------------------------------------------- |
63
+ | `schema:json` | `tsx ./gen/gen.ts` | `gen/global-attribute.data.ts` | `schemas/global-attributes.schema.json`, `schemas/attributes.schema.json` |
64
+ | `schema:content-models` | `json2ts ./schemas/content-models.schema.json` | `schemas/content-models.schema.json` | `src/types/permitted-structures.ts` |
65
+ | `schema:attributes` | `json2ts ./schemas/attributes.schema.json --cwd ./schemas` | `schemas/attributes.schema.json` | `src/types/attributes.ts` |
66
+ | `schema:aria` | `json2ts ./schemas/aria.schema.json --cwd ./schemas` | `schemas/aria.schema.json` | `src/types/aria.ts` |
67
+ | `schema:prettier` | `prettier --write` | `schemas/*.json`, `src/types/*.ts` | Formatted files |
68
+ | `schema:eslint` | `eslint --fix` | `src/types/*.ts` | Lint-fixed files |
69
+
70
+ Note: `schema:prettier` runs **twice** -- once after `schema:aria` to format generated files, then again after `schema:eslint` to clean up any eslint auto-fix formatting changes.
71
+
72
+ ### Cross-package dependency: `@markuplint/types`
73
+
74
+ `schemas/attributes.schema.json` contains a `$ref` to `@markuplint/types`:
75
+
76
+ ```json
77
+ {
78
+ "AttributeType": {
79
+ "$ref": "../../types/types.schema.json#/definitions/type"
80
+ }
81
+ }
82
+ ```
83
+
84
+ This means `@markuplint/types` must regenerate its schema **before** `@markuplint/ml-spec`. The monorepo-level `yarn up:schema` handles this order automatically:
85
+
86
+ 1. `@markuplint/types` -- generates `types.schema.json`, builds the package
87
+ 2. `@markuplint/ml-spec` -- generates schemas referencing `types.schema.json`
88
+ 3. Other packages with `schema` scripts
89
+
90
+ **Always prefer `yarn up:schema` from the repository root** when updating schemas that may involve cross-package references.
91
+
92
+ ## File Classification: Editable vs Generated
93
+
94
+ ### Files you MUST NOT edit directly
95
+
96
+ These files carry "DO NOT MODIFY" headers and are overwritten by the generation pipeline:
97
+
98
+ | File | Generated from |
99
+ | --------------------------------------- | --------------------------------------------- |
100
+ | `src/types/aria.ts` | `schemas/aria.schema.json` |
101
+ | `src/types/attributes.ts` | `schemas/attributes.schema.json` |
102
+ | `src/types/permitted-structures.ts` | `schemas/content-models.schema.json` |
103
+ | `schemas/global-attributes.schema.json` | `gen/gen.ts` + `gen/global-attribute.data.ts` |
104
+ | `schemas/attributes.schema.json` | `gen/gen.ts` + `gen/global-attribute.data.ts` |
105
+
106
+ ### Files you edit to change generated output
107
+
108
+ | To change... | Edit this file | Then run |
109
+ | ------------------------------------------ | --------------------------------------------- | ----------------------------------------------- |
110
+ | Global attribute categories/items | `gen/global-attribute.data.ts` | `yarn workspace @markuplint/ml-spec run schema` |
111
+ | `AttributeJSON` shape (add field) | `gen/gen.ts` (the `AttributeJSON` definition) | `yarn workspace @markuplint/ml-spec run schema` |
112
+ | ARIA role/property structure | `schemas/aria.schema.json` | `yarn workspace @markuplint/ml-spec run schema` |
113
+ | Content model patterns | `schemas/content-models.schema.json` | `yarn workspace @markuplint/ml-spec run schema` |
114
+ | Attribute value types (CSS keywords, etc.) | `@markuplint/types` package | `yarn up:schema` (from root) |
115
+
116
+ ### Files you edit directly (hand-written)
117
+
118
+ | File | Purpose |
119
+ | ----------------------------- | --------------------------------------------------------------------- |
120
+ | `src/types/index.ts` | Core hand-written types (`MLMLSpec`, `ElementSpec`, `ARIARole`, etc.) |
121
+ | `src/algorithm/aria/*.ts` | ARIA algorithm implementations |
122
+ | `src/algorithm/html/*.ts` | HTML algorithm implementations |
123
+ | `src/utils/*.ts` | Utility functions |
124
+ | `src/index.ts` | Public API exports |
125
+ | `schemas/element.schema.json` | Top-level element schema (manual, 11 lines) |
126
+
127
+ ## Testing
128
+
129
+ ### Test files
130
+
131
+ The package has 18 test files using vitest:
132
+
133
+ | Directory | Test files | Coverage |
134
+ | ----------------------------- | ---------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
135
+ | `src/algorithm/aria/` | 11 | `accname-computation`, `get-computed-aria-props`, `get-computed-role`, `get-implicit-role-spec`, `get-implicit-role`, `get-permitted-roles-spec`, `get-role-spec`, `has-required-owned-elements`, `is-exposed`, `matches-context-role` |
136
+ | `src/algorithm/aria/accname/` | 3 | `aria-steps`, `compute`, `element-names`, `label-steps` |
137
+ | `src/utils/` | 4 | `get-attr-specs-spec`, `get-spec-by-tag-name`, `resolve-namespace`, `resolve-version`, `schema-to-spec` |
138
+
139
+ ### Running tests
140
+
141
+ ```bash
142
+ # All tests in the monorepo
143
+ yarn test
144
+
145
+ # Only ml-spec tests
146
+ yarn test packages/@markuplint/ml-spec
147
+
148
+ # Specific test file
149
+ yarn test packages/@markuplint/ml-spec/src/algorithm/aria/get-computed-role.spec.ts
150
+ ```
151
+
152
+ Tests depend on `@markuplint/test-tools` (devDependency) which provides HTML parsing utilities for creating DOM elements in test environments.
153
+
154
+ ## Dependency Management
155
+
156
+ ### Runtime dependencies
157
+
158
+ | Package | Version | Purpose | Update risk |
159
+ | -------------------- | ------- | -------------------------------------- | ------------------------- |
160
+ | `@markuplint/ml-ast` | 4.4.10 | `NamespaceURI` type | Low (internal) |
161
+ | `@markuplint/types` | 4.8.1 | `Type` union for attribute value types | Medium (schema reference) |
162
+ | `is-plain-object` | 5.0.0 | Plain object detection for AAM info | Low (stable API) |
163
+ | `type-fest` | 4.41.0 | `ReadonlyDeep` utility type | Low (types only) |
164
+
165
+ ### Dev dependencies
166
+
167
+ | Package | Version | Purpose |
168
+ | --------------------------- | ------- | --------------------------------------- |
169
+ | `@markuplint/test-tools` | 4.5.22 | Test utilities for DOM element creation |
170
+ | `json-schema-to-typescript` | 15.0.4 | Schema → TypeScript type generation |
171
+
172
+ ### Updating dependencies
173
+
174
+ - **`json-schema-to-typescript`**: Major version updates may change generated type output (formatting, optional handling). After updating, run `yarn workspace @markuplint/ml-spec run schema` and review diffs in `src/types/*.ts`.
175
+ - **`@markuplint/types`**: Always run `yarn up:schema` after updating to ensure schema references stay consistent.
176
+ - **`type-fest`**: Type-only dependency. Update freely, but verify the build succeeds (`yarn build --scope @markuplint/ml-spec`).
177
+
178
+ ## Common Maintenance Recipes
179
+
180
+ ### 1. Add a new global attribute
181
+
182
+ Edit `gen/global-attribute.data.ts`, add the attribute name to the appropriate category array:
183
+
184
+ ```ts
185
+ '#HTMLGlobalAttrs': {
186
+ attrs: [
187
+ // ...existing attributes...
188
+ 'newattribute', // ← add here
189
+ ],
190
+ },
191
+ ```
192
+
193
+ Then regenerate:
194
+
195
+ ```bash
196
+ yarn workspace @markuplint/ml-spec run schema
197
+ ```
198
+
199
+ ### 2. Add a new global attribute category
200
+
201
+ Edit `gen/global-attribute.data.ts`, add a new entry:
202
+
203
+ ```ts
204
+ '#NewCategoryAttrs': {
205
+ description: 'Description with spec link',
206
+ attrs: ['attr1', 'attr2'],
207
+ },
208
+ ```
209
+
210
+ The key must match the pattern `#${string}Attrs`. The generator (`gen/gen.ts`) automatically handles the new category in both `global-attributes.schema.json` and `attributes.schema.json`.
211
+
212
+ Then regenerate:
213
+
214
+ ```bash
215
+ yarn workspace @markuplint/ml-spec run schema
216
+ ```
217
+
218
+ ### 3. Add a new field to `AttributeJSON`
219
+
220
+ Edit `gen/gen.ts`, add the property inside the `AttributeJSON` definition object:
221
+
222
+ ```ts
223
+ AttributeJSON: {
224
+ properties: {
225
+ // ...existing properties...
226
+ newField: { type: 'boolean' }, // ← add here
227
+ },
228
+ },
229
+ ```
230
+
231
+ Then regenerate. The new field will appear in `src/types/attributes.ts` as an optional property.
232
+
233
+ ### 4. Modify ARIA role/property schema
234
+
235
+ Edit `schemas/aria.schema.json` directly. For example, to add a new field to the role definition:
236
+
237
+ ```json
238
+ {
239
+ "definitions": {
240
+ "role": {
241
+ "properties": {
242
+ "newField": { "type": "boolean" }
243
+ }
244
+ }
245
+ }
246
+ }
247
+ ```
248
+
249
+ Then regenerate. The new field will appear in `src/types/aria.ts`.
250
+
251
+ ### 5. Add a new content model category
252
+
253
+ Edit `schemas/content-models.schema.json`, add the category to the `Category` enum and define its pattern.
254
+
255
+ ### 6. Add a new ARIA algorithm function
256
+
257
+ 1. Create the implementation file in `src/algorithm/aria/`.
258
+ 2. Create a corresponding `.spec.ts` test file.
259
+ 3. Export the function from `src/index.ts`.
260
+ 4. Update `docs/aria-algorithms.md` and `docs/aria-algorithms.ja.md`.
261
+
262
+ ### 7. Update W3C specification compliance
263
+
264
+ When a W3C specification updates (e.g., WAI-ARIA 1.3 becomes a Recommendation):
265
+
266
+ 1. Update `@markuplint/html-spec` data if element-level ARIA mappings changed.
267
+ 2. Update algorithm implementations in `src/algorithm/aria/*.ts` if algorithm behavior changed.
268
+ 3. Update `src/utils/aria-version.ts` if a new ARIA version is added.
269
+ 4. Run `yarn up:schema` to regenerate types.
270
+ 5. Run tests to verify compliance.
271
+
272
+ ## Caching Considerations
273
+
274
+ The package uses several runtime caches that are **never invalidated during a process lifetime**. This is safe for markuplint's single-run lint model, but be aware of it when:
275
+
276
+ | Cache location | Scope | Notes |
277
+ | ---------------------------------------- | ------------------------------------------------ | ------------------------------- |
278
+ | `getARIA()` internal cache | `Map` keyed by `localName + namespace + version` | Cleared only on process restart |
279
+ | `getSpecByTagName()` cache | `Map` keyed by `namespace:localName` | Per-specs instance |
280
+ | `getContentModel()` cache | `WeakMap<Element, ...>` | Per-element, GC-safe |
281
+ | `contentModelCategoryToTagNames()` cache | Module-level `Map<Category, string[]>` | Global, never invalidated |
282
+ | `getAttrSpecs()` cache | `WeakSet` + `Map` per schema | New schema resets cache |
283
+ | `resolveNamespace()` cache | Module-level `Map` | Global, never invalidated |
284
+
285
+ If you add a new algorithm function that computes expensive results, consider adding a similar caching strategy keyed by element + specs + version.
286
+
287
+ ## Versioning Policy
288
+
289
+ - HTML Schema/Specs are **not** part of the public API surface of markuplint.
290
+ - Changes to schemas, generated types, or algorithm behavior are treated as a **minor release**.
291
+ - Publishing is handled by Lerna during the normal release process.
292
+ - The `version` field in `package.json` is managed by Lerna -- do not manually update it.
293
+
294
+ ## Troubleshooting
295
+
296
+ ### Schema generation fails with `$ref` error
297
+
298
+ **Symptom:** `json2ts` reports an unresolved `$ref` during `schema:attributes`.
299
+
300
+ **Cause:** The `$ref` to `../../types/types.schema.json` requires `@markuplint/types` to have generated its schema first.
301
+
302
+ **Fix:** Run `yarn up:schema` from the repository root instead of the package-level `schema` script.
303
+
304
+ ### Generated types differ after `json-schema-to-typescript` update
305
+
306
+ **Symptom:** After updating `json-schema-to-typescript`, `src/types/*.ts` has unexpected changes.
307
+
308
+ **Cause:** New versions may change formatting, optional handling, or type generation strategy.
309
+
310
+ **Fix:** Review the diff carefully. If the types are semantically equivalent, commit the changes. If behavior changed (e.g., previously optional fields became required), investigate the `json-schema-to-typescript` changelog.
311
+
312
+ ### Build error: generated type mismatch
313
+
314
+ **Symptom:** TypeScript build errors referencing types in `src/types/aria.ts`, `attributes.ts`, or `permitted-structures.ts`.
315
+
316
+ **Cause:** The JSON schema was edited but types were not regenerated, or a cross-package schema reference is stale.
317
+
318
+ **Fix:**
319
+
320
+ ```bash
321
+ yarn up:schema
322
+ yarn build --scope @markuplint/ml-spec
323
+ ```
324
+
325
+ ### Cache-related issues in long-running processes
326
+
327
+ **Symptom:** Stale data when reusing the same Node.js process across multiple lint runs with different configurations.
328
+
329
+ **Cause:** Module-level caches (`contentModelCategoryToTagNames`, `resolveNamespace`) are never invalidated.
330
+
331
+ **Fix:** This is by design for markuplint's single-run model. If you embed markuplint in a long-running process (e.g., a language server), be aware that spec data is cached at first access. Restarting the process clears all caches.