@markuplint/pug-parser 4.6.21 → 4.6.23

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.
@@ -0,0 +1,188 @@
1
+ # メンテナンスガイド
2
+
3
+ ## コマンド
4
+
5
+ | コマンド | 説明 |
6
+ | ------------------------------------------- | ---------------------- |
7
+ | `yarn build --scope @markuplint/pug-parser` | このパッケージをビルド |
8
+ | `yarn dev --scope @markuplint/pug-parser` | ウォッチモードでビルド |
9
+ | `yarn clean --scope @markuplint/pug-parser` | ビルド成果物を削除 |
10
+ | `yarn test --scope @markuplint/pug-parser` | テストを実行 |
11
+
12
+ ## テスト
13
+
14
+ テストファイルは `*.spec.ts` の命名規則に従います:
15
+
16
+ | テストファイル | カバレッジ |
17
+ | ------------------------------------------------ | ---------------------------------------------------------------- |
18
+ | `src/index.spec.ts` | PugParser 統合テスト(Pug テンプレートのエンドツーエンドパース) |
19
+ | `src/pug-parser/index.spec.ts` | AST 最適化テスト(pugParse、optimizeAST) |
20
+ | `src/utils/get-offset-from-line-and-col.spec.ts` | オフセット計算ユーティリティのテスト |
21
+
22
+ 主なテストパターンでは `nodeListToDebugMaps` を使用したスナップショット形式のアサーションを行います:
23
+
24
+ ```ts
25
+ import { nodeListToDebugMaps } from '@markuplint/parser-utils';
26
+ import { parser } from '@markuplint/pug-parser';
27
+
28
+ const doc = parser.parse('div.foo#bar text content');
29
+ const debugMaps = nodeListToDebugMaps(doc.nodeList, true);
30
+ expect(debugMaps).toStrictEqual([
31
+ // 期待されるデバッグ出力
32
+ ]);
33
+ ```
34
+
35
+ ## レシピ
36
+
37
+ ### 1. 新しい Pug AST ノードタイプの追加
38
+
39
+ 1. `src/types.ts` を読み、新しい最適化済み型を追加:
40
+ ```ts
41
+ export type ASTNewType = PugAST.NewType & AdditionalASTData;
42
+ ```
43
+ 2. 新しい型を `ASTNode` 共用体に追加
44
+ 3. `src/pug-parser/index.ts` を読み、`optimizeAST()` に新しい `case` を追加:
45
+ ```ts
46
+ case 'NewType': {
47
+ const block = optimizeAST(node.block, tokens, pug);
48
+ const newNode: ASTNewType = {
49
+ type: node.type,
50
+ raw,
51
+ offset,
52
+ endOffset,
53
+ line,
54
+ endLine,
55
+ column,
56
+ endColumn,
57
+ block,
58
+ filename: node.filename ?? null,
59
+ };
60
+ nodes.push(newNode);
61
+ continue;
62
+ }
63
+ ```
64
+ 4. `src/parser.ts` を読み、`nodeize()` に新しい `case` を追加:
65
+ - HTML 的な要素の場合: `getNamespace()` と属性で `visitElement()` を使用
66
+ - Pug 固有の構文の場合: 子ノードで `visitPsBlock()` を使用
67
+ 5. ビルド: `yarn build --scope @markuplint/pug-parser`
68
+ 6. テスト: `yarn test --scope @markuplint/pug-parser`
69
+
70
+ ### 2. 属性処理の変更
71
+
72
+ 1. `src/parser.ts` を読む — `visitAttr()` メソッドには3つのパスがある:
73
+ - **ショートハンド**(`#` / `.`): `AttrState.BeforeValue` を使用し、`potentialName` を設定
74
+ - **通常**: `noQuoteValueType: 'script'` を使用
75
+ - **値パース**: `scriptParser()` で型検出(Numeric、Boolean、String、Template、dynamic)
76
+ 2. 変更を行う:
77
+ - 新しいショートハンド構文の場合: 既存の `#`/`.` チェックの前に条件を追加
78
+ - 属性名変換の場合: `attr.name.raw.endsWith('!')` チェックの後に追加
79
+ - 値型検出の場合: `scriptParser()` 結果の switch を変更
80
+ 3. `this.updateAttr()` でメタデータを設定: `potentialName`、`potentialValue`、`isDuplicatable`、`valueType`
81
+ 4. ビルドとテスト: `yarn build --scope @markuplint/pug-parser && yarn test --scope @markuplint/pug-parser`
82
+
83
+ ### 3. AST 最適化の更新
84
+
85
+ 1. `src/pug-parser/index.ts` を読む — 最適化パイプライン:
86
+ - `pugParse()` — エントリーポイント: lex → parse → optimize
87
+ - `optimizeAST()` — 再帰的なノード強化
88
+ - `getOffsetsFromLines()` — 累積オフセットルックアップテーブル
89
+ - `getLocationFromToken()` — 行/列によるトークンマッチング
90
+ - `getAttrs()` — レキサートークンからの属性強化
91
+ - `getEndAttributeLocation()` — 属性を含むタグの終了位置
92
+ - `mergeTextNode()` — 連続テキストノードのマージ
93
+ - `getPipelessText()` — パイプレステキストブロックの検出
94
+ - `getRawTextAndLocationEnd()` — 複数行テキストの処理
95
+ - `optimizeASTOfConditionalNode()` — else-if/else チェーンの処理
96
+ 2. 変更時の注意点:
97
+ - オフセットは `getOffsetsFromLines()` から `offsets[line - 2]` を使用して計算する必要がある
98
+ - 終了位置は `getLocationFromToken()` でマッチするレキサートークンから取得
99
+ - `raw` は元のソースからスライスする必要がある: `pug.slice(offset, endOffset)`
100
+ - `structuredClone()` によるトークンのクローンが必要 — パーサーはトークン配列を変更する
101
+ 3. ビルドとテスト: `yarn build --scope @markuplint/pug-parser && yarn test --scope @markuplint/pug-parser`
102
+
103
+ ### 4. インライン HTML 処理の変更
104
+
105
+ 1. `src/parser.ts` を読む — `nodeize()` の `Text` ケース:
106
+ - `<` や `#[` を含むテキストは `HtmlInPugParser` でパースされる
107
+ - `#ps:tag-interpolation` ノードは `PugParser` で再帰的にパースされる
108
+ 2. タグ補間構文を変更するには:
109
+ - `HtmlInPugParser` コンストラクタの `ignoreTags` を変更
110
+ - `Text` ケースの `#ps:tag-interpolation` 検出を更新
111
+ - `#[` プレフィックスと `]` サフィックスの除去のオフセット計算を更新
112
+ 3. インライン HTML の動作を変更するには:
113
+ - `HtmlInPugParser` クラスを変更(`HtmlParser` を拡張)
114
+ - `offsetOffset`、`offsetLine`、`offsetColumn` コンテキストが正しく渡される必要がある
115
+ 4. ビルドとテスト: `yarn build --scope @markuplint/pug-parser && yarn test --scope @markuplint/pug-parser`
116
+
117
+ ### 5. useOffset インデントフィルタリングの変更
118
+
119
+ 1. `src/pug-parser/index.ts` を読む — `pugParse()` 関数
120
+ 2. `useOffset` フラグは、ゼロ以外のオフセットでサブテンプレートをパースする際に `indent` と `outdent` トークンをフィルタリングする
121
+ 3. 変更するには:
122
+ - `if (useOffset)` ブロック内のフィルタ条件を変更
123
+ - サブテンプレートコンテキストで他のトークンタイプもフィルタリングが必要かを検討
124
+ 4. ビルドとテスト: `yarn build --scope @markuplint/pug-parser && yarn test --scope @markuplint/pug-parser`
125
+
126
+ ## トラブルシューティング
127
+
128
+ ### Pug AST ノードのオフセットがおかしい
129
+
130
+ **症状:** Pug ノードの `offset`、`endOffset`、`endLine`、`endColumn` が markuplint AST 内で不正。
131
+
132
+ **原因:** `optimizeAST()` 関数がオフセットを誤って計算しているか、マッチするレキサートークンが不正。
133
+
134
+ **解決策:**
135
+
136
+ 1. `getOffsetsFromLines()` を確認 — 入力に対して累積オフセットテーブルが正しいことを検証
137
+ 2. `getLocationFromToken()` を確認 — 行/列で正しいトークンがマッチし、`tokenType` フィルタリングが正しいことを確認
138
+ 3. 属性付きタグの場合、`getEndAttributeLocation()` を確認 — 正しいトークンで停止していることを検証
139
+ 4. デバッグログを追加: 関連する `optimizeAST()` ケースで `console.log(JSON.stringify(node, null, 2))`
140
+
141
+ ### タグ補間がパースされない
142
+
143
+ **症状:** `#[tag content]` が markuplint ノードに展開されず、生テキストとして表示される。
144
+
145
+ **原因:** テキストノードが `HtmlInPugParser` パスに到達していないか、`#ps:tag-interpolation` の検出が失敗している。
146
+
147
+ **解決策:**
148
+
149
+ 1. `nodeize()` の `Text` ケースを確認 — `originNode.raw.includes('#[')` が `true` と評価されることを確認
150
+ 2. `HtmlInPugParser` を確認 — `ignoreTags` が `#[...]` を正しくマスクしていることを検証
151
+ 3. `#ps:tag-interpolation` の検出を確認 — `node.nodeName === '#ps:tag-interpolation'` であることを確認
152
+ 4. 再帰的な `PugParser` 呼び出しを確認 — オフセットコンテキスト(`offsetOffset`、`offsetLine`、`offsetColumn`)が正しく計算されていることを検証
153
+
154
+ ### 複雑な式の属性パースが失敗する
155
+
156
+ **症状:** 複雑な JavaScript 値を持つ Pug 属性(例: `data-value=obj.prop + 1`)がパースエラーまたは不正な AST を引き起こす。
157
+
158
+ **原因:** 複数トークンの式に対して `scriptParser()` の結果が正しく処理されていない。
159
+
160
+ **解決策:**
161
+
162
+ 1. `visitAttr()` メソッドを確認 — 最後の `return` ブロックが複数トークンの式を `isDynamicValue: true, valueType: 'code'` として処理している
163
+ 2. `@markuplint/parser-utils` の `scriptParser()` を確認 — 値の式が正しくトークン化されていることを検証
164
+ 3. 単一トークンの式の場合、`switch (token.type)` がトークンタイプを正しく処理しているか検証
165
+
166
+ ### ショートハンド属性の potentialName がおかしい
167
+
168
+ **症状:** `#my-id` や `.my-class` が間違った `potentialName` を持つ属性を生成する。
169
+
170
+ **原因:** ショートハンド検出または `endOffset` の再計算が誤っている。
171
+
172
+ **解決策:**
173
+
174
+ 1. `visitAttr()` の `#`/`.` ブランチを確認 — `potentialName` が `#` の場合 `'id'`、`.` の場合 `'class'` に設定されていることを確認
175
+ 2. `nodeize()` の Tag ケースで `endOffset` の再計算を確認 — ショートハンド属性では `attr.offset === attr.endOffset` が true であり、`endOffset` は `attr.offset + attr.val.length - 1` であるべき
176
+ 3. Pug AST の `val` 値を検証 — `#my-id` の場合、`val` は `"'my-id'"`(前後にクォート付き)であるべき
177
+
178
+ ### パイプレステキストが検出されない
179
+
180
+ **症状:** `.` 付きタグの後のインデントされたテキストがパイプレステキストとして扱われない。
181
+
182
+ **原因:** `getPipelessText()` 関数が `start-pipeless-text` / `end-pipeless-text` トークンを見つけられないか、行範囲チェックが失敗している。
183
+
184
+ **解決策:**
185
+
186
+ 1. レキサー出力を確認 — `start-pipeless-text` と `end-pipeless-text` トークンが存在することを検証
187
+ 2. 行範囲を確認: `startPipelessText.loc.start.line < node.line && node.line < endPipelessText.loc.start.line`
188
+ 3. トークンが存在するが範囲が誤っている場合、pug-lexer バージョンの問題の可能性がある
@@ -0,0 +1,188 @@
1
+ # Maintenance Guide
2
+
3
+ ## Commands
4
+
5
+ | Command | Description |
6
+ | ------------------------------------------- | ---------------------- |
7
+ | `yarn build --scope @markuplint/pug-parser` | Build this package |
8
+ | `yarn dev --scope @markuplint/pug-parser` | Watch mode build |
9
+ | `yarn clean --scope @markuplint/pug-parser` | Remove build artifacts |
10
+ | `yarn test --scope @markuplint/pug-parser` | Run tests |
11
+
12
+ ## Testing
13
+
14
+ Test files follow the `*.spec.ts` naming convention:
15
+
16
+ | Test File | Coverage |
17
+ | ------------------------------------------------ | -------------------------------------------------------------- |
18
+ | `src/index.spec.ts` | PugParser integration tests (parsing Pug templates end-to-end) |
19
+ | `src/pug-parser/index.spec.ts` | AST optimization tests (pugParse, optimizeAST) |
20
+ | `src/utils/get-offset-from-line-and-col.spec.ts` | Offset calculation utility tests |
21
+
22
+ The primary testing pattern uses `nodeListToDebugMaps` for snapshot-style assertions:
23
+
24
+ ```ts
25
+ import { nodeListToDebugMaps } from '@markuplint/parser-utils';
26
+ import { parser } from '@markuplint/pug-parser';
27
+
28
+ const doc = parser.parse('div.foo#bar text content');
29
+ const debugMaps = nodeListToDebugMaps(doc.nodeList, true);
30
+ expect(debugMaps).toStrictEqual([
31
+ // expected debug output
32
+ ]);
33
+ ```
34
+
35
+ ## Recipes
36
+
37
+ ### 1. Adding a New Pug AST Node Type
38
+
39
+ 1. Read `src/types.ts` — add the new optimized type:
40
+ ```ts
41
+ export type ASTNewType = PugAST.NewType & AdditionalASTData;
42
+ ```
43
+ 2. Add the new type to the `ASTNode` union
44
+ 3. Read `src/pug-parser/index.ts` — add a new `case` in `optimizeAST()`:
45
+ ```ts
46
+ case 'NewType': {
47
+ const block = optimizeAST(node.block, tokens, pug);
48
+ const newNode: ASTNewType = {
49
+ type: node.type,
50
+ raw,
51
+ offset,
52
+ endOffset,
53
+ line,
54
+ endLine,
55
+ column,
56
+ endColumn,
57
+ block,
58
+ filename: node.filename ?? null,
59
+ };
60
+ nodes.push(newNode);
61
+ continue;
62
+ }
63
+ ```
64
+ 4. Read `src/parser.ts` — add a new `case` in `nodeize()`:
65
+ - For HTML-like elements: use `visitElement()` with `getNamespace()` and attributes
66
+ - For Pug-specific constructs: use `visitPsBlock()` with child nodes
67
+ 5. Build: `yarn build --scope @markuplint/pug-parser`
68
+ 6. Test: `yarn test --scope @markuplint/pug-parser`
69
+
70
+ ### 2. Modifying Attribute Processing
71
+
72
+ 1. Read `src/parser.ts` — the `visitAttr()` method has three paths:
73
+ - **Shorthand** (`#` / `.`): Uses `AttrState.BeforeValue`, sets `potentialName`
74
+ - **Regular**: Uses `noQuoteValueType: 'script'`
75
+ - **Value parsing**: Uses `scriptParser()` for type detection (Numeric, Boolean, String, Template, dynamic)
76
+ 2. Make the change:
77
+ - For new shorthand syntax: add a condition before the existing `#`/`.` check
78
+ - For attribute name transforms: add after the `attr.name.raw.endsWith('!')` check
79
+ - For value type detection: modify the `scriptParser()` result switch
80
+ 3. Use `this.updateAttr()` to set metadata: `potentialName`, `potentialValue`, `isDuplicatable`, `valueType`
81
+ 4. Build and test: `yarn build --scope @markuplint/pug-parser && yarn test --scope @markuplint/pug-parser`
82
+
83
+ ### 3. Updating AST Optimization
84
+
85
+ 1. Read `src/pug-parser/index.ts` — the optimization pipeline:
86
+ - `pugParse()` — entry point: lex → parse → optimize
87
+ - `optimizeAST()` — recursive node enrichment
88
+ - `getOffsetsFromLines()` — cumulative offset lookup table
89
+ - `getLocationFromToken()` — token matching by line/column
90
+ - `getAttrs()` — attribute enrichment from lexer tokens
91
+ - `getEndAttributeLocation()` — tag end position including attributes
92
+ - `mergeTextNode()` — consecutive text node merging
93
+ - `getPipelessText()` — pipeless text block detection
94
+ - `getRawTextAndLocationEnd()` — multi-line text handling
95
+ - `optimizeASTOfConditionalNode()` — else-if/else chain processing
96
+ 2. Make the change, paying attention to:
97
+ - Offsets must be computed from `getOffsetsFromLines()` using `offsets[line - 2]`
98
+ - End positions come from matching lexer tokens via `getLocationFromToken()`
99
+ - `raw` must be sliced from the original source: `pug.slice(offset, endOffset)`
100
+ - Token cloning via `structuredClone()` is required — the parser mutates the token array
101
+ 3. Build and test: `yarn build --scope @markuplint/pug-parser && yarn test --scope @markuplint/pug-parser`
102
+
103
+ ### 4. Modifying Inline HTML Handling
104
+
105
+ 1. Read `src/parser.ts` — the `Text` case in `nodeize()`:
106
+ - Text with `<` or `#[` is parsed through `HtmlInPugParser`
107
+ - `#ps:tag-interpolation` nodes are recursively parsed by `PugParser`
108
+ 2. To change tag interpolation syntax:
109
+ - Modify the `ignoreTags` in `HtmlInPugParser` constructor
110
+ - Update the `#ps:tag-interpolation` detection in the `Text` case
111
+ - Update the offset calculations for `#[` prefix and `]` suffix stripping
112
+ 3. To change inline HTML behavior:
113
+ - Modify the `HtmlInPugParser` class (extends `HtmlParser`)
114
+ - The `offsetOffset`, `offsetLine`, `offsetColumn` context must be passed correctly
115
+ 4. Build and test: `yarn build --scope @markuplint/pug-parser && yarn test --scope @markuplint/pug-parser`
116
+
117
+ ### 5. Modifying the useOffset Indent Filtering
118
+
119
+ 1. Read `src/pug-parser/index.ts` — the `pugParse()` function
120
+ 2. The `useOffset` flag filters `indent` and `outdent` tokens when parsing sub-templates at non-zero offsets
121
+ 3. To modify:
122
+ - Change the filter condition in the `if (useOffset)` block
123
+ - Consider whether other token types need filtering for the sub-template context
124
+ 4. Build and test: `yarn build --scope @markuplint/pug-parser && yarn test --scope @markuplint/pug-parser`
125
+
126
+ ## Troubleshooting
127
+
128
+ ### Pug AST node has wrong offsets
129
+
130
+ **Symptom:** A Pug node's `offset`, `endOffset`, `endLine`, or `endColumn` is incorrect in the markuplint AST.
131
+
132
+ **Cause:** The `optimizeAST()` function is computing wrong offsets, or the matching lexer token is incorrect.
133
+
134
+ **Solution:**
135
+
136
+ 1. Check `getOffsetsFromLines()` — verify the cumulative offset table is correct for the input
137
+ 2. Check `getLocationFromToken()` — ensure the correct token is matched by line/column, and that `tokenType` filtering is correct
138
+ 3. For tags with attributes, check `getEndAttributeLocation()` — verify it stops at the right token
139
+ 4. Add debug logging: `console.log(JSON.stringify(node, null, 2))` in the relevant `optimizeAST()` case
140
+
141
+ ### Tag interpolation is not parsed
142
+
143
+ **Symptom:** `#[tag content]` appears as raw text instead of being expanded into markuplint nodes.
144
+
145
+ **Cause:** The text node is not reaching the `HtmlInPugParser` path, or the `#ps:tag-interpolation` detection is failing.
146
+
147
+ **Solution:**
148
+
149
+ 1. Check the `Text` case in `nodeize()` — ensure `originNode.raw.includes('#[')` evaluates to `true`
150
+ 2. Check the `HtmlInPugParser` — verify `ignoreTags` correctly masks `#[...]`
151
+ 3. Check the `#ps:tag-interpolation` detection — ensure `node.nodeName === '#ps:tag-interpolation'`
152
+ 4. Check the recursive `PugParser` call — verify offset context (`offsetOffset`, `offsetLine`, `offsetColumn`) is computed correctly
153
+
154
+ ### Attribute parsing fails for complex expressions
155
+
156
+ **Symptom:** A Pug attribute with a complex JavaScript value (e.g., `data-value=obj.prop + 1`) causes a parse error or incorrect AST.
157
+
158
+ **Cause:** The `scriptParser()` result is not being handled correctly for multi-token expressions.
159
+
160
+ **Solution:**
161
+
162
+ 1. Check the `visitAttr()` method — the final `return` block handles multi-token expressions as `isDynamicValue: true, valueType: 'code'`
163
+ 2. Check `scriptParser()` from `@markuplint/parser-utils` — verify it correctly tokenizes the value expression
164
+ 3. For single-token expressions, verify the `switch (token.type)` handles the token type correctly
165
+
166
+ ### Shorthand attribute has wrong potentialName
167
+
168
+ **Symptom:** `#my-id` or `.my-class` produces an attribute with the wrong `potentialName`.
169
+
170
+ **Cause:** The shorthand detection or `endOffset` recalculation is wrong.
171
+
172
+ **Solution:**
173
+
174
+ 1. Check the `#`/`.` branch in `visitAttr()` — ensure `potentialName` is set to `'id'` for `#` and `'class'` for `.`
175
+ 2. Check the `endOffset` recalculation in `nodeize()` Tag case — for shorthand attributes, `attr.offset === attr.endOffset` must be true, and `endOffset` should be `attr.offset + attr.val.length - 1`
176
+ 3. Verify the `val` value from the Pug AST — for `#my-id`, `val` should be `"'my-id'"` (with surrounding quotes)
177
+
178
+ ### Pipeless text not detected
179
+
180
+ **Symptom:** Indented text after a tag with `.` is not treated as pipeless text.
181
+
182
+ **Cause:** The `getPipelessText()` function is not finding `start-pipeless-text` / `end-pipeless-text` tokens, or the line range check is failing.
183
+
184
+ **Solution:**
185
+
186
+ 1. Check the lexer output — verify that `start-pipeless-text` and `end-pipeless-text` tokens exist
187
+ 2. Check the line range: `startPipelessText.loc.start.line < node.line && node.line < endPipelessText.loc.start.line`
188
+ 3. If the tokens exist but the range is wrong, the issue may be in the pug-lexer version
package/lib/index.d.ts CHANGED
@@ -1 +1,7 @@
1
+ /**
2
+ * @module
3
+ * Pug template parser for markuplint. Provides a parser that transforms Pug (formerly Jade)
4
+ * template syntax into markuplint's AST, handling indentation-based nesting, tag interpolation,
5
+ * inline HTML, Pug attributes, mixins, conditionals, and other Pug-specific constructs.
6
+ */
1
7
  export { parser } from './parser.js';
package/lib/index.js CHANGED
@@ -1 +1,7 @@
1
+ /**
2
+ * @module
3
+ * Pug template parser for markuplint. Provides a parser that transforms Pug (formerly Jade)
4
+ * template syntax into markuplint's AST, handling indentation-based nesting, tag interpolation,
5
+ * inline HTML, Pug attributes, mixins, conditionals, and other Pug-specific constructs.
6
+ */
1
7
  export { parser } from './parser.js';
package/lib/parser.d.ts CHANGED
@@ -2,6 +2,14 @@ import type { ASTNode } from './types.js';
2
2
  import type { MLASTAttr, MLASTNodeTreeItem, MLASTParentNode } from '@markuplint/ml-ast';
3
3
  import type { ChildToken, ParseOptions, Token } from '@markuplint/parser-utils';
4
4
  import { ParserError, Parser } from '@markuplint/parser-utils';
5
+ /**
6
+ * Parser implementation for Pug templates.
7
+ * Extends the base Parser to handle Pug's indentation-based syntax, including tags,
8
+ * inline HTML, tag interpolation (`#[...]`), Pug attributes (including shorthand
9
+ * `#id` and `.class`), `&attributes` spread syntax, mixins, conditionals,
10
+ * and other Pug-specific constructs. Uses pug-lexer and pug-parser for
11
+ * initial tokenization before mapping to markuplint's node tree.
12
+ */
5
13
  declare class PugParser extends Parser<ASTNode> {
6
14
  constructor();
7
15
  tokenize(options?: ParseOptions): {
@@ -9,8 +17,30 @@ declare class PugParser extends Parser<ASTNode> {
9
17
  isFragment: boolean;
10
18
  };
11
19
  parseError(error: any): ParserError;
20
+ /**
21
+ * Converts a Pug AST node into markuplint node tree items.
22
+ * Handles Doctype, Text (including inline HTML and tag interpolation),
23
+ * Comment, BlockComment, Tag (with attributes and child blocks),
24
+ * and other Pug-specific constructs (mixins, conditionals, etc.)
25
+ * which are mapped to preprocessor-specific blocks.
26
+ *
27
+ * @param originNode - The Pug AST node to convert
28
+ * @param parentNode - The parent node in the markuplint tree, or null for root nodes
29
+ * @param depth - The nesting depth of the node
30
+ * @returns An array of markuplint node tree items
31
+ */
12
32
  nodeize(originNode: ASTNode, parentNode: MLASTParentNode | null, depth: number): readonly MLASTNodeTreeItem[];
13
33
  afterFlattenNodes(nodeList: readonly MLASTNodeTreeItem[]): readonly MLASTNodeTreeItem[];
34
+ /**
35
+ * Visits an element token for Pug, constructing a start tag node with
36
+ * pre-parsed attributes (including `&attributes` spread syntax) and
37
+ * visiting child nodes within the Pug block.
38
+ *
39
+ * @param token - The child token with tag metadata and namespace
40
+ * @param childNodes - The child Pug AST nodes within the tag's block
41
+ * @param options - Options containing pre-parsed attribute overrides
42
+ * @returns An array of markuplint node tree items for the element and its children
43
+ */
14
44
  visitElement(token: ChildToken & {
15
45
  readonly nodeName: string;
16
46
  readonly namespace: string;
@@ -21,6 +51,14 @@ declare class PugParser extends Parser<ASTNode> {
21
51
  };
22
52
  }): MLASTNodeTreeItem[];
23
53
  visitSpreadAttr(): null;
54
+ /**
55
+ * Visits an attribute token, handling Pug-specific syntax including
56
+ * shorthand `#id` and `.class` notation, quoted attribute names,
57
+ * unescaped attribute names (trailing `!`), and JavaScript expression values.
58
+ *
59
+ * @param token - The token representing the attribute
60
+ * @returns The parsed attribute node with Pug-specific metadata
61
+ */
24
62
  visitAttr(token: Token): MLASTAttr;
25
63
  }
26
64
  export declare const parser: PugParser;
package/lib/parser.js CHANGED
@@ -1,6 +1,11 @@
1
1
  import { HtmlParser, getNamespace } from '@markuplint/html-parser';
2
2
  import { ParserError, Parser, AttrState, scriptParser } from '@markuplint/parser-utils';
3
3
  import { pugParse } from './pug-parser/index.js';
4
+ /**
5
+ * Internal HTML parser used for inline HTML content within Pug templates.
6
+ * Extends the standard HTML parser to handle Pug tag interpolation syntax (`#[...]`),
7
+ * treating interpolated tags as preprocessor-specific blocks.
8
+ */
4
9
  class HtmlInPugParser extends HtmlParser {
5
10
  constructor() {
6
11
  super({
@@ -19,6 +24,14 @@ class HtmlInPugParser extends HtmlParser {
19
24
  });
20
25
  }
21
26
  }
27
+ /**
28
+ * Parser implementation for Pug templates.
29
+ * Extends the base Parser to handle Pug's indentation-based syntax, including tags,
30
+ * inline HTML, tag interpolation (`#[...]`), Pug attributes (including shorthand
31
+ * `#id` and `.class`), `&attributes` spread syntax, mixins, conditionals,
32
+ * and other Pug-specific constructs. Uses pug-lexer and pug-parser for
33
+ * initial tokenization before mapping to markuplint's node tree.
34
+ */
22
35
  class PugParser extends Parser {
23
36
  constructor() {
24
37
  super({
@@ -43,6 +56,18 @@ class PugParser extends Parser {
43
56
  }
44
57
  return super.parseError(error);
45
58
  }
59
+ /**
60
+ * Converts a Pug AST node into markuplint node tree items.
61
+ * Handles Doctype, Text (including inline HTML and tag interpolation),
62
+ * Comment, BlockComment, Tag (with attributes and child blocks),
63
+ * and other Pug-specific constructs (mixins, conditionals, etc.)
64
+ * which are mapped to preprocessor-specific blocks.
65
+ *
66
+ * @param originNode - The Pug AST node to convert
67
+ * @param parentNode - The parent node in the markuplint tree, or null for root nodes
68
+ * @param depth - The nesting depth of the node
69
+ * @returns An array of markuplint node tree items
70
+ */
46
71
  nodeize(
47
72
  // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
48
73
  originNode, parentNode, depth) {
@@ -189,6 +214,16 @@ class PugParser extends Parser {
189
214
  exposeWhiteSpace: false,
190
215
  });
191
216
  }
217
+ /**
218
+ * Visits an element token for Pug, constructing a start tag node with
219
+ * pre-parsed attributes (including `&attributes` spread syntax) and
220
+ * visiting child nodes within the Pug block.
221
+ *
222
+ * @param token - The child token with tag metadata and namespace
223
+ * @param childNodes - The child Pug AST nodes within the tag's block
224
+ * @param options - Options containing pre-parsed attribute overrides
225
+ * @returns An array of markuplint node tree items for the element and its children
226
+ */
192
227
  visitElement(token,
193
228
  // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
194
229
  childNodes, options) {
@@ -210,6 +245,14 @@ class PugParser extends Parser {
210
245
  visitSpreadAttr() {
211
246
  return null;
212
247
  }
248
+ /**
249
+ * Visits an attribute token, handling Pug-specific syntax including
250
+ * shorthand `#id` and `.class` notation, quoted attribute names,
251
+ * unescaped attribute names (trailing `!`), and JavaScript expression values.
252
+ *
253
+ * @param token - The token representing the attribute
254
+ * @returns The parsed attribute node with Pug-specific metadata
255
+ */
213
256
  visitAttr(token) {
214
257
  if (token.raw[0] === '#' || token.raw[0] === '.') {
215
258
  const attr = super.visitAttr(token, {
@@ -1,2 +1,11 @@
1
1
  import type { ASTBlock } from '../types.js';
2
+ /**
3
+ * Parses a Pug template string into an optimized AST with computed offsets
4
+ * and location data by lexing with pug-lexer, parsing with pug-parser,
5
+ * and then enriching each node with raw source, offsets, and end positions.
6
+ *
7
+ * @param pug - The raw Pug template source code
8
+ * @param useOffset - Whether to strip indent/outdent tokens (used when parsing at a non-zero offset)
9
+ * @returns The optimized Pug AST block containing enriched nodes
10
+ */
2
11
  export declare function pugParse(pug: string, useOffset?: boolean): ASTBlock;