securemark 0.297.1 → 0.297.3
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 +8 -0
- package/design.md +1 -1
- package/dist/index.js +69 -70
- package/package.json +1 -1
- package/src/parser/api/bind.ts +2 -0
- package/src/parser/api/parse.test.ts +3 -3
- package/src/parser/inline/annotation.test.ts +1 -1
- package/src/parser/inline/annotation.ts +2 -2
- package/src/parser/inline/extension/indexee.ts +16 -6
- package/src/parser/inline/link.ts +2 -2
- package/src/parser/processor/note.test.ts +57 -40
- package/src/parser/processor/note.ts +62 -78
- package/src/renderer/render.ts +1 -1
package/CHANGELOG.md
CHANGED
package/design.md
CHANGED
|
@@ -293,7 +293,7 @@ Securemarkはブロック単位の差分更新によりリアルタイムレン
|
|
|
293
293
|
|
|
294
294
|
CommonMarkは初手設計ミスったせいで構文一つで最悪計算量32nを叩き出す最悪計算量O(n\*32^m)のクソ言語になり拡張性がなく終わってる。
|
|
295
295
|
|
|
296
|
-
Securemarkの
|
|
296
|
+
SecuremarkのReference構文に典型的であるように文脈を変更する構文の中にその文脈に依存し変更される他の構文が存在する場合文脈の相違から解析結果を再利用不能(`αAβ | αA'B`)なバックトラックが生じる。またこの結果再帰的バックトラックが生じる可能性があり再帰的バックトラックは一般的にメモ化により解決されるがCommonMarkは最小計算量と実行性能を追及するためメモ化を廃止していることからメモ化により性能を低下させてまで文脈依存構文の問題を解決するつもりはないと思われる(すなわちCommonMarkは機械を至上とし人間に制約を課す低水準の言語であり人間の需要と生産性を至上とする高水準の言語であるSecuremarkの対極に位置する)。従ってCommonMarkは再帰的バックトラックなしで解析可能な構文と最小計算量に制約され基本的に再帰的バックトラックが生じるものである文脈依存構文を追加できないという拡張性の欠陥が存在する(CommonMarkは文脈を変えず`*A*`の記号と解釈を変更しただけの`~~A~~`のような文脈自由構文は容易に追加できるが他の構文を包含可能な文脈依存構文はリンク構文で発生している再帰的バックトラックまたはその修正のために激増した計算量を組み合わせ爆発により指数関数的に致命的に悪化させるため追加できない。例えばすでに最悪計算量32nであるリンク構文を包含した追加構文が1回バックトラックするだけで最悪計算量が32n\*2=64nに悪化し追加構文がリンク構文と同じく最悪計算量32nなら全体の最悪計算量は32n\*32=n\*32^2=1024nとなる。すなわちCommonMarkの最悪計算量は再帰的バックトラックが生じる構文の数mに対してO(n\*32^m)と驚異的かつ絶望的に劣悪な計算量であり構文数が一つであろうと自己再帰可能ならば入れ子数mに対して同じくO(n\*32^m)となる。なお一般的に実用可能な計算量の上限はO(n^3)であるためCommonMarkは文脈依存構文数または入れ子数m>3になるだけで実用可能な計算量の上限を超える。すなわちCommonMarkは自己再帰可能な文脈依存構文を定義することが不可能である。この事実に開発開始から数年後に直面し再帰数の上限を32回に制限することで指数計算量を防ぐも依然として32nという非常識な計算量になっているのがリンク構文とイメージ構文である。なおリンク構文とイメージ構文を入れ子にできているのはイメージ構文を入れる角括弧部分が文脈自由部分だからであり文脈依存部分である丸括弧部分は入れ子になっておらず文脈依存部分の入れ子が生じていないからである。しかし文脈依存構文を追加してリンク構文を包含すれば丸括弧部分を包含し文脈依存部分が入れ子になり計算量の爆発を避けられない)。CommonMarkの仕様策定者が構文の拡張に(名称を維持するか否かにかかわらず)不自然なまでに消極的であり進展がないのは正当な理由や単なる怠慢からでなく構文追加可否を議論すればCommonMarkは理論的欠陥により最悪計算量が絶望的に劣悪であるため文脈依存構文を追加できないというCommonMarkの設計の破綻と失敗が明らかになることが避けられないためおよび最小計算量を放棄して現在の高い実行性能を低下させたくないためであり陳腐な自尊心を守るためにこのような計算量と拡張性の根本的欠陥を秘匿しCommonMarkとその仕様策定者である自分の評価が下がらないよう画策しているからである。でなければこの計算量と拡張性の根本的欠陥を何年も隠蔽せず速やかに公表して助力を求めていなければならず不都合な事実を隠し陳腐な自尊心を守るために全Markdown利用者および開発者を不必要に足止めした罪は重い。
|
|
297
297
|
CommonMarkは小さく単純であるうちだけ破綻せずに正しく見せかけられる象牙の塔であり仕様策定者はこの見せかけの正しさを失わず正しいままでいたいがために象牙の塔に引きこもり小さな表面的正しさに固執し続けているに過ぎない。しかしCommonMarkは実際にはすでに致命的に破綻しており本来文脈依存言語であるMarkdownを文脈自由言語として解析しようとして失敗したことで指数計算量(正確には指数計算量より悪い階乗計算量)になっており実際のところCommonMarkは最初から最後までずっと壊れている。CommonMarkは可能な限り文脈自由言語として設計することでバックトラックなく最小計算量で解析しようとしているが実際には文脈依存言語であるMarkdownから文脈依存構文を文脈自由構文に変換して再帰的バックトラックを除去することに失敗しているためCommonMarkは最初の数年間は再帰的バックトラックに気づかず最悪計算量が指数計算量になっており修正後も依然として最悪計算量が当初の想定の1nから32nへと劇的に悪化している(より正確にはCommonMarkは少なくともCode構文とHTML構文により+2nされるが説明の簡略化のため省略しこれら以外のInline構文のみを比較する)。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は仕様策定が停滞し未だに1nの最小計算量に固執しているがそんなものはCommonMarkの破綻と失敗が露呈するを恐れて隠蔽しまたとっくの昔に破綻している最小計算量のための設計に未練がましく執着しているだけである。32nという最悪計算量は適切に設計し計算量が抑制された文脈依存言語の最悪計算量より悪く最初から文脈依存言語として適切に設計するほうが自然で破綻がなく拡張性を確保できていた。たった一つの構文だけで最悪計算量が32nも増加するクソ言語に拡張性がないことは明らかである。さらにSecuremarkは再帰的バックトラックを予め対策して設計されているため文脈依存構文数が増えても最悪計算量はたかだか構文数に比例して線形にしか増加しないのに対してCommonMarkは再帰的バックトラックに根本的対策を取れないため文脈依存構文数が増えると最悪計算量が指数関数的に致命的に爆発する。または計算量を組み合わせ爆発させないために文脈依存構文の入れ子使用を制限する、存在自体が破綻と失敗の宣言に等しい制限が必要になる。文脈依存構文を強引に文脈自由構文として解析しようとして失敗したために最悪計算量が当初の想定の1nから32nに劇的に悪化し結局文脈依存言語の妥当な最悪計算量より悪い水準に落ちていることおよび文脈依存構文を追加すると最悪計算量が指数関数的に悪化することから文脈自由化に失敗したCommonMarkの破綻と失敗は明らかでありCommonMarkは文脈自由構文に固執せず最初から多少の文脈依存構文を許容するよう設計しなければならなかった。実際には文脈依存言語であるにもかかわらず文脈自由言語の範囲でしか構文解析できなければ構文解析が破綻し構文が増えるほど破綻が拡大することは自明でありすでに破綻済みで失敗済みのCommonMarkに未来などない。文脈依存言語であるMarkdownに対して文脈自由構文解析器として作られたCommonMarkは最初から開発戦略と技術選択を間違え失敗しており最初から破綻していた。CommonMarkが文脈依存言語を文脈自由言語として最小計算量で解析するために使用した手法は邪道の小手先の技術に過ぎずCommonMarkは邪道を選んだ挙句失敗に終わったのである。文脈依存言語を文脈依存言語のまま解析する正道を選んだSecuremarkが正着し文脈依存言語を文脈自由言語に歪める邪道を選んだCommonMarkが失着に終わったのは当然の帰結であり最初の解析戦略時選択の時点で決まっていたことである。文脈依存言語であるMarkdownを文脈自由言語として解析しようとした結果行き詰ったCommonMarkとその閉塞に技術的合理性はなくCommonMarkは最初からの失敗していた過去の遺物であり廃棄すべき負債である。CommonMarkに動きがないのはすでに破綻しており死んでいることに気付かれないように死んでいるからに過ぎない。このようにCommonMarkは完全に破綻し失敗に終わっているためCommonMarkの拡張や発展を期待しても無駄であり既存の文脈依存構文の最悪計算量を健全化し新たに文脈依存構文を追加可能な拡張性の高いMarkdown仕様は新しく作り直さなければ作れない。しかしCommonMarkの仕様策定者は独自の新しい仕様においても依然としてMarkdownを文脈自由化して文脈自由言語として設計しているため文脈依存構文を追加すると指数計算量になり救いようがない。しかもその構文と仕様は機械可読性を至上としているため非常に醜く人間が書くことも読むことも困難で人間に対する実用性が欠如している。
|
|
298
298
|
Securemarkはスーパークラス構文が解析に失敗した入力をサブクラス構文で解析しないことにより再帰的バックトラックを回避する(解析中の構文自身はスーパークラスとサブクラスの両方に含まれるものとする)。スーパークラス構文A(`αAβ`)の解析が失敗すればサブクラス構文B(`α'Aβ'`)の解析も失敗することは自明であり試みるまでもなく解析を省略できる。これは二つの構文の文法が生成する各言語空間がスーパーセットとサブセットの関係にあるならスーパーセットの言語空間の外にある文字列はサブセットの言語空間の内に入る余地がないことからも自明である(この解析法は事前解析によっても可能だが文脈内外のオートリンクURLの括弧解析などを高速に行うこともバックトラックなしで解析することも困難であり本解析に近い解析コストを要するためMarkdownをこの事前解析により高速化することは難しい)。メモ化は解析結果の再利用による高速化の副次的または追加的効果として再帰的バックトラックを回避しているのでありメモ化は再帰的バックトラックを回避するだけなら過剰であり不要である(メモ化はバックトラックがなければ使用されないためバックトラックが少ないほとんどの入力に対してはほとんど使用されず無駄であり空間計算量を不必要に常時数倍以上増加させることから構文解析において必須にも標準にもできない。再帰的バックトラック回避のためにメモ化するとバックトラックなしで解析可能な場合も常に不必要に空間計算量が増加し平均計算量が有意に悪化することがメモ化の最大の欠点である(この問題は解析失敗時のみメモ化すれば解消可能のはずだが基本的にはこうなる)。特に文脈自由構文解析器におけるメモ化の使用は完全に無駄でありバグである。バックトラックが発生しないか他の方法で解決されるならば使用されず破棄されるメモ化は無駄である。複数の文脈で解析結果が同一である文脈独立性のある構文ならメモ化した解析結果を異なる文脈で再利用でき有用だがそのような構文は基本的に少数であるため効果が限定的であり最悪計算量は改善されない。文脈依存構文の解析を困難にするメモ化のコストの重さは解析に本来不要な高速化のために生じておりメモ化からバックトラックがない通常時も常時高コストで低速化し平均実行速度とスループットを低下させるバックトラック時限定の不要な高速化とこのためのコストを除去すれば再帰的バックトラック回避機能だけを低コストで標準的に使用しこれまで高コストであったため敷居が高く使用困難であった文脈依存言語を低コストで手軽に定義および解析できるようになる。もうCommonMarkのように低機能のくせに最悪計算量が劣悪で拡張不能なクソ言語を我慢して使い続けなくてよくなるのである)。この解析法により、CommonMarkならば最悪計算量がn\*32^5=33,554,432nとなる拡張Markdown言語をSecuremarkはメモ化なしで5nの最悪時間計算量で解析している。言語差を考慮せず直接比較してさえ単純なCommonMarkの最悪計算量32nに対して複雑なSecuremarkは5nに過ぎずSecuremarkはCommonMarkより最悪計算量が非常に小さい。またSecuremarkはメモ化を行っていないため空間計算量も小さい。時間計算量と空間計算量を合わせてO(n, n)と表記すると文脈依存言語の通常の最悪計算量はO(n^2, n)、メモ化により効率化できた場合もO(nm, nm)(S(m)>=m byte)(解析結果の位置や構文木等を記録するため空間使用量S(m)>はm byte以上となり数値一つやポインタ一つだけでも8byteを消費する)に過ぎないが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の再帰数制限はパーサーコンビネーターの使用による再帰的関数呼び出しに対する実装方式依存の制限であるため計算量と無関係であり再帰的関数呼び出しが生じないよう書き換えれば再帰数制限もない。従ってCommonMarkは再帰上限数と最悪計算量が一致し再帰上限数32回と最悪計算量32nが一致するがSecuremarkの最悪計算量は再帰上限数が100回だろうと100万回だろうと5n固定である。SecuremarkをCommonMarkのような再帰数制限のない実装に変換することは設計上および理論的に何の問題もないがCommonMarkをSecuremarkのような正常な文脈依存言語解析器に変更することは現在の異常な解析規則の破壊的変更による修正なしに不可能である。具体的には二重リンク`[[]()]()`を解析するときCommonMarkはバックトラックと計算量を最小化すべく文脈自由構文解析器として設計されているためリンク構文内をリンク構文が定義されていない異なる文脈として解析せず外側のリンク構文の解析を破棄して内側のみリンク構文として解析するがSecuremarkは文脈依存構文解析器とし設計されているためリンク構文内にリンク構文が定義されておらず外側のみリンクとして解析し他のMarkdown構文解析器もこのように解析しなければならない(ここでCommonMarkはリンク構文`[]()`のバックトラック除去ひいては文脈自由化に角括弧部分`[]`に対しては成功したが丸括弧部分`()`に対しては失敗したことで最悪計算量が指数計算量ないし32nに悪化した。リンク構文を本来通り文脈依存構文として解析すればリンク構文の最悪計算量が2nとなり角括弧部分に限っては1nから2nに悪化するが丸括弧部分は32nから2nに著しく改善する。ここがCommonMarkの根本的な欠陥と失敗が最も明瞭に表出している部分である)。この問題はイメージ構文においてさらに顕著でありリンク構文と同じ問題が正当な表現`![![]()]()`で発生しさらにHTMLのaltはプレーンテキストとして表示されるためMarkdownのaltもプレーンテキストとしてそのまま表示されなければならないにもかかわらず文脈を一致させ再帰的バックトラックを防ぐためにMarkdown文字列として解析しaltに`*a*`と書かれたものを`a`に不正に変換して表示する。無論新しい文脈依存構文を追加する場合も同じ制約が永遠についてまわり構文内文字列をMarkdownとして解析する文脈依存構文においてこの制約を破ると最悪計算量が32\*2^mないし32^mで指数関数的に増加する。すなわちCommonMarkは文脈依存構文を追加すると最悪計算量が32\*2^mないし32^mで指数関数的に悪化するという拡張性の致命的欠陥が存在する。こんな最悪計算量が32^mで組み合わせ爆発する欠陥言語を拡張できるわけがないことはもはや明白である。また大多数のプログラミング言語を見ても明らかなように文脈依存言語は構文内で使用可能な構文を定義しその他の構文は使用できず例外処理するのが通常でありCommonMarkのように本来使用不能な構文を外側の構文を無効化して使用可能に変える異常な言語はほとんどの人間はCommonMark以外に見たことがないだろう。ほぼすべての人間において他のすべての言語が同じ一貫した規則を持ち同じ規則で統一的に使用できるのに対してCommonMarkだけが他と異なる異常な挙動をして使用者に認知的負荷をかけるのである。破壊的変更を避けるため旧構文だけ従来通り文脈自由構文として解析し新構文を文脈依存構文として解析すればキメラ的な非常に不自然かつ歪で一貫性のない解析規則によりCommonMarkという一つの言語の中だけでもユーザーを混乱させるものとなり旧構文で使用した苦肉の策を不必要に新構文でも使用して一貫させれば文脈依存言語なのに文脈自由言語の苦肉の策の解析規則で解析されるこれもまたキメラ的な非常に不自然かつ理論的に設計ミスが明白で実用的にも認知的負荷の高い言語となる。正しく設計された言語と解析器にはありえないこのような解析規則の根本的不整合はその不整合の存在そのものが言語と解析器が誤った設計による失敗作であることを証明しており不整合が存在する限りその不整合により自らが失敗作であることを宣言し続けることになる。CommonMarkとはそういう失敗した言語と解析器なのである。このようにCommonMarkは新構文だけまたは解析器だけ文脈依存に変更しても理論的齟齬が解析結果と使用感の不自然さと違和感に明白に表れるためCommonMarkが失敗した言語である事実は到底隠し切れるものではない。Markdownはもはや負債以外の何物でもないCommonMarkの異常な解析規則を捨てて素直な文脈依存構文言語として新しい仕様を作り直すのが賢明である。
|
|
299
299
|
文脈依存言語を再帰的バックトラックなしで解析可能な方法は2つある。一つは解釈を予言的に決定する方法、もう一つは予備的または中間的その他事前の解析結果に対する解釈を事後に決定する方法である。前者は構文を峻別するための制約が強く後者は共通構造の適切な設計が必要でありいずれも再帰的バックトラックを防ぐために未終端の構文も受理する必要がある。しかし予言的解析は類似の異文脈構文へのバックトラックが不可能になるため共通構造についての事前解析結果のような追加情報を利用できるのでなければ類似の異文脈構文の定義が不可能になる。また共通構造をバックトラックなしで解析するにはそのための言語設計が必要であることに変わりなく任意の文字列を使用可能である必要があるURL、コード、数式などに含まれる任意の文字列が他の構文と文脈で解釈される際に共通構造を破壊するためこのような文字列を構造的に決定的に解釈する基本構造(バックトラック可能だが入力に対する解析結果がすべての文脈で構造的に共通すなわち決定的でなければならない。構文が解析されない場合も構文全体が包含されれば問題ない)を共通構造に定義しなければ構造的共通化は不可能であり分離構造は終端不要な開放可能構文としての予言的構文でなければバックトラックが不可避となる。共通構造の事前解析は一見すると最悪計算量を2nに削減できるように見えるが実際には共通構造をバックトラックなしで解析することが元の言語より容易にはなっても依然として難しくバックトラックなしで解析できたとしてもすべての解析ひいては平均計算量が+1nされるため平均的にはむしろ計算量を悪化させる方法であり仮に最悪計算量32nを事前解析により2nに抑えられたとしても平均計算量が1nならば平均計算量が2nに倍加し実行性能が半減および実行コストが倍加するため明らかに事前解析を行うべきでない。実用的なアルゴリズムの計算量において重要なのは最悪計算量がO(n^3)相当以下の実用的な計算量であるかと平均計算量でありその他は重要ではない。メモ化が空間計算量を代償に悪化させる最悪時間計算量線形化手法であるのに対して事前解析は平均時間計算量を代償に悪化させる最悪時間計算量線形化手法でありマーキング法は何も代償に悪化させない最悪時間計算量線形化手法である(無論ゼロコストではないが解析の他の部分やASTに要するコストより小さいため無視できる。空間計算量は実際にはASTにより容易に数倍になりメモリ使用量は入力サイズと並列数に制約されるため空間計算量自体はさほど重要ではなく空間計算量を増加させる処理により生じる時間オーバーヘッドのほうが本質的に重要となる。メモ化が常時記録かつ実データ記録ゆえデータ数もデータサイズも大きいのに対してマーキング法は失敗時記録かつフラグのみ記録ゆえデータ数もデータサイズも小さいことでオーバーヘッドが最小化されバックトラック率の低い入力が大多数を占める場合の平均実行速度が高速化される。平均性能すなわち重要指標が向上するならばその他の指標は許容範囲内で悪化させることができ不要な指標値を必要な指標値に変換できるならばそうしなければならない)。なおマーキング法を使用するSecuremarkは本来の構文解析と共通構造解析を統合し同時解析することで計算量の増加なく共通構造解析を行い共通構造を利用して最悪時間計算量を指数計算量から5nへ削減している。
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! securemark v0.297.
|
|
1
|
+
/*! securemark v0.297.3 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"));
|
|
@@ -4302,6 +4302,12 @@ function bind(target, settings) {
|
|
|
4302
4302
|
type: 'cancel'
|
|
4303
4303
|
};
|
|
4304
4304
|
}
|
|
4305
|
+
yield {
|
|
4306
|
+
type: 'break'
|
|
4307
|
+
};
|
|
4308
|
+
if (rev !== revision) return yield {
|
|
4309
|
+
type: 'cancel'
|
|
4310
|
+
};
|
|
4305
4311
|
for (const el of (0, figure_1.figure)(next(0)?.parentNode ?? target, settings.notes, context)) {
|
|
4306
4312
|
el ? yield {
|
|
4307
4313
|
type: 'figure',
|
|
@@ -6323,7 +6329,7 @@ const bracket_1 = __webpack_require__(4526);
|
|
|
6323
6329
|
const visibility_1 = __webpack_require__(6364);
|
|
6324
6330
|
const util_1 = __webpack_require__(4992);
|
|
6325
6331
|
const dom_1 = __webpack_require__(394);
|
|
6326
|
-
exports.annotation = (0, combinator_1.lazy)(() => (0, combinator_1.constraint)(128 /* State.annotation */, (0, combinator_1.surround)((0, combinator_1.
|
|
6332
|
+
exports.annotation = (0, combinator_1.lazy)(() => (0, combinator_1.constraint)(128 /* State.annotation */, (0, combinator_1.surround)((0, combinator_1.open)('((', visibility_1.beforeNonblank), (0, combinator_1.precedence)(1, (0, combinator_1.recursion)(4 /* Recursion.inline */, (0, combinator_1.recursion)(5 /* Recursion.bracket */, (0, combinator_1.recursion)(5 /* Recursion.bracket */, (0, combinator_1.some)((0, combinator_1.union)([inline_1.inline]), ')', [[')', 1]]))))), '))', false, [], ([, ns], context) => {
|
|
6327
6333
|
const {
|
|
6328
6334
|
linebreak
|
|
6329
6335
|
} = context;
|
|
@@ -7123,7 +7129,7 @@ function baseR(n, r) {
|
|
|
7123
7129
|
return acc;
|
|
7124
7130
|
}
|
|
7125
7131
|
function signature(target) {
|
|
7126
|
-
for (let es = target.querySelectorAll('code[data-src], .math[data-src], .remark, rt, rp, br, .annotation, .reference, :is(.annotation, .reference) > a, .checkbox, ul, ol, .label[data-label]'),
|
|
7132
|
+
for (let es = target.querySelectorAll('code[data-src], .math[data-src], .remark, rt, rp, br, .annotation, .reference, :is(.annotation, .reference) > a, .checkbox, ul, ol, .label[data-label]'), i = es.length; i--;) {
|
|
7127
7133
|
const el = es[i];
|
|
7128
7134
|
switch (el.className) {
|
|
7129
7135
|
case 'math':
|
|
@@ -7132,10 +7138,15 @@ function signature(target) {
|
|
|
7132
7138
|
case 'label':
|
|
7133
7139
|
el.replaceWith(`[$${el.getAttribute('data-label').replace('$', '')}]`);
|
|
7134
7140
|
continue;
|
|
7135
|
-
case 'checkbox':
|
|
7136
|
-
case 'remark':
|
|
7137
7141
|
case 'annotation':
|
|
7142
|
+
el.replaceWith(`((${el.textContent}))`);
|
|
7143
|
+
continue;
|
|
7138
7144
|
case 'reference':
|
|
7145
|
+
const abbr = el.getAttribute('data-abbr');
|
|
7146
|
+
el.replaceWith(`[[${abbr ? `^${abbr}` : el.textContent}]]`);
|
|
7147
|
+
continue;
|
|
7148
|
+
case 'checkbox':
|
|
7149
|
+
case 'remark':
|
|
7139
7150
|
el.remove();
|
|
7140
7151
|
continue;
|
|
7141
7152
|
}
|
|
@@ -7159,16 +7170,21 @@ function signature(target) {
|
|
|
7159
7170
|
}
|
|
7160
7171
|
exports.signature = signature;
|
|
7161
7172
|
function text(target) {
|
|
7162
|
-
for (let es = target.querySelectorAll('code[data-src], .math[data-src], .remark, rt, rp, br, .annotation, .reference, :is(.annotation, .reference) > a, .checkbox, ul, ol'),
|
|
7173
|
+
for (let es = target.querySelectorAll('code[data-src], .math[data-src], .remark, rt, rp, br, .annotation, .reference, :is(.annotation, .reference) > a, .checkbox, ul, ol'), i = es.length; i--;) {
|
|
7163
7174
|
const el = es[i];
|
|
7164
7175
|
switch (el.className) {
|
|
7165
7176
|
case 'math':
|
|
7166
7177
|
el.replaceWith(el.getAttribute('data-src'));
|
|
7167
7178
|
continue;
|
|
7168
|
-
case 'checkbox':
|
|
7169
|
-
case 'remark':
|
|
7170
7179
|
case 'annotation':
|
|
7180
|
+
el.replaceWith(`((${el.textContent}))`);
|
|
7181
|
+
continue;
|
|
7171
7182
|
case 'reference':
|
|
7183
|
+
const abbr = el.getAttribute('data-abbr');
|
|
7184
|
+
el.replaceWith(`[[${abbr ? `^${abbr}` : el.textContent}]]`);
|
|
7185
|
+
continue;
|
|
7186
|
+
case 'checkbox':
|
|
7187
|
+
case 'remark':
|
|
7172
7188
|
el.remove();
|
|
7173
7189
|
continue;
|
|
7174
7190
|
}
|
|
@@ -7486,7 +7502,7 @@ const optspec = {
|
|
|
7486
7502
|
rel: ['nofollow']
|
|
7487
7503
|
};
|
|
7488
7504
|
Object.setPrototypeOf(optspec, null);
|
|
7489
|
-
exports.textlink = (0, combinator_1.lazy)(() => (0, combinator_1.bind)((0, combinator_1.subsequence)([(0, combinator_1.constraint)(8 /* State.link */, (0, combinator_1.state)(251 /* State.linkers */, (0, combinator_1.dup)((0, combinator_1.surround)((0, combinator_1.
|
|
7505
|
+
exports.textlink = (0, combinator_1.lazy)(() => (0, combinator_1.bind)((0, combinator_1.subsequence)([(0, combinator_1.constraint)(8 /* State.link */, (0, combinator_1.state)(251 /* State.linkers */, (0, combinator_1.dup)((0, combinator_1.surround)((0, combinator_1.open)('[', visibility_1.beforeNonblank), (0, combinator_1.precedence)(1, (0, combinator_1.some)((0, combinator_1.union)([inline_1.inline]), ']', [[']', 1]])), ']', true, [3 | 4 /* Backtrack.common */ | 64 /* Backtrack.link */, 2 | 32 /* Backtrack.ruby */], ([, ns = new parser_1.List()], context) => {
|
|
7490
7506
|
if (context.linebreak !== 0) {
|
|
7491
7507
|
const head = context.position - context.range;
|
|
7492
7508
|
return void (0, combinator_1.setBacktrack)(context, 2 | 64 /* Backtrack.link */ | 32 /* Backtrack.ruby */, head);
|
|
@@ -8265,25 +8281,33 @@ function capitalize(label) {
|
|
|
8265
8281
|
Object.defineProperty(exports, "__esModule", ({
|
|
8266
8282
|
value: true
|
|
8267
8283
|
}));
|
|
8268
|
-
exports.
|
|
8284
|
+
exports.note = void 0;
|
|
8269
8285
|
const indexee_1 = __webpack_require__(7610);
|
|
8270
8286
|
const util_1 = __webpack_require__(4992);
|
|
8271
8287
|
const memoize_1 = __webpack_require__(6925);
|
|
8272
8288
|
const dom_1 = __webpack_require__(394);
|
|
8273
8289
|
function* note(target, notes, opts = {}, bottom = null) {
|
|
8274
|
-
|
|
8275
|
-
|
|
8290
|
+
const referenceRefMemory = referenceRefsMemoryCaller(target);
|
|
8291
|
+
const annotationRefMemory = annotationRefsMemoryCaller(target);
|
|
8292
|
+
for (const memory of [referenceRefMemory, annotationRefMemory]) {
|
|
8293
|
+
for (const [ref, {
|
|
8294
|
+
content
|
|
8295
|
+
}] of memory) {
|
|
8296
|
+
ref.replaceChildren(content);
|
|
8297
|
+
}
|
|
8298
|
+
memory.clear();
|
|
8299
|
+
}
|
|
8300
|
+
yield* reference(referenceRefMemory, target, notes?.references, opts, bottom);
|
|
8301
|
+
yield* annotation(annotationRefMemory, target, notes?.annotations, opts, bottom);
|
|
8276
8302
|
}
|
|
8277
8303
|
exports.note = note;
|
|
8278
|
-
|
|
8279
|
-
|
|
8280
|
-
|
|
8281
|
-
|
|
8282
|
-
function build(syntax,
|
|
8283
|
-
splitter &&= `${splitter}, .${
|
|
8284
|
-
|
|
8285
|
-
return function* (target, note, opts = {}, bottom = null) {
|
|
8286
|
-
const refMemory = refMemoryCaller(target);
|
|
8304
|
+
const annotationRefsMemoryCaller = (0, memoize_1.memoize)(target => new Map() ?? target, new WeakMap());
|
|
8305
|
+
const referenceRefsMemoryCaller = (0, memoize_1.memoize)(target => new Map() ?? target, new WeakMap());
|
|
8306
|
+
const annotation = build('annotation', 'annotations', '.annotation:not(:is(.annotations, .references) .annotation, .disabled)', n => `*${n}`, 'h1, h2, h3, h4, h5, h6, aside.aside, hr');
|
|
8307
|
+
const reference = build('reference', 'references', '.reference:not(:is(.annotations, .references) .reference, .disabled)', (n, abbr) => `[${abbr || n}]`);
|
|
8308
|
+
function build(syntax, list, query, marker, splitter = '') {
|
|
8309
|
+
splitter &&= `${splitter}, .${list}`;
|
|
8310
|
+
return function* (memory, target, note, opts = {}, bottom = null) {
|
|
8287
8311
|
const refInfoCaller = (0, memoize_1.memoize)(ref => {
|
|
8288
8312
|
const content = ref.firstElementChild;
|
|
8289
8313
|
const abbr = ref.getAttribute('data-abbr') ?? '';
|
|
@@ -8296,16 +8320,9 @@ function build(syntax, plural, marker, splitter = '') {
|
|
|
8296
8320
|
abbr,
|
|
8297
8321
|
text: txt
|
|
8298
8322
|
};
|
|
8299
|
-
},
|
|
8300
|
-
for (const [ref, {
|
|
8301
|
-
content
|
|
8302
|
-
}] of refMemory) {
|
|
8303
|
-
content.replaceWith(content.cloneNode(true));
|
|
8304
|
-
ref.replaceChildren(content);
|
|
8305
|
-
refMemory.delete(ref);
|
|
8306
|
-
}
|
|
8323
|
+
}, memory);
|
|
8307
8324
|
const defs = new Map();
|
|
8308
|
-
const refs = target.querySelectorAll(
|
|
8325
|
+
const refs = target.querySelectorAll(query);
|
|
8309
8326
|
const identifierInfoCaller = (0, memoize_1.memoize)(identifier => ({
|
|
8310
8327
|
defIndex: 0,
|
|
8311
8328
|
defSubindex: 0,
|
|
@@ -8321,18 +8338,19 @@ function build(syntax, plural, marker, splitter = '') {
|
|
|
8321
8338
|
let refIndex = 0;
|
|
8322
8339
|
for (let len = refs.length, i = 0; i < len; ++i) {
|
|
8323
8340
|
const ref = refs[i];
|
|
8324
|
-
if (splitter) for (let
|
|
8341
|
+
if (splitter) for (let splitter; splitter = splitters[iSplitters]; ++iSplitters) {
|
|
8342
|
+
const pos = splitter?.compareDocumentPosition(ref) ?? 0;
|
|
8343
|
+
if (pos & (Node.DOCUMENT_POSITION_PRECEDING | Node.DOCUMENT_POSITION_DISCONNECTED)) break;
|
|
8325
8344
|
if (~iSplitters << 32 - 8 === 0) yield;
|
|
8326
|
-
if (
|
|
8327
|
-
|
|
8328
|
-
el.remove();
|
|
8345
|
+
if (splitter.classList.contains(list) && defs.size === 0) {
|
|
8346
|
+
splitter.remove();
|
|
8329
8347
|
continue;
|
|
8330
8348
|
}
|
|
8331
8349
|
if (defs.size > 0) {
|
|
8332
8350
|
total += defs.size;
|
|
8333
|
-
const note =
|
|
8334
|
-
class:
|
|
8335
|
-
}),
|
|
8351
|
+
const note = splitter.classList.contains(list) ? splitter : target.insertBefore((0, dom_1.html)('ol', {
|
|
8352
|
+
class: list
|
|
8353
|
+
}), splitter);
|
|
8336
8354
|
yield* proc(defs, note);
|
|
8337
8355
|
}
|
|
8338
8356
|
}
|
|
@@ -8394,17 +8412,15 @@ function build(syntax, plural, marker, splitter = '') {
|
|
|
8394
8412
|
}, `^${++refIndex}`));
|
|
8395
8413
|
}
|
|
8396
8414
|
if (note || defs.size > 0) {
|
|
8397
|
-
const
|
|
8398
|
-
note
|
|
8399
|
-
class:
|
|
8400
|
-
}),
|
|
8401
|
-
yield* proc(defs, note);
|
|
8415
|
+
const splitter = splitters[iSplitters++];
|
|
8416
|
+
yield* proc(defs, note ?? (splitter?.classList.contains(list) ? splitter : target.insertBefore((0, dom_1.html)('ol', {
|
|
8417
|
+
class: list
|
|
8418
|
+
}), splitter ?? bottom)));
|
|
8402
8419
|
}
|
|
8403
|
-
if (splitter) for (let
|
|
8420
|
+
if (splitter) for (let splitter; splitter = splitters[iSplitters]; ++iSplitters) {
|
|
8404
8421
|
if (~iSplitters << 32 - 8 === 0) yield;
|
|
8405
|
-
if (
|
|
8406
|
-
|
|
8407
|
-
el.remove();
|
|
8422
|
+
if (splitter.classList.contains(list)) {
|
|
8423
|
+
splitter.remove();
|
|
8408
8424
|
}
|
|
8409
8425
|
}
|
|
8410
8426
|
};
|
|
@@ -8413,30 +8429,13 @@ function* proc(defs, note) {
|
|
|
8413
8429
|
const {
|
|
8414
8430
|
children
|
|
8415
8431
|
} = note;
|
|
8416
|
-
|
|
8417
|
-
|
|
8418
|
-
let length = children.length;
|
|
8419
|
-
I: for (const [key, def] of defs) {
|
|
8420
|
-
defs.delete(key);
|
|
8421
|
-
++count;
|
|
8422
|
-
for (; length > size;) {
|
|
8423
|
-
const node = children[count - 1];
|
|
8424
|
-
if (equal(node, def)) continue I;
|
|
8425
|
-
yield note.removeChild(node);
|
|
8426
|
-
--length;
|
|
8427
|
-
}
|
|
8428
|
-
const node = count <= length ? children[count - 1] : null;
|
|
8429
|
-
if (node && equal(node, def)) continue;
|
|
8430
|
-
yield note.insertBefore(def, node);
|
|
8431
|
-
++length;
|
|
8432
|
-
}
|
|
8433
|
-
for (; length > size;) {
|
|
8434
|
-
yield note.removeChild(children[size]);
|
|
8435
|
-
--length;
|
|
8432
|
+
for (let defs = note.children, i = defs.length; i--;) {
|
|
8433
|
+
yield note.removeChild(children[i]);
|
|
8436
8434
|
}
|
|
8437
|
-
|
|
8438
|
-
|
|
8439
|
-
|
|
8435
|
+
for (const [, def] of defs) {
|
|
8436
|
+
yield note.appendChild(def);
|
|
8437
|
+
}
|
|
8438
|
+
defs.clear();
|
|
8440
8439
|
}
|
|
8441
8440
|
|
|
8442
8441
|
/***/ },
|
|
@@ -9357,7 +9356,7 @@ const math_1 = __webpack_require__(3165);
|
|
|
9357
9356
|
const media_1 = __webpack_require__(3567);
|
|
9358
9357
|
const memoize_1 = __webpack_require__(6925);
|
|
9359
9358
|
const query_1 = __webpack_require__(2282);
|
|
9360
|
-
const selector = '
|
|
9359
|
+
const selector = ':not(.invalid):is(.media:is(img:not([src])[data-src], a > :not(img).media), pre.code, .math)';
|
|
9361
9360
|
const extend = (0, memoize_1.reduce)(opts => ({
|
|
9362
9361
|
code: code_1.code,
|
|
9363
9362
|
math: math_1.math,
|
package/package.json
CHANGED
package/src/parser/api/bind.ts
CHANGED
|
@@ -124,6 +124,8 @@ export function bind(target: DocumentFragment | HTMLElement | ShadowRoot, settin
|
|
|
124
124
|
yield { type: 'block', value: el };
|
|
125
125
|
if (rev !== revision) return yield { type: 'cancel' };
|
|
126
126
|
}
|
|
127
|
+
yield { type: 'break' };
|
|
128
|
+
if (rev !== revision) return yield { type: 'cancel' };
|
|
127
129
|
for (const el of figure(next(0)?.parentNode ?? target, settings.notes, context)) {
|
|
128
130
|
assert(rev === revision);
|
|
129
131
|
el
|
|
@@ -216,12 +216,12 @@ describe('Unit: parser/api/parse', () => {
|
|
|
216
216
|
[...parse('$-a\n$$\n$$\n\n(($-a[[^B]]))[[^B|$-a]]', { notes }).children].map(el => el.outerHTML),
|
|
217
217
|
[
|
|
218
218
|
'<figure data-type="math" data-label="$-a" data-group="$" data-number="1" id="label:$-a"><figcaption><span class="figindex">(1)</span><span class="figtext"></span></figcaption><div><div class="math" translate="no">$$\n$$</div></div></figure>',
|
|
219
|
-
'<p><sup class="annotation" id="annotation::ref:[$-a]:1" title="(1)"><a href="#annotation::def:[$-a]:1">*1</a></sup><sup class="reference" data-abbr="B" id="reference::ref:B:
|
|
220
|
-
'<ol class="annotations"><li id="annotation::def:[$-a]:1" data-marker="*1"><span><a class="label" data-label="$-a" href="#label:$-a">(1)</a><sup class="reference" data-abbr="B" id="reference::ref:B:
|
|
219
|
+
'<p><sup class="annotation" id="annotation::ref:[$-a][[^B]]:1" title="(1)[[^B]]"><a href="#annotation::def:[$-a][[^B]]:1">*1</a></sup><sup class="reference" data-abbr="B" id="reference::ref:B:2" title="(1)"><a href="#reference::def:B">[B]</a></sup></p>',
|
|
220
|
+
'<ol class="annotations"><li id="annotation::def:[$-a][[^B]]:1" data-marker="*1"><span><a class="label" data-label="$-a" href="#label:$-a">(1)</a><sup class="reference" data-abbr="B" id="reference::ref:B:1" title="(1)"><a href="#reference::def:B">[B]</a></sup></span><sup><a href="#annotation::ref:[$-a][[^B]]:1">^1</a></sup></li></ol>',
|
|
221
221
|
]);
|
|
222
222
|
assert.deepStrictEqual(
|
|
223
223
|
notes.references.outerHTML,
|
|
224
|
-
'<ol><li id="reference::def:B"><span><a class="label" data-label="$-a" href="#label:$-a">(1)</a></span><sup><a href="#reference::ref:B:1"
|
|
224
|
+
'<ol><li id="reference::def:B"><span><a class="label" data-label="$-a" href="#label:$-a">(1)</a></span><sup><a href="#reference::ref:B:1">^1</a><a href="#reference::ref:B:2" title="(1)">^2</a></sup></li></ol>');
|
|
225
225
|
assert.deepStrictEqual(
|
|
226
226
|
[...parse([
|
|
227
227
|
'[[^A 1|b]]',
|
|
@@ -12,7 +12,7 @@ describe('Unit: parser/inline/annotation', () => {
|
|
|
12
12
|
assert.deepStrictEqual(inspect(parser, input('', new Context())), undefined);
|
|
13
13
|
assert.deepStrictEqual(inspect(parser, input('(', new Context())), undefined);
|
|
14
14
|
assert.deepStrictEqual(inspect(parser, input('()', new Context())), undefined);
|
|
15
|
-
assert.deepStrictEqual(inspect(parser, input('((', new Context())),
|
|
15
|
+
assert.deepStrictEqual(inspect(parser, input('((', new Context())), undefined);
|
|
16
16
|
assert.deepStrictEqual(inspect(parser, input('(())', new Context())), [['<span class="paren">(<span class="paren">(</span></span>'], '))']);
|
|
17
17
|
assert.deepStrictEqual(inspect(parser, input('(()))', new Context())), [['<span class="paren">(<span class="paren">(</span></span>'], ')))']);
|
|
18
18
|
assert.deepStrictEqual(inspect(parser, input('(("))', new Context())), [['<span class="paren">(<span class="paren">("))</span></span>'], '']);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { AnnotationParser } from '../inline';
|
|
2
2
|
import { State, Recursion } from '../context';
|
|
3
3
|
import { List, Node } from '../../combinator/data/parser';
|
|
4
|
-
import { union, some, recursion, precedence, constraint, surround,
|
|
4
|
+
import { union, some, recursion, precedence, constraint, surround, open, lazy } from '../../combinator';
|
|
5
5
|
import { inline } from '../inline';
|
|
6
6
|
import { indexA } from './bracket';
|
|
7
7
|
import { beforeNonblank, trimBlankNodeEnd } from '../visibility';
|
|
@@ -9,7 +9,7 @@ import { unwrap } from '../util';
|
|
|
9
9
|
import { html, defrag } from 'typed-dom/dom';
|
|
10
10
|
|
|
11
11
|
export const annotation: AnnotationParser = lazy(() => constraint(State.annotation, surround(
|
|
12
|
-
|
|
12
|
+
open('((', beforeNonblank),
|
|
13
13
|
precedence(1, recursion(Recursion.inline, recursion(Recursion.bracket, recursion(Recursion.bracket,
|
|
14
14
|
some(union([inline]), ')', [[')', 1]]))))),
|
|
15
15
|
'))',
|
|
@@ -110,7 +110,7 @@ export function signature(target: Element | DocumentFragment): string {
|
|
|
110
110
|
assert(!target.parentNode);
|
|
111
111
|
assert(!target.querySelector('br:not(:has(+ :is(ul, ol)))') || target.nodeName === 'MARK');
|
|
112
112
|
for (let es = target.querySelectorAll('code[data-src], .math[data-src], .remark, rt, rp, br, .annotation, .reference, :is(.annotation, .reference) > a, .checkbox, ul, ol, .label[data-label]'),
|
|
113
|
-
|
|
113
|
+
i = es.length; i--;) {
|
|
114
114
|
const el = es[i];
|
|
115
115
|
switch (el.className) {
|
|
116
116
|
case 'math':
|
|
@@ -119,10 +119,15 @@ export function signature(target: Element | DocumentFragment): string {
|
|
|
119
119
|
case 'label':
|
|
120
120
|
el.replaceWith(`[$${el.getAttribute('data-label')!.replace('$', '')}]`);
|
|
121
121
|
continue;
|
|
122
|
-
case 'checkbox':
|
|
123
|
-
case 'remark':
|
|
124
122
|
case 'annotation':
|
|
123
|
+
el.replaceWith(`((${el.textContent}))`);
|
|
124
|
+
continue;
|
|
125
125
|
case 'reference':
|
|
126
|
+
const abbr = el.getAttribute('data-abbr');
|
|
127
|
+
el.replaceWith(`[[${abbr ? `^${abbr}` : el.textContent}]]`);
|
|
128
|
+
continue;
|
|
129
|
+
case 'checkbox':
|
|
130
|
+
case 'remark':
|
|
126
131
|
el.remove();
|
|
127
132
|
continue;
|
|
128
133
|
}
|
|
@@ -149,16 +154,21 @@ export function text(target: Element | DocumentFragment): string {
|
|
|
149
154
|
assert(!target.parentNode);
|
|
150
155
|
assert(!target.querySelector('br:not(:has(+ :is(ul, ol)))'));
|
|
151
156
|
for (let es = target.querySelectorAll('code[data-src], .math[data-src], .remark, rt, rp, br, .annotation, .reference, :is(.annotation, .reference) > a, .checkbox, ul, ol'),
|
|
152
|
-
|
|
157
|
+
i = es.length; i--;) {
|
|
153
158
|
const el = es[i];
|
|
154
159
|
switch (el.className) {
|
|
155
160
|
case 'math':
|
|
156
161
|
el.replaceWith(el.getAttribute('data-src')!);
|
|
157
162
|
continue;
|
|
158
|
-
case 'checkbox':
|
|
159
|
-
case 'remark':
|
|
160
163
|
case 'annotation':
|
|
164
|
+
el.replaceWith(`((${el.textContent}))`);
|
|
165
|
+
continue;
|
|
161
166
|
case 'reference':
|
|
167
|
+
const abbr = el.getAttribute('data-abbr');
|
|
168
|
+
el.replaceWith(`[[${abbr ? `^${abbr}` : el.textContent}]]`);
|
|
169
|
+
continue;
|
|
170
|
+
case 'checkbox':
|
|
171
|
+
case 'remark':
|
|
162
172
|
el.remove();
|
|
163
173
|
continue;
|
|
164
174
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { LinkParser } from '../inline';
|
|
2
2
|
import { Context, State, Backtrack, Command } from '../context';
|
|
3
3
|
import { List, Node } from '../../combinator/data/parser';
|
|
4
|
-
import { union, inits, sequence, subsequence, some, consume, precedence, state, constraint, surround, open,
|
|
4
|
+
import { union, inits, sequence, subsequence, some, consume, precedence, state, constraint, surround, open, setBacktrack, dup, lazy, fmap, bind } from '../../combinator';
|
|
5
5
|
import { inline, media, shortmedia } from '../inline';
|
|
6
6
|
import { attributes } from './html';
|
|
7
7
|
import { str } from '../source';
|
|
@@ -18,7 +18,7 @@ Object.setPrototypeOf(optspec, null);
|
|
|
18
18
|
export const textlink: LinkParser.TextLinkParser = lazy(() => bind(
|
|
19
19
|
subsequence([
|
|
20
20
|
constraint(State.link, state(State.linkers, dup(surround(
|
|
21
|
-
|
|
21
|
+
open('[', beforeNonblank),
|
|
22
22
|
precedence(1,
|
|
23
23
|
some(union([inline]), ']', [[']', 1]])),
|
|
24
24
|
']',
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { note
|
|
1
|
+
import { note } from './note';
|
|
2
2
|
import { parse as parse_ } from '../../parser';
|
|
3
3
|
import { html } from 'typed-dom/dom';
|
|
4
4
|
|
|
@@ -8,7 +8,7 @@ describe('Unit: parser/processor/note', () => {
|
|
|
8
8
|
describe('annotation', () => {
|
|
9
9
|
it('empty', () => {
|
|
10
10
|
const target = parse('');
|
|
11
|
-
[...
|
|
11
|
+
[...note(target)];
|
|
12
12
|
assert.deepStrictEqual(
|
|
13
13
|
[...target.children].map(el => el.outerHTML),
|
|
14
14
|
[]);
|
|
@@ -17,7 +17,7 @@ describe('Unit: parser/processor/note', () => {
|
|
|
17
17
|
it('1', () => {
|
|
18
18
|
const target = parse('((a b))');
|
|
19
19
|
for (let i = 0; i < 3; ++i) {
|
|
20
|
-
assert.deepStrictEqual([...
|
|
20
|
+
assert.deepStrictEqual([...note(target)].length, i === 0 ? 2 : 3);
|
|
21
21
|
assert.deepStrictEqual(
|
|
22
22
|
[...target.children].map(el => el.outerHTML),
|
|
23
23
|
[
|
|
@@ -39,7 +39,7 @@ describe('Unit: parser/processor/note', () => {
|
|
|
39
39
|
it('2', () => {
|
|
40
40
|
const target = parse('((1))((12345678901234567890))');
|
|
41
41
|
for (let i = 0; i < 3; ++i) {
|
|
42
|
-
assert.deepStrictEqual([...
|
|
42
|
+
assert.deepStrictEqual([...note(target)].length, i === 0 ? 4 : 6);
|
|
43
43
|
assert.deepStrictEqual(
|
|
44
44
|
[...target.children].map(el => el.outerHTML),
|
|
45
45
|
[
|
|
@@ -68,7 +68,7 @@ describe('Unit: parser/processor/note', () => {
|
|
|
68
68
|
it('unify', () => {
|
|
69
69
|
const target = parse('((1))((2))((3))((2))((4))');
|
|
70
70
|
for (let i = 0; i < 3; ++i) {
|
|
71
|
-
[...
|
|
71
|
+
[...note(target)];
|
|
72
72
|
assert.deepStrictEqual(
|
|
73
73
|
[...target.children].map(el => el.outerHTML),
|
|
74
74
|
[
|
|
@@ -121,7 +121,7 @@ describe('Unit: parser/processor/note', () => {
|
|
|
121
121
|
'((4))',
|
|
122
122
|
].join('\n\n')).children);
|
|
123
123
|
for (let i = 0; i < 3; ++i) {
|
|
124
|
-
[...
|
|
124
|
+
[...note(target)];
|
|
125
125
|
assert.deepStrictEqual(
|
|
126
126
|
[...target.children].map(el => el.outerHTML),
|
|
127
127
|
[
|
|
@@ -202,7 +202,7 @@ describe('Unit: parser/processor/note', () => {
|
|
|
202
202
|
it('id', () => {
|
|
203
203
|
const target = parse('((a b))');
|
|
204
204
|
for (let i = 0; i < 3; ++i) {
|
|
205
|
-
assert.deepStrictEqual([...
|
|
205
|
+
assert.deepStrictEqual([...note(target, undefined, { id: '0' })].length, i === 0 ? 2 : 3);
|
|
206
206
|
assert.deepStrictEqual(
|
|
207
207
|
[...target.children].map(el => el.outerHTML),
|
|
208
208
|
[
|
|
@@ -222,37 +222,39 @@ describe('Unit: parser/processor/note', () => {
|
|
|
222
222
|
});
|
|
223
223
|
|
|
224
224
|
it('nest', () => {
|
|
225
|
-
const target = parse('((a((b((c))))))((a))((b))');
|
|
225
|
+
const target = parse('((a((b((c))))))((a))((b))((c))');
|
|
226
226
|
for (let i = 0; i < 3; ++i) {
|
|
227
|
-
[...
|
|
227
|
+
[...note(target)];
|
|
228
228
|
assert.deepStrictEqual(
|
|
229
229
|
[...target.children].map(el => el.outerHTML),
|
|
230
230
|
[
|
|
231
231
|
html('p', [
|
|
232
|
+
html('sup', { class: 'annotation', id: 'annotation::ref:a((b((c)))):1', title: 'a((b((c))))' }, [
|
|
233
|
+
html('a', { href: '#annotation::def:a((b((c)))):1' }, '*1')
|
|
234
|
+
]),
|
|
232
235
|
html('sup', { class: 'annotation', id: 'annotation::ref:a:1', title: 'a' }, [
|
|
233
|
-
html('a', { href: '#annotation::def:a:1' }, '*
|
|
236
|
+
html('a', { href: '#annotation::def:a:1' }, '*4')
|
|
234
237
|
]),
|
|
235
|
-
html('sup', { class: 'annotation', id: 'annotation::ref:
|
|
236
|
-
html('a', { href: '#annotation::def:
|
|
238
|
+
html('sup', { class: 'annotation', id: 'annotation::ref:b:1', title: 'b' }, [
|
|
239
|
+
html('a', { href: '#annotation::def:b:1' }, '*5')
|
|
237
240
|
]),
|
|
238
|
-
html('sup', { class: 'annotation', id: 'annotation::ref:
|
|
239
|
-
html('a', { href: '#annotation::def:
|
|
241
|
+
html('sup', { class: 'annotation', id: 'annotation::ref:c:2', title: 'c' }, [
|
|
242
|
+
html('a', { href: '#annotation::def:c:1' }, '*3')
|
|
240
243
|
]),
|
|
241
244
|
]).outerHTML,
|
|
242
245
|
html('ol', { class: 'annotations' }, [
|
|
243
|
-
html('li', { id: 'annotation::def:a:1', 'data-marker': '*1' }, [
|
|
246
|
+
html('li', { id: 'annotation::def:a((b((c)))):1', 'data-marker': '*1' }, [
|
|
244
247
|
html('span', [
|
|
245
248
|
'a',
|
|
246
|
-
html('sup', { class: 'annotation', id: 'annotation::ref:b:1', title: 'b' }, [
|
|
247
|
-
html('a', { href: '#annotation::def:b:1' }, '*2')
|
|
249
|
+
html('sup', { class: 'annotation', id: 'annotation::ref:b((c)):1', title: 'b((c))' }, [
|
|
250
|
+
html('a', { href: '#annotation::def:b((c)):1' }, '*2')
|
|
248
251
|
]),
|
|
249
252
|
]),
|
|
250
253
|
html('sup', [
|
|
251
|
-
html('a', { href: '#annotation::ref:a:1' }, '^1'),
|
|
252
|
-
html('a', { href: '#annotation::ref:a:2' }, '^4'),
|
|
254
|
+
html('a', { href: '#annotation::ref:a((b((c)))):1' }, '^1'),
|
|
253
255
|
])
|
|
254
256
|
]),
|
|
255
|
-
html('li', { id: 'annotation::def:b:1', 'data-marker': '*2' }, [
|
|
257
|
+
html('li', { id: 'annotation::def:b((c)):1', 'data-marker': '*2' }, [
|
|
256
258
|
html('span', [
|
|
257
259
|
'b',
|
|
258
260
|
html('sup', { class: 'annotation', id: 'annotation::ref:c:1', title: 'c' }, [
|
|
@@ -260,8 +262,7 @@ describe('Unit: parser/processor/note', () => {
|
|
|
260
262
|
]),
|
|
261
263
|
]),
|
|
262
264
|
html('sup', [
|
|
263
|
-
html('a', { href: '#annotation::ref:b:1' }, '^2'),
|
|
264
|
-
html('a', { href: '#annotation::ref:b:2' }, '^5'),
|
|
265
|
+
html('a', { href: '#annotation::ref:b((c)):1' }, '^2'),
|
|
265
266
|
])
|
|
266
267
|
]),
|
|
267
268
|
html('li', { id: 'annotation::def:c:1', 'data-marker': '*3' }, [
|
|
@@ -270,6 +271,23 @@ describe('Unit: parser/processor/note', () => {
|
|
|
270
271
|
]),
|
|
271
272
|
html('sup', [
|
|
272
273
|
html('a', { href: '#annotation::ref:c:1' }, '^3'),
|
|
274
|
+
html('a', { href: '#annotation::ref:c:2' }, '^6'),
|
|
275
|
+
])
|
|
276
|
+
]),
|
|
277
|
+
html('li', { id: 'annotation::def:a:1', 'data-marker': '*4' }, [
|
|
278
|
+
html('span', [
|
|
279
|
+
'a',
|
|
280
|
+
]),
|
|
281
|
+
html('sup', [
|
|
282
|
+
html('a', { href: '#annotation::ref:a:1' }, '^4'),
|
|
283
|
+
])
|
|
284
|
+
]),
|
|
285
|
+
html('li', { id: 'annotation::def:b:1', 'data-marker': '*5' }, [
|
|
286
|
+
html('span', [
|
|
287
|
+
'b',
|
|
288
|
+
]),
|
|
289
|
+
html('sup', [
|
|
290
|
+
html('a', { href: '#annotation::ref:b:1' }, '^5'),
|
|
273
291
|
])
|
|
274
292
|
]),
|
|
275
293
|
]).outerHTML,
|
|
@@ -282,9 +300,9 @@ describe('Unit: parser/processor/note', () => {
|
|
|
282
300
|
describe('reference', () => {
|
|
283
301
|
it('1', () => {
|
|
284
302
|
const target = parse('[[a b]]');
|
|
285
|
-
const
|
|
303
|
+
const notes = { references: html('ol') };
|
|
286
304
|
for (let i = 0; i < 3; ++i) {
|
|
287
|
-
[...
|
|
305
|
+
[...note(target, notes)];
|
|
288
306
|
assert.deepStrictEqual(
|
|
289
307
|
[...target.children].map(el => el.outerHTML),
|
|
290
308
|
[
|
|
@@ -295,7 +313,7 @@ describe('Unit: parser/processor/note', () => {
|
|
|
295
313
|
]).outerHTML,
|
|
296
314
|
]);
|
|
297
315
|
assert.deepStrictEqual(
|
|
298
|
-
[
|
|
316
|
+
[notes.references.outerHTML],
|
|
299
317
|
[
|
|
300
318
|
html('ol', [
|
|
301
319
|
html('li', { id: 'reference::def:a_b' }, [
|
|
@@ -309,9 +327,9 @@ describe('Unit: parser/processor/note', () => {
|
|
|
309
327
|
|
|
310
328
|
it('abbr', () => {
|
|
311
329
|
const target = parse('[[^A 1]][[^A 1|b]][[^A 1]]');
|
|
312
|
-
const
|
|
330
|
+
const notes = { references: html('ol') };
|
|
313
331
|
for (let i = 0; i < 3; ++i) {
|
|
314
|
-
[...
|
|
332
|
+
[...note(target, notes)];
|
|
315
333
|
assert.deepStrictEqual(
|
|
316
334
|
[...target.children].map(el => el.outerHTML),
|
|
317
335
|
[
|
|
@@ -328,7 +346,7 @@ describe('Unit: parser/processor/note', () => {
|
|
|
328
346
|
]).outerHTML,
|
|
329
347
|
]);
|
|
330
348
|
assert.deepStrictEqual(
|
|
331
|
-
[
|
|
349
|
+
[notes.references.outerHTML],
|
|
332
350
|
[
|
|
333
351
|
html('ol', [
|
|
334
352
|
html('li', { id: 'reference::def:A_1' }, [
|
|
@@ -346,42 +364,41 @@ describe('Unit: parser/processor/note', () => {
|
|
|
346
364
|
|
|
347
365
|
it('nest', () => {
|
|
348
366
|
const target = parse('((a[[^B]]))[[^B|c]]');
|
|
349
|
-
const
|
|
367
|
+
const notes = { references: html('ol') };
|
|
350
368
|
for (let i = 0; i < 3; ++i) {
|
|
351
|
-
[...
|
|
352
|
-
[...reference(target, note)];
|
|
369
|
+
[...note(target, notes)];
|
|
353
370
|
assert.deepStrictEqual(
|
|
354
371
|
[...target.children].map(el => el.outerHTML),
|
|
355
372
|
[
|
|
356
373
|
html('p', [
|
|
357
|
-
html('sup', { class: 'annotation', id: 'annotation::ref:a:1', title: 'a' }, [
|
|
358
|
-
html('a', { href: '#annotation::def:a:1' }, '*1')
|
|
374
|
+
html('sup', { class: 'annotation', id: 'annotation::ref:a[[^B]]:1', title: 'a[[^B]]' }, [
|
|
375
|
+
html('a', { href: '#annotation::def:a[[^B]]:1' }, '*1')
|
|
359
376
|
]),
|
|
360
|
-
html('sup', { class: 'reference', 'data-abbr': 'B', id: 'reference::ref:B:
|
|
377
|
+
html('sup', { class: 'reference', 'data-abbr': 'B', id: 'reference::ref:B:2', title: 'c' }, [
|
|
361
378
|
html('a', { href: '#reference::def:B' }, '[B]')
|
|
362
379
|
]),
|
|
363
380
|
]).outerHTML,
|
|
364
381
|
html('ol', { class: 'annotations' }, [
|
|
365
|
-
html('li', { id: 'annotation::def:a:1', 'data-marker': '*1' }, [
|
|
382
|
+
html('li', { id: 'annotation::def:a[[^B]]:1', 'data-marker': '*1' }, [
|
|
366
383
|
html('span', [
|
|
367
384
|
'a',
|
|
368
|
-
html('sup', { class: 'reference', 'data-abbr': 'B', id: 'reference::ref:B:
|
|
385
|
+
html('sup', { class: 'reference', 'data-abbr': 'B', id: 'reference::ref:B:1', title: 'c' }, [
|
|
369
386
|
html('a', { href: '#reference::def:B' }, '[B]')
|
|
370
387
|
]),
|
|
371
388
|
]),
|
|
372
|
-
html('sup', [html('a', { href: '#annotation::ref:a:1' }, '^1')])
|
|
389
|
+
html('sup', [html('a', { href: '#annotation::ref:a[[^B]]:1' }, '^1')])
|
|
373
390
|
]),
|
|
374
391
|
]).outerHTML,
|
|
375
392
|
]);
|
|
376
393
|
assert.deepStrictEqual(
|
|
377
|
-
[
|
|
394
|
+
[notes.references.outerHTML],
|
|
378
395
|
[
|
|
379
396
|
html('ol', [
|
|
380
397
|
html('li', { id: 'reference::def:B' }, [
|
|
381
398
|
html('span', 'c'),
|
|
382
399
|
html('sup', [
|
|
383
|
-
html('a', { href: '#reference::ref:B:1'
|
|
384
|
-
html('a', { href: '#reference::ref:B:2' }, '^2'),
|
|
400
|
+
html('a', { href: '#reference::ref:B:1' }, '^1'),
|
|
401
|
+
html('a', { href: '#reference::ref:B:2', title: 'c' }, '^2'),
|
|
385
402
|
]),
|
|
386
403
|
]),
|
|
387
404
|
]).outerHTML,
|
|
@@ -12,45 +12,66 @@ export function* note(
|
|
|
12
12
|
opts: { readonly id?: string; } = {},
|
|
13
13
|
bottom: Node | null = null,
|
|
14
14
|
): Generator<HTMLAnchorElement | HTMLLIElement | undefined, undefined, undefined> {
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
const referenceRefMemory = referenceRefsMemoryCaller(target);
|
|
16
|
+
const annotationRefMemory = annotationRefsMemoryCaller(target);
|
|
17
|
+
for (const memory of [referenceRefMemory, annotationRefMemory]) {
|
|
18
|
+
for (const [ref, { content }] of memory) {
|
|
19
|
+
ref.replaceChildren(content);
|
|
20
|
+
}
|
|
21
|
+
memory.clear();
|
|
22
|
+
}
|
|
23
|
+
yield* reference(referenceRefMemory, target, notes?.references, opts, bottom);
|
|
24
|
+
yield* annotation(annotationRefMemory, target, notes?.annotations, opts, bottom);
|
|
17
25
|
}
|
|
18
26
|
|
|
19
|
-
|
|
27
|
+
interface RefMemory {
|
|
28
|
+
readonly content: Element;
|
|
29
|
+
readonly identifier: string;
|
|
30
|
+
readonly abbr: string;
|
|
31
|
+
readonly text: string;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const annotationRefsMemoryCaller = memoize((target: Node) =>
|
|
35
|
+
new Map<HTMLElement, RefMemory>() ?? target,
|
|
36
|
+
new WeakMap());
|
|
37
|
+
|
|
38
|
+
const referenceRefsMemoryCaller = memoize((target: Node) =>
|
|
39
|
+
new Map<HTMLElement, {
|
|
40
|
+
readonly content: Element;
|
|
41
|
+
readonly identifier: string;
|
|
42
|
+
readonly abbr: string;
|
|
43
|
+
readonly text: string;
|
|
44
|
+
}>() ?? target,
|
|
45
|
+
new WeakMap());
|
|
46
|
+
|
|
47
|
+
const annotation = build(
|
|
20
48
|
'annotation',
|
|
21
49
|
'annotations',
|
|
50
|
+
'.annotation:not(:is(.annotations, .references) .annotation, .disabled)',
|
|
22
51
|
n => `*${n}`,
|
|
23
52
|
'h1, h2, h3, h4, h5, h6, aside.aside, hr');
|
|
24
|
-
|
|
53
|
+
const reference = build(
|
|
25
54
|
'reference',
|
|
26
55
|
'references',
|
|
56
|
+
'.reference:not(:is(.annotations, .references) .reference, .disabled)',
|
|
27
57
|
(n, abbr) => `[${abbr || n}]`);
|
|
28
58
|
|
|
29
|
-
// Referenceを含むAnnotationの重複排除は両構文が互いに処理済みであることを必要とするため
|
|
30
|
-
// 構文ごとに各1回の処理では不可能
|
|
31
59
|
function build(
|
|
32
60
|
syntax: string,
|
|
33
|
-
|
|
61
|
+
list: string,
|
|
62
|
+
query: string,
|
|
34
63
|
marker: (index: number, abbr: string) => string,
|
|
35
64
|
splitter: string = '',
|
|
36
65
|
) {
|
|
37
66
|
assert(syntax.match(/^[a-z]+$/));
|
|
38
|
-
splitter &&= `${splitter}, .${
|
|
39
|
-
const refMemoryCaller = memoize((target: Node) =>
|
|
40
|
-
new Map<HTMLElement, {
|
|
41
|
-
readonly content: Element;
|
|
42
|
-
readonly identifier: string;
|
|
43
|
-
readonly abbr: string;
|
|
44
|
-
readonly text: string;
|
|
45
|
-
}>() ?? target,
|
|
46
|
-
new WeakMap());
|
|
67
|
+
splitter &&= `${splitter}, .${list}`;
|
|
47
68
|
return function* (
|
|
69
|
+
memory: Map<HTMLElement, RefMemory>,
|
|
48
70
|
target: ParentNode & Node,
|
|
49
71
|
note?: HTMLOListElement,
|
|
50
72
|
opts: { readonly id?: string } = {},
|
|
51
73
|
bottom: Node | null = null,
|
|
52
74
|
): Generator<HTMLAnchorElement | HTMLLIElement | undefined, undefined, undefined> {
|
|
53
|
-
const refMemory = refMemoryCaller(target);
|
|
54
75
|
const refInfoCaller = memoize((ref: HTMLElement) => {
|
|
55
76
|
const content = ref.firstElementChild!;
|
|
56
77
|
const abbr = ref.getAttribute('data-abbr') ?? '';
|
|
@@ -72,15 +93,9 @@ function build(
|
|
|
72
93
|
abbr,
|
|
73
94
|
text: txt,
|
|
74
95
|
};
|
|
75
|
-
},
|
|
76
|
-
for (const [ref, { content }] of refMemory) {
|
|
77
|
-
content.replaceWith(content.cloneNode(true));
|
|
78
|
-
ref.replaceChildren(content);
|
|
79
|
-
refMemory.delete(ref);
|
|
80
|
-
}
|
|
81
|
-
assert(refMemory.size === 0);
|
|
96
|
+
}, memory);
|
|
82
97
|
const defs = new Map<string, HTMLLIElement>();
|
|
83
|
-
const refs = target.querySelectorAll<HTMLElement>(
|
|
98
|
+
const refs = target.querySelectorAll<HTMLElement>(query);
|
|
84
99
|
const identifierInfoCaller = memoize((identifier: string) => ({
|
|
85
100
|
defIndex: 0,
|
|
86
101
|
defSubindex: 0,
|
|
@@ -96,23 +111,21 @@ function build(
|
|
|
96
111
|
let refIndex = 0;
|
|
97
112
|
for (let len = refs.length, i = 0; i < len; ++i) {
|
|
98
113
|
const ref = refs[i];
|
|
99
|
-
if (splitter) for (
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
el?.compareDocumentPosition(ref) & Node.DOCUMENT_POSITION_FOLLOWING;
|
|
103
|
-
++iSplitters) {
|
|
114
|
+
if (splitter) for (let splitter; splitter = splitters[iSplitters]; ++iSplitters) {
|
|
115
|
+
const pos = splitter?.compareDocumentPosition(ref) ?? 0;
|
|
116
|
+
if (pos & (Node.DOCUMENT_POSITION_PRECEDING | Node.DOCUMENT_POSITION_DISCONNECTED)) break;
|
|
104
117
|
if (~iSplitters << 32 - 8 === 0) yield;
|
|
105
|
-
if (
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
el.remove();
|
|
118
|
+
if (splitter.classList.contains(list) && defs.size === 0) {
|
|
119
|
+
assert(splitter.matches(`.${list}`));
|
|
120
|
+
splitter.remove();
|
|
109
121
|
continue;
|
|
110
122
|
}
|
|
111
123
|
if (defs.size > 0) {
|
|
112
124
|
total += defs.size;
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
125
|
+
assert(splitter.parentNode);
|
|
126
|
+
const note = splitter.classList.contains(list)
|
|
127
|
+
? splitter as HTMLOListElement
|
|
128
|
+
: target.insertBefore(html('ol', { class: list }), splitter);
|
|
116
129
|
assert(note.parentNode);
|
|
117
130
|
yield* proc(defs, note);
|
|
118
131
|
assert(defs.size === 0);
|
|
@@ -185,19 +198,16 @@ function build(
|
|
|
185
198
|
`^${++refIndex}`));
|
|
186
199
|
}
|
|
187
200
|
if (note || defs.size > 0) {
|
|
188
|
-
const
|
|
189
|
-
note
|
|
190
|
-
?
|
|
191
|
-
: target.insertBefore(html('ol', { class:
|
|
192
|
-
yield* proc(defs, note);
|
|
201
|
+
const splitter = splitters[iSplitters++];
|
|
202
|
+
yield* proc(defs, note ?? (splitter?.classList.contains(list)
|
|
203
|
+
? splitter as HTMLOListElement
|
|
204
|
+
: target.insertBefore(html('ol', { class: list }), splitter ?? bottom)));
|
|
193
205
|
assert(defs.size === 0);
|
|
194
206
|
}
|
|
195
|
-
if (splitter) for (let
|
|
207
|
+
if (splitter) for (let splitter; splitter = splitters[iSplitters]; ++iSplitters) {
|
|
196
208
|
if (~iSplitters << 32 - 8 === 0) yield;
|
|
197
|
-
if (
|
|
198
|
-
|
|
199
|
-
assert(el.matches(`.${plural}`));
|
|
200
|
-
el.remove();
|
|
209
|
+
if (splitter.classList.contains(list)) {
|
|
210
|
+
splitter.remove();
|
|
201
211
|
}
|
|
202
212
|
}
|
|
203
213
|
}
|
|
@@ -205,37 +215,11 @@ function build(
|
|
|
205
215
|
|
|
206
216
|
function* proc(defs: Map<string, HTMLLIElement>, note: HTMLOListElement): Generator<HTMLLIElement | undefined, undefined, undefined> {
|
|
207
217
|
const { children } = note;
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
let length = children.length;
|
|
211
|
-
I:
|
|
212
|
-
for (const [key, def] of defs) {
|
|
213
|
-
defs.delete(key);
|
|
214
|
-
++count;
|
|
215
|
-
for (; length > size;) {
|
|
216
|
-
const node = children[count - 1] as HTMLLIElement;
|
|
217
|
-
if (equal(node, def)) continue I;
|
|
218
|
-
yield note.removeChild(node);
|
|
219
|
-
--length;
|
|
220
|
-
assert(children.length === length);
|
|
221
|
-
}
|
|
222
|
-
const node = count <= length
|
|
223
|
-
? children[count - 1]
|
|
224
|
-
: null;
|
|
225
|
-
if (node && equal(node, def)) continue;
|
|
226
|
-
assert(def.parentNode !== note);
|
|
227
|
-
yield note.insertBefore(def, node);
|
|
228
|
-
++length;
|
|
229
|
-
assert(children.length === length);
|
|
218
|
+
for (let defs = note.children, i = defs.length; i--;) {
|
|
219
|
+
yield note.removeChild(children[i] as HTMLLIElement);
|
|
230
220
|
}
|
|
231
|
-
for (
|
|
232
|
-
yield note.
|
|
233
|
-
--length;
|
|
234
|
-
assert(children.length === length);
|
|
221
|
+
for (const [, def] of defs) {
|
|
222
|
+
yield note.appendChild(def);
|
|
235
223
|
}
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
function equal(a: Element, b: HTMLElement): boolean {
|
|
239
|
-
return a.id === b.id
|
|
240
|
-
&& a.innerHTML === b.innerHTML;
|
|
224
|
+
defs.clear();
|
|
241
225
|
}
|
package/src/renderer/render.ts
CHANGED
|
@@ -5,7 +5,7 @@ import { media } from './render/media';
|
|
|
5
5
|
import { reduce } from 'spica/memoize';
|
|
6
6
|
import { querySelectorAllWith } from 'typed-dom/query';
|
|
7
7
|
|
|
8
|
-
const selector = '
|
|
8
|
+
const selector = ':not(.invalid):is(.media:is(img:not([src])[data-src], a > :not(img).media), pre.code, .math)';
|
|
9
9
|
|
|
10
10
|
const extend = reduce((opts: RenderingOptions): RenderingOptions =>
|
|
11
11
|
({ code, math, media: {}, ...opts }));
|