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,25 +1,29 @@
1
1
  import { ExtensionParser } from '../../block';
2
2
  import { Recursion } from '../../context';
3
+ import { List, Data } from '../../../combinator/data/parser';
3
4
  import { recursion, block, fence, fmap } from '../../../combinator';
4
5
  import { identity } from '../../inline/extension/indexee';
5
- import { invalid } from '../../util';
6
+ import { unwrap, invalid } from '../../util';
6
7
  import { parse } from '../../api/parse';
7
8
  import { html } from 'typed-dom/dom';
8
9
 
9
10
  export const aside: ExtensionParser.AsideParser = recursion(Recursion.block, block(fmap(
10
11
  fence(/(~{3,})aside(?!\S)([^\n]*)(?:$|\n)/y, 300),
11
12
  // Bug: Type mismatch between outer and inner.
12
- ([body, overflow, closer, opener, delim, param]: string[], context) => {
13
- if (!closer || overflow || param.trimStart()) return [html('pre', {
14
- class: 'invalid',
15
- translate: 'no',
16
- ...invalid(
17
- 'aside',
18
- !closer || overflow ? 'fence' : 'argument',
19
- !closer ? `Missing the closing delimiter "${delim}"` :
20
- overflow ? `Invalid trailing line after the closing delimiter "${delim}"` :
21
- 'Invalid argument'),
22
- }, `${opener}${body}${overflow || closer}`)];
13
+ (nodes: List<Data<string>>, context) => {
14
+ const [body, overflow, closer, opener, delim, param] = unwrap(nodes);
15
+ if (!closer || overflow || param.trimStart()) return new List([
16
+ new Data(html('pre', {
17
+ class: 'invalid',
18
+ translate: 'no',
19
+ ...invalid(
20
+ 'aside',
21
+ !closer || overflow ? 'fence' : 'argument',
22
+ !closer ? `Missing the closing delimiter "${delim}"` :
23
+ overflow ? `Invalid trailing line after the closing delimiter "${delim}"` :
24
+ 'Invalid argument'),
25
+ }, `${opener}${body}${overflow || closer}`))
26
+ ]);
23
27
  const references = html('ol', { class: 'references' });
24
28
  const document = parse(body.slice(0, -1), {
25
29
  id: '',
@@ -29,17 +33,19 @@ export const aside: ExtensionParser.AsideParser = recursion(Recursion.block, blo
29
33
  }, context);
30
34
  assert(!document.querySelector('[id]'));
31
35
  const heading = 'H1 H2 H3 H4 H5 H6'.split(' ').includes(document.firstElementChild?.tagName!) && document.firstElementChild as HTMLHeadingElement;
32
- if (!heading) return [html('pre', {
33
- class: 'invalid',
34
- translate: 'no',
35
- ...invalid('aside', 'content', 'Missing the title at the first line'),
36
- }, `${opener}${body}${closer}`)];
36
+ if (!heading) return new List([
37
+ new Data(html('pre', {
38
+ class: 'invalid',
39
+ translate: 'no',
40
+ ...invalid('aside', 'content', 'Missing the title at the first line'),
41
+ }, `${opener}${body}${closer}`))
42
+ ]);
37
43
  assert(identity('index', context.id, heading));
38
- return [
39
- html('aside', { id: identity('index', context.id, heading), class: 'aside' }, [
44
+ return new List([
45
+ new Data(html('aside', { id: identity('index', context.id, heading), class: 'aside' }, [
40
46
  document,
41
47
  html('h2', 'References'),
42
48
  references,
43
- ]),
44
- ];
49
+ ]))
50
+ ]);
45
51
  })));
@@ -1,9 +1,9 @@
1
1
  import { ExtensionParser } from '../../block';
2
2
  import { Recursion } from '../../context';
3
- import { input, eval } from '../../../combinator/data/parser';
3
+ import { List, Data, subinput, eval } from '../../../combinator/data/parser';
4
4
  import { recursion, block, fence, fmap } from '../../../combinator';
5
5
  import { mathblock } from '../mathblock';
6
- import { invalid } from '../../util';
6
+ import { unwrap, invalid } from '../../util';
7
7
  import { parse } from '../../api/parse';
8
8
  import { html } from 'typed-dom/dom';
9
9
 
@@ -12,17 +12,20 @@ const opener = /(~{3,})(?:example\/(\S+))?(?!\S)([^\n]*)(?:$|\n)/y;
12
12
  export const example: ExtensionParser.ExampleParser = recursion(Recursion.block, block(fmap(
13
13
  fence(opener, 300),
14
14
  // Bug: Type mismatch between outer and inner.
15
- ([body, overflow, closer, opener, delim, type = 'markdown', param]: string[], context) => {
16
- if (!closer || overflow || param.trimStart()) return [html('pre', {
17
- class: 'invalid',
18
- translate: 'no',
19
- ...invalid(
20
- 'example',
21
- !closer || overflow ? 'fence' : 'argument',
22
- !closer ? `Missing the closing delimiter "${delim}"` :
23
- overflow ? `Invalid trailing line after the closing delimiter "${delim}"` :
24
- 'Invalid argument'),
25
- }, `${opener}${body}${overflow || closer}`)];
15
+ (nodes: List<Data<string>>, context) => {
16
+ const [body, overflow, closer, opener, delim, type = 'markdown', param] = unwrap(nodes);
17
+ if (!closer || overflow || param.trimStart()) return new List([
18
+ new Data(html('pre', {
19
+ class: 'invalid',
20
+ translate: 'no',
21
+ ...invalid(
22
+ 'example',
23
+ !closer || overflow ? 'fence' : 'argument',
24
+ !closer ? `Missing the closing delimiter "${delim}"` :
25
+ overflow ? `Invalid trailing line after the closing delimiter "${delim}"` :
26
+ 'Invalid argument'),
27
+ }, `${opener}${body}${overflow || closer}`))
28
+ ]);
26
29
  switch (type) {
27
30
  case 'markdown': {
28
31
  const references = html('ol', { class: 'references' });
@@ -33,29 +36,29 @@ export const example: ExtensionParser.ExampleParser = recursion(Recursion.block,
33
36
  },
34
37
  }, context);
35
38
  assert(!document.querySelector('[id]'));
36
- return [
37
- html('aside', { class: 'example', 'data-type': 'markdown' }, [
39
+ return new List([
40
+ new Data(html('aside', { class: 'example', 'data-type': 'markdown' }, [
38
41
  html('pre', { translate: 'no' }, body.slice(0, -1)),
39
42
  html('hr'),
40
43
  html('section', [document, html('h2', 'References'), references]),
41
- ]),
42
- ];
44
+ ])),
45
+ ]);
43
46
  }
44
47
  case 'math':
45
- return [
46
- html('aside', { class: 'example', 'data-type': 'math' }, [
48
+ return new List([
49
+ new Data(html('aside', { class: 'example', 'data-type': 'math' }, [
47
50
  html('pre', { translate: 'no' }, body.slice(0, -1)),
48
51
  html('hr'),
49
- eval(mathblock(input(`$$\n${body}$$`, { ...context })), [])[0],
50
- ]),
51
- ];
52
+ eval(mathblock(subinput(`$$\n${body}$$`, context)))!.head!.value,
53
+ ])),
54
+ ]);
52
55
  default:
53
- return [
54
- html('pre', {
56
+ return new List([
57
+ new Data(html('pre', {
55
58
  class: 'invalid',
56
59
  translate: 'no',
57
60
  ...invalid('example', 'type', 'Invalid example type'),
58
- }, `${opener}${body}${closer}`),
59
- ];
61
+ }, `${opener}${body}${closer}`)),
62
+ ]);
60
63
  }
61
64
  })));
@@ -36,7 +36,7 @@ export const fig: FigParser = block(rewrite(segment, verify(convert(
36
36
  },
37
37
  union([figure]),
38
38
  false),
39
- ([el]) => el.tagName === 'FIGURE')));
39
+ ([{ value: el }]) => el.tagName === 'FIGURE')));
40
40
 
41
41
  const parser = sequence([
42
42
  line(close(seg_label, /(?=\s).*\n/y)),
@@ -1,4 +1,5 @@
1
1
  import { ExtensionParser } from '../../block';
2
+ import { List, Data } from '../../../combinator/data/parser';
2
3
  import { union, block, line, validate, fmap } from '../../../combinator';
3
4
  import { label } from '../../inline/extension/label';
4
5
  import { html } from 'typed-dom/dom';
@@ -6,14 +7,14 @@ import { html } from 'typed-dom/dom';
6
7
  export const figbase: ExtensionParser.FigbaseParser = block(fmap(
7
8
  validate(/\[?\$-(?:[0-9]+\.)*0\]?[^\S\n]*(?!\S|\n[^\S\n]*\S)/y,
8
9
  line(union([label]))),
9
- ([el]) => {
10
+ ([{ value: el }]) => {
10
11
  const label = el.getAttribute('data-label')!;
11
12
  const group = label.split('-', 1)[0];
12
- return [
13
- html('figure', {
13
+ return new List([
14
+ new Data(html('figure', {
14
15
  'data-label': label,
15
16
  'data-group': group,
16
17
  hidden: '',
17
- }),
18
- ];
18
+ })),
19
+ ]);
19
20
  }));
@@ -1,5 +1,5 @@
1
1
  import { ExtensionParser } from '../../block';
2
- import { input } from '../../../combinator/data/parser';
2
+ import { List, Data, subinput } from '../../../combinator/data/parser';
3
3
  import { union, inits, sequence, some, block, line, fence, rewrite, close, match, convert, fallback, fmap } from '../../../combinator';
4
4
  import { str, contentline, emptyline } from '../../source';
5
5
  import { label, segment as seg_label } from '../../inline/extension/label';
@@ -14,7 +14,7 @@ import { blockquote, segment as seg_blockquote } from '../blockquote';
14
14
  import { placeholder, segment_ as seg_placeholder } from './placeholder';
15
15
  import { inline, media, lineshortmedia } from '../../inline';
16
16
  import { visualize, trimBlank } from '../../visibility';
17
- import { invalid } from '../../util';
17
+ import { unwrap, invalid } from '../../util';
18
18
  import { memoize } from 'spica/memoize';
19
19
  import { html, defrag } from 'typed-dom/dom';
20
20
 
@@ -68,20 +68,24 @@ export const figure: FigureParser = block(fallback(rewrite(segment, fmap(
68
68
  block(visualize(trimBlank(some(inline)))),
69
69
  ]),
70
70
  ]), false),
71
- ([label, param, content, ...caption]: [HTMLAnchorElement, string, ...HTMLElement[]]) => [
72
- html('figure',
73
- attributes(label.getAttribute('data-label')!, param, content, caption),
74
- [
75
- html('figcaption', [
76
- html('span', { class: 'figindex' }),
77
- html('span', { class: 'figtext' }, defrag(caption)),
78
- ]),
79
- html('div', [content]),
80
- ])
81
- ])),
71
+ nodes => {
72
+ const [label, param, content, ...caption] = unwrap(nodes) as [HTMLAnchorElement, string, ...HTMLElement[]];
73
+ return new List([
74
+ new Data(html('figure',
75
+ attributes(label.getAttribute('data-label')!, param, content, caption),
76
+ [
77
+ html('figcaption', [
78
+ html('span', { class: 'figindex' }),
79
+ html('span', { class: 'figtext' }, defrag(caption)),
80
+ ]),
81
+ html('div', [content]),
82
+ ]))
83
+ ]);
84
+ })),
82
85
  fmap(
83
86
  fence(/(~{3,})(?:figure|\[?\$\S*)(?!\S)[^\n]*(?:$|\n)/y, 300),
84
- ([body, overflow, closer, opener, delim]: string[], context) => {
87
+ (nodes, context) => {
88
+ const [body, overflow, closer, opener, delim] = unwrap<string>(nodes);
85
89
  const violation =
86
90
  !closer && [
87
91
  'fence',
@@ -91,7 +95,7 @@ export const figure: FigureParser = block(fallback(rewrite(segment, fmap(
91
95
  'fence',
92
96
  `Invalid trailing line after the closing delimiter "${delim}"`,
93
97
  ] ||
94
- !seg_label(input(opener.match(/^~+(?:figure[^\S\n]+)?(\[?\$\S+)/)?.[1] ?? '', { ...context })) && [
98
+ !seg_label(subinput(opener.match(/^~+(?:figure[^\S\n]+)?(\[?\$\S+)/)?.[1] ?? '', context)) && [
95
99
  'label',
96
100
  'Invalid label',
97
101
  ] ||
@@ -103,13 +107,13 @@ export const figure: FigureParser = block(fallback(rewrite(segment, fmap(
103
107
  'content',
104
108
  'Invalid content',
105
109
  ];
106
- return [
107
- html('pre', {
110
+ return new List([
111
+ new Data(html('pre', {
108
112
  class: 'invalid',
109
113
  translate: 'no',
110
114
  ...invalid('figure', violation[0], violation[1]),
111
- }, `${opener}${body}${overflow || closer}`),
112
- ];
115
+ }, `${opener}${body}${overflow || closer}`)),
116
+ ]);
113
117
  })));
114
118
 
115
119
  function attributes(label: string, param: string, content: HTMLElement, caption: readonly HTMLElement[]): Record<string, string | undefined> {
@@ -1,5 +1,5 @@
1
1
  import { ExtensionParser } from '../../block';
2
- import { input, eval } from '../../../combinator/data/parser';
2
+ import { List, Data, subinput, eval } from '../../../combinator/data/parser';
3
3
  import { union, block, fence, fmap } from '../../../combinator';
4
4
  import { segment } from '../../segment';
5
5
  import { emptyline } from '../../source';
@@ -13,8 +13,8 @@ import { sidefence } from '../sidefence';
13
13
  import { blockquote } from '../blockquote';
14
14
  import { mediablock } from '../mediablock';
15
15
  import { paragraph } from '../paragraph';
16
- import { invalid } from '../../util';
17
- import { unshift, push } from 'spica/array';
16
+ import { unwrap, invalid } from '../../util';
17
+ import { push } from 'spica/array';
18
18
  import { html } from 'typed-dom/dom';
19
19
 
20
20
  import MessageParser = ExtensionParser.MessageParser;
@@ -22,34 +22,45 @@ import MessageParser = ExtensionParser.MessageParser;
22
22
  export const message: MessageParser = block(fmap(
23
23
  fence(/(~{3,})message\/(\S+)([^\n]*)(?:$|\n)/y, 300),
24
24
  // Bug: Type mismatch between outer and inner.
25
- ([body, overflow, closer, opener, delim, type, param]: string[], context) => {
26
- if (!closer || overflow || param.trimStart()) return [html('pre', {
27
- class: 'invalid',
28
- translate: 'no',
29
- ...invalid(
30
- 'message',
31
- !closer || overflow ? 'fence' : 'argument',
32
- !closer ? `Missing the closing delimiter "${delim}"` :
33
- overflow ? `Invalid trailing line after the closing delimiter "${delim}"` :
34
- 'Invalid argument'),
35
- }, `${opener}${body}${overflow || closer}`)];
25
+ (nodes: List<Data<string>>, context) => {
26
+ const [body, overflow, closer, opener, delim, type, param] = unwrap(nodes);
27
+ if (!closer || overflow || param.trimStart()) return new List([
28
+ new Data(html('pre', {
29
+ class: 'invalid',
30
+ translate: 'no',
31
+ ...invalid(
32
+ 'message',
33
+ !closer || overflow ? 'fence' : 'argument',
34
+ !closer ? `Missing the closing delimiter "${delim}"` :
35
+ overflow ? `Invalid trailing line after the closing delimiter "${delim}"` :
36
+ 'Invalid argument'),
37
+ }, `${opener}${body}${overflow || closer}`))
38
+ ]);
36
39
  switch (type) {
37
40
  case 'note':
38
41
  case 'caution':
39
42
  case 'warning':
40
43
  break;
41
44
  default:
42
- return [html('pre', {
43
- class: 'invalid',
44
- translate: 'no',
45
- ...invalid('message', 'type', 'Invalid message type'),
46
- }, `${opener}${body}${closer}`)];
45
+ return new List([
46
+ new Data(html('pre', {
47
+ class: 'invalid',
48
+ translate: 'no',
49
+ ...invalid('message', 'type', 'Invalid message type'),
50
+ }, `${opener}${body}${closer}`))
51
+ ]);
47
52
  }
48
- return [
49
- html('section', { class: `message`, 'data-type': type }, unshift(
50
- [html('h1', title(type))],
51
- [...segment(body)].reduce((acc, seg) => push(acc, eval(content(input(seg, { ...context })), [])), []))),
52
- ];
53
+ return new List([
54
+ new Data(html('section',
55
+ {
56
+ class: `message`,
57
+ 'data-type': type,
58
+ },
59
+ [...segment(body)].reduce(
60
+ (acc, seg) =>
61
+ push(acc, unwrap(eval(content(subinput(seg, context)))!)),
62
+ [html('h1', title(type))])))
63
+ ]);
53
64
  }));
54
65
 
55
66
  function title(type: string): string {
@@ -1,6 +1,7 @@
1
1
  import { ExtensionParser } 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 = /(~{3,})(?!~)[^\n]*(?:$|\n)/y;
@@ -13,15 +14,18 @@ export const segment_: ExtensionParser.PlaceholderParser.SegmentParser = block(
13
14
 
14
15
  export const placeholder: ExtensionParser.PlaceholderParser = block(fmap(
15
16
  fence(opener, Infinity),
16
- ([body, overflow, closer, opener, delim]) => [
17
- html('pre', {
18
- class: 'invalid',
19
- translate: 'no',
20
- ...invalid(
21
- 'extension',
22
- 'fence',
23
- !closer ? `Missing the closing delimiter "${delim}"` :
24
- overflow ? `Invalid trailing line after the closing delimiter "${delim}"` :
25
- 'Invalid argument'),
26
- }, `${opener}${body}${overflow || closer}`),
27
- ]));
17
+ nodes => {
18
+ const [body, overflow, closer, opener, delim] = unwrap(nodes);
19
+ return new List([
20
+ new Data(html('pre', {
21
+ class: 'invalid',
22
+ translate: 'no',
23
+ ...invalid(
24
+ 'extension',
25
+ 'fence',
26
+ !closer ? `Missing the closing delimiter "${delim}"` :
27
+ overflow ? `Invalid trailing line after the closing delimiter "${delim}"` :
28
+ 'Invalid argument'),
29
+ }, `${opener}${body}${overflow || closer}`)),
30
+ ]);
31
+ }));
@@ -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, eval } 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 (eval(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', () => {