securemark 0.289.5 → 0.289.6

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
@@ -1,5 +1,9 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.289.6
4
+
5
+ - Refactoring.
6
+
3
7
  ## 0.289.5
4
8
 
5
9
  - Refactoring.
package/design.md CHANGED
@@ -291,7 +291,7 @@ CodeMirrorが素では速いがVimModeでは数万文字程度でも耐え難く
291
291
 
292
292
  SecuremarkのAnnotation構文に典型的であるように文脈を変更する構文の中にその文脈に依存し変更される他の構文が存在する場合文脈の相違から解析結果を再利用不能(`αAβ | αA'B`)なバックトラックが生じる。またこの結果再帰的バックトラックが生じる可能性があり再帰的バックトラックは一般的にメモ化により解決されるがCommonMarkは最小計算量と実行性能を追及するためメモ化を廃止していることからメモ化により性能を低下させてまで文脈依存構文の問題を解決するつもりはないと思われる(すなわちCommonMarkは機械を至上とし人間に制約を課す低水準の言語であり人間の需要を至上とするSecuremarkとは対極に位置する)。従って現在の再帰的バックトラックなしで解析可能な構文と最小計算量に制約されるCommonMarkにはこれ以上再帰的バックトラックが生じる可能性を増加させて文脈依存構文を追加できないという拡張性の欠陥が存在する(CommonMarkは`~~a~~`のような文脈自由構文は容易に追加できるがこうしたマージンを失えばもはや後はなく文脈依存構文を追加できないという事実に直面する)。CommonMarkの仕様策定者が構文の拡張に(名称を維持するか否かにかかわらず)不自然なまでに消極的または進展がないのは正当な理由や怠慢からでなく文脈依存構文を追加するにつれて構文解析戦略の失敗が明白になっていくためおよび最小計算量を放棄して現在の高い実行性能を低下させたくないためであり陳腐な自尊心を守るためにこのような拡張性の欠陥を秘匿しCommonMarkとその仕様策定者である自分の評価が下がらないよう画策しているからである。でなければこの拡張性の欠陥を何年も隠さず速やかに公表して助力を求めていなければならず不都合な事実を隠し陳腐な自尊心を守るために全Markdown利用者および開発者を不必要に足止めした罪は重い。
293
293
  CommonMarkは小さく単純であるがゆえに正しくいられる象牙の塔であり仕様策定者はこの正しさを失わず正しいままでいたいがために象牙の塔に引きこもり小さな表面的完全性に固執し続けているに過ぎない。しかしCommonMarkは実際にはまったく完全ではなく本来文脈依存言語であるMarkdownを文脈自由言語として解析しているため破綻している部分があり実際のところCommonMarkは最初から最後までずっと壊れている。CommonMarkはバックトラックなく最小計算量で解析するために文脈自由言語として設計されているが実際には文脈依存言語であるMarkdownから文脈依存構文を文脈自由構文に変換して除去することに失敗しているためCommonMarkは最初の数年間は再帰的バックトラックに気づかず最悪計算量が指数関数計算量になっており修正後は最悪計算量が当初の想定の2nから32nへと劇的に悪化している(より正確にはCommonMarkもSecuremarkもCode構文により+1nされるが説明の簡略化のため省略する)。CommonMarkが最初の数年間他人に指摘され修正されるまで指数関数計算量であった事実(https://github.com/commonmark/cmark/commit/45f4fc9b917c11221aa03e70a41e3046335a235d)はCommonMarkが初歩的な再帰的バックトラックの原理すら理解していないド素人により設計された素人仕事である事実を証明しておりたかが強調構文の解析のためにメモ化を行い(https://github.com/commonmark/commonmark.js/commit/6d7d6cf150dedb53b7f0972b79313df3364ebbed https://github.com/commonmark/commonmark.js/blob/ac8529c9f55da7fdc1186e3f34313cf411de6e71/js/stmd.js )他人にメモ化を使わない正しい実装に修正された事実(https://github.com/commonmark/commonmark.js/commit/8837f199608ac2e321f75653736747b1e692072f)もまたCommonMarkの仕様策定者がその任に堪える能力のないド素人である事実を証明している。スタックを使う代わりにメモ化するド素人の能力を誰が擁護できるのか?ド素人が作った結果初歩的な再帰的バックトラックすら他人に指摘されるまで気づかず最悪計算量が32nにまで著しく悪化した設計が正しいと言えるのか?不可能である。一貫してド素人により設計開発仕様策定されているCommonMarkは未だにバックトラックを忌避し2nの最小計算量に固執しているがそんなものはとっくの昔に破綻してるのを未練がましく執着しているだけである。最悪計算量が32nにまで悪化するのであれば計算量が少ないよう適切に設計された文脈依存言語と大差なく最初から文脈依存言語として適切に設計するほうが自然で破綻がなく拡張性を確保できていた。。さらにSecuremarkは再帰的バックトラックを対策しているため文脈依存構文数が増えても最悪計算量は1+mで定数的にしか増加しない(新しい構文の新しい文脈も内部の括弧類のような基本構造は共通であるため一度解析すればあとは既存の解析情報を利用してバックトラックなしで1回で解析できる)がCommonMarkは再帰的バックトラックを対策していないため文脈依存構文数が増えると最悪計算量が2^mで指数関数的に致命的に激増する(より正確には通常の文脈依存構文を基準にすれば32\*2^m、リンク構文を基準にすれば32^m)。または計算量が組み合わせ爆発しないよう文脈依存構文の入れ子を制限する、存在自体が欠陥と失敗の宣言に等しい制限が必要になる(リンク構文とイメージ構文を入れ子にできるのはaltを不適切に外部と同じ文脈のMarkdownとして解析することで文脈自由化しているからであり本来文脈依存構文は異なる文脈を持つためこのようなことはできずイメージ構文もこの本来できない文脈自由化を行ったためにCommomMarkではaltがプレーンテキストでなくMarkdownとして不適切に解析されている)。文脈依存構文を強引に文脈自由構文として解析したために最悪計算量が当初の想定の2nから32nに劇的に悪化し結局文脈依存言語の妥当な最悪計算量の水準に落ちていることおよび文脈依存構文を追加すると最悪計算量が指数関数的に悪化することから文脈自由言語として設計されたCommonMarkの破綻と失敗は明らかでありCommonMarkは文脈自由構文に固執せず最初から多少の文脈依存構文を許容するよう設計しなければならなかった。実際には文脈依存言語であるにもかかわらず文脈自由言語としてしか構文解析できなければ構文解析が破綻し構文が増えるほど破綻が拡大することは自明でありすでに破綻済みで失敗済みのCommonMarkに未来などない。文脈依存言語であるMarkdownに対して文脈自由構文解析器として作られたCommonMarkは最初から技術選択を間違え失敗しており最初から破綻していた。CommonMarkが文脈依存言語を文脈自由言語として最小計算量で解析するために使用した手法は邪道の小手先の技術に過ぎずCommonMarkは邪道を選んだ挙句失敗に終わったのである。文脈依存言語を文脈依存言語のまま解析する正道を選んだSecuremarkが正着し文脈自由言語に歪める邪道を選んだCommonMarkが失着に終わったのは当然の帰結であり最初の言語種別選択の時点で決まっていたことである。文脈依存言語であるMarkdownを文脈自由言語として解析しようとして行き詰ったCommonMarkとその閉塞に技術的合理性はなくCommonMarkは最初からの失敗していた過去の遺物であり廃棄すべき負債である。CommonMarkに動きがないのはすでに破綻しており死んでいることに気付かれないように死んでいるからに過ぎない。このようにCommonMarkは完全に破綻し失敗に終わっているためCommonMarkの拡張や発展を期待しても無駄であり既存の文脈依存構文による破綻がなく新たに文脈依存構文を追加可能な拡張性の高いMarkdown仕様は新しく作り直さなければ作れない。しかしCommonMarkの仕様策定者は独自の新しい仕様においてもMarkdownをバックトラックを排除した文脈自由言語として設計しているため救いようがない。しかもその構文と仕様は機械可読性を至上としているため非常に醜く人間が書くことも読むことも困難で実用性の欠如したものである。
294
- Securemarkはスーパークラス構文が解析に失敗した入力をサブクラス構文で解析しないことにより再帰的バックトラックを回避する(解析中の構文自身はスーパークラスとサブクラスの両方に含まれるものとする)。スーパークラス構文A(`αAβ`)の解析が失敗すればサブクラス構文B(`α'A'β'`)の解析も失敗することは自明であり試みるまでもなく解析を省略できる。これは二つの構文の文法が生成する各言語空間がスーパーセットとサブセットの関係にあるならスーパーセットの言語空間の外にある文字列はサブセットの言語空間の内に入る余地がないことからも自明である(この解析法は事前処理によっても可能だが文脈内外のオートリンクURLの括弧解析などを高速に行うことは困難であるためMarkdownをこの事前処理により高速化することは難しい)。メモ化は解析結果を再利用することで結果的に副次的効果としてバックトラックを回避しているのでありメモ化はバックトラックを回避するだけなら過剰機能であり不要である(メモ化はバックトラックがなければ使用されないためバックトラックの少ないほとんどの入力に対してはほとんど使用されず無駄であり空間計算量を常に不必要に数倍以上に増加させてまで行う利益は少ないことから構文解析において必須でも標準でもない。バックトラック回避のためにメモ化するとバックトラックなしで解析可能な場合も常に不必要に空間計算量が増加することがメモ化の最大の欠点である(この問題は解析失敗時のみメモ化すれば解消可能のはずだが基本的にはこうなる)。特に文脈自由構文解析器におけるメモ化の使用は完全に無駄でありバグである。バックトラックが発生しないか他の方法で解決されるならば最終的に使用されないメモ化は無駄であり複数の文脈で解析結果が同一である文脈独立性のある構文ならメモ化した解析結果を異なる文脈で再利用でき有用だがそのような構文は基本的に少数であるため効果が限定的であり最悪計算量は改善されない)。この独自の解析法により、CommonMarkならば最悪計算量32n\*2^2+4n=132nを下らない拡張Markdown言語をSecuremarkはメモ化なしで8nの最悪時間計算量で解析している。すなわち直接比較してもCommonMarkの最悪計算量32nに対してSecuremarkは8nでありSecuremarkはCommonMarkより最悪計算量が小さい。またSecuremarkはメモ化を行っていないため実装依存の非効率性を除けば空間計算量も小さい。時間計算量と空間計算量を合わせてO(n, n)と表記すると文脈依存言語の通常の最悪計算量はO(n^2, n)、メモ化により効率化できた場合もO(nm, nm)(S(m)>=m byte)(解析結果の構文木等を記録するため空間使用量S(m)>=m byte)に過ぎないがSecuremarkのマーキング法はO(nm, nm)(S(m)=m bit)(解析の失敗フラグしか記録しないためS(m)=m bit。また包含文字列を含め全体でn byteの構文1つに対してメモ化は少なくともn byteを消費するがマーキング法のメモリ消費量は構文全体のサイズにかかわらず1bit固定である。よって100KBの構文1つに対してメモ化は100KB以上消費するがこの場合もマーキング法は1bitしか消費しない。なお成功フラグによる解析は解析済みかの情報が追加で必要になり処理が複雑化かつほとんどの成功した解析に対してメモリ消費と追加処理が発生し解析効率が全体として悪化するが失敗フラグは少数の失敗した解析でしか解析効率が悪化しないため失敗フラグを記録するほうが全体として解析効率が高く優れている)と極めて効率的であり最も優れている。以上のようにSecuremarkの構文解析アルゴリズムの優位性は理論と実践いずれにおいても革新的かつ圧倒的である。現在のSecuremarkは開発効率と安全性優先の実装により実行性能が大きく低下しているが一定時間内で解析不能な入力の影響を解析時間と解析範囲の制限により局限しているため、最悪計算量で低速に動作させる入力に対してはこの実装をサーバーで使用し多数のユーザーのリクエストに応じるには低速で脆弱性となる可能性があるがクライアントで個別のユーザーの操作に応じるには十分高速であるためクライアントで解析する限り解析の効率または速度が実用上問題となることはなく仕様が固まり実行効率優先の高速な実装に移れば速度面の懸念もないだろう。またSecuremarkの再帰数制限はパーサーコンビネーターの使用による実装依存の制限であるため再帰が生じないよう書き換えれば再帰数制限もない。SecuremarkをCommonMarkのような再帰数制限のない実装に変換することは設計上何の支障もないがCommonMarkをSecuremarkのような正常な文脈依存言語解析器に変更することは解析規則の破壊的変更なしに不可能である。具体的には二重リンク`[[]()]()`を解析するときCommonMarkはバックトラックと計算量を最小化すべく文脈自由構文解析器として設計されているためリンク構文内をリンク構文が定義されていない異なる文脈として解析せず外側のリンク構文の解析を破棄して内側のみリンク構文として解析するがSecuremarkは文脈依存構文解析器とし設計されているためリンク構文内にリンク構文が定義されておらず外側のみリンクとして解析する(ここでCommonMarkはリンク構文`[]()`のバックトラック除去ひいては文脈自由化に角括弧`[]`に対しては成功したが丸括弧`()`に対しては失敗したことで最悪計算量が指数関数計算量ないし32nに悪化した。リンク構文を本来通り文脈依存構文として解析すればリンク構文の最悪計算量が2nとなり角括弧部分に限っては1nから2nに悪化するが丸括弧部分は32nから2nに著しく改善する。ここがCommonMarkの根本的な欠陥と失敗が最も明瞭に表出している部分である)。この問題はイメージ構文においてさらに顕著でありリンク構文と同じ問題が正当な表現`![![]()]()`で発生しさらにHTMLのaltはプレーンテキストとして表示されるためMarkdownのaltもプレーンテキストとしてそのまま表示されなければならないにもかかわらず文脈を一致させ再帰的バックトラックを防ぐためにMarkdown文字列として解析されaltに`*a*`と書かれたものを`a`に変換して表示する。無論新しい文脈依存構文を追加する場合も同じ制約が永遠についてまわり構文内文字列をMarkdownとして解析する文脈依存構文においてこの制約を破ると最悪計算量が2^m、より正確には32\*2^mないし32^mで指数関数的に増加する。すなわちCommonMarkは文脈依存構文を追加すると最悪計算量が32\*2^mないし32^mで指数関数的に悪化するという拡張性の致命的欠陥が存在する。こんな最悪計算量が32^mで組み合わせ爆発する欠陥言語を拡張できるわけがないことはもはや明白である。また多くのプログラミング言語を見ても明らかなように文脈依存言語は構文内で使用可能な構文を定義しその他の構文は構文内で使用できず例外処理するのが通常でありCommonMarkのように本来使用不能な構文を外側の構文を無効化して使用可能に変える異常な言語はほとんどの人間はCommonMark以外に見たことがないだろう。ほぼすべての人間において他のすべての言語が同じ一貫した規則を持ち同じ規則で統一的に使用できるのに対してCommonMarkだけが他と異なる異常な挙動をして認知的負荷をかけるのである。破壊的変更を避けるため旧構文だけ従来通り文脈自由構文として解析し新構文を文脈依存構文として解析すればキメラ的な非常に不自然かつ歪で一貫性のない解析規則によりCommonMarkという一つの言語の中だけでもユーザーを混乱させるものとなり旧構文で使用した苦肉の策を不必要に新構文でも使用して一貫させれば文脈依存言語なのに文脈自由言語の苦肉の策で解析されるこれもまたキメラ的な非常に不自然で理論的に設計ミスが明白で実用的にも認知的負荷の高い言語となる。そして構文エラーであることが明らかな二重リンクを意図的に入力することはほぼないためCommonMarkの異常な挙動はこれまであまり人目に付かなかったがMarkdownに文脈依存構文を追加して明らかでない構文エラーが頻発すると他の言語と逆に外側の構文を無効化していくCommonMarkの異常な挙動を頻繁に目撃し認知的負荷をかけられることになる。このようにCommonMarkは内部設計だけ文脈依存構文解析器に変更しても理論的齟齬が解析結果と使用感に明白に表れるためCommonMarkが失敗した言語である事実は到底隠し切れるものではない。Markdownはもはや負債以外の何物でもないCommonMarkの異常な解析規則を捨てて素直な文脈依存構文言語として新しい仕様を作り直すのが賢明である。
294
+ Securemarkはスーパークラス構文が解析に失敗した入力をサブクラス構文で解析しないことにより再帰的バックトラックを回避する(解析中の構文自身はスーパークラスとサブクラスの両方に含まれるものとする)。スーパークラス構文A(`αAβ`)の解析が失敗すればサブクラス構文B(`α'A'β'`)の解析も失敗することは自明であり試みるまでもなく解析を省略できる。これは二つの構文の文法が生成する各言語空間がスーパーセットとサブセットの関係にあるならスーパーセットの言語空間の外にある文字列はサブセットの言語空間の内に入る余地がないことからも自明である(この解析法は事前処理によっても可能だが文脈内外のオートリンクURLの括弧解析などを高速に行うことは困難であるためMarkdownをこの事前処理により高速化することは難しい)。メモ化は解析結果を再利用することで結果的に副次的効果としてバックトラックを回避しているのでありメモ化はバックトラックを回避するだけなら過剰機能であり不要である(メモ化はバックトラックがなければ使用されないためバックトラックの少ないほとんどの入力に対してはほとんど使用されず無駄であり空間計算量を常に不必要に数倍以上に増加させてまで行う利益は少ないことから構文解析において必須でも標準でもない。バックトラック回避のためにメモ化するとバックトラックなしで解析可能な場合も常に不必要に空間計算量が増加することがメモ化の最大の欠点である(この問題は解析失敗時のみメモ化すれば解消可能のはずだが基本的にはこうなる)。特に文脈自由構文解析器におけるメモ化の使用は完全に無駄でありバグである。バックトラックが発生しないか他の方法で解決されるならば最終的に使用されないメモ化は無駄であり複数の文脈で解析結果が同一である文脈独立性のある構文ならメモ化した解析結果を異なる文脈で再利用でき有用だがそのような構文は基本的に少数であるため効果が限定的であり最悪計算量は改善されない)。この独自の解析法により、CommonMarkならば最悪計算量32n\*2^2+4n=132nを下らない拡張Markdown言語をSecuremarkはメモ化なしで7nの最悪時間計算量で解析している。すなわち直接比較してもCommonMarkの最悪計算量32nに対してSecuremarkは7nでありSecuremarkはCommonMarkより最悪計算量が非常に小さい。またSecuremarkはメモ化を行っていないため実装依存の非効率性を除けば空間計算量も小さい。時間計算量と空間計算量を合わせてO(n, n)と表記すると文脈依存言語の通常の最悪計算量はO(n^2, n)、メモ化により効率化できた場合もO(nm, nm)(S(m)>=m byte)(解析結果の構文木等を記録するため空間使用量S(m)>=m byte)に過ぎないがSecuremarkのマーキング法はO(nm, nm)(S(m)=m bit)(解析の失敗フラグしか記録しないためS(m)=m bit。また包含文字列を含め全体でn byteの構文1つに対してメモ化は少なくともn byteを消費するがマーキング法のメモリ消費量は構文全体のサイズにかかわらず1bit固定である。よって100KBの構文1つに対してメモ化は100KB以上消費するがこの場合もマーキング法は1bitしか消費しない。なお成功フラグによる解析は解析済みかの情報が追加で必要になり処理が複雑化かつほとんどの成功した解析に対してメモリ消費と追加処理が発生し解析効率が全体として悪化するが失敗フラグは少数の失敗した解析でしか解析効率が悪化しないため失敗フラグを記録するほうが全体として解析効率が高く優れている)と極めて効率的であり最も優れている。以上のようにSecuremarkの構文解析アルゴリズムの優位性は理論と実践いずれにおいても革新的かつ圧倒的である。現在のSecuremarkは開発効率と安全性優先の実装により実行性能が大きく低下しているが一定時間内で解析不能な入力の影響を解析時間と解析範囲の制限により局限しているため、最悪計算量で低速に動作させる入力に対してはこの実装をサーバーで使用し多数のユーザーのリクエストに応じるには低速で脆弱性となる可能性があるがクライアントで個別のユーザーの操作に応じるには十分高速であるためクライアントで解析する限り解析の効率または速度が実用上問題となることはなく仕様が固まり実行効率優先の高速な実装に移れば速度面の懸念もないだろう。またSecuremarkの再帰数制限はパーサーコンビネーターの使用による実装依存の制限であるため再帰が生じないよう書き換えれば再帰数制限もない。SecuremarkをCommonMarkのような再帰数制限のない実装に変換することは設計上何の支障もないがCommonMarkをSecuremarkのような正常な文脈依存言語解析器に変更することは解析規則の破壊的変更なしに不可能である。具体的には二重リンク`[[]()]()`を解析するときCommonMarkはバックトラックと計算量を最小化すべく文脈自由構文解析器として設計されているためリンク構文内をリンク構文が定義されていない異なる文脈として解析せず外側のリンク構文の解析を破棄して内側のみリンク構文として解析するがSecuremarkは文脈依存構文解析器とし設計されているためリンク構文内にリンク構文が定義されておらず外側のみリンクとして解析する(ここでCommonMarkはリンク構文`[]()`のバックトラック除去ひいては文脈自由化に角括弧`[]`に対しては成功したが丸括弧`()`に対しては失敗したことで最悪計算量が指数関数計算量ないし32nに悪化した。リンク構文を本来通り文脈依存構文として解析すればリンク構文の最悪計算量が2nとなり角括弧部分に限っては1nから2nに悪化するが丸括弧部分は32nから2nに著しく改善する。ここがCommonMarkの根本的な欠陥と失敗が最も明瞭に表出している部分である)。この問題はイメージ構文においてさらに顕著でありリンク構文と同じ問題が正当な表現`![![]()]()`で発生しさらにHTMLのaltはプレーンテキストとして表示されるためMarkdownのaltもプレーンテキストとしてそのまま表示されなければならないにもかかわらず文脈を一致させ再帰的バックトラックを防ぐためにMarkdown文字列として解析されaltに`*a*`と書かれたものを`a`に変換して表示する。無論新しい文脈依存構文を追加する場合も同じ制約が永遠についてまわり構文内文字列をMarkdownとして解析する文脈依存構文においてこの制約を破ると最悪計算量が2^m、より正確には32\*2^mないし32^mで指数関数的に増加する。すなわちCommonMarkは文脈依存構文を追加すると最悪計算量が32\*2^mないし32^mで指数関数的に悪化するという拡張性の致命的欠陥が存在する。こんな最悪計算量が32^mで組み合わせ爆発する欠陥言語を拡張できるわけがないことはもはや明白である。また多くのプログラミング言語を見ても明らかなように文脈依存言語は構文内で使用可能な構文を定義しその他の構文は構文内で使用できず例外処理するのが通常でありCommonMarkのように本来使用不能な構文を外側の構文を無効化して使用可能に変える異常な言語はほとんどの人間はCommonMark以外に見たことがないだろう。ほぼすべての人間において他のすべての言語が同じ一貫した規則を持ち同じ規則で統一的に使用できるのに対してCommonMarkだけが他と異なる異常な挙動をして認知的負荷をかけるのである。破壊的変更を避けるため旧構文だけ従来通り文脈自由構文として解析し新構文を文脈依存構文として解析すればキメラ的な非常に不自然かつ歪で一貫性のない解析規則によりCommonMarkという一つの言語の中だけでもユーザーを混乱させるものとなり旧構文で使用した苦肉の策を不必要に新構文でも使用して一貫させれば文脈依存言語なのに文脈自由言語の苦肉の策で解析されるこれもまたキメラ的な非常に不自然で理論的に設計ミスが明白で実用的にも認知的負荷の高い言語となる。そして構文エラーであることが明らかな二重リンクを意図的に入力することはほぼないためCommonMarkの異常な挙動はこれまであまり人目に付かなかったがMarkdownに文脈依存構文を追加して明らかでない構文エラーが頻発すると他の言語と逆に外側の構文を無効化していくCommonMarkの異常な挙動を頻繁に目撃し認知的負荷をかけられることになる。このようにCommonMarkは内部設計だけ文脈依存構文解析器に変更しても理論的齟齬が解析結果と使用感に明白に表れるためCommonMarkが失敗した言語である事実は到底隠し切れるものではない。Markdownはもはや負債以外の何物でもないCommonMarkの異常な解析規則を捨てて素直な文脈依存構文言語として新しい仕様を作り直すのが賢明である。
295
295
 
296
296
  ### 最適化
297
297
 
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- /*! securemark v0.289.5 https://github.com/falsandtru/securemark | (c) 2017, falsandtru | UNLICENSED License */
1
+ /*! securemark v0.289.6 https://github.com/falsandtru/securemark | (c) 2017, falsandtru | UNLICENSED License */
2
2
  (function webpackUniversalModuleDefinition(root, factory) {
3
3
  if(typeof exports === 'object' && typeof module === 'object')
4
4
  module.exports = factory(require("Prism"), require("DOMPurify"));
@@ -3177,7 +3177,7 @@ Object.defineProperty(exports, "__esModule", ({
3177
3177
  exports.setBacktrack = exports.getBacktrack = exports.close = exports.open = exports.surround = void 0;
3178
3178
  const parser_1 = __webpack_require__(605);
3179
3179
  const array_1 = __webpack_require__(6876);
3180
- function surround(opener, parser, closer, optional = false, f, g, backtracks = [], backtrackstate = 0) {
3180
+ function surround(opener, parser, closer, optional = false, f, g, backtracks = []) {
3181
3181
  switch (typeof opener) {
3182
3182
  case 'string':
3183
3183
  case 'object':
@@ -3205,16 +3205,11 @@ function surround(opener, parser, closer, optional = false, f, g, backtracks = [
3205
3205
  if (resultS === undefined) return void revert(context, linebreak);
3206
3206
  const nodesS = (0, parser_1.eval)(resultS);
3207
3207
  const me_ = (0, parser_1.exec)(resultS);
3208
- if (getBacktrack(context, backtracks, sme_, me_)) return void revert(context, linebreak);
3209
- const {
3210
- backtrack = 0
3211
- } = context;
3212
- context.backtrack = backtrack | backtrackstate;
3208
+ if (getBacktrack(context, backtracks, sme_, sme_.length - me_.length)) return void revert(context, linebreak);
3213
3209
  const resultM = me_ !== '' ? parser({
3214
3210
  source: me_,
3215
3211
  context
3216
3212
  }) : undefined;
3217
- context.backtrack = backtrack;
3218
3213
  const nodesM = (0, parser_1.eval)(resultM);
3219
3214
  const e_ = (0, parser_1.exec)(resultM, me_);
3220
3215
  const resultE = nodesM || optional ? closer({
@@ -3223,7 +3218,7 @@ function surround(opener, parser, closer, optional = false, f, g, backtracks = [
3223
3218
  }) : undefined;
3224
3219
  const nodesE = (0, parser_1.eval)(resultE);
3225
3220
  const rest = (0, parser_1.exec)(resultE, e_);
3226
- nodesE || setBacktrack(context, backtracks, sme_);
3221
+ nodesE || setBacktrack(context, backtracks, sme_.length);
3227
3222
  if (!nodesM && !optional) return void revert(context, linebreak);
3228
3223
  if (rest.length === sme_.length) return void revert(context, linebreak);
3229
3224
  context.recent = [sme_.slice(0, sme_.length - me_.length), me_.slice(0, me_.length - e_.length), e_.slice(0, e_.length - rest.length)];
@@ -3237,46 +3232,44 @@ function surround(opener, parser, closer, optional = false, f, g, backtracks = [
3237
3232
  };
3238
3233
  }
3239
3234
  exports.surround = surround;
3240
- function open(opener, parser, optional, backtracks, backtrackstate) {
3241
- return surround(opener, parser, '', optional, undefined, undefined, backtracks, backtrackstate);
3235
+ function open(opener, parser, optional, backtracks) {
3236
+ return surround(opener, parser, '', optional, undefined, undefined, backtracks);
3242
3237
  }
3243
3238
  exports.open = open;
3244
- function close(parser, closer, optional, backtracks, backtrackstate) {
3245
- return surround('', parser, closer, optional, undefined, undefined, backtracks, backtrackstate);
3239
+ function close(parser, closer, optional, backtracks) {
3240
+ return surround('', parser, closer, optional, undefined, undefined, backtracks);
3246
3241
  }
3247
3242
  exports.close = close;
3248
3243
  const statesize = 2;
3249
- function getBacktrack(context, backtracks, sme_, me_) {
3244
+ function getBacktrack(context, backtracks, source, length) {
3250
3245
  for (const backtrack of backtracks) {
3251
3246
  if (backtrack & 1) {
3252
3247
  const {
3253
3248
  backtracks = {},
3254
- backtrack: state = 0,
3255
3249
  offset = 0
3256
3250
  } = context;
3257
- for (let i = 0, len = sme_.length - me_.length || 1; i < len; ++i) {
3258
- if (sme_[i] !== sme_[0]) break;
3259
- const pos = sme_.length - i + offset - 1;
3251
+ for (let i = 0; i < length; ++i) {
3252
+ if (source[i] !== source[0]) break;
3253
+ const pos = source.length - i + offset - 1;
3260
3254
  if (!(pos in backtracks)) continue;
3261
- const shift = backtrack >>> statesize & state >>> statesize ? state & (1 << statesize) - 1 : 0;
3262
- if (backtracks[pos] & 1 << size(backtrack >>> statesize) + shift) return true;
3255
+ if (backtracks[pos] & 1 << size(backtrack >>> statesize)) return true;
3263
3256
  }
3264
3257
  }
3265
3258
  }
3266
3259
  return false;
3267
3260
  }
3268
3261
  exports.getBacktrack = getBacktrack;
3269
- function setBacktrack(context, backtracks, sme_) {
3262
+ function setBacktrack(context, backtracks, position, length = 1) {
3270
3263
  for (const backtrack of backtracks) {
3271
3264
  if (backtrack & 2) {
3272
3265
  const {
3273
3266
  backtracks = {},
3274
- backtrack: state = 0,
3275
3267
  offset = 0
3276
3268
  } = context;
3277
- const pos = sme_.length + offset - 1;
3278
- const shift = backtrack >>> statesize & state >>> statesize ? state & (1 << statesize) - 1 : 0;
3279
- backtracks[pos] |= 1 << size(backtrack >>> statesize) + shift;
3269
+ for (let i = 0; i < length; ++i) {
3270
+ const pos = position - i + offset - 1;
3271
+ backtracks[pos] |= 1 << size(backtrack >>> statesize);
3272
+ }
3280
3273
  }
3281
3274
  }
3282
3275
  }
@@ -3358,6 +3351,7 @@ function bind(parser, f) {
3358
3351
  if (source === '') return;
3359
3352
  const res1 = parser(input);
3360
3353
  if (res1 === undefined) return;
3354
+ context.recent = [source.slice(0, source.length - (0, parser_1.exec)(res1).length)];
3361
3355
  const res2 = f((0, parser_1.eval)(res1), (0, parser_1.exec)(res1), context);
3362
3356
  if (res2 === undefined) return;
3363
3357
  return (0, parser_1.exec)(res2).length <= (0, parser_1.exec)(res1).length ? res2 : undefined;
@@ -5950,9 +5944,9 @@ const combinator_1 = __webpack_require__(3484);
5950
5944
  const inline_1 = __webpack_require__(7973);
5951
5945
  const visibility_1 = __webpack_require__(6364);
5952
5946
  const dom_1 = __webpack_require__(394);
5953
- exports.annotation = (0, combinator_1.lazy)(() => (0, combinator_1.constraint)(128 /* State.annotation */, false, (0, combinator_1.surround)('((', (0, combinator_1.precedence)(1, (0, combinator_1.state)(128 /* State.annotation */ | 4 /* State.media */, (0, visibility_1.trimBlankStart)((0, combinator_1.some)((0, combinator_1.union)([inline_1.inline]), ')', [['\n', 9], [')', 1]])))), '))', false, ([, ns], rest) => (0, visibility_1.trimBlankNodeEnd)(ns).length > 0 ? [[(0, dom_1.html)('sup', {
5947
+ exports.annotation = (0, combinator_1.lazy)(() => (0, combinator_1.constraint)(128 /* State.annotation */, false, (0, combinator_1.surround)('((', (0, combinator_1.precedence)(1, (0, combinator_1.state)(128 /* State.annotation */ | 4 /* State.media */, (0, visibility_1.trimBlankStart)((0, combinator_1.some)((0, combinator_1.union)([inline_1.inline]), ')', [[')', 1]])))), '))', false, ([, ns], rest, context) => context.linebreak === undefined && (0, visibility_1.trimBlankNodeEnd)(ns).length > 0 ? [[(0, dom_1.html)('sup', {
5954
5948
  class: 'annotation'
5955
- }, [(0, dom_1.html)('span', (0, dom_1.defrag)(ns))])], rest] : undefined, undefined, [3 | 32 /* Backtrack.linedoublebracket */, 1 | 16 /* Backtrack.linebracket */], 8 /* Backtrack.bracket */ | 1 /* BacktrackState.nobreak */)));
5949
+ }, [(0, dom_1.html)('span', (0, dom_1.defrag)(ns))])], rest] : undefined, undefined, [3 | 16 /* Backtrack.doublebracket */, 1 | 8 /* Backtrack.bracket */])));
5956
5950
 
5957
5951
  /***/ },
5958
5952
 
@@ -6083,7 +6077,7 @@ const combinator_1 = __webpack_require__(3484);
6083
6077
  const source_1 = __webpack_require__(8745);
6084
6078
  const dom_1 = __webpack_require__(394);
6085
6079
  // https://html.spec.whatwg.org/multipage/input.html
6086
- exports.email = (0, combinator_1.rewrite)((0, combinator_1.verify)((0, source_1.str)(/^[0-9a-z](?:[_.+-](?=[0-9a-z])|[0-9a-z]){0,255}@[0-9a-z](?:(?:[0-9a-z]|-(?=[0-9a-z])){0,61}[0-9a-z])?(?:\.[0-9a-z](?:(?:[0-9a-z]|-(?=[0-9a-z])){0,61}[0-9a-z])?)*(?![0-9a-z])/i), ([source]) => source.length <= 255), (0, combinator_1.union)([(0, combinator_1.constraint)(1 /* State.autolink */, false, (0, combinator_1.state)(1 /* State.autolink */, ({
6080
+ exports.email = (0, combinator_1.rewrite)((0, combinator_1.surround)((0, source_1.str)(/^[0-9a-z]/i), (0, combinator_1.verify)((0, source_1.str)(/^(?:[_.+-](?=[0-9a-z])|[0-9a-z]){0,255}@[0-9a-z](?:(?:[0-9a-z]|-(?=[0-9a-z])){0,61}[0-9a-z])?(?:\.[0-9a-z](?:(?:[0-9a-z]|-(?=[0-9a-z])){0,61}[0-9a-z])?)*(?![0-9a-z])/i), ([source]) => source.length <= 255 - 1), '', false, undefined, undefined, [3 | 0 /* Backtrack.autolink */]), (0, combinator_1.union)([(0, combinator_1.constraint)(1 /* State.autolink */, false, (0, combinator_1.state)(1 /* State.autolink */, ({
6087
6081
  source
6088
6082
  }) => [[(0, dom_1.html)('a', {
6089
6083
  class: 'email',
@@ -6135,7 +6129,7 @@ const dom_1 = __webpack_require__(394);
6135
6129
  // https://example/hashtags/a must be a hashtag page or a redirect page going there.
6136
6130
  // https://github.com/tc39/proposal-regexp-unicode-property-escapes#matching-emoji
6137
6131
  exports.emoji = String.raw`\p{Emoji_Modifier_Base}\p{Emoji_Modifier}?|\p{Emoji_Presentation}|\p{Emoji}\uFE0F`;
6138
- exports.hashtag = (0, combinator_1.lazy)(() => (0, combinator_1.rewrite)((0, combinator_1.open)('#', (0, source_1.str)(new RegExp([/^(?!['_])(?=(?:[0-9]{1,9})?(?:[^\d\p{C}\p{S}\p{P}\s]|emoji|'(?=[0-9A-Za-z])|_(?=[^'\p{C}\p{S}\p{P}\s]|emoji)))/u.source, /(?:[^\p{C}\p{S}\p{P}\s]|emoji|'(?=[0-9A-Za-z])|_(?=[^'\p{C}\p{S}\p{P}\s]|emoji))+/u.source].join('').replace(/emoji/g, exports.emoji), 'u'))), (0, combinator_1.union)([(0, combinator_1.constraint)(1 /* State.autolink */, false, (0, combinator_1.state)(1 /* State.autolink */, (0, combinator_1.fmap)((0, combinator_1.convert)(source => `[${source}]{ ${`/hashtags/${source.slice(1)}`} }`, link_1.unsafelink, false), ([el]) => [(0, dom_1.define)(el, {
6132
+ exports.hashtag = (0, combinator_1.lazy)(() => (0, combinator_1.rewrite)((0, combinator_1.open)('#', (0, source_1.str)(new RegExp([/^(?!['_])(?=(?:[0-9]{1,9})?(?:[^\d\p{C}\p{S}\p{P}\s]|emoji|'(?=[0-9A-Za-z])|_(?=[^'\p{C}\p{S}\p{P}\s]|emoji)))/u.source, /(?:[^\p{C}\p{S}\p{P}\s]|emoji|'(?=[0-9A-Za-z])|_(?=[^'\p{C}\p{S}\p{P}\s]|emoji))+/u.source].join('').replace(/emoji/g, exports.emoji), 'u')), false, [3 | 0 /* Backtrack.autolink */]), (0, combinator_1.union)([(0, combinator_1.constraint)(1 /* State.autolink */, false, (0, combinator_1.state)(1 /* State.autolink */, (0, combinator_1.fmap)((0, combinator_1.convert)(source => `[${source}]{ ${`/hashtags/${source.slice(1)}`} }`, link_1.unsafelink, false), ([el]) => [(0, dom_1.define)(el, {
6139
6133
  class: 'hashtag'
6140
6134
  })]))), ({
6141
6135
  source
@@ -6157,13 +6151,13 @@ const combinator_1 = __webpack_require__(3484);
6157
6151
  const link_1 = __webpack_require__(3628);
6158
6152
  const source_1 = __webpack_require__(8745);
6159
6153
  const closer = /^[-+*=~^_,.;:!?]*(?=[\\"`|\[\](){}<>]|[^\x21-\x7E]|$)/;
6160
- exports.url = (0, combinator_1.lazy)(() => (0, combinator_1.validate)(['http://', 'https://'], (0, combinator_1.rewrite)((0, combinator_1.open)(/^https?:\/\/(?=[\x21-\x7E])/, (0, combinator_1.precedence)(1, (0, combinator_1.some)((0, combinator_1.union)([(0, combinator_1.verify)(bracket, ns => ns.length > 0), (0, combinator_1.some)(source_1.unescsource, closer)]), undefined, [[/^[^\x21-\x7E]/, 3]])), false, [3 | 0 /* Backtrack.url */]), (0, combinator_1.union)([(0, combinator_1.constraint)(1 /* State.autolink */, false, (0, combinator_1.state)(1 /* State.autolink */, (0, combinator_1.convert)(url => `{ ${url} }`, link_1.unsafelink, false))), ({
6154
+ exports.url = (0, combinator_1.lazy)(() => (0, combinator_1.validate)(['http://', 'https://'], (0, combinator_1.rewrite)((0, combinator_1.open)(/^https?:\/\/(?=[\x21-\x7E])/, (0, combinator_1.precedence)(1, (0, combinator_1.some)((0, combinator_1.union)([(0, combinator_1.verify)(bracket, ns => ns.length > 0), (0, combinator_1.some)(source_1.unescsource, closer)]), undefined, [[/^[^\x21-\x7E]/, 3]])), false, [3 | 0 /* Backtrack.autolink */]), (0, combinator_1.union)([(0, combinator_1.constraint)(1 /* State.autolink */, false, (0, combinator_1.state)(1 /* State.autolink */, (0, combinator_1.convert)(url => `{ ${url} }`, link_1.unsafelink, false))), ({
6161
6155
  source
6162
6156
  }) => [[source], '']]))));
6163
6157
  exports.lineurl = (0, combinator_1.lazy)(() => (0, combinator_1.open)(source_1.linebreak, (0, combinator_1.focus)(/^!?https?:\/\/\S+(?=[^\S\n]*(?:$|\n))/, (0, combinator_1.tails)([(0, source_1.str)('!'), (0, combinator_1.union)([(0, combinator_1.constraint)(1 /* State.autolink */, false, (0, combinator_1.state)(1 /* State.autolink */, (0, combinator_1.convert)(url => `{ ${url} }`, link_1.unsafelink, false))), ({
6164
6158
  source
6165
- }) => [[source], '']])])), false, [3 | 16 /* Backtrack.linebracket */]));
6166
- const bracket = (0, combinator_1.lazy)(() => (0, combinator_1.union)([(0, combinator_1.surround)((0, source_1.str)('('), (0, combinator_1.recursion)(6 /* Recursion.terminal */, (0, combinator_1.some)((0, combinator_1.union)([bracket, source_1.unescsource]), ')')), (0, source_1.str)(')'), true, undefined, () => [[], ''], [3 | 0 /* Backtrack.url */]), (0, combinator_1.surround)((0, source_1.str)('['), (0, combinator_1.recursion)(6 /* Recursion.terminal */, (0, combinator_1.some)((0, combinator_1.union)([bracket, source_1.unescsource]), ']')), (0, source_1.str)(']'), true, undefined, () => [[], ''], [3 | 0 /* Backtrack.url */]), (0, combinator_1.surround)((0, source_1.str)('{'), (0, combinator_1.recursion)(6 /* Recursion.terminal */, (0, combinator_1.some)((0, combinator_1.union)([bracket, source_1.unescsource]), '}')), (0, source_1.str)('}'), true, undefined, () => [[], ''], [3 | 0 /* Backtrack.url */]), (0, combinator_1.surround)((0, source_1.str)('"'), (0, combinator_1.precedence)(2, (0, combinator_1.recursion)(6 /* Recursion.terminal */, (0, combinator_1.some)(source_1.unescsource, '"'))), (0, source_1.str)('"'), true, undefined, () => [[], ''], [3 | 0 /* Backtrack.url */])]));
6159
+ }) => [[source], '']])])), false, [3 | 0 /* Backtrack.autolink */]));
6160
+ const bracket = (0, combinator_1.lazy)(() => (0, combinator_1.union)([(0, combinator_1.surround)((0, source_1.str)('('), (0, combinator_1.recursion)(6 /* Recursion.terminal */, (0, combinator_1.some)((0, combinator_1.union)([bracket, source_1.unescsource]), ')')), (0, source_1.str)(')'), true, undefined, () => [[], ''], [3 | 0 /* Backtrack.autolink */]), (0, combinator_1.surround)((0, source_1.str)('['), (0, combinator_1.recursion)(6 /* Recursion.terminal */, (0, combinator_1.some)((0, combinator_1.union)([bracket, source_1.unescsource]), ']')), (0, source_1.str)(']'), true, undefined, () => [[], ''], [3 | 0 /* Backtrack.autolink */]), (0, combinator_1.surround)((0, source_1.str)('{'), (0, combinator_1.recursion)(6 /* Recursion.terminal */, (0, combinator_1.some)((0, combinator_1.union)([bracket, source_1.unescsource]), '}')), (0, source_1.str)('}'), true, undefined, () => [[], ''], [3 | 0 /* Backtrack.autolink */]), (0, combinator_1.surround)((0, source_1.str)('"'), (0, combinator_1.precedence)(2, (0, combinator_1.recursion)(6 /* Recursion.terminal */, (0, combinator_1.some)(source_1.unescsource, '"'))), (0, source_1.str)('"'), true, undefined, () => [[], ''], [3 | 0 /* Backtrack.autolink */])]));
6167
6161
 
6168
6162
  /***/ },
6169
6163
 
@@ -6215,12 +6209,12 @@ const dom_1 = __webpack_require__(394);
6215
6209
  exports.code = (0, combinator_1.validate)(({
6216
6210
  source,
6217
6211
  context
6218
- }) => source[0] === '`' && !(0, combinator_1.getBacktrack)(context, [1 | 16 /* Backtrack.linebracket */], source, source.slice(1)), (0, combinator_1.match)(/^(`+)(?!`)([^\n]*?)(?:((?<!`)\1(?!`))|$|\n)/, ([whole,, body, closer]) => ({
6212
+ }) => source[0] === '`' && !(0, combinator_1.getBacktrack)(context, [1 | 8 /* Backtrack.bracket */], source, source.length - 1), (0, combinator_1.match)(/^(`+)(?!`)([^\n]*?)(?:((?<!`)\1(?!`))|$|\n)/, ([whole,, body, closer]) => ({
6219
6213
  source,
6220
6214
  context
6221
6215
  }) => closer ? [[(0, dom_1.html)('code', {
6222
6216
  'data-src': whole
6223
- }, format(body))], source.slice(whole.length)] : void (0, combinator_1.setBacktrack)(context, [2 | 16 /* Backtrack.linebracket */], source), true));
6217
+ }, format(body))], source.slice(whole.length)] : void (0, combinator_1.setBacktrack)(context, [2 | 8 /* Backtrack.bracket */], source.length), true));
6224
6218
  function format(text) {
6225
6219
  return `${text[0]}${text.at(-1)}` === ' ' && text.trimStart() ? text.slice(1, -1) : text;
6226
6220
  }
@@ -6379,9 +6373,9 @@ const source_1 = __webpack_require__(8745);
6379
6373
  const visibility_1 = __webpack_require__(6364);
6380
6374
  const array_1 = __webpack_require__(6876);
6381
6375
  const dom_1 = __webpack_require__(394);
6382
- exports.index = (0, combinator_1.lazy)(() => (0, combinator_1.constraint)(32 /* State.index */, false, (0, combinator_1.fmap)((0, indexee_1.indexee)((0, combinator_1.surround)('[#', (0, combinator_1.precedence)(1, (0, combinator_1.state)(251 /* State.linkers */ | 4 /* State.media */, (0, visibility_1.tightStart)((0, combinator_1.some)((0, combinator_1.inits)([inline_1.inline, exports.signature]), ']', [['\n', 9], [']', 1]])))), ']', false, ([, ns], rest) => (0, visibility_1.trimBlankNodeEnd)(ns).length > 0 ? [[(0, dom_1.html)('a', {
6376
+ exports.index = (0, combinator_1.lazy)(() => (0, combinator_1.constraint)(32 /* State.index */, false, (0, combinator_1.fmap)((0, indexee_1.indexee)((0, combinator_1.surround)('[#', (0, combinator_1.precedence)(1, (0, combinator_1.state)(251 /* State.linkers */ | 4 /* State.media */, (0, visibility_1.tightStart)((0, combinator_1.some)((0, combinator_1.inits)([inline_1.inline, exports.signature]), ']', [[']', 1]])))), ']', false, ([, ns], rest, context) => context.linebreak === undefined && (0, visibility_1.trimBlankNodeEnd)(ns).length > 0 ? [[(0, dom_1.html)('a', {
6383
6377
  'data-index': dataindex(ns)
6384
- }, (0, dom_1.defrag)(ns))], rest] : undefined, undefined, [3 | 16 /* Backtrack.linebracket */], 8 /* Backtrack.bracket */ | 1 /* BacktrackState.nobreak */)), ([el]) => [(0, dom_1.define)(el, {
6378
+ }, (0, dom_1.defrag)(ns))], rest] : undefined, undefined, [3 | 8 /* Backtrack.bracket */])), ([el]) => [(0, dom_1.define)(el, {
6385
6379
  id: el.id ? null : undefined,
6386
6380
  class: 'index',
6387
6381
  href: el.id ? `#${el.id}` : undefined
@@ -6591,7 +6585,7 @@ const source_1 = __webpack_require__(8745);
6591
6585
  const dom_1 = __webpack_require__(394);
6592
6586
  const body = (0, source_1.str)(/^\$[A-Za-z]*(?:(?:-[A-Za-z][0-9A-Za-z]*)+|-(?:(?:0|[1-9][0-9]*)\.)*(?:0|[1-9][0-9]*)(?![0-9A-Za-z]))/);
6593
6587
  exports.segment = (0, combinator_1.clear)((0, combinator_1.union)([(0, combinator_1.surround)('[', body, ']'), body]));
6594
- exports.label = (0, combinator_1.constraint)(16 /* State.label */, false, (0, combinator_1.fmap)((0, combinator_1.union)([(0, combinator_1.surround)('[', body, ']', false, undefined, undefined, [1 | 16 /* Backtrack.linebracket */, 1]), body]), ([text]) => [(0, dom_1.html)('a', {
6588
+ exports.label = (0, combinator_1.constraint)(16 /* State.label */, false, (0, combinator_1.fmap)((0, combinator_1.union)([(0, combinator_1.surround)('[', body, ']', false, undefined, undefined, [1 | 8 /* Backtrack.bracket */, 1]), body]), ([text]) => [(0, dom_1.html)('a', {
6595
6589
  class: 'label',
6596
6590
  'data-label': text.slice(text[1] === '-' ? 0 : 1).toLowerCase()
6597
6591
  }, text)]));
@@ -6670,7 +6664,7 @@ Object.setPrototypeOf(attrspecs, null);
6670
6664
  Object.values(attrspecs).forEach(o => Object.setPrototypeOf(o, null));
6671
6665
  exports.html = (0, combinator_1.lazy)(() => (0, combinator_1.validate)(/^<[a-z]+(?=[^\S\n]|>)/i, (0, combinator_1.union)([(0, combinator_1.focus)(/^<wbr[^\S\n]*>/i, () => [[(0, dom_1.html)('wbr')], '']), (0, combinator_1.surround)(
6672
6666
  // https://html.spec.whatwg.org/multipage/syntax.html#void-elements
6673
- (0, source_1.str)(/^<(?:area|base|br|col|embed|hr|img|input|link|meta|source|track|wbr)(?=[^\S\n]|>)/i), (0, combinator_1.some)((0, combinator_1.union)([exports.attribute])), (0, source_1.str)(/^[^\S\n]*>/), true, ([as, bs = [], cs], rest) => [[elem(as[0].slice(1), (0, array_1.push)((0, array_1.unshift)(as, bs), cs), [], [])], rest], undefined, [3 | 16 /* Backtrack.linebracket */]), (0, combinator_1.match)(new RegExp(String.raw`^<(${TAGS.join('|')})(?=[^\S\n]|>)`), (0, memoize_1.memoize)(([, tag]) => (0, combinator_1.surround)((0, combinator_1.surround)((0, source_1.str)(`<${tag}`), (0, combinator_1.some)(exports.attribute), (0, source_1.str)(/^[^\S\n]*>/), true, undefined, undefined, [3 | 16 /* Backtrack.linebracket */]), (0, combinator_1.precedence)(3, (0, combinator_1.recursion)(4 /* Recursion.inline */, (0, combinator_1.subsequence)([(0, combinator_1.focus)(/^[^\S\n]*\n/, (0, combinator_1.some)(inline_1.inline)), (0, combinator_1.some)((0, combinator_1.open)(/^\n?/, (0, combinator_1.some)(inline_1.inline, (0, visibility_1.blankWith)('\n', `</${tag}>`), [[(0, visibility_1.blankWith)('\n', `</${tag}>`), 3]]), true))]))), (0, source_1.str)(`</${tag}>`), true, ([as, bs = [], cs], rest) => [[elem(tag, as, bs, cs)], rest], ([as, bs = []], rest) => [[elem(tag, as, bs, [])], rest]), ([, tag]) => tag, new Map())), (0, combinator_1.match)(/^<([a-z]+)(?=[^\S\n]|>)/i, (0, memoize_1.memoize)(([, tag]) => (0, combinator_1.surround)((0, combinator_1.surround)((0, source_1.str)(`<${tag}`), (0, combinator_1.some)(exports.attribute), (0, source_1.str)(/^[^\S\n]*>/), true, undefined, undefined, [3 | 16 /* Backtrack.linebracket */]), (0, combinator_1.precedence)(3, (0, combinator_1.recursion)(4 /* Recursion.inline */, (0, combinator_1.subsequence)([(0, combinator_1.focus)(/^[^\S\n]*\n/, (0, combinator_1.some)(inline_1.inline)), (0, combinator_1.some)(inline_1.inline, `</${tag}>`, [[`</${tag}>`, 3]])]))), (0, source_1.str)(`</${tag}>`), true, ([as, bs = [], cs], rest) => [[elem(tag, as, bs, cs)], rest], ([as, bs = []], rest) => [[elem(tag, as, bs, [])], rest]), ([, tag]) => tag, new clock_1.Clock(10000)))])));
6667
+ (0, source_1.str)(/^<(?:area|base|br|col|embed|hr|img|input|link|meta|source|track|wbr)(?=[^\S\n]|>)/i), (0, combinator_1.some)((0, combinator_1.union)([exports.attribute])), (0, source_1.str)(/^[^\S\n]*>/), true, ([as, bs = [], cs], rest) => [[elem(as[0].slice(1), (0, array_1.push)((0, array_1.unshift)(as, bs), cs), [], [])], rest], undefined, [3 | 8 /* Backtrack.bracket */]), (0, combinator_1.match)(new RegExp(String.raw`^<(${TAGS.join('|')})(?=[^\S\n]|>)`), (0, memoize_1.memoize)(([, tag]) => (0, combinator_1.surround)((0, combinator_1.surround)((0, source_1.str)(`<${tag}`), (0, combinator_1.some)(exports.attribute), (0, source_1.str)(/^[^\S\n]*>/), true, undefined, undefined, [3 | 8 /* Backtrack.bracket */]), (0, combinator_1.precedence)(3, (0, combinator_1.recursion)(4 /* Recursion.inline */, (0, combinator_1.subsequence)([(0, combinator_1.focus)(/^[^\S\n]*\n/, (0, combinator_1.some)(inline_1.inline)), (0, combinator_1.some)((0, combinator_1.open)(/^\n?/, (0, combinator_1.some)(inline_1.inline, (0, visibility_1.blankWith)('\n', `</${tag}>`), [[(0, visibility_1.blankWith)('\n', `</${tag}>`), 3]]), true))]))), (0, source_1.str)(`</${tag}>`), true, ([as, bs = [], cs], rest) => [[elem(tag, as, bs, cs)], rest], ([as, bs = []], rest) => [[elem(tag, as, bs, [])], rest]), ([, tag]) => tag, new Map())), (0, combinator_1.match)(/^<([a-z]+)(?=[^\S\n]|>)/i, (0, memoize_1.memoize)(([, tag]) => (0, combinator_1.surround)((0, combinator_1.surround)((0, source_1.str)(`<${tag}`), (0, combinator_1.some)(exports.attribute), (0, source_1.str)(/^[^\S\n]*>/), true, undefined, undefined, [3 | 8 /* Backtrack.bracket */]), (0, combinator_1.precedence)(3, (0, combinator_1.recursion)(4 /* Recursion.inline */, (0, combinator_1.subsequence)([(0, combinator_1.focus)(/^[^\S\n]*\n/, (0, combinator_1.some)(inline_1.inline)), (0, combinator_1.some)(inline_1.inline, `</${tag}>`, [[`</${tag}>`, 3]])]))), (0, source_1.str)(`</${tag}>`), true, ([as, bs = [], cs], rest) => [[elem(tag, as, bs, cs)], rest], ([as, bs = []], rest) => [[elem(tag, as, bs, [])], rest]), ([, tag]) => tag, new clock_1.Clock(10000)))])));
6674
6668
  exports.attribute = (0, combinator_1.union)([(0, source_1.str)(/^[^\S\n]+[a-z]+(?:-[a-z]+)*(?:="[^"\n]*")?(?=[^\S\n]|>)/i)]);
6675
6669
  // https://developer.mozilla.org/en-US/docs/Web/HTML/Element
6676
6670
  // [...document.querySelectorAll('tbody > tr > td:first-child')].map(el => el.textContent.slice(1, -1))
@@ -6802,12 +6796,22 @@ const source_1 = __webpack_require__(8745);
6802
6796
  const visibility_1 = __webpack_require__(6364);
6803
6797
  const util_1 = __webpack_require__(4992);
6804
6798
  const url_1 = __webpack_require__(1904);
6799
+ const array_1 = __webpack_require__(6876);
6805
6800
  const dom_1 = __webpack_require__(394);
6806
6801
  const optspec = {
6807
6802
  rel: ['nofollow']
6808
6803
  };
6809
6804
  Object.setPrototypeOf(optspec, null);
6810
- exports.textlink = (0, combinator_1.lazy)(() => (0, combinator_1.constraint)(8 /* State.link */, false, (0, combinator_1.creation)(10, (0, combinator_1.precedence)(1, (0, combinator_1.state)(251 /* State.linkers */ | 4 /* State.media */, (0, combinator_1.bind)((0, combinator_1.reverse)((0, combinator_1.tails)([(0, combinator_1.dup)((0, combinator_1.surround)('[', (0, visibility_1.trimBlankStart)((0, combinator_1.some)((0, combinator_1.union)([inline_1.inline]), ']', [['\n', 9], [']', 1]])), ']', true, undefined, undefined, [1 | 16 /* Backtrack.linebracket */], 8 /* Backtrack.bracket */ | 1 /* BacktrackState.nobreak */)), (0, combinator_1.dup)((0, combinator_1.surround)(/^{(?![{}])/, (0, combinator_1.inits)([exports.uri, (0, combinator_1.some)(exports.option)]), /^[^\S\n]*}/, false, undefined, undefined, [3 | 128 /* Backtrack.link */]))])), ([params, content = []], rest, context) => {
6805
+ exports.textlink = (0, combinator_1.lazy)(() => (0, combinator_1.constraint)(8 /* State.link */, false, (0, combinator_1.creation)(10, (0, combinator_1.precedence)(1, (0, combinator_1.state)(251 /* State.linkers */ | 4 /* State.media */, (0, combinator_1.bind)((0, combinator_1.subsequence)([(0, combinator_1.dup)((0, combinator_1.surround)('[', (0, visibility_1.trimBlankStart)((0, combinator_1.some)((0, combinator_1.union)([inline_1.inline]), ']', [[']', 1]])), ']', true, ([, ns = []], rest, context) => context.linebreak === undefined ? [(0, array_1.push)(ns, ["\u001B" /* Command.Escape */]), rest] : undefined, undefined, [3 | 64 /* Backtrack.link */, 3 | 8 /* Backtrack.bracket */])), (0, combinator_1.dup)((0, combinator_1.surround)(/^{(?![{}])/, (0, combinator_1.inits)([exports.uri, (0, combinator_1.some)(exports.option)]), /^[^\S\n]*}/, false, undefined, undefined, [3 | 64 /* Backtrack.link */]))]), ([content, params], rest, context) => {
6806
+ if (content.at(-1) === "\u001B" /* Command.Escape */) {
6807
+ content.pop();
6808
+ if (params === undefined) {
6809
+ return void (0, combinator_1.setBacktrack)(context, [2 | 64 /* Backtrack.link */], context.recent.reduce((a, b) => a + b.length, 0));
6810
+ }
6811
+ } else {
6812
+ params = content;
6813
+ content = [];
6814
+ }
6811
6815
  if (content.length !== 0 && (0, visibility_1.trimBlankNodeEnd)(content).length === 0) return;
6812
6816
  return [[parse((0, dom_1.defrag)(content), params, context)], rest];
6813
6817
  }))))));
@@ -6990,7 +6994,7 @@ const optspec = {
6990
6994
  rel: undefined
6991
6995
  };
6992
6996
  Object.setPrototypeOf(optspec, null);
6993
- exports.media = (0, combinator_1.lazy)(() => (0, combinator_1.constraint)(4 /* State.media */, false, (0, combinator_1.validate)(['![', '!{'], (0, combinator_1.creation)(10, (0, combinator_1.open)('!', (0, combinator_1.bind)((0, combinator_1.verify)((0, combinator_1.fmap)((0, combinator_1.tails)([(0, combinator_1.dup)((0, combinator_1.surround)('[', (0, combinator_1.precedence)(1, (0, combinator_1.some)((0, combinator_1.union)([htmlentity_1.unsafehtmlentity, bracket, source_1.txt]), ']', [['\n', 9]])), ']', true, undefined, undefined, [3 | 4 /* Backtrack.lineescbracket */])), (0, combinator_1.dup)((0, combinator_1.surround)(/^{(?![{}])/, (0, combinator_1.inits)([link_1.uri, (0, combinator_1.some)(option)]), /^[^\S\n]*}/, false, undefined, undefined, [3 | 128 /* Backtrack.link */]))]), ([as, bs]) => bs ? [[as.join('').trim() || as.join('')], bs] : [[''], as]), ([[text]]) => text === '' || text.trim() !== ''), ([[text], params], rest, context) => {
6997
+ exports.media = (0, combinator_1.lazy)(() => (0, combinator_1.constraint)(4 /* State.media */, false, (0, combinator_1.validate)(['![', '!{'], (0, combinator_1.creation)(10, (0, combinator_1.open)('!', (0, combinator_1.bind)((0, combinator_1.verify)((0, combinator_1.fmap)((0, combinator_1.tails)([(0, combinator_1.dup)((0, combinator_1.surround)('[', (0, combinator_1.precedence)(1, (0, combinator_1.some)((0, combinator_1.union)([htmlentity_1.unsafehtmlentity, bracket, source_1.txt]), ']')), ']', true, ([, ns = []], rest, context) => context.linebreak === undefined ? [ns, rest] : undefined, undefined, [3 | 4 /* Backtrack.escbracket */])), (0, combinator_1.dup)((0, combinator_1.surround)(/^{(?![{}])/, (0, combinator_1.inits)([link_1.uri, (0, combinator_1.some)(option)]), /^[^\S\n]*}/, false, undefined, undefined, [3 | 64 /* Backtrack.link */]))]), ([as, bs]) => bs ? [[as.join('').trim() || as.join('')], bs] : [[''], as]), ([[text]]) => text === '' || text.trim() !== ''), ([[text], params], rest, context) => {
6994
6998
  const INSECURE_URI = params.shift();
6995
6999
  const url = new url_1.ReadonlyURL((0, link_1.resolve)(INSECURE_URI, context.host ?? location, context.url ?? context.host ?? location), context.host?.href || location.href);
6996
7000
  let cache;
@@ -7017,7 +7021,7 @@ exports.media = (0, combinator_1.lazy)(() => (0, combinator_1.constraint)(4 /* S
7017
7021
  });
7018
7022
  }))))));
7019
7023
  exports.linemedia = (0, combinator_1.surround)(source_1.linebreak, (0, combinator_1.union)([exports.media]), /^(?=[^\S\n]*(?:$|\n))/);
7020
- const bracket = (0, combinator_1.lazy)(() => (0, combinator_1.recursion)(6 /* Recursion.terminal */, (0, combinator_1.union)([(0, combinator_1.surround)((0, source_1.str)('('), (0, combinator_1.some)((0, combinator_1.union)([htmlentity_1.unsafehtmlentity, bracket, source_1.txt]), ')'), (0, source_1.str)(')'), true, undefined, () => [[], ''], [3 | 4 /* Backtrack.lineescbracket */]), (0, combinator_1.surround)((0, source_1.str)('['), (0, combinator_1.some)((0, combinator_1.union)([htmlentity_1.unsafehtmlentity, bracket, source_1.txt]), ']'), (0, source_1.str)(']'), true, undefined, () => [[], ''], [3 | 4 /* Backtrack.lineescbracket */]), (0, combinator_1.surround)((0, source_1.str)('{'), (0, combinator_1.some)((0, combinator_1.union)([htmlentity_1.unsafehtmlentity, bracket, source_1.txt]), '}'), (0, source_1.str)('}'), true, undefined, () => [[], ''], [3 | 4 /* Backtrack.lineescbracket */]), (0, combinator_1.surround)((0, source_1.str)('"'), (0, combinator_1.precedence)(2, (0, combinator_1.some)((0, combinator_1.union)([htmlentity_1.unsafehtmlentity, source_1.txt]), '"')), (0, source_1.str)('"'), true, undefined, () => [[], ''], [3 | 4 /* Backtrack.lineescbracket */])])));
7024
+ const bracket = (0, combinator_1.lazy)(() => (0, combinator_1.recursion)(6 /* Recursion.terminal */, (0, combinator_1.union)([(0, combinator_1.surround)((0, source_1.str)('('), (0, combinator_1.some)((0, combinator_1.union)([htmlentity_1.unsafehtmlentity, bracket, source_1.txt]), ')'), (0, source_1.str)(')'), true, undefined, () => [[], ''], [3 | 4 /* Backtrack.escbracket */]), (0, combinator_1.surround)((0, source_1.str)('['), (0, combinator_1.some)((0, combinator_1.union)([htmlentity_1.unsafehtmlentity, bracket, source_1.txt]), ']'), (0, source_1.str)(']'), true, undefined, () => [[], ''], [3 | 4 /* Backtrack.escbracket */]), (0, combinator_1.surround)((0, source_1.str)('{'), (0, combinator_1.some)((0, combinator_1.union)([htmlentity_1.unsafehtmlentity, bracket, source_1.txt]), '}'), (0, source_1.str)('}'), true, undefined, () => [[], ''], [3 | 4 /* Backtrack.escbracket */]), (0, combinator_1.surround)((0, source_1.str)('"'), (0, combinator_1.precedence)(2, (0, combinator_1.some)((0, combinator_1.union)([htmlentity_1.unsafehtmlentity, source_1.txt]), '"')), (0, source_1.str)('"'), true, undefined, () => [[], ''], [3 | 4 /* Backtrack.escbracket */])])));
7021
7025
  const option = (0, combinator_1.lazy)(() => (0, combinator_1.union)([(0, combinator_1.fmap)((0, source_1.str)(/^[^\S\n]+[1-9][0-9]*x[1-9][0-9]*(?=[^\S\n]|})/), ([opt]) => [` width="${opt.slice(1).split('x')[0]}"`, ` height="${opt.slice(1).split('x')[1]}"`]), (0, combinator_1.fmap)((0, source_1.str)(/^[^\S\n]+[1-9][0-9]*:[1-9][0-9]*(?=[^\S\n]|})/), ([opt]) => [` aspect-ratio="${opt.slice(1).split(':').join('/')}"`]), link_1.option]));
7022
7026
  function sanitize(target, uri, alt) {
7023
7027
  switch (uri.protocol) {
@@ -7068,11 +7072,14 @@ const visibility_1 = __webpack_require__(6364);
7068
7072
  const dom_1 = __webpack_require__(394);
7069
7073
  const array_1 = __webpack_require__(6876);
7070
7074
  const util_1 = __webpack_require__(4992);
7071
- exports.reference = (0, combinator_1.lazy)(() => (0, combinator_1.constraint)(64 /* State.reference */, false, (0, combinator_1.surround)((0, source_1.str)('[['), (0, combinator_1.precedence)(1, (0, combinator_1.state)(128 /* State.annotation */ | 64 /* State.reference */ | 4 /* State.media */, (0, combinator_1.subsequence)([abbr, (0, visibility_1.trimBlankStart)((0, combinator_1.some)(inline_1.inline, ']', [['\n', 9], [']', 1]]))]))), ']]', false, ([, ns], rest) => (0, visibility_1.trimBlankNodeEnd)(ns).length > 0 ? [[(0, dom_1.html)('sup', attributes(ns), [(0, dom_1.html)('span', (0, dom_1.defrag)(ns))])], rest] : undefined, ([as, bs], rest, {
7072
- state = 0
7073
- }) => state & 128 /* State.annotation */ ? [(0, array_1.unshift)(as, bs), rest] : undefined, [3 | 32 /* Backtrack.linedoublebracket */, 1 | 16 /* Backtrack.linebracket */], 8 /* Backtrack.bracket */ | 1 /* BacktrackState.nobreak */)));
7075
+ exports.reference = (0, combinator_1.lazy)(() => (0, combinator_1.constraint)(64 /* State.reference */, false, (0, combinator_1.surround)((0, source_1.str)('[['), (0, combinator_1.precedence)(1, (0, combinator_1.state)(128 /* State.annotation */ | 64 /* State.reference */ | 4 /* State.media */, (0, combinator_1.subsequence)([abbr, (0, visibility_1.trimBlankStart)((0, combinator_1.some)(inline_1.inline, ']', [[']', 1]]))]))), ']]', false, ([, ns], rest, context) => context.linebreak === undefined && (0, visibility_1.trimBlankNodeEnd)(ns).length > 0 ? [[(0, dom_1.html)('sup', attributes(ns), [(0, dom_1.html)('span', (0, dom_1.defrag)(ns))])], rest] : undefined, ([as, bs], rest, context) => {
7076
+ if (rest[0] !== ']') {
7077
+ (0, combinator_1.setBacktrack)(context, [2 | 8 /* Backtrack.bracket */], context.recent.reduce((a, b) => a + b.length, 0), 2);
7078
+ }
7079
+ return context.state & 128 /* State.annotation */ ? [(0, array_1.unshift)(as, bs), rest] : undefined;
7080
+ }, [3 | 16 /* Backtrack.doublebracket */, 1 | 8 /* Backtrack.bracket */])));
7074
7081
  // Chicago-Style
7075
- const abbr = (0, combinator_1.surround)('^', (0, combinator_1.union)([(0, source_1.str)(/^(?=[A-Z])(?:[0-9A-Za-z]'?|(?:[-.:]|\.?\??,? ?)(?!['\-.:?, ]))+/)]), /^\|?(?=]])|^\|[^\S\n]*/, true, ([, ns], rest) => ns ? [['\n', ns[0].trimEnd()], rest.replace(visibility_1.blank.start, '')] : [[''], `^${rest}`], ([,, rest]) => [[''], `^${rest}`]);
7082
+ const abbr = (0, combinator_1.surround)('^', (0, combinator_1.union)([(0, source_1.str)(/^(?=[A-Z])(?:[0-9A-Za-z]'?|(?:[-.:]|\.?\??,? ?)(?!['\-.:?, ]))+/)]), /^\|?(?=]])|^\|[^\S\n]*/, true, ([, ns], rest) => ns ? [["\u001B" /* Command.Escape */, ns[0].trimEnd()], rest.replace(visibility_1.blank.start, '')] : [[''], `^${rest}`], ([,, rest]) => [[''], `^${rest}`]);
7076
7083
  function attributes(ns) {
7077
7084
  switch (ns[0]) {
7078
7085
  case '':
@@ -7080,7 +7087,7 @@ function attributes(ns) {
7080
7087
  class: 'invalid',
7081
7088
  ...(0, util_1.invalid)('reference', 'syntax', 'Invalid abbreviation')
7082
7089
  };
7083
- case '\n':
7090
+ case "\u001B" /* Command.Escape */:
7084
7091
  const abbr = ns[1];
7085
7092
  ns[0] = ns[1] = '';
7086
7093
  return {
@@ -7139,27 +7146,30 @@ const visibility_1 = __webpack_require__(6364);
7139
7146
  const util_1 = __webpack_require__(4992);
7140
7147
  const array_1 = __webpack_require__(6876);
7141
7148
  const dom_1 = __webpack_require__(394);
7142
- exports.ruby = (0, combinator_1.lazy)(() => (0, combinator_1.fmap)((0, combinator_1.sequence)([(0, combinator_1.dup)((0, combinator_1.surround)('[', (0, source_1.str)(/^(?:\\[^\n]|[^\\[\](){}<>"\n])+/), ']', false, ([, [source]], rest, context) => {
7149
+ exports.ruby = (0, combinator_1.lazy)(() => (0, combinator_1.bind)((0, combinator_1.inits)([(0, combinator_1.dup)((0, combinator_1.surround)('[', (0, source_1.str)(/^(?:\\[^\n]|[^\\[\](){}<>"\n])+/), ']', false, ([, [source]], rest, context) => {
7143
7150
  const ns = (0, parser_1.eval)(text({
7144
7151
  source,
7145
7152
  context
7146
7153
  }), [undefined])[0];
7147
7154
  ns && ns.at(-1) === '' && ns.pop();
7148
7155
  return ns && (0, visibility_1.isTightNodeStart)(ns) ? [ns, rest] : undefined;
7149
- }, undefined, [3 | 64 /* Backtrack.ruby */])), (0, combinator_1.dup)((0, combinator_1.surround)('(', (0, source_1.str)(/^(?:\\[^\n]|[^\\[\](){}<>"\n])+/), ')', false, ([, [source]], rest, context) => {
7156
+ }, undefined, [3 | 32 /* Backtrack.ruby */ | 1, 64 /* Backtrack.link */, 1 | 8 /* Backtrack.bracket */])), (0, combinator_1.dup)((0, combinator_1.surround)('(', (0, source_1.str)(/^(?:\\[^\n]|[^\\[\](){}<>"\n])+/), ')', false, ([, [source]], rest, context) => {
7150
7157
  const ns = (0, parser_1.eval)(text({
7151
7158
  source,
7152
7159
  context
7153
7160
  }), [undefined])[0];
7154
7161
  return ns && [ns, rest];
7155
- }, undefined, [3 | 64 /* Backtrack.ruby */]))]), ([texts, rubies]) => {
7162
+ }, undefined, [3 | 32 /* Backtrack.ruby */ | 1, 64 /* Backtrack.link */, 1 | 8 /* Backtrack.bracket */]))]), ([texts, rubies], rest, context) => {
7163
+ if (rubies === undefined) {
7164
+ return void (0, combinator_1.setBacktrack)(context, [2 | 32 /* Backtrack.ruby */], context.recent.reduce((a, b) => a + b.length, 0));
7165
+ }
7156
7166
  switch (true) {
7157
7167
  case rubies.length <= texts.length:
7158
- return [(0, dom_1.html)('ruby', attributes(texts, rubies), (0, dom_1.defrag)(texts.reduce((acc, _, i) => (0, array_1.push)(acc, (0, array_1.unshift)([texts[i]], i < rubies.length && rubies[i] ? [(0, dom_1.html)('rp', '('), (0, dom_1.html)('rt', rubies[i]), (0, dom_1.html)('rp', ')')] : [(0, dom_1.html)('rt')])), [])))];
7168
+ return [[(0, dom_1.html)('ruby', attributes(texts, rubies), (0, dom_1.defrag)(texts.reduce((acc, _, i) => (0, array_1.push)(acc, (0, array_1.unshift)([texts[i]], i < rubies.length && rubies[i] ? [(0, dom_1.html)('rp', '('), (0, dom_1.html)('rt', rubies[i]), (0, dom_1.html)('rp', ')')] : [(0, dom_1.html)('rt')])), [])))], rest];
7159
7169
  case texts.length === 1 && [...texts[0]].length >= rubies.length:
7160
- return [(0, dom_1.html)('ruby', attributes(texts, rubies), (0, dom_1.defrag)([...texts[0]].reduce((acc, _, i, texts) => (0, array_1.push)(acc, (0, array_1.unshift)([texts[i]], i < rubies.length && rubies[i] ? [(0, dom_1.html)('rp', '('), (0, dom_1.html)('rt', rubies[i]), (0, dom_1.html)('rp', ')')] : [(0, dom_1.html)('rt')])), [])))];
7170
+ return [[(0, dom_1.html)('ruby', attributes(texts, rubies), (0, dom_1.defrag)([...texts[0]].reduce((acc, _, i, texts) => (0, array_1.push)(acc, (0, array_1.unshift)([texts[i]], i < rubies.length && rubies[i] ? [(0, dom_1.html)('rp', '('), (0, dom_1.html)('rt', rubies[i]), (0, dom_1.html)('rp', ')')] : [(0, dom_1.html)('rt')])), [])))], rest];
7161
7171
  default:
7162
- return [(0, dom_1.html)('ruby', attributes(texts, rubies), (0, dom_1.defrag)((0, array_1.unshift)([texts.join(' ')], [(0, dom_1.html)('rp', '('), (0, dom_1.html)('rt', rubies.join(' ').trim()), (0, dom_1.html)('rp', ')')])))];
7172
+ return [[(0, dom_1.html)('ruby', attributes(texts, rubies), (0, dom_1.defrag)((0, array_1.unshift)([texts.join(' ')], [(0, dom_1.html)('rp', '('), (0, dom_1.html)('rt', rubies.join(' ').trim()), (0, dom_1.html)('rp', ')')])))], rest];
7163
7173
  }
7164
7174
  }));
7165
7175
  const text = ({
@@ -7272,10 +7282,10 @@ exports.template = void 0;
7272
7282
  const combinator_1 = __webpack_require__(3484);
7273
7283
  const source_1 = __webpack_require__(8745);
7274
7284
  const dom_1 = __webpack_require__(394);
7275
- exports.template = (0, combinator_1.lazy)(() => (0, combinator_1.surround)('{{', (0, combinator_1.precedence)(1, (0, combinator_1.some)((0, combinator_1.union)([bracket, source_1.escsource]), '}', [['\n', 9]])), '}}', true, ([, ns = []], rest) => [[(0, dom_1.html)('span', {
7285
+ exports.template = (0, combinator_1.lazy)(() => (0, combinator_1.surround)('{{', (0, combinator_1.precedence)(1, (0, combinator_1.some)((0, combinator_1.union)([bracket, source_1.escsource]), '}')), '}}', true, ([, ns = []], rest, context) => context.linebreak === undefined ? [[(0, dom_1.html)('span', {
7276
7286
  class: 'template'
7277
- }, `{{${ns.join('')}}}`)], rest], undefined, [3 | 32 /* Backtrack.linedoublebracket */, 1 | 4 /* Backtrack.lineescbracket */]));
7278
- const bracket = (0, combinator_1.lazy)(() => (0, combinator_1.union)([(0, combinator_1.surround)((0, source_1.str)('('), (0, combinator_1.recursion)(6 /* Recursion.terminal */, (0, combinator_1.some)((0, combinator_1.union)([bracket, source_1.escsource]), ')')), (0, source_1.str)(')'), true, undefined, () => [[], ''], [3 | 4 /* Backtrack.lineescbracket */]), (0, combinator_1.surround)((0, source_1.str)('['), (0, combinator_1.recursion)(6 /* Recursion.terminal */, (0, combinator_1.some)((0, combinator_1.union)([bracket, source_1.escsource]), ']')), (0, source_1.str)(']'), true, undefined, () => [[], ''], [3 | 4 /* Backtrack.lineescbracket */]), (0, combinator_1.surround)((0, source_1.str)('{'), (0, combinator_1.recursion)(6 /* Recursion.terminal */, (0, combinator_1.some)((0, combinator_1.union)([bracket, source_1.escsource]), '}')), (0, source_1.str)('}'), true, undefined, () => [[], ''], [3 | 4 /* Backtrack.lineescbracket */]), (0, combinator_1.surround)((0, source_1.str)('"'), (0, combinator_1.precedence)(2, (0, combinator_1.recursion)(6 /* Recursion.terminal */, (0, combinator_1.some)(source_1.escsource, '"'))), (0, source_1.str)('"'), true, undefined, () => [[], ''], [3 | 4 /* Backtrack.lineescbracket */])]));
7287
+ }, `{{${ns.join('')}}}`)], rest] : undefined, undefined, [3 | 16 /* Backtrack.doublebracket */, 1 | 8 /* Backtrack.bracket */]));
7288
+ const bracket = (0, combinator_1.lazy)(() => (0, combinator_1.union)([(0, combinator_1.surround)((0, source_1.str)('('), (0, combinator_1.recursion)(6 /* Recursion.terminal */, (0, combinator_1.some)((0, combinator_1.union)([bracket, source_1.escsource]), ')')), (0, source_1.str)(')'), true, undefined, () => [[], ''], [3 | 4 /* Backtrack.escbracket */]), (0, combinator_1.surround)((0, source_1.str)('['), (0, combinator_1.recursion)(6 /* Recursion.terminal */, (0, combinator_1.some)((0, combinator_1.union)([bracket, source_1.escsource]), ']')), (0, source_1.str)(']'), true, undefined, () => [[], ''], [3 | 4 /* Backtrack.escbracket */]), (0, combinator_1.surround)((0, source_1.str)('{'), (0, combinator_1.recursion)(6 /* Recursion.terminal */, (0, combinator_1.some)((0, combinator_1.union)([bracket, source_1.escsource]), '}')), (0, source_1.str)('}'), true, undefined, () => [[], ''], [3 | 4 /* Backtrack.escbracket */]), (0, combinator_1.surround)((0, source_1.str)('"'), (0, combinator_1.precedence)(2, (0, combinator_1.recursion)(6 /* Recursion.terminal */, (0, combinator_1.some)(source_1.escsource, '"'))), (0, source_1.str)('"'), true, undefined, () => [[], ''], [3 | 4 /* Backtrack.escbracket */])]));
7279
7289
 
7280
7290
  /***/ },
7281
7291
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "securemark",
3
- "version": "0.289.5",
3
+ "version": "0.289.6",
4
4
  "description": "Secure markdown renderer working on browsers for user input data.",
5
5
  "private": false,
6
6
  "homepage": "https://github.com/falsandtru/securemark",
@@ -7,7 +7,6 @@ export function surround<P extends Parser<unknown>, S = string>(
7
7
  f?: (rss: [S[], SubNode<P>[], S[]], rest: string, context: Context<P>) => Result<Node<P>, Context<P>, SubParsers<P>>,
8
8
  g?: (rss: [S[], SubNode<P>[], string], rest: string, context: Context<P>) => Result<Node<P>, Context<P>, SubParsers<P>>,
9
9
  backtracks?: readonly number[],
10
- backtrackstate?: number,
11
10
  ): P;
12
11
  export function surround<P extends Parser<unknown>, S = string>(
13
12
  opener: string | RegExp | Parser<S, Context<P>>, parser: IntermediateParser<P>, closer: string | RegExp | Parser<S, Context<P>>,
@@ -15,7 +14,6 @@ export function surround<P extends Parser<unknown>, S = string>(
15
14
  f?: (rss: [S[], SubNode<P>[] | undefined, S[]], rest: string, context: Context<P>) => Result<Node<P>, Context<P>, SubParsers<P>>,
16
15
  g?: (rss: [S[], SubNode<P>[] | undefined, string], rest: string, context: Context<P>) => Result<Node<P>, Context<P>, SubParsers<P>>,
17
16
  backtracks?: readonly number[],
18
- backtrackstate?: number,
19
17
  ): P;
20
18
  export function surround<P extends Parser<unknown>, S = string>(
21
19
  opener: string | RegExp | Parser<S, Context<P>>, parser: P, closer: string | RegExp | Parser<S, Context<P>>,
@@ -23,7 +21,6 @@ export function surround<P extends Parser<unknown>, S = string>(
23
21
  f?: (rss: [S[], Node<P>[], S[]], rest: string, context: Context<P>) => Result<Node<P>, Context<P>, SubParsers<P>>,
24
22
  g?: (rss: [S[], Node<P>[], string], rest: string, context: Context<P>) => Result<Node<P>, Context<P>, SubParsers<P>>,
25
23
  backtracks?: readonly number[],
26
- backtrackstate?: number,
27
24
  ): P;
28
25
  export function surround<P extends Parser<unknown>, S = string>(
29
26
  opener: string | RegExp | Parser<S, Context<P>>, parser: P, closer: string | RegExp | Parser<S, Context<P>>,
@@ -31,7 +28,6 @@ export function surround<P extends Parser<unknown>, S = string>(
31
28
  f?: (rss: [S[], Node<P>[] | undefined, S[]], rest: string, context: Context<P>) => Result<Node<P>, Context<P>, SubParsers<P>>,
32
29
  g?: (rss: [S[], Node<P>[] | undefined, string], rest: string, context: Context<P>) => Result<Node<P>, Context<P>, SubParsers<P>>,
33
30
  backtracks?: readonly number[],
34
- backtrackstate?: number,
35
31
  ): P;
36
32
  export function surround<N>(
37
33
  opener: string | RegExp | Parser<N>, parser: Parser<N>, closer: string | RegExp | Parser<N>,
@@ -39,7 +35,6 @@ export function surround<N>(
39
35
  f?: (rss: [N[], N[], N[]], rest: string, context: Ctx) => Result<N>,
40
36
  g?: (rss: [N[], N[], string], rest: string, context: Ctx) => Result<N>,
41
37
  backtracks: readonly number[] = [],
42
- backtrackstate: number = 0,
43
38
  ): Parser<N> {
44
39
  switch (typeof opener) {
45
40
  case 'string':
@@ -61,19 +56,16 @@ export function surround<N>(
61
56
  if (resultS === undefined) return void revert(context, linebreak);
62
57
  const nodesS = eval(resultS);
63
58
  const me_ = exec(resultS);
64
- if (getBacktrack(context, backtracks, sme_, me_)) return void revert(context, linebreak);
65
- const { backtrack = 0 } = context;
66
- context.backtrack = backtrack | backtrackstate;
59
+ if (getBacktrack(context, backtracks, sme_, sme_.length - me_.length)) return void revert(context, linebreak);
67
60
  const resultM = me_ !== '' ? parser({ source: me_, context }) : undefined;
68
61
  assert(check(me_, resultM));
69
- context.backtrack = backtrack;
70
62
  const nodesM = eval(resultM);
71
63
  const e_ = exec(resultM, me_);
72
64
  const resultE = nodesM || optional ? closer({ source: e_, context }) : undefined;
73
65
  assert(check(e_, resultE, false));
74
66
  const nodesE = eval(resultE);
75
67
  const rest = exec(resultE, e_);
76
- nodesE || setBacktrack(context, backtracks, sme_);
68
+ nodesE || setBacktrack(context, backtracks, sme_.length);
77
69
  if (!nodesM && !optional) return void revert(context, linebreak);
78
70
  if (rest.length === sme_.length) return void revert(context, linebreak);
79
71
  context.recent = [
@@ -102,51 +94,46 @@ export function open<P extends Parser<unknown>>(
102
94
  parser: P,
103
95
  optional?: boolean,
104
96
  backtracks?: readonly number[],
105
- backtrackstate?: number,
106
97
  ): P;
107
98
  export function open<N>(
108
99
  opener: string | RegExp | Parser<N>,
109
100
  parser: Parser<N>,
110
101
  optional?: boolean,
111
102
  backtracks?: readonly number[],
112
- backtrackstate?: number,
113
103
  ): Parser<N> {
114
- return surround(opener, parser, '', optional, undefined, undefined, backtracks, backtrackstate);
104
+ return surround(opener, parser, '', optional, undefined, undefined, backtracks);
115
105
  }
116
106
  export function close<P extends Parser<unknown>>(
117
107
  parser: P,
118
108
  closer: string | RegExp | Parser<Node<P>, Context<P>>,
119
109
  optional?: boolean,
120
110
  backtracks?: readonly number[],
121
- backtrackstate?: number,
122
111
  ): P;
123
112
  export function close<N>(
124
113
  parser: Parser<N>,
125
114
  closer: string | RegExp | Parser<N>,
126
115
  optional?: boolean,
127
116
  backtracks?: readonly number[],
128
- backtrackstate?: number,
129
117
  ): Parser<N> {
130
- return surround('', parser, closer, optional, undefined, undefined, backtracks, backtrackstate);
118
+ return surround('', parser, closer, optional, undefined, undefined, backtracks);
131
119
  }
132
120
 
133
121
  const statesize = 2;
134
122
  export function getBacktrack(
135
123
  context: Ctx,
136
124
  backtracks: readonly number[],
137
- sme_: string,
138
- me_: string,
125
+ source: string,
126
+ length: number,
139
127
  ): boolean {
140
128
  for (const backtrack of backtracks) {
141
129
  if (backtrack & 1) {
142
- const { backtracks = {}, backtrack: state = 0, offset = 0 } = context;
143
- for (let i = 0, len = sme_.length - me_.length || 1; i < len; ++i) {
144
- if (sme_[i] !== sme_[0]) break;
145
- const pos = sme_.length - i + offset - 1;
130
+ const { backtracks = {}, offset = 0 } = context;
131
+ for (let i = 0; i < length; ++i) {
132
+ if (source[i] !== source[0]) break;
133
+ const pos = source.length - i + offset - 1;
146
134
  assert(pos >= 0);
147
135
  if (!(pos in backtracks)) continue;
148
- const shift = backtrack >>> statesize & state >>> statesize ? state & (1 << statesize) - 1 : 0;
149
- if (backtracks[pos] & 1 << size(backtrack >>> statesize) + shift) return true;
136
+ if (backtracks[pos] & 1 << size(backtrack >>> statesize)) return true;
150
137
  }
151
138
  }
152
139
  }
@@ -155,18 +142,21 @@ export function getBacktrack(
155
142
  export function setBacktrack(
156
143
  context: Ctx,
157
144
  backtracks: readonly number[],
158
- sme_: string,
145
+ position: number,
146
+ length: number = 1,
159
147
  ): void {
160
148
  for (const backtrack of backtracks) {
161
149
  if (backtrack & 2) {
162
- const { backtracks = {}, backtrack: state = 0, offset = 0 } = context;
163
- const pos = sme_.length + offset - 1;
164
- assert(pos >= 0);
165
- const shift = backtrack >>> statesize & state >>> statesize ? state & (1 << statesize) - 1 : 0;
166
- backtracks[pos] |= 1 << size(backtrack >>> statesize) + shift;
150
+ const { backtracks = {}, offset = 0 } = context;
151
+ for (let i = 0; i < length; ++i) {
152
+ const pos = position - i + offset - 1;
153
+ assert(pos >= 0);
154
+ backtracks[pos] |= 1 << size(backtrack >>> statesize);
155
+ }
167
156
  }
168
157
  }
169
158
  }
159
+
170
160
  function match(pattern: string | RegExp): (input: Input) => [never[], string] | undefined {
171
161
  switch (typeof pattern) {
172
162
  case 'string':
@@ -12,6 +12,7 @@ export function bind<N, U>(parser: Parser<N>, f: (nodes: N[], rest: string, cont
12
12
  const res1 = parser(input);
13
13
  assert(check(source, res1));
14
14
  if (res1 === undefined) return;
15
+ context.recent = [source.slice(0, source.length - exec(res1).length)];
15
16
  const res2 = f(eval(res1), exec(res1), context);
16
17
  assert(check(source, res2));
17
18
  assert(check(exec(res1), res2, false));
@@ -21,7 +21,6 @@ export interface Ctx {
21
21
  state?: number;
22
22
  depth?: number;
23
23
  backtracks?: Record<number, number>;
24
- backtrack?: number;
25
24
  linebreak?: number;
26
25
  recent?: string[];
27
26
  }
@@ -350,9 +350,8 @@ describe('Unit: parser/api/parse', () => {
350
350
 
351
351
  it('backtrack', function () {
352
352
  this.timeout(5000);
353
- // 9n = template + link + annotation/reference + link + link +
354
- // code + url + ruby + text
355
- const source = `${'.'.repeat(2 + 0)}{{(([[[\`http://[${'.'.repeat(11103)}`;
353
+ // 8n = template + link + annotation/reference + link + code + url + ruby + text
354
+ const source = `${'.'.repeat(1 + 0)}{{(([[[\`http://[${'.'.repeat(12493)}`;
356
355
  assert.deepStrictEqual(
357
356
  [...parse(source).children].map(el => el.outerHTML.replace(/:\w+/, ':rnd')),
358
357
  [`<p>${source}</p>`]);
@@ -360,7 +359,7 @@ describe('Unit: parser/api/parse', () => {
360
359
 
361
360
  it('backtrack error', function () {
362
361
  this.timeout(5000);
363
- const source = `${'.'.repeat(2 + 1)}{{(([[[\`http://[${'.'.repeat(11103)}`;
362
+ const source = `${'.'.repeat(1 + 1)}{{(([[[\`http://[${'.'.repeat(12493)}`;
364
363
  assert.deepStrictEqual(
365
364
  [...parse(source).children].map(el => el.outerHTML.replace(/:\w+/, ':rnd')),
366
365
  [
@@ -28,18 +28,12 @@ export const enum Recursion {
28
28
  }
29
29
 
30
30
  export const enum Backtrack {
31
- link = 1 << 7,
32
- ruby = 1 << 6,
33
- linedoublebracket = 1 << 5,
34
- linebracket = 1 << 4,
31
+ link = 1 << 6,
32
+ ruby = 1 << 5,
33
+ doublebracket = 1 << 4,
35
34
  bracket = 1 << 3,
36
- lineescbracket = 1 << 2,
37
- url = 0 << 2,
38
- }
39
- // バックトラックを削減するため括弧派生構文を改行禁止し
40
- // 括弧派生構文内のバックトラック状態を統一する。
41
- export const enum BacktrackState {
42
- nobreak = 1,
35
+ escbracket = 1 << 2,
36
+ autolink = 0 << 2,
43
37
  }
44
38
 
45
39
  export const enum Command {
@@ -1,5 +1,5 @@
1
1
  import { AnnotationParser } from '../inline';
2
- import { State, Backtrack, BacktrackState } from '../context';
2
+ import { State, Backtrack } from '../context';
3
3
  import { union, some, precedence, state, constraint, surround, lazy } from '../../combinator';
4
4
  import { inline } from '../inline';
5
5
  import { trimBlankStart, trimBlankNodeEnd } from '../visibility';
@@ -8,13 +8,13 @@ import { html, defrag } from 'typed-dom/dom';
8
8
  export const annotation: AnnotationParser = lazy(() => constraint(State.annotation, false, surround(
9
9
  '((',
10
10
  precedence(1, state(State.annotation | State.media,
11
- trimBlankStart(some(union([inline]), ')', [['\n', 9], [')', 1]])))),
11
+ trimBlankStart(some(union([inline]), ')', [[')', 1]])))),
12
12
  '))',
13
13
  false,
14
- ([, ns], rest) =>
14
+ ([, ns], rest, context) =>
15
+ context.linebreak === undefined &&
15
16
  trimBlankNodeEnd(ns).length > 0
16
17
  ? [[html('sup', { class: 'annotation' }, [html('span', defrag(ns))])], rest]
17
18
  : undefined,
18
19
  undefined,
19
- [3 | Backtrack.linedoublebracket, 1 | Backtrack.linebracket],
20
- Backtrack.bracket | BacktrackState.nobreak)));
20
+ [3 | Backtrack.doublebracket, 1 | Backtrack.bracket])));
@@ -1,14 +1,20 @@
1
1
  import { AutolinkParser } from '../../inline';
2
- import { State } from '../../context';
3
- import { union, state, constraint, verify, rewrite } from '../../../combinator';
2
+ import { State, Backtrack } from '../../context';
3
+ import { union, state, constraint, verify, rewrite, surround } from '../../../combinator';
4
4
  import { str } from '../../source';
5
5
  import { html } from 'typed-dom/dom';
6
6
 
7
7
  // https://html.spec.whatwg.org/multipage/input.html
8
8
 
9
- export const email: AutolinkParser.EmailParser = rewrite(verify(
10
- str(/^[0-9a-z](?:[_.+-](?=[0-9a-z])|[0-9a-z]){0,255}@[0-9a-z](?:(?:[0-9a-z]|-(?=[0-9a-z])){0,61}[0-9a-z])?(?:\.[0-9a-z](?:(?:[0-9a-z]|-(?=[0-9a-z])){0,61}[0-9a-z])?)*(?![0-9a-z])/i),
11
- ([source]) => source.length <= 255),
9
+ export const email: AutolinkParser.EmailParser = rewrite(
10
+ surround(
11
+ str(/^[0-9a-z]/i),
12
+ verify(
13
+ str(/^(?:[_.+-](?=[0-9a-z])|[0-9a-z]){0,255}@[0-9a-z](?:(?:[0-9a-z]|-(?=[0-9a-z])){0,61}[0-9a-z])?(?:\.[0-9a-z](?:(?:[0-9a-z]|-(?=[0-9a-z])){0,61}[0-9a-z])?)*(?![0-9a-z])/i),
14
+ ([source]) => source.length <= 255 - 1),
15
+ '',
16
+ false, undefined, undefined,
17
+ [3 | Backtrack.autolink]),
12
18
  union([
13
19
  constraint(State.autolink, false, state(State.autolink,
14
20
  ({ source }) => [[html('a', { class: 'email', href: `mailto:${source}` }, source)], ''])),
@@ -1,5 +1,5 @@
1
1
  import { AutolinkParser } from '../../inline';
2
- import { State } from '../../context';
2
+ import { State, Backtrack } from '../../context';
3
3
  import { union, state, constraint, rewrite, open, convert, fmap, lazy } from '../../../combinator';
4
4
  import { unsafelink } from '../link';
5
5
  import { str } from '../../source';
@@ -16,7 +16,9 @@ export const hashtag: AutolinkParser.HashtagParser = lazy(() => rewrite(
16
16
  str(new RegExp([
17
17
  /^(?!['_])(?=(?:[0-9]{1,9})?(?:[^\d\p{C}\p{S}\p{P}\s]|emoji|'(?=[0-9A-Za-z])|_(?=[^'\p{C}\p{S}\p{P}\s]|emoji)))/u.source,
18
18
  /(?:[^\p{C}\p{S}\p{P}\s]|emoji|'(?=[0-9A-Za-z])|_(?=[^'\p{C}\p{S}\p{P}\s]|emoji))+/u.source,
19
- ].join('').replace(/emoji/g, emoji), 'u'))),
19
+ ].join('').replace(/emoji/g, emoji), 'u')),
20
+ false,
21
+ [3 | Backtrack.autolink]),
20
22
  union([
21
23
  constraint(State.autolink, false, state(State.autolink, fmap(convert(
22
24
  source => `[${source}]{ ${`/hashtags/${source.slice(1)}`} }`,
@@ -14,7 +14,7 @@ export const url: AutolinkParser.UrlParser = lazy(() => validate(['http://', 'ht
14
14
  some(unescsource, closer),
15
15
  ]), undefined, [[/^[^\x21-\x7E]/, 3]])),
16
16
  false,
17
- [3 | Backtrack.url]),
17
+ [3 | Backtrack.autolink]),
18
18
  union([
19
19
  constraint(State.autolink, false, state(State.autolink, convert(
20
20
  url => `{ ${url} }`,
@@ -38,15 +38,15 @@ export const lineurl: AutolinkParser.UrlParser.LineUrlParser = lazy(() => open(
38
38
  ]),
39
39
  ])),
40
40
  false,
41
- [3 | Backtrack.linebracket]));
41
+ [3 | Backtrack.autolink]));
42
42
 
43
43
  const bracket: AutolinkParser.UrlParser.BracketParser = lazy(() => union([
44
44
  surround(str('('), recursion(Recursion.terminal, some(union([bracket, unescsource]), ')')), str(')'), true,
45
- undefined, () => [[], ''], [3 | Backtrack.url]),
45
+ undefined, () => [[], ''], [3 | Backtrack.autolink]),
46
46
  surround(str('['), recursion(Recursion.terminal, some(union([bracket, unescsource]), ']')), str(']'), true,
47
- undefined, () => [[], ''], [3 | Backtrack.url]),
47
+ undefined, () => [[], ''], [3 | Backtrack.autolink]),
48
48
  surround(str('{'), recursion(Recursion.terminal, some(union([bracket, unescsource]), '}')), str('}'), true,
49
- undefined, () => [[], ''], [3 | Backtrack.url]),
49
+ undefined, () => [[], ''], [3 | Backtrack.autolink]),
50
50
  surround(str('"'), precedence(2, recursion(Recursion.terminal, some(unescsource, '"'))), str('"'), true,
51
- undefined, () => [[], ''], [3 | Backtrack.url]),
51
+ undefined, () => [[], ''], [3 | Backtrack.autolink]),
52
52
  ]));
@@ -6,13 +6,13 @@ import { html } from 'typed-dom/dom';
6
6
  export const code: CodeParser = validate(
7
7
  ({ source, context }) =>
8
8
  source[0] === '`' &&
9
- !getBacktrack(context, [1 | Backtrack.linebracket], source, source.slice(1)),
9
+ !getBacktrack(context, [1 | Backtrack.bracket], source, source.length - 1),
10
10
  match(
11
11
  /^(`+)(?!`)([^\n]*?)(?:((?<!`)\1(?!`))|$|\n)/,
12
12
  ([whole, , body, closer]) => ({ source, context }) =>
13
13
  closer
14
14
  ? [[html('code', { 'data-src': whole }, format(body))], source.slice(whole.length)]
15
- : void setBacktrack(context, [2 | Backtrack.linebracket], source),
15
+ : void setBacktrack(context, [2 | Backtrack.bracket], source.length),
16
16
  true));
17
17
 
18
18
  function format(text: string): string {
@@ -1,5 +1,5 @@
1
1
  import { ExtensionParser } from '../../inline';
2
- import { State, Backtrack, BacktrackState, Command } from '../../context';
2
+ import { State, Backtrack, Command } from '../../context';
3
3
  import { eval } from '../../../combinator/data/parser';
4
4
  import { union, inits, some, precedence, state, constraint, validate, surround, lazy, fmap } from '../../../combinator';
5
5
  import { inline } from '../../inline';
@@ -19,16 +19,16 @@ export const index: IndexParser = lazy(() => constraint(State.index, false, fmap
19
19
  some(inits([
20
20
  inline,
21
21
  signature,
22
- ]), ']', [['\n', 9], [']', 1]])))),
22
+ ]), ']', [[']', 1]])))),
23
23
  ']',
24
24
  false,
25
- ([, ns], rest) =>
25
+ ([, ns], rest, context) =>
26
+ context.linebreak === undefined &&
26
27
  trimBlankNodeEnd(ns).length > 0
27
28
  ? [[html('a', { 'data-index': dataindex(ns) }, defrag(ns))], rest]
28
29
  : undefined,
29
30
  undefined,
30
- [3 | Backtrack.linebracket],
31
- Backtrack.bracket | BacktrackState.nobreak)),
31
+ [3 | Backtrack.bracket])),
32
32
  ([el]: [HTMLAnchorElement]) => [
33
33
  define(el,
34
34
  {
@@ -13,7 +13,7 @@ export const segment: ExtensionParser.LabelParser.SegmentParser = clear(union([
13
13
 
14
14
  export const label: ExtensionParser.LabelParser = constraint(State.label, false, fmap(
15
15
  union([
16
- surround('[', body, ']', false, undefined, undefined, [1 | Backtrack.linebracket, 1]),
16
+ surround('[', body, ']', false, undefined, undefined, [1 | Backtrack.bracket, 1]),
17
17
  body,
18
18
  ]),
19
19
  ([text]) => [
@@ -32,7 +32,7 @@ export const html: HTMLParser = lazy(() => validate(/^<[a-z]+(?=[^\S\n]|>)/i,
32
32
  ([as, bs = [], cs], rest) =>
33
33
  [[elem(as[0].slice(1), push(unshift(as, bs), cs), [], [])], rest],
34
34
  undefined,
35
- [3 | Backtrack.linebracket]),
35
+ [3 | Backtrack.bracket]),
36
36
  match(
37
37
  new RegExp(String.raw`^<(${TAGS.join('|')})(?=[^\S\n]|>)`),
38
38
  memoize(
@@ -40,7 +40,7 @@ export const html: HTMLParser = lazy(() => validate(/^<[a-z]+(?=[^\S\n]|>)/i,
40
40
  surround<HTMLParser.TagParser, string>(
41
41
  surround(
42
42
  str(`<${tag}`), some(attribute), str(/^[^\S\n]*>/), true,
43
- undefined, undefined, [3 | Backtrack.linebracket]),
43
+ undefined, undefined, [3 | Backtrack.bracket]),
44
44
  precedence(3, recursion(Recursion.inline,
45
45
  subsequence([
46
46
  focus(/^[^\S\n]*\n/, some(inline)),
@@ -60,7 +60,7 @@ export const html: HTMLParser = lazy(() => validate(/^<[a-z]+(?=[^\S\n]|>)/i,
60
60
  surround<HTMLParser.TagParser, string>(
61
61
  surround(
62
62
  str(`<${tag}`), some(attribute), str(/^[^\S\n]*>/), true,
63
- undefined, undefined, [3 | Backtrack.linebracket]),
63
+ undefined, undefined, [3 | Backtrack.bracket]),
64
64
  precedence(3, recursion(Recursion.inline,
65
65
  subsequence([
66
66
  focus(/^[^\S\n]*\n/, some(inline)),
@@ -1,13 +1,14 @@
1
1
  import { MarkdownParser } from '../../../markdown';
2
2
  import { LinkParser } from '../inline';
3
- import { State, Backtrack, BacktrackState } from '../context';
4
- import { union, inits, tails, sequence, some, creation, precedence, state, constraint, validate, surround, open, dup, reverse, lazy, fmap, bind } from '../../combinator';
3
+ import { State, Backtrack, Command } from '../context';
4
+ import { union, inits, tails, sequence, subsequence, some, creation, precedence, state, constraint, validate, surround, open, setBacktrack, dup, reverse, lazy, fmap, bind } from '../../combinator';
5
5
  import { inline, media, shortmedia } from '../inline';
6
6
  import { attributes } from './html';
7
7
  import { linebreak, unescsource, str } from '../source';
8
8
  import { trimBlankStart, trimBlankNodeEnd } from '../visibility';
9
9
  import { invalid, stringify } from '../util';
10
10
  import { ReadonlyURL } from 'spica/url';
11
+ import { push } from 'spica/array';
11
12
  import { html, define, defrag } from 'typed-dom/dom';
12
13
 
13
14
  const optspec = {
@@ -17,22 +18,36 @@ Object.setPrototypeOf(optspec, null);
17
18
 
18
19
  export const textlink: LinkParser.TextLinkParser = lazy(() => constraint(State.link, false, creation(10,
19
20
  precedence(1, state(State.linkers | State.media,
20
- bind(reverse(tails([
21
+ bind(subsequence([
21
22
  dup(surround(
22
23
  '[',
23
- trimBlankStart(some(union([inline]), ']', [['\n', 9], [']', 1]])),
24
+ trimBlankStart(some(union([inline]), ']', [[']', 1]])),
24
25
  ']',
25
- true, undefined, undefined,
26
- [1 | Backtrack.linebracket],
27
- Backtrack.bracket | BacktrackState.nobreak)),
26
+ true,
27
+ ([, ns = []], rest, context) =>
28
+ context.linebreak === undefined
29
+ ? [push(ns, [Command.Escape]), rest]
30
+ : undefined,
31
+ undefined,
32
+ [3 | Backtrack.link, 3 | Backtrack.bracket])),
28
33
  dup(surround(
29
34
  /^{(?![{}])/,
30
35
  inits([uri, some(option)]),
31
36
  /^[^\S\n]*}/,
32
37
  false, undefined, undefined,
33
38
  [3 | Backtrack.link])),
34
- ])),
35
- ([params, content = []]: [string[], (HTMLElement | string)[]], rest, context) => {
39
+ ]),
40
+ ([content, params]: [(HTMLElement | string)[], string[]], rest, context) => {
41
+ if (content.at(-1) === Command.Escape) {
42
+ content.pop();
43
+ if (params === undefined) {
44
+ return void setBacktrack(context, [2 | Backtrack.link], context.recent!.reduce((a, b) => a + b.length, 0));
45
+ }
46
+ }
47
+ else {
48
+ params = content as string[];
49
+ content = [];
50
+ }
36
51
  assert(!html('div', content).querySelector('a, .media, .annotation, .reference'));
37
52
  assert(content[0] !== '');
38
53
  if (content.length !== 0 && trimBlankNodeEnd(content).length === 0) return;
@@ -27,10 +27,15 @@ export const media: MediaParser = lazy(() => constraint(State.media, false, vali
27
27
  unsafehtmlentity,
28
28
  bracket,
29
29
  txt,
30
- ]), ']', [['\n', 9]])),
30
+ ]), ']')),
31
31
  ']',
32
- true, undefined, undefined,
33
- [3 | Backtrack.lineescbracket])),
32
+ true,
33
+ ([, ns = []], rest, context) =>
34
+ context.linebreak === undefined
35
+ ? [ns, rest]
36
+ : undefined,
37
+ undefined,
38
+ [3 | Backtrack.escbracket])),
34
39
  dup(surround(
35
40
  /^{(?![{}])/,
36
41
  inits([uri, some(option)]),
@@ -77,13 +82,13 @@ export const linemedia: MediaParser.LineMediaParser = surround(
77
82
 
78
83
  const bracket: MediaParser.TextParser.BracketParser = lazy(() => recursion(Recursion.terminal, union([
79
84
  surround(str('('), some(union([unsafehtmlentity, bracket, txt]), ')'), str(')'), true,
80
- undefined, () => [[], ''], [3 | Backtrack.lineescbracket]),
85
+ undefined, () => [[], ''], [3 | Backtrack.escbracket]),
81
86
  surround(str('['), some(union([unsafehtmlentity, bracket, txt]), ']'), str(']'), true,
82
- undefined, () => [[], ''], [3 | Backtrack.lineescbracket]),
87
+ undefined, () => [[], ''], [3 | Backtrack.escbracket]),
83
88
  surround(str('{'), some(union([unsafehtmlentity, bracket, txt]), '}'), str('}'), true,
84
- undefined, () => [[], ''], [3 | Backtrack.lineescbracket]),
89
+ undefined, () => [[], ''], [3 | Backtrack.escbracket]),
85
90
  surround(str('"'), precedence(2, some(union([unsafehtmlentity, txt]), '"')), str('"'), true,
86
- undefined, () => [[], ''], [3 | Backtrack.lineescbracket]),
91
+ undefined, () => [[], ''], [3 | Backtrack.escbracket]),
87
92
  ])));
88
93
 
89
94
  const option: MediaParser.ParameterParser.OptionParser = lazy(() => union([
@@ -1,6 +1,6 @@
1
1
  import { ReferenceParser } from '../inline';
2
- import { State, Backtrack, BacktrackState } from '../context';
3
- import { union, subsequence, some, precedence, state, constraint, surround, lazy } from '../../combinator';
2
+ import { State, Backtrack, Command } from '../context';
3
+ import { union, subsequence, some, precedence, state, constraint, surround, setBacktrack, lazy } from '../../combinator';
4
4
  import { inline } from '../inline';
5
5
  import { str } from '../source';
6
6
  import { blank, trimBlankStart, trimBlankNodeEnd } from '../visibility';
@@ -13,20 +13,24 @@ export const reference: ReferenceParser = lazy(() => constraint(State.reference,
13
13
  precedence(1, state(State.annotation | State.reference | State.media,
14
14
  subsequence([
15
15
  abbr,
16
- trimBlankStart(some(inline, ']', [['\n', 9], [']', 1]])),
16
+ trimBlankStart(some(inline, ']', [[']', 1]])),
17
17
  ]))),
18
18
  ']]',
19
19
  false,
20
- ([, ns], rest) =>
20
+ ([, ns], rest, context) =>
21
+ context.linebreak === undefined &&
21
22
  trimBlankNodeEnd(ns).length > 0
22
23
  ? [[html('sup', attributes(ns), [html('span', defrag(ns))])], rest]
23
24
  : undefined,
24
- ([as, bs], rest, { state = 0 }) =>
25
- state & State.annotation
25
+ ([as, bs], rest, context) => {
26
+ if (rest[0] !== ']') {
27
+ setBacktrack(context, [2 | Backtrack.bracket], context.recent!.reduce((a, b) => a + b.length, 0), 2);
28
+ }
29
+ return context.state! & State.annotation
26
30
  ? [unshift(as, bs), rest]
27
- : undefined,
28
- [3 | Backtrack.linedoublebracket, 1 | Backtrack.linebracket],
29
- Backtrack.bracket | BacktrackState.nobreak)));
31
+ : undefined;
32
+ },
33
+ [3 | Backtrack.doublebracket, 1 | Backtrack.bracket])));
30
34
 
31
35
  // Chicago-Style
32
36
  const abbr: ReferenceParser.AbbrParser = surround(
@@ -34,14 +38,14 @@ const abbr: ReferenceParser.AbbrParser = surround(
34
38
  union([str(/^(?=[A-Z])(?:[0-9A-Za-z]'?|(?:[-.:]|\.?\??,? ?)(?!['\-.:?, ]))+/)]),
35
39
  /^\|?(?=]])|^\|[^\S\n]*/,
36
40
  true,
37
- ([, ns], rest) => ns ? [['\n', ns[0].trimEnd()], rest.replace(blank.start, '')] : [[''], `^${rest}`],
41
+ ([, ns], rest) => ns ? [[Command.Escape, ns[0].trimEnd()], rest.replace(blank.start, '')] : [[''], `^${rest}`],
38
42
  ([, , rest]) => [[''], `^${rest}`]);
39
43
 
40
44
  function attributes(ns: (string | HTMLElement)[]): Record<string, string | undefined> {
41
45
  switch (ns[0]) {
42
46
  case '':
43
47
  return { class: 'invalid', ...invalid('reference', 'syntax', 'Invalid abbreviation') };
44
- case '\n':
48
+ case Command.Escape:
45
49
  const abbr = ns[1] as string;
46
50
  ns[0] = ns[1] = '';
47
51
  return { class: 'reference', 'data-abbr': abbr };
@@ -1,7 +1,7 @@
1
1
  import { RubyParser } from '../inline';
2
2
  import { Backtrack, Command, CmdRegExp } from '../context';
3
3
  import { eval, exec } from '../../combinator/data/parser';
4
- import { sequence, surround, dup, lazy, fmap } from '../../combinator';
4
+ import { inits, surround, setBacktrack, dup, lazy, bind } from '../../combinator';
5
5
  import { unsafehtmlentity } from './htmlentity';
6
6
  import { text as txt, str } from '../source';
7
7
  import { isTightNodeStart } from '../visibility';
@@ -9,8 +9,8 @@ import { invalid } from '../util';
9
9
  import { unshift, push } from 'spica/array';
10
10
  import { html, defrag } from 'typed-dom/dom';
11
11
 
12
- export const ruby: RubyParser = lazy(() => fmap(
13
- sequence([
12
+ export const ruby: RubyParser = lazy(() => bind(
13
+ inits([
14
14
  dup(surround(
15
15
  '[', str(/^(?:\\[^\n]|[^\\[\](){}<>"\n])+/), ']',
16
16
  false,
@@ -20,7 +20,7 @@ export const ruby: RubyParser = lazy(() => fmap(
20
20
  return ns && isTightNodeStart(ns) ? [ns, rest] : undefined;
21
21
  },
22
22
  undefined,
23
- [3 | Backtrack.ruby])),
23
+ [3 | Backtrack.ruby | 1, Backtrack.link, 1 | Backtrack.bracket])),
24
24
  dup(surround(
25
25
  '(', str(/^(?:\\[^\n]|[^\\[\](){}<>"\n])+/), ')',
26
26
  false,
@@ -29,12 +29,15 @@ export const ruby: RubyParser = lazy(() => fmap(
29
29
  return ns && [ns, rest];
30
30
  },
31
31
  undefined,
32
- [3 | Backtrack.ruby])),
32
+ [3 | Backtrack.ruby | 1, Backtrack.link, 1 | Backtrack.bracket])),
33
33
  ]),
34
- ([texts, rubies]) => {
34
+ ([texts, rubies], rest, context) => {
35
+ if (rubies === undefined) {
36
+ return void setBacktrack(context, [2 | Backtrack.ruby], context.recent!.reduce((a, b) => a + b.length, 0));
37
+ }
35
38
  switch (true) {
36
39
  case rubies.length <= texts.length:
37
- return [
40
+ return [[
38
41
  html('ruby', attributes(texts, rubies), defrag(texts
39
42
  .reduce((acc, _, i) =>
40
43
  push(acc, unshift(
@@ -43,9 +46,9 @@ export const ruby: RubyParser = lazy(() => fmap(
43
46
  ? [html('rp', '('), html('rt', rubies[i]), html('rp', ')')]
44
47
  : [html('rt')]))
45
48
  , []))),
46
- ];
49
+ ], rest];
47
50
  case texts.length === 1 && [...texts[0]].length >= rubies.length:
48
- return [
51
+ return [[
49
52
  html('ruby', attributes(texts, rubies), defrag([...texts[0]]
50
53
  .reduce((acc, _, i, texts) =>
51
54
  push(acc, unshift(
@@ -54,14 +57,14 @@ export const ruby: RubyParser = lazy(() => fmap(
54
57
  ? [html('rp', '('), html('rt', rubies[i]), html('rp', ')')]
55
58
  : [html('rt')]))
56
59
  , []))),
57
- ];
60
+ ], rest];
58
61
  default:
59
62
  assert(rubies.length > 0);
60
- return [
63
+ return [[
61
64
  html('ruby', attributes(texts, rubies), defrag(unshift(
62
65
  [texts.join(' ')],
63
66
  [html('rp', '('), html('rt', rubies.join(' ').trim()), html('rp', ')')]))),
64
- ];
67
+ ], rest];
65
68
  }
66
69
  }));
67
70
 
@@ -7,20 +7,23 @@ import { html } from 'typed-dom/dom';
7
7
  export const template: TemplateParser = lazy(() => surround(
8
8
  '{{',
9
9
  precedence(1,
10
- some(union([bracket, escsource]), '}', [['\n', 9]])),
10
+ some(union([bracket, escsource]), '}')),
11
11
  '}}',
12
12
  true,
13
- ([, ns = []], rest) => [[html('span', { class: 'template' }, `{{${ns.join('')}}}`)], rest],
13
+ ([, ns = []], rest, context) =>
14
+ context.linebreak === undefined
15
+ ? [[html('span', { class: 'template' }, `{{${ns.join('')}}}`)], rest]
16
+ : undefined,
14
17
  undefined,
15
- [3 | Backtrack.linedoublebracket, 1 | Backtrack.lineescbracket]));
18
+ [3 | Backtrack.doublebracket, 1 | Backtrack.bracket]));
16
19
 
17
20
  const bracket: TemplateParser.BracketParser = lazy(() => union([
18
21
  surround(str('('), recursion(Recursion.terminal, some(union([bracket, escsource]), ')')), str(')'), true,
19
- undefined, () => [[], ''], [3 | Backtrack.lineescbracket]),
22
+ undefined, () => [[], ''], [3 | Backtrack.escbracket]),
20
23
  surround(str('['), recursion(Recursion.terminal, some(union([bracket, escsource]), ']')), str(']'), true,
21
- undefined, () => [[], ''], [3 | Backtrack.lineescbracket]),
24
+ undefined, () => [[], ''], [3 | Backtrack.escbracket]),
22
25
  surround(str('{'), recursion(Recursion.terminal, some(union([bracket, escsource]), '}')), str('}'), true,
23
- undefined, () => [[], ''], [3 | Backtrack.lineescbracket]),
26
+ undefined, () => [[], ''], [3 | Backtrack.escbracket]),
24
27
  surround(str('"'), precedence(2, recursion(Recursion.terminal, some(escsource, '"'))), str('"'), true,
25
- undefined, () => [[], ''], [3 | Backtrack.lineescbracket]),
28
+ undefined, () => [[], ''], [3 | Backtrack.escbracket]),
26
29
  ]));
@@ -34,7 +34,6 @@ export const escsource: EscapableSourceParser = ({ source, context }) => {
34
34
  return [[source.slice(0, 2)], source.slice(2)];
35
35
  }
36
36
  case '\n':
37
- assert(false);
38
37
  context.linebreak ??= source.length;
39
38
  return [[source[0]], source.slice(1)];
40
39
  default:
@@ -22,7 +22,6 @@ export const unescsource: UnescapableSourceParser = ({ source, context }) => {
22
22
  consume(1, context);
23
23
  return [[source.slice(1, 2)], source.slice(2)];
24
24
  case '\n':
25
- assert(false);
26
25
  context.linebreak ??= source.length;
27
26
  return [[source[0]], source.slice(1)];
28
27
  default: