feat(ast, parser, render)!: WikitextSettings.allowHtmlBlocksを追加し[[html]]ブロックを context 別に無効化可能に#46
Merged
Merged
Conversation
createSettings の各モード既定値: - page: true (現状互換) - draft / forum-post / direct-message: false Wikidot legacy では Html rule を $disable に入れているため (Wiki.php line 145-147)、本来 page も false が Wikidot 互換だが、wp は transition のため page=true を維持する。 BREAKING CHANGE: WikitextSettings に必須プロパティ allowHtmlBlocks が 追加された。手書きで WikitextSettings を構築している消費者は allowHtmlBlocks フィールドの追加が必要。createSettings(mode) を経由 していれば影響なし。
opener の `]]` を検証してから settings.allowHtmlBlocks === false を判定。 disabled 時はブロック全体を消費して空要素 (success:true / elements:[]) を 返し、ctx.htmlBlocks には push しない。close が見つからない場合も EOF まで 消費して同じく空要素を返す (unclosed-block warning + html-block-disabled info の両方を emit)。中身が text として漏れない。 malformed opener (closing `]]` 欠落) は従来どおり success:false で fallback する。enabled 時の挙動は完全維持。 BREAKING CHANGE: WikitextSettings.allowHtmlBlocks が false の context では [[html]] が AST にも html-blocks 配列にも出ない。
renderHtmlBlock の先頭で ctx.settings.allowHtmlBlocks === false を判定し 早期 return。nextHtmlBlockIndex() の counter advance や htmlBlockUrl resolver 呼び出しより前に置くことで、disabled-but-still-in-AST な ブロック (手組み AST、キャッシュ AST、別 parser 由来) でも何も出力しない。 これによりパース側で settings ゲートが効かないパス (例: 手組み AST の 直接 render) でも enforcement boundary が保てる。 BREAKING CHANGE: WikitextSettings.allowHtmlBlocks が false の context では html element をレンダしない (空)。
parser (tests/unit/parser/settings.test.ts): - createSettings 既定値 (page=true / draft, forum-post, direct-message=false) - enabled (page): [[html]] が html element になり html-blocks に push される - disabled (draft): element 出ず html-blocks 空、html-block-disabled diagnostic、本文に漏れない - disabled + unclosed: EOF まで consume、unclosed-block + html-block-disabled 両方 emit、漏れない - disabled + 周囲非干渉: 前後の paragraph は残る - forum-post / direct-message でも disabled になる render (tests/unit/render/settings.test.ts): - enabled: iframe が出る - disabled: 手組み AST に html element があっても iframe 出ない (enforcement boundary) - disabled: htmlBlockUrl resolver が呼ばれない
3 件の漏れ・誤検出を修正: 1. (High) close-detection の修正 parseBlockName で名前が "html" と一致した時点で foundClose=true に していたため、malformed `[[/html no-close` (BLOCK_CLOSE 欠落) で close と誤認識し、後続テキストが leak する可能性があった。BLOCK_CLOSE まで reach できることを確認してから close と認める実装に変更 (whitespace は 許容)。これにより disabled 時の unclosed パスも常に EOF まで consume する。 2. (Medium) text-level の [[html]] strip pre-pass を追加 block-rule の gate だけでは段落内 `before [[html]]X[[/html]] after` のような inline-position occurrence を捕まえられない (block dispatcher が mid-paragraph トークンに到達しない)。Wikidot 互換の非貪欲 regex で parse 開始時に text-level で strip し、両ポジションで漏れない設計に変更。 parse() に `stripDisabledHtmlBlocks` を追加。 3. (Low) disabled 時の contents 累積をスキップ disabled では body を破棄するため、token.value を contents に積む処理 をガード。大きな入力でのメモリ/CPU を節約。 test: 段落内 inline 漏れ防止 + malformed close 漏れ防止 のケースを追加。
…pre-pass 廃止) text-level pre-pass の問題点を洗い直して再設計: 1. (High) Parser class 直接使用で pre-pass がバイパスされる 2. (High) closed のみ strip、mid-paragraph unclosed が漏れる 3. (Medium) text-level pre-pass が [[code]]/[[html]] 等 raw 内も削除 4. (Medium) strip 後の lex で diagnostic 位置がずれる 5. (Medium) pre-pass の gate が truthiness、rule/render は === false → text-level pre-pass を廃止し、inline html rule 追加で再設計: - packages/parser/src/parser/preprocess/strip-disabled-html.ts 削除 - parse() を元に戻す - packages/parser/src/parser/rules/inline/html.ts (新規 htmlInlineRule): - allowHtmlBlocks !== false: success:false (従来挙動維持) - === false: [[html]]...[[/html]] を inline で消費、空要素返す - close-detection は BLOCK_CLOSE まで verify (whitespace 許容) - unclosed: NEWLINE+NEWLINE (blank line) で停止 (後続 paragraph 保護) - block rule にも同じ blank-line 停止を追加 - inline rules 配列に登録 (commentRule の直後) これで5件すべて解消: 1. rule 自体が parse 時に走るので Parser 直接使用でも gate される 2. inline rule が mid-paragraph closed/unclosed 両方扱う 3. [[code]]/[[html]] 内は block rule で raw 扱いされ inline rule は到達しない 4. source mutation なしで位置情報そのまま 5. すべて === false に統一 test 追加: Parser 直接使用 / blank-line で stop / code 内 [[html]] 保護
2 件のバグを修正: 1. (High) blank-line stop が enabled でも効き、空行を含む valid [[html]] block が page mode で壊れる。例: [[html]]\n<p>one</p>\n\n<p>two</p>\n[[/html]] → blank-line stop を disabled 時のみに限定。 2. (Medium) close detection は [[/html ]] (whitespace before ]]) を 許容するが、close 消費側が whitespace を skip しておらず ]] が paragraph text に漏れていた。close 消費側にも whitespace skip を追加。 test: 空行入り valid html block / whitespace 付き close tag のケース追加。
disabled mode で blank-line stop が close より先に発火し、空行を含む closed [[html]] (例: [[html]]\n<p>one</p>\n\n<p>two</p>\n[[/html]]) の 後半 <p>two</p> と [[/html]] が paragraph text に漏れていた。 修正: 事前の forward lookahead で real close 存在を確認する lookaheadHasHtmlClose ヘルパを追加し、close が ahead に存在する場合は blank-line stop を抑止。close 不在 (truly unclosed) の時のみ blank-line stop が効く。block rule / inline rule 両方に適用。 regression test: disabled mode で空行入り closed block が完全に消費される ことを確認。
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
wdpr-demo-v1 | 6fb375d | Commit Preview URL Branch Preview URL |
Jun 03 2026, 03:51 AM |
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
decompiler-preview | 6fb375d | Commit Preview URL Branch Preview URL |
Jun 03 2026, 03:50 AM |
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
wdpr-demo-v1-files | 6fb375d | Commit Preview URL Branch Preview URL |
Jun 03 2026, 03:50 AM |
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.
Summary
WikitextSettingsに 必須プロパティallowHtmlBlocks: booleanを追加し、parser と renderer の両側で[[html]]ブロックを無効化できるようにする。createSettings(mode)の既定値:page=true(現状互換) /draft, forum-post, direct-message = false。[[html]]...[[/html]]のブロック全体を消費して空要素を返す (中身が text として漏れない)。[[html]]も新規 inline rule で gate。renderHtmlBlock先頭 (counter / resolver より前) に gate を入れ、手組み AST / キャッシュ AST / 別 parser 由来 AST でも enforcement boundary が効くようにする。背景
[[html]]は raw HTML を iframe 経由で配信する仕組みだが、静的ホスティングや未信頼入力のプレビュー等、その仕組みが使えない / 使いたくない context が存在する。これまでユーザー側で parse 後 AST を走査してhtmlノードを除去する暫定対処が必要だったが、本フラグ導入により settings 経由でクリーンに無効化できる。なお Wikidot legacy (
lib/Text_Wiki/Text/Wiki.phpの$disable = ['Html']) では Html は 既定 disable だが、wp は既存ユーザー保護のためpage=trueを当面維持する。将来的に Wikidot 互換へ寄せる際は別 issue で扱う。Changes
1.
@wdprlib/astWikitextSettingsにallowHtmlBlocks: booleanを必須追加。createSettings(mode)の defaults を上記の通り設定。WikitextModeの JSDoc table を 5 列に拡張。2.
@wdprlib/parserhtmlBlockRuleに gate を追加:BLOCK_CLOSEを検証した直後でctx.settings.allowHtmlBlocks === falseを判定。BLOCK_END_OPEN+ name(html) + 任意の whitespace +BLOCK_CLOSEを検証 (malformed[[/htmlで誤認識して後続テキストが漏れる挙動を防止)。close 末尾の whitespace は consume 側でも skip。consumed経路はsuccess: true / elements: []を返し、html-block-disabled(info) を emit。未閉じ時はunclosed-block(warning) も併用。htmlInlineRule(packages/parser/src/parser/rules/inline/html.ts):allowHtmlBlocks !== falseならsuccess: false(従来挙動維持)。=== falseなら[[html]]...[[/html]]を inline で消費し空要素返す。htmlInlineRuleを登録 (commentRule直後)。3.
@wdprlib/renderrenderHtmlBlock(ctx, data)の先頭でctx.settings.allowHtmlBlocks === false時に早期 return。nextHtmlBlockIndex()counter advance やhtmlBlockUrlresolver 呼び出しより前に置くことで、手組み / キャッシュ / 別 parser 由来 AST でも iframe 出力を確実に抑止。4. テスト
tests/unit/parser/settings.test.ts:createSettingsの既定値確認 (page=true / 他=false)。[[html]]が html element になりhtml-blocksに push される /html-block-disableddiagnostic は出ない。html-blocks空 /html-block-disabled出る / 本文に漏れない。html-block-disabled+unclosed-block両方 emit。[[html]]の inline 漏れ防止。[[/htmlBLOCK_CLOSE 欠落) でも leak しない。Parserクラス直接使用でも gate される。[[html]]block (page) が正常 parse。[[html]]block (draft) が leak せず完全消費。[[/html ]]) が正しく consume。[[code]]内の[[html]]は raw 扱いで影響なし。tests/unit/render/settings.test.ts:htmlelement があっても iframe 出ない。htmlBlockUrlresolver が呼ばれない。BREAKING CHANGE
WikitextSettingsに必須プロパティallowHtmlBlocksが追加されました。手書きでWikitextSettingsを構築しているユーザーはallowHtmlBlocksフィールド追加が必要 (createSettings(mode)を経由していれば影響なし)。WikitextSettings.allowHtmlBlocks === falseの context では[[html]]ブロックが AST にもhtml-blocks配列にも出ず、render 側も iframe を出さない。Test plan
bun testで 1190 件)。tests/fixtures/html/basic,tests/fixtures/html/fail) で page mode の従来挙動を回帰確認。