securemark 0.293.5 → 0.294.0

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 (105) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/dist/index.js +845 -534
  3. package/markdown.d.ts +13 -13
  4. package/package.json +3 -3
  5. package/src/combinator/control/constraint/block.test.ts +6 -6
  6. package/src/combinator/control/constraint/contract.ts +3 -3
  7. package/src/combinator/control/constraint/line.test.ts +7 -7
  8. package/src/combinator/control/constraint/line.ts +1 -1
  9. package/src/combinator/control/manipulation/clear.ts +2 -3
  10. package/src/combinator/control/manipulation/convert.ts +2 -2
  11. package/src/combinator/control/manipulation/duplicate.ts +4 -5
  12. package/src/combinator/control/manipulation/fence.ts +2 -2
  13. package/src/combinator/control/manipulation/indent.test.ts +2 -2
  14. package/src/combinator/control/manipulation/indent.ts +4 -4
  15. package/src/combinator/control/manipulation/reverse.ts +2 -2
  16. package/src/combinator/control/manipulation/scope.ts +3 -4
  17. package/src/combinator/control/manipulation/surround.ts +12 -13
  18. package/src/combinator/control/monad/bind.ts +6 -6
  19. package/src/combinator/control/monad/fmap.ts +7 -7
  20. package/src/combinator/data/data.ts +135 -0
  21. package/src/combinator/data/parser/context.test.ts +8 -8
  22. package/src/combinator/data/parser/context.ts +3 -3
  23. package/src/combinator/data/parser/inits.ts +6 -7
  24. package/src/combinator/data/parser/sequence.test.ts +3 -3
  25. package/src/combinator/data/parser/sequence.ts +6 -7
  26. package/src/combinator/data/parser/some.test.ts +3 -3
  27. package/src/combinator/data/parser/some.ts +4 -4
  28. package/src/combinator/data/parser/subsequence.test.ts +4 -4
  29. package/src/combinator/data/parser/subsequence.ts +3 -3
  30. package/src/combinator/data/parser/tails.ts +3 -3
  31. package/src/combinator/data/parser/union.test.ts +3 -3
  32. package/src/combinator/data/parser.ts +16 -7
  33. package/src/debug.test.ts +6 -5
  34. package/src/parser/api/bind.ts +4 -6
  35. package/src/parser/api/header.ts +1 -1
  36. package/src/parser/api/normalize.ts +1 -1
  37. package/src/parser/api/parse.ts +3 -1
  38. package/src/parser/block/blockquote.ts +6 -4
  39. package/src/parser/block/codeblock.ts +8 -7
  40. package/src/parser/block/dlist.ts +9 -8
  41. package/src/parser/block/extension/aside.ts +27 -21
  42. package/src/parser/block/extension/example.ts +29 -26
  43. package/src/parser/block/extension/fig.ts +1 -1
  44. package/src/parser/block/extension/figbase.ts +6 -5
  45. package/src/parser/block/extension/figure.ts +23 -19
  46. package/src/parser/block/extension/message.ts +35 -24
  47. package/src/parser/block/extension/placeholder.ts +17 -13
  48. package/src/parser/block/extension/table.ts +47 -40
  49. package/src/parser/block/heading.test.ts +3 -12
  50. package/src/parser/block/heading.ts +12 -8
  51. package/src/parser/block/ilist.ts +13 -12
  52. package/src/parser/block/mathblock.ts +21 -17
  53. package/src/parser/block/mediablock.ts +7 -5
  54. package/src/parser/block/olist.ts +15 -5
  55. package/src/parser/block/pagebreak.ts +2 -1
  56. package/src/parser/block/paragraph.ts +3 -1
  57. package/src/parser/block/reply/cite.ts +20 -15
  58. package/src/parser/block/reply/quote.ts +6 -4
  59. package/src/parser/block/reply.ts +6 -3
  60. package/src/parser/block/sidefence.ts +8 -7
  61. package/src/parser/block/table.ts +23 -22
  62. package/src/parser/block/ulist.ts +16 -12
  63. package/src/parser/block.ts +7 -6
  64. package/src/parser/header.ts +18 -18
  65. package/src/parser/inline/annotation.ts +3 -1
  66. package/src/parser/inline/autolink/account.ts +3 -2
  67. package/src/parser/inline/autolink/anchor.ts +3 -2
  68. package/src/parser/inline/autolink/channel.ts +5 -4
  69. package/src/parser/inline/autolink/email.ts +4 -3
  70. package/src/parser/inline/autolink/hashnum.ts +3 -2
  71. package/src/parser/inline/autolink/hashtag.ts +4 -3
  72. package/src/parser/inline/autolink/url.ts +7 -6
  73. package/src/parser/inline/bracket.ts +16 -15
  74. package/src/parser/inline/code.ts +5 -4
  75. package/src/parser/inline/deletion.ts +5 -5
  76. package/src/parser/inline/emphasis.ts +4 -3
  77. package/src/parser/inline/emstrong.test.ts +18 -18
  78. package/src/parser/inline/emstrong.ts +39 -30
  79. package/src/parser/inline/extension/index.ts +22 -19
  80. package/src/parser/inline/extension/indexee.ts +2 -2
  81. package/src/parser/inline/extension/indexer.ts +2 -1
  82. package/src/parser/inline/extension/label.ts +7 -3
  83. package/src/parser/inline/extension/placeholder.ts +6 -6
  84. package/src/parser/inline/html.ts +27 -28
  85. package/src/parser/inline/htmlentity.ts +9 -8
  86. package/src/parser/inline/insertion.ts +5 -5
  87. package/src/parser/inline/italic.ts +5 -5
  88. package/src/parser/inline/link.ts +36 -38
  89. package/src/parser/inline/mark.ts +7 -7
  90. package/src/parser/inline/math.ts +5 -4
  91. package/src/parser/inline/media.ts +33 -32
  92. package/src/parser/inline/reference.ts +19 -20
  93. package/src/parser/inline/remark.ts +11 -11
  94. package/src/parser/inline/ruby.ts +50 -53
  95. package/src/parser/inline/strong.ts +4 -3
  96. package/src/parser/inline/template.ts +16 -15
  97. package/src/parser/inline.test.ts +3 -3
  98. package/src/parser/segment.ts +3 -1
  99. package/src/parser/source/escapable.ts +9 -8
  100. package/src/parser/source/line.ts +4 -3
  101. package/src/parser/source/str.ts +2 -2
  102. package/src/parser/source/text.ts +9 -8
  103. package/src/parser/source/unescapable.ts +6 -5
  104. package/src/parser/util.ts +18 -13
  105. package/src/parser/visibility.ts +19 -20
@@ -1,5 +1,6 @@
1
1
  import { ExtensionParser } from '../../inline';
2
2
  import { State, Backtrack } from '../../context';
3
+ import { List, Data } from '../../../combinator/data/parser';
3
4
  import { union, constraint, clear, surround, fmap } from '../../../combinator';
4
5
  import { str } from '../../source';
5
6
  import { html } from 'typed-dom/dom';
@@ -16,9 +17,12 @@ export const label: ExtensionParser.LabelParser = constraint(State.label, fmap(
16
17
  surround('[', body, ']', false, undefined, undefined, [1 | Backtrack.bracket, 1]),
17
18
  body,
18
19
  ]),
19
- ([text]) => [
20
- html('a', { class: 'label', 'data-label': text.slice(text[1] === '-' ? 0 : 1).toLowerCase() }, text),
21
- ]));
20
+ ([{ value }]) => new List([
21
+ new Data(html('a', {
22
+ class: 'label',
23
+ 'data-label': value.slice(value[1] === '-' ? 0 : 1).toLowerCase(),
24
+ }, value)),
25
+ ])));
22
26
 
23
27
  export function number(label: string, base: string): string {
24
28
  return isFixed(label)
@@ -1,11 +1,11 @@
1
1
  import { ExtensionParser } from '../../inline';
2
2
  import { Recursion, Backtrack } from '../../context';
3
+ import { List, Data } from '../../../combinator/data/parser';
3
4
  import { union, some, recursion, precedence, surround, lazy } from '../../../combinator';
4
5
  import { inline } from '../../inline';
5
6
  import { str } from '../../source';
6
7
  import { tightStart } from '../../visibility';
7
8
  import { invalid } from '../../util';
8
- import { unshift } from 'spica/array';
9
9
  import { html } from 'typed-dom/dom';
10
10
 
11
11
  // Don't use the symbols already used: !#$%@&*+~=|
@@ -18,13 +18,13 @@ export const placeholder: ExtensionParser.PlaceholderParser = lazy(() => surroun
18
18
  precedence(1, recursion(Recursion.inline,
19
19
  tightStart(some(union([inline]), ']', [[']', 1]])))),
20
20
  str(']'), false,
21
- (_, context) => [[
22
- html('span',
21
+ (_, context) => new List([
22
+ new Data(html('span',
23
23
  {
24
24
  class: 'invalid',
25
25
  ...invalid('extension', 'syntax', `Invalid start symbol or linebreak`),
26
26
  },
27
- context.source.slice(context.position - context.range!, context.position))
28
- ]],
29
- ([as, bs]) => bs && [unshift(as, bs)],
27
+ context.source.slice(context.position - context.range!, context.position)))
28
+ ]),
29
+ ([as, bs]) => bs && as.import(bs as List<Data<string>>),
30
30
  [3 | Backtrack.bracket]));
@@ -1,13 +1,12 @@
1
1
  import { HTMLParser } from '../inline';
2
2
  import { Recursion } from '../context';
3
- import { Ctx } from '../../combinator/data/parser';
3
+ import { List, Data, Ctx } from '../../combinator/data/parser';
4
4
  import { union, some, recursion, precedence, validate, surround, open, match, lazy } from '../../combinator';
5
5
  import { inline } from '../inline';
6
6
  import { str } from '../source';
7
7
  import { isLooseNodeStart, blankWith } from '../visibility';
8
- import { invalid } from '../util';
8
+ import { invalid, unwrap } from '../util';
9
9
  import { memoize } from 'spica/memoize';
10
- import { unshift, push } from 'spica/array';
11
10
  import { html as h, defrag } from 'typed-dom/dom';
12
11
 
13
12
  const tags: readonly string[] = ['wbr', 'bdo', 'bdi'];
@@ -28,10 +27,10 @@ export const html: HTMLParser = lazy(() => validate(/<[a-z]+(?=[ >])/yi,
28
27
  some(union([attribute])),
29
28
  open(str(/ ?/y), str('>'), true),
30
29
  true,
31
- ([as, bs = [], cs], context) =>
32
- [[elem(as[0].slice(1), false, push(unshift(as, bs), cs), [], [], context)]],
33
- ([as, bs = []], context) =>
34
- [[elem(as[0].slice(1), false, unshift(as, bs), [], [], context)]]),
30
+ ([as, bs = new List(), cs], context) =>
31
+ new List([new Data(elem(as.head!.value.slice(1), false, [...unwrap(as.import(bs).import(cs))], new List(), new List(), context))]),
32
+ ([as, bs = new List()], context) =>
33
+ new List([new Data(elem(as.head!.value.slice(1), false, [...unwrap(as.import(bs))], new List(), new List(), context))])),
35
34
  match(
36
35
  new RegExp(String.raw`<(${TAGS.join('|')})(?=[^\S\n]|>)`, 'y'),
37
36
  memoize(
@@ -40,8 +39,8 @@ export const html: HTMLParser = lazy(() => validate(/<[a-z]+(?=[ >])/yi,
40
39
  surround(
41
40
  str(`<${tag}`), some(attribute), open(str(/ ?/y), str('>'), true),
42
41
  true,
43
- ([as, bs = [], cs]) => [push(unshift(as, bs), cs)],
44
- ([as, bs = []]) => [unshift(as, bs)]),
42
+ ([as, bs = new List(), cs]) => as.import(bs).import(cs),
43
+ ([as, bs = new List()]) => as.import(bs)),
45
44
  // 不可視のHTML構造が可視構造を変化させるべきでない。
46
45
  // 可視のHTMLは優先度変更を検討する。
47
46
  // このため<>は将来的に共通構造を変化させる可能性があり
@@ -53,10 +52,10 @@ export const html: HTMLParser = lazy(() => validate(/<[a-z]+(?=[ >])/yi,
53
52
  ])))),
54
53
  str(`</${tag}>`),
55
54
  true,
56
- ([as, bs = [], cs], context) =>
57
- [[elem(tag, true, as, bs, cs, context)]],
58
- ([as, bs = []], context) =>
59
- [[elem(tag, true, as, bs, [], context)]]),
55
+ ([as, bs = new List(), cs], context) =>
56
+ new List([new Data(elem(tag, true, [...unwrap(as)], bs, cs, context))]),
57
+ ([as, bs = new List()], context) =>
58
+ new List([new Data(elem(tag, true, [...unwrap(as)], bs, new List(), context))])),
60
59
  ([, tag]) => tag,
61
60
  new Map())),
62
61
  surround(
@@ -65,10 +64,10 @@ export const html: HTMLParser = lazy(() => validate(/<[a-z]+(?=[ >])/yi,
65
64
  some(union([attribute])),
66
65
  open(str(/ ?/y), str('>'), true),
67
66
  true,
68
- ([as, bs = [], cs], context) =>
69
- [[elem(as[0].slice(1), false, push(unshift(as, bs), cs), [], [], context)]],
70
- ([as, bs = []], context) =>
71
- [[elem(as[0].slice(1), false, unshift(as, bs), [], [], context)]]),
67
+ ([as, bs = new List(), cs], context) =>
68
+ new List([new Data(elem(as.head!.value.slice(1), false, [...unwrap(as.import(bs).import(cs))], new List(), new List(), context))]),
69
+ ([as, bs = new List()], context) =>
70
+ new List([new Data(elem(as.head!.value.slice(1), false, [...unwrap(as.import(bs))], new List(), new List(), context))])),
72
71
  ])));
73
72
 
74
73
  export const attribute: HTMLParser.AttributeParser = union([
@@ -76,7 +75,7 @@ export const attribute: HTMLParser.AttributeParser = union([
76
75
  str(/ [^\s<>]+/y),
77
76
  ]);
78
77
 
79
- function elem(tag: string, content: boolean, as: string[], bs: (HTMLElement | string)[], cs: string[], context: Ctx): HTMLElement {
78
+ function elem(tag: string, content: boolean, as: readonly string[], bs: List<Data<HTMLElement | string>>, cs: List<Data<string>>, context: Ctx): HTMLElement {
80
79
  assert(as.length > 0);
81
80
  assert(as[0][0] === '<');
82
81
  if (!tags.includes(tag)) return ielem('tag', `Invalid HTML tag name "${tag}"`, context);
@@ -88,7 +87,7 @@ function elem(tag: string, content: boolean, as: string[], bs: (HTMLElement | st
88
87
  const [attrs] = attributes('html', attrspecs[tag], as.slice(1, as.at(-1) === '>' ? -1 : as.length));
89
88
  if (/(?<!\S)invalid(?!\S)/.test(attrs['class'] ?? '')) return ielem('attribute', 'Invalid HTML attribute', context)
90
89
  if (as.at(-1) !== '>') return ielem('tag', `Missing the closing symbol ">"`, context);
91
- return h(tag as 'span', attrs, defrag(bs));
90
+ return h(tag as 'span', attrs, defrag(unwrap(bs)));
92
91
  }
93
92
 
94
93
  function ielem(type: string, message: string, context: Ctx): HTMLElement {
@@ -105,7 +104,7 @@ const requiredAttributes = memoize(
105
104
  export function attributes(
106
105
  syntax: string,
107
106
  spec: Readonly<Record<string, readonly (string | undefined)[] | undefined>> | undefined,
108
- params: readonly string[],
107
+ params: Iterable<string>,
109
108
  ): [Record<string, string | undefined>, string[]] {
110
109
  assert(spec instanceof Object === false);
111
110
  assert(!spec?.['__proto__']);
@@ -113,17 +112,17 @@ export function attributes(
113
112
  const remains = [];
114
113
  let invalidation = false;
115
114
  const attrs: Record<string, string | undefined> = {};
116
- for (let i = 0; i < params.length; ++i) {
117
- const param = params[i].trimStart();
118
- if (param === '') continue;
119
- const name = param.split('=', 1)[0];
120
- const value = param !== name
121
- ? param.slice(name.length + 2, -1).replace(/\\(.?)/g, '$1')
115
+ for (const param of params) {
116
+ const attr = param.trimStart();
117
+ if (attr === '') continue;
118
+ const name = attr.split('=', 1)[0];
119
+ const value = attr !== name
120
+ ? attr.slice(name.length + 2, -1).replace(/\\(.?)/g, '$1')
122
121
  : undefined;
123
122
  invalidation ||= name === '' || !spec || name in attrs;
124
- if (name === '')continue;
123
+ if (name === '') continue;
125
124
  if (spec && name in spec && !spec[name]) {
126
- remains.push(params[i]);
125
+ remains.push(param);
127
126
  continue;
128
127
  }
129
128
  if (spec?.[name]?.includes(value) || spec?.[name]?.length === 0 && value !== undefined) {
@@ -1,4 +1,5 @@
1
1
  import { HTMLEntityParser, UnsafeHTMLEntityParser } from '../inline';
2
+ import { List, Data } from '../../combinator/data/parser';
2
3
  import { union, focus, fmap } from '../../combinator';
3
4
  import { invalid } from '../util';
4
5
  import { html } from 'typed-dom/dom';
@@ -10,20 +11,20 @@ export const unsafehtmlentity: UnsafeHTMLEntityParser = focus(
10
11
  const { source } = context;
11
12
  context.position += source.length;
12
13
  return source.length > 1 && source.at(-1) === ';'
13
- ? [[parser(source) ?? source]]
14
- : [[source]];
14
+ ? new List([new Data(parser(source) ?? source)])
15
+ : new List([new Data(source)]);
15
16
  });
16
17
 
17
18
  export const htmlentity: HTMLEntityParser = fmap(
18
19
  union([unsafehtmlentity]),
19
- ([text]) => [
20
- length === 1 || text.at(-1) !== ';'
21
- ? text
22
- : html('span', {
20
+ ([{ value }]) => new List([
21
+ length === 1 || value.at(-1) !== ';'
22
+ ? new Data(value)
23
+ : new Data(html('span', {
23
24
  class: 'invalid',
24
25
  ...invalid('htmlentity', 'syntax', 'Invalid HTML entity'),
25
- }, text)
26
- ]);
26
+ }, value))
27
+ ]));
27
28
 
28
29
  const parser = (el => (entity: string): string | undefined => {
29
30
  if (entity === '&NewLine;') return ' ';
@@ -1,10 +1,10 @@
1
1
  import { InsertionParser } from '../inline';
2
2
  import { Recursion, Command } from '../context';
3
+ import { List, Data } from '../../combinator/data/parser';
3
4
  import { union, some, recursion, precedence, validate, surround, open, lazy } from '../../combinator';
4
5
  import { inline } from '../inline';
5
6
  import { blankWith } from '../visibility';
6
- import { repeat } from '../util';
7
- import { push } from 'spica/array';
7
+ import { unwrap, repeat } from '../util';
8
8
  import { html, defrag } from 'typed-dom/dom';
9
9
 
10
10
  export const insertion: InsertionParser = lazy(() => validate('++',
@@ -16,6 +16,6 @@ export const insertion: InsertionParser = lazy(() => validate('++',
16
16
  open('\n', some(inline, '+'), true),
17
17
  ]))),
18
18
  '++', false,
19
- ([, bs], { buffer }) => [push(buffer!, bs)],
20
- ([, bs], { buffer }) => bs && [push(push(buffer!, bs), [Command.Cancel])]),
21
- nodes => [html('ins', defrag(nodes))]))));
19
+ ([, bs], { buffer }) => buffer!.import(bs),
20
+ ([, bs], { buffer }) => bs && buffer!.import(bs).push(new Data(Command.Cancel)) && buffer!),
21
+ nodes => new List([new Data(html('ins', defrag(unwrap(nodes))))])))));
@@ -1,10 +1,10 @@
1
1
  import { ItalicParser } from '../inline';
2
2
  import { Recursion, Command } from '../context';
3
+ import { List, Data } from '../../combinator/data/parser';
3
4
  import { union, some, recursion, precedence, validate, surround, open, lazy } from '../../combinator';
4
5
  import { inline } from '../inline';
5
6
  import { tightStart, blankWith } from '../visibility';
6
- import { repeat } from '../util';
7
- import { push } from 'spica/array';
7
+ import { unwrap, repeat } from '../util';
8
8
  import { html, defrag } from 'typed-dom/dom';
9
9
 
10
10
  // 可読性のため実際にはオブリーク体を指定する。
@@ -19,6 +19,6 @@ export const italic: ItalicParser = lazy(() => validate('///',
19
19
  open(some(inline, '/'), inline),
20
20
  ])))),
21
21
  '///', false,
22
- ([, bs], { buffer }) => [push(buffer!, bs)],
23
- ([, bs], { buffer }) => bs && [push(push(buffer!, bs), [Command.Cancel])]),
24
- nodes => [html('i', defrag(nodes))]))));
22
+ ([, bs], { buffer }) => buffer!.import(bs),
23
+ ([, bs], { buffer }) => bs && buffer!.import(bs).push(new Data(Command.Cancel)) && buffer!),
24
+ nodes => new List([new Data(html('i', defrag(unwrap(nodes))))])))));
@@ -1,14 +1,14 @@
1
1
  import { MarkdownParser } from '../../../markdown';
2
2
  import { LinkParser } from '../inline';
3
3
  import { State, Backtrack, Command } from '../context';
4
+ import { List, Data } from '../../combinator/data/parser';
4
5
  import { union, inits, tails, sequence, subsequence, some, creation, precedence, state, constraint, validate, surround, open, setBacktrack, dup, reverse, lazy, fmap, bind } from '../../combinator';
5
6
  import { inline, media, shortmedia } from '../inline';
6
7
  import { attributes } from './html';
7
8
  import { unescsource, str } from '../source';
8
9
  import { trimBlankStart, trimBlankNodeEnd } from '../visibility';
9
- import { invalid, stringify } from '../util';
10
+ import { unwrap, invalid, stringify } from '../util';
10
11
  import { ReadonlyURL } from 'spica/url';
11
- import { unshift, push } from 'spica/array';
12
12
  import { html, define, defrag } from 'typed-dom/dom';
13
13
 
14
14
  const optspec = {
@@ -24,9 +24,9 @@ export const textlink: LinkParser.TextLinkParser = lazy(() => constraint(State.l
24
24
  trimBlankStart(some(union([inline]), ']', [[']', 1]])),
25
25
  ']',
26
26
  true,
27
- ([, ns = []], context) =>
27
+ ([, ns = new List()], context) =>
28
28
  context.linebreak === 0
29
- ? [push(ns, [Command.Separator])]
29
+ ? ns.push(new Data(Command.Separator)) && ns
30
30
  : undefined,
31
31
  undefined,
32
32
  [3 | Backtrack.bracket, 3 | Backtrack.link, 2 | Backtrack.ruby])),
@@ -42,12 +42,12 @@ export const textlink: LinkParser.TextLinkParser = lazy(() => constraint(State.l
42
42
  if (!bs) return;
43
43
  const head = context.position - context.range!;
44
44
  setBacktrack(context, [2 | Backtrack.link], head);
45
- return [push(unshift(as, bs), [Command.Cancel])];
45
+ return as.import(bs).push(new Data(Command.Cancel)) && as;
46
46
  },
47
47
  [3 | Backtrack.link])),
48
48
  ]),
49
- ([content, params]: [(HTMLElement | string)[], string[]], context) => {
50
- if (content.at(-1) === Command.Separator) {
49
+ ([{ value: content }, { value: params = undefined } = {}], context) => {
50
+ if (content.last!.value === Command.Separator) {
51
51
  content.pop();
52
52
  if (params === undefined) {
53
53
  const head = context.position - context.range!;
@@ -55,37 +55,37 @@ export const textlink: LinkParser.TextLinkParser = lazy(() => constraint(State.l
55
55
  }
56
56
  }
57
57
  else {
58
- params = content as string[];
59
- content = [];
58
+ params = content as List<Data<string>>;
59
+ content = new List();
60
60
  }
61
- if (params.at(-1) === Command.Cancel) {
61
+ if (params.last!.value === Command.Cancel) {
62
62
  params.pop();
63
- return [[
64
- html('span',
63
+ return new List([
64
+ new Data(html('span',
65
65
  {
66
66
  class: 'invalid',
67
67
  ...invalid('link', 'syntax', 'Missing the closing symbol "}"')
68
68
  },
69
- context.source.slice(context.position - context.range!, context.position))
70
- ]];
69
+ context.source.slice(context.position - context.range!, context.position)))
70
+ ]);
71
71
  }
72
- assert(!html('div', content).querySelector('a, .media, .annotation, .reference'));
73
- assert(content[0] !== '');
72
+ assert(!html('div', unwrap(content)).querySelector('a, .media, .annotation, .reference'));
73
+ assert(content.head?.value !== '');
74
74
  if (content.length !== 0 && trimBlankNodeEnd(content).length === 0) return;
75
- return [[parse(defrag(content), params, context)]];
75
+ return new List([new Data(parse(content, params as List<Data<string>>, context))]);
76
76
  }))))));
77
77
 
78
78
  export const medialink: LinkParser.MediaLinkParser = lazy(() => constraint(State.link | State.media, validate(/[[{]/y, creation(10,
79
79
  state(State.linkers,
80
- bind(reverse(sequence([
80
+ bind(sequence([
81
81
  dup(surround(
82
82
  '[',
83
83
  union([media, shortmedia]),
84
84
  ']')),
85
85
  dup(surround(/{(?![{}])/y, inits([uri, some(option)]), / ?}/y)),
86
- ])),
87
- ([params, content = []]: [string[], (HTMLElement | string)[]], context) =>
88
- [[parse(defrag(content), params, context)]]))))));
86
+ ]),
87
+ ([{ value: content }, { value: params }], context) =>
88
+ new List([new Data(parse(content, params as List<Data<string>>, context))])))))));
89
89
 
90
90
  export const unsafelink: LinkParser.UnsafeLinkParser = lazy(() =>
91
91
  creation(10,
@@ -96,8 +96,8 @@ export const unsafelink: LinkParser.UnsafeLinkParser = lazy(() =>
96
96
  ']')),
97
97
  dup(surround(/{(?![{}])/y, inits([uri, some(option)]), / ?}/y)),
98
98
  ])),
99
- ([params, content = []], context) =>
100
- [[parse(defrag(content), params, context)]])));
99
+ ([{ value: params }, { value: content } = new Data(new List<Data<string>>())], context) =>
100
+ new List([new Data(parse(content, params, context))]))));
101
101
 
102
102
  export const uri: LinkParser.ParameterParser.UriParser = union([
103
103
  open(/ /y, str(/\S+/y)),
@@ -105,19 +105,18 @@ export const uri: LinkParser.ParameterParser.UriParser = union([
105
105
  ]);
106
106
 
107
107
  export const option: LinkParser.ParameterParser.OptionParser = union([
108
- fmap(str(/ nofollow(?=[ }])/y), () => [` rel="nofollow"`]),
108
+ fmap(str(/ nofollow(?=[ }])/y), () => new List([new Data(' rel="nofollow"')])),
109
109
  str(/ [a-z]+(?:-[a-z]+)*(?:="(?:\\[^\n]|[^\\\n"])*")?(?=[ }])/yi),
110
110
  str(/ [^\s{}]+/y),
111
111
  ]);
112
112
 
113
113
  function parse(
114
- content: readonly (string | HTMLElement)[],
115
- params: string[],
114
+ content: List<Data<string | HTMLElement>>,
115
+ params: List<Data<string>>,
116
116
  context: MarkdownParser.Context,
117
117
  ): HTMLAnchorElement {
118
118
  assert(params.length > 0);
119
- assert(params.every(p => typeof p === 'string'));
120
- const INSECURE_URI = params.shift()!;
119
+ const INSECURE_URI = params.shift()!.value;
121
120
  assert(INSECURE_URI === INSECURE_URI.trim());
122
121
  assert(!INSECURE_URI.match(/\s/));
123
122
  let uri: ReadonlyURL | undefined;
@@ -135,12 +134,12 @@ function parse(
135
134
  context.host?.origin || location.origin);
136
135
  return el.classList.contains('invalid')
137
136
  ? el
138
- : define(el, attributes('link', optspec, params)[0]);
137
+ : define(el, attributes('link', optspec, unwrap(params))[0]);
139
138
  }
140
139
 
141
140
  function elem(
142
141
  INSECURE_URI: string,
143
- content: readonly (string | HTMLElement)[],
142
+ content: List<Data<string | HTMLElement>>,
144
143
  uri: ReadonlyURL | undefined,
145
144
  origin: string,
146
145
  ): HTMLAnchorElement {
@@ -155,7 +154,7 @@ function elem(
155
154
  case 'https:':
156
155
  assert(uri.host);
157
156
  switch (true) {
158
- case /[0-9a-z]:\S/i.test(stringify(content)):
157
+ case /[0-9a-z]:\S/i.test(stringify(unwrap(content))):
159
158
  type = 'content';
160
159
  message = 'URI must not be contained';
161
160
  break;
@@ -171,20 +170,19 @@ function elem(
171
170
  href: uri.source,
172
171
  target: undefined
173
172
  || uri.origin !== origin
174
- || typeof content[0] === 'object' && content[0].classList.contains('media')
173
+ || typeof content.head?.value === 'object' && content.head!.value.classList.contains('media')
175
174
  ? '_blank'
176
175
  : undefined,
177
176
  },
178
177
  content.length === 0
179
178
  ? decode(INSECURE_URI)
180
- : content);
179
+ : defrag(unwrap(content)));
181
180
  }
182
181
  break;
183
182
  case 'tel:':
184
- assert(content.length <= 1);
185
183
  const tel = content.length === 0
186
184
  ? INSECURE_URI
187
- : content[0];
185
+ : stringify(unwrap(content));
188
186
  const pattern = /^(?:tel:)?(?:\+(?!0))?\d+(?:-\d+)*$/i;
189
187
  switch (true) {
190
188
  case content.length <= 1
@@ -198,8 +196,8 @@ function elem(
198
196
  href: uri.source,
199
197
  },
200
198
  content.length === 0
201
- ? [INSECURE_URI]
202
- : content);
199
+ ? INSECURE_URI
200
+ : defrag(unwrap(content)));
203
201
  default:
204
202
  type = 'content';
205
203
  message = 'Invalid content';
@@ -216,7 +214,7 @@ function elem(
216
214
  },
217
215
  content.length === 0
218
216
  ? INSECURE_URI
219
- : content);
217
+ : defrag(unwrap(content)));
220
218
  }
221
219
 
222
220
  export function resolve(uri: string, host: URL | Location, source: URL | Location): string {
@@ -1,11 +1,11 @@
1
1
  import { MarkParser } from '../inline';
2
2
  import { State, Recursion, Command } from '../context';
3
+ import { List, Data } from '../../combinator/data/parser';
3
4
  import { union, some, recursion, precedence, state, constraint, validate, surround, open, lazy } from '../../combinator';
4
5
  import { inline } from '../inline';
5
6
  import { identity, signature } from './extension/indexee';
6
7
  import { tightStart, blankWith } from '../visibility';
7
- import { repeat } from '../util';
8
- import { push } from 'spica/array';
8
+ import { unwrap, repeat } from '../util';
9
9
  import { html, define, defrag } from 'typed-dom/dom';
10
10
 
11
11
  export const mark: MarkParser = lazy(() => constraint(State.linkers & ~State.mark, validate('==',
@@ -17,12 +17,12 @@ export const mark: MarkParser = lazy(() => constraint(State.linkers & ~State.mar
17
17
  open(some(inline, '='), inline),
18
18
  ])))),
19
19
  '==', false,
20
- ([, bs], { buffer }) => [push(buffer!, bs)],
21
- ([, bs], { buffer }) => bs && [push(push(buffer!, bs), [Command.Cancel])]),
20
+ ([, bs], { buffer }) => buffer!.import(bs),
21
+ ([, bs], { buffer }) => bs && buffer!.import(bs).push(new Data(Command.Cancel)) && buffer!),
22
22
  (nodes, { id }) => {
23
- const el = html('mark', defrag(nodes));
23
+ const el = html('mark', defrag(unwrap(nodes)));
24
24
  define(el, { id: identity('mark', id, signature(el)) });
25
25
  return el.id
26
- ? [el, html('a', { href: `#${el.id}` })]
27
- : [el];
26
+ ? new List([new Data(el), new Data(html('a', { href: `#${el.id}` }))])
27
+ : new List([new Data(el)]);
28
28
  }))))));
@@ -1,5 +1,6 @@
1
1
  import { MathParser } from '../inline';
2
2
  import { Backtrack, Recursion } from '../context';
3
+ import { List, Data } from '../../combinator/data/parser';
3
4
  import { union, some, recursion, precedence, rewrite, surround, lazy } from '../../combinator';
4
5
  import { escsource, str } from '../source';
5
6
  import { invalid } from '../util';
@@ -23,8 +24,8 @@ export const math: MathParser = lazy(() => rewrite(
23
24
  /\$(?![-0-9A-Za-z])/y,
24
25
  false, undefined, undefined, [3 | Backtrack.bracket]),
25
26
  ]),
26
- ({ context: { source, caches: { math: cache } = {} } }) => [[
27
- cache?.get(source)?.cloneNode(true) ||
27
+ ({ context: { source, caches: { math: cache } = {} } }) => new List([
28
+ new Data(cache?.get(source)?.cloneNode(true) ||
28
29
  html('span',
29
30
  !forbiddenCommand.test(source)
30
31
  ? { class: 'math', translate: 'no', 'data-src': source }
@@ -34,8 +35,8 @@ export const math: MathParser = lazy(() => rewrite(
34
35
  ...invalid('math', 'content',
35
36
  `"${source.match(forbiddenCommand)![0]}" command is forbidden`),
36
37
  },
37
- source)
38
- ]]));
38
+ source))
39
+ ])));
39
40
 
40
41
  const bracket: MathParser.BracketParser = lazy(() => surround(
41
42
  str('{'),