@markuplint/nunjucks-parser 4.6.22 → 4.18.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.
- package/ARCHITECTURE.ja.md +91 -0
- package/ARCHITECTURE.md +91 -0
- package/CHANGELOG.md +9 -1
- package/SKILL.md +94 -0
- package/docs/maintenance.ja.md +102 -0
- package/docs/maintenance.md +102 -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,91 @@
|
|
|
1
|
+
# @markuplint/nunjucks-parser
|
|
2
|
+
|
|
3
|
+
## 概要
|
|
4
|
+
|
|
5
|
+
`@markuplint/nunjucks-parser` は `HtmlParser` を拡張し、Nunjucks テンプレート式を含む HTML をリントします。Nunjucks 構文に対する3つの無視パターンを宣言することで、テンプレート式を不透明なブロックとして扱いながら、周囲の HTML 構造を markuplint が解析できるようにします。
|
|
6
|
+
|
|
7
|
+
## 動作の仕組み
|
|
8
|
+
|
|
9
|
+
このパーサーは基底 `HtmlParser` が提供する `ignoreTags` メカニズムを使用します:
|
|
10
|
+
|
|
11
|
+
1. **マスク** -- パース前に、すべての Nunjucks テンプレート式が開始/終了デリミタで識別され、プレースホルダーテキストに置換される
|
|
12
|
+
2. **パース** -- マスクされた HTML が標準 HTML パーサー(parse5)によって、テンプレート式が存在しないかのようにパースされる
|
|
13
|
+
3. **保持** -- 元の Nunjucks 式は AST 内で `#ps:*`(PreprocessorSpecificBlock)ノードとして保持され、ソース位置が維持される
|
|
14
|
+
|
|
15
|
+
このアプローチにより、markuplint は Nunjucks 構文に混乱することなく HTML 構造をリントできます。
|
|
16
|
+
|
|
17
|
+
## ignoreTags 設定
|
|
18
|
+
|
|
19
|
+
`NunjucksParser` コンストラクタは3つの無視パターンを定義します:
|
|
20
|
+
|
|
21
|
+
| タイプ | 開始 | 終了 | 説明 |
|
|
22
|
+
| ------------------ | ---- | ---- | ------------------------------------------------ |
|
|
23
|
+
| `nunjucks-block` | `{%` | `%}` | ブロックタグ(if, for, macro, block, extends等) |
|
|
24
|
+
| `nunjucks-output` | `{{` | `}}` | 出力 / 変数展開 |
|
|
25
|
+
| `nunjucks-comment` | `{#` | `#}` | コメント(レンダリングされない) |
|
|
26
|
+
|
|
27
|
+
## サポートされない構文
|
|
28
|
+
|
|
29
|
+
**引用符なしの属性値**内のテンプレート式はサポートされていません。これはすべてのテンプレートエンジンパーサーに共通する既知の制限です([#240](https://github.com/markuplint/markuplint/issues/240))。[ウェブサイトのドキュメント](https://markuplint.dev/docs/guides/besides-html)も参照してください。
|
|
30
|
+
|
|
31
|
+
使用可能:
|
|
32
|
+
|
|
33
|
+
```html
|
|
34
|
+
<div attr="{{ value }}"></div>
|
|
35
|
+
<div attr="{{ value }}"></div>
|
|
36
|
+
<div attr="{{ value }}-{{ value2 }}-{{ value3 }}"></div>
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
使用不可(引用符なし):
|
|
40
|
+
|
|
41
|
+
```html
|
|
42
|
+
<div attr="{{" value }}></div>
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## ディレクトリ構成
|
|
46
|
+
|
|
47
|
+
```
|
|
48
|
+
src/
|
|
49
|
+
├── index.ts -- parser を再エクスポート
|
|
50
|
+
├── parser.ts -- HtmlParser を拡張する NunjucksParser クラス
|
|
51
|
+
└── index.spec.ts -- パーサー統合テスト
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## 主要ソースファイル
|
|
55
|
+
|
|
56
|
+
| ファイル | 用途 |
|
|
57
|
+
| --------------- | --------------------------------------------------------------------------------- |
|
|
58
|
+
| `src/parser.ts` | `NunjucksParser` クラスを定義し、シングルトン `parser` インスタンスをエクスポート |
|
|
59
|
+
| `src/index.ts` | パッケージエントリポイント; `parser` を再エクスポート |
|
|
60
|
+
|
|
61
|
+
## 統合ポイント
|
|
62
|
+
|
|
63
|
+
```mermaid
|
|
64
|
+
flowchart TD
|
|
65
|
+
subgraph upstream ["上流"]
|
|
66
|
+
htmlParser["@markuplint/html-parser\n(HtmlParser クラス)"]
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
subgraph pkg ["@markuplint/nunjucks-parser"]
|
|
70
|
+
nunjucksParser["NunjucksParser\nextends HtmlParser\n(ignoreTags のみ)"]
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
subgraph downstream ["下流"]
|
|
74
|
+
mlCore["@markuplint/ml-core\n(MLASTDocument -> MLDOM)"]
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
htmlParser -->|"継承"| nunjucksParser
|
|
78
|
+
nunjucksParser -->|"MLASTDocument を生成"| mlCore
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### 上流
|
|
82
|
+
|
|
83
|
+
- **`@markuplint/html-parser`** -- `ignoreTags` サポートを備えた `HtmlParser` 基底クラスを提供
|
|
84
|
+
|
|
85
|
+
### 下流
|
|
86
|
+
|
|
87
|
+
- **`@markuplint/ml-core`** -- このパーサーが生成する `MLASTDocument` を消費し、ルール評価用の MLDOM を構築
|
|
88
|
+
|
|
89
|
+
## ドキュメントマップ
|
|
90
|
+
|
|
91
|
+
- [メンテナンスガイド](docs/maintenance.ja.md) -- コマンド、レシピ、テスト
|
package/ARCHITECTURE.md
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# @markuplint/nunjucks-parser
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
`@markuplint/nunjucks-parser` extends `HtmlParser` to lint HTML containing Nunjucks template expressions. By declaring three ignore patterns for Nunjucks syntax, the parser lets markuplint analyze the surrounding HTML structure while treating template expressions as opaque blocks.
|
|
6
|
+
|
|
7
|
+
## How It Works
|
|
8
|
+
|
|
9
|
+
The parser uses the `ignoreTags` mechanism provided by the base `HtmlParser`:
|
|
10
|
+
|
|
11
|
+
1. **Mask** -- Before parsing, all Nunjucks template expressions are identified by their start/end delimiters and replaced with placeholder text
|
|
12
|
+
2. **Parse** -- The masked HTML is parsed by the standard HTML parser (parse5) as if the template expressions did not exist
|
|
13
|
+
3. **Preserve** -- The original Nunjucks expressions are preserved in the AST as `#ps:*` (PreprocessorSpecificBlock) nodes, maintaining their source positions
|
|
14
|
+
|
|
15
|
+
This approach allows markuplint to lint the HTML structure without being confused by Nunjucks syntax.
|
|
16
|
+
|
|
17
|
+
## ignoreTags Configuration
|
|
18
|
+
|
|
19
|
+
The `NunjucksParser` constructor defines three ignore patterns:
|
|
20
|
+
|
|
21
|
+
| Type | Start | End | Description |
|
|
22
|
+
| ------------------ | ----- | ---- | ---------------------------------------------- |
|
|
23
|
+
| `nunjucks-block` | `{%` | `%}` | Block tags (if, for, macro, block, extends...) |
|
|
24
|
+
| `nunjucks-output` | `{{` | `}}` | Output / variable interpolation |
|
|
25
|
+
| `nunjucks-comment` | `{#` | `#}` | Comments (not rendered) |
|
|
26
|
+
|
|
27
|
+
## Unsupported Syntaxes
|
|
28
|
+
|
|
29
|
+
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).
|
|
30
|
+
|
|
31
|
+
Available:
|
|
32
|
+
|
|
33
|
+
```html
|
|
34
|
+
<div attr="{{ value }}"></div>
|
|
35
|
+
<div attr="{{ value }}"></div>
|
|
36
|
+
<div attr="{{ value }}-{{ value2 }}-{{ value3 }}"></div>
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Unavailable (unquoted):
|
|
40
|
+
|
|
41
|
+
```html
|
|
42
|
+
<div attr="{{" value }}></div>
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Directory Structure
|
|
46
|
+
|
|
47
|
+
```
|
|
48
|
+
src/
|
|
49
|
+
├── index.ts -- Re-exports parser
|
|
50
|
+
├── parser.ts -- NunjucksParser class extending HtmlParser
|
|
51
|
+
└── index.spec.ts -- Parser integration tests
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Key Source Files
|
|
55
|
+
|
|
56
|
+
| File | Purpose |
|
|
57
|
+
| --------------- | ---------------------------------------------------------------------- |
|
|
58
|
+
| `src/parser.ts` | Defines `NunjucksParser` class and exports singleton `parser` instance |
|
|
59
|
+
| `src/index.ts` | Package entry point; re-exports `parser` |
|
|
60
|
+
|
|
61
|
+
## Integration Points
|
|
62
|
+
|
|
63
|
+
```mermaid
|
|
64
|
+
flowchart TD
|
|
65
|
+
subgraph upstream ["Upstream"]
|
|
66
|
+
htmlParser["@markuplint/html-parser\n(HtmlParser class)"]
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
subgraph pkg ["@markuplint/nunjucks-parser"]
|
|
70
|
+
nunjucksParser["NunjucksParser\nextends HtmlParser\n(ignoreTags only)"]
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
subgraph downstream ["Downstream"]
|
|
74
|
+
mlCore["@markuplint/ml-core\n(MLASTDocument -> MLDOM)"]
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
htmlParser -->|"extends"| nunjucksParser
|
|
78
|
+
nunjucksParser -->|"produces MLASTDocument"| mlCore
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### Upstream
|
|
82
|
+
|
|
83
|
+
- **`@markuplint/html-parser`** -- Provides the `HtmlParser` base class with `ignoreTags` support
|
|
84
|
+
|
|
85
|
+
### Downstream
|
|
86
|
+
|
|
87
|
+
- **`@markuplint/ml-core`** -- Consumes the `MLASTDocument` produced by this parser to build the MLDOM for rule evaluation
|
|
88
|
+
|
|
89
|
+
## Documentation Map
|
|
90
|
+
|
|
91
|
+
- [Maintenance Guide](docs/maintenance.md) -- Commands, recipes, and testing
|
package/CHANGELOG.md
CHANGED
|
@@ -3,13 +3,21 @@
|
|
|
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
|
-
|
|
6
|
+
# [4.18.0](https://github.com/markuplint/markuplint/compare/v4.14.1...v4.18.0) (2026-04-22)
|
|
7
7
|
|
|
8
8
|
**Note:** Version bump only for package @markuplint/nunjucks-parser
|
|
9
9
|
|
|
10
|
+
## [4.6.24](https://github.com/markuplint/markuplint/compare/@markuplint/nunjucks-parser@4.6.23...@markuplint/nunjucks-parser@4.6.24) (2026-04-21)
|
|
11
|
+
|
|
12
|
+
**Note:** Version bump only for package @markuplint/nunjucks-parser
|
|
10
13
|
|
|
14
|
+
## [4.6.23](https://github.com/markuplint/markuplint/compare/@markuplint/nunjucks-parser@4.6.22...@markuplint/nunjucks-parser@4.6.23) (2026-02-10)
|
|
11
15
|
|
|
16
|
+
**Note:** Version bump only for package @markuplint/nunjucks-parser
|
|
12
17
|
|
|
18
|
+
## [4.6.22](https://github.com/markuplint/markuplint/compare/@markuplint/nunjucks-parser@4.6.21...@markuplint/nunjucks-parser@4.6.22) (2025-11-05)
|
|
19
|
+
|
|
20
|
+
**Note:** Version bump only for package @markuplint/nunjucks-parser
|
|
13
21
|
|
|
14
22
|
## [4.6.21](https://github.com/markuplint/markuplint/compare/@markuplint/nunjucks-parser@4.6.20...@markuplint/nunjucks-parser@4.6.21) (2025-08-24)
|
|
15
23
|
|
package/SKILL.md
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Perform maintenance tasks for @markuplint/nunjucks-parser
|
|
3
|
+
globs:
|
|
4
|
+
- packages/@markuplint/nunjucks-parser/src/**
|
|
5
|
+
alwaysApply: false
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# nunjucks-parser-maintenance
|
|
9
|
+
|
|
10
|
+
Perform maintenance tasks for `@markuplint/nunjucks-parser`: modify ignoreTags configuration,
|
|
11
|
+
add new Nunjucks syntax patterns, and update tests.
|
|
12
|
+
|
|
13
|
+
## Input
|
|
14
|
+
|
|
15
|
+
`$ARGUMENTS` specifies the task. Supported tasks:
|
|
16
|
+
|
|
17
|
+
| Task | Description |
|
|
18
|
+
| ------------------ | -------------------------------------- |
|
|
19
|
+
| `modify-ignoretag` | Modify or add an ignoreTags pattern |
|
|
20
|
+
| `fix-parsing` | Fix a parsing issue with Nunjucks HTML |
|
|
21
|
+
| `add-test` | Add a new test case |
|
|
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 table, and integration points
|
|
33
|
+
- `src/parser.ts` -- NunjucksParser class (source of truth for ignore patterns)
|
|
34
|
+
|
|
35
|
+
## Task: modify-ignoretag
|
|
36
|
+
|
|
37
|
+
Modify or add an ignoreTags pattern. Follow recipe #1 in `docs/maintenance.md`.
|
|
38
|
+
|
|
39
|
+
### Step 1: Understand the current patterns
|
|
40
|
+
|
|
41
|
+
1. Read `src/parser.ts` and review the `ignoreTags` array in the constructor
|
|
42
|
+
2. Each entry has `type` (node name), `start` (opening delimiter), and `end` (closing delimiter)
|
|
43
|
+
|
|
44
|
+
### Step 2: Make the change
|
|
45
|
+
|
|
46
|
+
1. Add or modify entries in the `ignoreTags` array
|
|
47
|
+
2. If the new pattern overlaps with existing patterns, place the more specific pattern first
|
|
48
|
+
3. Use a regex string for `start` if a simple string match is insufficient
|
|
49
|
+
|
|
50
|
+
### Step 3: Verify
|
|
51
|
+
|
|
52
|
+
1. Build: `yarn build --scope @markuplint/nunjucks-parser`
|
|
53
|
+
2. Add test cases to `src/index.spec.ts`
|
|
54
|
+
3. Test: `yarn test --scope @markuplint/nunjucks-parser`
|
|
55
|
+
|
|
56
|
+
## Task: fix-parsing
|
|
57
|
+
|
|
58
|
+
Fix a parsing issue with Nunjucks-containing HTML. Follow recipe #2 in `docs/maintenance.md`.
|
|
59
|
+
|
|
60
|
+
### Step 1: Reproduce
|
|
61
|
+
|
|
62
|
+
1. Add a failing test case to `src/index.spec.ts` using `nodeListToDebugMaps`
|
|
63
|
+
2. Run: `yarn test --scope @markuplint/nunjucks-parser`
|
|
64
|
+
|
|
65
|
+
### Step 2: Diagnose
|
|
66
|
+
|
|
67
|
+
1. Check if the issue is in ignoreTags patterns (`src/parser.ts`) or in the upstream `HtmlParser`
|
|
68
|
+
2. If the issue is upstream, fix it in `@markuplint/html-parser` instead
|
|
69
|
+
|
|
70
|
+
### Step 3: Verify
|
|
71
|
+
|
|
72
|
+
1. Build: `yarn build --scope @markuplint/nunjucks-parser`
|
|
73
|
+
2. Test: `yarn test --scope @markuplint/nunjucks-parser`
|
|
74
|
+
|
|
75
|
+
## Task: add-test
|
|
76
|
+
|
|
77
|
+
Add a new test case. Follow recipe #3 in `docs/maintenance.md`.
|
|
78
|
+
|
|
79
|
+
### Step 1: Write the test
|
|
80
|
+
|
|
81
|
+
1. Read `src/index.spec.ts` for existing patterns
|
|
82
|
+
2. Use `nodeListToDebugMaps` for snapshot-style assertions
|
|
83
|
+
3. Use `parser.parse(source).nodeList` to get the node list
|
|
84
|
+
|
|
85
|
+
### Step 2: Verify
|
|
86
|
+
|
|
87
|
+
1. Test: `yarn test --scope @markuplint/nunjucks-parser`
|
|
88
|
+
|
|
89
|
+
## Rules
|
|
90
|
+
|
|
91
|
+
1. **Never override HtmlParser methods** in `NunjucksParser` -- this parser is ignoreTags-only.
|
|
92
|
+
2. **Order ignoreTags from most specific to least specific** when patterns share a common prefix.
|
|
93
|
+
3. **Add JSDoc comments** to all new public methods and properties.
|
|
94
|
+
4. **Test all three expression types** (block, output, comment) when modifying patterns.
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# メンテナンスガイド
|
|
2
|
+
|
|
3
|
+
## コマンド
|
|
4
|
+
|
|
5
|
+
| コマンド | 説明 |
|
|
6
|
+
| ------------------------------------------------ | ---------------------- |
|
|
7
|
+
| `yarn build --scope @markuplint/nunjucks-parser` | このパッケージをビルド |
|
|
8
|
+
| `yarn dev --scope @markuplint/nunjucks-parser` | ウォッチモードでビルド |
|
|
9
|
+
| `yarn clean --scope @markuplint/nunjucks-parser` | ビルド成果物を削除 |
|
|
10
|
+
| `yarn test --scope @markuplint/nunjucks-parser` | テストを実行 |
|
|
11
|
+
|
|
12
|
+
## テスト
|
|
13
|
+
|
|
14
|
+
テストファイルは `*.spec.ts` の命名規則に従い、`src/` ディレクトリに配置されています:
|
|
15
|
+
|
|
16
|
+
| テストファイル | カバレッジ |
|
|
17
|
+
| --------------- | --------------------------------------------------------------------------------- |
|
|
18
|
+
| `index.spec.ts` | パーサー統合テスト(block、output、comment タグの認識とネストされた HTML の処理) |
|
|
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>{% if foo %}<span>{{ bar }}</span>{% endif %}</div>');
|
|
27
|
+
const debugMaps = nodeListToDebugMaps(doc.nodeList);
|
|
28
|
+
expect(debugMaps).toStrictEqual([
|
|
29
|
+
// 期待されるデバッグ出力
|
|
30
|
+
]);
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
シンプルなタグ認識テストの場合:
|
|
34
|
+
|
|
35
|
+
```ts
|
|
36
|
+
expect(parser.parse('{% any %}').nodeList[0]?.nodeName).toBe('#ps:nunjucks-block');
|
|
37
|
+
expect(parser.parse('{{ any }}').nodeList[0]?.nodeName).toBe('#ps:nunjucks-output');
|
|
38
|
+
expect(parser.parse('{# any #}').nodeList[0]?.nodeName).toBe('#ps:nunjucks-comment');
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## レシピ
|
|
42
|
+
|
|
43
|
+
### 1. ignoreTags パターンの追加・変更
|
|
44
|
+
|
|
45
|
+
1. `src/parser.ts` を読み、`ignoreTags` 配列を確認
|
|
46
|
+
2. `type`、`start`、`end` プロパティを持つエントリを追加または変更
|
|
47
|
+
3. パターンが共通のプレフィックスを持つ場合、より具体的なパターンを先に配置
|
|
48
|
+
4. ビルド: `yarn build --scope @markuplint/nunjucks-parser`
|
|
49
|
+
5. `src/index.spec.ts` にテストケースを追加し、新しいパターンが期待される `#ps:*` ノードを生成することを検証
|
|
50
|
+
6. テスト: `yarn test --scope @markuplint/nunjucks-parser`
|
|
51
|
+
|
|
52
|
+
### 2. パース問題の修正
|
|
53
|
+
|
|
54
|
+
1. `src/index.spec.ts` に問題を再現する失敗するテストケースを追加
|
|
55
|
+
2. 問題が ignoreTags 設定(`src/parser.ts`)にあるか、上流の `@markuplint/html-parser` にあるかを判断
|
|
56
|
+
3. 上流の場合、そちらで修正し両パッケージをテスト:
|
|
57
|
+
```shell
|
|
58
|
+
yarn test --scope @markuplint/html-parser --scope @markuplint/nunjucks-parser
|
|
59
|
+
```
|
|
60
|
+
4. ローカルの場合、ignoreTags パターンを調整
|
|
61
|
+
5. ビルドとテスト: `yarn build --scope @markuplint/nunjucks-parser && yarn test --scope @markuplint/nunjucks-parser`
|
|
62
|
+
|
|
63
|
+
### 3. テストケースの追加
|
|
64
|
+
|
|
65
|
+
1. `src/index.spec.ts` の既存パターンを確認
|
|
66
|
+
2. タグ認識テスト: `nodeName` が `#ps:nunjucks-block`、`#ps:nunjucks-output`、`#ps:nunjucks-comment` であることをアサート
|
|
67
|
+
3. 複雑な HTML: `nodeListToDebugMaps` を使用した完全な AST スナップショット比較
|
|
68
|
+
4. 実行: `yarn test --scope @markuplint/nunjucks-parser`
|
|
69
|
+
|
|
70
|
+
## 上流への影響
|
|
71
|
+
|
|
72
|
+
このパッケージは `@markuplint/html-parser` のみに依存しています。`HtmlParser` クラスまたはその `ignoreTags` メカニズムへの変更がこのパーサーに影響する可能性があります。上流の依存関係をアップグレードする際:
|
|
73
|
+
|
|
74
|
+
1. ビルド: `yarn build --scope @markuplint/nunjucks-parser`
|
|
75
|
+
2. テスト: `yarn test --scope @markuplint/nunjucks-parser`
|
|
76
|
+
3. 3つの式タイプ(block、output、comment)がすべて正しくパースされることを検証
|
|
77
|
+
|
|
78
|
+
## トラブルシューティング
|
|
79
|
+
|
|
80
|
+
### Nunjucks 式がプリプロセッサブロックとして認識されない
|
|
81
|
+
|
|
82
|
+
**症状:** Nunjucks 式(例: `{% raw %}`)が `#ps:nunjucks-block` ノードではなくテキストコンテンツとして表示される。
|
|
83
|
+
|
|
84
|
+
**原因:** ignoreTags パターンがその式のデリミタにマッチしていない。
|
|
85
|
+
|
|
86
|
+
**解決策:**
|
|
87
|
+
|
|
88
|
+
1. `src/parser.ts` を確認 -- ignoreTags エントリの `start` と `end` デリミタを検証
|
|
89
|
+
2. 式がバリアントデリミタを使用している場合、新しい ignoreTags エントリを追加するか既存のパターンを調整
|
|
90
|
+
3. 失敗した特定の式でテスト
|
|
91
|
+
|
|
92
|
+
### HTML 属性内の Nunjucks 式がパースエラーを引き起こす
|
|
93
|
+
|
|
94
|
+
**症状:** 属性値に Nunjucks 式を含む HTML(例: `class="{{ foo }}"`)が予期しない AST 出力を生成する。
|
|
95
|
+
|
|
96
|
+
**原因:** ignoreTags のマスクはソース位置を保持するが、プレースホルダーが HTML 属性パースと相互作用する可能性がある。
|
|
97
|
+
|
|
98
|
+
**解決策:**
|
|
99
|
+
|
|
100
|
+
1. `nodeListToDebugMaps` を使用した最小限のテストケースで再現
|
|
101
|
+
2. これは通常、上流の `HtmlParser` の問題 -- 他のテンプレートパーサーでも同じ問題があるか確認
|
|
102
|
+
3. Nunjucks デリミタに固有の問題であれば、`@markuplint/html-parser` に対してイシューを作成
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# Maintenance Guide
|
|
2
|
+
|
|
3
|
+
## Commands
|
|
4
|
+
|
|
5
|
+
| Command | Description |
|
|
6
|
+
| ------------------------------------------------ | ---------------------- |
|
|
7
|
+
| `yarn build --scope @markuplint/nunjucks-parser` | Build this package |
|
|
8
|
+
| `yarn dev --scope @markuplint/nunjucks-parser` | Watch mode build |
|
|
9
|
+
| `yarn clean --scope @markuplint/nunjucks-parser` | Remove build artifacts |
|
|
10
|
+
| `yarn test --scope @markuplint/nunjucks-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` | Parser integration tests (block, output, comment tag recognition and nested HTML) |
|
|
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>{% if foo %}<span>{{ bar }}</span>{% endif %}</div>');
|
|
27
|
+
const debugMaps = nodeListToDebugMaps(doc.nodeList);
|
|
28
|
+
expect(debugMaps).toStrictEqual([
|
|
29
|
+
// expected debug output
|
|
30
|
+
]);
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
For simple tag recognition tests:
|
|
34
|
+
|
|
35
|
+
```ts
|
|
36
|
+
expect(parser.parse('{% any %}').nodeList[0]?.nodeName).toBe('#ps:nunjucks-block');
|
|
37
|
+
expect(parser.parse('{{ any }}').nodeList[0]?.nodeName).toBe('#ps:nunjucks-output');
|
|
38
|
+
expect(parser.parse('{# any #}').nodeList[0]?.nodeName).toBe('#ps:nunjucks-comment');
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Recipes
|
|
42
|
+
|
|
43
|
+
### 1. Adding or Modifying an ignoreTags Pattern
|
|
44
|
+
|
|
45
|
+
1. Read `src/parser.ts` and review the `ignoreTags` array
|
|
46
|
+
2. Add or modify the entry with `type`, `start`, and `end` properties
|
|
47
|
+
3. If patterns share a common prefix, place the more specific pattern first
|
|
48
|
+
4. Build: `yarn build --scope @markuplint/nunjucks-parser`
|
|
49
|
+
5. Add test cases to `src/index.spec.ts` verifying the new pattern produces the expected `#ps:*` node
|
|
50
|
+
6. Test: `yarn test --scope @markuplint/nunjucks-parser`
|
|
51
|
+
|
|
52
|
+
### 2. Fixing a Parsing Issue
|
|
53
|
+
|
|
54
|
+
1. Add a failing test case to `src/index.spec.ts` reproducing the issue
|
|
55
|
+
2. Determine whether the issue is in the ignoreTags configuration (`src/parser.ts`) or upstream in `@markuplint/html-parser`
|
|
56
|
+
3. If upstream, fix it there and test both packages:
|
|
57
|
+
```shell
|
|
58
|
+
yarn test --scope @markuplint/html-parser --scope @markuplint/nunjucks-parser
|
|
59
|
+
```
|
|
60
|
+
4. If local, adjust the ignoreTags patterns
|
|
61
|
+
5. Build and test: `yarn build --scope @markuplint/nunjucks-parser && yarn test --scope @markuplint/nunjucks-parser`
|
|
62
|
+
|
|
63
|
+
### 3. Adding a Test Case
|
|
64
|
+
|
|
65
|
+
1. Read `src/index.spec.ts` for existing patterns
|
|
66
|
+
2. For tag recognition: assert `nodeName` equals `#ps:nunjucks-block`, `#ps:nunjucks-output`, or `#ps:nunjucks-comment`
|
|
67
|
+
3. For complex HTML: use `nodeListToDebugMaps` for full AST snapshot comparison
|
|
68
|
+
4. Run: `yarn test --scope @markuplint/nunjucks-parser`
|
|
69
|
+
|
|
70
|
+
## Upstream Impact
|
|
71
|
+
|
|
72
|
+
This package depends solely on `@markuplint/html-parser`. Changes to the `HtmlParser` class or its `ignoreTags` mechanism may affect this parser. When upgrading the upstream dependency:
|
|
73
|
+
|
|
74
|
+
1. Build: `yarn build --scope @markuplint/nunjucks-parser`
|
|
75
|
+
2. Test: `yarn test --scope @markuplint/nunjucks-parser`
|
|
76
|
+
3. Verify all three expression types (block, output, comment) still parse correctly
|
|
77
|
+
|
|
78
|
+
## Troubleshooting
|
|
79
|
+
|
|
80
|
+
### Nunjucks expression not recognized as a preprocessor block
|
|
81
|
+
|
|
82
|
+
**Symptom:** A Nunjucks expression (e.g., `{% raw %}`) appears as text content instead of a `#ps:nunjucks-block` node.
|
|
83
|
+
|
|
84
|
+
**Cause:** The ignoreTags pattern does not match the expression's delimiters.
|
|
85
|
+
|
|
86
|
+
**Solution:**
|
|
87
|
+
|
|
88
|
+
1. Check `src/parser.ts` -- verify the `start` and `end` delimiters in the ignoreTags entry
|
|
89
|
+
2. If the expression uses a variant delimiter, add a new ignoreTags entry or adjust the existing pattern
|
|
90
|
+
3. Test with the specific expression that failed
|
|
91
|
+
|
|
92
|
+
### Nunjucks expression inside an HTML attribute causes parse error
|
|
93
|
+
|
|
94
|
+
**Symptom:** HTML containing Nunjucks expressions in attribute values (e.g., `class="{{ foo }}"`) produces unexpected AST output.
|
|
95
|
+
|
|
96
|
+
**Cause:** The ignoreTags masking preserves source positions but the placeholder may interact with HTML attribute parsing.
|
|
97
|
+
|
|
98
|
+
**Solution:**
|
|
99
|
+
|
|
100
|
+
1. Reproduce with a minimal test case using `nodeListToDebugMaps`
|
|
101
|
+
2. This is typically an upstream `HtmlParser` issue -- check if other template parsers have the same problem
|
|
102
|
+
3. If specific to Nunjucks delimiters, file an issue against `@markuplint/html-parser`
|
package/lib/index.d.ts
CHANGED
|
@@ -1 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module @markuplint/nunjucks-parser
|
|
3
|
+
* Markuplint parser plugin for Nunjucks templates. Extends the standard HTML parser
|
|
4
|
+
* to treat Nunjucks block tags, output expressions, and comments as opaque blocks,
|
|
5
|
+
* 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/nunjucks-parser
|
|
3
|
+
* Markuplint parser plugin for Nunjucks templates. Extends the standard HTML parser
|
|
4
|
+
* to treat Nunjucks block tags, output expressions, and comments as opaque blocks,
|
|
5
|
+
* 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 Nunjucks templates that extends the standard HTML parser.
|
|
4
|
+
*
|
|
5
|
+
* Configures the HTML parser to recognize Nunjucks tag variants as opaque blocks:
|
|
6
|
+
* - `{% ... %}` (block tags such as if, for, macro)
|
|
7
|
+
* - `{{ ... }}` (output / variable interpolation)
|
|
8
|
+
* - `{# ... #}` (comments)
|
|
9
|
+
*/
|
|
2
10
|
declare class NunjucksParser extends HtmlParser {
|
|
3
11
|
constructor();
|
|
4
12
|
}
|
|
13
|
+
/**
|
|
14
|
+
* Singleton Nunjucks parser instance for use by the markuplint engine.
|
|
15
|
+
*/
|
|
5
16
|
export declare const parser: NunjucksParser;
|
|
6
17
|
export {};
|
package/lib/parser.js
CHANGED
|
@@ -1,4 +1,12 @@
|
|
|
1
1
|
import { HtmlParser } from '@markuplint/html-parser';
|
|
2
|
+
/**
|
|
3
|
+
* Parser for Nunjucks templates that extends the standard HTML parser.
|
|
4
|
+
*
|
|
5
|
+
* Configures the HTML parser to recognize Nunjucks tag variants as opaque blocks:
|
|
6
|
+
* - `{% ... %}` (block tags such as if, for, macro)
|
|
7
|
+
* - `{{ ... }}` (output / variable interpolation)
|
|
8
|
+
* - `{# ... #}` (comments)
|
|
9
|
+
*/
|
|
2
10
|
class NunjucksParser extends HtmlParser {
|
|
3
11
|
constructor() {
|
|
4
12
|
super({
|
|
@@ -22,4 +30,7 @@ class NunjucksParser extends HtmlParser {
|
|
|
22
30
|
});
|
|
23
31
|
}
|
|
24
32
|
}
|
|
33
|
+
/**
|
|
34
|
+
* Singleton Nunjucks parser instance for use by the markuplint engine.
|
|
35
|
+
*/
|
|
25
36
|
export const parser = new NunjucksParser();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@markuplint/nunjucks-parser",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.18.0",
|
|
4
4
|
"description": "Nunjucks 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.
|
|
24
|
+
"@markuplint/html-parser": "4.18.0"
|
|
25
25
|
},
|
|
26
26
|
"devDependencies": {
|
|
27
|
-
"@markuplint/parser-utils": "4.
|
|
27
|
+
"@markuplint/parser-utils": "4.18.0"
|
|
28
28
|
},
|
|
29
|
-
"gitHead": "
|
|
29
|
+
"gitHead": "1885af6349def3f19df975b9e9c399dd47361de1"
|
|
30
30
|
}
|