@markuplint/mustache-parser 4.6.22 → 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.
- package/ARCHITECTURE.ja.md +106 -0
- package/ARCHITECTURE.md +106 -0
- package/CHANGELOG.md +3 -3
- package/SKILL.md +100 -0
- package/docs/maintenance.ja.md +120 -0
- package/docs/maintenance.md +120 -0
- package/lib/index.d.ts +6 -0
- package/lib/index.js +6 -0
- package/lib/parser.d.ts +11 -0
- package/lib/parser.js +11 -0
- package/package.json +4 -4
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
# @markuplint/mustache-parser
|
|
2
|
+
|
|
3
|
+
## 概要
|
|
4
|
+
|
|
5
|
+
`@markuplint/mustache-parser` は `HtmlParser` を拡張し、Mustache および Handlebars テンプレート式を含む HTML ファイルのリントを可能にします。完全なテンプレートパーサーを実装するのではなく、`HtmlParser` の `ignoreTags` メカニズムを設定して Mustache/Handlebars 構文を不透明なブロックとして扱います。これにより、markuplint はテンプレート式をスキップしながら周囲の HTML 構造を検証できます。
|
|
6
|
+
|
|
7
|
+
Handlebars は Mustache のスーパーセットであり、同じデリミタ構文を使用するため、このパッケージは Handlebars とも互換性があります。
|
|
8
|
+
|
|
9
|
+
## 動作原理
|
|
10
|
+
|
|
11
|
+
パーサーは `HtmlParser` のコンストラクタで3つの `ignoreTags` エントリを宣言することで動作します。トークン化の際、基底 `Parser` クラスがソース内でこれらのデリミタペアを検索し、`#ps:*`(PreprocessorSpecific)ノードとして抽出し、残りの HTML を通常通りパースします。
|
|
12
|
+
|
|
13
|
+
`ignoreTags` エントリの順序は重要です。より具体的なパターンを、より一般的なパターンの前に配置する必要があります。例えば、`{{{`(トリプルスタッシュ)は `{{`(ダブルスタッシュ)の前にマッチする必要があり、`{{!`(コメント)も `{{` の前にマッチする必要があります。
|
|
14
|
+
|
|
15
|
+
## ignoreTags 設定
|
|
16
|
+
|
|
17
|
+
| タイプ | 開始 | 終了 | 説明 |
|
|
18
|
+
| -------------------- | ----- | ----- | -------------------------------------------------------- |
|
|
19
|
+
| `mustache-comment` | `{{!` | `}}` | Mustache コメント(`{{! comment }}`) |
|
|
20
|
+
| `mustache-unescaped` | `{{{` | `}}}` | エスケープなし / トリプルスタッシュ出力(`{{{ raw }}}`) |
|
|
21
|
+
| `mustache-tag` | `{{` | `}}` | 標準的な補間とブロックヘルパー |
|
|
22
|
+
|
|
23
|
+
マッチした式は `#ps:mustache-tag`、`#ps:mustache-unescaped`、`#ps:mustache-comment` のような名前を持つ AST ノードになります。
|
|
24
|
+
|
|
25
|
+
## サポートされない構文
|
|
26
|
+
|
|
27
|
+
**引用符なしの属性値**内のテンプレート式はサポートされていません。これはすべてのテンプレートエンジンパーサーに共通する既知の制限です([#240](https://github.com/markuplint/markuplint/issues/240))。[ウェブサイトのドキュメント](https://markuplint.dev/docs/guides/besides-html)も参照してください。
|
|
28
|
+
|
|
29
|
+
使用可能:
|
|
30
|
+
|
|
31
|
+
```html
|
|
32
|
+
<div attr="{{ value }}"></div>
|
|
33
|
+
<div attr="{{ value }}"></div>
|
|
34
|
+
<div attr="{{ value }}-{{ value2 }}-{{ value3 }}"></div>
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
使用不可(引用符なし):
|
|
38
|
+
|
|
39
|
+
```html
|
|
40
|
+
<div attr="{{" value }}></div>
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## ディレクトリ構成
|
|
44
|
+
|
|
45
|
+
```
|
|
46
|
+
src/
|
|
47
|
+
├── index.ts — parser シングルトンを再エクスポート
|
|
48
|
+
├── parser.ts — HtmlParser を拡張する MustacheParser クラス
|
|
49
|
+
└── index.spec.ts — タグ認識とノードリスト構造のテスト
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## 主要ソースファイル
|
|
53
|
+
|
|
54
|
+
### `parser.ts`
|
|
55
|
+
|
|
56
|
+
上記3つの `ignoreTags` エントリを持つ `MustacheParser`(`HtmlParser` を拡張)を定義します。シングルトンインスタンスが `parser` としてエクスポートされます。
|
|
57
|
+
|
|
58
|
+
### `index.ts`
|
|
59
|
+
|
|
60
|
+
`parser.ts` から `parser` をパブリック API として再エクスポートします。
|
|
61
|
+
|
|
62
|
+
### `index.spec.ts`
|
|
63
|
+
|
|
64
|
+
テストカバレッジ:
|
|
65
|
+
|
|
66
|
+
- テキストや HTML 要素に挟まれた単一・複数の `{{ }}` タグ
|
|
67
|
+
- ネストされた HTML を含むブロックヘルパー(`{{#user}}...{{/user}}`)
|
|
68
|
+
- ベアテキスト(HTML 要素でラップされていない場合)
|
|
69
|
+
- 各タグタイプの正しい `nodeName`(`#ps:mustache-tag`、`#ps:mustache-unescaped`、`#ps:mustache-comment`)
|
|
70
|
+
|
|
71
|
+
## 統合ポイント
|
|
72
|
+
|
|
73
|
+
```mermaid
|
|
74
|
+
flowchart TD
|
|
75
|
+
subgraph upstream ["上流"]
|
|
76
|
+
htmlParser["@markuplint/html-parser\n(HtmlParser 基底クラス)"]
|
|
77
|
+
parserUtils["@markuplint/parser-utils\n(抽象 Parser, nodeListToDebugMaps)"]
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
subgraph pkg ["@markuplint/mustache-parser"]
|
|
81
|
+
mustacheParser["MustacheParser\nextends HtmlParser"]
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
subgraph downstream ["下流"]
|
|
85
|
+
mlCore["@markuplint/ml-core\n(MLASTDocument -> MLDOM)"]
|
|
86
|
+
config["markuplint 設定\n(parser オプション)"]
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
htmlParser -->|"継承"| mustacheParser
|
|
90
|
+
parserUtils -->|"テストユーティリティ"| mustacheParser
|
|
91
|
+
mustacheParser -->|"MLASTDocument を生成"| mlCore
|
|
92
|
+
config -->|"パーサーを選択"| mustacheParser
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### 上流
|
|
96
|
+
|
|
97
|
+
- **`@markuplint/html-parser`** -- `MustacheParser` が拡張する基底クラス `HtmlParser` を提供。HTML パースロジック(parse5 統合、ゴースト要素、名前空間解決)はすべて継承される。
|
|
98
|
+
|
|
99
|
+
### 下流
|
|
100
|
+
|
|
101
|
+
- **`@markuplint/ml-core`** -- このパーサーが生成する `MLASTDocument` を消費
|
|
102
|
+
- **markuplint 設定** -- ユーザーが markuplint 設定の `parser` オプションでこのパーサーを選択
|
|
103
|
+
|
|
104
|
+
## ドキュメントマップ
|
|
105
|
+
|
|
106
|
+
- [メンテナンスガイド](docs/maintenance.ja.md) -- コマンド、レシピ、トラブルシューティング
|
package/ARCHITECTURE.md
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
# @markuplint/mustache-parser
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
`@markuplint/mustache-parser` extends `HtmlParser` to lint HTML files containing Mustache and Handlebars template expressions. Instead of implementing a full template parser, it configures `HtmlParser`'s `ignoreTags` mechanism to treat Mustache/Handlebars syntax as opaque blocks. This lets markuplint validate the surrounding HTML structure while skipping over template expressions.
|
|
6
|
+
|
|
7
|
+
The package is also compatible with Handlebars, since Handlebars is a superset of Mustache and uses the same delimiter syntax.
|
|
8
|
+
|
|
9
|
+
## How It Works
|
|
10
|
+
|
|
11
|
+
The parser works by declaring three `ignoreTags` entries in the `HtmlParser` constructor. During tokenization, the base `Parser` class scans the source for these delimiter pairs, extracts them as `#ps:*` (PreprocessorSpecific) nodes, and parses the remaining HTML normally.
|
|
12
|
+
|
|
13
|
+
The order of `ignoreTags` entries matters: more specific patterns must appear before less specific ones. For example, `{{{` (triple-stache) must be matched before `{{` (double-stache), and `{{!` (comment) must be matched before `{{` as well.
|
|
14
|
+
|
|
15
|
+
## ignoreTags Configuration
|
|
16
|
+
|
|
17
|
+
| Type | Start | End | Description |
|
|
18
|
+
| -------------------- | ----- | ----- | ------------------------------------------------ |
|
|
19
|
+
| `mustache-comment` | `{{!` | `}}` | Mustache comments (`{{! comment }}`) |
|
|
20
|
+
| `mustache-unescaped` | `{{{` | `}}}` | Unescaped / triple-stache output (`{{{ raw }}}`) |
|
|
21
|
+
| `mustache-tag` | `{{` | `}}` | Standard interpolation and block helpers |
|
|
22
|
+
|
|
23
|
+
Matched expressions become AST nodes with names like `#ps:mustache-tag`, `#ps:mustache-unescaped`, and `#ps:mustache-comment`.
|
|
24
|
+
|
|
25
|
+
## Unsupported Syntaxes
|
|
26
|
+
|
|
27
|
+
Template expressions inside **unquoted attribute values** are not supported. This is a known limitation shared by all template engine parsers ([#240](https://github.com/markuplint/markuplint/issues/240)). See also the [website documentation](https://markuplint.dev/docs/guides/besides-html).
|
|
28
|
+
|
|
29
|
+
Available:
|
|
30
|
+
|
|
31
|
+
```html
|
|
32
|
+
<div attr="{{ value }}"></div>
|
|
33
|
+
<div attr="{{ value }}"></div>
|
|
34
|
+
<div attr="{{ value }}-{{ value2 }}-{{ value3 }}"></div>
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Unavailable (unquoted):
|
|
38
|
+
|
|
39
|
+
```html
|
|
40
|
+
<div attr="{{" value }}></div>
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Directory Structure
|
|
44
|
+
|
|
45
|
+
```
|
|
46
|
+
src/
|
|
47
|
+
├── index.ts — Re-exports the parser singleton
|
|
48
|
+
├── parser.ts — MustacheParser class extending HtmlParser
|
|
49
|
+
└── index.spec.ts — Tests for tag recognition and node list structure
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Key Source Files
|
|
53
|
+
|
|
54
|
+
### `parser.ts`
|
|
55
|
+
|
|
56
|
+
Defines `MustacheParser` which extends `HtmlParser` with the three `ignoreTags` entries listed above. A singleton instance is exported as `parser`.
|
|
57
|
+
|
|
58
|
+
### `index.ts`
|
|
59
|
+
|
|
60
|
+
Re-exports `parser` from `parser.ts` as the public API.
|
|
61
|
+
|
|
62
|
+
### `index.spec.ts`
|
|
63
|
+
|
|
64
|
+
Tests cover:
|
|
65
|
+
|
|
66
|
+
- Single and multiple `{{ }}` tags interleaved with text and HTML elements
|
|
67
|
+
- Block helpers (`{{#user}}...{{/user}}`) with nested HTML
|
|
68
|
+
- Bare text (no wrapping HTML element)
|
|
69
|
+
- Correct `nodeName` for each tag type (`#ps:mustache-tag`, `#ps:mustache-unescaped`, `#ps:mustache-comment`)
|
|
70
|
+
|
|
71
|
+
## Integration Points
|
|
72
|
+
|
|
73
|
+
```mermaid
|
|
74
|
+
flowchart TD
|
|
75
|
+
subgraph upstream ["Upstream"]
|
|
76
|
+
htmlParser["@markuplint/html-parser\n(HtmlParser base class)"]
|
|
77
|
+
parserUtils["@markuplint/parser-utils\n(Abstract Parser, nodeListToDebugMaps)"]
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
subgraph pkg ["@markuplint/mustache-parser"]
|
|
81
|
+
mustacheParser["MustacheParser\nextends HtmlParser"]
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
subgraph downstream ["Downstream"]
|
|
85
|
+
mlCore["@markuplint/ml-core\n(MLASTDocument -> MLDOM)"]
|
|
86
|
+
config["markuplint config\n(parser option)"]
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
htmlParser -->|"extends"| mustacheParser
|
|
90
|
+
parserUtils -->|"test utility"| mustacheParser
|
|
91
|
+
mustacheParser -->|"produces MLASTDocument"| mlCore
|
|
92
|
+
config -->|"selects parser"| mustacheParser
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### Upstream
|
|
96
|
+
|
|
97
|
+
- **`@markuplint/html-parser`** -- Provides `HtmlParser`, the base class that `MustacheParser` extends. All HTML parsing logic (parse5 integration, ghost elements, namespace resolution) is inherited.
|
|
98
|
+
|
|
99
|
+
### Downstream
|
|
100
|
+
|
|
101
|
+
- **`@markuplint/ml-core`** -- Consumes the `MLASTDocument` produced by this parser
|
|
102
|
+
- **markuplint config** -- Users select this parser via the `parser` option in their markuplint configuration
|
|
103
|
+
|
|
104
|
+
## Documentation Map
|
|
105
|
+
|
|
106
|
+
- [Maintenance Guide](docs/maintenance.md) -- Commands, recipes, and troubleshooting
|
package/CHANGELOG.md
CHANGED
|
@@ -3,13 +3,13 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
-
## [4.6.
|
|
6
|
+
## [4.6.23](https://github.com/markuplint/markuplint/compare/@markuplint/mustache-parser@4.6.22...@markuplint/mustache-parser@4.6.23) (2026-02-10)
|
|
7
7
|
|
|
8
8
|
**Note:** Version bump only for package @markuplint/mustache-parser
|
|
9
9
|
|
|
10
|
+
## [4.6.22](https://github.com/markuplint/markuplint/compare/@markuplint/mustache-parser@4.6.21...@markuplint/mustache-parser@4.6.22) (2025-11-05)
|
|
10
11
|
|
|
11
|
-
|
|
12
|
-
|
|
12
|
+
**Note:** Version bump only for package @markuplint/mustache-parser
|
|
13
13
|
|
|
14
14
|
## [4.6.21](https://github.com/markuplint/markuplint/compare/@markuplint/mustache-parser@4.6.20...@markuplint/mustache-parser@4.6.21) (2025-08-24)
|
|
15
15
|
|
package/SKILL.md
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Perform maintenance tasks for @markuplint/mustache-parser
|
|
3
|
+
globs:
|
|
4
|
+
- packages/@markuplint/mustache-parser/src/**
|
|
5
|
+
alwaysApply: false
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# mustache-parser-maintenance
|
|
9
|
+
|
|
10
|
+
Perform maintenance tasks for `@markuplint/mustache-parser`: modify ignoreTags configuration,
|
|
11
|
+
add new Mustache/Handlebars tag types, and update parser behavior.
|
|
12
|
+
|
|
13
|
+
## Input
|
|
14
|
+
|
|
15
|
+
`$ARGUMENTS` specifies the task. Supported tasks:
|
|
16
|
+
|
|
17
|
+
| Task | Description |
|
|
18
|
+
| ------------------ | -------------------------------------------- |
|
|
19
|
+
| `modify-ignoretag` | Modify or add an ignoreTags entry |
|
|
20
|
+
| `fix-parsing` | Fix a parsing issue with Mustache/Handlebars |
|
|
21
|
+
| `update-tests` | Add or update test cases |
|
|
22
|
+
|
|
23
|
+
If omitted, defaults to `modify-ignoretag`.
|
|
24
|
+
|
|
25
|
+
## Reference
|
|
26
|
+
|
|
27
|
+
Before executing any task, read `docs/maintenance.md` (or `docs/maintenance.ja.md`)
|
|
28
|
+
for the full guide. The recipes there are the source of truth for procedures.
|
|
29
|
+
|
|
30
|
+
Also read:
|
|
31
|
+
|
|
32
|
+
- `ARCHITECTURE.md` -- Package overview, ignoreTags configuration, and integration points
|
|
33
|
+
- `src/parser.ts` -- MustacheParser class (source of truth for ignoreTags)
|
|
34
|
+
|
|
35
|
+
## Task: modify-ignoretag
|
|
36
|
+
|
|
37
|
+
Modify or add an ignoreTags entry. Follow recipe #1 in `docs/maintenance.md`.
|
|
38
|
+
|
|
39
|
+
### Step 1: Understand the current configuration
|
|
40
|
+
|
|
41
|
+
1. Read `src/parser.ts` and review the existing `ignoreTags` array
|
|
42
|
+
2. Understand the matching order: more specific patterns must come before less specific ones
|
|
43
|
+
|
|
44
|
+
### Step 2: Make the change
|
|
45
|
+
|
|
46
|
+
1. Add or modify the entry in the `ignoreTags` array in the `MustacheParser` constructor
|
|
47
|
+
2. Ensure correct ordering (e.g., `{{{` before `{{`, `{{!` before `{{`)
|
|
48
|
+
3. Each entry needs `type`, `start`, and `end` properties
|
|
49
|
+
|
|
50
|
+
### Step 3: Verify
|
|
51
|
+
|
|
52
|
+
1. Build: `yarn build --scope @markuplint/mustache-parser`
|
|
53
|
+
2. Add test cases to `src/index.spec.ts` for the new tag type
|
|
54
|
+
3. Test: `yarn test --scope @markuplint/mustache-parser`
|
|
55
|
+
|
|
56
|
+
## Task: fix-parsing
|
|
57
|
+
|
|
58
|
+
Fix a parsing issue with Mustache/Handlebars templates. Follow recipe #2 in `docs/maintenance.md`.
|
|
59
|
+
|
|
60
|
+
### Step 1: Reproduce the issue
|
|
61
|
+
|
|
62
|
+
1. Create a minimal HTML template that demonstrates the parsing problem
|
|
63
|
+
2. Write a failing test case in `src/index.spec.ts`
|
|
64
|
+
|
|
65
|
+
### Step 2: Investigate
|
|
66
|
+
|
|
67
|
+
1. Read `src/parser.ts` to check if the issue is in the ignoreTags configuration
|
|
68
|
+
2. If the issue is in the base parser, check `@markuplint/html-parser` (HtmlParser)
|
|
69
|
+
|
|
70
|
+
### Step 3: Fix and verify
|
|
71
|
+
|
|
72
|
+
1. Apply the fix
|
|
73
|
+
2. Build: `yarn build --scope @markuplint/mustache-parser`
|
|
74
|
+
3. Test: `yarn test --scope @markuplint/mustache-parser`
|
|
75
|
+
|
|
76
|
+
## Task: update-tests
|
|
77
|
+
|
|
78
|
+
Add or update test cases. Follow recipe #3 in `docs/maintenance.md`.
|
|
79
|
+
|
|
80
|
+
### Step 1: Understand the testing pattern
|
|
81
|
+
|
|
82
|
+
1. Read `src/index.spec.ts` to understand the existing test structure
|
|
83
|
+
2. Tests use `nodeListToDebugMaps` from `@markuplint/parser-utils` for assertions
|
|
84
|
+
|
|
85
|
+
### Step 2: Write the tests
|
|
86
|
+
|
|
87
|
+
1. Use `parser.parse()` to parse the template
|
|
88
|
+
2. Assert against `nodeListToDebugMaps(doc.nodeList)` for node structure
|
|
89
|
+
3. Assert against `doc.nodeList[n]?.nodeName` for individual node names
|
|
90
|
+
|
|
91
|
+
### Step 3: Verify
|
|
92
|
+
|
|
93
|
+
1. Test: `yarn test --scope @markuplint/mustache-parser`
|
|
94
|
+
|
|
95
|
+
## Rules
|
|
96
|
+
|
|
97
|
+
1. **Maintain ignoreTags ordering** -- more specific patterns (`{{{`, `{{!`) must appear before the general `{{` pattern.
|
|
98
|
+
2. **Keep the parser minimal** -- this package only configures `ignoreTags`; HTML parsing logic belongs in `@markuplint/html-parser`.
|
|
99
|
+
3. **Add JSDoc comments** to all new public exports.
|
|
100
|
+
4. **Test all tag types** when modifying the ignoreTags configuration.
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
# メンテナンスガイド
|
|
2
|
+
|
|
3
|
+
## コマンド
|
|
4
|
+
|
|
5
|
+
| コマンド | 説明 |
|
|
6
|
+
| ------------------------------------------------ | ---------------------- |
|
|
7
|
+
| `yarn build --scope @markuplint/mustache-parser` | このパッケージをビルド |
|
|
8
|
+
| `yarn dev --scope @markuplint/mustache-parser` | ウォッチモードでビルド |
|
|
9
|
+
| `yarn clean --scope @markuplint/mustache-parser` | ビルド成果物を削除 |
|
|
10
|
+
| `yarn test --scope @markuplint/mustache-parser` | テストを実行 |
|
|
11
|
+
|
|
12
|
+
## テスト
|
|
13
|
+
|
|
14
|
+
テストファイルは `*.spec.ts` の命名規則に従い、`src/` ディレクトリに配置されています:
|
|
15
|
+
|
|
16
|
+
| テストファイル | カバレッジ |
|
|
17
|
+
| --------------- | ---------------------------------------------------------- |
|
|
18
|
+
| `index.spec.ts` | タグ認識、ノードリスト構造、ブロックヘルパー、ベアテキスト |
|
|
19
|
+
|
|
20
|
+
主なテストパターンでは `nodeListToDebugMaps` を使用したスナップショット形式のアサーションを行います:
|
|
21
|
+
|
|
22
|
+
```ts
|
|
23
|
+
import { nodeListToDebugMaps } from '@markuplint/parser-utils';
|
|
24
|
+
import { parser } from './parser.js';
|
|
25
|
+
|
|
26
|
+
const doc = parser.parse('<div>{{ name }}</div>');
|
|
27
|
+
expect(nodeListToDebugMaps(doc.nodeList)).toStrictEqual([
|
|
28
|
+
'[1:1]>[1:6](0,5)div: <div>',
|
|
29
|
+
'[1:6]>[1:15](5,14)#ps:mustache-tag: {{␣name␣}}',
|
|
30
|
+
'[1:15]>[1:21](14,20)div: </div>',
|
|
31
|
+
]);
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
個別のタグタイプのアサーション:
|
|
35
|
+
|
|
36
|
+
```ts
|
|
37
|
+
expect(parse('{{ any }}').nodeList[0]?.nodeName).toBe('#ps:mustache-tag');
|
|
38
|
+
expect(parse('{{{ any }}}').nodeList[0]?.nodeName).toBe('#ps:mustache-unescaped');
|
|
39
|
+
expect(parse('{{! any }}').nodeList[0]?.nodeName).toBe('#ps:mustache-comment');
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## レシピ
|
|
43
|
+
|
|
44
|
+
### 1. ignoreTags エントリの追加・変更
|
|
45
|
+
|
|
46
|
+
1. `src/parser.ts` を読み、`MustacheParser` コンストラクタの `ignoreTags` 配列を確認
|
|
47
|
+
2. エントリを追加または変更し、正しい順序を維持:
|
|
48
|
+
- より具体的な開始デリミタは、より一般的なものの前に配置する必要がある
|
|
49
|
+
- 現在の順序: `{{!` -> `{{{` -> `{{`
|
|
50
|
+
3. 各エントリには `type`(文字列識別子)、`start`(開始デリミタ)、`end`(終了デリミタ)が必要
|
|
51
|
+
4. ビルド: `yarn build --scope @markuplint/mustache-parser`
|
|
52
|
+
5. `src/index.spec.ts` にテストケースを追加し、新しいタグタイプが正しい `#ps:*` ノード名を生成することを検証
|
|
53
|
+
6. テスト: `yarn test --scope @markuplint/mustache-parser`
|
|
54
|
+
|
|
55
|
+
### 2. パース問題の修正
|
|
56
|
+
|
|
57
|
+
1. 最小限の再現テンプレートを作成し、`src/index.spec.ts` に失敗するテストを記述
|
|
58
|
+
2. 問題の所在を特定:
|
|
59
|
+
- **ignoreTags 設定**(このパッケージ)-- デリミタのマッチング、順序
|
|
60
|
+
- **基底 HTML パーサー**(`@markuplint/html-parser`)-- HTML 構造処理
|
|
61
|
+
3. 適切なパッケージで修正を適用
|
|
62
|
+
4. ビルドとテスト: `yarn build --scope @markuplint/mustache-parser && yarn test --scope @markuplint/mustache-parser`
|
|
63
|
+
5. 修正が `@markuplint/html-parser` にある場合: `yarn test --scope @markuplint/html-parser` も実行
|
|
64
|
+
|
|
65
|
+
### 3. テストケースの追加
|
|
66
|
+
|
|
67
|
+
1. `src/index.spec.ts` を読み、既存のテスト構造を理解
|
|
68
|
+
2. ノードリストテストには `nodeListToDebugMaps` パターンを使用:
|
|
69
|
+
```ts
|
|
70
|
+
const doc = parse('テンプレート文字列');
|
|
71
|
+
expect(nodeListToDebugMaps(doc.nodeList)).toStrictEqual([...]);
|
|
72
|
+
```
|
|
73
|
+
3. タグタイプテストには `nodeName` でアサート:
|
|
74
|
+
```ts
|
|
75
|
+
expect(parse('{{ expr }}').nodeList[0]?.nodeName).toBe('#ps:mustache-tag');
|
|
76
|
+
```
|
|
77
|
+
4. テスト: `yarn test --scope @markuplint/mustache-parser`
|
|
78
|
+
|
|
79
|
+
## 上流の影響
|
|
80
|
+
|
|
81
|
+
このパッケージは `@markuplint/html-parser` に依存しています。`HtmlParser` の変更(特に `ignoreTags` 処理、`visitText`、`researchTags` メカニズム)はこのパーサーに影響を与える可能性があります。
|
|
82
|
+
|
|
83
|
+
`@markuplint/html-parser` が更新された場合は、以下を実行してください:
|
|
84
|
+
|
|
85
|
+
```shell
|
|
86
|
+
yarn test --scope @markuplint/mustache-parser
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## トラブルシューティング
|
|
90
|
+
|
|
91
|
+
### Mustache タグが認識されない
|
|
92
|
+
|
|
93
|
+
**症状:** `{{ name }}` のような Mustache 式が `#ps:mustache-tag` ノードではなく生テキストとして表示される。
|
|
94
|
+
|
|
95
|
+
**原因:** `ignoreTags` エントリが欠落しているか、start/end デリミタが不正。
|
|
96
|
+
|
|
97
|
+
**解決策:**
|
|
98
|
+
|
|
99
|
+
1. `src/parser.ts` を確認 -- `ignoreTags` 配列に `start: '{{'` と `end: '}}'` のエントリが含まれていることを検証
|
|
100
|
+
2. エントリの順序を確認 -- より具体的なパターンが先に配置されている必要がある
|
|
101
|
+
|
|
102
|
+
### トリプルスタッシュがダブルスタッシュとしてパースされる
|
|
103
|
+
|
|
104
|
+
**症状:** `{{{ raw }}}` が `#ps:mustache-unescaped` ではなく `#ps:mustache-tag` ノードを生成する。
|
|
105
|
+
|
|
106
|
+
**原因:** `mustache-unescaped` エントリ(`{{{` / `}}}`)が `mustache-tag` エントリ(`{{` / `}}`)の後に配置されているため、より一般的なパターンが先にマッチする。
|
|
107
|
+
|
|
108
|
+
**解決策:**
|
|
109
|
+
|
|
110
|
+
1. `ignoreTags` 配列内で `mustache-unescaped` エントリを `mustache-tag` エントリの前に移動
|
|
111
|
+
|
|
112
|
+
### コメントタグが通常のタグとしてパースされる
|
|
113
|
+
|
|
114
|
+
**症状:** `{{! comment }}` が `#ps:mustache-comment` ではなく `#ps:mustache-tag` ノードを生成する。
|
|
115
|
+
|
|
116
|
+
**原因:** `mustache-comment` エントリ(`{{!` / `}}`)が `mustache-tag` エントリ(`{{` / `}}`)の後に配置されている。
|
|
117
|
+
|
|
118
|
+
**解決策:**
|
|
119
|
+
|
|
120
|
+
1. `ignoreTags` 配列内で `mustache-comment` エントリが `mustache-tag` エントリの前にリストされていることを確認
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
# Maintenance Guide
|
|
2
|
+
|
|
3
|
+
## Commands
|
|
4
|
+
|
|
5
|
+
| Command | Description |
|
|
6
|
+
| ------------------------------------------------ | ---------------------- |
|
|
7
|
+
| `yarn build --scope @markuplint/mustache-parser` | Build this package |
|
|
8
|
+
| `yarn dev --scope @markuplint/mustache-parser` | Watch mode build |
|
|
9
|
+
| `yarn clean --scope @markuplint/mustache-parser` | Remove build artifacts |
|
|
10
|
+
| `yarn test --scope @markuplint/mustache-parser` | Run tests |
|
|
11
|
+
|
|
12
|
+
## Testing
|
|
13
|
+
|
|
14
|
+
Test files follow the `*.spec.ts` naming convention and are located in the `src/` directory:
|
|
15
|
+
|
|
16
|
+
| Test File | Coverage |
|
|
17
|
+
| --------------- | -------------------------------------------------------------- |
|
|
18
|
+
| `index.spec.ts` | Tag recognition, node list structure, block helpers, bare text |
|
|
19
|
+
|
|
20
|
+
The primary testing pattern uses `nodeListToDebugMaps` for snapshot-style assertions:
|
|
21
|
+
|
|
22
|
+
```ts
|
|
23
|
+
import { nodeListToDebugMaps } from '@markuplint/parser-utils';
|
|
24
|
+
import { parser } from './parser.js';
|
|
25
|
+
|
|
26
|
+
const doc = parser.parse('<div>{{ name }}</div>');
|
|
27
|
+
expect(nodeListToDebugMaps(doc.nodeList)).toStrictEqual([
|
|
28
|
+
'[1:1]>[1:6](0,5)div: <div>',
|
|
29
|
+
'[1:6]>[1:15](5,14)#ps:mustache-tag: {{␣name␣}}',
|
|
30
|
+
'[1:15]>[1:21](14,20)div: </div>',
|
|
31
|
+
]);
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Individual tag type assertions:
|
|
35
|
+
|
|
36
|
+
```ts
|
|
37
|
+
expect(parse('{{ any }}').nodeList[0]?.nodeName).toBe('#ps:mustache-tag');
|
|
38
|
+
expect(parse('{{{ any }}}').nodeList[0]?.nodeName).toBe('#ps:mustache-unescaped');
|
|
39
|
+
expect(parse('{{! any }}').nodeList[0]?.nodeName).toBe('#ps:mustache-comment');
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Recipes
|
|
43
|
+
|
|
44
|
+
### 1. Adding or Modifying an ignoreTags Entry
|
|
45
|
+
|
|
46
|
+
1. Read `src/parser.ts` and review the `ignoreTags` array in the `MustacheParser` constructor
|
|
47
|
+
2. Add or modify the entry, preserving correct ordering:
|
|
48
|
+
- More specific start delimiters must appear before less specific ones
|
|
49
|
+
- Current order: `{{!` -> `{{{` -> `{{`
|
|
50
|
+
3. Each entry requires: `type` (string identifier), `start` (opening delimiter), `end` (closing delimiter)
|
|
51
|
+
4. Build: `yarn build --scope @markuplint/mustache-parser`
|
|
52
|
+
5. Add test cases to `src/index.spec.ts` to verify the new tag type produces the correct `#ps:*` node name
|
|
53
|
+
6. Test: `yarn test --scope @markuplint/mustache-parser`
|
|
54
|
+
|
|
55
|
+
### 2. Fixing a Parsing Issue
|
|
56
|
+
|
|
57
|
+
1. Create a minimal reproducing template and write a failing test in `src/index.spec.ts`
|
|
58
|
+
2. Determine whether the issue is in:
|
|
59
|
+
- **ignoreTags configuration** (this package) -- delimiter matching, ordering
|
|
60
|
+
- **Base HTML parser** (`@markuplint/html-parser`) -- HTML structure handling
|
|
61
|
+
3. Apply the fix in the appropriate package
|
|
62
|
+
4. Build and test: `yarn build --scope @markuplint/mustache-parser && yarn test --scope @markuplint/mustache-parser`
|
|
63
|
+
5. If the fix is in `@markuplint/html-parser`, also run: `yarn test --scope @markuplint/html-parser`
|
|
64
|
+
|
|
65
|
+
### 3. Adding Test Cases
|
|
66
|
+
|
|
67
|
+
1. Read `src/index.spec.ts` to understand the existing test structure
|
|
68
|
+
2. For node list tests, use the `nodeListToDebugMaps` pattern:
|
|
69
|
+
```ts
|
|
70
|
+
const doc = parse('template string here');
|
|
71
|
+
expect(nodeListToDebugMaps(doc.nodeList)).toStrictEqual([...]);
|
|
72
|
+
```
|
|
73
|
+
3. For tag type tests, assert against `nodeName`:
|
|
74
|
+
```ts
|
|
75
|
+
expect(parse('{{ expr }}').nodeList[0]?.nodeName).toBe('#ps:mustache-tag');
|
|
76
|
+
```
|
|
77
|
+
4. Test: `yarn test --scope @markuplint/mustache-parser`
|
|
78
|
+
|
|
79
|
+
## Upstream Impact
|
|
80
|
+
|
|
81
|
+
This package depends on `@markuplint/html-parser`. Changes in `HtmlParser` (especially `ignoreTags` processing, `visitText`, or the `researchTags` mechanism) may affect this parser.
|
|
82
|
+
|
|
83
|
+
When `@markuplint/html-parser` is updated, run:
|
|
84
|
+
|
|
85
|
+
```shell
|
|
86
|
+
yarn test --scope @markuplint/mustache-parser
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## Troubleshooting
|
|
90
|
+
|
|
91
|
+
### Mustache tags are not recognized
|
|
92
|
+
|
|
93
|
+
**Symptom:** Mustache expressions like `{{ name }}` appear as raw text instead of `#ps:mustache-tag` nodes.
|
|
94
|
+
|
|
95
|
+
**Cause:** The `ignoreTags` entry is missing or the start/end delimiters are incorrect.
|
|
96
|
+
|
|
97
|
+
**Solution:**
|
|
98
|
+
|
|
99
|
+
1. Check `src/parser.ts` -- verify the `ignoreTags` array includes an entry with `start: '{{'` and `end: '}}'`
|
|
100
|
+
2. Verify the entry ordering -- more specific patterns must appear first
|
|
101
|
+
|
|
102
|
+
### Triple-stache parsed as double-stache
|
|
103
|
+
|
|
104
|
+
**Symptom:** `{{{ raw }}}` produces a `#ps:mustache-tag` node instead of `#ps:mustache-unescaped`.
|
|
105
|
+
|
|
106
|
+
**Cause:** The `mustache-unescaped` entry (`{{{` / `}}}`) appears after the `mustache-tag` entry (`{{` / `}}`), so the less specific pattern matches first.
|
|
107
|
+
|
|
108
|
+
**Solution:**
|
|
109
|
+
|
|
110
|
+
1. Move the `mustache-unescaped` entry before the `mustache-tag` entry in the `ignoreTags` array
|
|
111
|
+
|
|
112
|
+
### Comment tags parsed as regular tags
|
|
113
|
+
|
|
114
|
+
**Symptom:** `{{! comment }}` produces a `#ps:mustache-tag` node instead of `#ps:mustache-comment`.
|
|
115
|
+
|
|
116
|
+
**Cause:** The `mustache-comment` entry (`{{!` / `}}`) appears after the `mustache-tag` entry (`{{` / `}}`).
|
|
117
|
+
|
|
118
|
+
**Solution:**
|
|
119
|
+
|
|
120
|
+
1. Ensure the `mustache-comment` entry is listed before the `mustache-tag` entry in the `ignoreTags` array
|
package/lib/index.d.ts
CHANGED
|
@@ -1 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module @markuplint/mustache-parser
|
|
3
|
+
* Markuplint parser plugin for Mustache and Handlebars templates. Extends the standard
|
|
4
|
+
* HTML parser to treat Mustache/Handlebars tags, unescaped expressions, and comments
|
|
5
|
+
* as opaque blocks, allowing markuplint to lint the surrounding HTML structure.
|
|
6
|
+
*/
|
|
1
7
|
export { parser } from './parser.js';
|
package/lib/index.js
CHANGED
|
@@ -1 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module @markuplint/mustache-parser
|
|
3
|
+
* Markuplint parser plugin for Mustache and Handlebars templates. Extends the standard
|
|
4
|
+
* HTML parser to treat Mustache/Handlebars tags, unescaped expressions, and comments
|
|
5
|
+
* as opaque blocks, allowing markuplint to lint the surrounding HTML structure.
|
|
6
|
+
*/
|
|
1
7
|
export { parser } from './parser.js';
|
package/lib/parser.d.ts
CHANGED
|
@@ -1,6 +1,17 @@
|
|
|
1
1
|
import { HtmlParser } from '@markuplint/html-parser';
|
|
2
|
+
/**
|
|
3
|
+
* Parser for Mustache and Handlebars templates that extends the standard HTML parser.
|
|
4
|
+
*
|
|
5
|
+
* Configures the HTML parser to recognize Mustache/Handlebars tag variants as opaque blocks:
|
|
6
|
+
* - `{{! ... }}` (comments)
|
|
7
|
+
* - `{{{ ... }}}` (unescaped / triple-stache output)
|
|
8
|
+
* - `{{ ... }}` (standard interpolation and block helpers)
|
|
9
|
+
*/
|
|
2
10
|
declare class MustacheParser extends HtmlParser {
|
|
3
11
|
constructor();
|
|
4
12
|
}
|
|
13
|
+
/**
|
|
14
|
+
* Singleton Mustache/Handlebars parser instance for use by the markuplint engine.
|
|
15
|
+
*/
|
|
5
16
|
export declare const parser: MustacheParser;
|
|
6
17
|
export {};
|
package/lib/parser.js
CHANGED
|
@@ -1,4 +1,12 @@
|
|
|
1
1
|
import { HtmlParser } from '@markuplint/html-parser';
|
|
2
|
+
/**
|
|
3
|
+
* Parser for Mustache and Handlebars templates that extends the standard HTML parser.
|
|
4
|
+
*
|
|
5
|
+
* Configures the HTML parser to recognize Mustache/Handlebars tag variants as opaque blocks:
|
|
6
|
+
* - `{{! ... }}` (comments)
|
|
7
|
+
* - `{{{ ... }}}` (unescaped / triple-stache output)
|
|
8
|
+
* - `{{ ... }}` (standard interpolation and block helpers)
|
|
9
|
+
*/
|
|
2
10
|
class MustacheParser extends HtmlParser {
|
|
3
11
|
constructor() {
|
|
4
12
|
super({
|
|
@@ -22,4 +30,7 @@ class MustacheParser extends HtmlParser {
|
|
|
22
30
|
});
|
|
23
31
|
}
|
|
24
32
|
}
|
|
33
|
+
/**
|
|
34
|
+
* Singleton Mustache/Handlebars parser instance for use by the markuplint engine.
|
|
35
|
+
*/
|
|
25
36
|
export const parser = new MustacheParser();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@markuplint/mustache-parser",
|
|
3
|
-
"version": "4.6.
|
|
3
|
+
"version": "4.6.23",
|
|
4
4
|
"description": "The mustache template parser for markuplint",
|
|
5
5
|
"repository": "git@github.com:markuplint/markuplint.git",
|
|
6
6
|
"author": "Yusuke Hirao <yusukehirao@me.com>",
|
|
@@ -21,10 +21,10 @@
|
|
|
21
21
|
"clean": "tsc --build --clean tsconfig.build.json"
|
|
22
22
|
},
|
|
23
23
|
"dependencies": {
|
|
24
|
-
"@markuplint/html-parser": "4.6.
|
|
24
|
+
"@markuplint/html-parser": "4.6.23"
|
|
25
25
|
},
|
|
26
26
|
"devDependencies": {
|
|
27
|
-
"@markuplint/parser-utils": "4.8.
|
|
27
|
+
"@markuplint/parser-utils": "4.8.11"
|
|
28
28
|
},
|
|
29
|
-
"gitHead": "
|
|
29
|
+
"gitHead": "193ee7c1262bbed95424e38efdf1a8e56ff049f4"
|
|
30
30
|
}
|