@markuplint/smarty-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 +85 -0
- package/ARCHITECTURE.md +85 -0
- package/CHANGELOG.md +3 -3
- package/SKILL.md +95 -0
- package/docs/maintenance.ja.md +125 -0
- package/docs/maintenance.md +125 -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,85 @@
|
|
|
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
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
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/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/smarty-parser@4.6.22...@markuplint/smarty-parser@4.6.23) (2026-02-10)
|
|
7
7
|
|
|
8
8
|
**Note:** Version bump only for package @markuplint/smarty-parser
|
|
9
9
|
|
|
10
|
+
## [4.6.22](https://github.com/markuplint/markuplint/compare/@markuplint/smarty-parser@4.6.21...@markuplint/smarty-parser@4.6.22) (2025-11-05)
|
|
10
11
|
|
|
11
|
-
|
|
12
|
-
|
|
12
|
+
**Note:** Version bump only for package @markuplint/smarty-parser
|
|
13
13
|
|
|
14
14
|
## [4.6.21](https://github.com/markuplint/markuplint/compare/@markuplint/smarty-parser@4.6.20...@markuplint/smarty-parser@4.6.21) (2025-08-24)
|
|
15
15
|
|
package/SKILL.md
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
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.
|
|
@@ -0,0 +1,125 @@
|
|
|
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}` であることを確認
|
|
@@ -0,0 +1,125 @@
|
|
|
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}`
|
package/lib/index.d.ts
CHANGED
|
@@ -1 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module @markuplint/smarty-parser
|
|
3
|
+
* Markuplint parser plugin for Smarty templates. Extends the standard HTML parser
|
|
4
|
+
* to treat Smarty literal blocks, comments, and scriptlet tags 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/smarty-parser
|
|
3
|
+
* Markuplint parser plugin for Smarty templates. Extends the standard HTML parser
|
|
4
|
+
* to treat Smarty literal blocks, comments, and scriptlet tags 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 Smarty templates that extends the standard HTML parser.
|
|
4
|
+
*
|
|
5
|
+
* Configures the HTML parser to recognize Smarty tag variants as opaque blocks:
|
|
6
|
+
* - `{literal} ... {/literal}` (literal blocks passed through without parsing)
|
|
7
|
+
* - `{* ... *}` (Smarty comments)
|
|
8
|
+
* - `{ ... }` (general Smarty scriptlet tags for variables, functions, and modifiers)
|
|
9
|
+
*/
|
|
2
10
|
declare class SmartyParser extends HtmlParser {
|
|
3
11
|
constructor();
|
|
4
12
|
}
|
|
13
|
+
/**
|
|
14
|
+
* Singleton Smarty parser instance for use by the markuplint engine.
|
|
15
|
+
*/
|
|
5
16
|
export declare const parser: SmartyParser;
|
|
6
17
|
export {};
|
package/lib/parser.js
CHANGED
|
@@ -1,4 +1,12 @@
|
|
|
1
1
|
import { HtmlParser } from '@markuplint/html-parser';
|
|
2
|
+
/**
|
|
3
|
+
* Parser for Smarty templates that extends the standard HTML parser.
|
|
4
|
+
*
|
|
5
|
+
* Configures the HTML parser to recognize Smarty tag variants as opaque blocks:
|
|
6
|
+
* - `{literal} ... {/literal}` (literal blocks passed through without parsing)
|
|
7
|
+
* - `{* ... *}` (Smarty comments)
|
|
8
|
+
* - `{ ... }` (general Smarty scriptlet tags for variables, functions, and modifiers)
|
|
9
|
+
*/
|
|
2
10
|
class SmartyParser extends HtmlParser {
|
|
3
11
|
constructor() {
|
|
4
12
|
super({
|
|
@@ -22,4 +30,7 @@ class SmartyParser extends HtmlParser {
|
|
|
22
30
|
});
|
|
23
31
|
}
|
|
24
32
|
}
|
|
33
|
+
/**
|
|
34
|
+
* Singleton Smarty parser instance for use by the markuplint engine.
|
|
35
|
+
*/
|
|
25
36
|
export const parser = new SmartyParser();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@markuplint/smarty-parser",
|
|
3
|
-
"version": "4.6.
|
|
3
|
+
"version": "4.6.23",
|
|
4
4
|
"description": "Smarty 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
|
}
|