securemark 0.298.4 → 0.298.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.298.6
4
+
5
+ - Refactoring.
6
+
7
+ ## 0.298.5
8
+
9
+ - Refactoring.
10
+
3
11
  ## 0.298.4
4
12
 
5
13
  - Refactoring.
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- /*! securemark v0.298.4 https://github.com/falsandtru/securemark | (c) 2017, falsandtru | UNLICENSED License */
1
+ /*! securemark v0.298.6 https://github.com/falsandtru/securemark | (c) 2017, falsandtru | UNLICENSED License */
2
2
  (function webpackUniversalModuleDefinition(root, factory) {
3
3
  if(typeof exports === 'object' && typeof module === 'object')
4
4
  module.exports = factory(require("Prism"), require("DOMPurify"));
@@ -3376,16 +3376,24 @@ class Delimiters {
3376
3376
  exports.Delimiters = Delimiters;
3377
3377
  function matcher(pattern, advance, after) {
3378
3378
  const count = typeof pattern === 'object' ? /[^^\\*+][*+]|{\d+,}/.test(pattern.source) : false;
3379
+ let sid = 0,
3380
+ pos = 0,
3381
+ index = -1;
3379
3382
  switch (typeof pattern) {
3380
3383
  case 'string':
3381
3384
  if (pattern === '') return () => new parser_1.List([new parser_1.Node(pattern)]);
3382
3385
  return input => {
3383
3386
  const context = input;
3384
3387
  const {
3388
+ SID,
3385
3389
  source,
3386
3390
  position
3387
3391
  } = context;
3388
- if (!source.startsWith(pattern, position)) return;
3392
+ const hit = SID === sid && position === pos;
3393
+ index = hit ? index : source.startsWith(pattern, position) ? position : -1;
3394
+ sid = SID;
3395
+ pos = position;
3396
+ if (index === -1) return;
3389
3397
  if (advance) {
3390
3398
  context.position += pattern.length;
3391
3399
  }
@@ -3396,15 +3404,20 @@ function matcher(pattern, advance, after) {
3396
3404
  return input => {
3397
3405
  const context = input;
3398
3406
  const {
3407
+ SID,
3399
3408
  source,
3400
3409
  position
3401
3410
  } = context;
3411
+ const hit = SID === sid && position === pos;
3402
3412
  pattern.lastIndex = position;
3403
- if (!pattern.test(source)) return;
3404
- const src = source.slice(position, pattern.lastIndex);
3405
- count && (0, context_1.consume)(src.length, context);
3413
+ index = hit ? index : pattern.test(source) ? pattern.lastIndex : -1;
3414
+ sid = SID;
3415
+ pos = position;
3416
+ if (index === -1) return;
3417
+ const src = source.slice(position, index);
3418
+ count && !hit && (0, context_1.consume)(src.length, context);
3406
3419
  if (advance) {
3407
- context.position += src.length;
3420
+ context.position = index;
3408
3421
  }
3409
3422
  const next = after?.(input);
3410
3423
  return after ? next && new parser_1.List([new parser_1.Node(src)]).import(next) : new parser_1.List([new parser_1.Node(src)]);
@@ -3414,16 +3427,24 @@ function matcher(pattern, advance, after) {
3414
3427
  exports.matcher = matcher;
3415
3428
  function tester(pattern, advance, after) {
3416
3429
  const count = typeof pattern === 'object' ? /[^^\\*+][*+]|{\d+,}/.test(pattern.source) : false;
3430
+ let sid = 0,
3431
+ pos = 0,
3432
+ index = -1;
3417
3433
  switch (typeof pattern) {
3418
3434
  case 'string':
3419
3435
  if (pattern === '') return () => new parser_1.List();
3420
3436
  return input => {
3421
3437
  const context = input;
3422
3438
  const {
3439
+ SID,
3423
3440
  source,
3424
3441
  position
3425
3442
  } = context;
3426
- if (!source.startsWith(pattern, position)) return;
3443
+ const hit = SID === sid && position === pos;
3444
+ index = hit ? index : source.startsWith(pattern, position) ? position : -1;
3445
+ sid = SID;
3446
+ pos = position;
3447
+ if (index === -1) return;
3427
3448
  if (advance) {
3428
3449
  context.position += pattern.length;
3429
3450
  }
@@ -3434,15 +3455,20 @@ function tester(pattern, advance, after) {
3434
3455
  return input => {
3435
3456
  const context = input;
3436
3457
  const {
3458
+ SID,
3437
3459
  source,
3438
3460
  position
3439
3461
  } = context;
3462
+ const hit = SID === sid && position === pos;
3440
3463
  pattern.lastIndex = position;
3441
- if (!pattern.test(source)) return;
3442
- const len = pattern.lastIndex - position;
3443
- count && (0, context_1.consume)(len, context);
3464
+ index = hit ? index : pattern.test(source) ? pattern.lastIndex : -1;
3465
+ sid = SID;
3466
+ pos = position;
3467
+ if (index === -1) return;
3468
+ const len = index - position;
3469
+ count && !hit && (0, context_1.consume)(len, context);
3444
3470
  if (advance) {
3445
- context.position += len;
3471
+ context.position = index;
3446
3472
  }
3447
3473
  if (after && after(input) === undefined) return;
3448
3474
  return new parser_1.List();
@@ -3625,6 +3651,10 @@ class Node {
3625
3651
  }
3626
3652
  }
3627
3653
  exports.Node = Node;
3654
+ let SID = 0;
3655
+ function sid() {
3656
+ return SID = ++SID >>> 0 || 1;
3657
+ }
3628
3658
  class Context {
3629
3659
  constructor({
3630
3660
  source,
@@ -3639,6 +3669,7 @@ class Context {
3639
3669
  offset,
3640
3670
  backtracks
3641
3671
  } = {}) {
3672
+ this.SID = sid();
3642
3673
  this.source = source ?? '';
3643
3674
  this.position = position ?? 0;
3644
3675
  this.segment = segment ?? 0;
@@ -3654,6 +3685,7 @@ class Context {
3654
3685
  }
3655
3686
  exports.Context = Context;
3656
3687
  function input(source, context) {
3688
+ context.SID = sid();
3657
3689
  context.source = source;
3658
3690
  context.position = 0;
3659
3691
  return context;
@@ -3662,6 +3694,7 @@ exports.input = input;
3662
3694
  function subinput(source, context) {
3663
3695
  return {
3664
3696
  ...context,
3697
+ SID: sid(),
3665
3698
  source,
3666
3699
  position: 0,
3667
3700
  offset: 0,
@@ -3808,13 +3841,15 @@ function recursions(rs, parser) {
3808
3841
  } = resources;
3809
3842
  for (const recursion of rs) {
3810
3843
  const rec = (0, alias_1.min)(recursion, recursions.length - 1);
3811
- if (rec >= 0 && recursions[rec] < 1) throw new Error('Too much recursion');
3812
- rec >= 0 && --recursions[rec];
3844
+ if (rec === -1) continue;
3845
+ if (recursions[rec] < 1) throw new Error('Too much recursion');
3846
+ --recursions[rec];
3813
3847
  }
3814
3848
  const result = parser(input);
3815
3849
  for (const recursion of rs) {
3816
3850
  const rec = (0, alias_1.min)(recursion, recursions.length - 1);
3817
- rec >= 0 && ++recursions[rec];
3851
+ if (rec === -1) continue;
3852
+ ++recursions[rec];
3818
3853
  }
3819
3854
  return result;
3820
3855
  };
@@ -3975,8 +4010,10 @@ function some(parser, delimiter, after, delimiters, limit = -1) {
3975
4010
  for (const len = source.length; context.position < len;) {
3976
4011
  if (match(input)) break;
3977
4012
  if (context.delimiters.test(input)) break;
4013
+ const pos = context.position;
3978
4014
  const result = parser(input);
3979
4015
  if (result === undefined) break;
4016
+ if (context.position === pos) break;
3980
4017
  nodes = nodes?.import(result) ?? result;
3981
4018
  if (limit >= 0 && context.position - position > limit) break;
3982
4019
  }
@@ -4043,7 +4080,7 @@ function union(parsers) {
4043
4080
  case 1:
4044
4081
  return parsers[0];
4045
4082
  default:
4046
- return eval(['((', parsers.map((_, i) => `parser${i},`).join(''), ') =>', 'input =>', parsers.map((_, i) => `|| parser${i}(input)`).join('').slice(2), ')'].join(''))(...parsers);
4083
+ return eval(['(', parsers.map((_, i) => `parser${i},`).join(''), ') =>', 'input =>', parsers.map((_, i) => `|| parser${i}(input)`).join('').slice(2)].join(''))(...parsers);
4047
4084
  }
4048
4085
  }
4049
4086
  exports.union = union;
@@ -6790,11 +6827,11 @@ const inline_1 = __webpack_require__(7973);
6790
6827
  const visibility_1 = __webpack_require__(6364);
6791
6828
  const util_1 = __webpack_require__(4992);
6792
6829
  const dom_1 = __webpack_require__(394);
6793
- exports.deletion = (0, combinator_1.lazy)(() => (0, combinator_1.precedence)(0, (0, util_1.repeat)('~~', '', (0, combinator_1.recursion)(3 /* Recursion.inline */, (0, combinator_1.surround)('', (0, combinator_1.some)((0, combinator_1.union)([(0, combinator_1.some)(inline_1.inline, (0, visibility_1.blankWith)('\n', '~~')), (0, combinator_1.open)('\n', (0, combinator_1.some)(inline_1.inline, '~'), true)])), '~~', false, [], ([, bs], {
6830
+ exports.deletion = (0, combinator_1.lazy)(() => (0, util_1.repeat)('~~', '', (0, combinator_1.precedence)(0, (0, combinator_1.recursion)(3 /* Recursion.inline */, (0, combinator_1.surround)('', (0, combinator_1.some)((0, combinator_1.union)([(0, combinator_1.some)(inline_1.inline, (0, visibility_1.blankWith)('\n', '~~')), (0, combinator_1.open)('\n', (0, combinator_1.some)(inline_1.inline, '~'), true)])), '~~', false, [], ([, bs], {
6794
6831
  buffer
6795
6832
  }) => buffer.import(bs), ([, bs], {
6796
6833
  buffer
6797
- }) => bs && buffer.import(bs).push(new parser_1.Node("\u0018" /* Command.Cancel */)) && buffer)), nodes => new parser_1.List([new parser_1.Node((0, dom_1.html)('del', (0, dom_1.defrag)((0, util_1.unwrap)(nodes))))]))));
6834
+ }) => bs && buffer.import(bs).push(new parser_1.Node("\u0018" /* Command.Cancel */)) && buffer))), nodes => new parser_1.List([new parser_1.Node((0, dom_1.html)('del', (0, dom_1.defrag)((0, util_1.unwrap)(nodes))))])));
6798
6835
 
6799
6836
  /***/ },
6800
6837
 
@@ -6844,7 +6881,7 @@ const subemphasis = (0, combinator_1.lazy)(() => (0, combinator_1.some)((0, comb
6844
6881
  // 開閉が明示的でない構文は開閉の不明確な記号による再帰的適用を行わず
6845
6882
  // 可能な限り早く閉じるよう解析しなければならない。
6846
6883
  // このため終端記号の後ろを見て終端を中止し同じ構文を再帰的に適用してはならない。
6847
- exports.emstrong = (0, combinator_1.lazy)(() => (0, combinator_1.precedence)(0, (0, util_1.repeat)('***', visibility_1.beforeNonblank, (0, combinator_1.recursion)(3 /* Recursion.inline */, (0, combinator_1.surround)('', (0, combinator_1.some)((0, combinator_1.union)([(0, combinator_1.some)(inline_1.inline, '*', visibility_1.afterNonblank)])), (0, source_1.strs)('*', 1, 3), false, [], ([, bs, cs], context) => {
6884
+ exports.emstrong = (0, combinator_1.lazy)(() => (0, util_1.repeat)('***', visibility_1.beforeNonblank, (0, combinator_1.precedence)(0, (0, combinator_1.recursion)(3 /* Recursion.inline */, (0, combinator_1.surround)('', (0, combinator_1.some)((0, combinator_1.union)([(0, combinator_1.some)(inline_1.inline, '*', visibility_1.afterNonblank)])), (0, source_1.strs)('*', 1, 3), false, [], ([, bs, cs], context) => {
6848
6885
  const {
6849
6886
  buffer
6850
6887
  } = context;
@@ -6888,7 +6925,7 @@ exports.emstrong = (0, combinator_1.lazy)(() => (0, combinator_1.precedence)(0,
6888
6925
  }
6889
6926
  }, ([, bs], {
6890
6927
  buffer
6891
- }) => bs && buffer.import(bs) && buffer.push(new parser_1.Node("\u0018" /* Command.Cancel */)) && buffer)),
6928
+ }) => bs && buffer.import(bs) && buffer.push(new parser_1.Node("\u0018" /* Command.Cancel */)) && buffer))),
6892
6929
  // 3以上の`*`に対してemの適用を保証する
6893
6930
  nodes => new parser_1.List([new parser_1.Node((0, dom_1.html)('em', [(0, dom_1.html)('strong', (0, dom_1.defrag)((0, util_1.unwrap)(nodes)))]))]), (nodes, context, prefix, postfix, state) => {
6894
6931
  context.position += postfix;
@@ -6943,7 +6980,7 @@ nodes => new parser_1.List([new parser_1.Node((0, dom_1.html)('em', [(0, dom_1.h
6943
6980
  nodes = prepend('*'.repeat(prefix - postfix), nodes);
6944
6981
  }
6945
6982
  return nodes;
6946
- })));
6983
+ }));
6947
6984
  function prepend(prefix, nodes) {
6948
6985
  if (typeof nodes.head?.value === 'string') {
6949
6986
  nodes.head.value = prefix + nodes.head.value;
@@ -7416,11 +7453,11 @@ const inline_1 = __webpack_require__(7973);
7416
7453
  const visibility_1 = __webpack_require__(6364);
7417
7454
  const util_1 = __webpack_require__(4992);
7418
7455
  const dom_1 = __webpack_require__(394);
7419
- exports.insertion = (0, combinator_1.lazy)(() => (0, combinator_1.precedence)(0, (0, util_1.repeat)('++', '', (0, combinator_1.recursion)(3 /* Recursion.inline */, (0, combinator_1.surround)('', (0, combinator_1.some)((0, combinator_1.union)([(0, combinator_1.some)(inline_1.inline, (0, visibility_1.blankWith)('\n', '++')), (0, combinator_1.open)('\n', (0, combinator_1.some)(inline_1.inline, '+'), true)])), '++', false, [], ([, bs], {
7456
+ exports.insertion = (0, combinator_1.lazy)(() => (0, util_1.repeat)('++', '', (0, combinator_1.precedence)(0, (0, combinator_1.recursion)(3 /* Recursion.inline */, (0, combinator_1.surround)('', (0, combinator_1.some)((0, combinator_1.union)([(0, combinator_1.some)(inline_1.inline, (0, visibility_1.blankWith)('\n', '++')), (0, combinator_1.open)('\n', (0, combinator_1.some)(inline_1.inline, '+'), true)])), '++', false, [], ([, bs], {
7420
7457
  buffer
7421
7458
  }) => buffer.import(bs), ([, bs], {
7422
7459
  buffer
7423
- }) => bs && buffer.import(bs).push(new parser_1.Node("\u0018" /* Command.Cancel */)) && buffer)), nodes => new parser_1.List([new parser_1.Node((0, dom_1.html)('ins', (0, dom_1.defrag)((0, util_1.unwrap)(nodes))))]))));
7460
+ }) => bs && buffer.import(bs).push(new parser_1.Node("\u0018" /* Command.Cancel */)) && buffer))), nodes => new parser_1.List([new parser_1.Node((0, dom_1.html)('ins', (0, dom_1.defrag)((0, util_1.unwrap)(nodes))))])));
7424
7461
 
7425
7462
  /***/ },
7426
7463
 
@@ -7443,11 +7480,11 @@ const dom_1 = __webpack_require__(394);
7443
7480
  // 可読性のため実際にはオブリーク体を指定する。
7444
7481
  // 斜体は単語に使うとかえって見づらく読み飛ばしやすくなるため使わないべきであり
7445
7482
  // ある程度の長さのある文に使うのが望ましい。
7446
- exports.italic = (0, combinator_1.lazy)(() => (0, combinator_1.precedence)(0, (0, util_1.repeat)('///', visibility_1.beforeNonblank, (0, combinator_1.recursion)(3 /* Recursion.inline */, (0, combinator_1.surround)('', (0, combinator_1.some)((0, combinator_1.union)([inline_1.inline]), '///', visibility_1.afterNonblank), '///', false, [], ([, bs], {
7483
+ exports.italic = (0, combinator_1.lazy)(() => (0, util_1.repeat)('///', visibility_1.beforeNonblank, (0, combinator_1.precedence)(0, (0, combinator_1.recursion)(3 /* Recursion.inline */, (0, combinator_1.surround)('', (0, combinator_1.some)((0, combinator_1.union)([inline_1.inline]), '///', visibility_1.afterNonblank), '///', false, [], ([, bs], {
7447
7484
  buffer
7448
7485
  }) => buffer.import(bs), ([, bs], {
7449
7486
  buffer
7450
- }) => bs && buffer.import(bs).push(new parser_1.Node("\u0018" /* Command.Cancel */)) && buffer)), nodes => new parser_1.List([new parser_1.Node((0, dom_1.html)('i', (0, dom_1.defrag)((0, util_1.unwrap)(nodes))))]))));
7487
+ }) => bs && buffer.import(bs).push(new parser_1.Node("\u0018" /* Command.Cancel */)) && buffer))), nodes => new parser_1.List([new parser_1.Node((0, dom_1.html)('i', (0, dom_1.defrag)((0, util_1.unwrap)(nodes))))])));
7451
7488
 
7452
7489
  /***/ },
7453
7490
 
@@ -7624,11 +7661,11 @@ const indexee_1 = __webpack_require__(7610);
7624
7661
  const visibility_1 = __webpack_require__(6364);
7625
7662
  const util_1 = __webpack_require__(4992);
7626
7663
  const dom_1 = __webpack_require__(394);
7627
- exports.mark = (0, combinator_1.lazy)(() => (0, combinator_1.precedence)(0, (0, util_1.repeat)('==', visibility_1.beforeNonblank, (0, combinator_1.recursion)(3 /* Recursion.inline */, (0, combinator_1.surround)('', (0, combinator_1.state)(2 /* State.mark */, (0, combinator_1.some)((0, combinator_1.union)([inline_1.inline]), '==', visibility_1.afterNonblank)), '==', false, [], ([, bs], {
7664
+ exports.mark = (0, combinator_1.lazy)(() => (0, util_1.repeat)('==', visibility_1.beforeNonblank, (0, combinator_1.precedence)(0, (0, combinator_1.recursion)(3 /* Recursion.inline */, (0, combinator_1.surround)('', (0, combinator_1.state)(2 /* State.mark */, (0, combinator_1.some)((0, combinator_1.union)([inline_1.inline]), '==', visibility_1.afterNonblank)), '==', false, [], ([, bs], {
7628
7665
  buffer
7629
7666
  }) => buffer.import(bs), ([, bs], {
7630
7667
  buffer
7631
- }) => bs && buffer.import(bs).push(new parser_1.Node("\u0018" /* Command.Cancel */)) && buffer)), (nodes, {
7668
+ }) => bs && buffer.import(bs).push(new parser_1.Node("\u0018" /* Command.Cancel */)) && buffer))), (nodes, {
7632
7669
  id,
7633
7670
  state
7634
7671
  }, nest) => {
@@ -7640,7 +7677,7 @@ exports.mark = (0, combinator_1.lazy)(() => (0, combinator_1.precedence)(0, (0,
7640
7677
  return el.id ? new parser_1.List([new parser_1.Node(el), new parser_1.Node((0, dom_1.html)('a', {
7641
7678
  href: `#${el.id}`
7642
7679
  }))]) : new parser_1.List([new parser_1.Node(el)]);
7643
- })));
7680
+ }));
7644
7681
 
7645
7682
  /***/ },
7646
7683
 
@@ -9091,7 +9128,6 @@ function repeat(symbol, after, parser, cons, termination = (nodes, context, pref
9091
9128
  }
9092
9129
  break;
9093
9130
  }
9094
- if (nodes.length === 0) return;
9095
9131
  const prefix = i;
9096
9132
  i = 0;
9097
9133
  for (let len = (0, alias_1.min)(prefix, source.length - context.position); i < len && source[context.position + i] === symbol[0];) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "securemark",
3
- "version": "0.298.4",
3
+ "version": "0.298.6",
4
4
  "description": "Secure markdown renderer working on browsers for user input data.",
5
5
  "private": false,
6
6
  "homepage": "https://github.com/falsandtru/securemark",
@@ -161,13 +161,20 @@ export function matcher(pattern: string | RegExp, advance: boolean, after?: Pars
161
161
  const count = typeof pattern === 'object'
162
162
  ? /[^^\\*+][*+]|{\d+,}/.test(pattern.source)
163
163
  : false;
164
+ let sid = 0, pos = 0, index = -1;
164
165
  switch (typeof pattern) {
165
166
  case 'string':
166
167
  if (pattern === '') return () => new List([new Node(pattern)]);
167
168
  return input => {
168
169
  const context = input;
169
- const { source, position } = context;
170
- if (!source.startsWith(pattern, position)) return;
170
+ const { SID, source, position } = context;
171
+ const hit = SID === sid && position === pos;
172
+ index = hit
173
+ ? index
174
+ : source.startsWith(pattern, position) ? position : -1;
175
+ sid = SID;
176
+ pos = position;
177
+ if (index === -1) return;
171
178
  if (advance) {
172
179
  context.position += pattern.length;
173
180
  }
@@ -180,13 +187,19 @@ export function matcher(pattern: string | RegExp, advance: boolean, after?: Pars
180
187
  assert(pattern.sticky);
181
188
  return input => {
182
189
  const context = input;
183
- const { source, position } = context;
190
+ const { SID, source, position } = context;
191
+ const hit = SID === sid && position === pos;
184
192
  pattern.lastIndex = position;
185
- if (!pattern.test(source)) return;
186
- const src = source.slice(position, pattern.lastIndex);
187
- count && consume(src.length, context);
193
+ index = hit
194
+ ? index
195
+ : pattern.test(source) ? pattern.lastIndex : -1;
196
+ sid = SID;
197
+ pos = position;
198
+ if (index === -1) return;
199
+ const src = source.slice(position, index);
200
+ count && !hit && consume(src.length, context);
188
201
  if (advance) {
189
- context.position += src.length;
202
+ context.position = index;
190
203
  }
191
204
  const next = after?.(input);
192
205
  return after
@@ -201,13 +214,20 @@ export function tester(pattern: string | RegExp, advance: boolean, after?: Parse
201
214
  const count = typeof pattern === 'object'
202
215
  ? /[^^\\*+][*+]|{\d+,}/.test(pattern.source)
203
216
  : false;
217
+ let sid = 0, pos = 0, index = -1;
204
218
  switch (typeof pattern) {
205
219
  case 'string':
206
220
  if (pattern === '') return () => new List();
207
221
  return input => {
208
222
  const context = input;
209
- const { source, position } = context;
210
- if (!source.startsWith(pattern, position)) return;
223
+ const { SID, source, position } = context;
224
+ const hit = SID === sid && position === pos;
225
+ index = hit
226
+ ? index
227
+ : source.startsWith(pattern, position) ? position : -1;
228
+ sid = SID;
229
+ pos = position;
230
+ if (index === -1) return;
211
231
  if (advance) {
212
232
  context.position += pattern.length;
213
233
  }
@@ -218,13 +238,19 @@ export function tester(pattern: string | RegExp, advance: boolean, after?: Parse
218
238
  assert(pattern.sticky);
219
239
  return input => {
220
240
  const context = input;
221
- const { source, position } = context;
241
+ const { SID, source, position } = context;
242
+ const hit = SID === sid && position === pos;
222
243
  pattern.lastIndex = position;
223
- if (!pattern.test(source)) return;
224
- const len = pattern.lastIndex - position;
225
- count && consume(len, context);
244
+ index = hit
245
+ ? index
246
+ : pattern.test(source) ? pattern.lastIndex : -1;
247
+ sid = SID;
248
+ pos = position;
249
+ if (index === -1) return;
250
+ const len = index - position;
251
+ count && !hit && consume(len, context);
226
252
  if (advance) {
227
- context.position += len;
253
+ context.position = index;
228
254
  }
229
255
  if (after && after(input) === undefined) return;
230
256
  return new List();
@@ -122,13 +122,15 @@ export function recursions(rs: readonly number[], parser: Parser): Parser {
122
122
  assert(recursions.length > 0);
123
123
  for (const recursion of rs) {
124
124
  const rec = min(recursion, recursions.length - 1);
125
- if (rec >= 0 && recursions[rec] < 1) throw new Error('Too much recursion');
126
- rec >= 0 && --recursions[rec];
125
+ if (rec === -1) continue;
126
+ if (recursions[rec] < 1) throw new Error('Too much recursion');
127
+ --recursions[rec];
127
128
  }
128
129
  const result = parser(input);
129
130
  for (const recursion of rs) {
130
131
  const rec = min(recursion, recursions.length - 1);
131
- rec >= 0 && ++recursions[rec];
132
+ if (rec === -1) continue;
133
+ ++recursions[rec];
132
134
  }
133
135
  return result;
134
136
  };
@@ -38,8 +38,10 @@ export function some<N>(parser: Parser<N>, delimiter?: number | string | RegExp
38
38
  for (const len = source.length; context.position < len;) {
39
39
  if (match(input)) break;
40
40
  if (context.delimiters.test(input)) break;
41
+ const pos = context.position;
41
42
  const result = parser(input);
42
43
  if (result === undefined) break;
44
+ if (context.position === pos) break;
43
45
  nodes = nodes?.import(result) ?? result;
44
46
  if (limit >= 0 && context.position - position > limit) break;
45
47
  }
@@ -10,12 +10,9 @@ export function union<N, D extends Parser<N>[]>(parsers: D): Parser<N, Context,
10
10
  return parsers[0];
11
11
  default:
12
12
  return eval([
13
- '((',
14
- parsers.map((_, i) => `parser${i},`).join(''),
15
- ') =>',
13
+ '(', parsers.map((_, i) => `parser${i},`).join(''), ') =>',
16
14
  'input =>',
17
15
  parsers.map((_, i) => `|| parser${i}(input)`).join('').slice(2),
18
- ')',
19
16
  ].join(''))(...parsers);
20
17
  }
21
18
  }
@@ -26,6 +26,10 @@ export class Node<N> implements List.Node {
26
26
  public next?: this = undefined;
27
27
  public prev?: this = undefined;
28
28
  }
29
+ let SID = 0;
30
+ function sid(): number {
31
+ return SID = ++SID >>> 0 || 1;
32
+ }
29
33
  export class Context {
30
34
  constructor(
31
35
  {
@@ -54,6 +58,7 @@ export class Context {
54
58
  this.offset = offset ?? 0;
55
59
  this.backtracks = backtracks ?? {};
56
60
  }
61
+ public SID: number = sid();
57
62
  public source: string;
58
63
  public position: number;
59
64
  public segment: number;
@@ -110,6 +115,7 @@ export const enum Segment {
110
115
  }
111
116
 
112
117
  export function input<C extends Context>(source: string, context: C): Input<C> {
118
+ context.SID = sid();
113
119
  context.source = source;
114
120
  context.position = 0;
115
121
  return context;
@@ -118,6 +124,7 @@ export function input<C extends Context>(source: string, context: C): Input<C> {
118
124
  export function subinput<C extends Context>(source: string, context: C): Input<C> {
119
125
  return {
120
126
  ...context,
127
+ SID: sid(),
121
128
  source,
122
129
  position: 0,
123
130
  offset: 0,
@@ -83,6 +83,7 @@ describe('Unit: parser/inline/autolink/url', () => {
83
83
  assert.deepStrictEqual(inspect(parser, input(' http://host>', new Context())), [['<a class="url" href="http://host" target="_blank">http://host</a>'], '>']);
84
84
  assert.deepStrictEqual(inspect(parser, input(' http://host(', new Context())), [['<a class="url" href="http://host" target="_blank">http://host</a>'], '(']);
85
85
  assert.deepStrictEqual(inspect(parser, input(' http://host)', new Context())), [['<a class="url" href="http://host" target="_blank">http://host</a>'], ')']);
86
+ assert.deepStrictEqual(inspect(parser, input(` http://host${'+'.repeat(5e5)}`, new Context())), [['<a class="url" href="http://host" target="_blank">http://host</a>'], '+'.repeat(5e5)]);
86
87
  });
87
88
 
88
89
  it('trailing entities', () => {
@@ -11,7 +11,7 @@ describe('Unit: parser/inline/deletion', () => {
11
11
  it('invalid', () => {
12
12
  assert.deepStrictEqual(inspect(parser, input('', new Context())), undefined);
13
13
  assert.deepStrictEqual(inspect(parser, input('~', new Context())), undefined);
14
- assert.deepStrictEqual(inspect(parser, input('~~', new Context())), undefined);
14
+ assert.deepStrictEqual(inspect(parser, input('~~', new Context())), [['~~'], '']);
15
15
  assert.deepStrictEqual(inspect(parser, input('~~a', new Context())), [['~~', 'a'], '']);
16
16
  assert.deepStrictEqual(inspect(parser, input('~~a~', new Context())), [['~~', 'a~'], '']);
17
17
  assert.deepStrictEqual(inspect(parser, input(' ~~a~~', new Context())), undefined);
@@ -8,7 +8,7 @@ import { unwrap, repeat } from '../util';
8
8
  import { html, defrag } from 'typed-dom/dom';
9
9
 
10
10
  export const deletion: DeletionParser = lazy(() =>
11
- precedence(0, repeat('~~', '', recursion(Recursion.inline, surround(
11
+ repeat('~~', '', precedence(0, recursion(Recursion.inline, surround(
12
12
  '',
13
13
  some(union([
14
14
  some(inline, blankWith('\n', '~~')),
@@ -17,5 +17,5 @@ export const deletion: DeletionParser = lazy(() =>
17
17
  '~~',
18
18
  false, [],
19
19
  ([, bs], { buffer }) => buffer.import(bs),
20
- ([, bs], { buffer }) => bs && buffer.import(bs).push(new Node(Command.Cancel)) && buffer)),
21
- nodes => new List([new Node(html('del', defrag(unwrap(nodes))))]))));
20
+ ([, bs], { buffer }) => bs && buffer.import(bs).push(new Node(Command.Cancel)) && buffer))),
21
+ nodes => new List([new Node(html('del', defrag(unwrap(nodes))))])));
@@ -9,7 +9,7 @@ describe('Unit: parser/inline/emstrong', () => {
9
9
  const parser = some(emstrong);
10
10
 
11
11
  it('invalid', () => {
12
- assert.deepStrictEqual(inspect(parser, input('***', new Context())), undefined);
12
+ assert.deepStrictEqual(inspect(parser, input('***', new Context())), [['***'], '']);
13
13
  assert.deepStrictEqual(inspect(parser, input('***a', new Context())), [['***a'], '']);
14
14
  assert.deepStrictEqual(inspect(parser, input('***a ***', new Context())), [['***a ', '***'], '']);
15
15
  assert.deepStrictEqual(inspect(parser, input('***a ***', new Context())), [['***a', ' ', '***'], '']);
@@ -85,7 +85,7 @@ describe('Unit: parser/inline/emstrong', () => {
85
85
  assert.deepStrictEqual(inspect(parser, input('***a***b', new Context())), [['<em><strong>a</strong></em>'], 'b']);
86
86
  assert.deepStrictEqual(inspect(parser, input('***a****', new Context())), [['<em><strong>a</strong></em>'], '*']);
87
87
  assert.deepStrictEqual(inspect(parser, input('***a*****', new Context())), [['<em><strong>a</strong></em>'], '**']);
88
- assert.deepStrictEqual(inspect(parser, input('***a******', new Context())), [['<em><strong>a</strong></em>'], '***']);
88
+ assert.deepStrictEqual(inspect(parser, input('***a******', new Context())), [['<em><strong>a</strong></em>', '***'], '']);
89
89
  assert.deepStrictEqual(inspect(parser, input('****a***', new Context())), [['*', '<em><strong>a</strong></em>'], '']);
90
90
  assert.deepStrictEqual(inspect(parser, input('****a***b', new Context())), [['*', '<em><strong>a</strong></em>', 'b'], '']);
91
91
  assert.deepStrictEqual(inspect(parser, input('****a***b*', new Context())), [['<em><em><strong>a</strong></em>b</em>'], '']);
@@ -23,7 +23,7 @@ const subemphasis: Parser.IntermediateParser<EmphasisParser> = lazy(() => some(u
23
23
  // 可能な限り早く閉じるよう解析しなければならない。
24
24
  // このため終端記号の後ろを見て終端を中止し同じ構文を再帰的に適用してはならない。
25
25
  export const emstrong: EmStrongParser = lazy(() =>
26
- precedence(0, repeat('***', beforeNonblank, recursion(Recursion.inline, surround(
26
+ repeat('***', beforeNonblank, precedence(0, recursion(Recursion.inline, surround(
27
27
  '',
28
28
  some(union([some(inline, '*', afterNonblank)])),
29
29
  strs('*', 1, 3),
@@ -75,7 +75,7 @@ export const emstrong: EmStrongParser = lazy(() =>
75
75
  }
76
76
  assert(false);
77
77
  },
78
- ([, bs], { buffer }) => bs && buffer.import(bs) && buffer.push(new Node(Command.Cancel)) && buffer)),
78
+ ([, bs], { buffer }) => bs && buffer.import(bs) && buffer.push(new Node(Command.Cancel)) && buffer))),
79
79
  // 3以上の`*`に対してemの適用を保証する
80
80
  nodes => new List([new Node(html('em', [html('strong', defrag(unwrap(nodes)))]))]),
81
81
  (nodes, context, prefix, postfix, state) => {
@@ -137,7 +137,7 @@ export const emstrong: EmStrongParser = lazy(() =>
137
137
  nodes = prepend('*'.repeat(prefix - postfix), nodes);
138
138
  }
139
139
  return nodes;
140
- })));
140
+ }));
141
141
 
142
142
  function prepend<N>(prefix: string, nodes: List<Node<N>>): List<Node<N>> {
143
143
  if (typeof nodes.head?.value === 'string') {
@@ -11,7 +11,7 @@ describe('Unit: parser/inline/insertion', () => {
11
11
  it('invalid', () => {
12
12
  assert.deepStrictEqual(inspect(parser, input('', new Context())), undefined);
13
13
  assert.deepStrictEqual(inspect(parser, input('+', new Context())), undefined);
14
- assert.deepStrictEqual(inspect(parser, input('++', new Context())), undefined);
14
+ assert.deepStrictEqual(inspect(parser, input('++', new Context())), [['++'], '']);
15
15
  assert.deepStrictEqual(inspect(parser, input('++a', new Context())), [['++', 'a'], '']);
16
16
  assert.deepStrictEqual(inspect(parser, input('++a+', new Context())), [['++', 'a+'], '']);
17
17
  assert.deepStrictEqual(inspect(parser, input(' ++a++', new Context())), undefined);
@@ -8,7 +8,7 @@ import { unwrap, repeat } from '../util';
8
8
  import { html, defrag } from 'typed-dom/dom';
9
9
 
10
10
  export const insertion: InsertionParser = lazy(() =>
11
- precedence(0, repeat('++', '', recursion(Recursion.inline, surround(
11
+ repeat('++', '', precedence(0, recursion(Recursion.inline, surround(
12
12
  '',
13
13
  some(union([
14
14
  some(inline, blankWith('\n', '++')),
@@ -17,5 +17,5 @@ export const insertion: InsertionParser = lazy(() =>
17
17
  '++',
18
18
  false, [],
19
19
  ([, bs], { buffer }) => buffer.import(bs),
20
- ([, bs], { buffer }) => bs && buffer.import(bs).push(new Node(Command.Cancel)) && buffer)),
21
- nodes => new List([new Node(html('ins', defrag(unwrap(nodes))))]))));
20
+ ([, bs], { buffer }) => bs && buffer.import(bs).push(new Node(Command.Cancel)) && buffer))),
21
+ nodes => new List([new Node(html('ins', defrag(unwrap(nodes))))])));
@@ -9,7 +9,7 @@ describe('Unit: parser/inline/italic', () => {
9
9
  const parser = some(italic);
10
10
 
11
11
  it('invalid', () => {
12
- assert.deepStrictEqual(inspect(parser, input('///', new Context())), undefined);
12
+ assert.deepStrictEqual(inspect(parser, input('///', new Context())), [['///'], '']);
13
13
  assert.deepStrictEqual(inspect(parser, input('///a', new Context())), [['///', 'a'], '']);
14
14
  assert.deepStrictEqual(inspect(parser, input('///a ///', new Context())), [['///', 'a ', '///'], '']);
15
15
  assert.deepStrictEqual(inspect(parser, input('///a ///', new Context())), [['///', 'a', ' ', '///'], '']);
@@ -11,11 +11,11 @@ import { html, defrag } from 'typed-dom/dom';
11
11
  // 斜体は単語に使うとかえって見づらく読み飛ばしやすくなるため使わないべきであり
12
12
  // ある程度の長さのある文に使うのが望ましい。
13
13
  export const italic: ItalicParser = lazy(() =>
14
- precedence(0, repeat('///', beforeNonblank, recursion(Recursion.inline, surround(
14
+ repeat('///', beforeNonblank, precedence(0, recursion(Recursion.inline, surround(
15
15
  '',
16
16
  some(union([inline]), '///', afterNonblank),
17
17
  '///',
18
18
  false, [],
19
19
  ([, bs], { buffer }) => buffer.import(bs),
20
- ([, bs], { buffer }) => bs && buffer.import(bs).push(new Node(Command.Cancel)) && buffer)),
21
- nodes => new List([new Node(html('i', defrag(unwrap(nodes))))]))));
20
+ ([, bs], { buffer }) => bs && buffer.import(bs).push(new Node(Command.Cancel)) && buffer))),
21
+ nodes => new List([new Node(html('i', defrag(unwrap(nodes))))])));
@@ -11,7 +11,7 @@ describe('Unit: parser/inline/mark', () => {
11
11
  it('invalid', () => {
12
12
  assert.deepStrictEqual(inspect(parser, input('', new Context())), undefined);
13
13
  assert.deepStrictEqual(inspect(parser, input('=', new Context())), undefined);
14
- assert.deepStrictEqual(inspect(parser, input('==', new Context())), undefined);
14
+ assert.deepStrictEqual(inspect(parser, input('==', new Context())), [['=='], '']);
15
15
  assert.deepStrictEqual(inspect(parser, input('==a', new Context())), [['==', 'a'], '']);
16
16
  assert.deepStrictEqual(inspect(parser, input('==a=', new Context())), [['==', 'a='], '']);
17
17
  assert.deepStrictEqual(inspect(parser, input('==a ==', new Context())), [['==', 'a ', '=='], '']);
@@ -9,13 +9,13 @@ import { unwrap, repeat } from '../util';
9
9
  import { html, define, defrag } from 'typed-dom/dom';
10
10
 
11
11
  export const mark: MarkParser = lazy(() =>
12
- precedence(0, repeat('==', beforeNonblank, recursion(Recursion.inline, surround(
12
+ repeat('==', beforeNonblank, precedence(0, recursion(Recursion.inline, surround(
13
13
  '',
14
14
  state(State.mark, some(union([inline]), '==', afterNonblank)),
15
15
  '==',
16
16
  false, [],
17
17
  ([, bs], { buffer }) => buffer.import(bs),
18
- ([, bs], { buffer }) => bs && buffer.import(bs).push(new Node(Command.Cancel)) && buffer)),
18
+ ([, bs], { buffer }) => bs && buffer.import(bs).push(new Node(Command.Cancel)) && buffer))),
19
19
  (nodes, { id, state }, nest) => {
20
20
  const el = html('mark', defrag(unwrap(nodes)));
21
21
  if (state & State.linkers || nest) return new List([new Node(el)]);
@@ -23,4 +23,4 @@ export const mark: MarkParser = lazy(() =>
23
23
  return el.id
24
24
  ? new List([new Node(el), new Node(html('a', { href: `#${el.id}` }))])
25
25
  : new List([new Node(el)]);
26
- })));
26
+ }));
@@ -22,6 +22,8 @@ describe('Unit: parser/inline', () => {
22
22
  it('nest', () => {
23
23
  assert.deepStrictEqual(inspect(parser, input('あ(A)', new Context())), [['あ', '<span class="paren">(A)</span>'], '']);
24
24
  assert.deepStrictEqual(inspect(parser, input('あ(い)', new Context())), [['あ', '<span class="paren">(い)</span>'], '']);
25
+ assert.deepStrictEqual(inspect(parser, input('='.repeat(1e6), new Context())), [['='.repeat(1e6)], '']);
26
+ assert.deepStrictEqual(inspect(parser, input('*'.repeat(1e6), new Context())), [['*'.repeat(1e6)], '']);
25
27
  assert.deepStrictEqual(inspect(parser, input('* a*', new Context())), [['* a', '*'], '']);
26
28
  assert.deepStrictEqual(inspect(parser, input('** a**', new Context())), [['**', ' a', '**'], '']);
27
29
  assert.deepStrictEqual(inspect(parser, input('*** a***', new Context())), [['***', ' a', '***'], '']);
@@ -67,7 +67,6 @@ export function repeat<N extends HTMLElement | string>(symbol: string, after: st
67
67
  }
68
68
  break;
69
69
  }
70
- if (nodes.length === 0) return;
71
70
  const prefix = i;
72
71
  i = 0;
73
72
  for (let len = min(prefix, source.length - context.position); i < len && source[context.position + i] === symbol[0];) {