@markuplint/smarty-parser 5.0.0-rc.2 → 5.0.0-rc.5

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/CHANGELOG.md CHANGED
@@ -3,6 +3,18 @@
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
+ # [5.0.0-rc.5](https://github.com/markuplint/markuplint/compare/v5.0.0-rc.4...v5.0.0-rc.5) (2026-08-28)
7
+
8
+ **Note:** Version bump only for package @markuplint/smarty-parser
9
+
10
+ # [5.0.0-rc.4](https://github.com/markuplint/markuplint/compare/v5.0.0-rc.3...v5.0.0-rc.4) (2026-04-19)
11
+
12
+ **Note:** Version bump only for package @markuplint/smarty-parser
13
+
14
+ # [5.0.0-rc.3](https://github.com/markuplint/markuplint/compare/v5.0.0-rc.2...v5.0.0-rc.3) (2026-04-19)
15
+
16
+ **Note:** Version bump only for package @markuplint/smarty-parser
17
+
6
18
  # [5.0.0-rc.2](https://github.com/markuplint/markuplint/compare/v5.0.0-rc.1...v5.0.0-rc.2) (2026-04-15)
7
19
 
8
20
  **Note:** Version bump only for package @markuplint/smarty-parser
package/lib/parser.d.ts CHANGED
@@ -6,6 +6,13 @@ import { HtmlParser } from '@markuplint/html-parser';
6
6
  * - `{literal} ... {/literal}` (literal blocks passed through without parsing)
7
7
  * - `{* ... *}` (Smarty comments)
8
8
  * - `{ ... }` (general Smarty scriptlet tags for variables, functions, and modifiers)
9
+ *
10
+ * Known limitation: template expressions inside unquoted attribute values
11
+ * (e.g. `<div attr={ $value }>`) are not supported; quoted attribute
12
+ * values work. This limitation is shared by all template engine parsers.
13
+ *
14
+ * @see https://github.com/markuplint/markuplint/issues/240
15
+ * @see https://markuplint.dev/docs/guides/besides-html
9
16
  */
10
17
  declare class SmartyParser extends HtmlParser {
11
18
  constructor();
package/lib/parser.js CHANGED
@@ -6,10 +6,21 @@ import { HtmlParser } from '@markuplint/html-parser';
6
6
  * - `{literal} ... {/literal}` (literal blocks passed through without parsing)
7
7
  * - `{* ... *}` (Smarty comments)
8
8
  * - `{ ... }` (general Smarty scriptlet tags for variables, functions, and modifiers)
9
+ *
10
+ * Known limitation: template expressions inside unquoted attribute values
11
+ * (e.g. `<div attr={ $value }>`) are not supported; quoted attribute
12
+ * values work. This limitation is shared by all template engine parsers.
13
+ *
14
+ * @see https://github.com/markuplint/markuplint/issues/240
15
+ * @see https://markuplint.dev/docs/guides/besides-html
9
16
  */
10
17
  class SmartyParser extends HtmlParser {
11
18
  constructor() {
12
19
  super({
20
+ // Patterns are matched in order, so the entries are ordered from
21
+ // most specific to least specific; `{literal}` and `{*` must come
22
+ // before the catch-all `{` pattern, otherwise the generic
23
+ // `smarty-scriptlet` pattern would match them first.
13
24
  ignoreTags: [
14
25
  {
15
26
  type: 'smarty-literal',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@markuplint/smarty-parser",
3
- "version": "5.0.0-rc.2",
3
+ "version": "5.0.0-rc.5",
4
4
  "description": "Smarty parser for markuplint",
5
5
  "repository": {
6
6
  "type": "git",
@@ -10,7 +10,7 @@
10
10
  "author": "Yusuke Hirao <yusukehirao@me.com>",
11
11
  "license": "MIT",
12
12
  "engines": {
13
- "node": ">=22"
13
+ "node": ">=24"
14
14
  },
15
15
  "type": "module",
16
16
  "exports": {
@@ -28,10 +28,10 @@
28
28
  "clean": "tsc --build --clean tsconfig.build.json"
29
29
  },
30
30
  "dependencies": {
31
- "@markuplint/html-parser": "5.0.0-rc.2"
31
+ "@markuplint/html-parser": "5.0.0-rc.5"
32
32
  },
33
33
  "devDependencies": {
34
- "@markuplint/parser-utils": "5.0.0-rc.2"
34
+ "@markuplint/parser-utils": "5.0.0-rc.5"
35
35
  },
36
- "gitHead": "e43763858d9234c417053becc73dbd088c1e7ea6"
36
+ "gitHead": "8d87463af2ff3f1b83fb28da20f1819362cf3555"
37
37
  }
@@ -1,85 +0,0 @@
1
- # @markuplint/smarty-parser
2
-
3
- ## 概要
4
-
5
- `@markuplint/smarty-parser` は `HtmlParser` を拡張し、Smarty テンプレート式を含む HTML のリントを可能にします。Smarty 固有の `ignoreTags` パターンを定義する薄い設定レイヤーであり、すべてのパースロジックは基底の HTML パーサーに委譲されます。
6
-
7
- ## 動作の仕組み
8
-
9
- このパーサーは基底の `HtmlParser` が提供する `ignoreTags` メカニズムを使用します:
10
-
11
- 1. **マスク** -- パース前に、すべての Smarty テンプレート式(`{ ... }`、`{* ... *}`、`{literal} ... {/literal}`)が開始/終了デリミタにより識別され、プレースホルダーテキストに置換される
12
- 2. **パース** -- マスクされた HTML は、テンプレート式が存在しないかのように標準 HTML パーサー(parse5)によってパースされる
13
- 3. **保持** -- 元の Smarty 式は AST 内に `#ps:*`(PreprocessorSpecificBlock)ノードとして保持され、ソース位置も維持される
14
-
15
- このアプローチにより、markuplint は Smarty 構文に影響されることなく HTML 構造をリントできます。
16
-
17
- ## ignoreTags 設定
18
-
19
- `SmartyParser` コンストラクタは、正しいマッチングを保証するために、最も具体的なものから順に3つのパターンを定義しています:
20
-
21
- | タイプ | 開始 | 終了 | 説明 |
22
- | ------------------ | ----------- | ------------ | -------------------------------------------------- |
23
- | `smarty-literal` | `{literal}` | `{/literal}` | Smarty パースを経由しないリテラルブロック |
24
- | `smarty-comment` | `{*` | `*}` | Smarty コメント(出力にレンダリングされない) |
25
- | `smarty-scriptlet` | `{` | `}` | 一般的な Smarty タグ(変数、関数、モディファイア) |
26
-
27
- 順序が重要です: `{literal}` と `{*` は汎用的な `{` パターンより先にマッチさせる必要があり、誤マッチを防止します。
28
-
29
- ## サポートされない構文
30
-
31
- **引用符なしの属性値**内のテンプレート式はサポートされていません。これはすべてのテンプレートエンジンパーサーに共通する既知の制限です([#240](https://github.com/markuplint/markuplint/issues/240))。[ウェブサイトのドキュメント](https://markuplint.dev/docs/guides/besides-html)も参照してください。
32
-
33
- 使用可能:
34
-
35
- ```html
36
- <div attr="{ $value }"></div>
37
- <div attr="{ $value }"></div>
38
- <div attr="{ $value }-{ $value2 }-{ $value3 }"></div>
39
- ```
40
-
41
- 使用不可(引用符なし):
42
-
43
- ```html
44
- <div attr="{" $value }></div>
45
- ```
46
-
47
- ## ディレクトリ構成
48
-
49
- ```
50
- src/
51
- ├── index.ts -- parser を再エクスポート
52
- ├── parser.ts -- HtmlParser を拡張する SmartyParser クラス
53
- └── index.spec.ts -- パーサー統合テスト
54
- ```
55
-
56
- ## 主要ソースファイル
57
-
58
- | ファイル | 用途 |
59
- | --------------- | ------------------------------------------------------------------- |
60
- | `src/parser.ts` | `SmartyParser` クラスを定義し、シングルトン `parser` をエクスポート |
61
- | `src/index.ts` | パッケージエントリーポイント。`parser` を再エクスポート |
62
-
63
- ## 統合ポイント
64
-
65
- ```mermaid
66
- flowchart TD
67
- subgraph upstream ["上流"]
68
- htmlParser["@markuplint/html-parser\n(HtmlParser クラス)"]
69
- end
70
-
71
- subgraph pkg ["@markuplint/smarty-parser"]
72
- smartyParser["SmartyParser\nextends HtmlParser\n(ignoreTags のみ)"]
73
- end
74
-
75
- subgraph downstream ["下流"]
76
- mlCore["@markuplint/ml-core\n(MLASTDocument → MLDOM)"]
77
- end
78
-
79
- htmlParser -->|"継承"| smartyParser
80
- smartyParser -->|"MLASTDocument を生成"| mlCore
81
- ```
82
-
83
- ## ドキュメントマップ
84
-
85
- - [メンテナンスガイド](docs/maintenance.ja.md) -- コマンド、レシピ、テスト
package/ARCHITECTURE.md DELETED
@@ -1,85 +0,0 @@
1
- # @markuplint/smarty-parser
2
-
3
- ## Overview
4
-
5
- `@markuplint/smarty-parser` extends `HtmlParser` to lint HTML containing Smarty template expressions. It is a thin configuration layer that defines Smarty-specific `ignoreTags` patterns, delegating all parsing logic to the base HTML parser.
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 Smarty template expressions (`{ ... }`, `{* ... *}`, `{literal} ... {/literal}`) 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 Smarty 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 Smarty syntax.
16
-
17
- ## ignoreTags Configuration
18
-
19
- The `SmartyParser` constructor defines three ignore patterns, ordered from most specific to least specific to ensure correct matching:
20
-
21
- | Type | Start | End | Description |
22
- | ------------------ | ----------- | ------------ | ----------------------------------------------------- |
23
- | `smarty-literal` | `{literal}` | `{/literal}` | Literal blocks passed through without Smarty parsing |
24
- | `smarty-comment` | `{*` | `*}` | Smarty comments (not rendered in output) |
25
- | `smarty-scriptlet` | `{` | `}` | General Smarty tags (variables, functions, modifiers) |
26
-
27
- The ordering matters: `{literal}` and `{*` must be matched before the generic `{` pattern to prevent false matches.
28
-
29
- ## Unsupported Syntaxes
30
-
31
- 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).
32
-
33
- Available:
34
-
35
- ```html
36
- <div attr="{ $value }"></div>
37
- <div attr="{ $value }"></div>
38
- <div attr="{ $value }-{ $value2 }-{ $value3 }"></div>
39
- ```
40
-
41
- Unavailable (unquoted):
42
-
43
- ```html
44
- <div attr="{" $value }></div>
45
- ```
46
-
47
- ## Directory Structure
48
-
49
- ```
50
- src/
51
- ├── index.ts -- Re-exports parser
52
- ├── parser.ts -- SmartyParser class extending HtmlParser
53
- └── index.spec.ts -- Parser integration tests
54
- ```
55
-
56
- ## Key Source Files
57
-
58
- | File | Purpose |
59
- | --------------- | -------------------------------------------------------------------- |
60
- | `src/parser.ts` | Defines `SmartyParser` class and exports singleton `parser` instance |
61
- | `src/index.ts` | Package entry point; re-exports `parser` |
62
-
63
- ## Integration Points
64
-
65
- ```mermaid
66
- flowchart TD
67
- subgraph upstream ["Upstream"]
68
- htmlParser["@markuplint/html-parser\n(HtmlParser class)"]
69
- end
70
-
71
- subgraph pkg ["@markuplint/smarty-parser"]
72
- smartyParser["SmartyParser\nextends HtmlParser\n(ignoreTags only)"]
73
- end
74
-
75
- subgraph downstream ["Downstream"]
76
- mlCore["@markuplint/ml-core\n(MLASTDocument → MLDOM)"]
77
- end
78
-
79
- htmlParser -->|"extends"| smartyParser
80
- smartyParser -->|"produces MLASTDocument"| mlCore
81
- ```
82
-
83
- ## Documentation Map
84
-
85
- - [Maintenance Guide](docs/maintenance.md) -- Commands, recipes, and testing
package/SKILL.md DELETED
@@ -1,95 +0,0 @@
1
- ---
2
- description: Perform maintenance tasks for @markuplint/smarty-parser
3
- globs:
4
- - packages/@markuplint/smarty-parser/src/**
5
- alwaysApply: false
6
- ---
7
-
8
- # smarty-parser-maintenance
9
-
10
- Perform maintenance tasks for `@markuplint/smarty-parser`: modify ignoreTags configuration,
11
- add new Smarty tag patterns, and update tests.
12
-
13
- ## Input
14
-
15
- `$ARGUMENTS` specifies the task. Supported tasks:
16
-
17
- | Task | Description |
18
- | ------------------ | ---------------------------------------- |
19
- | `modify-ignoretag` | Add or modify an ignoreTags pattern |
20
- | `fix-parsing` | Fix a parsing issue with Smarty syntax |
21
- | `add-test` | Add test cases for specific Smarty usage |
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 and ignoreTags configuration
33
- - `src/parser.ts` -- SmartyParser class (source of truth for ignore patterns)
34
-
35
- ## Task: modify-ignoretag
36
-
37
- Add or modify an ignoreTags pattern. 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 ordering: most specific patterns must come first
43
-
44
- ### Step 2: Make the change
45
-
46
- 1. Add the new pattern or modify an existing one in the `ignoreTags` array
47
- 2. Use a descriptive `type` name prefixed with `smarty-`
48
- 3. Ensure proper ordering: longer/more specific start delimiters before shorter ones
49
-
50
- ### Step 3: Verify
51
-
52
- 1. Build: `yarn build --scope @markuplint/smarty-parser`
53
- 2. Add test cases to `src/index.spec.ts` verifying the new pattern produces the correct `#ps:smarty-*` node
54
- 3. Test: `yarn test --scope @markuplint/smarty-parser`
55
-
56
- ## Task: fix-parsing
57
-
58
- Fix a parsing issue with Smarty syntax. Follow recipe #2 in `docs/maintenance.md`.
59
-
60
- ### Step 1: Reproduce the issue
61
-
62
- 1. Create a minimal Smarty template that demonstrates the problem
63
- 2. Write a failing test case in `src/index.spec.ts`
64
-
65
- ### Step 2: Identify the cause
66
-
67
- 1. Check if the issue is in the ignoreTags ordering (most common cause)
68
- 2. Check if the delimiter pattern is too greedy or too restrictive
69
- 3. If the issue is in the base parser, the fix belongs in `@markuplint/html-parser` or `@markuplint/parser-utils`
70
-
71
- ### Step 3: Verify
72
-
73
- 1. Build: `yarn build --scope @markuplint/smarty-parser`
74
- 2. Test: `yarn test --scope @markuplint/smarty-parser`
75
-
76
- ## Task: add-test
77
-
78
- Add test cases for specific Smarty usage. Follow recipe #3 in `docs/maintenance.md`.
79
-
80
- ### Step 1: Write the test
81
-
82
- 1. Read `src/index.spec.ts` for the existing test patterns
83
- 2. Use `nodeListToDebugMaps()` for snapshot-style assertions
84
- 3. Test node names: `#ps:smarty-scriptlet`, `#ps:smarty-comment`, `#ps:smarty-literal`
85
-
86
- ### Step 2: Verify
87
-
88
- 1. Test: `yarn test --scope @markuplint/smarty-parser`
89
-
90
- ## Rules
91
-
92
- 1. **Never reorder ignoreTags carelessly** -- more specific patterns must come before less specific ones.
93
- 2. **Always prefix type names with `smarty-`** for consistency.
94
- 3. **Test with real Smarty patterns** -- `{if}`, `{foreach}`, `{include}`, `{$variable}`, `{$var|modifier}`.
95
- 4. **Add JSDoc comments** to all new public methods and properties.
@@ -1,125 +0,0 @@
1
- # メンテナンスガイド
2
-
3
- ## コマンド
4
-
5
- | コマンド | 説明 |
6
- | ---------------------------------------------- | ---------------------- |
7
- | `yarn build --scope @markuplint/smarty-parser` | このパッケージをビルド |
8
- | `yarn dev --scope @markuplint/smarty-parser` | ウォッチモードでビルド |
9
- | `yarn clean --scope @markuplint/smarty-parser` | ビルド成果物を削除 |
10
- | `yarn test --scope @markuplint/smarty-parser` | テストを実行 |
11
-
12
- ## テスト
13
-
14
- テストファイルは `*.spec.ts` の命名規則に従い、`src/` ディレクトリに配置されています:
15
-
16
- | テストファイル | カバレッジ |
17
- | --------------- | -------------------------------------------------------------------------------------------------- |
18
- | `index.spec.ts` | SmartyParser 統合テスト(スクリプトレット、コメント、リテラルブロック、ネストブロック、フル 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>{ title }</div>');
27
- const debugMaps = nodeListToDebugMaps(doc.nodeList);
28
- expect(debugMaps).toStrictEqual([
29
- '[1:1]>[1:6](0,5)div: <div>',
30
- '[1:6]>[1:15](5,14)#ps:smarty-scriptlet: {␣title␣}',
31
- '[1:15]>[1:21](14,20)div: </div>',
32
- ]);
33
- ```
34
-
35
- 各タグタイプのノード名:
36
-
37
- | ignoreTags タイプ | AST ノード名 |
38
- | ------------------ | ---------------------- |
39
- | `smarty-literal` | `#ps:smarty-literal` |
40
- | `smarty-comment` | `#ps:smarty-comment` |
41
- | `smarty-scriptlet` | `#ps:smarty-scriptlet` |
42
-
43
- ## レシピ
44
-
45
- ### 1. ignoreTags パターンの追加・変更
46
-
47
- 1. `src/parser.ts` を読み、既存の `ignoreTags` 配列を確認
48
- 2. 新しいエントリを追加、または既存のものを変更:
49
- - `type`: `smarty-` プレフィックスを持つ説明的な名前
50
- - `start`: 開始デリミタ(文字列または正規表現)
51
- - `end`: 終了デリミタ(文字列)
52
- 3. 適切な順序を確保: より具体的なパターン(長い開始デリミタ)をより一般的なものの前に配置。例: `{literal}` を `{` の前に
53
- 4. ビルド: `yarn build --scope @markuplint/smarty-parser`
54
- 5. `src/index.spec.ts` にテストケースを追加
55
- 6. テスト: `yarn test --scope @markuplint/smarty-parser`
56
-
57
- ### 2. パース問題の修正
58
-
59
- 1. 問題を再現する最小限の Smarty テンプレートを作成
60
- 2. `src/index.spec.ts` に `nodeListToDebugMaps` を使用した失敗するテストケースを記述
61
- 3. よくある原因:
62
- - **順序の誤り** -- 汎用パターン(`{`)が具体的なパターン(`{literal}`)より先にマッチしている
63
- - **貪欲なマッチング** -- デリミタがテキストを過剰に消費している
64
- - **基底パーサーの問題** -- 問題は `@markuplint/html-parser` または `@markuplint/parser-utils` にあり、このパッケージではない
65
- 4. `src/parser.ts` で問題を修正
66
- 5. ビルドとテスト: `yarn build --scope @markuplint/smarty-parser && yarn test --scope @markuplint/smarty-parser`
67
-
68
- ### 3. テストケースの追加
69
-
70
- 1. `src/index.spec.ts` の既存パターンを確認
71
- 2. `nodeListToDebugMaps()` を使用してデバッグ出力を生成
72
- 3. ノード名が期待される `#ps:smarty-*` パターンと一致することを検証
73
- 4. テストすべき一般的な Smarty パターン:
74
- - 変数: `{$name}`、`{$user.name}`
75
- - モディファイア: `{$name|escape}`、`{$date|date_format:"%Y"}`
76
- - 関数: `{include file='header.tpl'}`、`{assign var='x' value='y'}`
77
- - ブロックタグ: `{if $cond}...{/if}`、`{foreach $items as $item}...{/foreach}`
78
- - コメント: `{* this is a comment *}`
79
- - リテラルブロック: `{literal}...{/literal}`
80
-
81
- ## 上流依存
82
-
83
- このパッケージは `@markuplint/html-parser` のみに依存しています。`HtmlParser` の `ignoreTags` メカニズムや基底 `Parser` クラスの変更がこのパッケージに影響する可能性があります。
84
-
85
- `@markuplint/html-parser` が更新された場合:
86
-
87
- ```shell
88
- yarn build --scope @markuplint/smarty-parser && yarn test --scope @markuplint/smarty-parser
89
- ```
90
-
91
- ## トラブルシューティング
92
-
93
- ### Smarty 式が検出されない
94
-
95
- **症状:** `{$variable}` のような Smarty タグが `#ps:smarty-scriptlet` ノードではなくプレーンテキストとして表示される。
96
-
97
- **原因:** `ignoreTags` パターンがマッチしていない。開始または終了デリミタが不正な可能性がある。
98
-
99
- **解決策:**
100
-
101
- 1. `src/parser.ts` の `ignoreTags` 配列を確認
102
- 2. 開始/終了デリミタが対象の Smarty 構文と一致することを検証
103
- 3. 問題を再現するテストケースを追加
104
-
105
- ### 誤ったタグタイプが割り当てられる
106
-
107
- **症状:** `{* comment *}` が `#ps:smarty-comment` ではなく `#ps:smarty-scriptlet` として検出される。
108
-
109
- **原因:** パターン順序の問題。汎用的な `{` パターンが、より具体的な `{*` パターンの前にマッチしている。
110
-
111
- **解決策:**
112
-
113
- 1. `ignoreTags` 配列でより具体的なパターンが先に配置されていることを確認
114
- 2. 正しい順序: `smarty-literal` > `smarty-comment` > `smarty-scriptlet`
115
-
116
- ### リテラルブロックが正しく処理されない
117
-
118
- **症状:** `{literal}...{/literal}` 内のコンテンツが Smarty 式としてパースされる。
119
-
120
- **原因:** `smarty-literal` パターンがマッチしていない、または `smarty-scriptlet` の後に配置されている。
121
-
122
- **解決策:**
123
-
124
- 1. `smarty-literal` が `ignoreTags` の最初のエントリであることを確認
125
- 2. start が正確に `{literal}` で end が正確に `{/literal}` であることを確認
@@ -1,125 +0,0 @@
1
- # Maintenance Guide
2
-
3
- ## Commands
4
-
5
- | Command | Description |
6
- | ---------------------------------------------- | ---------------------- |
7
- | `yarn build --scope @markuplint/smarty-parser` | Build this package |
8
- | `yarn dev --scope @markuplint/smarty-parser` | Watch mode build |
9
- | `yarn clean --scope @markuplint/smarty-parser` | Remove build artifacts |
10
- | `yarn test --scope @markuplint/smarty-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` | SmartyParser integration tests (scriptlets, comments, literal blocks, nested blocks, full 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>{ title }</div>');
27
- const debugMaps = nodeListToDebugMaps(doc.nodeList);
28
- expect(debugMaps).toStrictEqual([
29
- '[1:1]>[1:6](0,5)div: <div>',
30
- '[1:6]>[1:15](5,14)#ps:smarty-scriptlet: {␣title␣}',
31
- '[1:15]>[1:21](14,20)div: </div>',
32
- ]);
33
- ```
34
-
35
- Node names for each tag type:
36
-
37
- | ignoreTags Type | AST Node Name |
38
- | ------------------ | ---------------------- |
39
- | `smarty-literal` | `#ps:smarty-literal` |
40
- | `smarty-comment` | `#ps:smarty-comment` |
41
- | `smarty-scriptlet` | `#ps:smarty-scriptlet` |
42
-
43
- ## Recipes
44
-
45
- ### 1. Adding or Modifying an ignoreTags Pattern
46
-
47
- 1. Read `src/parser.ts` and review the existing `ignoreTags` array
48
- 2. Add the new entry or modify an existing one:
49
- - `type`: A descriptive name prefixed with `smarty-`
50
- - `start`: The opening delimiter (string or regex)
51
- - `end`: The closing delimiter (string)
52
- 3. Ensure proper ordering: more specific patterns (longer start delimiters) must come before less specific ones. For example, `{literal}` before `{`
53
- 4. Build: `yarn build --scope @markuplint/smarty-parser`
54
- 5. Add test cases to `src/index.spec.ts`
55
- 6. Test: `yarn test --scope @markuplint/smarty-parser`
56
-
57
- ### 2. Fixing a Parsing Issue
58
-
59
- 1. Create a minimal Smarty template that reproduces the issue
60
- 2. Write a failing test case in `src/index.spec.ts` using `nodeListToDebugMaps`
61
- 3. Common causes:
62
- - **Wrong ordering** -- A generic pattern (`{`) matches before a specific one (`{literal}`)
63
- - **Greedy matching** -- A delimiter consumes too much text
64
- - **Base parser issue** -- The problem is in `@markuplint/html-parser` or `@markuplint/parser-utils`, not here
65
- 4. Fix the issue in `src/parser.ts`
66
- 5. Build and test: `yarn build --scope @markuplint/smarty-parser && yarn test --scope @markuplint/smarty-parser`
67
-
68
- ### 3. Adding Test Cases
69
-
70
- 1. Read `src/index.spec.ts` for existing patterns
71
- 2. Use `nodeListToDebugMaps()` to generate debug output
72
- 3. Verify node names match the expected `#ps:smarty-*` pattern
73
- 4. Common Smarty patterns to test:
74
- - Variables: `{$name}`, `{$user.name}`
75
- - Modifiers: `{$name|escape}`, `{$date|date_format:"%Y"}`
76
- - Functions: `{include file='header.tpl'}`, `{assign var='x' value='y'}`
77
- - Block tags: `{if $cond}...{/if}`, `{foreach $items as $item}...{/foreach}`
78
- - Comments: `{* this is a comment *}`
79
- - Literal blocks: `{literal}...{/literal}`
80
-
81
- ## Upstream Dependency
82
-
83
- This package depends solely on `@markuplint/html-parser`. Changes to `HtmlParser`'s `ignoreTags` mechanism or the base `Parser` class may affect this package.
84
-
85
- When `@markuplint/html-parser` is updated:
86
-
87
- ```shell
88
- yarn build --scope @markuplint/smarty-parser && yarn test --scope @markuplint/smarty-parser
89
- ```
90
-
91
- ## Troubleshooting
92
-
93
- ### Smarty expressions are not detected
94
-
95
- **Symptom:** Smarty tags like `{$variable}` appear as plain text instead of `#ps:smarty-scriptlet` nodes.
96
-
97
- **Cause:** The `ignoreTags` pattern is not matching. The start or end delimiter may be incorrect.
98
-
99
- **Solution:**
100
-
101
- 1. Check the `ignoreTags` array in `src/parser.ts`
102
- 2. Verify the start/end delimiters match the Smarty syntax in question
103
- 3. Add a test case reproducing the issue
104
-
105
- ### Wrong tag type is assigned
106
-
107
- **Symptom:** A `{* comment *}` is detected as `#ps:smarty-scriptlet` instead of `#ps:smarty-comment`.
108
-
109
- **Cause:** Pattern ordering issue. The generic `{` pattern is matching before the more specific `{*` pattern.
110
-
111
- **Solution:**
112
-
113
- 1. Ensure more specific patterns appear earlier in the `ignoreTags` array
114
- 2. The correct order is: `smarty-literal` > `smarty-comment` > `smarty-scriptlet`
115
-
116
- ### Literal blocks are not handled correctly
117
-
118
- **Symptom:** Content inside `{literal}...{/literal}` is parsed as Smarty expressions.
119
-
120
- **Cause:** The `smarty-literal` pattern is not matching, or it appears after `smarty-scriptlet` in the array.
121
-
122
- **Solution:**
123
-
124
- 1. Verify `smarty-literal` is the first entry in `ignoreTags`
125
- 2. Check that start is exactly `{literal}` and end is exactly `{/literal}`