securemark 0.300.6 → 0.300.8

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.300.8
4
+
5
+ - Refactoring.
6
+
7
+ ## 0.300.7
8
+
9
+ - Refactoring.
10
+
3
11
  ## 0.300.6
4
12
 
5
13
  - Refactoring.
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- /*! securemark v0.300.6 https://github.com/falsandtru/securemark | (c) 2017, falsandtru | UNLICENSED License */
1
+ /*! securemark v0.300.8 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"));
@@ -2785,7 +2785,7 @@ function* parse(source, opts = {}, options) {
2785
2785
  if (options.id?.match(/[^0-9a-z/-]/i)) throw new Error('Invalid ID: ID must be alphanumeric');
2786
2786
  if (options.host?.origin === 'null') throw new Error(`Invalid host: ${options.host.href}`);
2787
2787
  const output = new parser_1.Output();
2788
- for (const _ of (0, parser_1.run)(document_1.document, new context_1.Input(options, source), output)) yield;
2788
+ yield* (0, parser_1.run)(document_1.document, new context_1.Input(options, source), output);
2789
2789
  return output.peek().head.value;
2790
2790
  }
2791
2791
  exports.parse = parse;
@@ -6414,7 +6414,6 @@ exports.input = input;
6414
6414
  class Input extends parser_1.Input {
6415
6415
  constructor(options = {}, source) {
6416
6416
  super(options);
6417
- this.recursion = new RecursionCounter(2);
6418
6417
  const {
6419
6418
  segment,
6420
6419
  header,
@@ -6434,7 +6433,10 @@ class Input extends parser_1.Input {
6434
6433
  recursions: [
6435
6434
  // DOMの垂直的追加の繰り返しが加速的に異常に重くなる。
6436
6435
  // ブラウザの問題でありアルゴリズムの計算量は問題ない。
6437
- 10 || 0 /* Recursion.document */, 100 || 0 /* Recursion.block */, 100 || 0 /* Recursion.inline */, 100 || 0 /* Recursion.bracket */]
6436
+ // HTMLでなくDOMでレンダリングすること自体に限界があると思われる。
6437
+ 10 || 0 /* Recursion.document */,
6438
+ // スタックでも意外と低速化するため制限しておく。
6439
+ 100 || 0 /* Recursion.block */, 100 || 0 /* Recursion.inline */, 100 || 0 /* Recursion.bracket */]
6438
6440
  };
6439
6441
  this.segment = segment ?? 0 /* Segment.unknown */;
6440
6442
  this.header = header ?? true;
@@ -6449,23 +6451,6 @@ class Input extends parser_1.Input {
6449
6451
  }
6450
6452
  }
6451
6453
  exports.Input = Input;
6452
- class RecursionCounter {
6453
- constructor(limit) {
6454
- this.limit = limit;
6455
- this.stack = [];
6456
- this.index = 0;
6457
- }
6458
- add(depth) {
6459
- const {
6460
- stack
6461
- } = this;
6462
- for (; this.index > 0 && stack[this.index - 1] >= depth; --this.index);
6463
- stack[this.index] = depth;
6464
- ++this.index;
6465
- // 内側から数えるので無効化処理できない。
6466
- return this.index <= this.limit;
6467
- }
6468
- }
6469
6454
 
6470
6455
  /***/ },
6471
6456
 
@@ -6729,9 +6714,7 @@ exports.annotation = (0, combinator_1.lazy)(() => (0, combinator_1.constraint)(1
6729
6714
  const {
6730
6715
  position,
6731
6716
  linebreak,
6732
- range,
6733
- recursion,
6734
- resources
6717
+ range
6735
6718
  } = input;
6736
6719
  if (linebreak !== 0 || nodes.length === 0 || lead === 0 || follow % 2 === 0) {
6737
6720
  nodes.unshift(new parser_1.Node('('));
@@ -6741,21 +6724,21 @@ exports.annotation = (0, combinator_1.lazy)(() => (0, combinator_1.constraint)(1
6741
6724
  }, (0, dom_1.defrag)((0, util_1.unwrap)(nodes))))]);
6742
6725
  }
6743
6726
  input.position += 1;
6744
- if (!recursion.add(resources?.recursions[2 /* Recursion.inline */] ?? resources?.recursions.at(-1))) {
6745
- return new parser_1.List([new parser_1.Node((0, dom_1.html)('span', {
6746
- class: 'invalid',
6747
- ...(0, util_1.invalid)('annotation', 'syntax', 'Recursions must be two or fewer')
6748
- }, (0, dom_1.defrag)((0, util_1.unwrap)((0, visibility_1.trimBlankNodeEnd)(nodes)))))]);
6749
- }
6750
6727
  const el = (0, dom_1.html)('sup', {
6751
6728
  class: 'annotation'
6752
6729
  }, [(0, dom_1.html)('span', (0, dom_1.defrag)((0, util_1.unwrap)((0, visibility_1.trimBlankNodeEnd)(nodes))))]);
6753
6730
  for (let list = output.annotations.at(-1), node = list.last, pos = position - range, i = 0;; node = node.prev, ++i) {
6754
- if (node && node.position > pos) continue;
6755
- i === list.length ? list.unshift(new parser_1.Node(el, pos)) : list.insert(new parser_1.Node(el, pos), node?.next);
6756
- break;
6731
+ if (node && node.position > pos) {
6732
+ if (~node.flags & 2 /* Node.Flag.nested */) continue;
6733
+ return new parser_1.List([new parser_1.Node((0, dom_1.define)(el.firstElementChild, {
6734
+ class: 'invalid',
6735
+ ...(0, util_1.invalid)('annotation', 'syntax', 'Recursions must be two or fewer')
6736
+ }))]);
6737
+ }
6738
+ const flag = i === 0 ? 0 /* Node.Flag.none */ : 2 /* Node.Flag.nested */;
6739
+ i === list.length ? list.unshift(new parser_1.Node(el, pos, flag)) : list.insert(new parser_1.Node(el, pos, flag), node?.next);
6740
+ return new parser_1.List([new parser_1.Node(el)]);
6757
6741
  }
6758
- return new parser_1.List([new parser_1.Node(el)]);
6759
6742
  }, (nodes, input, output, prefix, postfix) => {
6760
6743
  for (let i = 0; i < prefix; ++i) {
6761
6744
  nodes.unshift(new parser_1.Node('('));
@@ -8690,6 +8673,7 @@ function repeat(opener, after, closer, recursion, parser, cons, termination = (n
8690
8673
  input.position += closer.length;
8691
8674
  const pos = input.position;
8692
8675
  m.follow = m.follow > 0 ? m.follow : countFollows(source, pos, closer, lead / opener.length | 0);
8676
+ input.range = input.position - m.position - m.i + opener.length;
8693
8677
  output.push(cons(output.pop(), input, output, lead, m.follow));
8694
8678
  if (input.position > pos) {
8695
8679
  const advance = input.position - pos;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "securemark",
3
- "version": "0.300.6",
3
+ "version": "0.300.8",
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",
package/src/api/parse.ts CHANGED
@@ -29,7 +29,7 @@ export function* parse(source: string, opts: Opts = {}, options?: Options): Gene
29
29
  assert(output.labels[0] = opts.labels ?? output.labels[0]);
30
30
  assert(output.annotations[0] = opts.annotations ?? output.annotations[0]);
31
31
  assert(output.references[0] = opts.references ?? output.references[0]);
32
- for (const _ of run(document, new Input(options, source), output)) yield;
32
+ yield* run(document, new Input(options, source), output);
33
33
  assert(output.data.length === 1);
34
34
  assert(output.peek().length === 1);
35
35
  return output.peek().head!.value;
@@ -159,6 +159,7 @@ export class Node<T> implements List.Node {
159
159
  export namespace Node {
160
160
  export const enum Flag {
161
161
  none,
162
- blank,
162
+ blank = 1 << 0,
163
+ nested = 1 << 1,
163
164
  }
164
165
  }
@@ -30,7 +30,9 @@ export class Input<M extends object = object> extends Ipt<M> {
30
30
  recursions: [
31
31
  // DOMの垂直的追加の繰り返しが加速的に異常に重くなる。
32
32
  // ブラウザの問題でありアルゴリズムの計算量は問題ない。
33
+ // HTMLでなくDOMでレンダリングすること自体に限界があると思われる。
33
34
  10 || Recursion.document,
35
+ // スタックでも意外と低速化するため制限しておく。
34
36
  100 || Recursion.block,
35
37
  100 || Recursion.inline,
36
38
  100 || Recursion.bracket,
@@ -56,7 +58,6 @@ export class Input<M extends object = object> extends Ipt<M> {
56
58
  public header: boolean;
57
59
  public local: boolean;
58
60
  public whitespace: boolean;
59
- public recursion = new RecursionCounter(2);
60
61
  public readonly host?: URL;
61
62
  public readonly url?: URL;
62
63
  public id?: string;
@@ -72,23 +73,6 @@ export class Input<M extends object = object> extends Ipt<M> {
72
73
  }
73
74
  export type Options = Partial<Input>;
74
75
 
75
- class RecursionCounter {
76
- constructor(
77
- private readonly limit: number,
78
- ) {
79
- }
80
- private readonly stack: number[] = [];
81
- private index = 0;
82
- public add(depth: number): boolean {
83
- const { stack } = this
84
- for (; this.index > 0 && stack[this.index - 1] >= depth; --this.index);
85
- stack[this.index] = depth;
86
- ++this.index;
87
- // 内側から数えるので無効化処理できない。
88
- return this.index <= this.limit;
89
- }
90
- }
91
-
92
76
  export const enum Segment {
93
77
  unknown = 0,
94
78
  read = 0,
@@ -86,6 +86,9 @@ describe('Unit: parser/inline/annotation', () => {
86
86
  assert.deepStrictEqual(
87
87
  inspect(parser, input(`${'(('.repeat(3)}0))((1))))))`)),
88
88
  [['<span class="invalid"><sup class="annotation"><span><sup class="annotation"><span>0</span></sup><sup class="annotation"><span>1</span></sup></span></sup></span>'], '']);
89
+ assert.deepStrictEqual(
90
+ inspect(parser, input(`${'(0'.repeat(4)}((0${'))'.repeat(3)}${'(('.repeat(2)}0${'))'.repeat(2)}`)),
91
+ [['<span class="paren">(0<span class="paren">(0<span class="paren">(0<span class="paren">(0<sup class="annotation"><span>0</span></sup>)</span>)</span>)</span>)</span>', '<sup class="annotation"><span><sup class="annotation"><span>0</span></sup></span></sup>'], '']);
89
92
  });
90
93
 
91
94
  });
@@ -7,7 +7,7 @@ import { bracketname } from './bracket';
7
7
  import { repeat } from '../repeat';
8
8
  import { beforeNonblank, trimBlankNodeEnd } from '../visibility';
9
9
  import { unwrap, invalid } from '../util';
10
- import { html, defrag } from 'typed-dom/dom';
10
+ import { html, define, defrag } from 'typed-dom/dom';
11
11
 
12
12
  // シグネチャ等生成のために構文木のツリーウォークを再帰的に行い指数計算量にならないよう
13
13
  // 動的計画法を適用するか再帰数を制限する必要がある。
@@ -32,7 +32,7 @@ export const annotation: AnnotationParser = lazy(() => constraint(State.annotati
32
32
  ([, bs], _, output) => output.import(bs),
33
33
  ([, bs], _, output) => bs && output.import(bs.push(new Node(Command.Cancel)))))),
34
34
  (nodes, input, output, lead, follow) => {
35
- const { position, linebreak, range, recursion, resources } = input;
35
+ const { position, linebreak, range } = input;
36
36
  if (linebreak !== 0 || nodes.length === 0 || lead === 0 || follow % 2 === 0) {
37
37
  nodes.unshift(new Node('('));
38
38
  nodes.push(new Node(')'));
@@ -41,25 +41,26 @@ export const annotation: AnnotationParser = lazy(() => constraint(State.annotati
41
41
  ]);
42
42
  }
43
43
  input.position += 1;
44
- if (!recursion.add(resources?.recursions[Recursion.inline] ?? resources?.recursions.at(-1))) {
45
- return new List([new Node(html('span',
46
- {
47
- class: 'invalid',
48
- ...invalid('annotation', 'syntax', 'Recursions must be two or fewer')
49
- },
50
- defrag(unwrap(trimBlankNodeEnd(nodes)))))]);
51
- }
52
44
  const el = html('sup', { class: 'annotation' }, [
53
45
  html('span', defrag(unwrap(trimBlankNodeEnd(nodes))))
54
46
  ]);
55
47
  for (let list = output.annotations.at(-1)!, node = list.last, pos = position - range, i = 0; ; node = node!.prev, ++i) {
56
- if (node && node.position > pos) continue;
48
+ if (node && node.position > pos) {
49
+ if (~node.flags & Node.Flag.nested) continue;
50
+ return new List([
51
+ new Node(define(el.firstElementChild as HTMLElement,
52
+ {
53
+ class: 'invalid',
54
+ ...invalid('annotation', 'syntax', 'Recursions must be two or fewer')
55
+ }))
56
+ ]);
57
+ }
58
+ const flag = i === 0 ? Node.Flag.none : Node.Flag.nested;
57
59
  i === list.length
58
- ? list.unshift(new Node(el, pos))
59
- : list.insert(new Node(el, pos), node?.next);
60
- break;
60
+ ? list.unshift(new Node(el, pos, flag))
61
+ : list.insert(new Node(el, pos, flag), node?.next);
62
+ return new List([new Node(el)]);
61
63
  }
62
- return new List([new Node(el)]);
63
64
  },
64
65
  (nodes, input, output, prefix, postfix) => {
65
66
  assert(postfix === 0);
@@ -93,6 +93,7 @@ export function repeat<T extends HTMLElement | string>(
93
93
  input.position += closer.length;
94
94
  const pos = input.position;
95
95
  m.follow = m.follow > 0 ? m.follow : countFollows(source, pos, closer, lead / opener.length | 0);
96
+ input.range = input.position - m.position - m.i + opener.length;
96
97
  output.push(cons(output.pop(), input, output, lead, m.follow));
97
98
  if (input.position > pos) {
98
99
  const advance = input.position - pos;