securemark 0.234.3 → 0.235.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/securemark.js +210 -171
  3. package/markdown.d.ts +5 -2
  4. package/package-lock.json +40 -37
  5. package/package.json +1 -1
  6. package/src/combinator/control/constraint/block.ts +0 -2
  7. package/src/combinator/control/constraint/contract.ts +1 -1
  8. package/src/combinator/control/manipulation/context.test.ts +4 -4
  9. package/src/combinator/control/manipulation/context.ts +7 -0
  10. package/src/combinator/control/manipulation/match.ts +1 -1
  11. package/src/combinator/control/manipulation/resource.ts +6 -3
  12. package/src/combinator/control/manipulation/scope.ts +1 -1
  13. package/src/combinator/control/manipulation/surround.ts +3 -4
  14. package/src/combinator/data/parser/inits.ts +1 -1
  15. package/src/combinator/data/parser/sequence.ts +1 -1
  16. package/src/combinator/data/parser/some.ts +41 -21
  17. package/src/combinator/data/parser.ts +33 -7
  18. package/src/parser/api/bind.test.ts +3 -3
  19. package/src/parser/api/parse.test.ts +12 -5
  20. package/src/parser/block/blockquote.test.ts +1 -1
  21. package/src/parser/block/extension/aside.test.ts +1 -1
  22. package/src/parser/block/extension/example.test.ts +2 -2
  23. package/src/parser/block/extension/fig.test.ts +20 -20
  24. package/src/parser/block/extension/figure.test.ts +31 -28
  25. package/src/parser/block/extension/figure.ts +5 -3
  26. package/src/parser/block/extension/table.ts +6 -6
  27. package/src/parser/block/heading.test.ts +1 -1
  28. package/src/parser/block.ts +1 -2
  29. package/src/parser/inline/annotation.ts +3 -3
  30. package/src/parser/inline/bracket.test.ts +10 -10
  31. package/src/parser/inline/bracket.ts +5 -8
  32. package/src/parser/inline/deletion.test.ts +4 -1
  33. package/src/parser/inline/deletion.ts +7 -4
  34. package/src/parser/inline/emphasis.ts +3 -6
  35. package/src/parser/inline/emstrong.ts +7 -8
  36. package/src/parser/inline/extension/index.test.ts +19 -18
  37. package/src/parser/inline/extension/index.ts +3 -4
  38. package/src/parser/inline/extension/indexer.test.ts +1 -0
  39. package/src/parser/inline/extension/indexer.ts +1 -0
  40. package/src/parser/inline/html.test.ts +25 -17
  41. package/src/parser/inline/html.ts +39 -15
  42. package/src/parser/inline/insertion.test.ts +4 -1
  43. package/src/parser/inline/insertion.ts +7 -4
  44. package/src/parser/inline/link.test.ts +3 -0
  45. package/src/parser/inline/link.ts +9 -11
  46. package/src/parser/inline/mark.ts +3 -6
  47. package/src/parser/inline/media.test.ts +3 -0
  48. package/src/parser/inline/media.ts +9 -6
  49. package/src/parser/inline/reference.ts +6 -6
  50. package/src/parser/inline/ruby.ts +3 -4
  51. package/src/parser/inline/strong.test.ts +1 -1
  52. package/src/parser/inline/strong.ts +3 -6
  53. package/src/parser/inline.test.ts +2 -3
  54. package/src/parser/processor/figure.test.ts +28 -28
  55. package/src/parser/processor/figure.ts +1 -1
  56. package/src/parser/util.ts +43 -39
@@ -20,13 +20,19 @@ describe('Unit: parser/inline/extension/index', () => {
20
20
  assert.deepStrictEqual(inspect(parser('[#\\]')), undefined);
21
21
  assert.deepStrictEqual(inspect(parser('[#a')), undefined);
22
22
  assert.deepStrictEqual(inspect(parser('[#*a\nb*]')), undefined);
23
+ assert.deepStrictEqual(inspect(parser('[#a\n|#b]')), undefined);
23
24
  assert.deepStrictEqual(inspect(parser('[#a|#\n]')), undefined);
24
25
  assert.deepStrictEqual(inspect(parser('[#a|#\\\n]')), undefined);
26
+ assert.deepStrictEqual(inspect(parser('[#a|#(\n)]')), undefined);
27
+ assert.deepStrictEqual(inspect(parser('[#a|#(\\\n)]')), undefined);
25
28
  assert.deepStrictEqual(inspect(parser('[# |]')), undefined);
26
29
  assert.deepStrictEqual(inspect(parser('[# |#]')), undefined);
27
30
  assert.deepStrictEqual(inspect(parser('[# |#b]')), undefined);
28
- assert.deepStrictEqual(inspect(parser('[# |# ]')), undefined);
29
- assert.deepStrictEqual(inspect(parser('[# |# b]')), undefined);
31
+ assert.deepStrictEqual(inspect(parser('[# a|]')), undefined);
32
+ assert.deepStrictEqual(inspect(parser('[# a|#]')), undefined);
33
+ assert.deepStrictEqual(inspect(parser('[# a|#b]')), undefined);
34
+ assert.deepStrictEqual(inspect(parser('[# a|# ]')), undefined);
35
+ assert.deepStrictEqual(inspect(parser('[# a|# b]')), undefined);
30
36
  assert.deepStrictEqual(inspect(parser(' [#a]')), undefined);
31
37
  });
32
38
 
@@ -64,26 +70,21 @@ describe('Unit: parser/inline/extension/index', () => {
64
70
  assert.deepStrictEqual(inspect(parser('[#|]')), [['<a class="index" href="#index:|">|</a>'], '']);
65
71
  assert.deepStrictEqual(inspect(parser('[#|#]')), [['<a class="index" href="#index:|#">|#</a>'], '']);
66
72
  assert.deepStrictEqual(inspect(parser('[#|#b]')), [['<a class="index" href="#index:|#b">|#b</a>'], '']);
67
- assert.deepStrictEqual(inspect(parser('[#a|]')), [['<a class="index" href="#index:a|">a|</a>'], '']);
68
- assert.deepStrictEqual(inspect(parser('[#a|#]')), [['<a class="index" href="#index:a|#">a|#</a>'], '']);
69
- assert.deepStrictEqual(inspect(parser('[#a|# ]')), [['<a class="index" href="#index:a|#">a|#</a>'], '']);
70
- assert.deepStrictEqual(inspect(parser('[#a|#\\ ]')), [['<a class="index" href="#index:a|#">a|#</a>'], '']);
71
- assert.deepStrictEqual(inspect(parser('[#a|#b]')), [['<a class="index" href="#index:b">a<span class="indexer" data-index="b"></span></a>'], '']);
72
- assert.deepStrictEqual(inspect(parser('[#a|#b ]')), [['<a class="index" href="#index:b">a<span class="indexer" data-index="b"></span></a>'], '']);
73
- assert.deepStrictEqual(inspect(parser('[#a|#b ]')), [['<a class="index" href="#index:b">a<span class="indexer" data-index="b"></span></a>'], '']);
74
- assert.deepStrictEqual(inspect(parser('[#a|#\\b]')), [['<a class="index" href="#index:b">a<span class="indexer" data-index="b"></span></a>'], '']);
75
- assert.deepStrictEqual(inspect(parser('[#a|#*b*]')), [['<a class="index" href="#index:*b*">a<span class="indexer" data-index="*b*"></span></a>'], '']);
76
- assert.deepStrictEqual(inspect(parser('[#a|#b c]')), [['<a class="index" href="#index:b_c">a<span class="indexer" data-index="b_c"></span></a>'], '']);
77
- assert.deepStrictEqual(inspect(parser('[#a|#b c]')), [['<a class="index" href="#index:b_c">a<span class="indexer" data-index="b_c"></span></a>'], '']);
78
- assert.deepStrictEqual(inspect(parser('[#a|#[]]')), [['<a class="index" href="#index:[]">a<span class="indexer" data-index="[]"></span></a>'], '']);
79
- assert.deepStrictEqual(inspect(parser('[#a|#&copy;]')), [['<a class="index" href="#index:&amp;copy;">a<span class="indexer" data-index="&amp;copy;"></span></a>'], '']);
73
+ assert.deepStrictEqual(inspect(parser('[#a|#b]')), [['<a class="index" href="#index:a|#b">a|#b</a>'], '']);
80
74
  assert.deepStrictEqual(inspect(parser('[#a |]')), [['<a class="index" href="#index:a_|">a |</a>'], '']);
81
75
  assert.deepStrictEqual(inspect(parser('[#a |#]')), [['<a class="index" href="#index:a_|#">a |#</a>'], '']);
76
+ assert.deepStrictEqual(inspect(parser('[#a |# ]')), [['<a class="index" href="#index:a_|#">a |#</a>'], '']);
77
+ assert.deepStrictEqual(inspect(parser('[#a |#\\ ]')), [['<a class="index" href="#index:a_|#">a |#</a>'], '']);
82
78
  assert.deepStrictEqual(inspect(parser('[#a |#b]')), [['<a class="index" href="#index:b">a<span class="indexer" data-index="b"></span></a>'], '']);
79
+ assert.deepStrictEqual(inspect(parser('[#a |#b ]')), [['<a class="index" href="#index:b">a<span class="indexer" data-index="b"></span></a>'], '']);
80
+ assert.deepStrictEqual(inspect(parser('[#a |#b ]')), [['<a class="index" href="#index:b">a<span class="indexer" data-index="b"></span></a>'], '']);
81
+ assert.deepStrictEqual(inspect(parser('[#a |#\\b]')), [['<a class="index" href="#index:b">a<span class="indexer" data-index="b"></span></a>'], '']);
82
+ assert.deepStrictEqual(inspect(parser('[#a |#*b*]')), [['<a class="index" href="#index:*b*">a<span class="indexer" data-index="*b*"></span></a>'], '']);
83
+ assert.deepStrictEqual(inspect(parser('[#a |#b c]')), [['<a class="index" href="#index:b_c">a<span class="indexer" data-index="b_c"></span></a>'], '']);
84
+ assert.deepStrictEqual(inspect(parser('[#a |#b c]')), [['<a class="index" href="#index:b_c">a<span class="indexer" data-index="b_c"></span></a>'], '']);
85
+ assert.deepStrictEqual(inspect(parser('[#a |#[]]')), [['<a class="index" href="#index:[]">a<span class="indexer" data-index="[]"></span></a>'], '']);
86
+ assert.deepStrictEqual(inspect(parser('[#a |#&copy;]')), [['<a class="index" href="#index:&amp;copy;">a<span class="indexer" data-index="&amp;copy;"></span></a>'], '']);
83
87
  assert.deepStrictEqual(inspect(parser('[#a |#b]')), [['<a class="index" href="#index:b">a<span class="indexer" data-index="b"></span></a>'], '']);
84
- assert.deepStrictEqual(inspect(parser('[#a &nbsp;|#b]')), [['<a class="index" href="#index:b">a<span class="indexer" data-index="b"></span></a>'], '']);
85
- assert.deepStrictEqual(inspect(parser('[#a <wbr>|#b]')), [['<a class="index" href="#index:b">a<span class="indexer" data-index="b"></span></a>'], '']);
86
- assert.deepStrictEqual(inspect(parser('[#a [# b #]|#b]')), [['<a class="index" href="#index:b">a <span class="comment"><input type="checkbox"><span>[# b #]</span></span><span class="indexer" data-index="b"></span></a>'], '']);
87
88
  });
88
89
 
89
90
  });
@@ -23,11 +23,10 @@ export const index: IndexParser = lazy(() => creator(validate('[#', ']', '\n', f
23
23
  media: false,
24
24
  autolink: false,
25
25
  }}},
26
- open(str(/^\|?/, false),
27
26
  some(union([
28
27
  signature,
29
28
  inline,
30
- ]), ']', /^\\?\n/), true)))),
29
+ ]), ']', /^\\?\n/)))),
31
30
  ']'),
32
31
  ns => [html('a', trimNodeEnd(defrag(ns)))])),
33
32
  ([el]: [HTMLAnchorElement]) => [
@@ -41,8 +40,8 @@ export const index: IndexParser = lazy(() => creator(validate('[#', ']', '\n', f
41
40
  ]))));
42
41
 
43
42
  const signature: IndexParser.SignatureParser = lazy(() => creator(fmap(open(
44
- '|#',
45
- startTight(some(union([bracket, txt]), ']', /^\\?\n/))),
43
+ /^\s+\|#/,
44
+ startTight(some(union([bracket, txt]), ']'))),
46
45
  ns => [
47
46
  html('span', { class: 'indexer', 'data-index': identity(join(ns)).slice(6) }),
48
47
  ])));
@@ -15,6 +15,7 @@ describe('Unit: parser/inline/extension/indexer', () => {
15
15
  assert.deepStrictEqual(inspect(parser(' [#]')), undefined);
16
16
  assert.deepStrictEqual(inspect(parser(' [#]]')), undefined);
17
17
  assert.deepStrictEqual(inspect(parser(' [#a]]')), undefined);
18
+ assert.deepStrictEqual(inspect(parser(' [#&a;]')), undefined);
18
19
  });
19
20
 
20
21
  it('valid', () => {
@@ -10,6 +10,7 @@ export const indexer: ExtensionParser.IndexerParser = creator(fmap(verify(surrou
10
10
  }}},
11
11
  union([index])),
12
12
  /^\s*$/),
13
+ // Indexer is invisible but invalids must be visible.
13
14
  ([el]) => el.getElementsByClassName('invalid').length === 0),
14
15
  ([el]) => [
15
16
  html('span', { class: 'indexer', 'data-index': el.getAttribute('href')!.slice(7) }),
@@ -59,11 +59,14 @@ describe('Unit: parser/inline/html', () => {
59
59
  it('basic', () => {
60
60
  assert.deepStrictEqual(inspect(parser('<small> a</small>')), [['<small> a</small>'], '']);
61
61
  assert.deepStrictEqual(inspect(parser('<small> a </small>')), [['<small> a </small>'], '']);
62
+ assert.deepStrictEqual(inspect(parser('<small> a </small>')), [['<small> a </small>'], '']);
62
63
  assert.deepStrictEqual(inspect(parser('<small>a</small>')), [['<small>a</small>'], '']);
63
64
  assert.deepStrictEqual(inspect(parser('<small>a</small>a')), [['<small>a</small>'], 'a']);
64
65
  assert.deepStrictEqual(inspect(parser('<small>a </small>')), [['<small>a </small>'], '']);
65
- assert.deepStrictEqual(inspect(parser('<small>a </small>')), [['<small>a </small>'], '']);
66
+ assert.deepStrictEqual(inspect(parser('<small>a \n </small>')), [['<small>a </small>'], '']);
66
67
  assert.deepStrictEqual(inspect(parser('<small>a\n</small>')), [['<small>a</small>'], '']);
68
+ assert.deepStrictEqual(inspect(parser('<small>a\n </small>')), [['<small>a </small>'], '']);
69
+ assert.deepStrictEqual(inspect(parser('<small>a\n<wbr></small>')), [['<small>a<wbr></small>'], '']);
67
70
  assert.deepStrictEqual(inspect(parser('<small>a\nb</small>')), [['<small>a<br>b</small>'], '']);
68
71
  assert.deepStrictEqual(inspect(parser('<wbr>a')), [['<wbr>'], 'a']);
69
72
  });
@@ -85,22 +88,27 @@ describe('Unit: parser/inline/html', () => {
85
88
  });
86
89
 
87
90
  it('attribute', () => {
88
- assert.deepStrictEqual(inspect(parser('<small constructor>a</small>z')), [['<span class="invalid">&lt;small constructor&gt;a&lt;/small&gt;</span>'], 'z']);
89
- assert.deepStrictEqual(inspect(parser('<small toString>a</small>z')), undefined);
90
- assert.deepStrictEqual(inspect(parser('<bdo>a</bdo>z')), [['<span class="invalid">&lt;bdo&gt;a&lt;/bdo&gt;</span>'], 'z']);
91
- assert.deepStrictEqual(inspect(parser('<bdo >a</bdo>z')), undefined);
92
- assert.deepStrictEqual(inspect(parser('<bdo __proto__>a</bdo>z')), undefined);
93
- assert.deepStrictEqual(inspect(parser('<bdo constructor>a</bdo>z')), [['<span class="invalid">&lt;bdo constructor&gt;a&lt;/bdo&gt;</span>'], 'z']);
94
- assert.deepStrictEqual(inspect(parser('<bdo toString>a</bdo>z')), undefined);
95
- assert.deepStrictEqual(inspect(parser('<bdo dir>a</bdo>z')), [['<span class="invalid">&lt;bdo dir&gt;a&lt;/bdo&gt;</span>'], 'z']);
96
- assert.deepStrictEqual(inspect(parser('<bdo dir=>a</bdo>z')), undefined);
97
- assert.deepStrictEqual(inspect(parser('<bdo dir=rtl>a</bdo>z')), undefined);
98
- assert.deepStrictEqual(inspect(parser('<bdo dir=">a</bdo>z')), undefined);
99
- assert.deepStrictEqual(inspect(parser('<bdo dir="">a</bdo>z')), [['<span class="invalid">&lt;bdo dir=""&gt;a&lt;/bdo&gt;</span>'], 'z']);
100
- assert.deepStrictEqual(inspect(parser('<bdo dir="rtl" dir="rtl">a</bdo>z')), [['<span class="invalid">&lt;bdo dir="rtl" dir="rtl"&gt;a&lt;/bdo&gt;</span>'], 'z']);
101
- assert.deepStrictEqual(inspect(parser('<bdo dir="rtl">a</bdo>z')), [['<bdo dir="rtl">a</bdo>'], 'z']);
102
- assert.deepStrictEqual(inspect(parser('<bdo dir="rtl" >a</bdo>z')), undefined);
103
- assert.deepStrictEqual(inspect(parser('<wbr constructor>z')), [['<wbr class="invalid">'], 'z']);
91
+ assert.deepStrictEqual(inspect(parser('<small >a</small>')), [['<small>a</small>'], '']);
92
+ assert.deepStrictEqual(inspect(parser('<small >a</small>')), [['<small>a</small>'], '']);
93
+ assert.deepStrictEqual(inspect(parser('<small __proto__>a</small>')), undefined);
94
+ assert.deepStrictEqual(inspect(parser('<small constructor>a</small>')), [['<span class="invalid">&lt;small constructor&gt;a&lt;/small&gt;</span>'], '']);
95
+ assert.deepStrictEqual(inspect(parser('<small toString>a</small>')), undefined);
96
+ assert.deepStrictEqual(inspect(parser('<bdo>a</bdo>')), [['<span class="invalid">&lt;bdo&gt;a&lt;/bdo&gt;</span>'], '']);
97
+ assert.deepStrictEqual(inspect(parser('<bdo >a</bdo>')), [['<span class="invalid">&lt;bdo &gt;a&lt;/bdo&gt;</span>'], '']);
98
+ assert.deepStrictEqual(inspect(parser('<bdo __proto__>a</bdo>')), undefined);
99
+ assert.deepStrictEqual(inspect(parser('<bdo constructor>a</bdo>')), [['<span class="invalid">&lt;bdo constructor&gt;a&lt;/bdo&gt;</span>'], '']);
100
+ assert.deepStrictEqual(inspect(parser('<bdo toString>a</bdo>')), undefined);
101
+ assert.deepStrictEqual(inspect(parser('<bdo dir>a</bdo>')), [['<span class="invalid">&lt;bdo dir&gt;a&lt;/bdo&gt;</span>'], '']);
102
+ assert.deepStrictEqual(inspect(parser('<bdo dir=>a</bdo>')), undefined);
103
+ assert.deepStrictEqual(inspect(parser('<bdo dir=rtl>a</bdo>')), undefined);
104
+ assert.deepStrictEqual(inspect(parser('<bdo dir=">a</bdo>')), undefined);
105
+ assert.deepStrictEqual(inspect(parser('<bdo dir="">a</bdo>')), [['<span class="invalid">&lt;bdo dir=""&gt;a&lt;/bdo&gt;</span>'], '']);
106
+ assert.deepStrictEqual(inspect(parser('<bdo dir="rtl" dir="rtl">a</bdo>')), [['<span class="invalid">&lt;bdo dir="rtl" dir="rtl"&gt;a&lt;/bdo&gt;</span>'], '']);
107
+ assert.deepStrictEqual(inspect(parser('<bdo dir="rtl">a</bdo>')), [['<bdo dir="rtl">a</bdo>'], '']);
108
+ assert.deepStrictEqual(inspect(parser('<bdo dir="rtl" >a</bdo>')), [['<bdo dir="rtl">a</bdo>'], '']);
109
+ assert.deepStrictEqual(inspect(parser('<bdo dir="rtl" >a</bdo>')), [['<bdo dir="rtl">a</bdo>'], '']);
110
+ assert.deepStrictEqual(inspect(parser('<bdo dir="rtl">a</bdo>')), [['<bdo dir="rtl">a</bdo>'], '']);
111
+ assert.deepStrictEqual(inspect(parser('<wbr constructor>')), [['<wbr class="invalid">'], '']);
104
112
  });
105
113
 
106
114
  });
@@ -2,10 +2,10 @@ import { undefined } from 'spica/global';
2
2
  import { isFrozen, ObjectEntries, ObjectFreeze, ObjectSetPrototypeOf, ObjectValues } from 'spica/alias';
3
3
  import { MarkdownParser } from '../../../markdown';
4
4
  import { HTMLParser } from '../inline';
5
- import { union, some, validate, context, creator, surround, match, lazy } from '../../combinator';
5
+ import { union, some, validate, context, creator, surround, open, match, lazy } from '../../combinator';
6
6
  import { inline } from '../inline';
7
7
  import { str } from '../source';
8
- import { startLoose, trimNodeEndBR } from '../util';
8
+ import { startLoose, blank } from '../util';
9
9
  import { html as h, defrag } from 'typed-dom';
10
10
  import { memoize } from 'spica/memoize';
11
11
  import { Cache } from 'spica/cache';
@@ -26,17 +26,17 @@ export const html: HTMLParser = lazy(() => creator(validate('<', validate(/^<[a-
26
26
  memoize(
27
27
  ([, tag]) =>
28
28
  surround(
29
- `<${tag}`, some(union([attribute])), '>', true,
29
+ `<${tag}`, some(union([attribute])), /^\s*>/, true,
30
30
  ([, bs = []], rest) =>
31
31
  [[h(tag as 'span', attributes('html', [], attrspec[tag], bs))], rest]),
32
32
  ([, tag]) => tag)),
33
33
  match(
34
- /^(?=<(sup|sub|small|bdo|bdi)(?=[^\S\n]|>))/,
34
+ /^(?=<(sup|sub|small)(?=[^\S\n]|>))/,
35
35
  memoize(
36
36
  ([, tag]) =>
37
37
  validate(`<${tag}`, `</${tag}>`,
38
38
  surround<HTMLParser.TagParser, string>(surround(
39
- str(`<${tag}`), some(attribute), str('>'), true),
39
+ str(`<${tag}`), some(attribute), str(/^\s*>/), true),
40
40
  startLoose(
41
41
  context((() => {
42
42
  switch (tag) {
@@ -58,25 +58,49 @@ export const html: HTMLParser = lazy(() => creator(validate('<', validate(/^<[a-
58
58
  }},
59
59
  };
60
60
  default:
61
+ assert(false);
61
62
  return {};
62
63
  }
63
64
  })(),
64
- some(union([inline]), `</${tag}>`)), `</${tag}>`),
65
+ some(union([
66
+ some(inline, blank(/\n?/, `</${tag}>`)),
67
+ open(/^\n?/, some(inline, '</'), true),
68
+ ]), `</${tag}>`)), `</${tag}>`),
65
69
  str(`</${tag}>`), false,
66
70
  ([as, bs, cs], rest, context) =>
67
- [[elem(tag, as, trimNodeEndBR(defrag(bs)), cs, context)], rest])),
71
+ [[elem(tag, as, defrag(bs), cs, context)], rest])),
68
72
  ([, tag]) => tag)),
73
+ match(
74
+ /^(?=<(bdo|bdi)(?=[^\S\n]|>))/,
75
+ memoize(
76
+ ([, tag]) =>
77
+ validate(`<${tag}`, `</${tag}>`,
78
+ surround<HTMLParser.TagParser, string>(surround(
79
+ str(`<${tag}`), some(attribute), str(/^\s*>/), true),
80
+ startLoose(some(union([
81
+ some(inline, blank(/\n?/, `</${tag}>`)),
82
+ open(/^\n?/, some(inline, '</'), true),
83
+ ]), `</${tag}>`), `</${tag}>`),
84
+ str(`</${tag}>`), false,
85
+ ([as, bs, cs], rest) =>
86
+ [[elem(tag, as, defrag(bs), cs, {})], rest],
87
+ ([as, bs], rest) =>
88
+ as.length === 1 ? [unshift(as, bs), rest] : undefined)),
89
+ ([, tag]) => tag)),
69
90
  match(
70
91
  /^(?=<([a-z]+)(?=[^\S\n]|>))/,
71
92
  memoize(
72
93
  ([, tag]) =>
73
94
  validate(`<${tag}`, `</${tag}>`,
74
95
  surround<HTMLParser.TagParser, string>(surround(
75
- str(`<${tag}`), some(attribute), str('>'), true),
76
- startLoose(some(union([inline]), `</${tag}>`), `</${tag}>`),
96
+ str(`<${tag}`), some(attribute), str(/^\s*>/), true),
97
+ startLoose(some(union([
98
+ some(inline, blank(/\n?/, `</${tag}>`)),
99
+ open(/^\n?/, some(inline, '</'), true),
100
+ ]), `</${tag}>`), `</${tag}>`),
77
101
  str(`</${tag}>`), false,
78
102
  ([as, bs, cs], rest) =>
79
- [[elem(tag, as, trimNodeEndBR(defrag(bs)), cs, {})], rest],
103
+ [[elem(tag, as, defrag(bs), cs, {})], rest],
80
104
  ([as, bs], rest) =>
81
105
  as.length === 1 ? [unshift(as, bs), rest] : undefined)),
82
106
  ([, tag]) => tag,
@@ -87,8 +111,11 @@ export const attribute: HTMLParser.TagParser.AttributeParser = union([
87
111
  str(/^[^\S\n]+[a-z]+(?:-[a-z]+)*(?:="(?:\\[^\n]|[^\\\n"])*")?(?=[^\S\n]|>)/),
88
112
  ]);
89
113
 
90
- function elem(tag: string, as: (HTMLElement | string)[], bs: (HTMLElement | string)[], cs: (HTMLElement | string)[], context: MarkdownParser.Context): HTMLElement {
114
+ function elem(tag: string, as: string[], bs: (HTMLElement | string)[], cs: string[], context: MarkdownParser.Context): HTMLElement {
115
+ assert(as.length > 0);
116
+ assert(as[0][0] === '<' && as[as.length - 1].slice(-1) === '>');
91
117
  assert(bs.length === defrag(bs).length);
118
+ assert(cs.length === 1);
92
119
  if (!tags.includes(tag)) return invalid('tag', `Invalid HTML tag <${tag}>.`, as, bs, cs);
93
120
  switch (tag) {
94
121
  case 'sup':
@@ -108,11 +135,8 @@ function elem(tag: string, as: (HTMLElement | string)[], bs: (HTMLElement | stri
108
135
  }
109
136
  let attrs: Record<string, string | undefined> | undefined;
110
137
  switch (true) {
111
- case as[as.length - 1] !== '>'
112
- || 'data-invalid-syntax' in (attrs = attributes('html', [], attrspec[tag], as.slice(1, -1) as string[])):
138
+ case 'data-invalid-syntax' in (attrs = attributes('html', [], attrspec[tag], as.slice(1, -1) as string[])):
113
139
  return invalid('attribute', 'Invalid HTML attribute.', as, bs, cs);
114
- case cs.length === 0:
115
- return invalid('closer', `Missing the closing HTML tag <${tag}>.`, as, bs, cs);
116
140
  default:
117
141
  assert(attrs);
118
142
  return h(tag as 'span', attrs, bs);
@@ -18,7 +18,6 @@ describe('Unit: parser/inline/insertion', () => {
18
18
  it('basic', () => {
19
19
  assert.deepStrictEqual(inspect(parser('++a++')), [['<ins>a</ins>'], '']);
20
20
  assert.deepStrictEqual(inspect(parser('++a+b++')), [['<ins>a+b</ins>'], '']);
21
- assert.deepStrictEqual(inspect(parser('++a ++')), [['<ins>a </ins>'], '']);
22
21
  assert.deepStrictEqual(inspect(parser('++ ++')), [['<ins> </ins>'], '']);
23
22
  assert.deepStrictEqual(inspect(parser('++ a++')), [['<ins> a</ins>'], '']);
24
23
  assert.deepStrictEqual(inspect(parser('++ a ++')), [['<ins> a </ins>'], '']);
@@ -26,7 +25,11 @@ describe('Unit: parser/inline/insertion', () => {
26
25
  assert.deepStrictEqual(inspect(parser('++\na++')), [['<ins><br>a</ins>'], '']);
27
26
  assert.deepStrictEqual(inspect(parser('++\\\na++')), [['<ins><span class="linebreak"> </span>a</ins>'], '']);
28
27
  assert.deepStrictEqual(inspect(parser('++<wbr>a++')), [['<ins><wbr>a</ins>'], '']);
28
+ assert.deepStrictEqual(inspect(parser('++a ++')), [['<ins>a </ins>'], '']);
29
+ assert.deepStrictEqual(inspect(parser('++a \n ++')), [['<ins>a </ins>'], '']);
29
30
  assert.deepStrictEqual(inspect(parser('++a\n++')), [['<ins>a</ins>'], '']);
31
+ assert.deepStrictEqual(inspect(parser('++a\n ++')), [['<ins>a </ins>'], '']);
32
+ assert.deepStrictEqual(inspect(parser('++a\n<wbr>++')), [['<ins>a<wbr></ins>'], '']);
30
33
  assert.deepStrictEqual(inspect(parser('++a\nb++')), [['<ins>a<br>b</ins>'], '']);
31
34
  assert.deepStrictEqual(inspect(parser('++a\\\nb++')), [['<ins>a<span class="linebreak"> </span>b</ins>'], '']);
32
35
  assert.deepStrictEqual(inspect(parser('++\\+++')), [['<ins>+</ins>'], '']);
@@ -1,14 +1,17 @@
1
1
  import { InsertionParser } from '../inline';
2
- import { union, some, creator, surround, lazy } from '../../combinator';
2
+ import { union, some, creator, surround, open, lazy } from '../../combinator';
3
3
  import { inline } from '../inline';
4
4
  import { str } from '../source';
5
- import { trimNodeEndBR } from '../util';
5
+ import { blank } from '../util';
6
6
  import { html, defrag } from 'typed-dom';
7
7
  import { unshift } from 'spica/array';
8
8
 
9
9
  export const insertion: InsertionParser = lazy(() => creator(surround(
10
10
  str('++'),
11
- union([some(inline, '++')]),
11
+ some(union([
12
+ some(inline, blank(/\n?/, /\+\+/)),
13
+ open(/^\n?/, some(inline, '+'), true),
14
+ ])),
12
15
  str('++'), false,
13
- ([, bs], rest) => [[html('ins', defrag(trimNodeEndBR(bs)))], rest],
16
+ ([, bs], rest) => [[html('ins', defrag(bs))], rest],
14
17
  ([as, bs], rest) => [unshift(as, bs), rest])));
@@ -93,6 +93,9 @@ describe('Unit: parser/inline/link', () => {
93
93
  assert.deepStrictEqual(inspect(parser('[]{b }')), [['<a href="b">b</a>'], '']);
94
94
  assert.deepStrictEqual(inspect(parser('[]{ b }')), [['<a href="b">b</a>'], '']);
95
95
  assert.deepStrictEqual(inspect(parser('[]{ b }')), [['<a href="b">b</a>'], '']);
96
+ assert.deepStrictEqual(inspect(parser('[]{ b }')), [['<a href="b">b</a>'], '']);
97
+ assert.deepStrictEqual(inspect(parser('[]{ b }')), [['<a href="b">b</a>'], '']);
98
+ assert.deepStrictEqual(inspect(parser('[]{ b }')), [['<a href="b">b</a>'], '']);
96
99
  assert.deepStrictEqual(inspect(parser('[]{\\}')), [[`<a href="\\">\\</a>`], '']);
97
100
  assert.deepStrictEqual(inspect(parser('[]{\\ }')), [[`<a href="\\">\\</a>`], '']);
98
101
  assert.deepStrictEqual(inspect(parser('[]{\\b}')), [[`<a href="\\b">\\b</a>`], '']);
@@ -7,7 +7,7 @@ import { inline, media, shortmedia } from '../inline';
7
7
  import { attributes } from './html';
8
8
  import { autolink } from '../autolink';
9
9
  import { str } from '../source';
10
- import { startLoose, trimNode, stringify } from '../util';
10
+ import { startLoose, trimSpaceStart, trimNodeEnd, stringify } from '../util';
11
11
  import { html, define, defrag } from 'typed-dom';
12
12
  import { ReadonlyURL } from 'spica/url';
13
13
 
@@ -16,8 +16,7 @@ const optspec = {
16
16
  } as const;
17
17
  ObjectSetPrototypeOf(optspec, null);
18
18
 
19
- export const link: LinkParser = lazy(() => creator(10, bind(
20
- validate(['[', '{'], '}', '\n',
19
+ export const link: LinkParser = lazy(() => creator(10, validate(['[', '{'], '}', '\n', bind(
21
20
  guard(context => context.syntax?.inline?.link ?? true,
22
21
  reverse(tails([
23
22
  context({ syntax: { inline: {
@@ -39,12 +38,12 @@ export const link: LinkParser = lazy(() => creator(10, bind(
39
38
  media: false,
40
39
  autolink: false,
41
40
  }}},
42
- some(inline, ']', /^\\?\n/)), ']'),
41
+ trimSpaceStart(some(inline, ']', /^\\?\n/)))),
43
42
  ']',
44
43
  true),
45
44
  ]))),
46
- dup(surround(/^{(?![{}])/, inits([uri, some(option)]), /^[^\S\n]?}/)),
47
- ])))),
45
+ dup(surround(/^{(?![{}])/, inits([uri, some(option)]), /^[^\S\n]*}/)),
46
+ ]))),
48
47
  ([params, content = []]: [string[], (HTMLElement | string)[]], rest, context) => {
49
48
  assert(params.every(p => typeof p === 'string'));
50
49
  if (eval(some(autolink)(stringify(content), context))?.some(node => typeof node === 'object')) return;
@@ -54,7 +53,7 @@ export const link: LinkParser = lazy(() => creator(10, bind(
54
53
  assert(!INSECURE_URI.match(/\s/));
55
54
  const el = elem(
56
55
  INSECURE_URI,
57
- trimNode(defrag(content)),
56
+ trimNodeEnd(defrag(content)),
58
57
  new ReadonlyURL(
59
58
  resolve(INSECURE_URI, context.host ?? location, context.url ?? context.host ?? location),
60
59
  context.host?.href || location.href),
@@ -62,18 +61,17 @@ export const link: LinkParser = lazy(() => creator(10, bind(
62
61
  if (el.classList.contains('invalid')) return [[el], rest];
63
62
  assert(el.classList.length === 0);
64
63
  return [[define(el, attributes('link', [], optspec, params))], rest];
65
- })));
64
+ }))));
66
65
 
67
66
  export const uri: LinkParser.ParameterParser.UriParser = union([
68
- open(/^[^\S\n]/, str(/^\S+/)),
67
+ open(/^[^\S\n]+/, str(/^\S+/)),
69
68
  str(/^[^\s{}]+/),
70
69
  ]);
71
70
 
72
71
  export const option: LinkParser.ParameterParser.OptionParser = union([
73
72
  fmap(str(/^[^\S\n]+nofollow(?=[^\S\n]|})/), () => [` rel="nofollow"`]),
74
73
  str(/^[^\S\n]+[a-z]+(?:-[a-z]+)*(?:="(?:\\[^\n]|[^\\\n"])*")?(?=[^\S\n]|})/),
75
- fmap(str(/^[^\S\n]+(?=})/), () => []),
76
- fmap(str(/^[^\S\n]+[^\n{}]+/), opt => [` \\${opt.slice(1)}`]),
74
+ fmap(str(/^[^\S\n]+[^\s{}]+/), opt => [` \\${opt.slice(1)}`]),
77
75
  ]);
78
76
 
79
77
  export function resolve(uri: string, host: URL | Location, source: URL | Location): string {
@@ -2,19 +2,16 @@ import { MarkParser } from '../inline';
2
2
  import { union, some, creator, surround, open, lazy } from '../../combinator';
3
3
  import { inline } from '../inline';
4
4
  import { str } from '../source';
5
- import { startTight, isEndTightNodes, delimiter } from '../util';
5
+ import { startTight, blank } from '../util';
6
6
  import { html, defrag } from 'typed-dom';
7
7
  import { unshift } from 'spica/array';
8
8
 
9
9
  export const mark: MarkParser = lazy(() => creator(surround(
10
10
  str('=='),
11
11
  startTight(some(union([
12
- some(inline, delimiter('==')),
12
+ some(inline, blank('', /==/)),
13
13
  open(some(inline, '='), inline),
14
14
  ]))),
15
15
  str('=='), false,
16
- ([as, bs, cs], rest) =>
17
- isEndTightNodes(bs)
18
- ? [[html('mark', defrag(bs))], rest]
19
- : [unshift(as, bs), cs[0] + rest],
16
+ ([, bs], rest) => [[html('mark', defrag(bs))], rest],
20
17
  ([as, bs], rest) => [unshift(as, bs), rest])));
@@ -67,6 +67,9 @@ describe('Unit: parser/inline/media', () => {
67
67
  assert.deepStrictEqual(inspect(parser('![]{b }')), [['<a href="b" target="_blank"><img class="media" data-src="b" alt=""></a>'], '']);
68
68
  assert.deepStrictEqual(inspect(parser('![]{ b }')), [['<a href="b" target="_blank"><img class="media" data-src="b" alt=""></a>'], '']);
69
69
  assert.deepStrictEqual(inspect(parser('![]{ b }')), [['<a href="b" target="_blank"><img class="media" data-src="b" alt=""></a>'], '']);
70
+ assert.deepStrictEqual(inspect(parser('![]{ b }')), [['<a href="b" target="_blank"><img class="media" data-src="b" alt=""></a>'], '']);
71
+ assert.deepStrictEqual(inspect(parser('![]{ b }')), [['<a href="b" target="_blank"><img class="media" data-src="b" alt=""></a>'], '']);
72
+ assert.deepStrictEqual(inspect(parser('![]{ b }')), [['<a href="b" target="_blank"><img class="media" data-src="b" alt=""></a>'], '']);
70
73
  assert.deepStrictEqual(inspect(parser('![]{\\}')), [['<a href="\\" target="_blank"><img class="media" data-src="\\" alt=""></a>'], '']);
71
74
  assert.deepStrictEqual(inspect(parser('![]{\\ }')), [['<a href="\\" target="_blank"><img class="media" data-src="\\" alt=""></a>'], '']);
72
75
  assert.deepStrictEqual(inspect(parser('![]{\\b}')), [['<a href="\\b" target="_blank"><img class="media" data-src="\\b" alt=""></a>'], '']);
@@ -18,14 +18,17 @@ const optspec = {
18
18
  } as const;
19
19
  ObjectSetPrototypeOf(optspec, null);
20
20
 
21
- export const media: MediaParser = lazy(() => creator(10, bind(verify(fmap(open(
21
+ export const media: MediaParser = lazy(() => creator(10, validate(['![', '!{'], '}', '\n', bind(verify(fmap(open(
22
22
  '!',
23
- validate(['[', '{'], '}', '\n',
24
23
  guard(context => context.syntax?.inline?.media ?? true,
25
24
  tails([
26
- dup(surround(/^\[(?!\s*\\\s)/, some(union([unsafehtmlentity, bracket, txt]), ']', /^\\?\n/), ']', true)),
27
- dup(surround(/^{(?![{}])/, inits([uri, some(option)]), /^[^\S\n]?}/)),
28
- ])))),
25
+ dup(surround(
26
+ /^\[(?!\s*\\\s)/,
27
+ some(union([unsafehtmlentity, bracket, txt]), ']', /^\\?\n/),
28
+ ']',
29
+ true)),
30
+ dup(surround(/^{(?![{}])/, inits([uri, some(option)]), /^[^\S\n]*}/)),
31
+ ]))),
29
32
  ([as, bs]) => bs ? [[join(as).trim() || join(as)], bs] : [[''], as]),
30
33
  ([[text]]) => text === '' || text.trim() !== ''),
31
34
  ([[text], params], rest, context) => {
@@ -51,7 +54,7 @@ export const media: MediaParser = lazy(() => creator(10, bind(verify(fmap(open(
51
54
  link as MediaParser,
52
55
  ([link]) => [define(link, { target: '_blank' }, [el])])
53
56
  (`{ ${INSECURE_URI}${join(params)} }${rest}`, context);
54
- })));
57
+ }))));
55
58
 
56
59
  const bracket: MediaParser.TextParser.BracketParser = lazy(() => union([
57
60
  surround(str('('), some(union([unsafehtmlentity, bracket, txt]), ')'), str(')'), true, undefined, ([as, bs = []], rest) => [unshift(as, bs), rest]),
@@ -3,7 +3,7 @@ import { ReferenceParser } from '../inline';
3
3
  import { union, subsequence, some, validate, verify, focus, guard, context, creator, surround, lazy, fmap } from '../../combinator';
4
4
  import { inline } from '../inline';
5
5
  import { str } from '../source';
6
- import { startLoose, isStartLoose, trimNode, stringify } from '../util';
6
+ import { startLoose, isStartLoose, trimSpaceStart, trimNodeEnd, stringify } from '../util';
7
7
  import { html, defrag } from 'typed-dom';
8
8
 
9
9
  export const reference: ReferenceParser = lazy(() => creator(validate('[[', ']]', '\n', fmap(surround(
@@ -22,16 +22,16 @@ export const reference: ReferenceParser = lazy(() => creator(validate('[[', ']]'
22
22
  }}, state: undefined },
23
23
  subsequence([
24
24
  abbr,
25
- focus('^', c => [['', c], '']),
26
- some(inline, ']', /^\\?\n/),
27
- ])), ']]')),
25
+ focus(/^\^[^\S\n]*/, source => [['', source], '']),
26
+ trimSpaceStart(some(inline, ']', /^\\?\n/)),
27
+ ])))),
28
28
  ']]'),
29
- ns => [html('sup', attributes(ns), trimNode(defrag(ns)))]))));
29
+ ns => [html('sup', attributes(ns), trimNodeEnd(defrag(ns)))]))));
30
30
 
31
31
  const abbr: ReferenceParser.AbbrParser = creator(fmap(verify(surround(
32
32
  '^',
33
33
  union([str(/^(?![0-9]+\s?[|\]])[0-9A-Za-z]+(?:(?:-|(?=\W)(?!'\d)'?(?!\.\d)\.?(?!,\S),? ?)[0-9A-Za-z]+)*(?:-|'?\.?,? ?)?/)]),
34
- /^\|?(?=]])|^\|[^\S\n]/),
34
+ /^\|?(?=]])|^\|[^\S\n]+/),
35
35
  (_, rest, context) => isStartLoose(rest, context)),
36
36
  ([source]) => [html('abbr', source)]));
37
37
 
@@ -8,12 +8,11 @@ import { isStartTightNodes } from '../util';
8
8
  import { html, defrag } from 'typed-dom';
9
9
  import { unshift, push, join } from 'spica/array';
10
10
 
11
- export const ruby: RubyParser = lazy(() => creator(bind(verify(
12
- validate('[', ')', '\n',
11
+ export const ruby: RubyParser = lazy(() => creator(validate('[', ')', '\n', bind(verify(
13
12
  sequence([
14
13
  surround('[', focus(/^(?:\\[^\n]|[^\\\[\]\n])+(?=]\()/, text), ']'),
15
14
  surround('(', focus(/^(?:\\[^\n]|[^\\\(\)\n])+(?=\))/, text), ')'),
16
- ])),
15
+ ]),
17
16
  ([texts]) => isStartTightNodes(texts)),
18
17
  ([texts, rubies], rest) => {
19
18
  const tail = typeof texts[texts.length - 1] === 'object'
@@ -44,7 +43,7 @@ export const ruby: RubyParser = lazy(() => creator(bind(verify(
44
43
  [html('rp', '('), html('rt', join(rubies, ' ').trim()), html('rp', ')')]), tail)))
45
44
  ], rest];
46
45
  }
47
- })));
46
+ }))));
48
47
 
49
48
  const text: RubyParser.TextParser = creator((source, context) => {
50
49
  const acc = [''];
@@ -9,11 +9,11 @@ describe('Unit: parser/inline/strong', () => {
9
9
  it('invalid', () => {
10
10
  assert.deepStrictEqual(inspect(parser('**')), undefined);
11
11
  assert.deepStrictEqual(inspect(parser('**a')), [['**', 'a'], '']);
12
- assert.deepStrictEqual(inspect(parser('**a*')), [['**', 'a', '*'], '']);
13
12
  assert.deepStrictEqual(inspect(parser('**a **')), [['**', 'a', ' ', '**'], '']);
14
13
  assert.deepStrictEqual(inspect(parser('**a\n**')), [['**', 'a', '<br>', '**'], '']);
15
14
  assert.deepStrictEqual(inspect(parser('**a\\ **')), [['**', 'a', ' ', '**'], '']);
16
15
  assert.deepStrictEqual(inspect(parser('**a\\\n**')), [['**', 'a', '<span class="linebreak"> </span>', '**'], '']);
16
+ assert.deepStrictEqual(inspect(parser('**a*')), [['**', 'a', '*'], '']);
17
17
  assert.deepStrictEqual(inspect(parser('**a*b**')), [['**', 'a', '<em>b</em>', '*'], '']);
18
18
  assert.deepStrictEqual(inspect(parser('** **')), undefined);
19
19
  assert.deepStrictEqual(inspect(parser('** a**')), undefined);
@@ -2,19 +2,16 @@ import { StrongParser } from '../inline';
2
2
  import { union, some, creator, surround, open, lazy } from '../../combinator';
3
3
  import { inline } from '../inline';
4
4
  import { str } from '../source';
5
- import { startTight, isEndTightNodes, delimiter } from '../util';
5
+ import { startTight, blank } from '../util';
6
6
  import { html, defrag } from 'typed-dom';
7
7
  import { unshift } from 'spica/array';
8
8
 
9
9
  export const strong: StrongParser = lazy(() => creator(surround(
10
10
  str('**'),
11
11
  startTight(some(union([
12
- some(inline, delimiter(String.raw`\*\*`)),
12
+ some(inline, blank('', /\*\*/)),
13
13
  open(some(inline, '*'), inline),
14
14
  ])), '*'),
15
15
  str('**'), false,
16
- ([as, bs, cs], rest) =>
17
- isEndTightNodes(bs)
18
- ? [[html('strong', defrag(bs))], rest]
19
- : [unshift(as, bs), cs[0] + rest],
16
+ ([, bs], rest) => [[html('strong', defrag(bs))], rest],
20
17
  ([as, bs], rest) => [unshift(as, bs), rest])));
@@ -92,7 +92,6 @@ describe('Unit: parser/inline', () => {
92
92
  assert.deepStrictEqual(inspect(parser('***a***')), [['<em><strong>a</strong></em>'], '']);
93
93
  assert.deepStrictEqual(inspect(parser('***a***b')), [['<em><strong>a</strong></em>', 'b'], '']);
94
94
  assert.deepStrictEqual(inspect(parser('***a****')), [['<em><strong>a</strong></em>', '*'], '']);
95
- assert.deepStrictEqual(inspect(parser('***a *b****')), [['<em><strong>a <em>b</em></strong></em>'], '']);
96
95
  assert.deepStrictEqual(inspect(parser('****a***')), [['****', 'a', '***'], '']);
97
96
  assert.deepStrictEqual(inspect(parser('****a****')), [['****', 'a', '****'], '']);
98
97
  assert.deepStrictEqual(inspect(parser('*(*a*)*')), [['<em><span class="paren">(<em>a</em>)</span></em>'], '']);
@@ -118,9 +117,9 @@ describe('Unit: parser/inline', () => {
118
117
  assert.deepStrictEqual(inspect(parser('[[#a]]')), [['<sup class="reference"><a href="/hashtags/a" class="hashtag">#a</a></sup>'], '']);
119
118
  assert.deepStrictEqual(inspect(parser('[[$-1]]')), [['<sup class="reference"><a class="label" data-label="$-1">$-1</a></sup>'], '']);
120
119
  assert.deepStrictEqual(inspect(parser('[[#-1]]{b}')), [['<sup class="reference">#-1</sup>', '<a href="b">b</a>'], '']);
121
- assert.deepStrictEqual(inspect(parser('[[#-1]](b)')), [['<sup class="reference">#-1</sup>', '(b)'], '']);
120
+ assert.deepStrictEqual(inspect(parser('[[#-1]](b)')), [['<sup class="reference">#-1</sup>', '(', 'b', ')'], '']);
122
121
  assert.deepStrictEqual(inspect(parser('[[#-1]a]{b}')), [['<a href="b">[#-1]a</a>'], '']);
123
- assert.deepStrictEqual(inspect(parser('[[#-1]a](b)')), [['[', '<a class="index" href="#index:-1">-1</a>', 'a', ']', '(b)'], '']);
122
+ assert.deepStrictEqual(inspect(parser('[[#-1]a](b)')), [['[', '<a class="index" href="#index:-1">-1</a>', 'a', ']', '(', 'b', ')'], '']);
124
123
  assert.deepStrictEqual(inspect(parser('[#a]{b}')), [['<a class="index" href="#index:a">a</a>', '<a href="b">b</a>'], '']);
125
124
  assert.deepStrictEqual(inspect(parser('[@a]{b}')), [['[', '<a href="/@a" class="account">@a</a>', ']', '<a href="b">b</a>'], '']);
126
125
  assert.deepStrictEqual(inspect(parser('[http://host]{http://evil}')), [['[', '<a href="http://host" target="_blank">http://host</a>', ']', '<a href="http://evil" target="_blank">http://evil</a>'], '']);