securemark 0.293.5 → 0.294.1

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 +973 -617
  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 +4 -4
  7. package/src/combinator/control/constraint/line.test.ts +7 -7
  8. package/src/combinator/control/constraint/line.ts +2 -2
  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 -8
  15. package/src/combinator/control/manipulation/reverse.ts +2 -2
  16. package/src/combinator/control/manipulation/scope.ts +4 -7
  17. package/src/combinator/control/manipulation/surround.ts +16 -20
  18. package/src/combinator/control/monad/bind.ts +7 -8
  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 +8 -11
  24. package/src/combinator/data/parser/sequence.test.ts +3 -3
  25. package/src/combinator/data/parser/sequence.ts +8 -11
  26. package/src/combinator/data/parser/some.test.ts +3 -3
  27. package/src/combinator/data/parser/some.ts +7 -9
  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 +11 -20
  33. package/src/debug.test.ts +7 -6
  34. package/src/parser/api/bind.ts +8 -10
  35. package/src/parser/api/header.ts +2 -2
  36. package/src/parser/api/normalize.ts +2 -2
  37. package/src/parser/api/parse.ts +4 -2
  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 +24 -20
  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 +11 -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 +37 -28
  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/processor/note.ts +2 -2
  99. package/src/parser/segment.ts +5 -3
  100. package/src/parser/source/escapable.ts +9 -8
  101. package/src/parser/source/line.ts +9 -3
  102. package/src/parser/source/str.ts +3 -3
  103. package/src/parser/source/text.ts +9 -8
  104. package/src/parser/source/unescapable.ts +6 -5
  105. package/src/parser/util.ts +20 -15
  106. package/src/parser/visibility.ts +19 -20
@@ -1,12 +1,12 @@
1
- import { max, min, isArray } from 'spica/alias';
1
+ import { max, min } from 'spica/alias';
2
2
  import { ExtensionParser } from '../../block';
3
- import { Node, eval, input } from '../../../combinator/data/parser';
3
+ import { List, Data, subinput } from '../../../combinator/data/parser';
4
4
  import { union, subsequence, inits, some, block, line, validate, fence, rewrite, clear, surround, open, convert, dup, lazy, fmap } from '../../../combinator';
5
5
  import { inline, medialink, media, lineshortmedia } from '../../inline';
6
6
  import { str, anyline, emptyline, contentline } from '../../source';
7
- import { invalid } from '../../util';
7
+ import { unwrap, invalid } from '../../util';
8
8
  import { visualize, trimBlank, trimBlankEnd } from '../../visibility';
9
- import { unshift, splice } from 'spica/array';
9
+ import { splice } from 'spica/array';
10
10
  import { html, define, defrag } from 'typed-dom/dom';
11
11
 
12
12
  import TableParser = ExtensionParser.TableParser;
@@ -25,40 +25,49 @@ export const segment_: TableParser.SegmentParser = block(
25
25
  export const table: TableParser = block(fmap(
26
26
  fence(opener, 10000),
27
27
  // Bug: Type mismatch between outer and inner.
28
- ([body, overflow, closer, opener, delim, type, param]: string[], context) => {
29
- if (!closer || overflow || param.trimStart()) return [html('pre', {
30
- class: 'invalid',
31
- translate: 'no',
32
- ...invalid(
33
- 'table',
34
- !closer || overflow ? 'fence' : 'argument',
35
- !closer ? `Missing the closing delimiter "${delim}"` :
36
- overflow ? `Invalid trailing line after the closing delimiter "${delim}"` :
37
- 'Invalid argument'),
38
- }, `${opener}${body}${overflow || closer}`)];
28
+ (nodes: List<Data<string>>, context) => {
29
+ const [body, overflow, closer, opener, delim, type, param] = unwrap(nodes);
30
+ if (!closer || overflow || param.trimStart()) return new List([
31
+ new Data(html('pre', {
32
+ class: 'invalid',
33
+ translate: 'no',
34
+ ...invalid(
35
+ 'table',
36
+ !closer || overflow ? 'fence' : 'argument',
37
+ !closer ? `Missing the closing delimiter "${delim}"` :
38
+ overflow ? `Invalid trailing line after the closing delimiter "${delim}"` :
39
+ 'Invalid argument'),
40
+ }, `${opener}${body}${overflow || closer}`))
41
+ ]);
39
42
  switch (type) {
40
43
  case 'grid':
41
44
  case undefined:
42
- return (eval(parser(input(body, { ...context }))) ?? [html('table')])
43
- .map(el => define(el, { 'data-type': type }));
45
+ return (parser(subinput(body, context)) ?? new List([new Data(html('table'))]))
46
+ .foldl(
47
+ (acc, { value }) => acc.push(new Data(define(value, { 'data-type': type }))) && acc,
48
+ new List());
44
49
  default:
45
- return [html('pre', {
46
- class: 'invalid',
47
- translate: 'no',
48
- ...invalid('table', 'argument', 'Invalid table type'),
49
- }, `${opener}${body}${closer}`)];
50
+ return new List([
51
+ new Data(html('pre', {
52
+ class: 'invalid',
53
+ translate: 'no',
54
+ ...invalid('table', 'argument', 'Invalid table type'),
55
+ }, `${opener}${body}${closer}`))
56
+ ]);
50
57
  }
51
58
  }));
52
59
 
53
60
  const parser: TableParser = lazy(() => block(fmap(
54
61
  some(union([row])),
55
- rows => [html('table', format(rows))])));
62
+ rows => new List([
63
+ new Data(html('table', format([...unwrap(rows)])))
64
+ ]))));
56
65
 
57
66
  const row: RowParser = lazy(() => dup(fmap(
58
67
  subsequence([
59
- dup(union([
68
+ union([
60
69
  align,
61
- ])),
70
+ ]),
62
71
  some(union([
63
72
  head,
64
73
  data,
@@ -66,13 +75,13 @@ const row: RowParser = lazy(() => dup(fmap(
66
75
  emptyline,
67
76
  ])),
68
77
  ]),
69
- ns => !isArray(ns[0]) ? unshift([[[]]], ns) : ns)));
78
+ ns => Array.isArray(ns.head?.value) ? ns : ns.unshift(new Data([[]])) && ns)));
70
79
 
71
80
  const alignment = /[-=<>]+(?:\/[-=^v]*)?(?=[^\S\n]*\n)/y;
72
81
 
73
82
  const align: AlignParser = line(fmap(
74
83
  union([str(alignment)]),
75
- ([s]) => s.split('/').map(s => s.split(''))));
84
+ ([{ value }]) => new List([new Data(value.split('/').map(s => s.split('')) as [string[], string[]?])])));
76
85
 
77
86
  const delimiter = /[-=<>]+(?:\/[-=^v]*)?(?=[^\S\n]*\n)|[#:](?:(?!:\D|0)\d*:(?!0)\d*)?(?:!+[+]?)?(?=\s)/y;
78
87
 
@@ -91,11 +100,11 @@ const head: CellParser.HeadParser = block(fmap(open(
91
100
  media,
92
101
  lineshortmedia,
93
102
  ]),
94
- /\s*$/y)),
103
+ /[^\S\n]*(?:$|\n)/y)),
95
104
  open(/(?:[^\S\n]*\n|\s)/y, visualize(trimBlank(some(inline))), true),
96
105
  ])),
97
106
  true),
98
- ns => [html('th', attributes(ns.shift()! as string), defrag(ns))]),
107
+ ns => new List([new Data(html('th', attributes(ns.shift()!.value as string), defrag(unwrap(ns))))])),
99
108
  false);
100
109
 
101
110
  const data: CellParser.DataParser = block(fmap(open(
@@ -113,11 +122,11 @@ const data: CellParser.DataParser = block(fmap(open(
113
122
  media,
114
123
  lineshortmedia,
115
124
  ]),
116
- /\s*$/y)),
125
+ /[^\S\n]*(?:$|\n)/y)),
117
126
  open(/(?:[^\S\n]*\n|\s)/y, visualize(trimBlankEnd(some(inline))), true),
118
127
  ])),
119
128
  true),
120
- ns => [html('td', attributes(ns.shift()! as string), defrag(ns))]),
129
+ ns => new List([new Data(html('td', attributes(ns.shift()!.value as string), defrag(unwrap(ns))))])),
121
130
  false);
122
131
 
123
132
  const dataline: CellParser.DatalineParser = line(
@@ -157,7 +166,7 @@ function attributes(source: string): Record<string, string | undefined> {
157
166
  };
158
167
  }
159
168
 
160
- function format(rows: Node<RowParser>[]): HTMLTableSectionElement[] {
169
+ function format(rows: List<Data<[string[], string[]?] | HTMLTableCellElement>>[]): HTMLTableSectionElement[] {
161
170
  const thead = html('thead');
162
171
  const tbody = html('tbody');
163
172
  const tfoot = html('tfoot');
@@ -167,13 +176,11 @@ function format(rows: Node<RowParser>[]): HTMLTableSectionElement[] {
167
176
  let ranges: Record<number, Record<number, HTMLTableCellElement>> = {};
168
177
  let verticalHighlightExtensions = 0n;
169
178
  let verticalHighlightLevels: string[] = [];
170
- ROW:
171
- for (let i = 0; i < rows.length; ++i) {
179
+
180
+ let cnt = 0;
181
+ for (const list of rows) ROW: for (let i = cnt++; i < cnt; ++i) {
172
182
  // Copy to make them retryable.
173
- const [[[...as], [...vs] = []], ...cells] = rows[i];
174
- assert(as !== rows[i][0]?.[0]);
175
- assert(vs !== rows[i][0]?.[1]);
176
- assert(cells !== rows[i]);
183
+ const [{ value: [[...as], [...vs] = []] }, ...cells] = list as any as [Data<[string[], string[]?]>, ...Data<HTMLTableCellElement>[]];
177
184
  let isBody = target === tfoot
178
185
  ? false
179
186
  : undefined;
@@ -248,7 +255,7 @@ function format(rows: Node<RowParser>[]): HTMLTableSectionElement[] {
248
255
  const isVirtual = !!ranges[i]?.[j];
249
256
  const cell = isVirtual
250
257
  ? splice(cells, j, 0, undefined) && ranges[i][j]
251
- : cells[j];
258
+ : cells[j].value;
252
259
  const isHeadCell = cell.tagName === 'TH';
253
260
  heads |= isHeadCell ? 1n << jn : 0n;
254
261
  highlights |= cell.className === 'highlight' ? 1n << jn : 0n;
@@ -326,7 +333,7 @@ function format(rows: Node<RowParser>[]): HTMLTableSectionElement[] {
326
333
  const lHighlight = ~lHeadCellIndex && horizontalHighlights & 1n << lHeadCellIndex;
327
334
  const rHighlight = ~rHeadCellIndex && horizontalHighlights & 1n << rHeadCellIndex;
328
335
  for (let i = 0, m = 1n; i < cells.length; ++i, m <<= 1n) {
329
- const cell = cells[i];
336
+ const cell = cells[i]?.value;
330
337
  if (!cell) continue;
331
338
  if (heads & m) continue;
332
339
  assert(cell.tagName === 'TD');
@@ -1,16 +1,11 @@
1
- import { heading, segment } from './heading';
2
- import { input, eval } from '../../combinator/data/parser';
1
+ import { heading } from './heading';
2
+ import { input } from '../../combinator/data/parser';
3
3
  import { some } from '../../combinator';
4
4
  import { inspect } from '../../debug.test';
5
5
 
6
6
  describe('Unit: parser/block/heading', () => {
7
7
  describe('heading', () => {
8
- const parser = (source: string) => {
9
- const result = segment(input(source, ctx));
10
- return result
11
- ? [eval(result).flatMap(seg => eval<HTMLElement | string>(heading(input(seg, {})), [seg]))] as const
12
- : some(heading)(input(source, ctx));
13
- };
8
+ const parser = (source: string) => some(heading)(input(source, ctx));
14
9
  const { context: ctx } = input('', {});
15
10
 
16
11
  it('invalid', () => {
@@ -54,10 +49,6 @@ describe('Unit: parser/block/heading', () => {
54
49
  assert.deepStrictEqual(inspect(parser('# a[[b]]'), ctx), [['<h1 id="index::a[[b]]">a[[b]]</h1>'], '']);
55
50
  assert.deepStrictEqual(inspect(parser('## a[[b]]'), ctx), [['<h2 id="index::a[[b]]">a[[b]]</h2>'], '']);
56
51
  assert.deepStrictEqual(inspect(parser('###### a'), ctx), [['<h6 id="index::a">a</h6>'], '']);
57
- assert.deepStrictEqual(inspect(parser('# a\n##'), ctx), [['<h1 id="index::a">a</h1>', '##'], '']);
58
- assert.deepStrictEqual(inspect(parser('# a\n## '), ctx), [['<h1 id="index::a">a</h1>', '## '], '']);
59
- assert.deepStrictEqual(inspect(parser('# a\n## b'), ctx), [['<h1 id="index::a">a</h1>', '<h2 id="index::b">b</h2>'], '']);
60
- assert.deepStrictEqual(inspect(parser('# a\n##\n## b'), ctx), [['<h1 id="index::a">a</h1>', '##\n', '<h2 id="index::b">b</h2>'], '']);
61
52
  });
62
53
 
63
54
  it('indexer', () => {
@@ -1,15 +1,16 @@
1
1
  import { HeadingParser } from '../block';
2
2
  import { State } from '../context';
3
+ import { List, Data } from '../../combinator/data/parser';
3
4
  import { union, some, state, block, line, validate, focus, rewrite, open, fmap } from '../../combinator';
4
5
  import { inline, indexee, indexer, dataindex } from '../inline';
5
6
  import { str } from '../source';
6
7
  import { visualize, trimBlank } from '../visibility';
7
- import { invalid } from '../util';
8
+ import { unwrap, invalid } from '../util';
8
9
  import { html, defrag } from 'typed-dom/dom';
9
10
 
10
11
  export const segment: HeadingParser.SegmentParser = block(validate('#', focus(
11
12
  /#+[^\S\n]+\S[^\n]*(?:\n#+(?!\S)[^\n]*)*(?:$|\n)/y,
12
- some(line(({ context: { source } }) => [[source]])))));
13
+ some(line(({ context: { source } }) => new List([new Data(source)]))))));
13
14
 
14
15
  export const heading: HeadingParser = block(rewrite(segment,
15
16
  // その他の表示制御は各所のCSSで行う。
@@ -23,11 +24,14 @@ export const heading: HeadingParser = block(rewrite(segment,
23
24
  state(State.linkers,
24
25
  visualize(trimBlank(some(union([indexer, inline]))))), true),
25
26
  ]),
26
- ([h, ...ns]: [string, ...(HTMLElement | string)[]], context) => [
27
- h.length <= 6
28
- ? html(`h${h.length as 1}`, { 'data-index': dataindex(ns) }, defrag(ns))
29
- : html(`h6`, {
27
+ (nodes, context) => {
28
+ const [h, ...ns] = unwrap(nodes) as [string, ...(HTMLElement | string)[]];
29
+ return new List([
30
+ h.length <= 6
31
+ ? new Data(html(`h${h.length as 1}`, { 'data-index': dataindex(nodes) }, defrag(ns)))
32
+ : new Data(html(`h6`, {
30
33
  class: 'invalid',
31
34
  ...invalid('heading', 'syntax', 'Heading level must be up to 6'),
32
- }, context.source.slice(context.position - context.range!, context.position))
33
- ]))))));
35
+ }, context.source.slice(context.position - context.range!, context.position)))
36
+ ]);
37
+ }))))));
@@ -1,13 +1,14 @@
1
1
  import { IListParser } from '../block';
2
2
  import { Parser } from '../../combinator/data/parser';
3
3
  import { Recursion } from '../context';
4
+ import { List, Data } from '../../combinator/data/parser';
4
5
  import { union, inits, some, recursion, block, line, validate, indent, rewrite, open, fallback, lazy, fmap } from '../../combinator';
5
6
  import { ulist_, fillFirstLine } from './ulist';
6
7
  import { olist_ } from './olist';
7
8
  import { inline } from '../inline';
8
9
  import { contentline } from '../source';
9
10
  import { visualize, trimBlank } from '../visibility';
10
- import { invalid } from '../util';
11
+ import { unwrap, invalid } from '../util';
11
12
  import { html, defrag } from 'typed-dom/dom';
12
13
 
13
14
  export const ilist: IListParser = lazy(() => block(validate(
@@ -23,21 +24,21 @@ export const ilist_: IListParser = lazy(() => block(fmap(validate(
23
24
  indent(union([ulist_, olist_, ilist_])),
24
25
  ]),
25
26
  ilistitem),
26
- ns => [html('li', defrag(fillFirstLine(ns)))]),
27
+ ns => new List([new Data(html('li', defrag(unwrap(fillFirstLine(ns)))))])),
27
28
  ])))),
28
- es => [
29
- html('ul', {
29
+ ns => new List([
30
+ new Data(html('ul', {
30
31
  class: 'invalid',
31
32
  ...invalid('list', 'syntax', 'Use "-" instead of "+" or "*"'),
32
- }, es),
33
- ])));
33
+ }, unwrap(ns))),
34
+ ]))));
34
35
 
35
36
  export const ilistitem = rewrite(
36
- inits([contentline, indent<Parser<string>>(({ context: { source } }) => [[source]])]),
37
- ({ context: { source } }) => [[
38
- '',
39
- html('span', {
37
+ inits([contentline, indent<Parser<string>>(({ context: { source } }) => new List([new Data(source)]))]),
38
+ ({ context: { source } }) => new List([
39
+ new Data(''),
40
+ new Data(html('span', {
40
41
  class: 'invalid',
41
42
  ...invalid('list', 'syntax', 'Fix the indent or the head of the list item'),
42
- }, source.replace('\n', ''))
43
- ]]);
43
+ }, source.replace('\n', '')))
44
+ ]));
@@ -1,6 +1,7 @@
1
1
  import { MathBlockParser } from '../block';
2
+ import { List, Data } from '../../combinator/data/parser';
2
3
  import { block, fence, clear, fmap } from '../../combinator';
3
- import { invalid } from '../util';
4
+ import { unwrap, invalid } from '../util';
4
5
  import { html } from 'typed-dom/dom';
5
6
 
6
7
  const opener = /(\${2,})(?!\$)([^\n]*)(?:$|\n)/y;
@@ -14,19 +15,22 @@ export const segment_: MathBlockParser.SegmentParser = block(
14
15
  export const mathblock: MathBlockParser = block(fmap(
15
16
  fence(opener, 300),
16
17
  // Bug: Type mismatch between outer and inner.
17
- ([body, overflow, closer, opener, delim, param]: string[], { caches: { math: cache = undefined } = {} }) => [
18
- delim.length === 2 && closer && !overflow && param.trimStart() === ''
19
- ? cache?.get(`${delim}\n${body}${delim}`)?.cloneNode(true) as HTMLDivElement ||
20
- html('div', { class: 'math', translate: 'no' }, `${delim}\n${body}${delim}`)
21
- : html('pre', {
22
- class: 'invalid',
23
- translate: 'no',
24
- ...invalid(
25
- 'mathblock',
26
- delim.length > 2 ? 'syntax' : !closer || overflow ? 'fence' : 'argument',
27
- delim.length > 2 ? 'Invalid syntax' :
28
- !closer ? `Missing the closing delimiter "${delim}"` :
29
- overflow ? `Invalid trailing line after the closing delimiter "${delim}"` :
30
- 'Invalid argument'),
31
- }, `${opener}${body}${overflow || closer}`),
32
- ]));
18
+ (nodes, { caches: { math: cache = undefined } = {} }) => {
19
+ const [body, overflow, closer, opener, delim, param] = unwrap<string>(nodes);
20
+ return new List([
21
+ delim.length === 2 && closer && !overflow && param.trimStart() === ''
22
+ ? new Data(cache?.get(`${delim}\n${body}${delim}`)?.cloneNode(true) as HTMLDivElement ||
23
+ html('div', { class: 'math', translate: 'no' }, `${delim}\n${body}${delim}`))
24
+ : new Data(html('pre', {
25
+ class: 'invalid',
26
+ translate: 'no',
27
+ ...invalid(
28
+ 'mathblock',
29
+ delim.length > 2 ? 'syntax' : !closer || overflow ? 'fence' : 'argument',
30
+ delim.length > 2 ? 'Invalid syntax' :
31
+ !closer ? `Missing the closing delimiter "${delim}"` :
32
+ overflow ? `Invalid trailing line after the closing delimiter "${delim}"` :
33
+ 'Invalid argument'),
34
+ }, `${opener}${body}${overflow || closer}`)),
35
+ ]);
36
+ }));
@@ -1,7 +1,8 @@
1
1
  import { MediaBlockParser } from '../block';
2
+ import { List, Data } from '../../combinator/data/parser';
2
3
  import { union, inits, some, block, line, fallback, fmap } from '../../combinator';
3
4
  import { medialink, media, lineshortmedia } from '../inline';
4
- import { invalid } from '../util';
5
+ import { unwrap, invalid } from '../util';
5
6
  import { html } from 'typed-dom/dom';
6
7
 
7
8
  export const mediablock: MediaBlockParser = block(fmap(
@@ -15,9 +16,10 @@ export const mediablock: MediaBlockParser = block(fmap(
15
16
  medialink,
16
17
  media,
17
18
  lineshortmedia,
18
- ]), ({ context: { source } }) => [[html('span', {
19
+ ]), ({ context: { source } }) => new List([
20
+ new Data(html('span', {
19
21
  class: 'invalid',
20
22
  ...invalid('mediablock', 'syntax', 'Not media syntax'),
21
- }, source.replace('\n', ''))]]))),
22
- ]),
23
- ns => [html('div', ns)]));
23
+ }, source.replace('\n', '')))
24
+ ]))))]),
25
+ ns => new List([new Data(html('div', unwrap(ns)))])));
@@ -1,10 +1,11 @@
1
1
  import { OListParser } from '../block';
2
2
  import { Recursion } from '../context';
3
+ import { List, Data } from '../../combinator/data/parser';
3
4
  import { union, inits, subsequence, some, recursion, block, line, validate, indent, focus, open, match, fallback, lazy, fmap } from '../../combinator';
4
5
  import { ulist_, checkbox, fillFirstLine } from './ulist';
5
6
  import { ilist_, ilistitem } from './ilist';
6
7
  import { inline, indexee, indexer, dataindex } from '../inline';
7
- import { invalid } from '../util';
8
+ import { invalid, unwrap } from '../util';
8
9
  import { visualize, trimBlank } from '../visibility';
9
10
  import { memoize } from 'spica/memoize';
10
11
  import { html, define, defrag } from 'typed-dom/dom';
@@ -40,17 +41,26 @@ const list = (type: string, form: string): OListParser.ListParser => fmap(
40
41
  indent(union([ulist_, olist_, ilist_])),
41
42
  ]),
42
43
  ilistitem),
43
- ns => [html('li', { 'data-index': dataindex(ns), 'data-marker': ns.shift() as string || undefined }, defrag(fillFirstLine(ns)))])),
44
+ ns => new List([
45
+ new Data(html('li', {
46
+ 'data-index': dataindex(ns),
47
+ 'data-marker': ns.shift()?.value as string || undefined,
48
+ }, defrag(unwrap(fillFirstLine(ns)))))
49
+ ]))),
44
50
  ]))),
45
- es => [format(html('ol', es), type, form)]);
51
+ ns => new List([new Data(format(html('ol', unwrap(ns)), type, form))]));
46
52
 
47
53
  const heads = {
48
54
  '.': focus(
49
55
  openers['.'],
50
- ({ context: { source } }) => [[source.trimEnd().split('.', 1)[0] + '.']]),
56
+ ({ context: { source } }) => new List([
57
+ new Data(source.trimEnd().split('.', 1)[0] + '.')
58
+ ])),
51
59
  '(': focus(
52
60
  openers['('],
53
- ({ context: { source } }) => [[source.trimEnd().replace(/^\($/, '(1)').replace(/^\((\w+)$/, '($1)')]]),
61
+ ({ context: { source } }) => new List([
62
+ new Data(source.trimEnd().replace(/^\($/, '(1)').replace(/^\((\w+)$/, '($1)'))
63
+ ])),
54
64
  } as const;
55
65
 
56
66
  function idx(value: string): number {
@@ -1,7 +1,8 @@
1
1
  import { PagebreakParser } from '../block';
2
+ import { List, Data } from '../../combinator/data/parser';
2
3
  import { block, line, focus } from '../../combinator';
3
4
  import { html } from 'typed-dom/dom';
4
5
 
5
6
  export const pagebreak: PagebreakParser = block(line(focus(
6
7
  /={3,}[^\S\n]*(?:$|\n)/y,
7
- () => [[html('hr')]])));
8
+ () => new List([new Data(html('hr'))]))));
@@ -1,9 +1,11 @@
1
1
  import { ParagraphParser } from '../block';
2
+ import { List, Data } from '../../combinator/data/parser';
2
3
  import { union, some, block, fmap } from '../../combinator';
3
4
  import { inline } from '../inline';
4
5
  import { visualize, trimBlankEnd } from '../visibility';
6
+ import { unwrap } from '../util';
5
7
  import { html, defrag } from 'typed-dom/dom';
6
8
 
7
9
  export const paragraph: ParagraphParser = block(fmap(
8
10
  visualize(trimBlankEnd(some(union([inline])))),
9
- ns => [html('p', defrag(ns))]));
11
+ ns => new List([new Data(html('p', defrag(unwrap(ns))))])));
@@ -1,4 +1,5 @@
1
1
  import { ReplyParser } from '../../block';
2
+ import { List, Data } from '../../../combinator/data/parser';
2
3
  import { union, line, focus, open, fmap } from '../../../combinator';
3
4
  import { anchor } from '../../inline/autolink/anchor';
4
5
  import { str } from '../../source';
@@ -14,20 +15,24 @@ export const cite: ReplyParser.CiteParser = line(fmap(
14
15
  anchor,
15
16
  // Subject page representation.
16
17
  // リンクの実装は後で検討
17
- focus(/>>#\S*(?=\s*$)/y, ({ context: { source } }) => [[html('a', { class: 'anchor' }, source)]]),
18
- focus(/>>https?:\/\/\S+(?=\s*$)/y, ({ context: { source } }) => [[html('a', { class: 'anchor', href: source.slice(2).trimEnd(), target: '_blank' }, source)]]),
19
- focus(/>>.+(?=\s*$)/y, ({ context: { source } }) => [[source]]),
18
+ focus(/>>#\S*(?=\s*$)/y, ({ context: { source } }) => new List([new Data(html('a', { class: 'anchor' }, source))])),
19
+ focus(/>>https?:\/\/\S+(?=\s*$)/y, ({ context: { source } }) => new List([new Data(html('a', { class: 'anchor', href: source.slice(2).trimEnd(), target: '_blank' }, source))])),
20
+ focus(/>>.+(?=\s*$)/y, ({ context: { source } }) => new List([new Data(source)])),
20
21
  ])),
21
- ([quotes, node]: [string, HTMLElement | string]) => [
22
- html('span',
23
- typeof node === 'object'
24
- ? { class: 'cite' }
25
- : { class: 'cite invalid', ...invalid('cite', 'syntax', 'Invalid syntax') },
26
- defrag([
27
- `${quotes}>`,
22
+ nodes => {
23
+ const quotes = nodes.head!.value as string;
24
+ const node = nodes.last!.value;
25
+ return new List([
26
+ new Data(html('span',
28
27
  typeof node === 'object'
29
- ? define(node, { 'data-depth': `${quotes.length + 1}` }, node.innerText.slice(1))
30
- : node.slice(1),
31
- ])),
32
- html('br'),
33
- ]));
28
+ ? { class: 'cite' }
29
+ : { class: 'cite invalid', ...invalid('cite', 'syntax', 'Invalid syntax') },
30
+ defrag([
31
+ `${quotes}>`,
32
+ typeof node === 'object'
33
+ ? define(node, { 'data-depth': `${quotes.length + 1}` }, node.innerText.slice(1))
34
+ : node.slice(1),
35
+ ]))),
36
+ new Data(html('br')),
37
+ ]);
38
+ }));
@@ -1,8 +1,10 @@
1
1
  import { ReplyParser } from '../../block';
2
+ import { List, Data } from '../../../combinator/data/parser';
2
3
  import { union, some, block, validate, rewrite, convert, lazy, fmap } from '../../../combinator';
3
4
  import { math } from '../../inline/math';
4
5
  import { autolink } from '../../inline/autolink';
5
6
  import { linebreak, unescsource, anyline } from '../../source';
7
+ import { unwrap } from '../../util';
6
8
  import { html, defrag } from 'typed-dom/dom';
7
9
 
8
10
  export const syntax = />+[^\S\n]/y;
@@ -21,8 +23,8 @@ export const quote: ReplyParser.QuoteParser = lazy(() => block(fmap(
21
23
  unescsource,
22
24
  ])),
23
25
  false)),
24
- (ns: [string, ...(string | HTMLElement)[]], { source, position }) => [
25
- source[position - 1] === '\n' ? ns.pop() as HTMLBRElement : html('br'),
26
- html('span', { class: 'quote' }, defrag(ns)),
27
- ].reverse()),
26
+ (ns, { source, position }) => new List([
27
+ new Data(source[position - 1] === '\n' ? ns.pop()!.value as HTMLBRElement : html('br')),
28
+ new Data(html('span', { class: 'quote' }, defrag(unwrap(ns)))),
29
+ ].reverse())),
28
30
  false));
@@ -1,11 +1,12 @@
1
1
  import { ReplyParser } from '../block';
2
+ import { List, Data } from '../../combinator/data/parser';
2
3
  import { union, some, block, validate, rewrite, fmap } from '../../combinator';
3
4
  import { cite, syntax as csyntax } from './reply/cite';
4
5
  import { quote, syntax as qsyntax } from './reply/quote';
5
6
  import { inline } from '../inline';
6
7
  import { anyline } from '../source';
7
8
  import { visualize, trimBlankNodeEnd } from '../visibility';
8
- import { push } from 'spica/array';
9
+ import { unwrap } from '../util';
9
10
  import { html, defrag } from 'typed-dom/dom';
10
11
 
11
12
  const delimiter = new RegExp(`${csyntax.source}|${qsyntax.source}`, 'y');
@@ -17,6 +18,8 @@ export const reply: ReplyParser = block(validate(csyntax, fmap(
17
18
  rewrite(
18
19
  some(anyline, delimiter),
19
20
  visualize(fmap(some(inline), (ns, { source, position }) =>
20
- source[position - 1] === '\n' ? ns : push(ns, [html('br')])))),
21
+ source[position - 1] === '\n'
22
+ ? ns
23
+ : ns.push(new Data(html('br'))) && ns)))
21
24
  ])),
22
- ns => [html('p', trimBlankNodeEnd(defrag(ns)))])));
25
+ ns => new List([new Data(html('p', defrag(unwrap(trimBlankNodeEnd(ns)))))]))));
@@ -1,20 +1,21 @@
1
1
  import { SidefenceParser } from '../block';
2
2
  import { Recursion } from '../context';
3
+ import { List, Data } from '../../combinator/data/parser';
3
4
  import { union, some, recursion, block, focus, rewrite, convert, lazy, fmap } from '../../combinator';
4
5
  import { autolink } from '../autolink';
5
6
  import { contentline } from '../source';
6
- import { invalid } from '../util';
7
+ import { unwrap, invalid } from '../util';
7
8
  import { html, define, defrag } from 'typed-dom/dom';
8
9
 
9
10
  export const sidefence: SidefenceParser = lazy(() => block(fmap(focus(
10
11
  /(?=\|+(?:[^\S\n]|\n\|))(?:\|+(?:[^\S\n][^\n]*)?(?:$|\n))+$/y,
11
12
  union([source])),
12
- ([el]) => [
13
- define(el, {
13
+ ([{ value }]) => new List([
14
+ new Data(define(value, {
14
15
  class: 'invalid',
15
16
  ...invalid('sidefence', 'syntax', 'Reserved syntax'),
16
- }),
17
- ])));
17
+ })),
18
+ ]))));
18
19
 
19
20
  const opener = /(?=\|\|+(?:$|\s))/y;
20
21
  const unindent = (source: string) => source.replace(/(?<=^|\n)\|(?:[^\S\n]|(?=\|*(?:$|\s)))|\n$/g, '');
@@ -26,6 +27,6 @@ const source: SidefenceParser.SourceParser = lazy(() => fmap(
26
27
  convert(unindent, source, false, true)),
27
28
  rewrite(
28
29
  some(contentline, opener),
29
- convert(unindent, fmap(autolink, ns => [html('pre', defrag(ns))]), false, true)),
30
+ convert(unindent, fmap(autolink, ns => new List([new Data(html('pre', defrag(unwrap(ns))))])), false, true)),
30
31
  ]))),
31
- ns => [html('blockquote', ns)]));
32
+ ns => new List([new Data(html('blockquote', unwrap(ns)))])));