securemark 0.297.4 → 0.297.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.
@@ -307,7 +307,7 @@ describe('Unit: parser/api/parse', () => {
307
307
  // ]);
308
308
  assert.deepStrictEqual(
309
309
  [...parse(`${'('.repeat(20)}0`).children].map(el => el.outerHTML),
310
- [`<p>${'<span class="paren">('.repeat(19)}(0${'</span>'.repeat(19)}</p>`]);
310
+ [`<p>${'<span class="bracket">('.repeat(19)}(0${'</span>'.repeat(19)}</p>`]);
311
311
  assert.deepStrictEqual(
312
312
  [...parse(`${'('.repeat(21)}0`).children].map(el => el.outerHTML.replace(/:\w+/, ':rnd')),
313
313
  [
@@ -323,6 +323,42 @@ describe('Unit: parser/api/parse', () => {
323
323
  '<h1 id="error:rnd" class="error">Error: Too much recursion</h1>',
324
324
  `<pre class="error" translate="no">${'['.repeat(21)}0</pre>`,
325
325
  ]);
326
+ assert.deepStrictEqual(
327
+ [...parse(`${'(('.repeat(2)}0${'))'.repeat(2)}`).children].map(el => el.tagName),
328
+ ['P', 'OL']);
329
+ assert.deepStrictEqual(
330
+ [...parse(`${'(('.repeat(3)}0${'))'.repeat(3)}`).children].map(el => el.tagName),
331
+ ['H1', 'PRE']);
332
+ assert.deepStrictEqual(
333
+ [...parse(`${'(('.repeat(2)}!${'))'.repeat(2)}`).children].map(el => el.tagName),
334
+ ['P', 'OL']);
335
+ assert.deepStrictEqual(
336
+ [...parse(`${'(('.repeat(3)}!${'))'.repeat(3)}`).children].map(el => el.tagName),
337
+ ['H1', 'PRE']);
338
+ assert.deepStrictEqual(
339
+ [...parse(`(${'(('.repeat(2)}0${'))'.repeat(2)}`).children].map(el => el.tagName),
340
+ ['P', 'OL']);
341
+ assert.deepStrictEqual(
342
+ [...parse(`(${'(('.repeat(3)}0${'))'.repeat(3)}`).children].map(el => el.tagName),
343
+ ['H1', 'PRE']);
344
+ assert.deepStrictEqual(
345
+ [...parse(`(${'(('.repeat(2)}!${'))'.repeat(2)}`).children].map(el => el.tagName),
346
+ ['P', 'OL']);
347
+ assert.deepStrictEqual(
348
+ [...parse(`(${'(('.repeat(3)}!${'))'.repeat(3)}`).children].map(el => el.tagName),
349
+ ['H1', 'PRE']);
350
+ assert.deepStrictEqual(
351
+ [...parse(`${'(('.repeat(2)}0${'))'.repeat(2)}${'(('.repeat(2)}0${'))'.repeat(2)}`).children].map(el => el.tagName),
352
+ ['P', 'OL']);
353
+ assert.deepStrictEqual(
354
+ [...parse(`${'(('.repeat(2)}0${'))'.repeat(2)}${'(('.repeat(3)}0${'))'.repeat(3)}`).children].map(el => el.tagName),
355
+ ['H1', 'PRE']);
356
+ assert.deepStrictEqual(
357
+ [...parse(`${'(('.repeat(2)}0${'))'.repeat(2)}${'(('.repeat(9)}0${'))'.repeat(2)}`).children].map(el => el.tagName),
358
+ ['P', 'OL']);
359
+ assert.deepStrictEqual(
360
+ [...parse(`${'(('.repeat(2)}0${'))'.repeat(2)}${'(('.repeat(9)}0${'))'.repeat(3)}`).children].map(el => el.tagName),
361
+ ['H1', 'PRE']);
326
362
  });
327
363
 
328
364
  it('recovery', () => {
@@ -18,7 +18,7 @@ export const blockquote: BlockquoteParser = lazy(() => block(rewrite(segment, un
18
18
  ]))));
19
19
 
20
20
  const opener = /(?=>>+(?:$|[ \n]))/y;
21
- const indent = block(open(opener, some(contentline, />(?:$|[ \n])/y)), false);
21
+ const indent = open(opener, some(contentline, />(?:$|[ \n])/y));
22
22
  const unindent = (source: string) => source.replace(/(?<=^|\n)>(?: |(?=>*(?:$|[ \n])))|\n$/g, '');
23
23
 
24
24
  const source: BlockquoteParser.SourceParser = lazy(() => fmap(
@@ -44,8 +44,8 @@ describe('Unit: parser/block/heading', () => {
44
44
  assert.deepStrictEqual(inspect(parser, input('## http://host', new Context())), [['<h2 id="index::http://host"><a class="url" href="http://host" target="_blank">http://host</a></h2>'], '']);
45
45
  assert.deepStrictEqual(inspect(parser, input('# !http://host', new Context())), [['<h1 id="index::!http://host">!http://host</h1>'], '']);
46
46
  assert.deepStrictEqual(inspect(parser, input('## !http://host', new Context())), [['<h2 id="index::!http://host">!<a class="url" href="http://host" target="_blank">http://host</a></h2>'], '']);
47
- assert.deepStrictEqual(inspect(parser, input('# a((b))', new Context())), [['<h1 id="index::a((b))">a<span class="paren">((b))</span></h1>'], '']);
48
- assert.deepStrictEqual(inspect(parser, input('## a((b))', new Context())), [['<h2 id="index::a((b))">a<span class="paren">((b))</span></h2>'], '']);
47
+ assert.deepStrictEqual(inspect(parser, input('# a((b))', new Context())), [['<h1 id="index::a((b))">a<span class="bracket">(<span class="paren">(b)</span>)</span></h1>'], '']);
48
+ assert.deepStrictEqual(inspect(parser, input('## a((b))', new Context())), [['<h2 id="index::a((b))">a<span class="bracket">(<span class="paren">(b)</span>)</span></h2>'], '']);
49
49
  assert.deepStrictEqual(inspect(parser, input('# a[[b]]', new Context())), [['<h1 id="index::a[[b]]">a[[b]]</h1>'], '']);
50
50
  assert.deepStrictEqual(inspect(parser, input('## a[[b]]', new Context())), [['<h2 id="index::a[[b]]">a[[b]]</h2>'], '']);
51
51
  assert.deepStrictEqual(inspect(parser, input('###### a', new Context())), [['<h6 id="index::a">a</h6>'], '']);
@@ -1,7 +1,7 @@
1
1
  import { SidefenceParser } from '../block';
2
2
  import { Recursion } from '../context';
3
3
  import { List, Node } from '../../combinator/data/parser';
4
- import { union, some, recursion, block, focus, rewrite, convert, lazy, fmap } from '../../combinator';
4
+ import { union, some, recursion, block, focus, rewrite, open, convert, lazy, fmap } from '../../combinator';
5
5
  import { autolink } from '../autolink';
6
6
  import { contentline } from '../source';
7
7
  import { unwrap, invalid } from '../util';
@@ -18,12 +18,13 @@ export const sidefence: SidefenceParser = lazy(() => block(fmap(focus(
18
18
  ]))));
19
19
 
20
20
  const opener = /(?=\|\|+(?:$|[ \n]))/y;
21
+ const indent = open(opener, some(contentline, /\|(?:$|[ \n])/y));
21
22
  const unindent = (source: string) => source.replace(/(?<=^|\n)\|(?: |(?=\|*(?:$|[ \n])))|\n$/g, '');
22
23
 
23
24
  const source: SidefenceParser.SourceParser = lazy(() => fmap(
24
25
  recursion(Recursion.block, some(union([
25
- focus(
26
- /(?:\|\|+(?=$|[ \n])[^\n]*(?:$|\n))+/y,
26
+ rewrite(
27
+ indent,
27
28
  convert(unindent, source, true)),
28
29
  rewrite(
29
30
  some(contentline, opener),
@@ -15,6 +15,7 @@ describe('Unit: parser/block/table', () => {
15
15
  assert.deepStrictEqual(inspect(parser, input('||', new Context())), undefined);
16
16
  assert.deepStrictEqual(inspect(parser, input('|||', new Context())), undefined);
17
17
  assert.deepStrictEqual(inspect(parser, input('|\n|', new Context())), undefined);
18
+ assert.deepStrictEqual(inspect(parser, input('|\n|\n|', new Context())), undefined);
18
19
  assert.deepStrictEqual(inspect(parser, input('|h', new Context())), undefined);
19
20
  assert.deepStrictEqual(inspect(parser, input('|h', new Context())), undefined);
20
21
  assert.deepStrictEqual(inspect(parser, input('|h\n', new Context())), undefined);
@@ -27,13 +28,12 @@ describe('Unit: parser/block/table', () => {
27
28
  });
28
29
 
29
30
  it('valid', () => {
30
- assert.deepStrictEqual(inspect(parser, input('|\n|\n|', new Context())), [['<table><thead><tr></tr></thead><tbody><tr class="invalid"><td>|</td></tr><tr></tr></tbody></table>'], '']);
31
31
  assert.deepStrictEqual(inspect(parser, input('|\n|-\n|', new Context())), [['<table><thead><tr></tr></thead><tbody><tr></tr></tbody></table>'], '']);
32
32
  assert.deepStrictEqual(inspect(parser, input('||\n|-|\n||', new Context())), [['<table><thead><tr><th></th></tr></thead><tbody><tr><td></td></tr></tbody></table>'], '']);
33
33
  assert.deepStrictEqual(inspect(parser, input('|||\n|-|-|\n|||', new Context())), [['<table><thead><tr><th></th><th></th></tr></thead><tbody><tr><td></td><td></td></tr></tbody></table>'], '']);
34
34
  assert.deepStrictEqual(inspect(parser, input('|"|\n|-\n|', new Context())), [['<table><thead><tr><th>"</th></tr></thead><tbody><tr></tr></tbody></table>'], '']);
35
35
  assert.deepStrictEqual(inspect(parser, input('|`|`|\n|-\n|', new Context())), [['<table><thead><tr><th><code data-src="`|`">|</code></th></tr></thead><tbody><tr></tr></tbody></table>'], '']);
36
- assert.deepStrictEqual(inspect(parser, input('|((|\n|-\n|', new Context())), [['<table><thead><tr><th><span class="paren">(<span class="paren">(</span></span></th></tr></thead><tbody><tr></tr></tbody></table>'], '']);
36
+ assert.deepStrictEqual(inspect(parser, input('|((|\n|-\n|', new Context())), [['<table><thead><tr><th><span class="bracket">(<span class="bracket">(</span></span></th></tr></thead><tbody><tr></tr></tbody></table>'], '']);
37
37
  assert.deepStrictEqual(inspect(parser, input('|a|b|\n|-|-|\n|1|2|', new Context())), [['<table><thead><tr><th>a</th><th>b</th></tr></thead><tbody><tr><td>1</td><td>2</td></tr></tbody></table>'], '']);
38
38
  assert.deepStrictEqual(inspect(parser, input('|a|b\n|-|-\n|1|2', new Context())), [['<table><thead><tr><th>a</th><th>b</th></tr></thead><tbody><tr><td>1</td><td>2</td></tr></tbody></table>'], '']);
39
39
  assert.deepStrictEqual(inspect(parser, input('|a|\n|-|\n|1|', new Context())), [['<table><thead><tr><th>a</th></tr></thead><tbody><tr><td>1</td></tr></tbody></table>'], '']);
@@ -14,7 +14,7 @@ import AlignParser = TableParser.AlignParser;
14
14
  import CellParser = TableParser.CellParser;
15
15
 
16
16
  export const table: TableParser = lazy(() => block(fmap(validate(
17
- /\|[^\n]*(?:\n\|[^\n]*){2}/y,
17
+ /\|[^\n]*\n\|[-:][^\n]*\n\|/y,
18
18
  sequence([
19
19
  row(some(head), true),
20
20
  row(some(align), false),
@@ -49,10 +49,11 @@ export const block: BlockParser = reset(
49
49
  // バックトラックのせいで文字数制限を受けないようにする。
50
50
  clock: MAX_SEGMENT_SIZE * 6 + 1,
51
51
  recursions: [
52
- 10 || Recursion.block,
52
+ 5 || Recursion.block,
53
53
  20 || Recursion.blockquote,
54
54
  40 || Recursion.listitem,
55
55
  20 || Recursion.inline,
56
+ 20 || Recursion.annotation,
56
57
  20 || Recursion.bracket,
57
58
  20 || Recursion.terminal,
58
59
  ],
@@ -28,6 +28,7 @@ export class Context extends Ctx {
28
28
  public override segment: Segment;
29
29
  public buffer: List<Node<(string | HTMLElement)>>;
30
30
  public sequential: boolean;
31
+ public recursion = new RecursionCounter('annotation', 2);
31
32
  public readonly header: boolean;
32
33
  public readonly host?: URL;
33
34
  public readonly url?: URL;
@@ -40,6 +41,24 @@ export class Context extends Ctx {
40
41
  }
41
42
  export type Options = Partial<Context>;
42
43
 
44
+ class RecursionCounter {
45
+ constructor(
46
+ private readonly syntax: string,
47
+ private readonly limit: number,
48
+ ) {
49
+ }
50
+ private readonly stack: number[] = [];
51
+ private index = 0;
52
+ public add(depth: number): void {
53
+ const { stack } = this
54
+ for (; this.index > 0 && stack[this.index - 1] <= depth; --this.index);
55
+ // 内側から数えるので無効化処理できずエラーを投げるしかない。
56
+ if (this.index === this.limit) throw new Error(`Too much ${this.syntax} recursion`);
57
+ stack[this.index] = depth;
58
+ ++this.index;
59
+ }
60
+ }
61
+
43
62
  export const enum Segment {
44
63
  unknown = 0,
45
64
  write = 1,
@@ -70,11 +89,11 @@ export const enum State {
70
89
  }
71
90
 
72
91
  export const enum Recursion {
73
- //ignore,
74
- block = 1,
92
+ block,
75
93
  blockquote,
76
94
  listitem,
77
95
  inline,
96
+ annotation,
78
97
  bracket,
79
98
  terminal,
80
99
  }
@@ -13,11 +13,11 @@ describe('Unit: parser/inline/annotation', () => {
13
13
  assert.deepStrictEqual(inspect(parser, input('(', new Context())), undefined);
14
14
  assert.deepStrictEqual(inspect(parser, input('()', new Context())), undefined);
15
15
  assert.deepStrictEqual(inspect(parser, input('((', new Context())), undefined);
16
- assert.deepStrictEqual(inspect(parser, input('(())', new Context())), [['<span class="paren">(<span class="paren">(</span></span>'], '))']);
17
- assert.deepStrictEqual(inspect(parser, input('(()))', new Context())), [['<span class="paren">(<span class="paren">(</span></span>'], ')))']);
18
- assert.deepStrictEqual(inspect(parser, input('(("))', new Context())), [['<span class="paren">(<span class="paren">("))</span></span>'], '']);
19
- assert.deepStrictEqual(inspect(parser, input('(([))', new Context())), [['<span class="paren">(<span class="paren">([))</span></span>'], '']);
20
- assert.deepStrictEqual(inspect(parser, input('(([%))', new Context())), [['<span class="paren">(<span class="paren">([%))</span></span>'], '']);
16
+ assert.deepStrictEqual(inspect(parser, input('(())', new Context())), [['<span class="bracket">(<span class="bracket">(</span></span>'], '))']);
17
+ assert.deepStrictEqual(inspect(parser, input('(()))', new Context())), [['<span class="bracket">(<span class="bracket">(</span></span>'], ')))']);
18
+ assert.deepStrictEqual(inspect(parser, input('(("))', new Context())), [['<span class="bracket">(<span class="bracket">("))</span></span>'], '']);
19
+ assert.deepStrictEqual(inspect(parser, input('(([))', new Context())), [['<span class="bracket">(<span class="bracket">([))</span></span>'], '']);
20
+ assert.deepStrictEqual(inspect(parser, input('(([%))', new Context())), [['<span class="bracket">(<span class="bracket">([%))</span></span>'], '']);
21
21
  assert.deepStrictEqual(inspect(parser, input('(( ))', new Context())), undefined);
22
22
  assert.deepStrictEqual(inspect(parser, input('(( a))', new Context())), undefined);
23
23
  assert.deepStrictEqual(inspect(parser, input('(( a ))', new Context())), undefined);
@@ -26,16 +26,20 @@ describe('Unit: parser/inline/annotation', () => {
26
26
  assert.deepStrictEqual(inspect(parser, input('((\n))', new Context())), undefined);
27
27
  assert.deepStrictEqual(inspect(parser, input('((\na))', new Context())), undefined);
28
28
  assert.deepStrictEqual(inspect(parser, input('((\\\na))', new Context())), undefined);
29
- assert.deepStrictEqual(inspect(parser, input('((a\n))', new Context())), [['<span class="paren">(<span class="paren">(a<br>)</span>)</span>'], '']);
30
- assert.deepStrictEqual(inspect(parser, input('((a\\\n))', new Context())), [['<span class="paren">(<span class="paren">(a<br>)</span>)</span>'], '']);
31
- assert.deepStrictEqual(inspect(parser, input('((a\nb))', new Context())), [['<span class="paren">(<span class="paren">(a<br>b)</span>)</span>'], '']);
32
- assert.deepStrictEqual(inspect(parser, input('((a\\\nb))', new Context())), [['<span class="paren">(<span class="paren">(a<br>b)</span>)</span>'], '']);
33
- assert.deepStrictEqual(inspect(parser, input('((*a\nb*))', new Context())), [['<span class="paren">(<span class="paren">(<em>a<br>b</em>)</span>)</span>'], '']);
34
- assert.deepStrictEqual(inspect(parser, input('((\\))', new Context())), [['<span class="paren">(<span class="paren">()</span></span>'], ')']);
35
- assert.deepStrictEqual(inspect(parser, input('((a)b))', new Context())), [['<span class="paren">((a</span>'], ')b))']);
36
- assert.deepStrictEqual(inspect(parser, input('((!)b))', new Context())), [['<span class="paren">(<span class="paren">(!</span></span>'], ')b))']);
37
- assert.deepStrictEqual(inspect(parser, input('(((a))', new Context())), [['<span class="paren">(<sup class="annotation"><span>a</span></sup></span>'], '']);
38
- assert.deepStrictEqual(inspect(parser, input('(((!))', new Context())), [['<span class="paren">(<sup class="annotation"><span>!</span></sup></span>'], '']);
29
+ assert.deepStrictEqual(inspect(parser, input('((a\n))', new Context())), [['<span class="bracket">(<span class="bracket">(a<br>)</span>)</span>'], '']);
30
+ assert.deepStrictEqual(inspect(parser, input('((a\\\n))', new Context())), [['<span class="bracket">(<span class="bracket">(a<br>)</span>)</span>'], '']);
31
+ assert.deepStrictEqual(inspect(parser, input('((a\nb))', new Context())), [['<span class="bracket">(<span class="bracket">(a<br>b)</span>)</span>'], '']);
32
+ assert.deepStrictEqual(inspect(parser, input('((a\\\nb))', new Context())), [['<span class="bracket">(<span class="bracket">(a<br>b)</span>)</span>'], '']);
33
+ assert.deepStrictEqual(inspect(parser, input('((*a\nb*))', new Context())), [['<span class="bracket">(<span class="bracket">(<em>a<br>b</em>)</span>)</span>'], '']);
34
+ assert.deepStrictEqual(inspect(parser, input('((\\))', new Context())), [['<span class="bracket">(<span class="bracket">()</span></span>'], ')']);
35
+ assert.deepStrictEqual(inspect(parser, input('((a)b))', new Context())), [['<span class="bracket">((a</span>'], ')b))']);
36
+ assert.deepStrictEqual(inspect(parser, input('((!)b))', new Context())), [['<span class="bracket">(<span class="bracket">(!</span></span>'], ')b))']);
37
+ assert.deepStrictEqual(inspect(parser, input('(((a))', new Context())), [['<span class="bracket">(<sup class="annotation"><span>a</span></sup></span>'], '']);
38
+ assert.deepStrictEqual(inspect(parser, input('(((!))', new Context())), [['<span class="bracket">(<sup class="annotation"><span>!</span></sup></span>'], '']);
39
+ assert.deepStrictEqual(inspect(parser, input('(((*a*))', new Context())), [['<span class="bracket">(<sup class="annotation"><span><em>a</em></span></sup></span>'], '']);
40
+ assert.deepStrictEqual(inspect(parser, input('(((((a))))', new Context())), [['<span class="bracket">(<sup class="annotation"><span><sup class="annotation"><span>a</span></sup></span></sup></span>'], '']);
41
+ assert.deepStrictEqual(inspect(parser, input('(((((!))))', new Context())), [['<span class="bracket">(<sup class="annotation"><span><sup class="annotation"><span>!</span></sup></span></sup></span>'], '']);
42
+ assert.deepStrictEqual(inspect(parser, input('(((((*a*))))', new Context())), [['<span class="bracket">(<sup class="annotation"><span><sup class="annotation"><span><em>a</em></span></sup></span></sup></span>'], '']);
39
43
  assert.deepStrictEqual(inspect(parser, input(' ((a))', new Context())), undefined);
40
44
  });
41
45
 
@@ -54,7 +58,7 @@ describe('Unit: parser/inline/annotation', () => {
54
58
  assert.deepStrictEqual(inspect(parser, input('((http://host))', new Context())), [['<sup class="annotation"><span><a class="url" href="http://host" target="_blank">http://host</a></span></sup>'], '']);
55
59
  assert.deepStrictEqual(inspect(parser, input('((![]{a}))', new Context())), [['<sup class="annotation"><span>!<a class="url" href="a">a</a></span></sup>'], '']);
56
60
  assert.deepStrictEqual(inspect(parser, input('(([[a] ]))', new Context())), [['<sup class="annotation"><span>[[a] ]</span></sup>'], '']);
57
- assert.deepStrictEqual(inspect(parser, input('(((a)))', new Context())), [['<sup class="annotation"><span>(a)</span></sup>'], '']);
61
+ assert.deepStrictEqual(inspect(parser, input('(((a)))', new Context())), [['<sup class="annotation"><span><span class="paren">(a)</span></span></sup>'], '']);
58
62
  assert.deepStrictEqual(inspect(parser, input('((((a))))', new Context())), [['<sup class="annotation"><span><sup class="annotation"><span>a</span></sup></span></sup>'], '']);
59
63
  assert.deepStrictEqual(inspect(parser, input('(([[a]]))', new Context())), [['<sup class="annotation"><span><sup class="reference"><span>a</span></sup></span></sup>'], '']);
60
64
  });
@@ -1,57 +1,107 @@
1
1
  import { AnnotationParser } from '../inline';
2
2
  import { State, Recursion } from '../context';
3
3
  import { List, Node } from '../../combinator/data/parser';
4
- import { union, some, recursion, precedence, constraint, surround, open, lazy } from '../../combinator';
4
+ import { union, some, recursions, precedence, constraint, surround, open, lazy } from '../../combinator';
5
5
  import { inline } from '../inline';
6
6
  import { indexA } from './bracket';
7
7
  import { beforeNonblank, trimBlankNodeEnd } from '../visibility';
8
8
  import { unwrap } from '../util';
9
9
  import { html, defrag } from 'typed-dom/dom';
10
10
 
11
+ // シグネチャ等生成のために構文木のツリーウォークを再帰的に行い指数計算量にならないよう
12
+ // 動的計画法を適用するか再帰数を制限する必要がある。
13
+ // 動的計画法においては再帰的記録により指数空間計算量にならないよう下位の記録を消しながら記録しなければならない。
14
+ // トリムも再帰的に行わないよう前後のトリムサイズの記録を要する。
15
+ // しかし理論的には無制限の再帰が可能だがホバーテキストの記録やハッシュの計算を行う言語仕様から指数計算量を
16
+ // 避けられないためAnnotation構文に限り再帰数の制限が必要となる。
17
+ // シグネチャやハッシュは分割計算可能にすれば解決するがホバーテキストは記録せず動的に再計算して
18
+ // 表示しなければ指数空間計算量を避けられない。
19
+ // 注釈を除外すると重複排除により参照元が消滅し欠番が生じるため少なくとも直接注釈は残す必要があるが間接注釈は
20
+ // 除外できる。しかしこれを効率的に行うことは難しいため最大再帰数を1回に制限することで間接注釈を行えない
21
+ // ようにするのが合理的だろう。
22
+ // 原理的には逆順処理により圧縮後正順で再附番すればすべて解決するはずだがテキストとシグネチャとハッシュも
23
+ // 修正する必要があるためほぼ完全な二重処理が必要になり三重以上の注釈という不適切な使用のために
24
+ // 常に非常に非効率な処理を行い常時低速化するより三重以上の注釈を禁止して効率性を維持するのが妥当である。
25
+ const MAX_DEPTH = 20;
11
26
  export const annotation: AnnotationParser = lazy(() => constraint(State.annotation, surround(
12
27
  open('((', beforeNonblank),
13
- precedence(1, recursion(Recursion.inline, recursion(Recursion.bracket, recursion(Recursion.bracket,
14
- some(union([inline]), ')', [[')', 1]]))))),
28
+ precedence(1, recursions([Recursion.annotation, Recursion.inline, Recursion.bracket, Recursion.bracket],
29
+ some(union([inline]), ')', [[')', 1]]))),
15
30
  '))',
16
31
  false, [],
17
32
  ([, ns], context) => {
18
- const { linebreak } = context;
33
+ const { linebreak, recursion, resources } = context;
34
+ const depth = MAX_DEPTH - (resources?.recursions[Recursion.annotation] ?? resources?.recursions.at(-1) ?? MAX_DEPTH);
19
35
  if (linebreak === 0) {
36
+ recursion.add(depth);
20
37
  return new List([new Node(html('sup', { class: 'annotation' }, [html('span', defrag(unwrap(trimBlankNodeEnd(ns))))]))]);
21
38
  }
22
39
  ns.unshift(new Node('('));
23
40
  ns.push(new Node(')'));
24
- return new List([new Node(html('span', { class: 'paren' }, ['(', html('span', { class: 'paren' }, defrag(unwrap(ns))), ')']))]);
41
+ return new List([new Node(html('span', { class: 'bracket' }, ['(', html('span', { class: 'bracket' }, defrag(unwrap(ns))), ')']))]);
25
42
  },
26
43
  ([, bs = new List()], context) => {
27
- const { source, position, range, linebreak } = context;
28
- if (linebreak === 0 && bs.length === 1 && source[position] === ')' && typeof bs.head?.value === 'object' && bs.head.value.className === 'paren') {
29
- const { firstChild, lastChild } = bs.head.value;
30
- assert(firstChild instanceof Text);
31
- if (firstChild!.nodeValue!.length === 1) {
32
- firstChild!.remove();
44
+ const { source, position, range, linebreak, recursion, resources } = context;
45
+ const depth = MAX_DEPTH - (resources?.recursions[Recursion.annotation] ?? resources?.recursions.at(-1) ?? MAX_DEPTH);
46
+ if (linebreak === 0 && bs.length === 1 && source[position] === ')' && typeof bs.head?.value === 'object') {
47
+ const { className } = bs.head.value;
48
+ if (className === 'paren' || className === 'bracket') {
49
+ const { firstChild, lastChild } = bs.head.value;
50
+ assert(firstChild instanceof Text);
51
+ if (firstChild!.nodeValue!.length === 1) {
52
+ firstChild!.remove();
53
+ }
54
+ else {
55
+ firstChild!.nodeValue = firstChild!.nodeValue!.slice(1);
56
+ }
57
+ assert(lastChild instanceof Text);
58
+ if (lastChild!.nodeValue!.length === 1) {
59
+ lastChild!.remove();
60
+ }
61
+ else {
62
+ lastChild!.nodeValue = lastChild!.nodeValue!.slice(0, -1);
63
+ }
64
+ context.position += 1;
65
+ recursion.add(depth);
66
+ return new List([new Node(html('span', { class: 'bracket' }, ['(', html('sup', { class: 'annotation' }, [html('span', bs.head.value.childNodes)])]))]);
33
67
  }
34
- else {
35
- firstChild!.nodeValue = firstChild!.nodeValue!.slice(1);
68
+ if (className === 'annotation' && deepunwrap(bs)) {
69
+ context.position += 1;
70
+ recursion.add(depth);
71
+ return new List([new Node(html('span', { class: 'bracket' }, ['(', html('sup', { class: 'annotation' }, [html('span', [bs.head.value])])]))]);
36
72
  }
37
- assert(lastChild instanceof Text);
38
- if (lastChild!.nodeValue!.length === 1) {
39
- lastChild!.remove();
40
- }
41
- else {
42
- lastChild!.nodeValue = lastChild!.nodeValue!.slice(0, -1);
43
- }
44
- context.position += 1;
45
- return new List([new Node(html('span', { class: 'paren' }, ['(', html('sup', { class: 'annotation' }, [html('span', bs.head.value.childNodes)])]))]);
46
- }
47
- if (linebreak === 0 && bs.length === 3 && source[position - range + 2] === '(' && source[position] === ')' && source[position - 1] === ')' && source[position - 2] !== '\\') {
48
- context.position += 1;
49
- return new List([new Node(html('span', { class: 'paren' }, ['(', html('sup', { class: 'annotation' }, [html('span', [bs.head!.next!.value])])]))]);
50
73
  }
51
74
  const str = linebreak === 0 ? source.slice(position - range + 2, position) : '';
52
75
  if (linebreak === 0 && indexA.test(str)) {
53
- return new List([new Node(html('span', { class: 'paren' }, ['((' + str]))]);
76
+ return new List([new Node(html('span', { class: 'bracket' }, ['((' + str]))]);
54
77
  }
55
78
  bs.unshift(new Node('('));
56
- return new List([new Node(html('span', { class: 'paren' }, ['(', html('span', { class: 'paren' }, defrag(unwrap(bs)))]))]);
79
+ return new List([new Node(html('span', { class: 'bracket' }, ['(', html('span', { class: 'bracket' }, defrag(unwrap(bs)))]))]);
57
80
  })));
81
+
82
+ function deepunwrap(list: List<Node<string | HTMLElement>>): boolean {
83
+ let bottom = list.head!.value as HTMLElement;
84
+ for (; bottom;) {
85
+ const el = bottom.firstChild!.firstChild;
86
+ if (el !== el?.parentNode?.lastChild) break;
87
+ if (el instanceof HTMLElement === false) break;
88
+ if (el?.className !== 'annotation') break;
89
+ bottom = el;
90
+ }
91
+ const el = bottom.firstChild!.firstChild;
92
+ if (el instanceof Element === false) return false;
93
+ if (el === el?.parentNode?.lastChild) {
94
+ const { className, firstChild, lastChild } = el;
95
+ if (className === 'paren' || className === 'bracket') {
96
+ firstChild!.nodeValue!.length === 1
97
+ ? firstChild!.remove()
98
+ : firstChild!.nodeValue = firstChild!.nodeValue!.slice(1);
99
+ lastChild!.nodeValue!.length === 1
100
+ ? lastChild!.remove()
101
+ : lastChild!.nodeValue = lastChild!.nodeValue!.slice(0, -1);
102
+ el.replaceWith(...el.childNodes);
103
+ return true;
104
+ }
105
+ }
106
+ return false;
107
+ }
@@ -9,51 +9,51 @@ describe('Unit: parser/inline/bracket', () => {
9
9
  const parser = some(bracket);
10
10
 
11
11
  it('(', () => {
12
- assert.deepStrictEqual(inspect(parser, input('(', new Context())), [['<span class="paren">(</span>'], '']);
13
- assert.deepStrictEqual(inspect(parser, input('()', new Context())), [['<span class="paren">()</span>'], '']);
14
- assert.deepStrictEqual(inspect(parser, input('(a', new Context())), [['(', 'a'], '']);
15
- assert.deepStrictEqual(inspect(parser, input('(0)', new Context())), [['(', '0', ')'], '']);
16
- assert.deepStrictEqual(inspect(parser, input('(1)', new Context())), [['(', '1', ')'], '']);
17
- assert.deepStrictEqual(inspect(parser, input('(10)', new Context())), [['(', '10', ')'], '']);
18
- assert.deepStrictEqual(inspect(parser, input('(2000)', new Context())), [['(', '2000', ')'], '']);
19
- assert.deepStrictEqual(inspect(parser, input('(0-1)', new Context())), [['(', '0-1', ')'], '']);
20
- assert.deepStrictEqual(inspect(parser, input('(0)-1', new Context())), [['(', '0', ')'], '-1']);
21
- assert.deepStrictEqual(inspect(parser, input('(0.1)', new Context())), [['(', '0.1', ')'], '']);
22
- assert.deepStrictEqual(inspect(parser, input('(0.1.2)', new Context())), [['(', '0.1.2', ')'], '']);
23
- assert.deepStrictEqual(inspect(parser, input('(1.1, 1.2-1.3, 1.4)', new Context())), [['(', '1.1, 1.2-1.3, 1.4', ')'], '']);
24
- assert.deepStrictEqual(inspect(parser, input('(1 2)', new Context())), [['<span class="paren">(1 2)</span>'], '']);
25
- assert.deepStrictEqual(inspect(parser, input('(1, 2)', new Context())), [['(', '1, 2', ')'], '']);
26
- assert.deepStrictEqual(inspect(parser, input('(1a)', new Context())), [['(', '1a', ')'], '']);
27
- assert.deepStrictEqual(inspect(parser, input('(a)', new Context())), [['(', 'a', ')'], '']);
28
- assert.deepStrictEqual(inspect(parser, input('(a1)', new Context())), [['(', 'a1', ')'], '']);
29
- assert.deepStrictEqual(inspect(parser, input('(a-1)', new Context())), [['(', 'a-1', ')'], '']);
30
- assert.deepStrictEqual(inspect(parser, input('(a.1)', new Context())), [['(', 'a.1', ')'], '']);
31
- assert.deepStrictEqual(inspect(parser, input('(a b)', new Context())), [['<span class="paren">(a b)</span>'], '']);
32
- assert.deepStrictEqual(inspect(parser, input('(word)', new Context())), [['(', 'word', ')'], '']);
33
- assert.deepStrictEqual(inspect(parser, input('(word word)', new Context())), [['<span class="paren">(word word)</span>'], '']);
34
- assert.deepStrictEqual(inspect(parser, input('(word, word)', new Context())), [['(', 'word, word', ')'], '']);
35
- assert.deepStrictEqual(inspect(parser, input('(A)', new Context())), [['(', 'A', ')'], '']);
36
- assert.deepStrictEqual(inspect(parser, input('(Name)', new Context())), [['(', 'Name', ')'], '']);
37
- assert.deepStrictEqual(inspect(parser, input('(Word word)', new Context())), [['<span class="paren">(Word word)</span>'], '']);
38
- assert.deepStrictEqual(inspect(parser, input('(Word Word)', new Context())), [['<span class="paren">(Word Word)</span>'], '']);
39
- assert.deepStrictEqual(inspect(parser, input('(Name, Name)', new Context())), [['(', 'Name, Name', ')'], '']);
40
- assert.deepStrictEqual(inspect(parser, input('(ABBR)', new Context())), [['(', 'ABBR', ')'], '']);
41
- assert.deepStrictEqual(inspect(parser, input('(ABBR, ABBR)', new Context())), [['(', 'ABBR, ABBR', ')'], '']);
42
- assert.deepStrictEqual(inspect(parser, input('(\\a)', new Context())), [['<span class="paren">(a)</span>'], '']);
43
- assert.deepStrictEqual(inspect(parser, input('(==)', new Context())), [['<span class="paren">(==)</span>'], '']);
44
- assert.deepStrictEqual(inspect(parser, input('("(\n))"(")', new Context())), [['<span class="paren">("<span class="paren">(</span><br>)</span>'], ')"(")']);
45
- assert.deepStrictEqual(inspect(parser, input('($)$', new Context())), [['<span class="paren">(<span class="math" translate="no" data-src="$)$">$)$</span></span>'], '']);
12
+ assert.deepStrictEqual(inspect(parser, input('(', new Context())), [['<span class="bracket">(</span>'], '']);
13
+ assert.deepStrictEqual(inspect(parser, input('()', new Context())), [['<span class="bracket">()</span>'], '']);
14
+ assert.deepStrictEqual(inspect(parser, input('(a', new Context())), [['<span class="paren">(a</span>'], '']);
15
+ assert.deepStrictEqual(inspect(parser, input('(0)', new Context())), [['<span class="paren">(0)</span>'], '']);
16
+ assert.deepStrictEqual(inspect(parser, input('(1)', new Context())), [['<span class="paren">(1)</span>'], '']);
17
+ assert.deepStrictEqual(inspect(parser, input('(10)', new Context())), [['<span class="paren">(10)</span>'], '']);
18
+ assert.deepStrictEqual(inspect(parser, input('(2000)', new Context())), [['<span class="paren">(2000)</span>'], '']);
19
+ assert.deepStrictEqual(inspect(parser, input('(0-1)', new Context())), [['<span class="paren">(0-1)</span>'], '']);
20
+ assert.deepStrictEqual(inspect(parser, input('(0)-1', new Context())), [['<span class="paren">(0)</span>'], '-1']);
21
+ assert.deepStrictEqual(inspect(parser, input('(0.1)', new Context())), [['<span class="paren">(0.1)</span>'], '']);
22
+ assert.deepStrictEqual(inspect(parser, input('(0.1.2)', new Context())), [['<span class="paren">(0.1.2)</span>'], '']);
23
+ assert.deepStrictEqual(inspect(parser, input('(1.1, 1.2-1.3, 1.4)', new Context())), [['<span class="paren">(1.1, 1.2-1.3, 1.4)</span>'], '']);
24
+ assert.deepStrictEqual(inspect(parser, input('(1 2)', new Context())), [['<span class="bracket">(1 2)</span>'], '']);
25
+ assert.deepStrictEqual(inspect(parser, input('(1, 2)', new Context())), [['<span class="paren">(1, 2)</span>'], '']);
26
+ assert.deepStrictEqual(inspect(parser, input('(1a)', new Context())), [['<span class="paren">(1a)</span>'], '']);
27
+ assert.deepStrictEqual(inspect(parser, input('(a)', new Context())), [['<span class="paren">(a)</span>'], '']);
28
+ assert.deepStrictEqual(inspect(parser, input('(a1)', new Context())), [['<span class="paren">(a1)</span>'], '']);
29
+ assert.deepStrictEqual(inspect(parser, input('(a-1)', new Context())), [['<span class="paren">(a-1)</span>'], '']);
30
+ assert.deepStrictEqual(inspect(parser, input('(a.1)', new Context())), [['<span class="paren">(a.1)</span>'], '']);
31
+ assert.deepStrictEqual(inspect(parser, input('(a b)', new Context())), [['<span class="bracket">(a b)</span>'], '']);
32
+ assert.deepStrictEqual(inspect(parser, input('(word)', new Context())), [['<span class="paren">(word)</span>'], '']);
33
+ assert.deepStrictEqual(inspect(parser, input('(word word)', new Context())), [['<span class="bracket">(word word)</span>'], '']);
34
+ assert.deepStrictEqual(inspect(parser, input('(word, word)', new Context())), [['<span class="paren">(word, word)</span>'], '']);
35
+ assert.deepStrictEqual(inspect(parser, input('(A)', new Context())), [['<span class="paren">(A)</span>'], '']);
36
+ assert.deepStrictEqual(inspect(parser, input('(Name)', new Context())), [['<span class="paren">(Name)</span>'], '']);
37
+ assert.deepStrictEqual(inspect(parser, input('(Word word)', new Context())), [['<span class="bracket">(Word word)</span>'], '']);
38
+ assert.deepStrictEqual(inspect(parser, input('(Word Word)', new Context())), [['<span class="bracket">(Word Word)</span>'], '']);
39
+ assert.deepStrictEqual(inspect(parser, input('(Name, Name)', new Context())), [['<span class="paren">(Name, Name)</span>'], '']);
40
+ assert.deepStrictEqual(inspect(parser, input('(ABBR)', new Context())), [['<span class="paren">(ABBR)</span>'], '']);
41
+ assert.deepStrictEqual(inspect(parser, input('(ABBR, ABBR)', new Context())), [['<span class="paren">(ABBR, ABBR)</span>'], '']);
42
+ assert.deepStrictEqual(inspect(parser, input('(\\a)', new Context())), [['<span class="bracket">(a)</span>'], '']);
43
+ assert.deepStrictEqual(inspect(parser, input('(==)', new Context())), [['<span class="bracket">(==)</span>'], '']);
44
+ assert.deepStrictEqual(inspect(parser, input('("(\n))"(")', new Context())), [['<span class="bracket">("<span class="bracket">(</span><br>)</span>'], ')"(")']);
45
+ assert.deepStrictEqual(inspect(parser, input('($)$', new Context())), [['<span class="bracket">(<span class="math" translate="no" data-src="$)$">$)$</span></span>'], '']);
46
46
  assert.deepStrictEqual(inspect(parser, input(')', new Context())), undefined);
47
- assert.deepStrictEqual(inspect(parser, input('(1,2)', new Context())), [['(', '1,2', ')'], '']);
48
- assert.deepStrictEqual(inspect(parser, input('(0-1)', new Context())), [['(', '0-1', ')'], '']);
49
- assert.deepStrictEqual(inspect(parser, input('(0.1)', new Context())), [['(', '0.1', ')'], '']);
50
- assert.deepStrictEqual(inspect(parser, input('(a)', new Context())), [['(', 'a', ')'], '']);
51
- assert.deepStrictEqual(inspect(parser, input('(A)', new Context())), [['(', 'A', ')'], '']);
52
- assert.deepStrictEqual(inspect(parser, input('(A,B)', new Context())), [['(', 'A,B', ')'], '']);
53
- assert.deepStrictEqual(inspect(parser, input('(A、B)', new Context())), [['(', 'A、B', ')'], '']);
54
- assert.deepStrictEqual(inspect(parser, input('(<bdi>a\\\nb</bdi>)', new Context())), [['<span class="paren">(<bdi>a<br>b</bdi>)</span>'], '']);
55
- assert.deepStrictEqual(inspect(parser, input('([% a\\\nb %])', new Context())), [['<span class="paren">(<span class="remark"><input type="checkbox"><span>[% a<br>b %]</span></span>)</span>'], '']);
56
- assert.deepStrictEqual(inspect(parser, input('({{\\\n}})', new Context())), [['<span class="paren">(<span class="template">{{\\<br>}}</span>)</span>'], '']);
47
+ assert.deepStrictEqual(inspect(parser, input('(1,2)', new Context())), [['<span class="paren">(1,2)</span>'], '']);
48
+ assert.deepStrictEqual(inspect(parser, input('(0-1)', new Context())), [['<span class="paren">(0-1)</span>'], '']);
49
+ assert.deepStrictEqual(inspect(parser, input('(0.1)', new Context())), [['<span class="paren">(0.1)</span>'], '']);
50
+ assert.deepStrictEqual(inspect(parser, input('(a)', new Context())), [['<span class="paren">(a)</span>'], '']);
51
+ assert.deepStrictEqual(inspect(parser, input('(A)', new Context())), [['<span class="paren">(A)</span>'], '']);
52
+ assert.deepStrictEqual(inspect(parser, input('(A,B)', new Context())), [['<span class="paren">(A,B)</span>'], '']);
53
+ assert.deepStrictEqual(inspect(parser, input('(A、B)', new Context())), [['<span class="paren">(A、B)</span>'], '']);
54
+ assert.deepStrictEqual(inspect(parser, input('(<bdi>a\\\nb</bdi>)', new Context())), [['<span class="bracket">(<bdi>a<br>b</bdi>)</span>'], '']);
55
+ assert.deepStrictEqual(inspect(parser, input('([% a\\\nb %])', new Context())), [['<span class="bracket">(<span class="remark"><input type="checkbox"><span>[% a<br>b %]</span></span>)</span>'], '']);
56
+ assert.deepStrictEqual(inspect(parser, input('({{\\\n}})', new Context())), [['<span class="bracket">(<span class="template">{{\\<br>}}</span>)</span>'], '']);
57
57
  });
58
58
 
59
59
  it('[', () => {
@@ -80,10 +80,10 @@ describe('Unit: parser/inline/bracket', () => {
80
80
  assert.deepStrictEqual(inspect(parser, input('""', new Context())), [['"', '"'], '']);
81
81
  assert.deepStrictEqual(inspect(parser, input('"a', new Context())), [['"', 'a'], '']);
82
82
  assert.deepStrictEqual(inspect(parser, input('"a"', new Context())), [['"', 'a', '"'], '']);
83
- assert.deepStrictEqual(inspect(parser, input('"(")"', new Context())), [['"', '<span class="paren">(</span>', '"'], ')"']);
84
- assert.deepStrictEqual(inspect(parser, input('"(("', new Context())), [['"', '<span class="paren">(<span class="paren">(</span></span>', '"'], '']);
85
- assert.deepStrictEqual(inspect(parser, input('"(\\")"', new Context())), [['"', '<span class="paren">(")</span>', '"'], '']);
86
- assert.deepStrictEqual(inspect(parser, input('"(\n)"(")', new Context())), [['"', '<span class="paren">(</span>'], '\n)"(")']);
83
+ assert.deepStrictEqual(inspect(parser, input('"(")"', new Context())), [['"', '<span class="bracket">(</span>', '"'], ')"']);
84
+ assert.deepStrictEqual(inspect(parser, input('"(("', new Context())), [['"', '<span class="bracket">(<span class="bracket">(</span></span>', '"'], '']);
85
+ assert.deepStrictEqual(inspect(parser, input('"(\\")"', new Context())), [['"', '<span class="bracket">(")</span>', '"'], '']);
86
+ assert.deepStrictEqual(inspect(parser, input('"(\n)"(")', new Context())), [['"', '<span class="bracket">(</span>'], '\n)"(")']);
87
87
  assert.deepStrictEqual(inspect(parser, input('"\n"', new Context())), [['"'], '\n"']);
88
88
  assert.deepStrictEqual(inspect(parser, input('"\n"(")', new Context())), [['"'], '\n"(")']);
89
89
  });
@@ -42,15 +42,15 @@ const p1 = lazy(() => surround(
42
42
  ([as, bs = [], cs], { source, position, range, linebreak }) => {
43
43
  const str = linebreak === 0 ? source.slice(position - range + 1, position - 1) : '';
44
44
  return linebreak === 0 && indexA.test(str)
45
- ? new List([new Node(as.head!.value), new Node(str), new Node(cs.head!.value)])
46
- : new List([new Node(html('span', { class: 'paren' }, defrag(unwrap(as.import(bs as List<Node<string>>).import(cs)))))]);
45
+ ? new List([new Node(html('span', { class: 'paren' }, `(${str})`))])
46
+ : new List([new Node(html('span', { class: 'bracket' }, defrag(unwrap(as.import(bs as List<Node<string>>).import(cs)))))]);
47
47
  },
48
48
  ([as, bs = new List()], context) => {
49
49
  const { source, position, range, linebreak } = context;
50
50
  const str = linebreak === 0 ? source.slice(position - range + 1, position) : '';
51
51
  return linebreak === 0 && indexA.test(str)
52
- ? new List([new Node(as.head!.value), new Node(str)])
53
- : new List([new Node(html('span', { class: 'paren' }, defrag(unwrap(as.import(bs as List<Node<string>>)))))]);
52
+ ? new List([new Node(html('span', { class: 'paren' }, `(${str}`))])
53
+ : new List([new Node(html('span', { class: 'bracket' }, defrag(unwrap(as.import(bs as List<Node<string>>)))))]);
54
54
  }));
55
55
 
56
56
  const p2 = lazy(() => surround(
@@ -61,15 +61,15 @@ const p2 = lazy(() => surround(
61
61
  ([as, bs = [], cs], { source, position, range, linebreak }) => {
62
62
  const str = linebreak === 0 ? source.slice(position - range + 1, position - 1) : '';
63
63
  return linebreak === 0 && indexF.test(str)
64
- ? new List([new Node(as.head!.value), new Node(str), new Node(cs.head!.value)])
65
- : new List([new Node(html('span', { class: 'paren' }, defrag(unwrap(as.import(bs as List<Node<string>>).import(cs)))))]);
64
+ ? new List([new Node(html('span', { class: 'paren' }, `(${str})`))])
65
+ : new List([new Node(html('span', { class: 'bracket' }, defrag(unwrap(as.import(bs as List<Node<string>>).import(cs)))))]);
66
66
  },
67
67
  ([as, bs = new List()], context) => {
68
68
  const { source, position, range, linebreak } = context;
69
69
  const str = linebreak === 0 ? source.slice(position - range + 1, position) : '';
70
70
  return linebreak === 0 && indexF.test(str)
71
- ? new List([new Node(as.head!.value), new Node(str)])
72
- : new List([new Node(html('span', { class: 'paren' }, defrag(unwrap(as.import(bs as List<Node<string>>)))))]);
71
+ ? new List([new Node(html('span', { class: 'paren' }, `(${str}`))])
72
+ : new List([new Node(html('span', { class: 'bracket' }, defrag(unwrap(as.import(bs as List<Node<string>>)))))]);
73
73
  }));
74
74
 
75
75
  const s1 = lazy(() => surround(
@@ -51,8 +51,8 @@ describe('Unit: parser/inline/emphasis', () => {
51
51
  assert.deepStrictEqual(inspect(parser, input('*a**b**c*', new Context())), [['<em>a<strong>b</strong>c</em>'], '']);
52
52
  assert.deepStrictEqual(inspect(parser, input('*a**b**c*d', new Context())), [['<em>a<strong>b</strong>c</em>'], 'd']);
53
53
  assert.deepStrictEqual(inspect(parser, input('*`a`*', new Context())), [['<em><code data-src="`a`">a</code></em>'], '']);
54
- assert.deepStrictEqual(inspect(parser, input('*(*a*)*', new Context())), [['<em><span class="paren">(<em>a</em>)</span></em>'], '']);
55
- assert.deepStrictEqual(inspect(parser, input('*(**a**)*', new Context())), [['<em><span class="paren">(<strong>a</strong>)</span></em>'], '']);
54
+ assert.deepStrictEqual(inspect(parser, input('*(*a*)*', new Context())), [['<em><span class="bracket">(<em>a</em>)</span></em>'], '']);
55
+ assert.deepStrictEqual(inspect(parser, input('*(**a**)*', new Context())), [['<em><span class="bracket">(<strong>a</strong>)</span></em>'], '']);
56
56
  });
57
57
 
58
58
  });