securemark 0.283.0 → 0.283.2

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,13 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.283.2
4
+
5
+ - Fix backtracking control.
6
+
7
+ ## 0.283.1
8
+
9
+ - Fix bracket parser.
10
+
3
11
  ## 0.283.0
4
12
 
5
13
  - Refine backtracking control.
package/design.md CHANGED
@@ -288,7 +288,7 @@ CodeMirrorが素では速いがVimModeでは数万文字程度でも耐え難く
288
288
  SecuremarkのAnnotation構文に典型的であるように文脈を変更する構文の中にその文脈に依存し変更される他の構文が存在する場合一般に文脈の相違から解析結果を再利用不能な(`αA'β | αAB`)バックトラックが生じる。文脈依存構文の解析中に文脈により解釈の異なる字句(`[a((`)または現在の文脈を終了する字句(ただの括弧がスコープを作らない場合の`(([a))`)に遭遇したとき、現在の文脈での解析の継続を試行する解析方法はメモ化なしではバックトラックが再帰的に生じ線形時間で解析できず、現在の文脈での解析を中止し直前の文脈を継続または新たな文脈を開始する解析方法はバックトラックなしで線形時間で解析できる(バッファまたは解析試行ログを使用して解釈を変更する実装方法があるが開始記号の一部が重複しないよう構文が制限される場合がある)。
289
289
  CommonMarkはLink構文から明らかなように後者の解析方法により再帰的バックトラックなし(Markdown(2n)+正規表現(1n)で最悪計算量3n程度)で解析できる言語であるが同時にこれは文脈依存構文の正当な入れ子表現を解析できず文脈依存構文の存在する数に応じて多項式的(おそらく$n^{2+c}$)に構文の壊れやすさの増す脆く拡張性の低い言語であることを意味する。この問題はおそらくメモ化により解決できるがCommonMarkは実行性能追及のためメモ化を廃止しているためメモ化により性能を低下させてまで解決するつもりはないと思われる(すなわちCommonMarkは機械を至上とし人間に制約を課す低水準の言語であり人間の需要を至上とするSecuremarkとは対極に位置する)。
290
290
  従って現在の再帰的バックトラックなしで解析可能な文法に制約されるCommonMarkには文脈依存構文を入れ子表現の広範な制限ならびに構文の可読性および開始記号の信頼性の多項式的な低下と引き換えにしか追加できないという拡張性の欠陥が存在する。CommonMarkの仕様策定者が構文の拡張に(名称を維持するか否かにかかわらず)不自然なまでに消極的または進展がないのは正当な理由や怠慢からでなく文脈依存構文を追加するにつれて構文解析戦略の欠陥が明白になっていくためおよび現在の高い実行性能を低下させたくないためである。`~~a~~`のような文脈自由構文は容易に追加できるがこうしたマージンを失えばもはや後はない。CommonMarkは小さく単純であるがゆえに正しくいられる象牙の塔であり仕様策定者はこの正しさを失わず正しいままでいたいがために象牙の塔に引きこもり小さな完全性を固持し続けているのである(でなければ何年も隠さず速やかにこの拡張性の欠如を公表して助力を求めていなければならない)。
291
- Securemarkは線形時間で解析不能な文脈依存言語をおおよそ8n以下の最悪時間計算量に改善しさらに解析時間と解析範囲の局限により一定時間内で解析不能な入力の影響を局限することでこれらの問題を解決している。この解析方法はほとんどの自然な入力に対して1nに近い時間で効率的に動作し、最悪計算量で低速に動作させる入力に対してもこの開発効率と安全性優先の低速な実装においてはサーバーで多数のユーザーのリクエストに応じるには低速で脆弱性となる可能性があるがクライアントで単一のユーザーの操作に応じるには十分高速であるためクライアントで解析する限り解析の効率または速度が実用上問題となることはなく仕様が固まり実行効率優先の高速な実装に移れば速度面の懸念もないだろう。
291
+ Securemarkは線形時間で解析不能な文脈依存言語をおおよそ4nから8nの最悪時間計算量に改善しさらに解析時間と解析範囲の局限により一定時間内で解析不能な入力の影響を局限することでこれらの問題を解決している。この解析方法はほとんどの自然な入力に対して1nに近い時間で効率的に動作し、最悪計算量で低速に動作させる入力に対してもこの開発効率と安全性優先の低速な実装においてはサーバーで多数のユーザーのリクエストに応じるには低速で脆弱性となる可能性があるがクライアントで単一のユーザーの操作に応じるには十分高速であるためクライアントで解析する限り解析の効率または速度が実用上問題となることはなく仕様が固まり実行効率優先の高速な実装に移れば速度面の懸念もないだろう。
292
292
 
293
293
  ### 最適化
294
294
 
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- /*! securemark v0.283.0 https://github.com/falsandtru/securemark | (c) 2017, falsandtru | UNLICENSED License */
1
+ /*! securemark v0.283.2 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"));
@@ -963,14 +963,14 @@ function indent(opener, parser, separation = false) {
963
963
  source
964
964
  }) => [[source], '']))), ([indent]) => indent.length * 2 + +(indent[0] === ' '), {})), separation), (lines, rest, context) => {
965
965
  const {
966
- log
966
+ logger
967
967
  } = context;
968
- context.log = {};
968
+ context.logger = {};
969
969
  const result = parser({
970
970
  source: trimBlockEnd(lines.join('')),
971
971
  context
972
972
  });
973
- context.log = log;
973
+ context.logger = logger;
974
974
  return result && (0, parser_1.exec)(result) === '' ? [(0, parser_1.eval)(result), rest] : undefined;
975
975
  });
976
976
  }
@@ -1967,7 +1967,7 @@ const source_1 = __webpack_require__(8745);
1967
1967
  const closer = /^[-+*=~^_,.;:!?]*(?=[\\"`|\[\](){}<>]|$)/;
1968
1968
  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.focus)(/^[\x21-\x7E]+/, (0, combinator_1.some)((0, combinator_1.union)([bracket, (0, combinator_1.some)(source_1.unescsource, closer)])))), (0, combinator_1.convert)(url => `{ ${url} }`, (0, combinator_1.union)([link_1.unsafelink])))));
1969
1969
  exports.lineurl = (0, combinator_1.lazy)(() => (0, combinator_1.open)(source_1.linebreak, (0, combinator_1.tails)([(0, source_1.str)('!'), (0, combinator_1.focus)(/^https?:\/\/\S+(?=[^\S\n]*(?:$|\n))/, (0, combinator_1.convert)(url => `{ ${url} }`, link_1.unsafelink))])));
1970
- const bracket = (0, combinator_1.lazy)(() => (0, combinator_1.creation)(0, 6 /* Recursion.terminal */, (0, combinator_1.precedence)(2, (0, combinator_1.union)([(0, combinator_1.surround)((0, source_1.str)('('), (0, combinator_1.some)((0, combinator_1.union)([bracket, source_1.unescsource]), ')'), (0, source_1.str)(')'), true), (0, combinator_1.surround)((0, source_1.str)('['), (0, combinator_1.some)((0, combinator_1.union)([bracket, source_1.unescsource]), ']'), (0, source_1.str)(']'), true), (0, combinator_1.surround)((0, source_1.str)('{'), (0, combinator_1.some)((0, combinator_1.union)([bracket, source_1.unescsource]), '}'), (0, source_1.str)('}'), true), (0, combinator_1.surround)((0, source_1.str)('"'), (0, combinator_1.precedence)(3, (0, combinator_1.some)(source_1.unescsource, '"')), (0, source_1.str)('"'), true)]))));
1970
+ const bracket = (0, combinator_1.lazy)(() => (0, combinator_1.creation)(0, 6 /* Recursion.terminal */, (0, combinator_1.precedence)(2, (0, combinator_1.union)([(0, combinator_1.surround)((0, source_1.str)('('), (0, combinator_1.some)((0, combinator_1.union)([bracket, source_1.unescsource]), ')'), (0, source_1.str)(')'), true, undefined, undefined, 3 | 8 /* Backtrack.url */), (0, combinator_1.surround)((0, source_1.str)('['), (0, combinator_1.some)((0, combinator_1.union)([bracket, source_1.unescsource]), ']'), (0, source_1.str)(']'), true, undefined, undefined, 3 | 8 /* Backtrack.url */), (0, combinator_1.surround)((0, source_1.str)('{'), (0, combinator_1.some)((0, combinator_1.union)([bracket, source_1.unescsource]), '}'), (0, source_1.str)('}'), true, undefined, undefined, 3 | 8 /* Backtrack.url */), (0, combinator_1.surround)((0, source_1.str)('"'), (0, combinator_1.precedence)(3, (0, combinator_1.some)(source_1.unescsource, '"')), (0, source_1.str)('"'), true, undefined, undefined, 3 | 8 /* Backtrack.url */)]))));
1971
1971
 
1972
1972
  /***/ },
1973
1973
 
@@ -3234,7 +3234,7 @@ const optspec = {
3234
3234
  };
3235
3235
  Object.setPrototypeOf(optspec, null);
3236
3236
  exports.link = (0, combinator_1.lazy)(() => (0, combinator_1.validate)(['[', '{'], (0, combinator_1.union)([exports.medialink, exports.textlink])));
3237
- exports.textlink = (0, combinator_1.lazy)(() => (0, combinator_1.creation)(1, 0 /* Recursion.ignore */, (0, combinator_1.constraint)(16 /* State.link */, false, (0, combinator_1.syntax)(2, 502 /* State.linkers */ | 8 /* 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], [']', 2]])), ']', true, undefined, undefined, 1)), (0, combinator_1.dup)((0, combinator_1.surround)(/^{(?![{}])/, (0, combinator_1.inits)([exports.uri, (0, combinator_1.some)(exports.option)]), /^[^\S\n]*}/))])), ([params, content = []], rest, context) => {
3237
+ exports.textlink = (0, combinator_1.lazy)(() => (0, combinator_1.creation)(1, 0 /* Recursion.ignore */, (0, combinator_1.constraint)(16 /* State.link */, false, (0, combinator_1.syntax)(2, 502 /* State.linkers */ | 8 /* 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], [']', 2]])), ']', true, undefined, undefined, 1 | 4 /* 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 | 16 /* Backtrack.link */))])), ([params, content = []], rest, context) => {
3238
3238
  if (content.length !== 0 && (0, visibility_1.trimNodeEnd)(content = (0, dom_1.defrag)(content)).length === 0) return;
3239
3239
  return [[parse(content, params, context)], rest];
3240
3240
  })))));
@@ -4163,7 +4163,6 @@ Object.defineProperty(exports, "__esModule", ({
4163
4163
  exports.quote = void 0;
4164
4164
  const parser_1 = __webpack_require__(605);
4165
4165
  const cite_1 = __webpack_require__(1200);
4166
- //import { url } from '../parser/inline/autolink/url';
4167
4166
  function quote(anchor, range) {
4168
4167
  if ((0, parser_1.exec)((0, cite_1.cite)({
4169
4168
  source: `>>${anchor}`,
@@ -4179,13 +4178,9 @@ function quote(anchor, range) {
4179
4178
  case el.matches('.math'):
4180
4179
  el.replaceWith(el.getAttribute('data-src'));
4181
4180
  continue;
4182
- //case el.matches('.url'):
4183
- // if (exec(url({ source: el.getAttribute('href')!, context: {} })) === '') continue;
4184
- // el.replaceWith(
4185
- // /[\s{}]/.test(el.getAttribute('href')!)
4186
- // ? `{ ${el.getAttribute('href')} }`
4187
- // : `{${el.getAttribute('href')}}`);
4188
- // continue;
4181
+ case el.matches('.url'):
4182
+ el.replaceWith(/[\s{}]/.test(el.getAttribute('href')) ? `{ ${el.getAttribute('href')} }` : `{${el.getAttribute('href')}}`);
4183
+ continue;
4189
4184
  case el.matches('.media'):
4190
4185
  el.replaceWith(/[\s{}]/.test(el.getAttribute('data-src')) ? `!{ ${el.getAttribute('data-src')} }` : `!{${el.getAttribute('data-src')}}`);
4191
4186
  continue;
@@ -4291,9 +4286,9 @@ const combinator_1 = __webpack_require__(3484);
4291
4286
  const inline_1 = __webpack_require__(7973);
4292
4287
  const visibility_1 = __webpack_require__(6364);
4293
4288
  const dom_1 = __webpack_require__(394);
4294
- exports.annotation = (0, combinator_1.lazy)(() => (0, combinator_1.creation)(1, 0 /* Recursion.ignore */, (0, combinator_1.surround)('((', (0, combinator_1.constraint)(256 /* State.annotation */, false, (0, combinator_1.syntax)(6, 256 /* State.annotation */ | 8 /* State.media */, (0, visibility_1.trimBlankStart)((0, combinator_1.some)((0, combinator_1.union)([inline_1.inline]), ')', [[/^\\?\n/, 9], [')', 2], ['))', 6]])))), '))', false, ([, ns], rest) => [[(0, dom_1.html)('sup', {
4289
+ exports.annotation = (0, combinator_1.lazy)(() => (0, combinator_1.creation)(1, 0 /* Recursion.ignore */, (0, combinator_1.surround)('((', (0, combinator_1.constraint)(256 /* State.annotation */, false, (0, combinator_1.syntax)(6, 256 /* State.annotation */ | 8 /* State.media */, (0, visibility_1.trimBlankStart)((0, combinator_1.some)((0, combinator_1.union)([inline_1.inline]), ')', [[/^\\?\n/, 9], [')', 2]])))), '))', false, ([, ns], rest) => [[(0, dom_1.html)('sup', {
4295
4290
  class: 'annotation'
4296
- }, [(0, dom_1.html)('span', (0, visibility_1.trimNodeEnd)((0, dom_1.defrag)(ns)))])], rest], undefined, 1)));
4291
+ }, [(0, dom_1.html)('span', (0, visibility_1.trimNodeEnd)((0, dom_1.defrag)(ns)))])], rest], undefined, 1 | 4 /* Backtrack.bracket */)));
4297
4292
 
4298
4293
  /***/ },
4299
4294
 
@@ -4962,8 +4957,8 @@ const array_1 = __webpack_require__(6876);
4962
4957
  const dom_1 = __webpack_require__(394);
4963
4958
  exports.template = (0, combinator_1.lazy)(() => (0, combinator_1.creation)(1, 0 /* Recursion.ignore */, (0, combinator_1.surround)('{{', (0, combinator_1.syntax)(6, -1 /* State.all */, (0, combinator_1.some)((0, combinator_1.union)([bracket, source_1.escsource]), '}', [['}}', 6]])), '}}', true, ([, ns = []], rest) => [[(0, dom_1.html)('span', {
4964
4959
  class: 'template'
4965
- }, `{{${ns.join('').replace(/\x1B/g, '')}}}`)], rest])));
4966
- const bracket = (0, combinator_1.lazy)(() => (0, combinator_1.creation)(0, 6 /* Recursion.terminal */, (0, combinator_1.union)([(0, combinator_1.surround)((0, source_1.str)('('), (0, combinator_1.some)((0, combinator_1.union)([bracket, source_1.escsource]), ')'), (0, source_1.str)(')'), true, undefined, ([as, bs = []], rest) => [(0, array_1.unshift)(as, bs), rest]), (0, combinator_1.surround)((0, source_1.str)('['), (0, combinator_1.some)((0, combinator_1.union)([bracket, source_1.escsource]), ']'), (0, source_1.str)(']'), true, undefined, ([as, bs = []], rest) => [(0, array_1.unshift)(as, bs), rest]), (0, combinator_1.surround)((0, source_1.str)('{'), (0, combinator_1.some)((0, combinator_1.union)([bracket, source_1.escsource]), '}'), (0, source_1.str)('}'), true, undefined, ([as, bs = []], rest) => [(0, array_1.unshift)(as, bs), rest]), (0, combinator_1.surround)((0, source_1.str)('"'), (0, combinator_1.precedence)(3, (0, combinator_1.some)(source_1.escsource, /^"|^\\?\n/)), (0, source_1.str)('"'), true)])));
4960
+ }, `{{${ns.join('').replace(/\x1B/g, '')}}}`)], rest], undefined, 3 | 28 /* Backtrack.template */)));
4961
+ const bracket = (0, combinator_1.lazy)(() => (0, combinator_1.creation)(0, 6 /* Recursion.terminal */, (0, combinator_1.union)([(0, combinator_1.surround)((0, source_1.str)('('), (0, combinator_1.some)((0, combinator_1.union)([bracket, source_1.escsource]), ')'), (0, source_1.str)(')'), true, undefined, ([as, bs = []], rest) => [(0, array_1.unshift)(as, bs), rest], 3 | 28 /* Backtrack.template */), (0, combinator_1.surround)((0, source_1.str)('['), (0, combinator_1.some)((0, combinator_1.union)([bracket, source_1.escsource]), ']'), (0, source_1.str)(']'), true, undefined, ([as, bs = []], rest) => [(0, array_1.unshift)(as, bs), rest], 3 | 28 /* Backtrack.template */), (0, combinator_1.surround)((0, source_1.str)('{'), (0, combinator_1.some)((0, combinator_1.union)([bracket, source_1.escsource]), '}'), (0, source_1.str)('}'), true, undefined, ([as, bs = []], rest) => [(0, array_1.unshift)(as, bs), rest], 3 | 28 /* Backtrack.template */), (0, combinator_1.surround)((0, source_1.str)('"'), (0, combinator_1.precedence)(3, (0, combinator_1.some)(source_1.escsource, /^"|^\\?\n/)), (0, source_1.str)('"'), true, undefined, undefined, 3 | 28 /* Backtrack.template */)])));
4967
4962
 
4968
4963
  /***/ },
4969
4964
 
@@ -5003,11 +4998,11 @@ const source_1 = __webpack_require__(8745);
5003
4998
  const array_1 = __webpack_require__(6876);
5004
4999
  const dom_1 = __webpack_require__(394);
5005
5000
  const index = /^[0-9A-Za-z]+(?:(?:[.-]|, )[0-9A-Za-z]+)*/;
5006
- exports.bracket = (0, combinator_1.lazy)(() => (0, combinator_1.union)([(0, combinator_1.surround)((0, source_1.str)('('), (0, combinator_1.creation)(0, 5 /* Recursion.bracket */, (0, combinator_1.syntax)(2, 0 /* State.none */, (0, source_1.str)(index))), (0, source_1.str)(')')), (0, combinator_1.surround)((0, source_1.str)('('), (0, combinator_1.creation)(0, 5 /* Recursion.bracket */, (0, combinator_1.syntax)(2, 0 /* State.none */, (0, combinator_1.some)(inline_1.inline, ')', [[/^\\?\n/, 3], [')', 2]]))), (0, source_1.str)(')'), true, ([as, bs = [], cs], rest) => [[(0, dom_1.html)('span', {
5001
+ exports.bracket = (0, combinator_1.lazy)(() => (0, combinator_1.union)([(0, combinator_1.surround)((0, source_1.str)('('), (0, combinator_1.creation)(0, 5 /* Recursion.bracket */, (0, combinator_1.syntax)(2, 0 /* State.none */, (0, source_1.str)(index))), (0, source_1.str)(')')), (0, combinator_1.surround)((0, source_1.str)('('), (0, combinator_1.creation)(0, 5 /* Recursion.bracket */, (0, combinator_1.syntax)(2, 0 /* State.none */, (0, combinator_1.some)(inline_1.inline, ')', [[')', 2]]))), (0, source_1.str)(')'), true, ([as, bs = [], cs], rest) => [[(0, dom_1.html)('span', {
5007
5002
  class: 'paren'
5008
- }, (0, dom_1.defrag)((0, array_1.push)((0, array_1.unshift)(as, bs), cs)))], rest], ([as, bs = []], rest) => [(0, array_1.unshift)(as, bs), rest], 3), (0, combinator_1.surround)((0, source_1.str)('('), (0, combinator_1.creation)(0, 5 /* Recursion.bracket */, (0, combinator_1.syntax)(2, 0 /* State.none */, (0, source_1.str)(new RegExp(index.source.replace(', ', '[,、]').replace(/[09AZaz.]|\-(?!\w)/g, c => c.trimStart() && String.fromCharCode(c.charCodeAt(0) + 0xFEE0)))))), (0, source_1.str)(')')), (0, combinator_1.surround)((0, source_1.str)('('), (0, combinator_1.creation)(0, 5 /* Recursion.bracket */, (0, combinator_1.syntax)(2, 0 /* State.none */, (0, combinator_1.some)(inline_1.inline, ')', [[/^\\?\n/, 3], [')', 2]]))), (0, source_1.str)(')'), true, ([as, bs = [], cs], rest) => [[(0, dom_1.html)('span', {
5003
+ }, (0, dom_1.defrag)((0, array_1.push)((0, array_1.unshift)(as, bs), cs)))], rest], ([as, bs = []], rest) => [(0, array_1.unshift)(as, bs), rest], 3 | 4 /* Backtrack.bracket */), (0, combinator_1.surround)((0, source_1.str)('('), (0, combinator_1.creation)(0, 5 /* Recursion.bracket */, (0, combinator_1.syntax)(2, 0 /* State.none */, (0, source_1.str)(new RegExp(index.source.replace(', ', '[,、]').replace(/[09AZaz.]|\-(?!\w)/g, c => c.trimStart() && String.fromCharCode(c.charCodeAt(0) + 0xFEE0)))))), (0, source_1.str)(')')), (0, combinator_1.surround)((0, source_1.str)('('), (0, combinator_1.creation)(0, 5 /* Recursion.bracket */, (0, combinator_1.syntax)(2, 0 /* State.none */, (0, combinator_1.some)(inline_1.inline, ')', [[')', 2]]))), (0, source_1.str)(')'), true, ([as, bs = [], cs], rest) => [[(0, dom_1.html)('span', {
5009
5004
  class: 'paren'
5010
- }, (0, dom_1.defrag)((0, array_1.push)((0, array_1.unshift)(as, bs), cs)))], rest], ([as, bs = []], rest) => [(0, array_1.unshift)(as, bs), rest]), (0, combinator_1.surround)((0, source_1.str)('['), (0, combinator_1.creation)(0, 5 /* Recursion.bracket */, (0, combinator_1.syntax)(2, 0 /* State.none */, (0, combinator_1.some)(inline_1.inline, ']', [[/^\\?\n/, 3], [']', 2]]))), (0, source_1.str)(']'), true, undefined, ([as, bs = []], rest) => [(0, array_1.unshift)(as, bs), rest], 3), (0, combinator_1.surround)((0, source_1.str)('['), (0, combinator_1.creation)(0, 5 /* Recursion.bracket */, (0, combinator_1.syntax)(2, 0 /* State.none */, (0, combinator_1.some)(inline_1.inline, ']', [[/^\\?\n/, 3], [']', 2]]))), (0, source_1.str)(']'), true, undefined, ([as, bs = []], rest) => [(0, array_1.unshift)(as, bs), rest]), (0, combinator_1.surround)((0, source_1.str)('{'), (0, combinator_1.creation)(0, 5 /* Recursion.bracket */, (0, combinator_1.syntax)(2, 0 /* State.none */, (0, combinator_1.some)(inline_1.inline, '}', [[/^\\?\n/, 3], ['}', 2]]))), (0, source_1.str)('}'), true, undefined, ([as, bs = []], rest) => [(0, array_1.unshift)(as, bs), rest], 3), (0, combinator_1.surround)((0, source_1.str)('{'), (0, combinator_1.creation)(0, 5 /* Recursion.bracket */, (0, combinator_1.syntax)(2, 0 /* State.none */, (0, combinator_1.some)(inline_1.inline, '}', [[/^\\?\n/, 3], ['}', 2]]))), (0, source_1.str)('}'), true, undefined, ([as, bs = []], rest) => [(0, array_1.unshift)(as, bs), rest]), (0, combinator_1.surround)((0, source_1.str)('"'), (0, combinator_1.creation)(0, 5 /* Recursion.bracket */, (0, combinator_1.syntax)(3, 0 /* State.none */, (0, combinator_1.some)(inline_1.inline, '"', [[/^\\?\n/, 4], ['"', 3]]))), (0, source_1.str)('"'), true, undefined, ([as, bs = []], rest) => [(0, array_1.unshift)(as, bs), rest]), (0, combinator_1.surround)((0, source_1.str)('“'), (0, combinator_1.creation)(0, 5 /* Recursion.bracket */, (0, combinator_1.syntax)(3, 0 /* State.none */, (0, combinator_1.some)(inline_1.inline, '”', [[/^\\?\n/, 4], ['”', 3]]))), (0, source_1.str)('”'), true, undefined, ([as, bs = []], rest) => [(0, array_1.unshift)(as, bs), rest]), (0, combinator_1.surround)((0, source_1.str)('‘'), (0, combinator_1.creation)(0, 5 /* Recursion.bracket */, (0, combinator_1.syntax)(3, 0 /* State.none */, (0, combinator_1.some)(inline_1.inline, '’', [[/^\\?\n/, 4], ['’', 3]]))), (0, source_1.str)('’'), true, undefined, ([as, bs = []], rest) => [(0, array_1.unshift)(as, bs), rest]), (0, combinator_1.surround)((0, source_1.str)('「'), (0, combinator_1.creation)(0, 5 /* Recursion.bracket */, (0, combinator_1.syntax)(3, 0 /* State.none */, (0, combinator_1.some)(inline_1.inline, '」', [[/^\\?\n/, 4], ['」', 3]]))), (0, source_1.str)('」'), true, undefined, ([as, bs = []], rest) => [(0, array_1.unshift)(as, bs), rest]), (0, combinator_1.surround)((0, source_1.str)('『'), (0, combinator_1.creation)(0, 5 /* Recursion.bracket */, (0, combinator_1.syntax)(3, 0 /* State.none */, (0, combinator_1.some)(inline_1.inline, '』', [[/^\\?\n/, 4], ['』', 3]]))), (0, source_1.str)('』'), true, undefined, ([as, bs = []], rest) => [(0, array_1.unshift)(as, bs), rest])]));
5005
+ }, (0, dom_1.defrag)((0, array_1.push)((0, array_1.unshift)(as, bs), cs)))], rest], ([as, bs = []], rest) => [(0, array_1.unshift)(as, bs), rest]), (0, combinator_1.surround)((0, source_1.str)('['), (0, combinator_1.creation)(0, 5 /* Recursion.bracket */, (0, combinator_1.syntax)(2, 0 /* State.none */, (0, combinator_1.some)(inline_1.inline, ']', [[']', 2]]))), (0, source_1.str)(']'), true, undefined, ([as, bs = []], rest) => [(0, array_1.unshift)(as, bs), rest], 3 | 4 /* Backtrack.bracket */), (0, combinator_1.surround)((0, source_1.str)('['), (0, combinator_1.creation)(0, 5 /* Recursion.bracket */, (0, combinator_1.syntax)(2, 0 /* State.none */, (0, combinator_1.some)(inline_1.inline, ']', [[']', 2]]))), (0, source_1.str)(']'), true, undefined, ([as, bs = []], rest) => [(0, array_1.unshift)(as, bs), rest]), (0, combinator_1.surround)((0, source_1.str)('{'), (0, combinator_1.creation)(0, 5 /* Recursion.bracket */, (0, combinator_1.syntax)(2, 0 /* State.none */, (0, combinator_1.some)(inline_1.inline, '}', [['}', 2]]))), (0, source_1.str)('}'), true, undefined, ([as, bs = []], rest) => [(0, array_1.unshift)(as, bs), rest], 3 | 4 /* Backtrack.bracket */), (0, combinator_1.surround)((0, source_1.str)('{'), (0, combinator_1.creation)(0, 5 /* Recursion.bracket */, (0, combinator_1.syntax)(2, 0 /* State.none */, (0, combinator_1.some)(inline_1.inline, '}', [['}', 2]]))), (0, source_1.str)('}'), true, undefined, ([as, bs = []], rest) => [(0, array_1.unshift)(as, bs), rest]), (0, combinator_1.surround)((0, source_1.str)('"'), (0, combinator_1.creation)(0, 5 /* Recursion.bracket */, (0, combinator_1.syntax)(3, 0 /* State.none */, (0, combinator_1.some)(inline_1.inline, '"', [[/^\\?\n/, 9], ['"', 3]]))), (0, source_1.str)('"'), true, undefined, ([as, bs = []], rest) => [(0, array_1.unshift)(as, bs), rest]), (0, combinator_1.surround)((0, source_1.str)('“'), (0, combinator_1.creation)(0, 5 /* Recursion.bracket */, (0, combinator_1.syntax)(3, 0 /* State.none */, (0, combinator_1.some)(inline_1.inline, '”', [[/^\\?\n/, 9], ['”', 3]]))), (0, source_1.str)('”'), true, undefined, ([as, bs = []], rest) => [(0, array_1.unshift)(as, bs), rest]), (0, combinator_1.surround)((0, source_1.str)('‘'), (0, combinator_1.creation)(0, 5 /* Recursion.bracket */, (0, combinator_1.syntax)(3, 0 /* State.none */, (0, combinator_1.some)(inline_1.inline, '’', [[/^\\?\n/, 9], ['’', 3]]))), (0, source_1.str)('’'), true, undefined, ([as, bs = []], rest) => [(0, array_1.unshift)(as, bs), rest]), (0, combinator_1.surround)((0, source_1.str)('「'), (0, combinator_1.creation)(0, 5 /* Recursion.bracket */, (0, combinator_1.syntax)(3, 0 /* State.none */, (0, combinator_1.some)(inline_1.inline, '」', [[/^\\?\n/, 9], ['」', 3]]))), (0, source_1.str)('」'), true, undefined, ([as, bs = []], rest) => [(0, array_1.unshift)(as, bs), rest]), (0, combinator_1.surround)((0, source_1.str)('『'), (0, combinator_1.creation)(0, 5 /* Recursion.bracket */, (0, combinator_1.syntax)(3, 0 /* State.none */, (0, combinator_1.some)(inline_1.inline, '』', [[/^\\?\n/, 9], ['』', 3]]))), (0, source_1.str)('』'), true, undefined, ([as, bs = []], rest) => [(0, array_1.unshift)(as, bs), rest])]));
5011
5006
 
5012
5007
  /***/ },
5013
5008
 
@@ -5089,7 +5084,7 @@ const visibility_1 = __webpack_require__(6364);
5089
5084
  const dom_1 = __webpack_require__(394);
5090
5085
  exports.index = (0, combinator_1.lazy)(() => (0, combinator_1.validate)('[#', (0, combinator_1.creation)(1, 0 /* Recursion.ignore */, (0, combinator_1.fmap)((0, indexee_1.indexee)((0, combinator_1.surround)('[#', (0, combinator_1.constraint)(64 /* State.index */, false, (0, combinator_1.syntax)(2, 502 /* State.linkers */ | 8 /* State.media */, (0, visibility_1.startTight)((0, combinator_1.some)((0, combinator_1.inits)([inline_1.inline, exports.signature]), ']', [[/^\\?\n/, 9], [']', 2]])))), ']', false, ([, ns], rest) => [[(0, dom_1.html)('a', {
5091
5086
  'data-index': dataindex(ns)
5092
- }, (0, visibility_1.trimNodeEnd)((0, dom_1.defrag)(ns)))], rest], undefined, 1)), ([el]) => [(0, dom_1.define)(el, {
5087
+ }, (0, visibility_1.trimNodeEnd)((0, dom_1.defrag)(ns)))], rest], undefined, 1 | 4 /* Backtrack.bracket */)), ([el]) => [(0, dom_1.define)(el, {
5093
5088
  id: el.id ? null : undefined,
5094
5089
  class: 'index',
5095
5090
  href: el.id ? `#${el.id}` : undefined
@@ -5098,7 +5093,7 @@ exports.signature = (0, combinator_1.lazy)(() => (0, combinator_1.validate)('|',
5098
5093
  class: 'indexer',
5099
5094
  'data-index': (0, indexee_1.identity)('index', undefined, ns.join('')).slice(7)
5100
5095
  })]))));
5101
- const bracket = (0, combinator_1.lazy)(() => (0, combinator_1.creation)(0, 6 /* Recursion.terminal */, (0, combinator_1.union)([(0, combinator_1.surround)((0, source_1.str)('('), (0, combinator_1.some)((0, combinator_1.union)([bracket, source_1.txt]), ')'), (0, source_1.str)(')'), true), (0, combinator_1.surround)((0, source_1.str)('['), (0, combinator_1.some)((0, combinator_1.union)([bracket, source_1.txt]), ']'), (0, source_1.str)(']'), true), (0, combinator_1.surround)((0, source_1.str)('{'), (0, combinator_1.some)((0, combinator_1.union)([bracket, source_1.txt]), '}'), (0, source_1.str)('}'), true), (0, combinator_1.surround)((0, source_1.str)('"'), (0, combinator_1.precedence)(3, (0, combinator_1.some)(source_1.txt, '"')), (0, source_1.str)('"'), true)])));
5096
+ const bracket = (0, combinator_1.lazy)(() => (0, combinator_1.creation)(0, 6 /* Recursion.terminal */, (0, combinator_1.union)([(0, combinator_1.surround)((0, source_1.str)('('), (0, combinator_1.some)((0, combinator_1.union)([bracket, source_1.txt]), ')'), (0, source_1.str)(')'), true, undefined, undefined, 3 | 12 /* Backtrack.index */), (0, combinator_1.surround)((0, source_1.str)('['), (0, combinator_1.some)((0, combinator_1.union)([bracket, source_1.txt]), ']'), (0, source_1.str)(']'), true, undefined, undefined, 3 | 12 /* Backtrack.index */), (0, combinator_1.surround)((0, source_1.str)('{'), (0, combinator_1.some)((0, combinator_1.union)([bracket, source_1.txt]), '}'), (0, source_1.str)('}'), true, undefined, undefined, 3 | 12 /* Backtrack.index */), (0, combinator_1.surround)((0, source_1.str)('"'), (0, combinator_1.precedence)(3, (0, combinator_1.some)(source_1.txt, '"')), (0, source_1.str)('"'), true, undefined, undefined, 3 | 12 /* Backtrack.index */)])));
5102
5097
  function dataindex(ns) {
5103
5098
  if (ns.length === 0) return;
5104
5099
  for (let i = ns.length - 1; i >= 0; --i) {
@@ -5605,7 +5600,7 @@ function context(base, parser) {
5605
5600
  exports.context = context;
5606
5601
  function apply(parser, source, context, changes, values, reset = false) {
5607
5602
  if (reset) {
5608
- context.log = {};
5603
+ context.logger = {};
5609
5604
  }
5610
5605
  for (let i = 0; i < changes.length; ++i) {
5611
5606
  const change = changes[i];
@@ -5820,12 +5815,14 @@ function surround(opener, parser, closer, optional = false, f, g, log = 0) {
5820
5815
  const mr_ = (0, parser_1.exec)(res1);
5821
5816
  if (log & 1) {
5822
5817
  const {
5823
- log = {},
5818
+ logger = {},
5824
5819
  offset = 0
5825
5820
  } = context;
5826
5821
  for (let i = 0; i < source.length - mr_.length; ++i) {
5827
5822
  if (source[i] !== source[0]) break;
5828
- if (source.length + offset - i in log) return;
5823
+ const j = source.length + offset - i;
5824
+ if (!(j in logger)) continue;
5825
+ if (logger[j] & 1 << (log >>> 2)) return;
5829
5826
  }
5830
5827
  }
5831
5828
  const res2 = mr_ !== '' ? parser({
@@ -5844,10 +5841,10 @@ function surround(opener, parser, closer, optional = false, f, g, log = 0) {
5844
5841
  if (rest.length === lmr_.length) return;
5845
5842
  if (log & 2 && rr === undefined) {
5846
5843
  const {
5847
- log = {},
5844
+ logger = {},
5848
5845
  offset = 0
5849
5846
  } = context;
5850
- log[source.length + offset] = 0;
5847
+ logger[source.length + offset] |= 1 << (log >>> 2);
5851
5848
  }
5852
5849
  return rr ? f ? f([rl, rm, rr], rest, context) : [(0, array_1.push)((0, array_1.unshift)(rl, rm ?? []), rr), rest] : g ? g([rl, rm, mr_], rest, context) : undefined;
5853
5850
  };
@@ -6048,7 +6045,7 @@ exports.placeholder = (0, combinator_1.lazy)(() => (0, combinator_1.validate)('[
6048
6045
  'data-invalid-syntax': 'extension',
6049
6046
  'data-invalid-type': 'syntax',
6050
6047
  'data-invalid-message': `Invalid start symbol or linebreak`
6051
- }, (0, dom_1.defrag)(bs))], rest], ([as, bs], rest) => [(0, array_1.unshift)(as, bs), rest], 3))));
6048
+ }, (0, dom_1.defrag)(bs))], rest], ([as, bs], rest) => [(0, array_1.unshift)(as, bs), rest], 3 | 4 /* Backtrack.bracket */))));
6052
6049
 
6053
6050
  /***/ },
6054
6051
 
@@ -6377,14 +6374,14 @@ function convert(conv, parser, empty = false) {
6377
6374
  if (src === '') return empty ? [[], ''] : undefined;
6378
6375
  const sub = source.endsWith(src);
6379
6376
  const {
6380
- log
6377
+ logger
6381
6378
  } = context;
6382
- context.log = sub ? log : {};
6379
+ context.logger = sub ? logger : {};
6383
6380
  const result = parser({
6384
6381
  source: src,
6385
6382
  context
6386
6383
  });
6387
- context.log = log;
6384
+ context.logger = logger;
6388
6385
  return result;
6389
6386
  };
6390
6387
  }
@@ -6983,14 +6980,20 @@ const source_1 = __webpack_require__(8745);
6983
6980
  const visibility_1 = __webpack_require__(6364);
6984
6981
  const array_1 = __webpack_require__(6876);
6985
6982
  const dom_1 = __webpack_require__(394);
6986
- exports.ruby = (0, combinator_1.lazy)(() => (0, combinator_1.validate)('[', (0, combinator_1.creation)(1, 0 /* Recursion.ignore */, (0, combinator_1.syntax)(2, -1 /* State.all */, (0, combinator_1.fmap)((0, combinator_1.verify)((0, combinator_1.fmap)((0, combinator_1.sequence)([(0, combinator_1.surround)('[', (0, source_1.str)(/^(?:\\[^\n]|[^\\[\](){}"\n])+/), ']'), (0, combinator_1.surround)('(', (0, source_1.str)(/^(?:\\[^\n]|[^\\[\](){}"\n])+/), ')')]), ([texts, rubies], _, context) => [(0, parser_1.eval)(text({
6987
- source: texts,
6988
- context
6989
- }), [])[0] ?? '', (0, parser_1.eval)(text({
6990
- source: rubies,
6991
- context
6992
- }), [])[0] ?? '']), ([texts, rubies]) => texts && rubies && (0, visibility_1.isStartTightNodes)(texts)), ([texts, rubies]) => {
6993
- texts[texts.length - 1] === '' && texts.pop();
6983
+ exports.ruby = (0, combinator_1.lazy)(() => (0, combinator_1.validate)('[', (0, combinator_1.creation)(1, 0 /* Recursion.ignore */, (0, combinator_1.syntax)(2, -1 /* State.all */, (0, combinator_1.fmap)((0, combinator_1.sequence)([(0, combinator_1.bind)((0, combinator_1.surround)('[', (0, source_1.str)(/^(?:\\[^\n]|[^\\[\](){}"\n])+/), ']', false, undefined, undefined, 3 | 20 /* Backtrack.ruby */), ([source], rest, context) => {
6984
+ const ns = (0, parser_1.eval)(text({
6985
+ source,
6986
+ context
6987
+ }), [undefined])[0];
6988
+ ns && ns[ns.length - 1] === '' && ns.pop();
6989
+ return ns && (0, visibility_1.isStartTightNodes)(ns) ? [[ns], rest] : undefined;
6990
+ }), (0, combinator_1.bind)((0, combinator_1.surround)('(', (0, source_1.str)(/^(?:\\[^\n]|[^\\[\](){}"\n])+/), ')', false, undefined, undefined, 3 | 20 /* Backtrack.ruby */), ([source], rest, context) => {
6991
+ const ns = (0, parser_1.eval)(text({
6992
+ source,
6993
+ context
6994
+ }), [undefined])[0];
6995
+ return ns && [[ns], rest];
6996
+ })]), ([texts, rubies]) => {
6994
6997
  switch (true) {
6995
6998
  case rubies.length <= texts.length:
6996
6999
  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')])), [])))];
@@ -7137,7 +7140,7 @@ const optspec = {
7137
7140
  rel: undefined
7138
7141
  };
7139
7142
  Object.setPrototypeOf(optspec, null);
7140
- exports.media = (0, combinator_1.lazy)(() => (0, combinator_1.validate)(['![', '!{'], (0, combinator_1.creation)(1, 0 /* Recursion.ignore */, (0, combinator_1.open)('!', (0, combinator_1.constraint)(8 /* State.media */, false, (0, combinator_1.syntax)(2, ~16 /* State.link */, (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.some)((0, combinator_1.union)([htmlentity_1.unsafehtmlentity, bracket, source_1.txt]), ']', [[/^\\?\n/, 9]]), ']', true)), (0, combinator_1.dup)((0, combinator_1.surround)(/^{(?![{}])/, (0, combinator_1.inits)([link_1.uri, (0, combinator_1.some)(option)]), /^[^\S\n]*}/))]), ([as, bs]) => bs ? [[as.join('').trim() || as.join('')], bs] : [[''], as]), ([[text]]) => text === '' || text.trim() !== ''), ([[text], params], rest, context) => {
7143
+ exports.media = (0, combinator_1.lazy)(() => (0, combinator_1.validate)(['![', '!{'], (0, combinator_1.creation)(1, 0 /* Recursion.ignore */, (0, combinator_1.open)('!', (0, combinator_1.constraint)(8 /* State.media */, false, (0, combinator_1.syntax)(2, ~16 /* State.link */, (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.some)((0, combinator_1.union)([htmlentity_1.unsafehtmlentity, bracket, source_1.txt]), ']', [[/^\\?\n/, 9]]), ']', true, undefined, undefined, 1 | 24 /* Backtrack.media */)), (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 | 16 /* Backtrack.link */))]), ([as, bs]) => bs ? [[as.join('').trim() || as.join('')], bs] : [[''], as]), ([[text]]) => text === '' || text.trim() !== ''), ([[text], params], rest, context) => {
7141
7144
  const INSECURE_URI = params.shift();
7142
7145
  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);
7143
7146
  let cache;
@@ -7164,7 +7167,7 @@ exports.media = (0, combinator_1.lazy)(() => (0, combinator_1.validate)(['![', '
7164
7167
  });
7165
7168
  })))))));
7166
7169
  exports.linemedia = (0, combinator_1.surround)(source_1.linebreak, (0, combinator_1.union)([exports.media]), /^(?=[^\S\n]*(?:$|\n))/);
7167
- const bracket = (0, combinator_1.lazy)(() => (0, combinator_1.creation)(0, 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, ([as, bs = []], rest) => [(0, array_1.unshift)(as, bs), rest]), (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, ([as, bs = []], rest) => [(0, array_1.unshift)(as, bs), rest]), (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, ([as, bs = []], rest) => [(0, array_1.unshift)(as, bs), rest]), (0, combinator_1.surround)((0, source_1.str)('"'), (0, combinator_1.precedence)(3, (0, combinator_1.some)((0, combinator_1.union)([htmlentity_1.unsafehtmlentity, source_1.txt]), '"')), (0, source_1.str)('"'), true)])));
7170
+ const bracket = (0, combinator_1.lazy)(() => (0, combinator_1.creation)(0, 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, ([as, bs = []], rest) => [(0, array_1.unshift)(as, bs), rest], 3 | 24 /* Backtrack.media */), (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, ([as, bs = []], rest) => [(0, array_1.unshift)(as, bs), rest], 3 | 24 /* Backtrack.media */), (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, ([as, bs = []], rest) => [(0, array_1.unshift)(as, bs), rest], 3 | 24 /* Backtrack.media */), (0, combinator_1.surround)((0, source_1.str)('"'), (0, combinator_1.precedence)(3, (0, combinator_1.some)((0, combinator_1.union)([htmlentity_1.unsafehtmlentity, source_1.txt]), '"')), (0, source_1.str)('"'), true, undefined, undefined, 3 | 24 /* Backtrack.media */)])));
7168
7171
  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]));
7169
7172
  function sanitize(target, uri, alt) {
7170
7173
  switch (uri.protocol) {
@@ -7627,9 +7630,9 @@ function rewrite(scope, parser) {
7627
7630
  }) => {
7628
7631
  if (source === '') return;
7629
7632
  const {
7630
- log
7633
+ logger
7631
7634
  } = context;
7632
- context.log = {};
7635
+ context.logger = {};
7633
7636
  //const { resources = { clock: 0 } } = context;
7634
7637
  //const clock = resources.clock;
7635
7638
  const res1 = scope({
@@ -7637,7 +7640,7 @@ function rewrite(scope, parser) {
7637
7640
  context
7638
7641
  });
7639
7642
  //resources.clock = clock;
7640
- context.log = log;
7643
+ context.logger = logger;
7641
7644
  if (res1 === undefined || (0, parser_1.exec)(res1).length >= source.length) return;
7642
7645
  const src = source.slice(0, source.length - (0, parser_1.exec)(res1).length);
7643
7646
  const offset = source.length - src.length;
@@ -8659,7 +8662,7 @@ const inline_1 = __webpack_require__(7973);
8659
8662
  const source_1 = __webpack_require__(8745);
8660
8663
  const visibility_1 = __webpack_require__(6364);
8661
8664
  const dom_1 = __webpack_require__(394);
8662
- exports.reference = (0, combinator_1.lazy)(() => (0, combinator_1.creation)(1, 0 /* Recursion.ignore */, (0, combinator_1.surround)('[[', (0, combinator_1.constraint)(128 /* State.reference */, false, (0, combinator_1.syntax)(6, 256 /* State.annotation */ | 128 /* State.reference */ | 8 /* State.media */, (0, combinator_1.subsequence)([abbr, (0, visibility_1.trimBlankStart)((0, combinator_1.some)(inline_1.inline, ']', [[/^\\?\n/, 9], [']', 2], [']]', 6]]))]))), ']]', false, ([, ns], rest) => [[(0, dom_1.html)('sup', attributes(ns), [(0, dom_1.html)('span', (0, visibility_1.trimNodeEnd)((0, dom_1.defrag)(ns)))])], rest], undefined, 1)));
8665
+ exports.reference = (0, combinator_1.lazy)(() => (0, combinator_1.creation)(1, 0 /* Recursion.ignore */, (0, combinator_1.surround)('[[', (0, combinator_1.constraint)(128 /* State.reference */, false, (0, combinator_1.syntax)(6, 256 /* State.annotation */ | 128 /* State.reference */ | 8 /* State.media */, (0, combinator_1.subsequence)([abbr, (0, visibility_1.trimBlankStart)((0, combinator_1.some)(inline_1.inline, ']', [[/^\\?\n/, 9], [']', 2]]))]))), ']]', false, ([, ns], rest) => [[(0, dom_1.html)('sup', attributes(ns), [(0, dom_1.html)('span', (0, visibility_1.trimNodeEnd)((0, dom_1.defrag)(ns)))])], rest], undefined, 1 | 4 /* Backtrack.bracket */)));
8663
8666
  // Chicago-Style
8664
8667
  const abbr = (0, combinator_1.creation)(1, 0 /* Recursion.ignore */, (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}`]));
8665
8668
  function attributes(ns) {
package/markdown.d.ts CHANGED
@@ -819,8 +819,8 @@ export namespace MarkdownParser {
819
819
  // [AB](a b)
820
820
  Inline<'ruby'>,
821
821
  Parser<HTMLElement, Context, [
822
- SourceParser.StrParser,
823
- SourceParser.StrParser,
822
+ Parser<string[], Context, []>,
823
+ Parser<string[], Context, []>,
824
824
  ]> {
825
825
  }
826
826
  export namespace RubyParser {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "securemark",
3
- "version": "0.283.0",
3
+ "version": "0.283.2",
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",
@@ -8,11 +8,11 @@ export function convert<T>(conv: (source: string, context: Ctx) => string, parse
8
8
  const src = conv(source, context);
9
9
  if (src === '') return empty ? [[], ''] : undefined;
10
10
  const sub = source.endsWith(src);
11
- const { log } = context;
12
- context.log = sub ? log : {};
11
+ const { logger } = context;
12
+ context.logger = sub ? logger : {};
13
13
  const result = parser({ source: src, context });
14
14
  assert(check(src, result));
15
- context.log = log;
15
+ context.logger = logger;
16
16
  return result;
17
17
  };
18
18
  }
@@ -20,10 +20,10 @@ export function indent<T>(opener: RegExp | Parser<T>, parser?: Parser<T> | boole
20
20
  ([indent]) => indent.length * 2 + +(indent[0] === ' '), {})), separation),
21
21
  (lines, rest, context) => {
22
22
  assert(parser = parser as Parser<T>);
23
- const { log } = context;
24
- context.log = {};
23
+ const { logger } = context;
24
+ context.logger = {};
25
25
  const result = parser({ source: trimBlockEnd(lines.join('')), context });
26
- context.log = log;
26
+ context.logger = logger;
27
27
  return result && exec(result) === ''
28
28
  ? [eval(result), rest]
29
29
  : undefined;
@@ -34,14 +34,14 @@ export function rewrite<T>(scope: Parser<unknown>, parser: Parser<T>): Parser<T>
34
34
  assert(parser);
35
35
  return ({ source, context }) => {
36
36
  if (source === '') return;
37
- const { log } = context;
38
- context.log = {};
37
+ const { logger } = context;
38
+ context.logger = {};
39
39
  //const { resources = { clock: 0 } } = context;
40
40
  //const clock = resources.clock;
41
41
  const res1 = scope({ source, context });
42
42
  assert(check(source, res1));
43
43
  //resources.clock = clock;
44
- context.log = log;
44
+ context.logger = logger;
45
45
  if (res1 === undefined || exec(res1).length >= source.length) return;
46
46
  const src = source.slice(0, source.length - exec(res1).length);
47
47
  assert(src !== '');
@@ -3,33 +3,39 @@ import { fmap } from '../monad/fmap';
3
3
  import { unshift, push } from 'spica/array';
4
4
 
5
5
  export function surround<P extends Parser<unknown>, S = string>(
6
- opener: string | RegExp | Parser<S, Context<P>>, parser: IntermediateParser<P>, closer: string | RegExp | Parser<S, Context<P>>, optional?: false,
6
+ opener: string | RegExp | Parser<S, Context<P>>, parser: IntermediateParser<P>, closer: string | RegExp | Parser<S, Context<P>>,
7
+ optional?: false,
7
8
  f?: (rss: [S[], SubTree<P>[], S[]], rest: string, context: Context<P>) => Result<Tree<P>, Context<P>, SubParsers<P>>,
8
9
  g?: (rss: [S[], SubTree<P>[], string], rest: string, context: Context<P>) => Result<Tree<P>, Context<P>, SubParsers<P>>,
9
- log?: 0 | 1 | 2 | 3,
10
+ log?: number,
10
11
  ): P;
11
12
  export function surround<P extends Parser<unknown>, S = string>(
12
- opener: string | RegExp | Parser<S, Context<P>>, parser: IntermediateParser<P>, closer: string | RegExp | Parser<S, Context<P>>, optional?: boolean,
13
+ opener: string | RegExp | Parser<S, Context<P>>, parser: IntermediateParser<P>, closer: string | RegExp | Parser<S, Context<P>>,
14
+ optional?: boolean,
13
15
  f?: (rss: [S[], SubTree<P>[] | undefined, S[]], rest: string, context: Context<P>) => Result<Tree<P>, Context<P>, SubParsers<P>>,
14
16
  g?: (rss: [S[], SubTree<P>[] | undefined, string], rest: string, context: Context<P>) => Result<Tree<P>, Context<P>, SubParsers<P>>,
17
+ log?: number,
15
18
  ): P;
16
19
  export function surround<P extends Parser<unknown>, S = string>(
17
- opener: string | RegExp | Parser<S, Context<P>>, parser: P, closer: string | RegExp | Parser<S, Context<P>>, optional?: false,
20
+ opener: string | RegExp | Parser<S, Context<P>>, parser: P, closer: string | RegExp | Parser<S, Context<P>>,
21
+ optional?: false,
18
22
  f?: (rss: [S[], Tree<P>[], S[]], rest: string, context: Context<P>) => Result<Tree<P>, Context<P>, SubParsers<P>>,
19
23
  g?: (rss: [S[], Tree<P>[], string], rest: string, context: Context<P>) => Result<Tree<P>, Context<P>, SubParsers<P>>,
20
- log?: 0 | 1 | 2 | 3,
24
+ log?: number,
21
25
  ): P;
22
26
  export function surround<P extends Parser<unknown>, S = string>(
23
- opener: string | RegExp | Parser<S, Context<P>>, parser: P, closer: string | RegExp | Parser<S, Context<P>>, optional?: boolean,
27
+ opener: string | RegExp | Parser<S, Context<P>>, parser: P, closer: string | RegExp | Parser<S, Context<P>>,
28
+ optional?: boolean,
24
29
  f?: (rss: [S[], Tree<P>[] | undefined, S[]], rest: string, context: Context<P>) => Result<Tree<P>, Context<P>, SubParsers<P>>,
25
30
  g?: (rss: [S[], Tree<P>[] | undefined, string], rest: string, context: Context<P>) => Result<Tree<P>, Context<P>, SubParsers<P>>,
26
- log?: 0 | 1 | 2 | 3,
31
+ log?: number,
27
32
  ): P;
28
33
  export function surround<T>(
29
- opener: string | RegExp | Parser<T>, parser: Parser<T>, closer: string | RegExp | Parser<T>, optional: boolean = false,
34
+ opener: string | RegExp | Parser<T>, parser: Parser<T>, closer: string | RegExp | Parser<T>,
35
+ optional: boolean = false,
30
36
  f?: (rss: [T[], T[], T[]], rest: string, context: Ctx) => Result<T>,
31
37
  g?: (rss: [T[], T[], string], rest: string, context: Ctx) => Result<T>,
32
- log: 0 | 1 | 2 | 3 = 0,
38
+ log: number = 0,
33
39
  ): Parser<T> {
34
40
  switch (typeof opener) {
35
41
  case 'string':
@@ -50,10 +56,13 @@ export function surround<T>(
50
56
  const rl = eval(res1);
51
57
  const mr_ = exec(res1);
52
58
  if (log & 1) {
53
- const { log = {}, offset = 0 } = context;
59
+ const { logger = {}, offset = 0 } = context;
54
60
  for (let i = 0; i < source.length - mr_.length; ++i) {
55
61
  if (source[i] !== source[0]) break;
56
- if (source.length + offset - i in log) return;
62
+ const j = source.length + offset - i;
63
+ if (!(j in logger)) continue;
64
+ assert(log >>> 2);
65
+ if (logger[j] & 1 << (log >>> 2)) return;
57
66
  }
58
67
  }
59
68
  const res2 = mr_ !== '' ? parser({ source: mr_, context }) : undefined;
@@ -67,8 +76,8 @@ export function surround<T>(
67
76
  const rest = exec(res3, r_);
68
77
  if (rest.length === lmr_.length) return;
69
78
  if (log & 2 && rr === undefined) {
70
- const { log = {}, offset = 0 } = context;
71
- log[source.length + offset] = 0;
79
+ const { logger = {}, offset = 0 } = context;
80
+ logger[source.length + offset] |= 1 << (log >>> 2);
72
81
  }
73
82
  return rr
74
83
  ? f
@@ -25,7 +25,7 @@ export function context<T>(base: Ctx, parser: Parser<T>): Parser<T> {
25
25
  function apply<P extends Parser<unknown>>(parser: P, source: string, context: Context<P>, changes: readonly [string, unknown][], values: unknown[], reset?: boolean): Result<Tree<P>>;
26
26
  function apply<T>(parser: Parser<T>, source: string, context: Ctx, changes: readonly [string, unknown][], values: unknown[], reset = false): Result<T> {
27
27
  if (reset) {
28
- context.log = {};
28
+ context.logger = {};
29
29
  }
30
30
  for (let i = 0; i < changes.length; ++i) {
31
31
  const change = changes[i];
@@ -19,7 +19,7 @@ export interface Ctx {
19
19
  precedence?: number;
20
20
  delimiters?: Delimiters;
21
21
  state?: number;
22
- log?: Record<number, 0>;
22
+ logger?: Record<number, number>;
23
23
  }
24
24
  export type Tree<P extends Parser<unknown>> = P extends Parser<infer T> ? T : never;
25
25
  export type SubParsers<P extends Parser<unknown>> = P extends Parser<unknown, Ctx, infer D> ? D : never;
@@ -286,16 +286,6 @@ describe('Unit: parser/api/parse', () => {
286
286
  ['<p>a<br>b</p>']);
287
287
  });
288
288
 
289
- it('backtrack', () => {
290
- assert.deepStrictEqual(
291
- [...parse('"[% '.repeat(100) + '\n\na').children].map(el => el.outerHTML.replace(/:\w+/, ':rnd')),
292
- [
293
- '<h1 id="error:rnd" class="error">Error: Too much recursion</h1>',
294
- `<pre class="error" translate="no">${'"[% '.repeat(100)}\n</pre>`,
295
- '<p>a</p>',
296
- ]);
297
- });
298
-
299
289
  it('recursion', () => {
300
290
  assert.deepStrictEqual(
301
291
  [...parse(`${'{'.repeat(20)}a`).children].map(el => el.outerHTML),
@@ -329,6 +319,16 @@ describe('Unit: parser/api/parse', () => {
329
319
  [`<p>${'['.repeat(22)}<br>a</p>`]);
330
320
  });
331
321
 
322
+ it('recovery', () => {
323
+ assert.deepStrictEqual(
324
+ [...parse(`${'{'.repeat(21)}\n\na`).children].map(el => el.outerHTML.replace(/:\w+/, ':rnd')),
325
+ [
326
+ `<h1 id="error:rnd" class="error">Error: Too much recursion</h1>`,
327
+ `<pre class="error" translate="no">${'{'.repeat(21)}\n</pre>`,
328
+ '<p>a</p>',
329
+ ]);
330
+ });
331
+
332
332
  if (!navigator.userAgent.includes('Chrome')) return;
333
333
 
334
334
  it('creation', function () {
@@ -344,18 +344,24 @@ describe('Unit: parser/api/parse', () => {
344
344
  [...parse('.'.repeat(20001)).children].map(el => el.outerHTML.replace(/:\w+/, ':rnd')),
345
345
  [
346
346
  '<h1 id="error:rnd" class="error">Error: Too many creations</h1>',
347
- `<pre class="error" translate="no">${'.'.repeat(1000).slice(0, 997)}...</pre>`,
347
+ `<pre class="error" translate="no">${'.'.repeat(1000 - 3)}...</pre>`,
348
348
  ]);
349
349
  });
350
350
 
351
- it('recovery', function () {
351
+ it('backtrack', function () {
352
352
  this.timeout(5000);
353
353
  assert.deepStrictEqual(
354
- [...parse(`${'{'.repeat(21)}\n\na`).children].map(el => el.outerHTML.replace(/:\w+/, ':rnd')),
354
+ [...parse(`(({{${'['.repeat(19)}${'.'.repeat(3301)}`).children].map(el => el.outerHTML.replace(/:\w+/, ':rnd')),
355
+ [`<p>(({{${'['.repeat(19)}${'.'.repeat(3301)}</p>`]);
356
+ });
357
+
358
+ it('backtrack error', function () {
359
+ this.timeout(5000);
360
+ assert.deepStrictEqual(
361
+ [...parse(`(({{${'['.repeat(19)}${'.'.repeat(3302)}`).children].map(el => el.outerHTML.replace(/:\w+/, ':rnd')),
355
362
  [
356
- `<h1 id="error:rnd" class="error">Error: Too much recursion</h1>`,
357
- `<pre class="error" translate="no">${'{'.repeat(21)}\n</pre>`,
358
- '<p>a</p>',
363
+ '<h1 id="error:rnd" class="error">Error: Too many creations</h1>',
364
+ `<pre class="error" translate="no">(({{${'['.repeat(19)}${'.'.repeat(1000 - 4 - 19 - 3)}...</pre>`,
359
365
  ]);
360
366
  });
361
367
 
@@ -29,3 +29,13 @@ export const enum Recursion {
29
29
  bracket,
30
30
  terminal,
31
31
  }
32
+
33
+ export const enum Backtrack {
34
+ template = 7 << 2,
35
+ media = 6 << 2,
36
+ ruby = 5 << 2,
37
+ link = 4 << 2,
38
+ index = 3 << 2,
39
+ url = 2 << 2,
40
+ bracket = 1 << 2,
41
+ }
@@ -13,6 +13,9 @@ describe('Unit: parser/inline/annotation', () => {
13
13
  assert.deepStrictEqual(inspect(parser('((')), undefined);
14
14
  assert.deepStrictEqual(inspect(parser('(())')), undefined);
15
15
  assert.deepStrictEqual(inspect(parser('(()))')), undefined);
16
+ assert.deepStrictEqual(inspect(parser('(("))')), undefined);
17
+ assert.deepStrictEqual(inspect(parser('(([))')), undefined);
18
+ assert.deepStrictEqual(inspect(parser('((<bdi>))')), undefined);
16
19
  assert.deepStrictEqual(inspect(parser('(( ))')), undefined);
17
20
  assert.deepStrictEqual(inspect(parser('(( (a')), undefined);
18
21
  assert.deepStrictEqual(inspect(parser('((\n))')), undefined);
@@ -43,7 +46,6 @@ describe('Unit: parser/inline/annotation', () => {
43
46
  });
44
47
 
45
48
  it('nest', () => {
46
- assert.deepStrictEqual(inspect(parser('((<bdi>))')), [['<sup class="annotation"><span><span class="invalid">&lt;bdi&gt;</span></span></sup>'], '']);
47
49
  assert.deepStrictEqual(inspect(parser('((`a`))')), [['<sup class="annotation"><span><code data-src="`a`">a</code></span></sup>'], '']);
48
50
  assert.deepStrictEqual(inspect(parser('((@a))')), [['<sup class="annotation"><span><a class="account" href="/@a">@a</a></span></sup>'], '']);
49
51
  assert.deepStrictEqual(inspect(parser('((http://host))')), [['<sup class="annotation"><span><a class="url" href="http://host" target="_blank">http://host</a></span></sup>'], '']);
@@ -1,7 +1,7 @@
1
1
  import { AnnotationParser } from '../inline';
2
2
  import { union, some, syntax, creation, constraint, surround, lazy } from '../../combinator';
3
3
  import { inline } from '../inline';
4
- import { State, Recursion } from '../context';
4
+ import { State, Recursion, Backtrack } from '../context';
5
5
  import { trimBlankStart, trimNodeEnd } from '../visibility';
6
6
  import { html, defrag } from 'typed-dom/dom';
7
7
 
@@ -9,8 +9,8 @@ export const annotation: AnnotationParser = lazy(() => creation(1, Recursion.ign
9
9
  '((',
10
10
  constraint(State.annotation, false,
11
11
  syntax(6, State.annotation | State.media,
12
- trimBlankStart(some(union([inline]), ')', [[/^\\?\n/, 9], [')', 2], ['))', 6]])))),
12
+ trimBlankStart(some(union([inline]), ')', [[/^\\?\n/, 9], [')', 2]])))),
13
13
  '))',
14
14
  false,
15
15
  ([, ns], rest) => [[html('sup', { class: 'annotation' }, [html('span', trimNodeEnd(defrag(ns)))])], rest],
16
- undefined, 1)));
16
+ undefined, 1 | Backtrack.bracket)));
@@ -2,7 +2,7 @@ import { AutolinkParser } from '../../inline';
2
2
  import { union, tails, some, creation, precedence, validate, focus, rewrite, convert, surround, open, lazy } from '../../../combinator';
3
3
  import { unsafelink } from '../link';
4
4
  import { linebreak, unescsource, str } from '../../source';
5
- import { Recursion } from '../../context';
5
+ import { Backtrack, Recursion } from '../../context';
6
6
 
7
7
  const closer = /^[-+*=~^_,.;:!?]*(?=[\\"`|\[\](){}<>]|$)/;
8
8
 
@@ -26,8 +26,8 @@ export const lineurl: AutolinkParser.UrlParser.LineUrlParser = lazy(() => open(
26
26
  ])));
27
27
 
28
28
  const bracket: AutolinkParser.UrlParser.BracketParser = lazy(() => creation(0, Recursion.terminal, precedence(2, union([
29
- surround(str('('), some(union([bracket, unescsource]), ')'), str(')'), true),
30
- surround(str('['), some(union([bracket, unescsource]), ']'), str(']'), true),
31
- surround(str('{'), some(union([bracket, unescsource]), '}'), str('}'), true),
32
- surround(str('"'), precedence(3, some(unescsource, '"')), str('"'), true),
29
+ surround(str('('), some(union([bracket, unescsource]), ')'), str(')'), true, undefined, undefined, 3 | Backtrack.url),
30
+ surround(str('['), some(union([bracket, unescsource]), ']'), str(']'), true, undefined, undefined, 3 | Backtrack.url),
31
+ surround(str('{'), some(union([bracket, unescsource]), '}'), str('}'), true, undefined, undefined, 3 | Backtrack.url),
32
+ surround(str('"'), precedence(3, some(unescsource, '"')), str('"'), true, undefined, undefined, 3 | Backtrack.url),
33
33
  ]))));
@@ -2,7 +2,7 @@ import { BracketParser } from '../inline';
2
2
  import { union, some, syntax, creation, surround, lazy } from '../../combinator';
3
3
  import { inline } from '../inline';
4
4
  import { str } from '../source';
5
- import { State, Recursion } from '../context';
5
+ import { State, Recursion, Backtrack } from '../context';
6
6
  import { unshift, push } from 'spica/array';
7
7
  import { html, defrag } from 'typed-dom/dom';
8
8
 
@@ -10,38 +10,38 @@ const index = /^[0-9A-Za-z]+(?:(?:[.-]|, )[0-9A-Za-z]+)*/;
10
10
 
11
11
  export const bracket: BracketParser = lazy(() => union([
12
12
  surround(str('('), creation(0, Recursion.bracket, syntax(2, State.none, str(index))), str(')')),
13
- surround(str('('), creation(0, Recursion.bracket, syntax(2, State.none, some(inline, ')', [[/^\\?\n/, 3], [')', 2]]))), str(')'), true,
13
+ surround(str('('), creation(0, Recursion.bracket, syntax(2, State.none, some(inline, ')', [[')', 2]]))), str(')'), true,
14
14
  ([as, bs = [], cs], rest) => [[html('span', { class: 'paren' }, defrag(push(unshift(as, bs), cs)))], rest],
15
- ([as, bs = []], rest) => [unshift(as, bs), rest], 3),
15
+ ([as, bs = []], rest) => [unshift(as, bs), rest], 3 | Backtrack.bracket),
16
16
  surround(str('('), creation(0, Recursion.bracket, syntax(2, State.none, str(new RegExp(index.source.replace(', ', '[,、]').replace(/[09AZaz.]|\-(?!\w)/g, c => c.trimStart() && String.fromCharCode(c.charCodeAt(0) + 0xFEE0)))))), str(')')),
17
- surround(str('('), creation(0, Recursion.bracket, syntax(2, State.none, some(inline, ')', [[/^\\?\n/, 3], [')', 2]]))), str(')'), true,
17
+ surround(str('('), creation(0, Recursion.bracket, syntax(2, State.none, some(inline, ')', [[')', 2]]))), str(')'), true,
18
18
  ([as, bs = [], cs], rest) => [[html('span', { class: 'paren' }, defrag(push(unshift(as, bs), cs)))], rest],
19
19
  ([as, bs = []], rest) => [unshift(as, bs), rest]),
20
- surround(str('['), creation(0, Recursion.bracket, syntax(2, State.none, some(inline, ']', [[/^\\?\n/, 3], [']', 2]]))), str(']'), true,
20
+ surround(str('['), creation(0, Recursion.bracket, syntax(2, State.none, some(inline, ']', [[']', 2]]))), str(']'), true,
21
21
  undefined,
22
- ([as, bs = []], rest) => [unshift(as, bs), rest], 3),
23
- surround(str('['), creation(0, Recursion.bracket, syntax(2, State.none, some(inline, ']', [[/^\\?\n/, 3], [']', 2]]))), str(']'), true,
22
+ ([as, bs = []], rest) => [unshift(as, bs), rest], 3 | Backtrack.bracket),
23
+ surround(str('['), creation(0, Recursion.bracket, syntax(2, State.none, some(inline, ']', [[']', 2]]))), str(']'), true,
24
24
  undefined,
25
25
  ([as, bs = []], rest) => [unshift(as, bs), rest]),
26
- surround(str('{'), creation(0, Recursion.bracket, syntax(2, State.none, some(inline, '}', [[/^\\?\n/, 3], ['}', 2]]))), str('}'), true,
26
+ surround(str('{'), creation(0, Recursion.bracket, syntax(2, State.none, some(inline, '}', [['}', 2]]))), str('}'), true,
27
27
  undefined,
28
- ([as, bs = []], rest) => [unshift(as, bs), rest], 3),
29
- surround(str('{'), creation(0, Recursion.bracket, syntax(2, State.none, some(inline, '}', [[/^\\?\n/, 3], ['}', 2]]))), str('}'), true,
28
+ ([as, bs = []], rest) => [unshift(as, bs), rest], 3 | Backtrack.bracket),
29
+ surround(str('{'), creation(0, Recursion.bracket, syntax(2, State.none, some(inline, '}', [['}', 2]]))), str('}'), true,
30
30
  undefined,
31
31
  ([as, bs = []], rest) => [unshift(as, bs), rest]),
32
- surround(str('"'), creation(0, Recursion.bracket, syntax(3, State.none, some(inline, '"', [[/^\\?\n/, 4], ['"', 3]]))), str('"'), true,
32
+ surround(str('"'), creation(0, Recursion.bracket, syntax(3, State.none, some(inline, '"', [[/^\\?\n/, 9], ['"', 3]]))), str('"'), true,
33
33
  undefined,
34
34
  ([as, bs = []], rest) => [unshift(as, bs), rest]),
35
- surround(str('“'), creation(0, Recursion.bracket, syntax(3, State.none, some(inline, '”', [[/^\\?\n/, 4], ['”', 3]]))), str('”'), true,
35
+ surround(str('“'), creation(0, Recursion.bracket, syntax(3, State.none, some(inline, '”', [[/^\\?\n/, 9], ['”', 3]]))), str('”'), true,
36
36
  undefined,
37
37
  ([as, bs = []], rest) => [unshift(as, bs), rest]),
38
- surround(str('‘'), creation(0, Recursion.bracket, syntax(3, State.none, some(inline, '’', [[/^\\?\n/, 4], ['’', 3]]))), str('’'), true,
38
+ surround(str('‘'), creation(0, Recursion.bracket, syntax(3, State.none, some(inline, '’', [[/^\\?\n/, 9], ['’', 3]]))), str('’'), true,
39
39
  undefined,
40
40
  ([as, bs = []], rest) => [unshift(as, bs), rest]),
41
- surround(str('「'), creation(0, Recursion.bracket, syntax(3, State.none, some(inline, '」', [[/^\\?\n/, 4], ['」', 3]]))), str('」'), true,
41
+ surround(str('「'), creation(0, Recursion.bracket, syntax(3, State.none, some(inline, '」', [[/^\\?\n/, 9], ['」', 3]]))), str('」'), true,
42
42
  undefined,
43
43
  ([as, bs = []], rest) => [unshift(as, bs), rest]),
44
- surround(str('『'), creation(0, Recursion.bracket, syntax(3, State.none, some(inline, '』', [[/^\\?\n/, 4], ['』', 3]]))), str('』'), true,
44
+ surround(str('『'), creation(0, Recursion.bracket, syntax(3, State.none, some(inline, '』', [[/^\\?\n/, 9], ['』', 3]]))), str('』'), true,
45
45
  undefined,
46
46
  ([as, bs = []], rest) => [unshift(as, bs), rest]),
47
47
  ]));
@@ -3,7 +3,7 @@ import { union, inits, some, syntax, creation, precedence, constraint, validate,
3
3
  import { inline } from '../../inline';
4
4
  import { indexee, identity } from './indexee';
5
5
  import { txt, str } from '../../source';
6
- import { State, Recursion } from '../../context';
6
+ import { State, Recursion, Backtrack } from '../../context';
7
7
  import { startTight, trimNodeEnd } from '../../visibility';
8
8
  import { html, define, defrag } from 'typed-dom/dom';
9
9
 
@@ -21,7 +21,7 @@ export const index: IndexParser = lazy(() => validate('[#', creation(1, Recursio
21
21
  ']',
22
22
  false,
23
23
  ([, ns], rest) => [[html('a', { 'data-index': dataindex(ns) }, trimNodeEnd(defrag(ns)))], rest],
24
- undefined, 1)),
24
+ undefined, 1 | Backtrack.bracket)),
25
25
  ([el]: [HTMLAnchorElement]) => [
26
26
  define(el,
27
27
  {
@@ -39,10 +39,10 @@ export const signature: IndexParser.SignatureParser = lazy(() => validate('|', c
39
39
  ]))));
40
40
 
41
41
  const bracket: IndexParser.SignatureParser.BracketParser = lazy(() => creation(0, Recursion.terminal, union([
42
- surround(str('('), some(union([bracket, txt]), ')'), str(')'), true),
43
- surround(str('['), some(union([bracket, txt]), ']'), str(']'), true),
44
- surround(str('{'), some(union([bracket, txt]), '}'), str('}'), true),
45
- surround(str('"'), precedence(3, some(txt, '"')), str('"'), true),
42
+ surround(str('('), some(union([bracket, txt]), ')'), str(')'), true, undefined, undefined, 3 | Backtrack.index),
43
+ surround(str('['), some(union([bracket, txt]), ']'), str(']'), true, undefined, undefined, 3 | Backtrack.index),
44
+ surround(str('{'), some(union([bracket, txt]), '}'), str('}'), true, undefined, undefined, 3 | Backtrack.index),
45
+ surround(str('"'), precedence(3, some(txt, '"')), str('"'), true, undefined, undefined, 3 | Backtrack.index),
46
46
  ])));
47
47
 
48
48
  export function dataindex(ns: readonly (string | HTMLElement)[]): string | undefined {
@@ -2,7 +2,7 @@ import { ExtensionParser } from '../../inline';
2
2
  import { union, some, syntax, creation, validate, surround, lazy } from '../../../combinator';
3
3
  import { inline } from '../../inline';
4
4
  import { str } from '../../source';
5
- import { State, Recursion } from '../../context';
5
+ import { State, Recursion, Backtrack } from '../../context';
6
6
  import { startTight } from '../../visibility';
7
7
  import { unshift } from 'spica/array';
8
8
  import { html, defrag } from 'typed-dom/dom';
@@ -24,4 +24,4 @@ export const placeholder: ExtensionParser.PlaceholderParser = lazy(() => validat
24
24
  'data-invalid-message': `Invalid start symbol or linebreak`,
25
25
  }, defrag(bs)),
26
26
  ], rest],
27
- ([as, bs], rest) => [unshift(as, bs), rest], 3))));
27
+ ([as, bs], rest) => [unshift(as, bs), rest], 3 | Backtrack.bracket))));
@@ -4,7 +4,7 @@ import { union, inits, tails, sequence, some, constraint, syntax, creation, prec
4
4
  import { inline, media, shortmedia } from '../inline';
5
5
  import { attributes } from './html';
6
6
  import { linebreak, unescsource, str } from '../source';
7
- import { State, Recursion } from '../context';
7
+ import { State, Recursion, Backtrack } from '../context';
8
8
  import { trimBlankStart, trimNodeEnd } from '../visibility';
9
9
  import { stringify } from '../util';
10
10
  import { ReadonlyURL } from 'spica/url';
@@ -28,8 +28,12 @@ export const textlink: LinkParser.TextLinkParser = lazy(() => creation(1, Recurs
28
28
  '[',
29
29
  trimBlankStart(some(union([inline]), ']', [[/^\\?\n/, 9], [']', 2]])),
30
30
  ']',
31
- true, undefined, undefined, 1)),
32
- dup(surround(/^{(?![{}])/, inits([uri, some(option)]), /^[^\S\n]*}/)),
31
+ true, undefined, undefined, 1 | Backtrack.bracket)),
32
+ dup(surround(
33
+ /^{(?![{}])/,
34
+ inits([uri, some(option)]),
35
+ /^[^\S\n]*}/,
36
+ false, undefined, undefined, 3 | Backtrack.link)),
33
37
  ])),
34
38
  ([params, content = []]: [string[], (HTMLElement | string)[]], rest, context) => {
35
39
  assert(!html('div', content).querySelector('a, .media, .annotation, .reference'));
@@ -4,7 +4,7 @@ import { unsafelink, uri, option as linkoption, resolve } from './link';
4
4
  import { attributes } from './html';
5
5
  import { unsafehtmlentity } from './htmlentity';
6
6
  import { txt, linebreak, str } from '../source';
7
- import { State, Recursion } from '../context';
7
+ import { State, Recursion, Backtrack } from '../context';
8
8
  import { markInvalid } from '../util';
9
9
  import { ReadonlyURL } from 'spica/url';
10
10
  import { unshift, push } from 'spica/array';
@@ -27,8 +27,12 @@ export const media: MediaParser = lazy(() => validate(['![', '!{'], creation(1,
27
27
  '[',
28
28
  some(union([unsafehtmlentity, bracket, txt]), ']', [[/^\\?\n/, 9]]),
29
29
  ']',
30
- true)),
31
- dup(surround(/^{(?![{}])/, inits([uri, some(option)]), /^[^\S\n]*}/)),
30
+ true, undefined, undefined, 1 | Backtrack.media)),
31
+ dup(surround(
32
+ /^{(?![{}])/,
33
+ inits([uri, some(option)]),
34
+ /^[^\S\n]*}/,
35
+ false, undefined, undefined, 3 | Backtrack.link)),
32
36
  ]),
33
37
  ([as, bs]) => bs ? [[as.join('').trim() || as.join('')], bs] : [[''], as]),
34
38
  ([[text]]) => text === '' || text.trim() !== ''),
@@ -69,12 +73,13 @@ export const linemedia: MediaParser.LineMediaParser = surround(
69
73
 
70
74
  const bracket: MediaParser.TextParser.BracketParser = lazy(() => creation(0, Recursion.terminal, union([
71
75
  surround(str('('), some(union([unsafehtmlentity, bracket, txt]), ')'), str(')'), true,
72
- undefined, ([as, bs = []], rest) => [unshift(as, bs), rest]),
76
+ undefined, ([as, bs = []], rest) => [unshift(as, bs), rest], 3 | Backtrack.media),
73
77
  surround(str('['), some(union([unsafehtmlentity, bracket, txt]), ']'), str(']'), true,
74
- undefined, ([as, bs = []], rest) => [unshift(as, bs), rest]),
78
+ undefined, ([as, bs = []], rest) => [unshift(as, bs), rest], 3 | Backtrack.media),
75
79
  surround(str('{'), some(union([unsafehtmlentity, bracket, txt]), '}'), str('}'), true,
76
- undefined, ([as, bs = []], rest) => [unshift(as, bs), rest]),
77
- surround(str('"'), precedence(3, some(union([unsafehtmlentity, txt]), '"')), str('"'), true),
80
+ undefined, ([as, bs = []], rest) => [unshift(as, bs), rest], 3 | Backtrack.media),
81
+ surround(str('"'), precedence(3, some(union([unsafehtmlentity, txt]), '"')), str('"'), true,
82
+ undefined, undefined, 3 | Backtrack.media),
78
83
  ])));
79
84
 
80
85
  const option: MediaParser.ParameterParser.OptionParser = lazy(() => union([
@@ -13,6 +13,9 @@ describe('Unit: parser/inline/reference', () => {
13
13
  assert.deepStrictEqual(inspect(parser('[[')), undefined);
14
14
  assert.deepStrictEqual(inspect(parser('[[]]')), undefined);
15
15
  assert.deepStrictEqual(inspect(parser('[[]]]')), undefined);
16
+ assert.deepStrictEqual(inspect(parser('[["]]')), undefined);
17
+ assert.deepStrictEqual(inspect(parser('[[(]]')), undefined);
18
+ assert.deepStrictEqual(inspect(parser('[[<bdi>]]')), undefined);
16
19
  assert.deepStrictEqual(inspect(parser('[[ ]]')), undefined);
17
20
  assert.deepStrictEqual(inspect(parser('[[ [a')), undefined);
18
21
  assert.deepStrictEqual(inspect(parser('[[\n]]')), undefined);
@@ -2,7 +2,7 @@ import { ReferenceParser } from '../inline';
2
2
  import { union, subsequence, some, syntax, creation, constraint, surround, lazy } from '../../combinator';
3
3
  import { inline } from '../inline';
4
4
  import { str } from '../source';
5
- import { State, Recursion } from '../context';
5
+ import { State, Recursion, Backtrack } from '../context';
6
6
  import { blank, trimBlankStart, trimNodeEnd } from '../visibility';
7
7
  import { html, defrag } from 'typed-dom/dom';
8
8
 
@@ -12,12 +12,12 @@ export const reference: ReferenceParser = lazy(() => creation(1, Recursion.ignor
12
12
  syntax(6, State.annotation | State.reference | State.media,
13
13
  subsequence([
14
14
  abbr,
15
- trimBlankStart(some(inline, ']', [[/^\\?\n/, 9], [']', 2], [']]', 6]])),
15
+ trimBlankStart(some(inline, ']', [[/^\\?\n/, 9], [']', 2]])),
16
16
  ]))),
17
17
  ']]',
18
18
  false,
19
19
  ([, ns], rest) => [[html('sup', attributes(ns), [html('span', trimNodeEnd(defrag(ns)))])], rest],
20
- undefined, 1)));
20
+ undefined, 1 | Backtrack.bracket)));
21
21
 
22
22
  // Chicago-Style
23
23
  const abbr: ReferenceParser.AbbrParser = creation(1, Recursion.ignore, surround(
@@ -1,25 +1,26 @@
1
1
  import { RubyParser } from '../inline';
2
2
  import { eval, exec } from '../../combinator/data/parser';
3
- import { sequence, syntax, creation, validate, verify, surround, lazy, fmap } from '../../combinator';
3
+ import { sequence, syntax, creation, validate, surround, lazy, fmap, bind } from '../../combinator';
4
4
  import { unsafehtmlentity } from './htmlentity';
5
5
  import { text as txt, str } from '../source';
6
- import { State, Recursion } from '../context';
6
+ import { State, Recursion, Backtrack } from '../context';
7
7
  import { isStartTightNodes } from '../visibility';
8
8
  import { unshift, push } from 'spica/array';
9
9
  import { html, defrag } from 'typed-dom/dom';
10
10
 
11
- export const ruby: RubyParser = lazy(() => validate('[', creation(1, Recursion.ignore, syntax(2, State.all, fmap(verify(fmap(
11
+ export const ruby: RubyParser = lazy(() => validate('[', creation(1, Recursion.ignore, syntax(2, State.all, fmap(
12
12
  sequence([
13
- surround('[', str(/^(?:\\[^\n]|[^\\[\](){}"\n])+/), ']'),
14
- surround('(', str(/^(?:\\[^\n]|[^\\[\](){}"\n])+/), ')'),
13
+ bind(surround('[', str(/^(?:\\[^\n]|[^\\[\](){}"\n])+/), ']', false, undefined, undefined, 3 | Backtrack.ruby), ([source], rest, context) => {
14
+ const ns = eval(text({ source, context }), [undefined])[0];
15
+ ns && ns[ns.length - 1] === '' && ns.pop();
16
+ return ns && isStartTightNodes(ns) ? [[ns], rest] : undefined;
17
+ }),
18
+ bind(surround('(', str(/^(?:\\[^\n]|[^\\[\](){}"\n])+/), ')', false, undefined, undefined, 3 | Backtrack.ruby), ([source], rest, context) => {
19
+ const ns = eval(text({ source, context }), [undefined])[0];
20
+ return ns && [[ns], rest];
21
+ }),
15
22
  ]),
16
- ([texts, rubies], _, context) => [
17
- eval(text({ source: texts, context }), [])[0] ?? '',
18
- eval(text({ source: rubies, context }), [])[0] ?? '',
19
- ]),
20
- ([texts, rubies]) => texts && rubies && isStartTightNodes(texts)),
21
23
  ([texts, rubies]) => {
22
- texts[texts.length - 1] === '' && texts.pop();
23
24
  switch (true) {
24
25
  case rubies.length <= texts.length:
25
26
  return [
@@ -1,7 +1,7 @@
1
1
  import { TemplateParser } from '../inline';
2
2
  import { union, some, syntax, creation, precedence, surround, lazy } from '../../combinator';
3
3
  import { escsource, str } from '../source';
4
- import { State, Recursion } from '../context';
4
+ import { State, Recursion, Backtrack } from '../context';
5
5
  import { unshift } from 'spica/array';
6
6
  import { html } from 'typed-dom/dom';
7
7
 
@@ -10,14 +10,16 @@ export const template: TemplateParser = lazy(() => creation(1, Recursion.ignore,
10
10
  syntax(6, State.all, some(union([bracket, escsource]), '}', [['}}', 6]])),
11
11
  '}}',
12
12
  true,
13
- ([, ns = []], rest) => [[html('span', { class: 'template' }, `{{${ns.join('').replace(/\x1B/g, '')}}}`)], rest])));
13
+ ([, ns = []], rest) => [[html('span', { class: 'template' }, `{{${ns.join('').replace(/\x1B/g, '')}}}`)], rest],
14
+ undefined, 3 | Backtrack.template)));
14
15
 
15
16
  const bracket: TemplateParser.BracketParser = lazy(() => creation(0, Recursion.terminal, union([
16
17
  surround(str('('), some(union([bracket, escsource]), ')'), str(')'), true,
17
- undefined, ([as, bs = []], rest) => [unshift(as, bs), rest]),
18
+ undefined, ([as, bs = []], rest) => [unshift(as, bs), rest], 3 | Backtrack.template),
18
19
  surround(str('['), some(union([bracket, escsource]), ']'), str(']'), true,
19
- undefined, ([as, bs = []], rest) => [unshift(as, bs), rest]),
20
+ undefined, ([as, bs = []], rest) => [unshift(as, bs), rest], 3 | Backtrack.template),
20
21
  surround(str('{'), some(union([bracket, escsource]), '}'), str('}'), true,
21
- undefined, ([as, bs = []], rest) => [unshift(as, bs), rest]),
22
- surround(str('"'), precedence(3, some(escsource, /^"|^\\?\n/)), str('"'), true),
22
+ undefined, ([as, bs = []], rest) => [unshift(as, bs), rest], 3 | Backtrack.template),
23
+ surround(str('"'), precedence(3, some(escsource, /^"|^\\?\n/)), str('"'), true,
24
+ undefined, undefined, 3 | Backtrack.template),
23
25
  ])));
@@ -148,8 +148,8 @@ describe('Unit: parser/inline', () => {
148
148
  assert.deepStrictEqual(inspect(parser('(((a))')), [['(', '<sup class="annotation"><span>a</span></sup>'], '']);
149
149
  assert.deepStrictEqual(inspect(parser('((((a))')), [['(', '(', '<sup class="annotation"><span>a</span></sup>'], '']);
150
150
  assert.deepStrictEqual(inspect(parser('((((a))))')), [['<sup class="annotation"><span><span class="paren">((a))</span></span></sup>'], '']);
151
- assert.deepStrictEqual(inspect(parser('((<bdi>))')), [['<sup class="annotation"><span><span class="invalid">&lt;bdi&gt;</span></span></sup>'], '']);
152
151
  assert.deepStrictEqual(inspect(parser('((${))}$')), [['(', '(', '<span class="math" translate="no" data-src="${))}$">${))}$</span>'], '']);
152
+ assert.deepStrictEqual(inspect(parser('((a\nb))')), [['<span class="paren">(<span class="paren">(a<br>b)</span>)</span>'], '']);
153
153
  assert.deepStrictEqual(inspect(parser('"((""))')), [['"', '<sup class="annotation"><span>""</span></sup>'], '']);
154
154
  assert.deepStrictEqual(inspect(parser('[[[a]]')), [['[', '<sup class="reference"><span>a</span></sup>'], '']);
155
155
  assert.deepStrictEqual(inspect(parser('[[[[a]]')), [['[', '[', '<sup class="reference"><span>a</span></sup>'], '']);
@@ -158,7 +158,6 @@ describe('Unit: parser/inline', () => {
158
158
  assert.deepStrictEqual(inspect(parser('[[[]{a}]]')), [['<sup class="reference"><span><a class="url" href="a">a</a></span></sup>'], '']);
159
159
  assert.deepStrictEqual(inspect(parser('[[[a]{b}]]')), [['<sup class="reference"><span><a class="link" href="b">a</a></span></sup>'], '']);
160
160
  assert.deepStrictEqual(inspect(parser('[(([a]{#}))]{#}')), [['<a class="link" href="#"><span class="paren">(<span class="paren">([a]{#})</span>)</span></a>'], '']);
161
- assert.deepStrictEqual(inspect(parser('[[<bdi>]]')), [['<sup class="reference"><span><span class="invalid">&lt;bdi&gt;</span></span></sup>'], '']);
162
161
  assert.deepStrictEqual(inspect(parser('[[${]]}$')), [['[', '[', '<span class="math" translate="no" data-src="${]]}$">${]]}$</span>'], '']);
163
162
  assert.deepStrictEqual(inspect(parser('"[[""]]')), [['"', '<sup class="reference"><span>""</span></sup>'], '']);
164
163
  assert.deepStrictEqual(inspect(parser('[==a==]{b}')), [['<a class="link" href="b">==a==</a>'], '']);
package/src/util/quote.ts CHANGED
@@ -1,6 +1,5 @@
1
1
  import { exec } from '../combinator/data/parser';
2
2
  import { cite } from '../parser/block/reply/cite';
3
- //import { url } from '../parser/inline/autolink/url';
4
3
 
5
4
  export function quote(anchor: string, range: Range): string {
6
5
  if (exec(cite({ source: `>>${anchor}`, context: {} })) !== '') throw new Error(`Invalid anchor: ${anchor}`);
@@ -15,13 +14,12 @@ export function quote(anchor: string, range: Range): string {
15
14
  case el.matches('.math'):
16
15
  el.replaceWith(el.getAttribute('data-src')!);
17
16
  continue;
18
- //case el.matches('.url'):
19
- // if (exec(url({ source: el.getAttribute('href')!, context: {} })) === '') continue;
20
- // el.replaceWith(
21
- // /[\s{}]/.test(el.getAttribute('href')!)
22
- // ? `{ ${el.getAttribute('href')} }`
23
- // : `{${el.getAttribute('href')}}`);
24
- // continue;
17
+ case el.matches('.url'):
18
+ el.replaceWith(
19
+ /[\s{}]/.test(el.getAttribute('href')!)
20
+ ? `{ ${el.getAttribute('href')} }`
21
+ : `{${el.getAttribute('href')}}`);
22
+ continue;
25
23
  case el.matches('.media'):
26
24
  el.replaceWith(
27
25
  /[\s{}]/.test(el.getAttribute('data-src')!)