@markuplint/ml-core 4.13.2 → 5.0.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (92) hide show
  1. package/ARCHITECTURE.ja.md +524 -0
  2. package/ARCHITECTURE.md +524 -0
  3. package/CHANGELOG.md +52 -2
  4. package/README.md +5 -0
  5. package/SKILL.md +61 -0
  6. package/docs/linting-pipeline.ja.md +307 -0
  7. package/docs/linting-pipeline.md +307 -0
  8. package/docs/maintenance.ja.md +210 -0
  9. package/docs/maintenance.md +210 -0
  10. package/docs/ml-dom/attr.ja.md +103 -0
  11. package/docs/ml-dom/attr.md +103 -0
  12. package/docs/ml-dom/block.ja.md +272 -0
  13. package/docs/ml-dom/block.md +272 -0
  14. package/docs/ml-dom/document.ja.md +141 -0
  15. package/docs/ml-dom/document.md +141 -0
  16. package/docs/ml-dom/element.ja.md +176 -0
  17. package/docs/ml-dom/element.md +176 -0
  18. package/docs/ml-dom/helpers.ja.md +203 -0
  19. package/docs/ml-dom/helpers.md +203 -0
  20. package/docs/ml-dom/node.ja.md +199 -0
  21. package/docs/ml-dom/node.md +199 -0
  22. package/docs/ml-dom/others.ja.md +120 -0
  23. package/docs/ml-dom/others.md +120 -0
  24. package/docs/ml-dom/overview.ja.md +102 -0
  25. package/docs/ml-dom/overview.md +102 -0
  26. package/docs/ml-dom/pretender.ja.md +269 -0
  27. package/docs/ml-dom/pretender.md +269 -0
  28. package/docs/ml-dom/rule-mapping.ja.md +371 -0
  29. package/docs/ml-dom/rule-mapping.md +371 -0
  30. package/docs/ml-dom.ja.md +18 -0
  31. package/docs/ml-dom.md +18 -0
  32. package/docs/rule-system.ja.md +287 -0
  33. package/docs/rule-system.md +287 -0
  34. package/lib/convert-ruleset.d.ts +7 -0
  35. package/lib/convert-ruleset.js +7 -0
  36. package/lib/debug.d.ts +4 -0
  37. package/lib/debug.js +4 -0
  38. package/lib/index.d.ts +4 -3
  39. package/lib/index.js +1 -1
  40. package/lib/ml-core.d.ts +37 -1
  41. package/lib/ml-core.js +171 -82
  42. package/lib/ml-dom/helper/accname.d.ts +8 -0
  43. package/lib/ml-dom/helper/accname.js +71 -55
  44. package/lib/ml-dom/helper/create-node.js +1 -0
  45. package/lib/ml-dom/helper/get-indent.d.ts +4 -1
  46. package/lib/ml-dom/helper/get-indent.js +21 -30
  47. package/lib/ml-dom/node/attr.d.ts +65 -4
  48. package/lib/ml-dom/node/attr.js +151 -53
  49. package/lib/ml-dom/node/block.d.ts +23 -2
  50. package/lib/ml-dom/node/block.js +24 -1
  51. package/lib/ml-dom/node/child-node.d.ts +9 -0
  52. package/lib/ml-dom/node/child-node.js +9 -0
  53. package/lib/ml-dom/node/comment.d.ts +7 -0
  54. package/lib/ml-dom/node/comment.js +7 -0
  55. package/lib/ml-dom/node/document-fragment.d.ts +8 -0
  56. package/lib/ml-dom/node/document-fragment.js +8 -0
  57. package/lib/ml-dom/node/document-type.d.ts +22 -0
  58. package/lib/ml-dom/node/document-type.js +25 -0
  59. package/lib/ml-dom/node/document.d.ts +88 -7
  60. package/lib/ml-dom/node/document.js +128 -32
  61. package/lib/ml-dom/node/dom-token-list.js +17 -30
  62. package/lib/ml-dom/node/element-close-tag.js +1 -0
  63. package/lib/ml-dom/node/element.d.ts +151 -5
  64. package/lib/ml-dom/node/element.js +242 -50
  65. package/lib/ml-dom/node/node-store.js +6 -15
  66. package/lib/ml-dom/node/node.d.ts +19 -1
  67. package/lib/ml-dom/node/node.js +175 -166
  68. package/lib/ml-dom/node/parent-node.js +14 -30
  69. package/lib/ml-dom/node/rule-mapper.js +7 -20
  70. package/lib/ml-dom/node/text.d.ts +19 -0
  71. package/lib/ml-dom/node/text.js +21 -0
  72. package/lib/ml-dom/node/types.d.ts +68 -0
  73. package/lib/ml-dom/token/token.d.ts +42 -0
  74. package/lib/ml-dom/token/token.js +59 -39
  75. package/lib/ml-rule/create-rule.d.ts +17 -1
  76. package/lib/ml-rule/ml-rule-context.js +7 -11
  77. package/lib/ml-rule/ml-rule.d.ts +66 -1
  78. package/lib/ml-rule/ml-rule.js +95 -25
  79. package/lib/ml-rule/types.d.ts +41 -0
  80. package/lib/plugin/plugin.d.ts +8 -0
  81. package/lib/plugin/plugin.js +8 -0
  82. package/lib/plugin/types.d.ts +21 -0
  83. package/lib/ruleset/index.d.ts +10 -0
  84. package/lib/ruleset/index.js +13 -0
  85. package/lib/test/index.d.ts +42 -1
  86. package/lib/test/index.js +39 -2
  87. package/lib/types.d.ts +10 -1
  88. package/lib/violation-collector.d.ts +33 -0
  89. package/lib/violation-collector.js +48 -28
  90. package/lib/virtual-rule.d.ts +72 -0
  91. package/lib/virtual-rule.js +233 -0
  92. package/package.json +16 -13
@@ -0,0 +1,307 @@
1
+ # リンティングパイプライン
2
+
3
+ `@markuplint/ml-core` の MLCore リンティングエンジンの詳細リファレンスです。
4
+
5
+ ## 概要
6
+
7
+ `MLCore` はパース、DOM 構築、ルール実行、違反収集を接続するオーケストレーションエンジンです。パイプラインのフロー:
8
+
9
+ ```
10
+ ソースコード → パーサー → MLASTDocument → MLDocument → ルール検証 → 違反
11
+ ```
12
+
13
+ ## MLCore クラス
14
+
15
+ ソース: `src/ml-core.ts`
16
+
17
+ ### コンストラクタ
18
+
19
+ ```typescript
20
+ constructor(params: MLCoreParams)
21
+ ```
22
+
23
+ `MLCoreParams` は `MLFabric` を以下で拡張します:
24
+
25
+ | パラメータ | 型 | 説明 |
26
+ | ------------ | --------- | ---------------------- |
27
+ | `sourceCode` | `string` | リントするソースコード |
28
+ | `filename` | `string` | ソースファイル名 |
29
+ | `debug` | `boolean` | デバッグログの有効化 |
30
+
31
+ ### MLFabric
32
+
33
+ `MLFabric` 型はリンティング設定全体を定義します:
34
+
35
+ | フィールド | 型 | 説明 |
36
+ | -------------------- | --------------------------------- | ----------------------------------------------------- |
37
+ | `parser` | `MLParser` | パーサーインスタンス(例:`@markuplint/html-parser`) |
38
+ | `ruleset` | `Ruleset` | 解決済みルール設定 |
39
+ | `rules` | `readonly MLRule[]` | ルールインスタンスの配列 |
40
+ | `locale` | `LocaleSet` | 違反メッセージのロケール |
41
+ | `schemas` | `MLSchema` | HTML/ARIA 仕様タプル |
42
+ | `parserOptions` | `ParserOptions` | パーサー設定オプション |
43
+ | `severity` | `{ parseError?: SeverityOption }` | 重大度オーバーライド |
44
+ | `pretenders` | `readonly Pretender[]` | コンポーネントから HTML へのマッピング |
45
+ | `ruleCommonSettings` | `RuleCommonSettings` | すべてのルールにグローバルに適用される共通設定 |
46
+ | `configErrors` | `readonly ConfigError[]` | 報告する設定エラー |
47
+
48
+ ### プロパティ
49
+
50
+ | プロパティ | 型 | 説明 |
51
+ | ---------- | --------------------------- | ------------------------------------------ |
52
+ | `document` | `MLDocument \| ParserError` | パースされたドキュメントまたはパースエラー |
53
+
54
+ ### 構築フロー
55
+
56
+ 1. **Named nodeRule の展開** — `expandNamedNodeRules()` が `nodeRules` と `childNodeRules` の名前付きエントリを仮想 `MLRule` インスタンスに変換。展開前のオリジナルは `#originalNodeRules` / `#originalChildNodeRules` にホットリロード用に保持。名前空間 disable プレフィックスはワイルドカードエントリ(例: `"a11y/*": false`)から事前計算される。
57
+ 2. `_parse()` — `parser.parse(sourceCode, parserOptions)` を呼び出して `MLASTDocument` を生成
58
+ 3. `_createDocument()` — AST を `MLDocument` でラップ(ruleset、schemas、オプション付き)
59
+
60
+ パースが失敗した場合、`document` は `MLDocument` の代わりに `ParserError` を保持します。
61
+
62
+ ## パースフェーズ
63
+
64
+ ### `_parse()`
65
+
66
+ `parser.parse(sourceCode, parserOptions)` を呼び出し、`MLASTDocument` を返します。
67
+
68
+ パーサーがスローした場合:
69
+
70
+ - エラーが `ParserError` としてキャッチされる
71
+ - `document` に `ParserError` オブジェクトが設定される
72
+ - `verify()` が後でこれを `Violation` に変換
73
+
74
+ ## ドキュメント作成フェーズ
75
+
76
+ ### `_createDocument()`
77
+
78
+ パースされた AST から `MLDocument` を作成します:
79
+
80
+ ```typescript
81
+ new Document(ast, ruleset, schemas, ruleCommonSettings, {
82
+ filename,
83
+ endTag,
84
+ booleanish,
85
+ tagNameCaseSensitive,
86
+ pretenders,
87
+ });
88
+ ```
89
+
90
+ 構築時に `MLDocument` は:
91
+
92
+ 1. AST を走査してフラットな `nodeList` を構築
93
+ 2. `RuleMapper` を初期化してルール設定を配布
94
+ 3. pretender 定義が存在する場合、pretender コンテキストをセットアップ
95
+
96
+ ## 検証フェーズ
97
+
98
+ ### `verify(fix?): Promise<Violation[]>`
99
+
100
+ メインのリンティングメソッド。違反の配列を返します。
101
+
102
+ **フロー:**
103
+
104
+ ```mermaid
105
+ flowchart TD
106
+ A["verify(fix?)"] --> B{パースエラー?}
107
+ B -->|はい| C["_createParseError()\n→ Violation"]
108
+ B -->|いいえ| D["未定義ルールチェック"]
109
+ D --> E["configErrors を報告"]
110
+ E --> F["各ルールに対して:"]
111
+ F --> G["getRuleInfo(ruleset, rule.name)"]
112
+ G --> H{無効かつ\nオーバーライドなし?}
113
+ H -->|はい| I["スキップ"]
114
+ H -->|いいえ| J["rule.verify(document, locale, fix)"]
115
+ J --> K{ParserError?}
116
+ K -->|はい| L["キャッチ → Violation"]
117
+ K -->|いいえ| M["違反を収集"]
118
+ M --> N["カウントをログ"]
119
+ N --> O["Violation[] を返す"]
120
+ C --> O
121
+ ```
122
+
123
+ ### ステップごとの説明
124
+
125
+ 1. **パースエラーチェック**: `document` が `ParserError` の場合、単一の違反を作成して返す
126
+ 2. **未定義ルールの検出**: `setRuleNames`(設定内のルール)と `definedRuleName`(実際にロードされたルール)を比較。未定義ルールに対して `config-error` 警告を報告
127
+ 3. **設定エラー**: `configErrors` 配列を違反に変換
128
+ 4. **ルールループ**: 各ルールに対して:
129
+ - **仮想ルールの無効化チェック** — `rule.baseRuleId` がある場合、3つの条件を確認: 完全一致(`rules["alias"]: false`)、グループ無効化(`rules["groupName"]: false`)、名前空間ワイルドカード(`rules["scope/*"]: false`)。いずれかに該当した場合はスキップ。
130
+ - `rule.getRuleInfo(ruleset, rule.name)` で有効性をチェック
131
+ - `disabled && nodeRules.length === 0 && childNodeRules.length === 0` → スキップ
132
+ - `rule.verify(document, locale, fix)` — ルールを実行
133
+ - 検証中にスローされた `ParserError` をキャッチ
134
+ 5. **結果ログ**: デバッグ経由で error/warning/info カウントをログ出力
135
+
136
+ ### パースエラーの重大度
137
+
138
+ `severity.parseError` が設定されている場合:
139
+
140
+ | 設定 | 動作 |
141
+ | ---------------------- | ------------------------------ |
142
+ | `false` または `'off'` | パースエラーを抑制(違反なし) |
143
+ | `true` または `null` | `'error'` 重大度として報告 |
144
+ | Severity 値 | その重大度で報告 |
145
+
146
+ ## 更新と再パース
147
+
148
+ ### `setCode(sourceCode)`
149
+
150
+ 新しいソースコードで再パース:
151
+
152
+ 1. 保存されたソースコードを更新
153
+ 2. `_parse()` を呼び出して新しい AST を生成
154
+ 3. `_createDocument()` を呼び出して MLDOM を再構築
155
+
156
+ ### `update(partial<MLFabric>)`
157
+
158
+ リンティング設定の部分更新:
159
+
160
+ - Named nodeRules を仮想ルールに再展開。`ruleset` が提供されていない場合、`#originalNodeRules` / `#originalChildNodeRules`(展開前のコピー)をソースとして使用し、仮想ルール化で変換済みのエントリを失うことを防ぐ。
161
+ - `parserOptions` が変更された場合 → 完全な再パース(`_parse()` + `_createDocument()`)
162
+ - それ以外 → `_createDocument()` のみ(既存の AST を再利用)
163
+
164
+ この最適化により、ルールや設定のみの変更時に不要な再パースを回避します。
165
+
166
+ ## ViolationCollector
167
+
168
+ ソース: `src/violation-collector.ts`
169
+
170
+ オプションの最大数制限付きで複数ファイルの違反を集約します。
171
+
172
+ ### コンストラクタ
173
+
174
+ ```typescript
175
+ constructor(maxCount?: number)
176
+ ```
177
+
178
+ ### メソッド
179
+
180
+ | メソッド | 戻り値 | 説明 |
181
+ | --------------------------------------- | -------------------------- | --------------------------------------- |
182
+ | `pushWithFile(filePath, ...violations)` | `void` | ファイルの違反を追加(maxCount を尊重) |
183
+ | `isLocked()` | `boolean` | maxCount に到達した場合 `true` |
184
+ | `toArray()` | `FileViolation[]` | すべての違反をフラット配列として返す |
185
+ | `groupByFile()` | `Map<string, Violation[]>` | ファイルパスでグループ化された違反 |
186
+
187
+ ### プロパティ
188
+
189
+ | プロパティ | 型 | 説明 |
190
+ | ---------- | -------- | ---------- |
191
+ | `length` | `number` | 違反の総数 |
192
+
193
+ ### maxCount の動作
194
+
195
+ `maxCount` が設定されている場合:
196
+
197
+ - `pushWithFile()` は `length >= maxCount` に到達すると違反の受け入れを停止
198
+ - `isLocked()` は制限到達後に `true` を返す
199
+ - 既に追加された違反は保持される
200
+
201
+ ## Pretender システム
202
+
203
+ ソース: `src/ml-dom/node/document.ts`、要素の pretending メソッド
204
+
205
+ ### Pretender 型
206
+
207
+ ```typescript
208
+ type Pretender = {
209
+ selector: string; // コンポーネントにマッチする CSS セレクタ
210
+ as: string; // 偽装する HTML 要素
211
+ aria?: PretenderARIA; // オプションの ARIA オーバーライド
212
+ };
213
+ ```
214
+
215
+ ### 動作の仕組み
216
+
217
+ 1. `MLDocument` の構築時に `_pretending()` が pretender 定義を処理
218
+ 2. pretender セレクタにマッチする各 `MLElement` が `element.pretending(pretenders)` を呼び出す
219
+ 3. マッチした要素が `PretenderContext` を取得:
220
+ - コンポーネント要素に `type: 'pretender'`
221
+ - 対象 HTML 要素参照に `type: 'origin'`
222
+ 4. ルールが `element.pretenderContext` にアクセスしてセマンティックマッピングを確認
223
+ 5. アクセシブル名の計算(`getAccname()`)がロール/名前の解決に pretender コンテキストを使用
224
+
225
+ ### PretenderContext
226
+
227
+ ```typescript
228
+ type PretenderContext =
229
+ | { type: 'pretender'; as: MLElement; aria?: PretenderARIA }
230
+ | { type: 'origin'; pretender: MLElement };
231
+ ```
232
+
233
+ ## プラグインシステム
234
+
235
+ ソース: `src/plugin/types.ts`, `src/plugin/plugin.ts`
236
+
237
+ ### Plugin 型
238
+
239
+ ```typescript
240
+ type Plugin = {
241
+ readonly name: string;
242
+ readonly rules?: Record<string, RuleSeed<any, any>>;
243
+ readonly configs?: Record<string, Config>;
244
+ };
245
+ ```
246
+
247
+ ### PluginCreator
248
+
249
+ 設定を受け付けるプラグイン用:
250
+
251
+ ```typescript
252
+ type PluginCreator<S> = {
253
+ readonly name: string;
254
+ create(setting: S): Omit<Plugin, 'name'>;
255
+ };
256
+ ```
257
+
258
+ ### createPlugin
259
+
260
+ ```typescript
261
+ function createPlugin<S>(creator: PluginCreator<S>): PluginCreator<S>;
262
+ ```
263
+
264
+ 型安全なプラグインクリエーター定義のためのファクトリ関数。クリエーターをそのまま返し、型ヘルパーとして機能します。
265
+
266
+ ### プラグインの利用
267
+
268
+ プラグインが提供するもの:
269
+
270
+ - **カスタムルール** — 名前で登録される追加のルールシード
271
+ - **共有設定** — 再利用可能な設定プリセット
272
+
273
+ ## MLSchema
274
+
275
+ ソース: `src/types.ts`
276
+
277
+ ```typescript
278
+ type MLSchema = [MLMLSpec, ...ExtendedSpec[]];
279
+ ```
280
+
281
+ タプル構造:
282
+
283
+ - 最初の要素: ベースの HTML/ARIA 仕様(`MLMLSpec`)
284
+ - 残り: 拡張仕様(例:フレームワーク固有の要素定義)
285
+
286
+ ### schemaToSpec()
287
+
288
+ スキーマタプルを単一の仕様オブジェクトに解決します。MLDOM が要素/属性の検証に使用します。
289
+
290
+ ## デバッグ
291
+
292
+ ソース: `src/debug.ts`
293
+
294
+ ### enableDebug()
295
+
296
+ ml-core パッケージと CLI のデバッグログを有効化します。
297
+
298
+ ### デバッグ名前空間
299
+
300
+ | 名前空間 | 説明 |
301
+ | ------------------------- | ---------------------- |
302
+ | `ml-core` | コアエンジンの操作 |
303
+ | `ml-core:ml-dom` | MLDOM ツリーの操作 |
304
+ | `ml-core:ml-dom:document` | ドキュメント構築の詳細 |
305
+ | `ml-core:rule-mapper` | ルールマッピングの操作 |
306
+
307
+ デバッグ出力は `debug` npm パッケージで制御されます。環境変数 `DEBUG=ml-core*` で有効化できます。
@@ -0,0 +1,307 @@
1
+ # Linting Pipeline
2
+
3
+ Detailed reference for the MLCore linting engine in `@markuplint/ml-core`.
4
+
5
+ ## Overview
6
+
7
+ `MLCore` is the orchestration engine that connects parsing, DOM construction, rule execution, and violation collection. The pipeline flows:
8
+
9
+ ```
10
+ Source Code → Parser → MLASTDocument → MLDocument → Rule Verification → Violations
11
+ ```
12
+
13
+ ## MLCore Class
14
+
15
+ Source: `src/ml-core.ts`
16
+
17
+ ### Constructor
18
+
19
+ ```typescript
20
+ constructor(params: MLCoreParams)
21
+ ```
22
+
23
+ Where `MLCoreParams` extends `MLFabric` with:
24
+
25
+ | Parameter | Type | Description |
26
+ | ------------ | --------- | ----------------------- |
27
+ | `sourceCode` | `string` | The source code to lint |
28
+ | `filename` | `string` | Source filename |
29
+ | `debug` | `boolean` | Enable debug logging |
30
+
31
+ ### MLFabric
32
+
33
+ The `MLFabric` type defines the full linting configuration:
34
+
35
+ | Field | Type | Description |
36
+ | -------------------- | --------------------------------- | ------------------------------------------------- |
37
+ | `parser` | `MLParser` | Parser instance (e.g., `@markuplint/html-parser`) |
38
+ | `ruleset` | `Ruleset` | Resolved rule configuration |
39
+ | `rules` | `readonly MLRule[]` | Array of rule instances |
40
+ | `locale` | `LocaleSet` | Locale for violation messages |
41
+ | `schemas` | `MLSchema` | HTML/ARIA specification tuple |
42
+ | `parserOptions` | `ParserOptions` | Parser configuration options |
43
+ | `severity` | `{ parseError?: SeverityOption }` | Severity overrides |
44
+ | `pretenders` | `readonly Pretender[]` | Component-to-HTML mappings |
45
+ | `ruleCommonSettings` | `RuleCommonSettings` | Common settings applied globally to all rules |
46
+ | `configErrors` | `readonly ConfigError[]` | Configuration errors to report |
47
+
48
+ ### Properties
49
+
50
+ | Property | Type | Description |
51
+ | ---------- | --------------------------- | ------------------------------ |
52
+ | `document` | `MLDocument \| ParserError` | Parsed document or parse error |
53
+
54
+ ### Construction Flow
55
+
56
+ 1. **Named nodeRule expansion** — `expandNamedNodeRules()` converts named entries in `nodeRules` and `childNodeRules` into virtual `MLRule` instances. The originals are preserved in `#originalNodeRules` / `#originalChildNodeRules` for hot-reload. Namespace disable prefixes are pre-computed from wildcard entries (e.g., `"a11y/*": false`).
57
+ 2. `_parse()` — Invokes `parser.parse(sourceCode, parserOptions)` to produce `MLASTDocument`
58
+ 3. `_createDocument()` — Wraps AST in `MLDocument` with ruleset, schemas, and options
59
+
60
+ If parsing fails, `document` holds a `ParserError` instead of `MLDocument`.
61
+
62
+ ## Parse Phase
63
+
64
+ ### `_parse()`
65
+
66
+ Calls `parser.parse(sourceCode, parserOptions)` which returns an `MLASTDocument`.
67
+
68
+ If the parser throws:
69
+
70
+ - The error is caught as a `ParserError`
71
+ - `document` is set to the `ParserError` object
72
+ - `verify()` will later convert this to a `Violation`
73
+
74
+ ## Document Creation Phase
75
+
76
+ ### `_createDocument()`
77
+
78
+ Creates `MLDocument` from the parsed AST:
79
+
80
+ ```typescript
81
+ new Document(ast, ruleset, schemas, ruleCommonSettings, {
82
+ filename,
83
+ endTag,
84
+ booleanish,
85
+ tagNameCaseSensitive,
86
+ pretenders,
87
+ });
88
+ ```
89
+
90
+ During construction, `MLDocument`:
91
+
92
+ 1. Builds the flat `nodeList` by traversing the AST
93
+ 2. Initializes `RuleMapper` to distribute rule configuration
94
+ 3. Sets up pretender contexts when pretender definitions exist
95
+
96
+ ## Verification Phase
97
+
98
+ ### `verify(fix?): Promise<Violation[]>`
99
+
100
+ The main linting method. Returns an array of violations.
101
+
102
+ **Flow:**
103
+
104
+ ```mermaid
105
+ flowchart TD
106
+ A["verify(fix?)"] --> B{Parse error?}
107
+ B -->|Yes| C["_createParseError()\n→ Violation"]
108
+ B -->|No| D["Check undefined rules"]
109
+ D --> E["Report configErrors"]
110
+ E --> F["For each rule:"]
111
+ F --> G["getRuleInfo(ruleset, rule.name)"]
112
+ G --> H{Disabled and\nno overrides?}
113
+ H -->|Yes| I["Skip"]
114
+ H -->|No| J["rule.verify(document, locale, fix)"]
115
+ J --> K{ParserError?}
116
+ K -->|Yes| L["Catch → Violation"]
117
+ K -->|No| M["Collect violations"]
118
+ M --> N["Log counts"]
119
+ N --> O["Return Violation[]"]
120
+ C --> O
121
+ ```
122
+
123
+ ### Step-by-step
124
+
125
+ 1. **Parse error check**: If `document` is a `ParserError`, creates a single violation and returns
126
+ 2. **Undefined rule detection**: Compares `setRuleNames` (rules in config) vs `definedRuleName` (rules actually loaded). Reports `config-error` warnings for undefined rules
127
+ 3. **Config errors**: Converts `configErrors` array to violations
128
+ 4. **Rule loop**: For each rule:
129
+ - **Virtual rule disable check** — If `rule.baseRuleId` is set, checks three disable conditions: exact name match (`rules["alias"]: false`), group disable (`rules["groupName"]: false`), or namespace wildcard (`rules["scope/*"]: false`). Skips the rule if any condition is met.
130
+ - `rule.getRuleInfo(ruleset, rule.name)` checks enablement
131
+ - If `disabled && nodeRules.length === 0 && childNodeRules.length === 0` → skip
132
+ - `rule.verify(document, locale, fix)` — executes the rule
133
+ - Catches `ParserError` if thrown during verification
134
+ 5. **Result logging**: Logs error/warning/info counts via debug
135
+
136
+ ### Parse Error Violation
137
+
138
+ When `severity.parseError` is configured:
139
+
140
+ | Setting | Behavior |
141
+ | ------------------ | ------------------------------------- |
142
+ | `false` or `'off'` | Parse error suppressed (no violation) |
143
+ | `true` or `null` | Reported as `'error'` severity |
144
+ | Severity value | Reported with that severity |
145
+
146
+ ## Update and Re-parse
147
+
148
+ ### `setCode(sourceCode)`
149
+
150
+ Re-parses with new source code:
151
+
152
+ 1. Updates stored source code
153
+ 2. Calls `_parse()` to produce new AST
154
+ 3. Calls `_createDocument()` to rebuild MLDOM
155
+
156
+ ### `update(partial<MLFabric>)`
157
+
158
+ Partially updates the linting configuration:
159
+
160
+ - Re-expands named nodeRules into virtual rules. When `ruleset` is not provided, uses `#originalNodeRules` / `#originalChildNodeRules` (pre-expansion copies) as the source to avoid losing named entries that were already transformed.
161
+ - If `parserOptions` changed → full re-parse (`_parse()` + `_createDocument()`)
162
+ - Otherwise → only `_createDocument()` (reuses existing AST)
163
+
164
+ This optimization avoids unnecessary re-parsing when only rules or config change.
165
+
166
+ ## ViolationCollector
167
+
168
+ Source: `src/violation-collector.ts`
169
+
170
+ Aggregates violations across multiple files with an optional maximum count.
171
+
172
+ ### Constructor
173
+
174
+ ```typescript
175
+ constructor(maxCount?: number)
176
+ ```
177
+
178
+ ### Methods
179
+
180
+ | Method | Returns | Description |
181
+ | --------------------------------------- | -------------------------- | --------------------------------------------- |
182
+ | `pushWithFile(filePath, ...violations)` | `void` | Add violations for a file (respects maxCount) |
183
+ | `isLocked()` | `boolean` | `true` if maxCount reached |
184
+ | `toArray()` | `FileViolation[]` | All violations as flat array |
185
+ | `groupByFile()` | `Map<string, Violation[]>` | Violations grouped by file path |
186
+
187
+ ### Properties
188
+
189
+ | Property | Type | Description |
190
+ | -------- | -------- | --------------------- |
191
+ | `length` | `number` | Total violation count |
192
+
193
+ ### maxCount Behavior
194
+
195
+ When `maxCount` is set:
196
+
197
+ - `pushWithFile()` stops accepting violations once `length >= maxCount`
198
+ - `isLocked()` returns `true` after reaching the limit
199
+ - Already-added violations are preserved
200
+
201
+ ## Pretender System
202
+
203
+ Source: `src/ml-dom/node/document.ts`, element pretending methods
204
+
205
+ ### Pretender Type
206
+
207
+ ```typescript
208
+ type Pretender = {
209
+ selector: string; // CSS selector matching the component
210
+ as: string; // HTML element to pretend as
211
+ aria?: PretenderARIA; // Optional ARIA overrides
212
+ };
213
+ ```
214
+
215
+ ### How It Works
216
+
217
+ 1. During `MLDocument` construction, `_pretending()` processes pretender definitions
218
+ 2. Each `MLElement` matching a pretender selector calls `element.pretending(pretenders)`
219
+ 3. Matched elements get a `PretenderContext`:
220
+ - `type: 'pretender'` on the component element
221
+ - `type: 'origin'` on the target HTML element reference
222
+ 4. Rules access `element.pretenderContext` to check semantic mappings
223
+ 5. Accessible name computation (`getAccname()`) uses pretender context for role/name resolution
224
+
225
+ ### PretenderContext
226
+
227
+ ```typescript
228
+ type PretenderContext =
229
+ | { type: 'pretender'; as: MLElement; aria?: PretenderARIA }
230
+ | { type: 'origin'; pretender: MLElement };
231
+ ```
232
+
233
+ ## Plugin System
234
+
235
+ Source: `src/plugin/types.ts`, `src/plugin/plugin.ts`
236
+
237
+ ### Plugin Type
238
+
239
+ ```typescript
240
+ type Plugin = {
241
+ readonly name: string;
242
+ readonly rules?: Record<string, RuleSeed<any, any>>;
243
+ readonly configs?: Record<string, Config>;
244
+ };
245
+ ```
246
+
247
+ ### PluginCreator
248
+
249
+ For plugins that accept settings:
250
+
251
+ ```typescript
252
+ type PluginCreator<S> = {
253
+ readonly name: string;
254
+ create(setting: S): Omit<Plugin, 'name'>;
255
+ };
256
+ ```
257
+
258
+ ### createPlugin
259
+
260
+ ```typescript
261
+ function createPlugin<S>(creator: PluginCreator<S>): PluginCreator<S>;
262
+ ```
263
+
264
+ Factory function for type-safe plugin creator definitions. Returns the creator as-is, serving as a type helper.
265
+
266
+ ### Plugin Usage
267
+
268
+ Plugins provide:
269
+
270
+ - **Custom rules** — Additional rule seeds registered by name
271
+ - **Shared configurations** — Reusable config presets
272
+
273
+ ## MLSchema
274
+
275
+ Source: `src/types.ts`
276
+
277
+ ```typescript
278
+ type MLSchema = [MLMLSpec, ...ExtendedSpec[]];
279
+ ```
280
+
281
+ A tuple where:
282
+
283
+ - First element: The base HTML/ARIA specification (`MLMLSpec`)
284
+ - Rest: Extended specifications (e.g., framework-specific element definitions)
285
+
286
+ ### schemaToSpec()
287
+
288
+ Resolves the schema tuple into a single spec object used by MLDOM for element/attribute validation.
289
+
290
+ ## Debug
291
+
292
+ Source: `src/debug.ts`
293
+
294
+ ### enableDebug()
295
+
296
+ Enables debug logging for the ml-core package and CLI.
297
+
298
+ ### Debug Namespaces
299
+
300
+ | Namespace | Description |
301
+ | ------------------------- | ----------------------------- |
302
+ | `ml-core` | Core engine operations |
303
+ | `ml-core:ml-dom` | MLDOM tree operations |
304
+ | `ml-core:ml-dom:document` | Document construction details |
305
+ | `ml-core:rule-mapper` | Rule mapping operations |
306
+
307
+ Debug output is controlled via the `debug` npm package. Enable with `DEBUG=ml-core*` environment variable.