@markuplint/ml-ast 4.4.10-dev.350 → 4.4.11

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/SKILL.md ADDED
@@ -0,0 +1,124 @@
1
+ ---
2
+ description: Perform maintenance tasks for @markuplint/ml-ast
3
+ ---
4
+
5
+ # ml-ast-maintenance
6
+
7
+ Perform maintenance tasks for `@markuplint/ml-ast`: add AST node types,
8
+ add fields to existing nodes, add conditional type values, and update the parser interface.
9
+
10
+ ## Input
11
+
12
+ `$ARGUMENTS` specifies the task. Supported tasks:
13
+
14
+ | Task | Description |
15
+ | ------------------------------ | ---------------------------------------------- |
16
+ | `add-node-type <name>` | Add a new AST node type |
17
+ | `add-field <node> <field>` | Add a field to an existing node type |
18
+ | `add-conditional-type <value>` | Add a conditional type value for psblock nodes |
19
+ | `update-parser-interface` | Modify the MLParser interface |
20
+
21
+ If omitted, defaults to `add-node-type`.
22
+
23
+ ## Reference
24
+
25
+ Before executing any task, read `docs/maintenance.md` (or `docs/maintenance.ja.md`)
26
+ for the full guide. The recipes there are the source of truth for procedures.
27
+
28
+ Also read:
29
+
30
+ - `docs/node-reference.md` -- Detailed documentation of each AST node type
31
+ - `ARCHITECTURE.md` -- Package overview, type hierarchy, and integration points
32
+
33
+ ## Task: add-node-type
34
+
35
+ Add a new AST node type. Follow recipe #1 in `docs/maintenance.md`.
36
+
37
+ ### Step 1: Define the type
38
+
39
+ 1. Read `src/types.ts` to understand the existing type hierarchy
40
+ 2. Add the type value to `MLASTNodeType`
41
+ 3. Define the interface extending `MLASTAbstractNode`
42
+ 4. Add to relevant union types (`MLASTNode`, `MLASTChildNode`, etc.)
43
+
44
+ ### Step 2: Update downstream
45
+
46
+ 1. Update `ml-core`'s `createNode()` in `packages/@markuplint/ml-core/src/ml-dom/helper/create-node.ts`
47
+ 2. Add a `case` for the new type value in the `switch` statement
48
+ 3. Create or reuse an appropriate DOM node class
49
+
50
+ ### Step 3: Build and verify
51
+
52
+ 1. Build: `yarn build --scope @markuplint/ml-ast`
53
+ 2. Build: `yarn build --scope @markuplint/ml-core`
54
+ 3. Check the downstream impact checklist in `docs/maintenance.md`
55
+
56
+ ## Task: add-field
57
+
58
+ Add a field to an existing node type. Follow recipe #2 in `docs/maintenance.md`.
59
+
60
+ ### Step 1: Add the field
61
+
62
+ 1. Read `src/types.ts` and find the target interface
63
+ 2. Add the field (prefer optional `?` for backward compatibility)
64
+ 3. Add JSDoc documentation for the new field
65
+
66
+ ### Step 2: Update consumers
67
+
68
+ 1. Update parsers that should populate the new field
69
+ 2. Update `ml-core` if the field affects DOM node creation
70
+
71
+ ### Step 3: Build and verify
72
+
73
+ 1. Build: `yarn build --scope @markuplint/ml-ast`
74
+ 2. Build affected packages
75
+ 3. Check the downstream impact checklist in `docs/maintenance.md`
76
+
77
+ ## Task: add-conditional-type
78
+
79
+ Add a conditional type value for preprocessor-specific blocks. Follow recipe #4 in `docs/maintenance.md`.
80
+
81
+ ### Step 1: Add the value
82
+
83
+ 1. Read `src/types.ts` and find `MLASTPreprocessorSpecificBlockConditionalType`
84
+ 2. Add the new value to the union type
85
+ 3. Document the value's semantic meaning in the JSDoc comment
86
+
87
+ ### Step 2: Update parsers
88
+
89
+ 1. Update the parser that produces blocks with this conditional type
90
+ 2. Verify the value follows the naming convention (`category:variant`, e.g., `if:elseif`)
91
+
92
+ ### Step 3: Build and verify
93
+
94
+ 1. Build: `yarn build --scope @markuplint/ml-ast`
95
+ 2. Build the affected parser package
96
+
97
+ ## Task: update-parser-interface
98
+
99
+ Modify the `MLParser` interface. Follow recipe #5 in `docs/maintenance.md`.
100
+
101
+ ### Step 1: Make changes
102
+
103
+ 1. Read `src/types.ts` and find `MLParser`
104
+ 2. Make changes (prefer adding optional fields for backward compatibility)
105
+ 3. Update `MLMarkupLanguageParser` (deprecated) if needed for consistency
106
+
107
+ ### Step 2: Update all parsers
108
+
109
+ 1. Update all parser implementations (see the list in `docs/maintenance.md` recipe #5)
110
+ 2. Update `@markuplint/parser-utils` if it provides shared implementation
111
+
112
+ ### Step 3: Build and verify
113
+
114
+ 1. Build all packages: `yarn build`
115
+ 2. Run all tests: `yarn test`
116
+
117
+ ## Rules
118
+
119
+ 1. **All node types extend `MLASTAbstractNode`** (except attributes which extend `MLASTToken`).
120
+ 2. **Use `readonly` for all interface fields.** The AST is immutable after parsing.
121
+ 3. **Prefer optional fields** when adding to existing interfaces for backward compatibility.
122
+ 4. **Always update `createNode()` in `ml-core`** when adding new node types.
123
+ 5. **Follow the discriminated union pattern.** Every node must have a unique `type` literal value.
124
+ 6. **Add JSDoc comments** to all new exported types and fields.
@@ -0,0 +1,215 @@
1
+ # メンテナンスガイド
2
+
3
+ `@markuplint/ml-ast` の実践的な操作・メンテナンスガイドです。
4
+
5
+ ## コマンド
6
+
7
+ | コマンド | 説明 |
8
+ | --------------------------------------------- | --------------------------------- |
9
+ | `yarn build --scope @markuplint/ml-ast` | TypeScript を `lib/` にコンパイル |
10
+ | `yarn workspace @markuplint/ml-ast run dev` | ウォッチモードコンパイル |
11
+ | `yarn workspace @markuplint/ml-ast run clean` | コンパイル出力をクリーン |
12
+
13
+ ## テスト
14
+
15
+ このパッケージには**テストファイルがありません**。純粋な型定義パッケージのため、正当性はビルド時に TypeScript コンパイラで検証されます。統合テストはこれらの型を消費する下流パッケージで実施されます。
16
+
17
+ 型の正当性を検証するには:
18
+
19
+ ```bash
20
+ yarn build --scope @markuplint/ml-ast
21
+ ```
22
+
23
+ ## 一般的なレシピ
24
+
25
+ ### 1. 新しいノード型の追加
26
+
27
+ 新しい AST ノード型(例:仮想的な `MLASTDirective`)を追加する場合:
28
+
29
+ 1. **`MLASTNodeType` に型の値を追加**(`src/types.ts`):
30
+
31
+ ```typescript
32
+ export type MLASTNodeType =
33
+ | 'doctype'
34
+ | 'starttag'
35
+ // ... 既存の値
36
+ | 'directive'; // ここに追加
37
+ ```
38
+
39
+ 2. **`MLASTAbstractNode` を継承するインターフェースを定義**:
40
+
41
+ ```typescript
42
+ export interface MLASTDirective extends MLASTAbstractNode {
43
+ readonly type: 'directive';
44
+ readonly depth: number;
45
+ // 型固有のフィールドを追加
46
+ }
47
+ ```
48
+
49
+ 3. **関連する共用体型に追加**:
50
+ - `MLASTNode` -- 常にこの共用体に追加
51
+ - `MLASTChildNode` -- 要素の子になれる場合
52
+ - `MLASTNodeTreeItem` -- `nodeList` のトップレベルに出現できる場合
53
+ - `MLASTParentNode` -- 子ノードを含むことができる場合
54
+
55
+ 4. **`ml-core` の `createNode()` を更新**(`packages/@markuplint/ml-core/src/ml-dom/helper/create-node.ts`):
56
+ - `switch` 文に新しい type 値の `case` を追加
57
+ - 適切な DOM ノードクラスを作成または再利用
58
+
59
+ 5. **このノード型を生成するパーサーを更新**
60
+
61
+ 6. **ビルドして検証**:
62
+ ```bash
63
+ yarn build --scope @markuplint/ml-ast
64
+ yarn build --scope @markuplint/ml-core
65
+ ```
66
+
67
+ ### 2. 既存ノード型へのフィールド追加
68
+
69
+ 既存のノードインターフェースに新しいフィールドを追加する場合:
70
+
71
+ 1. **`src/types.ts` のインターフェースにフィールドを追加**:
72
+
73
+ ```typescript
74
+ export interface MLASTElement extends MLASTAbstractNode {
75
+ // ... 既存のフィールド
76
+ readonly newField: string; // 必須フィールド
77
+ readonly optionalField?: boolean; // オプションフィールド(後方互換性のため推奨)
78
+ }
79
+ ```
80
+
81
+ 2. **後方互換性のためオプションフィールド**(`?`)を推奨 -- フィールドがなくても既存のパーサーが壊れません。
82
+
83
+ 3. **新しいフィールドを設定するパーサーを更新**
84
+
85
+ 4. **フィールドが DOM ノードの作成や動作に影響する場合は `ml-core` を更新**
86
+
87
+ 5. **全チェーンをビルド**:
88
+ ```bash
89
+ yarn build --scope @markuplint/ml-ast
90
+ yarn build --scope @markuplint/ml-core
91
+ ```
92
+
93
+ ### 3. 新しい属性バリアントの追加
94
+
95
+ `MLASTHTMLAttr` と `MLASTSpreadAttr` に加えて新しい属性型を追加する場合:
96
+
97
+ 1. **`MLASTNodeType` に型の値を追加**(まだない場合)
98
+
99
+ 2. **`MLASTToken` を継承するインターフェースを定義**:
100
+
101
+ ```typescript
102
+ export interface MLASTNewAttr extends MLASTToken {
103
+ readonly type: 'newattr';
104
+ readonly nodeName: string;
105
+ // 属性固有のフィールドを追加
106
+ }
107
+ ```
108
+
109
+ 3. **`MLASTAttr` 共用体に追加**:
110
+
111
+ ```typescript
112
+ export type MLASTAttr = MLASTHTMLAttr | MLASTSpreadAttr | MLASTNewAttr;
113
+ ```
114
+
115
+ 4. **属性型で switch する下流の消費者を更新**
116
+
117
+ 5. **ビルドして検証**
118
+
119
+ ### 4. `PreprocessorSpecificBlockConditionalType` の値追加
120
+
121
+ プリプロセッサブロックの新しい conditional type 値を追加する場合:
122
+
123
+ 1. **`src/types.ts` の `MLASTPreprocessorSpecificBlockConditionalType` に値を追加**:
124
+
125
+ ```typescript
126
+ export type MLASTPreprocessorSpecificBlockConditionalType =
127
+ | 'if'
128
+ | 'if:elseif'
129
+ // ... 既存の値
130
+ | 'newvalue' // ここに追加
131
+ | null;
132
+ ```
133
+
134
+ 2. **この conditional type でブロックを生成するパーサーを更新**
135
+
136
+ 3. **新しい値が DOM 作成時に特別な処理を必要とする場合は `ml-core` を更新**
137
+
138
+ 4. **ビルドして検証**:
139
+ ```bash
140
+ yarn build --scope @markuplint/ml-ast
141
+ ```
142
+
143
+ ### 5. `MLParser` インターフェースの変更
144
+
145
+ パーサーインターフェースを変更する場合:
146
+
147
+ 1. **`src/types.ts` の `MLParser` を変更**
148
+
149
+ 2. **後方互換性を考慮**:
150
+ - オプションフィールドの追加は安全
151
+ - 必須フィールドの追加やシグネチャの変更は破壊的変更
152
+ - 一貫性のため必要に応じて `MLMarkupLanguageParser`(非推奨)も更新
153
+
154
+ 3. **すべてのパーサー実装を更新**:
155
+ - `@markuplint/html-parser`
156
+ - `@markuplint/jsx-parser`
157
+ - `@markuplint/vue-parser`
158
+ - `@markuplint/svelte-parser`
159
+ - `@markuplint/astro-parser`
160
+ - `@markuplint/pug-parser`
161
+ - `@markuplint/parser-utils`
162
+
163
+ 4. **影響を受けるすべてのパッケージをビルド**:
164
+ ```bash
165
+ yarn build
166
+ ```
167
+
168
+ ## 下流影響チェックリスト
169
+
170
+ このパッケージの型を変更する際、以下の下流パッケージがビルド・テストに通ることを確認してください:
171
+
172
+ - [ ] `@markuplint/html-parser` -- HTML パーサー
173
+ - [ ] `@markuplint/parser-utils` -- パーサーユーティリティ関数
174
+ - [ ] `@markuplint/jsx-parser` -- JSX パーサー
175
+ - [ ] `@markuplint/astro-parser` -- Astro パーサー
176
+ - [ ] `@markuplint/vue-parser` -- Vue SFC パーサー
177
+ - [ ] `@markuplint/svelte-parser` -- Svelte パーサー
178
+ - [ ] `@markuplint/pug-parser` -- Pug パーサー
179
+ - [ ] `@markuplint/ml-core` -- コア DOM マッピング(最重要)
180
+ - [ ] `@markuplint/ml-config` -- 設定型
181
+ - [ ] `@markuplint/ml-spec` -- 仕様型
182
+ - [ ] `@markuplint/file-resolver` -- ファイル解決
183
+
184
+ 最も重要な下流パッケージは `@markuplint/ml-core` で、`createNode()` -- `node.type` に対する `switch` 文で AST ノードを DOM ノードにマッピングする関数を含みます。
185
+
186
+ ## トラブルシューティング
187
+
188
+ ### 型変更後のビルドエラー
189
+
190
+ **症状:** 型の変更後、下流パッケージのビルドが失敗する。
191
+
192
+ **診断:**
193
+
194
+ 1. まずこのパッケージをビルド:`yarn build --scope @markuplint/ml-ast`
195
+ 2. 次に `ml-core` をビルド:`yarn build --scope @markuplint/ml-core`
196
+ 3. `switch` の網羅性エラーを確認 -- TypeScript は `node.type` の `switch` で新しい型値のケースが欠けている場合に報告します
197
+ 4. 共用体型の不一致を確認 -- 共用体に型を追加すると、既存の絞り込みコードの更新が必要になる場合があります
198
+
199
+ ### ml-core の `createNode()` のケース漏れ
200
+
201
+ **症状:** 実行時に `TypeError: Invalid AST node types "newtype"` が発生する。
202
+
203
+ **原因:** 新しいノード型が `MLASTNodeType` と関連する共用体型に追加されたが、`ml-core` の `createNode()` の switch 文が更新されていない。
204
+
205
+ **修正:** `packages/@markuplint/ml-core/src/ml-dom/helper/create-node.ts` に新しい型の `case` を追加してください。
206
+
207
+ ### パーサーが期待されるノードを生成しない
208
+
209
+ **症状:** パーサーが新しく追加されたフィールドや型のノードを生成しない。
210
+
211
+ **診断:**
212
+
213
+ 1. パーサーの実装が新しいフィールドを設定するように更新されているか確認
214
+ 2. オプションフィールドの場合、フィールドが暗黙的に `undefined` になっていないか検証
215
+ 3. パーサーとこのパッケージの両方をビルドして型の整合性を確認
@@ -0,0 +1,215 @@
1
+ # Maintenance Guide
2
+
3
+ Practical operations and maintenance guide for `@markuplint/ml-ast`.
4
+
5
+ ## Commands
6
+
7
+ | Command | Description |
8
+ | --------------------------------------------- | ---------------------------- |
9
+ | `yarn build --scope @markuplint/ml-ast` | Compile TypeScript to `lib/` |
10
+ | `yarn workspace @markuplint/ml-ast run dev` | Watch mode compilation |
11
+ | `yarn workspace @markuplint/ml-ast run clean` | Clean compiled output |
12
+
13
+ ## Testing
14
+
15
+ This package has **no test files**. It is a pure type-definition package, so correctness is verified by the TypeScript compiler during build. Integration testing is performed by downstream packages that consume these types.
16
+
17
+ To verify type correctness:
18
+
19
+ ```bash
20
+ yarn build --scope @markuplint/ml-ast
21
+ ```
22
+
23
+ ## Common Recipes
24
+
25
+ ### 1. Adding a New Node Type
26
+
27
+ To add a new AST node type (e.g., a hypothetical `MLASTDirective`):
28
+
29
+ 1. **Add the type value to `MLASTNodeType`** in `src/types.ts`:
30
+
31
+ ```typescript
32
+ export type MLASTNodeType =
33
+ | 'doctype'
34
+ | 'starttag'
35
+ // ... existing values
36
+ | 'directive'; // Add here
37
+ ```
38
+
39
+ 2. **Define the interface** extending `MLASTAbstractNode`:
40
+
41
+ ```typescript
42
+ export interface MLASTDirective extends MLASTAbstractNode {
43
+ readonly type: 'directive';
44
+ readonly depth: number;
45
+ // Add type-specific fields
46
+ }
47
+ ```
48
+
49
+ 3. **Add to relevant union types**:
50
+ - `MLASTNode` -- Always add to this union
51
+ - `MLASTChildNode` -- If it can be a child of elements
52
+ - `MLASTNodeTreeItem` -- If it can appear at the top level of `nodeList`
53
+ - `MLASTParentNode` -- If it can contain child nodes
54
+
55
+ 4. **Update `ml-core`'s `createNode()`** in `packages/@markuplint/ml-core/src/ml-dom/helper/create-node.ts`:
56
+ - Add a `case` for the new type value in the `switch` statement
57
+ - Create or reuse an appropriate DOM node class
58
+
59
+ 5. **Update parsers** that should produce this node type
60
+
61
+ 6. **Build and verify**:
62
+ ```bash
63
+ yarn build --scope @markuplint/ml-ast
64
+ yarn build --scope @markuplint/ml-core
65
+ ```
66
+
67
+ ### 2. Adding a Field to an Existing Node Type
68
+
69
+ To add a new field to an existing node interface:
70
+
71
+ 1. **Add the field** to the interface in `src/types.ts`:
72
+
73
+ ```typescript
74
+ export interface MLASTElement extends MLASTAbstractNode {
75
+ // ... existing fields
76
+ readonly newField: string; // Required field
77
+ readonly optionalField?: boolean; // Optional field (prefer for backward compat)
78
+ }
79
+ ```
80
+
81
+ 2. **Prefer optional fields** (`?`) for backward compatibility -- existing parsers will not break if the field is missing.
82
+
83
+ 3. **Update parsers** that should populate the new field.
84
+
85
+ 4. **Update `ml-core`** if the field affects DOM node creation or behavior.
86
+
87
+ 5. **Build the full chain**:
88
+ ```bash
89
+ yarn build --scope @markuplint/ml-ast
90
+ yarn build --scope @markuplint/ml-core
91
+ ```
92
+
93
+ ### 3. Adding a New Attribute Variant
94
+
95
+ To add a new attribute type alongside `MLASTHTMLAttr` and `MLASTSpreadAttr`:
96
+
97
+ 1. **Add the type value to `MLASTNodeType`** (if not already present)
98
+
99
+ 2. **Define the interface** extending `MLASTToken`:
100
+
101
+ ```typescript
102
+ export interface MLASTNewAttr extends MLASTToken {
103
+ readonly type: 'newattr';
104
+ readonly nodeName: string;
105
+ // Add attribute-specific fields
106
+ }
107
+ ```
108
+
109
+ 3. **Add to `MLASTAttr` union**:
110
+
111
+ ```typescript
112
+ export type MLASTAttr = MLASTHTMLAttr | MLASTSpreadAttr | MLASTNewAttr;
113
+ ```
114
+
115
+ 4. **Update downstream consumers** that switch on attribute types
116
+
117
+ 5. **Build and verify**
118
+
119
+ ### 4. Adding a `PreprocessorSpecificBlockConditionalType` Value
120
+
121
+ To add a new conditional type value for preprocessor blocks:
122
+
123
+ 1. **Add the value** to `MLASTPreprocessorSpecificBlockConditionalType` in `src/types.ts`:
124
+
125
+ ```typescript
126
+ export type MLASTPreprocessorSpecificBlockConditionalType =
127
+ | 'if'
128
+ | 'if:elseif'
129
+ // ... existing values
130
+ | 'newvalue' // Add here
131
+ | null;
132
+ ```
133
+
134
+ 2. **Update the parser** that produces blocks with this conditional type
135
+
136
+ 3. **Update `ml-core`** if the new value requires special handling during DOM creation
137
+
138
+ 4. **Build and verify**:
139
+ ```bash
140
+ yarn build --scope @markuplint/ml-ast
141
+ ```
142
+
143
+ ### 5. Modifying the `MLParser` Interface
144
+
145
+ When changing the parser interface:
146
+
147
+ 1. **Make changes** to `MLParser` in `src/types.ts`
148
+
149
+ 2. **Consider backward compatibility**:
150
+ - Adding optional fields is safe
151
+ - Adding required fields or changing signatures is a breaking change
152
+ - Update `MLMarkupLanguageParser` (deprecated) if needed for consistency
153
+
154
+ 3. **Update all parser implementations**:
155
+ - `@markuplint/html-parser`
156
+ - `@markuplint/jsx-parser`
157
+ - `@markuplint/vue-parser`
158
+ - `@markuplint/svelte-parser`
159
+ - `@markuplint/astro-parser`
160
+ - `@markuplint/pug-parser`
161
+ - `@markuplint/parser-utils`
162
+
163
+ 4. **Build all affected packages**:
164
+ ```bash
165
+ yarn build
166
+ ```
167
+
168
+ ## Downstream Impact Checklist
169
+
170
+ When modifying types in this package, verify that these downstream packages still build and pass tests:
171
+
172
+ - [ ] `@markuplint/html-parser` -- HTML parser
173
+ - [ ] `@markuplint/parser-utils` -- Parser utility functions
174
+ - [ ] `@markuplint/jsx-parser` -- JSX parser
175
+ - [ ] `@markuplint/astro-parser` -- Astro parser
176
+ - [ ] `@markuplint/vue-parser` -- Vue SFC parser
177
+ - [ ] `@markuplint/svelte-parser` -- Svelte parser
178
+ - [ ] `@markuplint/pug-parser` -- Pug parser
179
+ - [ ] `@markuplint/ml-core` -- Core DOM mapping (most critical)
180
+ - [ ] `@markuplint/ml-config` -- Configuration types
181
+ - [ ] `@markuplint/ml-spec` -- Specification types
182
+ - [ ] `@markuplint/file-resolver` -- File resolution
183
+
184
+ The most critical downstream package is `@markuplint/ml-core`, which contains `createNode()` -- the function that maps AST nodes to DOM nodes via a `switch` statement on `node.type`.
185
+
186
+ ## Troubleshooting
187
+
188
+ ### Build Errors After Type Changes
189
+
190
+ **Symptom:** Downstream packages fail to build after modifying types.
191
+
192
+ **Diagnosis:**
193
+
194
+ 1. Build this package first: `yarn build --scope @markuplint/ml-ast`
195
+ 2. Build `ml-core` next: `yarn build --scope @markuplint/ml-core`
196
+ 3. Check for `switch` exhaustiveness errors -- TypeScript will report if a `switch` on `node.type` is missing a case for a new type value
197
+ 4. Check for union type mismatches -- adding a type to a union may cause existing narrowing code to need updates
198
+
199
+ ### Missing Case in ml-core's `createNode()`
200
+
201
+ **Symptom:** `TypeError: Invalid AST node types "newtype"` at runtime.
202
+
203
+ **Cause:** A new node type was added to `MLASTNodeType` and the relevant union types, but `ml-core`'s `createNode()` switch statement was not updated.
204
+
205
+ **Fix:** Add a `case` for the new type in `packages/@markuplint/ml-core/src/ml-dom/helper/create-node.ts`.
206
+
207
+ ### Parser Not Producing Expected Nodes
208
+
209
+ **Symptom:** A parser does not produce nodes with newly added fields or types.
210
+
211
+ **Diagnosis:**
212
+
213
+ 1. Check that the parser implementation has been updated to populate new fields
214
+ 2. For optional fields, verify that the field is not silently `undefined`
215
+ 3. Build both the parser and this package to ensure type alignment