securemark 0.293.4 → 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 (106) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/dist/index.js +868 -564
  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 +14 -15
  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 +16 -15
  22. package/src/combinator/data/parser/context.ts +5 -4
  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 +6 -8
  35. package/src/parser/api/header.ts +1 -1
  36. package/src/parser/api/normalize.ts +2 -4
  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 +9 -7
  59. package/src/parser/block/reply.ts +7 -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.test.ts +3 -1
  65. package/src/parser/header.ts +20 -20
  66. package/src/parser/inline/annotation.ts +3 -1
  67. package/src/parser/inline/autolink/account.ts +3 -2
  68. package/src/parser/inline/autolink/anchor.ts +3 -2
  69. package/src/parser/inline/autolink/channel.ts +5 -4
  70. package/src/parser/inline/autolink/email.ts +4 -3
  71. package/src/parser/inline/autolink/hashnum.ts +3 -2
  72. package/src/parser/inline/autolink/hashtag.ts +4 -3
  73. package/src/parser/inline/autolink/url.ts +7 -6
  74. package/src/parser/inline/bracket.ts +16 -15
  75. package/src/parser/inline/code.ts +5 -4
  76. package/src/parser/inline/deletion.ts +5 -5
  77. package/src/parser/inline/emphasis.ts +4 -3
  78. package/src/parser/inline/emstrong.test.ts +18 -18
  79. package/src/parser/inline/emstrong.ts +39 -30
  80. package/src/parser/inline/extension/index.ts +22 -19
  81. package/src/parser/inline/extension/indexee.ts +2 -2
  82. package/src/parser/inline/extension/indexer.ts +2 -1
  83. package/src/parser/inline/extension/label.ts +7 -3
  84. package/src/parser/inline/extension/placeholder.ts +6 -6
  85. package/src/parser/inline/html.ts +27 -28
  86. package/src/parser/inline/htmlentity.ts +9 -8
  87. package/src/parser/inline/insertion.ts +5 -5
  88. package/src/parser/inline/italic.ts +5 -5
  89. package/src/parser/inline/link.ts +36 -38
  90. package/src/parser/inline/mark.ts +7 -7
  91. package/src/parser/inline/math.ts +5 -4
  92. package/src/parser/inline/media.ts +33 -32
  93. package/src/parser/inline/reference.ts +19 -20
  94. package/src/parser/inline/remark.ts +11 -11
  95. package/src/parser/inline/ruby.ts +50 -53
  96. package/src/parser/inline/strong.ts +4 -3
  97. package/src/parser/inline/template.ts +16 -15
  98. package/src/parser/inline.test.ts +3 -3
  99. package/src/parser/segment.ts +3 -1
  100. package/src/parser/source/escapable.ts +9 -8
  101. package/src/parser/source/line.ts +4 -3
  102. package/src/parser/source/str.ts +2 -2
  103. package/src/parser/source/text.ts +19 -26
  104. package/src/parser/source/unescapable.ts +6 -5
  105. package/src/parser/util.ts +16 -30
  106. package/src/parser/visibility.ts +19 -20
@@ -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('{'),
@@ -1,14 +1,13 @@
1
1
  import { MediaParser } from '../inline';
2
2
  import { State, Recursion, Backtrack, Command } from '../context';
3
- import { subinput } from '../../combinator/data/parser';
4
- import { union, inits, tails, some, creation, recursion, precedence, constraint, verify, surround, open, setBacktrack, dup, lazy, fmap, bind } from '../../combinator';
3
+ import { List, Data, subinput } from '../../combinator/data/parser';
4
+ import { union, inits, tails, some, creation, recursion, precedence, constraint, surround, open, setBacktrack, dup, lazy, fmap, bind } from '../../combinator';
5
5
  import { unsafelink, uri, option as linkoption, resolve, decode } from './link';
6
6
  import { attributes } from './html';
7
7
  import { unsafehtmlentity } from './htmlentity';
8
8
  import { txt, str } from '../source';
9
- import { invalid } from '../util';
9
+ import { unwrap, invalid } from '../util';
10
10
  import { ReadonlyURL } from 'spica/url';
11
- import { unshift, push } from 'spica/array';
12
11
  import { html, define } from 'typed-dom/dom';
13
12
 
14
13
  const optspec = {
@@ -21,7 +20,7 @@ Object.setPrototypeOf(optspec, null);
21
20
 
22
21
  export const media: MediaParser = lazy(() => constraint(State.media, creation(10, open(
23
22
  '!',
24
- bind(verify(fmap(tails([
23
+ bind(fmap(tails([
25
24
  dup(surround(
26
25
  '[',
27
26
  precedence(1, some(union([
@@ -31,9 +30,9 @@ export const media: MediaParser = lazy(() => constraint(State.media, creation(10
31
30
  ]), ']')),
32
31
  ']',
33
32
  true,
34
- ([, ns = []], context) =>
33
+ ([, ns = new List()], context) =>
35
34
  context.linebreak === 0
36
- ? [ns]
35
+ ? ns
37
36
  : undefined,
38
37
  undefined,
39
38
  [3 | Backtrack.escbracket])),
@@ -47,26 +46,29 @@ export const media: MediaParser = lazy(() => constraint(State.media, creation(10
47
46
  if (!bs) return;
48
47
  const head = context.position - context.range!;
49
48
  setBacktrack(context, [2 | Backtrack.link], head);
50
- return [push(unshift(as, bs), [Command.Cancel])];
49
+ return as.import(bs).push(new Data(Command.Cancel)) && as;
51
50
  },
52
51
  [3 | Backtrack.link])),
53
52
  ]),
54
- ([as, bs]) => bs ? [[as.join('').trim() || as.join('')], bs] : [[''], as]),
55
- ([[text]]) => text === '' || text.trim() !== ''),
56
- ([[text], params], context) => {
57
- if (params.at(-1) === Command.Cancel) {
53
+ nodes =>
54
+ nodes.length === 1
55
+ ? new List<Data<List<Data<string>>>>([new Data(new List([new Data('')])), nodes.delete(nodes.head!)])
56
+ : new List<Data<List<Data<string>>>>([new Data(new List([new Data(nodes.head!.value.foldl((acc, { value }) => acc + value, ''))])), nodes.delete(nodes.last!)])),
57
+ ([{ value: [{ value: text }] }, { value: params }], context) => {
58
+ if (text && text.trimStart() === '') return;
59
+ text = text.trim();
60
+ if (params.last!.value === Command.Cancel) {
58
61
  params.pop();
59
- return [[
60
- html('span',
62
+ return new List([
63
+ new Data(html('span',
61
64
  {
62
65
  class: 'invalid',
63
66
  ...invalid('media', 'syntax', 'Missing the closing symbol "}"')
64
67
  },
65
- '!' + context.source.slice(context.position - context.range!, context.position))
66
- ]];
68
+ '!' + context.source.slice(context.position - context.range!, context.position)))
69
+ ]);
67
70
  }
68
- assert(text === text.trim());
69
- const INSECURE_URI = params.shift()!;
71
+ const INSECURE_URI = params.shift()!.value;
70
72
  assert(INSECURE_URI === INSECURE_URI.trim());
71
73
  assert(!INSECURE_URI.match(/\s/));
72
74
  // altが空だとエラーが見えないため埋める。
@@ -85,37 +87,37 @@ export const media: MediaParser = lazy(() => constraint(State.media, creation(10
85
87
  || html('img', { class: 'media', 'data-src': uri?.source });
86
88
  assert(!el.matches('.invalid'));
87
89
  el.setAttribute('alt', text);
88
- if (!sanitize(el, uri)) return [[el]];
90
+ if (!sanitize(el, uri)) return new List([new Data(el)]);
89
91
  assert(!el.matches('.invalid'));
90
- const [attrs, linkparams] = attributes('media', optspec, params);
92
+ const [attrs, linkparams] = attributes('media', optspec, unwrap(params));
91
93
  define(el, attrs);
92
94
  assert(el.matches('img') || !el.matches('.invalid'));
93
95
  // Awaiting the generic support for attr().
94
96
  if (el.hasAttribute('aspect-ratio')) {
95
97
  el.style.aspectRatio = el.getAttribute('aspect-ratio')!;
96
98
  }
97
- if (context.state! & State.link) return [[el]];
98
- if (cache && cache.tagName !== 'IMG') return [[el]];
99
+ if (context.state! & State.link) return new List([new Data(el)]);
100
+ if (cache && cache.tagName !== 'IMG') return new List([new Data(el)]);
99
101
  const { source, position } = context;
100
102
  return fmap(
101
103
  unsafelink as MediaParser,
102
- ([link]) => {
104
+ ([{ value }]) => {
103
105
  context.source = source;
104
106
  context.position = position;
105
- return [define(link, { class: null, target: '_blank' }, [el])];
107
+ return new List([new Data(define(value, { class: null, target: '_blank' }, [el]))]);
106
108
  })
107
109
  (subinput(`{ ${INSECURE_URI}${linkparams.join('')} }`, context));
108
110
  })))));
109
111
 
110
112
  const bracket: MediaParser.TextParser.BracketParser = lazy(() => recursion(Recursion.terminal, union([
111
113
  surround(str('('), some(union([unsafehtmlentity, bracket, txt]), ')'), str(')'), true,
112
- undefined, () => [[]], [3 | Backtrack.escbracket]),
114
+ undefined, () => new List(), [3 | Backtrack.escbracket]),
113
115
  surround(str('['), some(union([unsafehtmlentity, bracket, txt]), ']'), str(']'), true,
114
- undefined, () => [[]], [3 | Backtrack.escbracket]),
116
+ undefined, () => new List(), [3 | Backtrack.escbracket]),
115
117
  surround(str('{'), some(union([unsafehtmlentity, bracket, txt]), '}'), str('}'), true,
116
- undefined, () => [[]], [3 | Backtrack.escbracket]),
118
+ undefined, () => new List(), [3 | Backtrack.escbracket]),
117
119
  surround(str('"'), precedence(2, some(union([unsafehtmlentity, txt]), '"')), str('"'), true,
118
- undefined, () => [[]], [3 | Backtrack.escbracket]),
120
+ undefined, () => new List(), [3 | Backtrack.escbracket]),
119
121
  ])));
120
122
 
121
123
  const option: MediaParser.ParameterParser.OptionParser = lazy(() => union([
@@ -124,11 +126,10 @@ const option: MediaParser.ParameterParser.OptionParser = lazy(() => union([
124
126
  str(/[x:]/y),
125
127
  str(/[1-9][0-9]*(?=[ }])/y),
126
128
  false,
127
- ([[a], [b], [c]]) => [
129
+ ([[{ value: a }], [{ value: b }], [{ value: c }]]) =>
128
130
  b === 'x'
129
- ? [`width="${a}"`, `height="${c}"`]
130
- : [`aspect-ratio="${a}/${c}"`],
131
- ]),
131
+ ? new List([new Data(`width="${a}"`), new Data(`height="${c}"`)])
132
+ : new List([new Data(`aspect-ratio="${a}/${c}"`)])),
132
133
  linkoption,
133
134
  ]));
134
135
 
@@ -1,14 +1,13 @@
1
1
  import { ReferenceParser } from '../inline';
2
2
  import { State, Backtrack, Command } from '../context';
3
- import { eval } from '../../combinator/data/parser';
3
+ import { List, Data, eval } from '../../combinator/data/parser';
4
4
  import { union, subsequence, some, precedence, state, constraint, surround, isBacktrack, setBacktrack, lazy } from '../../combinator';
5
5
  import { inline } from '../inline';
6
6
  import { textlink } from './link';
7
7
  import { str } from '../source';
8
8
  import { trimBlankStart, trimBlankNodeEnd } from '../visibility';
9
+ import { unwrap, invalid } from '../util';
9
10
  import { html, defrag } from 'typed-dom/dom';
10
- import { unshift, push } from 'spica/array';
11
- import { invalid } from '../util';
12
11
 
13
12
  export const reference: ReferenceParser = lazy(() => constraint(State.reference, surround(
14
13
  str('[['),
@@ -22,7 +21,7 @@ export const reference: ReferenceParser = lazy(() => constraint(State.reference,
22
21
  ([, ns], context) => {
23
22
  const { position, range = 0, linebreak = 0 } = context;
24
23
  if (linebreak === 0) {
25
- return [[html('sup', attributes(ns), [html('span', defrag(trimBlankNodeEnd(ns)))])]];
24
+ return new List([new Data(html('sup', attributes(ns), [html('span', defrag(unwrap(trimBlankNodeEnd(ns))))]))]);
26
25
  }
27
26
  else {
28
27
  const head = position - range;
@@ -42,13 +41,13 @@ export const reference: ReferenceParser = lazy(() => constraint(State.reference,
42
41
  else {
43
42
  assert(source[position] === ']');
44
43
  if (state & State.annotation) {
45
- push(bs, [source[position]]);
44
+ bs.push(new Data(source[position]));
46
45
  }
47
46
  context.position += 1;
48
47
  let result: ReturnType<typeof textlink>;
49
48
  if (source[context.position] !== '{') {
50
49
  setBacktrack(context, [2 | Backtrack.link], head + 1);
51
- result = [[]];
50
+ result = new List();
52
51
  }
53
52
  else {
54
53
  result = !isBacktrack(context, [1 | Backtrack.link])
@@ -57,7 +56,7 @@ export const reference: ReferenceParser = lazy(() => constraint(State.reference,
57
56
  context.range = range;
58
57
  if (!result) {
59
58
  setBacktrack(context, [2 | Backtrack.link], head + 1);
60
- result = [[]];
59
+ result = new List();
61
60
  }
62
61
  }
63
62
  assert(result);
@@ -71,21 +70,21 @@ export const reference: ReferenceParser = lazy(() => constraint(State.reference,
71
70
  some(inline, ']', [[']', 1]]),
72
71
  str(']'),
73
72
  true,
74
- ([, cs = [], ds]) =>
75
- [push(cs, ds)],
76
- ([, cs = []]) => {
73
+ ([, cs = new List(), ds]) =>
74
+ cs.import(ds),
75
+ ([, cs = new List()]) => {
77
76
  setBacktrack(context, [2 | Backtrack.link], head);
78
- return [cs];
77
+ return cs;
79
78
  })
80
79
  ({ context });
81
80
  if (state & State.annotation && next) {
82
- return [push(push(unshift(as, bs), eval(result)), eval(next))];
81
+ return (as as List<Data<string | HTMLElement>>).import(bs).import(eval(result!)).import(eval(next));
83
82
  }
84
83
  }
85
84
  context.position = position;
86
85
  }
87
86
  return state & State.annotation
88
- ? [unshift(as, bs)]
87
+ ? as.import(bs as List<Data<string>>)
89
88
  : undefined;
90
89
  },
91
90
  [1 | Backtrack.bracket, 3 | Backtrack.doublebracket])));
@@ -98,22 +97,22 @@ const abbr: ReferenceParser.AbbrParser = surround(
98
97
  true,
99
98
  ([, ns], context) => {
100
99
  const { source, position, range = 0 } = context;
101
- if (!ns) return [['', source.slice(position - range, source[position - 1] === '|' ? position - 1 : position)]];
100
+ if (!ns) return new List([new Data(''), new Data(source.slice(position - range, source[position - 1] === '|' ? position - 1 : position))]);
102
101
  context.position += source[position] === ' ' ? 1 : 0;
103
- return [[Command.Separator, ns[0].trimEnd()]];
102
+ return new List([new Data(Command.Separator), new Data(ns.head!.value.trimEnd())]);
104
103
  },
105
104
  (_, context) => {
106
105
  context.position -= context.range!;
107
- return [['']];
106
+ return new List([new Data('')]);
108
107
  });
109
108
 
110
- function attributes(ns: (string | HTMLElement)[]): Record<string, string | undefined> {
111
- switch (ns[0]) {
109
+ function attributes(ns: List<Data<string | HTMLElement>>): Record<string, string | undefined> {
110
+ switch (ns.head!.value) {
112
111
  case '':
113
112
  return { class: 'invalid', ...invalid('reference', 'syntax', 'Invalid abbreviation') };
114
113
  case Command.Separator:
115
- const abbr = ns[1] as string;
116
- ns[0] = ns[1] = '';
114
+ const abbr = ns.head!.next!.value as string;
115
+ ns.head!.value = ns.head!.next!.value = '';
117
116
  return { class: 'reference', 'data-abbr': abbr };
118
117
  default:
119
118
  return { class: 'reference' };
@@ -1,10 +1,10 @@
1
1
  import { RemarkParser } from '../inline';
2
2
  import { Recursion } from '../context';
3
+ import { List, Data } from '../../combinator/data/parser';
3
4
  import { union, some, recursion, precedence, focus, surround, close, fallback, lazy } from '../../combinator';
4
5
  import { inline } from '../inline';
5
6
  import { text, str } from '../source';
6
- import { invalid } from '../util';
7
- import { unshift, push } from 'spica/array';
7
+ import { unwrap, invalid } from '../util';
8
8
  import { html, defrag } from 'typed-dom/dom';
9
9
 
10
10
  export const remark: RemarkParser = lazy(() => fallback(surround(
@@ -12,13 +12,13 @@ export const remark: RemarkParser = lazy(() => fallback(surround(
12
12
  precedence(3, recursion(Recursion.inline,
13
13
  some(union([inline]), /\s%\]/y, [[/\s%\]/y, 3]]))),
14
14
  close(text, str(`%]`)), true,
15
- ([as, bs = [], cs]) => [[
16
- html('span', { class: 'remark' }, [
15
+ ([as, bs = new List(), cs]) => new List([
16
+ new Data(html('span', { class: 'remark' }, [
17
17
  html('input', { type: 'checkbox' }),
18
- html('span', defrag(push(unshift(as, bs), cs))),
19
- ]),
20
- ]],
21
- ([as, bs]) => bs && [unshift(as, bs)]),
22
- focus(/\[%+(?=\s)/y, ({ context: { source } }) => [[
23
- html('span', { class: 'invalid', ...invalid('remark', 'syntax', 'Invalid start symbol') }, source)
24
- ]])));
18
+ html('span', defrag(unwrap(as.import(bs as List<Data<string>>).import(cs)))),
19
+ ])),
20
+ ]),
21
+ ([as, bs]) => bs && as.import(bs as List<Data<string>>)),
22
+ focus(/\[%+(?=\s)/y, ({ context: { source } }) => new List([
23
+ new Data(html('span', { class: 'invalid', ...invalid('remark', 'syntax', 'Invalid start symbol') }, source))
24
+ ]))));