feat(parser/ast): opener-embedded [[#if]] / [[#expr]] / [[#ifexpr]] と [[iftags]] bare prefix 対応#50
Merged
Merged
Conversation
iftags/preprocess.ts に閉じていた `computeBracketDepths` / `maskRawRegions` / `makeUniqueSentinels` / `restorePlaceholders` を共通モジュール `packages/parser/src/parser/preprocess/utils.ts` に移し、iftags 側は import に 切り替えた。次コミットで追加する opener-embedded [[#if]] 等の preprocess も 同じ utility を共有する。
…から共有 これまで @wdprlib/render の utils 配下にあった [[#expr]] / [[#ifexpr]] 用の evaluator (`evaluateExpression`, `isTruthy`) と数値整形 (`formatExprValue`) を @wdprlib/ast に集約し、render の expr 要素も新しい場所から import するように 変更した。 合わせて以下を追加・修正: - `!` (BANG) を unary not 演算子として認識 (`!=` は従来どおり) - `true` / `false` をリテラルとしてサポート (それぞれ 1 / 0 として評価) - 比較演算子の RHS で `!()` が来る場合のため `parseUnary` でも BANG を扱う (例: `!(true)!=!(false)`) - `formatExprValue` は `String(n)` でフル精度を保持 (以前の 6 桁丸めを廃止) これにより render と preprocess の両方が同じ式評価ロジックを使い、出力が 場所によってずれない。
…t-level に評価 `[[div class="[[#if 1 | folded | unfolded ]]"]]` のように block opener の 属性内に埋め込まれた [[#if]] / [[#expr]] / [[#ifexpr]] は、トークナイザが well-formed な opener を復元できず、これまで [[div]] 行ごと生テキスト化 していた。 `packages/parser/src/parser/preprocess/expr.ts` を追加し、`[[#` の出現位置の 未閉ブラケット深度 (`computeBracketDepths`) が > 0 のときに限り text-level に 評価して then / else / 数値文字列に置換する。top-level の [[#if]] 等は既存の inline rule が処理するため AST に if/expr/ifexpr ノードが残る形は変わらない。 挙動の補足: - `[[#expr(1+1)]]` のようにキーワード直後に空白を持たない書式も受理する - empty `[[#expr ]]` は inline render に合わせて空文字を返す ([[#ifexpr | ... ]] の empty は ERROR placeholder のままにする) - ネストした [[#if [[#if ...]] | ... ]] は innermost-first で順次畳む `parse()` で `preprocessExpr(source)` を常時実行する。top-level 直接の [[#if]] 等を touch しないので既存呼び出しには影響しない。
`[[iftags]]` の condition string が `+`/`-` のみ (タグ名なしのプレフィックス) の場合、本家挙動は次のようになる: - `[[iftags - ]]` → 「forbid nothing」= Show Always - `[[iftags + ]]` → 「require unnamed tag」= 他にトークンがあっても常に false (Hide Always) - `[[iftags]]` (空) → supercommentout (= 常に false、従来どおり) `TagCondition` に `hasEmptyRequired?` / `hasEmptyForbidden?` を追加して bare prefix の有無を保持し、`evaluateTagCondition` の分岐を更新した。 `+` は他トークンと組み合わさっても常に false、`-` 単独のみ無条件 true。
bun runtime での development resolution が `dist/index.js` を読まず、 ワークスペース内の `src/index.ts` を直接読むよう `exports."." .bun` 条件を 追加した。あわせて publish tarball に src を含めるよう `files` にも src を 追加し、bun consumer が tarball install 後に bun 条件で src を解決しても ファイルが存在する状態を保つ。 通常の Node ESM / CJS consumer は従来どおり `dist` を読むため挙動は不変。
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
wdpr-demo-v1 | dafd205 | Commit Preview URL Branch Preview URL |
Jun 10 2026, 01:15 PM |
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
wdpr-demo-v1-files | dafd205 | Commit Preview URL Branch Preview URL |
Jun 10 2026, 01:14 PM |
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
decompiler-preview | dafd205 | Commit Preview URL Branch Preview URL |
Jun 10 2026, 01:14 PM |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
背景
[[div class="[[#if 1 | folded | unfolded ]]"]]のように block opener の属性内に[[#if]]/[[#expr]]/[[#ifexpr]]を埋め込んだ書式は、トークナイザが well-formed な opener を復元できず[[div]]行ごと生テキストとして残ってしまっていた。[[iftags]]もbare +/bare -の prefix を Wikidot 本家挙動と異なる扱いをしていた。合わせて
[[#expr]]/[[#ifexpr]]の evaluator が!演算子とtrue/falseリテラルをサポートしておらず、これらを使う式 ([[#ifexpr !(false) | NOT | else ]]等) がrun-time error: Unknown character: !で落ちていた。変更点
1. preprocess 共通 utility の抽出
computeBracketDepths/maskRawRegions/makeUniqueSentinels/restorePlaceholdersをpackages/parser/src/parser/preprocess/utils.tsに切り出し、iftags 側と新規 expr 側で共有。2. expression evaluator を
@wdprlib/astに移動evaluateExpression/isTruthy/formatExprValueを@wdprlib/renderから@wdprlib/astに集約。@wdprlib/parserから render に依存させないようにするため、評価器は ast 経由で参照する。evaluator の機能追加:
!(BANG) を unary not 演算子として認識 (!=は従来どおり)true/falseをリテラルとしてサポート (1 / 0 として評価)parseUnaryでも BANG を扱い、a != !(b)のような比較 RHS の!()を解釈formatExprValueはString(n)でフル精度 (以前の 6 桁固定丸めは廃止)3. opener-embedded
[[#if]]/[[#expr]]/[[#ifexpr]]の text-level 評価packages/parser/src/parser/preprocess/expr.tsを追加し、[[#の出現位置の未閉ブラケット深度が > 0 のときに限り text-level に評価して then / else / 数値文字列に置換する。top-level の[[#if]]等は既存の inline rule が処理するため AST にif/expr/ifexprノードが残る形は変わらない。挙動の補足:
[[#expr(1+1)]]のようにキーワード直後に空白を持たない書式も受理する[[#expr ]]は inline render と同じく空文字を返す[[#ifexpr | ... ]]の empty expression は ERROR placeholder を残し silently 潰さない[[#if [[#if ...]] | ... ]]は innermost-first で順次畳む4.
[[iftags]]の bare +/- prefix 対応TagConditionにhasEmptyRequired?/hasEmptyForbidden?を追加し、本家挙動を再現する。[[iftags - ]]→ 「forbid nothing」= Show Always[[iftags + ]]→ 「require unnamed tag」= 他にトークンがあっても常に false (Hide Always)[[iftags]](空) → supercommentout (常に false、従来どおり)5.
buncondition とsrcを package files に追加bun runtime の development resolution が
dist/index.jsを読まずワークスペース内のsrc/index.tsを直接読むようexports."." .bunを追加。publish tarball で src が引けるようfilesにも追加した。通常の Node ESM / CJS consumer は従来どおりdistを読む。検証
期待挙動の 11 ケース (
[[iftags - ]] Show Alwaysから[[#ifexpr !(true)!=!(false) | XOR ]]まで) がすべて期待値どおり出力されることを実機で確認:Test plan
bun run lint(10 warnings, 0 errors — 既存箇所のみ)bun run formatbun run typecheckbun test(1318 pass / 0 fail)tests/unit/parser/preprocess-if.test.ts):[[#if]]の collapse / depth gating[[#if]]を touch しないこと