securemark 0.299.2 → 0.299.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.299.3
4
+
5
+ - Refactoring.
6
+
3
7
  ## 0.299.2
4
8
 
5
9
  - Refactoring.
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- /*! securemark v0.299.2 https://github.com/falsandtru/securemark | (c) 2017, falsandtru | UNLICENSED License */
1
+ /*! securemark v0.299.3 https://github.com/falsandtru/securemark | (c) 2017, falsandtru | UNLICENSED License */
2
2
  (function webpackUniversalModuleDefinition(root, factory) {
3
3
  if(typeof exports === 'object' && typeof module === 'object')
4
4
  module.exports = factory(require("Prism"), require("DOMPurify"));
@@ -2605,7 +2605,7 @@ function fence(opener, limit, separation = true) {
2605
2605
  opener.lastIndex = position;
2606
2606
  const matches = opener.exec(source);
2607
2607
  if (!matches) return;
2608
- (0, combinator_1.consume)(matches[0].length, context);
2608
+ (0, combinator_1.spend)(context, matches[0].length);
2609
2609
  const delim = matches[1];
2610
2610
  if (matches[0].includes(delim, delim.length)) return;
2611
2611
  context.position += matches[0].length;
@@ -2727,7 +2727,7 @@ function match(pattern, f) {
2727
2727
  pattern.lastIndex = position;
2728
2728
  const params = pattern.exec(source);
2729
2729
  if (!params) return;
2730
- count && (0, combinator_1.consume)(params[0].length, context);
2730
+ count && (0, combinator_1.spend)(context, params[0].length);
2731
2731
  const result = f(params)(input);
2732
2732
  context.position += result ? context.position === position ? params[0].length : 0 : context.position - position;
2733
2733
  return result;
@@ -3239,7 +3239,7 @@ function matcher(pattern, advance, after) {
3239
3239
  pos = position;
3240
3240
  if (index === -1) return;
3241
3241
  const src = source.slice(position, index);
3242
- count && !hit && (0, context_1.consume)(src.length, context);
3242
+ count && !hit && (0, context_1.spend)(context, src.length);
3243
3243
  if (advance) {
3244
3244
  context.position = index;
3245
3245
  }
@@ -3290,7 +3290,7 @@ function tester(pattern, advance, after) {
3290
3290
  pos = position;
3291
3291
  if (index === -1) return;
3292
3292
  const len = index - position;
3293
- count && !hit && (0, context_1.consume)(len, context);
3293
+ count && !hit && (0, context_1.spend)(context, len);
3294
3294
  if (advance) {
3295
3295
  context.position = index;
3296
3296
  }
@@ -3547,35 +3547,28 @@ exports.failsafe = failsafe;
3547
3547
  Object.defineProperty(exports, "__esModule", ({
3548
3548
  value: true
3549
3549
  }));
3550
- exports.constraint = exports.state = exports.precedence = exports.recursions = exports.recursion = exports.consume = exports.creation = void 0;
3550
+ exports.constraint = exports.state = exports.precedence = exports.recur = exports.recursion = exports.spend = exports.creation = void 0;
3551
3551
  const alias_1 = __webpack_require__(5413);
3552
3552
  function creation(cost, parser) {
3553
3553
  return input => {
3554
3554
  const context = input;
3555
- const resources = context.resources ?? {
3556
- clock: cost || 1,
3557
- recursions: [1]
3558
- };
3559
- const {
3560
- recursions
3561
- } = resources;
3562
3555
  const result = parser(input);
3563
3556
  if (result === undefined) return;
3564
- consume(cost, context);
3557
+ spend(context, cost);
3565
3558
  return result;
3566
3559
  };
3567
3560
  }
3568
3561
  exports.creation = creation;
3569
- function consume(cost, context) {
3570
- const {
3571
- resources
3572
- } = context;
3573
- if (!resources) return;
3562
+ function spend(context, cost) {
3563
+ const resources = context.resources ?? {
3564
+ clock: cost || 1,
3565
+ recursions: [1]
3566
+ };
3574
3567
  if (resources.clock < cost) throw new Error('Too many creations');
3575
3568
  resources.clock -= cost;
3576
3569
  }
3577
- exports.consume = consume;
3578
- function recursion(recursion, parser) {
3570
+ exports.spend = spend;
3571
+ function recursion(index, parser) {
3579
3572
  return input => {
3580
3573
  const context = input;
3581
3574
  const resources = context.resources ?? {
@@ -3585,41 +3578,19 @@ function recursion(recursion, parser) {
3585
3578
  const {
3586
3579
  recursions
3587
3580
  } = resources;
3588
- const rec = (0, alias_1.min)(recursion, recursions.length - 1);
3589
- if (rec >= 0 && recursions[rec] < 1) throw new Error('Too much recursion');
3590
- rec >= 0 && --recursions[rec];
3581
+ recur(recursions, index, 1);
3591
3582
  const result = parser(input);
3592
- rec >= 0 && ++recursions[rec];
3583
+ recur(recursions, index, -1);
3593
3584
  return result;
3594
3585
  };
3595
3586
  }
3596
3587
  exports.recursion = recursion;
3597
- function recursions(rs, parser) {
3598
- return input => {
3599
- const context = input;
3600
- const resources = context.resources ?? {
3601
- clock: 1,
3602
- recursions: [4]
3603
- };
3604
- const {
3605
- recursions
3606
- } = resources;
3607
- for (const recursion of rs) {
3608
- const rec = (0, alias_1.min)(recursion, recursions.length - 1);
3609
- if (rec === -1) continue;
3610
- if (recursions[rec] < 1) throw new Error('Too much recursion');
3611
- --recursions[rec];
3612
- }
3613
- const result = parser(input);
3614
- for (const recursion of rs) {
3615
- const rec = (0, alias_1.min)(recursion, recursions.length - 1);
3616
- if (rec === -1) continue;
3617
- ++recursions[rec];
3618
- }
3619
- return result;
3620
- };
3588
+ function recur(recursions, index, size, force = false) {
3589
+ index = (0, alias_1.min)(index, recursions.length && recursions.length - 1);
3590
+ if (recursions[index] < size - +force) throw new Error('Too much recursion');
3591
+ recursions[index] -= size;
3621
3592
  }
3622
- exports.recursions = recursions;
3593
+ exports.recur = recur;
3623
3594
  function precedence(precedence, parser) {
3624
3595
  return input => {
3625
3596
  const context = input;
@@ -3773,7 +3744,6 @@ function some(parser, delimiter, after, delimiters, limit = 0) {
3773
3744
  source,
3774
3745
  position
3775
3746
  } = context;
3776
- //assert(context.backtracks ??= {});
3777
3747
  let nodes;
3778
3748
  delims && context.delimiters.push(delims);
3779
3749
  // whileは数倍遅い
@@ -4468,7 +4438,7 @@ exports.block = error((0, combinator_1.union)([source_1.emptysegment, input => {
4468
4438
  case '(':
4469
4439
  return (0, olist_1.olist)(input);
4470
4440
  default:
4471
- if ('0' <= char && char <= '9') return (0, olist_1.olist)(input);
4441
+ if (char <= '9' && '0' <= char) return (0, olist_1.olist)(input);
4472
4442
  }
4473
4443
  }, paragraph_1.paragraph]));
4474
4444
  function error(parser) {
@@ -4512,7 +4482,7 @@ const indent = (0, combinator_1.open)(opener, (0, combinator_1.some)(source_1.co
4512
4482
  const unindent = source => source.replace(/(?<=^|\n)>(?: |(?=>*(?:$|[ \r\n])))|\r?\n$/g, '');
4513
4483
  const source = (0, combinator_1.lazy)(() => (0, combinator_1.fmap)((0, combinator_1.recursion)(1 /* Recursion.blockquote */, (0, combinator_1.some)((0, combinator_1.union)([(0, combinator_1.rewrite)(indent, (0, combinator_1.convert)(unindent, source)), (0, combinator_1.rewrite)((0, combinator_1.some)(source_1.contentline, opener), (0, combinator_1.convert)(unindent, (0, combinator_1.fmap)(autolink_1.autolink, ns => new parser_1.List([new parser_1.Node((0, dom_1.html)('pre', (0, dom_1.defrag)((0, util_1.unwrap)(ns))))]))))]))), ns => new parser_1.List([new parser_1.Node((0, dom_1.html)('blockquote', (0, util_1.unwrap)(ns)))])));
4514
4484
  const markdown = (0, combinator_1.lazy)(() => (0, combinator_1.fmap)((0, combinator_1.recursion)(1 /* Recursion.blockquote */, (0, combinator_1.some)((0, combinator_1.union)([(0, combinator_1.rewrite)(indent, (0, combinator_1.convert)(unindent, markdown)), (0, combinator_1.rewrite)((0, combinator_1.some)(source_1.contentline, opener), (0, combinator_1.convert)(unindent, context => {
4515
- (0, combinator_1.consume)(10, context);
4485
+ (0, combinator_1.spend)(context, 10);
4516
4486
  const {
4517
4487
  source
4518
4488
  } = context;
@@ -5823,7 +5793,7 @@ exports.MAX_INPUT_SIZE = exports.MAX_SEGMENT_SIZE * 10;
5823
5793
  class Context extends parser_1.Context {
5824
5794
  constructor(options = {}) {
5825
5795
  super(options);
5826
- this.recursion = new RecursionCounter('annotation', 2);
5796
+ this.recursion = new RecursionCounter(2);
5827
5797
  const {
5828
5798
  segment,
5829
5799
  local,
@@ -5835,7 +5805,7 @@ class Context extends parser_1.Context {
5835
5805
  id,
5836
5806
  caches
5837
5807
  } = options;
5838
- this.resources ??= {
5808
+ this.resources = options.resources ?? {
5839
5809
  // バックトラックのせいで文字数制限を受けないようにする。
5840
5810
  clock: exports.MAX_SEGMENT_SIZE * (5 + 1),
5841
5811
  recursions: [5 || 0 /* Recursion.block */, 20 || 0 /* Recursion.blockquote */, 40 || 0 /* Recursion.listitem */, 20 || 0 /* Recursion.inline */, 20 || 0 /* Recursion.bracket */, 20 || 0 /* Recursion.terminal */]
@@ -5853,8 +5823,7 @@ class Context extends parser_1.Context {
5853
5823
  }
5854
5824
  exports.Context = Context;
5855
5825
  class RecursionCounter {
5856
- constructor(syntax, limit) {
5857
- this.syntax = syntax;
5826
+ constructor(limit) {
5858
5827
  this.limit = limit;
5859
5828
  this.stack = [];
5860
5829
  this.index = 0;
@@ -5865,7 +5834,7 @@ class RecursionCounter {
5865
5834
  } = this;
5866
5835
  for (; this.index > 0 && stack[this.index - 1] <= depth; --this.index);
5867
5836
  // 内側から数えるので無効化処理できずエラーを投げるしかない。
5868
- if (this.index === this.limit) throw new Error(`Too much ${this.syntax} recursion`);
5837
+ if (this.index === this.limit) throw new Error(`Too much recursion`);
5869
5838
  stack[this.index] = depth;
5870
5839
  ++this.index;
5871
5840
  }
@@ -6067,7 +6036,7 @@ Object.defineProperty(exports, "lineshortmedia", ({
6067
6036
  }
6068
6037
  }));
6069
6038
  function isAlphabet(char) {
6070
- return 'a' <= char && char <= 'z';
6039
+ return char <= 'z' && 'a' <= char;
6071
6040
  }
6072
6041
 
6073
6042
  /***/ },
@@ -6105,7 +6074,7 @@ const dom_1 = __webpack_require__(394);
6105
6074
  // 修正する必要があるためほぼ完全な二重処理が必要になり三重以上の注釈という不適切な使用のために
6106
6075
  // 常に非常に非効率な処理を行い常時低速化するより三重以上の注釈を禁止して効率性を維持するのが妥当である。
6107
6076
  const MAX_DEPTH = 20;
6108
- exports.annotation = (0, combinator_1.lazy)(() => (0, combinator_1.constraint)(128 /* State.annotation */, (0, repeat_1.repeat)('(', visibility_1.beforeNonblank, ')', [4 /* Recursion.bracket */], (0, combinator_1.precedence)(1, (0, combinator_1.surround)('', (0, combinator_1.some)((0, combinator_1.union)([inline_1.inline]), ')', [[')', 1]]), ')', false, [], ([, bs], {
6077
+ exports.annotation = (0, combinator_1.lazy)(() => (0, combinator_1.constraint)(128 /* State.annotation */, (0, repeat_1.repeat)('(', visibility_1.beforeNonblank, ')', 4 /* Recursion.bracket */, (0, combinator_1.precedence)(1, (0, combinator_1.surround)('', (0, combinator_1.some)((0, combinator_1.union)([inline_1.inline]), ')', [[')', 1]]), ')', false, [], ([, bs], {
6109
6078
  buffer
6110
6079
  }) => buffer.import(bs), ([, bs], {
6111
6080
  buffer
@@ -6519,7 +6488,7 @@ const repeat_1 = __webpack_require__(8019);
6519
6488
  const visibility_1 = __webpack_require__(6364);
6520
6489
  const util_1 = __webpack_require__(4992);
6521
6490
  const dom_1 = __webpack_require__(394);
6522
- exports.deletion = (0, combinator_1.lazy)(() => (0, repeat_1.repeat)('~~', '', '~~', [3 /* Recursion.inline */], (0, combinator_1.precedence)(0, (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], {
6491
+ exports.deletion = (0, combinator_1.lazy)(() => (0, repeat_1.repeat)('~~', '', '~~', 3 /* Recursion.inline */, (0, combinator_1.precedence)(0, (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], {
6523
6492
  buffer
6524
6493
  }) => buffer.import(bs), ([, bs], {
6525
6494
  buffer
@@ -6574,7 +6543,7 @@ const subemphasis = (0, combinator_1.lazy)(() => (0, combinator_1.some)((0, comb
6574
6543
  // 開閉が明示的でない構文は開閉の不明確な記号による再帰的適用を行わず
6575
6544
  // 可能な限り早く閉じるよう解析しなければならない。
6576
6545
  // このため終端記号の後ろを見て終端を中止し同じ構文を再帰的に適用してはならない。
6577
- exports.emstrong = (0, combinator_1.lazy)(() => (0, repeat_1.repeat)('***', visibility_1.beforeNonblank, '***', [3 /* Recursion.inline */], (0, combinator_1.precedence)(0, (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) => {
6546
+ exports.emstrong = (0, combinator_1.lazy)(() => (0, repeat_1.repeat)('***', visibility_1.beforeNonblank, '***', 3 /* Recursion.inline */, (0, combinator_1.precedence)(0, (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) => {
6578
6547
  const {
6579
6548
  buffer
6580
6549
  } = context;
@@ -7153,7 +7122,7 @@ const repeat_1 = __webpack_require__(8019);
7153
7122
  const visibility_1 = __webpack_require__(6364);
7154
7123
  const util_1 = __webpack_require__(4992);
7155
7124
  const dom_1 = __webpack_require__(394);
7156
- exports.insertion = (0, combinator_1.lazy)(() => (0, repeat_1.repeat)('++', '', '++', [3 /* Recursion.inline */], (0, combinator_1.precedence)(0, (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], {
7125
+ exports.insertion = (0, combinator_1.lazy)(() => (0, repeat_1.repeat)('++', '', '++', 3 /* Recursion.inline */, (0, combinator_1.precedence)(0, (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], {
7157
7126
  buffer
7158
7127
  }) => buffer.import(bs), ([, bs], {
7159
7128
  buffer
@@ -7181,7 +7150,7 @@ const dom_1 = __webpack_require__(394);
7181
7150
  // 可読性のため実際にはオブリーク体を指定する。
7182
7151
  // 斜体は単語に使うとかえって見づらく読み飛ばしやすくなるため使わないべきであり
7183
7152
  // ある程度の長さのある文に使うのが望ましい。
7184
- exports.italic = (0, combinator_1.lazy)(() => (0, repeat_1.repeat)('///', visibility_1.beforeNonblank, '///', [3 /* Recursion.inline */], (0, combinator_1.precedence)(0, (0, combinator_1.surround)('', (0, combinator_1.some)((0, combinator_1.union)([inline_1.inline]), '///', visibility_1.afterNonblank), '///', false, [], ([, bs], {
7153
+ exports.italic = (0, combinator_1.lazy)(() => (0, repeat_1.repeat)('///', visibility_1.beforeNonblank, '///', 3 /* Recursion.inline */, (0, combinator_1.precedence)(0, (0, combinator_1.surround)('', (0, combinator_1.some)((0, combinator_1.union)([inline_1.inline]), '///', visibility_1.afterNonblank), '///', false, [], ([, bs], {
7185
7154
  buffer
7186
7155
  }) => buffer.import(bs), ([, bs], {
7187
7156
  buffer
@@ -7256,7 +7225,7 @@ exports.uri = (0, combinator_1.union)([(0, combinator_1.open)(' ', (0, source_1.
7256
7225
  exports.option = (0, combinator_1.union)([(0, combinator_1.fmap)((0, source_1.str)(/ nofollow(?=[ }])/y), () => new parser_1.List([new parser_1.Node(' rel="nofollow"')])), (0, source_1.str)(/ [a-z]+(?:-[a-z]+)*(?:="(?:\\[^\r\n]|[^\\\r\n"])*")?(?=[ }])/yi), (0, source_1.str)(/ [^\s{}]+/y)]);
7257
7226
  function parse(content, params, context) {
7258
7227
  const INSECURE_URI = params.shift().value;
7259
- (0, combinator_1.consume)(10, context);
7228
+ (0, combinator_1.spend)(context, 10);
7260
7229
  let uri;
7261
7230
  try {
7262
7231
  uri = new url_1.ReadonlyURL(resolve(INSECURE_URI, context.host ?? location, context.url ?? context.host ?? location), context.host?.href || location.href);
@@ -7363,7 +7332,7 @@ const repeat_1 = __webpack_require__(8019);
7363
7332
  const visibility_1 = __webpack_require__(6364);
7364
7333
  const util_1 = __webpack_require__(4992);
7365
7334
  const dom_1 = __webpack_require__(394);
7366
- exports.mark = (0, combinator_1.lazy)(() => (0, repeat_1.repeat)('==', visibility_1.beforeNonblank, '==', [3 /* Recursion.inline */], (0, combinator_1.precedence)(0, (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], {
7335
+ exports.mark = (0, combinator_1.lazy)(() => (0, repeat_1.repeat)('==', visibility_1.beforeNonblank, '==', 3 /* Recursion.inline */, (0, combinator_1.precedence)(0, (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], {
7367
7336
  buffer
7368
7337
  }) => buffer.import(bs), ([, bs], {
7369
7338
  buffer
@@ -7465,7 +7434,7 @@ exports.media = (0, combinator_1.lazy)(() => (0, combinator_1.constraint)(4 /* S
7465
7434
  text = text.trim();
7466
7435
  if (text === '' || text[0] !== tmp[0]) return;
7467
7436
  }
7468
- (0, combinator_1.consume)(100, context);
7437
+ (0, combinator_1.spend)(context, 100);
7469
7438
  if (params.last.value === "\u0018" /* Command.Cancel */) {
7470
7439
  params.pop();
7471
7440
  return new parser_1.List([new parser_1.Node((0, dom_1.html)('span', {
@@ -8157,8 +8126,9 @@ Object.defineProperty(exports, "__esModule", ({
8157
8126
  exports.repeat = void 0;
8158
8127
  const parser_1 = __webpack_require__(605);
8159
8128
  const delimiter_1 = __webpack_require__(385);
8129
+ const combinator_1 = __webpack_require__(3484);
8160
8130
  const alias_1 = __webpack_require__(5413);
8161
- function repeat(opener, after, closer, rs, parser, cons, termination = (nodes, context, prefix, postfix) => {
8131
+ function repeat(opener, after, closer, recursion, parser, cons, termination = (nodes, context, prefix, postfix) => {
8162
8132
  const acc = new parser_1.List();
8163
8133
  if (prefix > 0) {
8164
8134
  acc.push(new parser_1.Node(opener[0].repeat(prefix)));
@@ -8184,7 +8154,7 @@ function repeat(opener, after, closer, rs, parser, cons, termination = (nodes, c
8184
8154
  position,
8185
8155
  resources: {
8186
8156
  recursions
8187
- } = {}
8157
+ }
8188
8158
  } = context;
8189
8159
  if (!source.startsWith(opener, context.position)) return;
8190
8160
  let nodes = new parser_1.List();
@@ -8196,20 +8166,11 @@ function repeat(opener, after, closer, rs, parser, cons, termination = (nodes, c
8196
8166
  return;
8197
8167
  }
8198
8168
  let depth = i / opener.length + 1 | 0;
8199
- if (recursions) for (const recursion of rs) {
8200
- const rec = (0, alias_1.min)(recursion, recursions.length - 1);
8201
- if (rec === -1) continue;
8202
- if (recursions[rec] < depth - 1) throw new Error('Too much recursion');
8203
- recursions[rec] -= depth;
8204
- }
8169
+ (0, combinator_1.recur)(recursions, recursion, depth, true);
8205
8170
  let state = false;
8206
8171
  let follow = 0;
8207
8172
  for (; i >= opener.length; i -= opener.length, follow -= closer.length) {
8208
- if (recursions) for (const recursion of rs) {
8209
- const rec = (0, alias_1.min)(recursion, recursions.length - 1);
8210
- if (rec === -1) continue;
8211
- recursions[rec] += 1;
8212
- }
8173
+ (0, combinator_1.recur)(recursions, recursion, -1);
8213
8174
  depth -= 1;
8214
8175
  const lead = i - opener.length;
8215
8176
  if (source.startsWith(closer, context.position)) {
@@ -8257,11 +8218,7 @@ function repeat(opener, after, closer, rs, parser, cons, termination = (nodes, c
8257
8218
  }
8258
8219
  break;
8259
8220
  }
8260
- if (recursions) for (let i = 0; i < depth; ++i) for (const recursion of rs) {
8261
- const rec = (0, alias_1.min)(recursion, recursions.length - 1);
8262
- if (rec === -1) continue;
8263
- recursions[rec] += depth;
8264
- }
8221
+ (0, combinator_1.recur)(recursions, recursion, -depth);
8265
8222
  depth = 0;
8266
8223
  const prefix = i;
8267
8224
  i = 0;
@@ -8448,11 +8405,11 @@ const escsource = context => {
8448
8405
  } = context;
8449
8406
  if (position === source.length) return;
8450
8407
  const char = source[position];
8451
- (0, combinator_1.consume)(1, context);
8408
+ (0, combinator_1.spend)(context, 1);
8452
8409
  context.position += 1;
8453
8410
  switch (char) {
8454
8411
  case "\u001B" /* Command.Escape */:
8455
- (0, combinator_1.consume)(1, context);
8412
+ (0, combinator_1.spend)(context, 1);
8456
8413
  context.position += 1;
8457
8414
  return new parser_1.List([new parser_1.Node(source.slice(position + 1, position + 2))]);
8458
8415
  case '\\':
@@ -8462,7 +8419,7 @@ const escsource = context => {
8462
8419
  case '\n':
8463
8420
  return new parser_1.List([new parser_1.Node(char)]);
8464
8421
  default:
8465
- (0, combinator_1.consume)(1, context);
8422
+ (0, combinator_1.spend)(context, 1);
8466
8423
  context.position += 1;
8467
8424
  return new parser_1.List([new parser_1.Node(source.slice(position, position + 2))]);
8468
8425
  }
@@ -8475,7 +8432,7 @@ const escsource = context => {
8475
8432
  if (context.sequential) return new parser_1.List([new parser_1.Node(char)]);
8476
8433
  let i = seek(source, position);
8477
8434
  i -= position;
8478
- (0, combinator_1.consume)(i - 1, context);
8435
+ (0, combinator_1.spend)(context, i - 1);
8479
8436
  context.position += i - 1;
8480
8437
  return new parser_1.List([new parser_1.Node(source.slice(position, context.position))]);
8481
8438
  }
@@ -8648,7 +8605,7 @@ const text = input => {
8648
8605
  } = context;
8649
8606
  if (position === source.length) return;
8650
8607
  const char = source[position];
8651
- (0, combinator_1.consume)(1, context);
8608
+ (0, combinator_1.spend)(context, 1);
8652
8609
  context.position += 1;
8653
8610
  switch (char) {
8654
8611
  case "\u001B" /* Command.Escape */:
@@ -8660,7 +8617,7 @@ const text = input => {
8660
8617
  case '\n':
8661
8618
  return new parser_1.List();
8662
8619
  default:
8663
- (0, combinator_1.consume)(1, context);
8620
+ (0, combinator_1.spend)(context, 1);
8664
8621
  context.position += 1;
8665
8622
  return new parser_1.List([new parser_1.Node(source.slice(position + 1, context.position))]);
8666
8623
  }
@@ -8677,7 +8634,7 @@ const text = input => {
8677
8634
  const lineend = false || s && i === source.length || s && source[i] === '\r' || s && source[i] === '\n';
8678
8635
  i -= position;
8679
8636
  i = lineend ? i : i - +s || 1;
8680
- (0, combinator_1.consume)(i - 1, context);
8637
+ (0, combinator_1.spend)(context, i - 1);
8681
8638
  context.position += i - 1;
8682
8639
  const linestart = position === 0 || source[position - 1] === '\n';
8683
8640
  if (position === context.position || s && !linestart || lineend) return new parser_1.List();
@@ -8707,7 +8664,7 @@ function isWhitespace(char, linebreak) {
8707
8664
  }
8708
8665
  function next(source, position, state) {
8709
8666
  let index = seek(source, position, state);
8710
- if (index === source.length) return source.length;
8667
+ if (index === source.length) return index;
8711
8668
  const char = source[index];
8712
8669
  switch (char) {
8713
8670
  case '%':
@@ -8771,8 +8728,9 @@ function backToEmailHead(source, position, index) {
8771
8728
  }
8772
8729
  exports.backToEmailHead = backToEmailHead;
8773
8730
  function isAlphanumeric(char) {
8774
- if (char < '0' || '\x7F' < char) return false;
8775
- return '0' <= char && char <= '9' || 'A' <= char && char <= 'Z' || 'a' <= char && char <= 'z';
8731
+ if (char < '0' || 'z' < char) return false;
8732
+ if (char <= '9' || 'a' <= char) return true;
8733
+ return 'A' <= char && char <= 'Z';
8776
8734
  }
8777
8735
  exports.isAlphanumeric = isAlphanumeric;
8778
8736
  function seek(source, position, state) {
@@ -8878,11 +8836,11 @@ const unescsource = context => {
8878
8836
  } = context;
8879
8837
  if (position === source.length) return;
8880
8838
  const char = source[position];
8881
- (0, combinator_1.consume)(1, context);
8839
+ (0, combinator_1.spend)(context, 1);
8882
8840
  context.position += 1;
8883
8841
  switch (char) {
8884
8842
  case "\u001B" /* Command.Escape */:
8885
- (0, combinator_1.consume)(1, context);
8843
+ (0, combinator_1.spend)(context, 1);
8886
8844
  context.position += 1;
8887
8845
  return new parser_1.List([new parser_1.Node(source.slice(position + 1, position + 2))]);
8888
8846
  case '\r':
@@ -8895,7 +8853,7 @@ const unescsource = context => {
8895
8853
  text_1.nonWhitespace.lastIndex = position + 1;
8896
8854
  let i = (0, text_1.canSkip)(source, position) ? text_1.nonWhitespace.test(source) ? text_1.nonWhitespace.lastIndex - 1 : source.length : next(source, position, state);
8897
8855
  i -= position;
8898
- (0, combinator_1.consume)(i - 1, context);
8856
+ (0, combinator_1.spend)(context, i - 1);
8899
8857
  context.position += i - 1;
8900
8858
  return new parser_1.List([new parser_1.Node(source.slice(position, context.position))]);
8901
8859
  }
@@ -8903,7 +8861,7 @@ const unescsource = context => {
8903
8861
  exports.unescsource = unescsource;
8904
8862
  function next(source, position, state) {
8905
8863
  let index = seek(source, position, state);
8906
- if (index === source.length) return source.length;
8864
+ if (index === source.length) return index;
8907
8865
  const char = source[index];
8908
8866
  switch (char) {
8909
8867
  case ':':
@@ -8972,7 +8930,7 @@ function seek(source, position, state) {
8972
8930
  return source.length;
8973
8931
  }
8974
8932
  function category(char) {
8975
- return '\x21' <= char && char <= '\x7E';
8933
+ return char <= '\x7E' && '\x21' <= char;
8976
8934
  }
8977
8935
 
8978
8936
  /***/ },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "securemark",
3
- "version": "0.299.2",
3
+ "version": "0.299.3",
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",
@@ -1,5 +1,5 @@
1
1
  import { Parser, List, Node, Context, failsafe } from '../../data/parser';
2
- import { consume } from '../../../combinator';
2
+ import { spend } from '../../../combinator';
3
3
  import { firstline, isEmptyline } from '../constraint/line';
4
4
  import { push } from 'spica/array';
5
5
 
@@ -13,7 +13,7 @@ export function fence<C extends Context, D extends Parser<unknown, C>[]>(opener:
13
13
  const matches = opener.exec(source);
14
14
  if (!matches) return;
15
15
  assert(matches[0] === firstline(source, position));
16
- consume(matches[0].length, context);
16
+ spend(context, matches[0].length);
17
17
  const delim = matches[1];
18
18
  assert(delim && delim === delim.trim());
19
19
  if (matches[0].includes(delim, delim.length)) return;
@@ -1,5 +1,5 @@
1
1
  import { Parser } from '../../data/parser';
2
- import { consume } from '../../../combinator';
2
+ import { spend } from '../../../combinator';
3
3
 
4
4
  export function match<P extends Parser>(pattern: RegExp, f: (matched: RegExpMatchArray) => P): P;
5
5
  export function match<N>(pattern: RegExp, f: (matched: RegExpMatchArray) => Parser<N>): Parser<N> {
@@ -15,7 +15,7 @@ export function match<N>(pattern: RegExp, f: (matched: RegExpMatchArray) => Pars
15
15
  const params = pattern.exec(source);
16
16
  if (!params) return;
17
17
  assert(source.startsWith(params[0], position));
18
- count && consume(params[0].length, context);
18
+ count && spend(context, params[0].length);
19
19
  const result = f(params)(input);
20
20
  context.position += result
21
21
  ? context.position === position
@@ -1,5 +1,5 @@
1
1
  import { Parser, Input, List, Node, Context } from './parser';
2
- import { consume } from './parser/context';
2
+ import { spend } from './parser/context';
3
3
 
4
4
  interface Delimiter {
5
5
  readonly memory: Delimiter[];
@@ -199,7 +199,7 @@ export function matcher(pattern: string | RegExp, advance: boolean, after?: Pars
199
199
  pos = position;
200
200
  if (index === -1) return;
201
201
  const src = source.slice(position, index);
202
- count && !hit && consume(src.length, context);
202
+ count && !hit && spend(context, src.length);
203
203
  if (advance) {
204
204
  context.position = index;
205
205
  }
@@ -250,7 +250,7 @@ export function tester(pattern: string | RegExp, advance: boolean, after?: Parse
250
250
  pos = position;
251
251
  if (index === -1) return;
252
252
  const len = index - position;
253
- count && !hit && consume(len, context);
253
+ count && !hit && spend(context, len);
254
254
  if (advance) {
255
255
  context.position = index;
256
256
  }
@@ -6,61 +6,35 @@ export function creation(cost: number, parser: Parser): Parser {
6
6
  assert(cost >= 0);
7
7
  return input => {
8
8
  const context = input;
9
- const resources = context.resources ?? { clock: cost || 1, recursions: [1] };
10
- const { recursions } = resources;
11
- assert(recursions.length > 0);
12
9
  const result = parser(input);
13
10
  if (result === undefined) return;
14
- consume(cost, context);
11
+ spend(context, cost);
15
12
  return result;
16
13
  };
17
14
  }
18
- export function consume(cost: number, context: Context): void {
19
- const { resources } = context;
20
- if (!resources) return;
15
+ export function spend(context: Context, cost: number): void {
16
+ const resources = context.resources ?? { clock: cost || 1, recursions: [1] };
21
17
  if (resources.clock < cost) throw new Error('Too many creations');
22
18
  resources.clock -= cost;
23
19
  }
24
20
 
25
- export function recursion<P extends Parser>(recursion: number, parser: P): P;
26
- export function recursion(recursion: number, parser: Parser): Parser {
27
- assert(recursion >= 0);
21
+ export function recursion<P extends Parser>(index: number, parser: P): P;
22
+ export function recursion(index: number, parser: Parser): Parser {
23
+ assert(index >= 0);
28
24
  return input => {
29
25
  const context = input;
30
26
  const resources = context.resources ?? { clock: 1, recursions: [1] };
31
27
  const { recursions } = resources;
32
- assert(recursions.length > 0);
33
- const rec = min(recursion, recursions.length - 1);
34
- if (rec >= 0 && recursions[rec] < 1) throw new Error('Too much recursion');
35
- rec >= 0 && --recursions[rec];
28
+ recur(recursions, index, 1);
36
29
  const result = parser(input);
37
- rec >= 0 && ++recursions[rec];
30
+ recur(recursions, index, -1);
38
31
  return result;
39
32
  };
40
33
  }
41
-
42
- export function recursions<P extends Parser>(recursions: readonly number[], parser: P): P;
43
- export function recursions(rs: readonly number[], parser: Parser): Parser {
44
- assert(rs.every(r => r >= 0));
45
- return input => {
46
- const context = input;
47
- const resources = context.resources ?? { clock: 1, recursions: [4] };
48
- const { recursions } = resources;
49
- assert(recursions.length > 0);
50
- for (const recursion of rs) {
51
- const rec = min(recursion, recursions.length - 1);
52
- if (rec === -1) continue;
53
- if (recursions[rec] < 1) throw new Error('Too much recursion');
54
- --recursions[rec];
55
- }
56
- const result = parser(input);
57
- for (const recursion of rs) {
58
- const rec = min(recursion, recursions.length - 1);
59
- if (rec === -1) continue;
60
- ++recursions[rec];
61
- }
62
- return result;
63
- };
34
+ export function recur(recursions: number[], index: number, size: number, force: boolean = false): void {
35
+ index = min(index, recursions.length && recursions.length - 1);
36
+ if (recursions[index] < size - +force) throw new Error('Too much recursion');
37
+ recursions[index] -= size;
64
38
  }
65
39
 
66
40
  export function precedence<P extends Parser>(precedence: number, parser: P): P;
@@ -38,7 +38,6 @@ export function some<N>(parser: Parser<N>, delimiter?: number | string | RegExp
38
38
  return input => {
39
39
  const context = input;
40
40
  const { source, position } = context;
41
- //assert(context.backtracks ??= {});
42
41
  let nodes: List<Node<N>> | undefined;
43
42
  delims && context.delimiters.push(delims);
44
43
  // whileは数倍遅い
@@ -1,7 +1,7 @@
1
1
  import { BlockquoteParser } from '../block';
2
2
  import { Recursion } from '../context';
3
3
  import { List, Node } from '../../combinator/data/parser';
4
- import { union, some, consume, recursion, block, validate, rewrite, open, convert, lazy, fmap } from '../../combinator';
4
+ import { union, some, spend, recursion, block, validate, rewrite, open, convert, lazy, fmap } from '../../combinator';
5
5
  import { autolink } from '../autolink';
6
6
  import { contentline } from '../source';
7
7
  import { unwrap, randomID } from '../util';
@@ -40,7 +40,7 @@ const markdown: BlockquoteParser.MarkdownParser = lazy(() => fmap(
40
40
  rewrite(
41
41
  some(contentline, opener),
42
42
  convert(unindent, context => {
43
- consume(10, context);
43
+ spend(context, 10);
44
44
  const { source } = context;
45
45
  const references = html('ol', { class: 'references' });
46
46
  const document = parse(source, {
@@ -99,7 +99,7 @@ export const block: BlockParser = error(union([
99
99
  case '(':
100
100
  return olist(input);
101
101
  default:
102
- if ('0' <= char && char <= '9') return olist(input);
102
+ if (char <= '9' && '0' <= char) return olist(input);
103
103
  }
104
104
  },
105
105
  paragraph
@@ -20,7 +20,7 @@ export class Context extends Ctx {
20
20
  id,
21
21
  caches,
22
22
  } = options;
23
- this.resources ??= {
23
+ this.resources = options.resources ?? {
24
24
  // バックトラックのせいで文字数制限を受けないようにする。
25
25
  clock: MAX_SEGMENT_SIZE * (5 + 1),
26
26
  recursions: [
@@ -42,7 +42,7 @@ export class Context extends Ctx {
42
42
  this.id = id;
43
43
  this.caches = caches;
44
44
  }
45
- public override readonly resources?: {
45
+ public override readonly resources: {
46
46
  clock: number;
47
47
  recursions: number[];
48
48
  };
@@ -50,7 +50,7 @@ export class Context extends Ctx {
50
50
  public local: boolean;
51
51
  public sequential: boolean;
52
52
  public buffer: List<Node<(string | HTMLElement)>>;
53
- public recursion = new RecursionCounter('annotation', 2);
53
+ public recursion = new RecursionCounter(2);
54
54
  public readonly header: boolean;
55
55
  public readonly host?: URL;
56
56
  public readonly url?: URL;
@@ -65,7 +65,6 @@ export type Options = Partial<Context>;
65
65
 
66
66
  class RecursionCounter {
67
67
  constructor(
68
- private readonly syntax: string,
69
68
  private readonly limit: number,
70
69
  ) {
71
70
  }
@@ -75,7 +74,7 @@ class RecursionCounter {
75
74
  const { stack } = this
76
75
  for (; this.index > 0 && stack[this.index - 1] <= depth; --this.index);
77
76
  // 内側から数えるので無効化処理できずエラーを投げるしかない。
78
- if (this.index === this.limit) throw new Error(`Too much ${this.syntax} recursion`);
77
+ if (this.index === this.limit) throw new Error(`Too much recursion`);
79
78
  stack[this.index] = depth;
80
79
  ++this.index;
81
80
  }
@@ -25,7 +25,7 @@ import { html, defrag } from 'typed-dom/dom';
25
25
  // 常に非常に非効率な処理を行い常時低速化するより三重以上の注釈を禁止して効率性を維持するのが妥当である。
26
26
  const MAX_DEPTH = 20;
27
27
  export const annotation: AnnotationParser = lazy(() => constraint(State.annotation,
28
- repeat('(', beforeNonblank, ')', [Recursion.bracket], precedence(1, surround(
28
+ repeat('(', beforeNonblank, ')', Recursion.bracket, precedence(1, surround(
29
29
  '',
30
30
  some(union([inline]), ')', [[')', 1]]),
31
31
  ')',
@@ -9,7 +9,7 @@ import { unwrap } from '../util';
9
9
  import { html, defrag } from 'typed-dom/dom';
10
10
 
11
11
  export const deletion: DeletionParser = lazy(() =>
12
- repeat('~~', '', '~~', [Recursion.inline], precedence(0, surround(
12
+ repeat('~~', '', '~~', Recursion.inline, precedence(0, surround(
13
13
  '',
14
14
  some(union([
15
15
  some(inline, blankWith('\n', '~~')),
@@ -24,7 +24,7 @@ const subemphasis: Parser.IntermediateParser<EmphasisParser> = lazy(() => some(u
24
24
  // 可能な限り早く閉じるよう解析しなければならない。
25
25
  // このため終端記号の後ろを見て終端を中止し同じ構文を再帰的に適用してはならない。
26
26
  export const emstrong: EmStrongParser = lazy(() =>
27
- repeat('***', beforeNonblank, '***', [Recursion.inline], precedence(0, surround(
27
+ repeat('***', beforeNonblank, '***', Recursion.inline, precedence(0, surround(
28
28
  '',
29
29
  some(union([some(inline, '*', afterNonblank)])),
30
30
  strs('*', 1, 3),
@@ -9,7 +9,7 @@ import { unwrap } from '../util';
9
9
  import { html, defrag } from 'typed-dom/dom';
10
10
 
11
11
  export const insertion: InsertionParser = lazy(() =>
12
- repeat('++', '', '++', [Recursion.inline], precedence(0, surround(
12
+ repeat('++', '', '++', Recursion.inline, precedence(0, surround(
13
13
  '',
14
14
  some(union([
15
15
  some(inline, blankWith('\n', '++')),
@@ -12,7 +12,7 @@ import { html, defrag } from 'typed-dom/dom';
12
12
  // 斜体は単語に使うとかえって見づらく読み飛ばしやすくなるため使わないべきであり
13
13
  // ある程度の長さのある文に使うのが望ましい。
14
14
  export const italic: ItalicParser = lazy(() =>
15
- repeat('///', beforeNonblank, '///', [Recursion.inline], precedence(0, surround(
15
+ repeat('///', beforeNonblank, '///', Recursion.inline, precedence(0, surround(
16
16
  '',
17
17
  some(union([inline]), '///', afterNonblank),
18
18
  '///',
@@ -1,7 +1,7 @@
1
1
  import { LinkParser } from '../inline';
2
2
  import { Context, State, Backtrack, Command } from '../context';
3
3
  import { List, Node } from '../../combinator/data/parser';
4
- import { union, inits, sequence, subsequence, some, consume, precedence, state, constraint, surround, open, setBacktrack, dup, lazy, fmap, bind } from '../../combinator';
4
+ import { union, inits, sequence, subsequence, some, spend, precedence, state, constraint, surround, open, setBacktrack, dup, lazy, fmap, bind } from '../../combinator';
5
5
  import { inline, media, shortmedia } from '../inline';
6
6
  import { attributes } from './html';
7
7
  import { str } from '../source';
@@ -109,7 +109,7 @@ export function parse(
109
109
  const INSECURE_URI = params.shift()!.value;
110
110
  assert(INSECURE_URI === INSECURE_URI.trim());
111
111
  assert(!INSECURE_URI.match(/\s/));
112
- consume(10, context);
112
+ spend(context, 10);
113
113
  let uri: ReadonlyURL | undefined;
114
114
  try{
115
115
  uri = new ReadonlyURL(
@@ -10,7 +10,7 @@ import { unwrap } from '../util';
10
10
  import { html, define, defrag } from 'typed-dom/dom';
11
11
 
12
12
  export const mark: MarkParser = lazy(() =>
13
- repeat('==', beforeNonblank, '==', [Recursion.inline], precedence(0, surround(
13
+ repeat('==', beforeNonblank, '==', Recursion.inline, precedence(0, surround(
14
14
  '',
15
15
  state(State.mark, some(union([inline]), '==', afterNonblank)),
16
16
  '==',
@@ -2,7 +2,7 @@ import { MediaParser } from '../inline';
2
2
  import { State, Recursion, Backtrack, Command } from '../context';
3
3
  import { List, Node } from '../../combinator/data/parser';
4
4
  import { Flag } from '../node';
5
- import { union, inits, tails, some, consume, recursion, precedence, constraint, surround, open, setBacktrack, dup, lazy, fmap, bind } from '../../combinator';
5
+ import { union, inits, tails, some, spend, recursion, precedence, constraint, surround, open, setBacktrack, dup, lazy, fmap, bind } from '../../combinator';
6
6
  import { uri, option as linkoption, resolve, decode, parse } from './link';
7
7
  import { attributes } from './html';
8
8
  import { unsafehtmlentity } from './htmlentity';
@@ -59,7 +59,7 @@ export const media: MediaParser = lazy(() => constraint(State.media, open(
59
59
  text = text.trim();
60
60
  if (text === '' || text[0] !== tmp[0]) return;
61
61
  }
62
- consume(100, context);
62
+ spend(context, 100);
63
63
  if (params.last!.value === Command.Cancel) {
64
64
  params.pop();
65
65
  return new List([
@@ -135,5 +135,5 @@ export { shortmedia, lineshortmedia } from './inline/shortmedia';
135
135
 
136
136
  function isAlphabet(char: string): boolean {
137
137
  assert(char.length === 1);
138
- return 'a' <= char && char <= 'z';
138
+ return char <= 'z' && 'a' <= char;
139
139
  }
@@ -1,17 +1,18 @@
1
1
  import { Parser, Result, List, Node } from '../combinator/data/parser';
2
2
  import { tester } from '../combinator/data/delimiter';
3
+ import { recur } from '../combinator';
3
4
  import { Context, Recursion, Command } from './context';
4
5
  import { min } from 'spica/alias';
5
6
 
6
7
  export function repeat<P extends Parser<HTMLElement | string, Context>>(
7
- opener: string, after: string | RegExp, closer: string, recursions: readonly Recursion[], parser: P,
8
+ opener: string, after: string | RegExp, closer: string, recursion: Recursion, parser: P,
8
9
  cons: (nodes: List<Node<Parser.Node<P>>>, context: Parser.Context<P>, lead: number, follow: number) =>
9
10
  List<Node<Parser.Node<P>>>,
10
11
  termination?: (acc: List<Node<Parser.Node<P>>>, context: Context, prefix: number, postfix: number, state: boolean) =>
11
12
  Result<string | Parser.Node<P>>,
12
13
  ): P;
13
14
  export function repeat<N extends HTMLElement | string>(
14
- opener: string, after: string | RegExp, closer: string, rs: readonly Recursion[], parser: Parser<N>,
15
+ opener: string, after: string | RegExp, closer: string, recursion: Recursion, parser: Parser<N>,
15
16
  cons: (nodes: List<Node<N>>, context: Context, lead: number, follow: number) =>
16
17
  List<Node<N>>,
17
18
  termination: (acc: List<Node<N>>, context: Context, prefix: number, postfix: number, state: boolean) =>
@@ -35,7 +36,7 @@ export function repeat<N extends HTMLElement | string>(
35
36
  const test = tester(after, false);
36
37
  return input => {
37
38
  const context = input;
38
- const { source, position, resources: { recursions } = {} } = context;
39
+ const { source, position, resources: { recursions } } = context;
39
40
  if (!source.startsWith(opener, context.position)) return;
40
41
  let nodes = new List<Node<N>>();
41
42
  let i = opener.length;
@@ -46,20 +47,11 @@ export function repeat<N extends HTMLElement | string>(
46
47
  return;
47
48
  }
48
49
  let depth = i / opener.length + 1 | 0;
49
- if (recursions) for (const recursion of rs) {
50
- const rec = min(recursion, recursions.length - 1);
51
- if (rec === -1) continue;
52
- if (recursions[rec] < depth - 1) throw new Error('Too much recursion');
53
- recursions[rec] -= depth;
54
- }
50
+ recur(recursions, recursion, depth, true);
55
51
  let state = false;
56
52
  let follow = 0;
57
53
  for (; i >= opener.length; i -= opener.length, follow -= closer.length) {
58
- if (recursions) for (const recursion of rs) {
59
- const rec = min(recursion, recursions.length - 1);
60
- if (rec === -1) continue;
61
- recursions[rec] += 1;
62
- }
54
+ recur(recursions, recursion, -1);
63
55
  depth -= 1;
64
56
  const lead = i - opener.length;
65
57
  if (source.startsWith(closer, context.position)) {
@@ -109,11 +101,7 @@ export function repeat<N extends HTMLElement | string>(
109
101
  }
110
102
  break;
111
103
  }
112
- if (recursions) for (let i = 0; i < depth; ++i) for (const recursion of rs) {
113
- const rec = min(recursion, recursions.length - 1);
114
- if (rec === -1) continue;
115
- recursions[rec] += depth;
116
- }
104
+ recur(recursions, recursion, -depth);
117
105
  depth = 0;
118
106
  const prefix = i;
119
107
  i = 0;
@@ -2,18 +2,18 @@ import { EscapableSourceParser } from '../source';
2
2
  import { Command } from '../context';
3
3
  import { Flag } from '../node';
4
4
  import { List, Node } from '../../combinator/data/parser';
5
- import { consume } from '../../combinator';
5
+ import { spend } from '../../combinator';
6
6
  import { html } from 'typed-dom/dom';
7
7
 
8
8
  export const escsource: EscapableSourceParser = context => {
9
9
  const { source, position } = context;
10
10
  if (position === source.length) return;
11
11
  const char = source[position];
12
- consume(1, context);
12
+ spend(context, 1);
13
13
  context.position += 1;
14
14
  switch (char) {
15
15
  case Command.Escape:
16
- consume(1, context);
16
+ spend(context, 1);
17
17
  context.position += 1;
18
18
  return new List([new Node(source.slice(position + 1, position + 2))]);
19
19
  case '\\':
@@ -23,7 +23,7 @@ export const escsource: EscapableSourceParser = context => {
23
23
  case '\n':
24
24
  return new List([new Node(char)]);
25
25
  default:
26
- consume(1, context);
26
+ spend(context, 1);
27
27
  context.position += 1;
28
28
  return new List([new Node(source.slice(position, position + 2))]);
29
29
  }
@@ -38,7 +38,7 @@ export const escsource: EscapableSourceParser = context => {
38
38
  let i = seek(source, position);
39
39
  assert(i > position);
40
40
  i -= position;
41
- consume(i - 1, context);
41
+ spend(context, i - 1);
42
42
  context.position += i - 1;
43
43
  return new List([new Node(source.slice(position, context.position))]);
44
44
  }
@@ -2,7 +2,7 @@ import { TextParser, TxtParser } from '../source';
2
2
  import { State, Command } from '../context';
3
3
  import { Flag } from '../node';
4
4
  import { List, Node } from '../../combinator/data/parser';
5
- import { union, consume } from '../../combinator';
5
+ import { union, spend } from '../../combinator';
6
6
  import { html } from 'typed-dom/dom';
7
7
 
8
8
  export const nonWhitespace = /[^ \t ]/g;
@@ -12,7 +12,7 @@ export const text: TextParser = input => {
12
12
  const { source, position, state } = context;
13
13
  if (position === source.length) return;
14
14
  const char = source[position];
15
- consume(1, context);
15
+ spend(context, 1);
16
16
  context.position += 1;
17
17
  switch (char) {
18
18
  case Command.Escape:
@@ -25,7 +25,7 @@ export const text: TextParser = input => {
25
25
  assert(char !== Command.Escape);
26
26
  return new List();
27
27
  default:
28
- consume(1, context);
28
+ spend(context, 1);
29
29
  context.position += 1;
30
30
  return new List([new Node(source.slice(position + 1, context.position))]);
31
31
  }
@@ -51,7 +51,7 @@ export const text: TextParser = input => {
51
51
  || s && source[i] === '\n';
52
52
  i -= position;
53
53
  i = lineend ? i : i - +s || 1;
54
- consume(i - 1, context);
54
+ spend(context, i - 1);
55
55
  context.position += i - 1;
56
56
  const linestart = position === 0 || source[position - 1] === '\n';
57
57
  if (position === context.position || s && !linestart || lineend) return new List();
@@ -86,7 +86,7 @@ function isWhitespace(char: string, linebreak: boolean): boolean {
86
86
  function next(source: string, position: number, state: number): number {
87
87
  let index= seek(source, position, state);
88
88
  assert(index > position);
89
- if (index === source.length) return source.length;
89
+ if (index === source.length) return index;
90
90
  const char = source[index];
91
91
  switch (char) {
92
92
  case '%':
@@ -163,10 +163,9 @@ export function backToEmailHead(source: string, position: number, index: number)
163
163
  }
164
164
  export function isAlphanumeric(char: string): boolean {
165
165
  assert(char.length === 1);
166
- if (char < '0' || '\x7F' < char) return false;
167
- return '0' <= char && char <= '9'
168
- || 'A' <= char && char <= 'Z'
169
- || 'a' <= char && char <= 'z';
166
+ if (char < '0' || 'z' < char) return false;
167
+ if (char <= '9' || 'a' <= char) return true;
168
+ return 'A' <= char && char <= 'Z';
170
169
  }
171
170
 
172
171
  function seek(source: string, position: number, state: number): number {
@@ -2,7 +2,7 @@ import { UnescapableSourceParser } from '../source';
2
2
  import { State, Command } from '../context';
3
3
  import { Flag } from '../node';
4
4
  import { List, Node } from '../../combinator/data/parser';
5
- import { consume } from '../../combinator';
5
+ import { spend } from '../../combinator';
6
6
  import { nonWhitespace, canSkip, backToUrlHead, backToEmailHead } from './text';
7
7
  import { html } from 'typed-dom/dom';
8
8
 
@@ -10,11 +10,11 @@ export const unescsource: UnescapableSourceParser = context => {
10
10
  const { source, position, state } = context;
11
11
  if (position === source.length) return;
12
12
  const char = source[position];
13
- consume(1, context);
13
+ spend(context, 1);
14
14
  context.position += 1;
15
15
  switch (char) {
16
16
  case Command.Escape:
17
- consume(1, context);
17
+ spend(context, 1);
18
18
  context.position += 1;
19
19
  return new List([new Node(source.slice(position + 1, position + 2))]);
20
20
  case '\r':
@@ -33,7 +33,7 @@ export const unescsource: UnescapableSourceParser = context => {
33
33
  : next(source, position, state);
34
34
  assert(i > position);
35
35
  i -= position;
36
- consume(i - 1, context);
36
+ spend(context, i - 1);
37
37
  context.position += i - 1;
38
38
  return new List([new Node(source.slice(position, context.position))]);
39
39
  }
@@ -42,7 +42,7 @@ export const unescsource: UnescapableSourceParser = context => {
42
42
  function next(source: string, position: number, state: number): number {
43
43
  let index= seek(source, position, state);
44
44
  assert(index > position);
45
- if (index === source.length) return source.length;
45
+ if (index === source.length) return index;
46
46
  const char = source[index];
47
47
  switch (char) {
48
48
  case ':':
@@ -119,5 +119,5 @@ function seek(source: string, position: number, state: number): number {
119
119
  }
120
120
 
121
121
  function category(char: string): boolean {
122
- return '\x21' <= char && char <= '\x7E';
122
+ return char <= '\x7E' && '\x21' <= char;
123
123
  }