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,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,9 +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';
6
- import { linearize } from '../../util';
7
+ import { unwrap } from '../../util';
7
8
  import { html, defrag } from 'typed-dom/dom';
8
9
 
9
10
  export const syntax = />+[^\S\n]/y;
@@ -11,7 +12,8 @@ export const syntax = />+[^\S\n]/y;
11
12
  export const quote: ReplyParser.QuoteParser = lazy(() => block(fmap(
12
13
  rewrite(
13
14
  some(validate(syntax, anyline)),
14
- linearize(convert(
15
+ convert(
16
+ // TODO: インデント数を渡してインデント数前の行頭確認を行う実装に置き換える
15
17
  source => source.replace(/(?<=^>+[^\S\n])/mg, '\r'),
16
18
  some(union([
17
19
  // quote補助関数が残した数式をパースする。
@@ -20,9 +22,9 @@ export const quote: ReplyParser.QuoteParser = lazy(() => block(fmap(
20
22
  linebreak,
21
23
  unescsource,
22
24
  ])),
23
- false), -1)),
24
- (ns: [string, ...(string | HTMLElement)[]]) => [
25
- html('span', { class: 'quote' }, defrag(ns)),
26
- html('br'),
27
- ]),
25
+ false)),
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
- import { linearize } from '../util';
8
8
  import { visualize, trimBlankNodeEnd } from '../visibility';
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');
@@ -16,6 +17,9 @@ export const reply: ReplyParser = block(validate(csyntax, fmap(
16
17
  quote,
17
18
  rewrite(
18
19
  some(anyline, delimiter),
19
- visualize(linearize(some(inline), 1))),
20
+ visualize(fmap(some(inline), (ns, { source, position }) =>
21
+ source[position - 1] === '\n'
22
+ ? ns
23
+ : ns.push(new Data(html('br'))) && ns)))
20
24
  ])),
21
- 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)))])));
@@ -1,9 +1,10 @@
1
1
  import { TableParser } from '../block';
2
+ import { List, Data } from '../../combinator/data/parser';
2
3
  import { union, sequence, some, block, line, validate, focus, rewrite, surround, open, close, fallback, lazy, fmap } from '../../combinator';
3
4
  import { inline, media, medialink, shortmedia } from '../inline';
4
5
  import { contentline } from '../source';
5
6
  import { trimBlank } from '../visibility';
6
- import { invalid } from '../util';
7
+ import { unwrap, invalid } from '../util';
7
8
  import { duffReduce } from 'spica/duff';
8
9
  import { push } from 'spica/array';
9
10
  import { html, defrag } from 'typed-dom/dom';
@@ -19,32 +20,32 @@ export const table: TableParser = lazy(() => block(fmap(validate(
19
20
  row(some(align), false),
20
21
  some(row(some(data), true)),
21
22
  ])),
22
- rows => [
23
- html('table', [
24
- html('thead', [rows.shift()!]),
25
- html('tbody', format(rows)),
26
- ]),
27
- ])));
23
+ rows => new List([
24
+ new Data(html('table', [
25
+ html('thead', [rows.shift()!.value]),
26
+ html('tbody', unwrap(format(rows))),
27
+ ])),
28
+ ]))));
28
29
 
29
30
  const row = <P extends CellParser | AlignParser>(parser: P, optional: boolean): RowParser<P> => fallback(fmap(
30
31
  line(surround(/(?=\|)/y, some(union([parser])), /[|\\]?\s*$/y, optional)),
31
- es => [html('tr', es)]),
32
- rewrite(contentline, ({ context: { source } }) => [[
33
- html('tr', {
32
+ ns => new List([new Data(html('tr', unwrap(ns)))])),
33
+ rewrite(contentline, ({ context: { source } }) => new List([
34
+ new Data(html('tr', {
34
35
  class: 'invalid',
35
36
  ...invalid('table-row', 'syntax', 'Missing the start symbol of the table row'),
36
- }, [html('td', source.replace('\n', ''))])
37
- ]]));
37
+ }, [html('td', source.replace('\n', ''))]))
38
+ ])));
38
39
 
39
40
  const align: AlignParser = fmap(open(
40
41
  '|',
41
42
  union([
42
43
  focus(/:-+:?/y, ({ context: { source } }) =>
43
- [[source.at(-1) === ':' ? 'center' : 'start']]),
44
+ new List([new Data(source.at(-1) === ':' ? 'center' : 'start')])),
44
45
  focus(/-+:?/y, ({ context: { source } }) =>
45
- [[source.at(-1) === ':' ? 'end' : '']]),
46
+ new List([new Data(source.at(-1) === ':' ? 'end' : '')])),
46
47
  ])),
47
- ns => [html('td', defrag(ns))]);
48
+ ns => new List([new Data(html('td', defrag(unwrap(ns))))]));
48
49
 
49
50
  const cell: CellParser = surround(
50
51
  /\|\s*(?=\S)/y,
@@ -58,18 +59,18 @@ const cell: CellParser = surround(
58
59
 
59
60
  const head: CellParser.HeadParser = fmap(
60
61
  cell,
61
- ns => [html('th', defrag(ns))]);
62
+ ns => new List([new Data(html('th', defrag(unwrap(ns))))]));
62
63
 
63
64
  const data: CellParser.DataParser = fmap(
64
65
  cell,
65
- ns => [html('td', defrag(ns))]);
66
+ ns => new List([new Data(html('td', defrag(unwrap(ns))))]));
66
67
 
67
- function format(rows: HTMLTableRowElement[]): HTMLTableRowElement[] {
68
- const aligns = rows[0].className === 'invalid'
68
+ function format(rows: List<Data<HTMLTableRowElement>>): List<Data<HTMLTableRowElement>> {
69
+ const aligns = rows.head!.value.className === 'invalid'
69
70
  ? []
70
- : duffReduce(rows.shift()!.children, (acc, el) => push(acc, [el.textContent!]), [] as string[]);
71
- for (let i = 0; i < rows.length; ++i) {
72
- for (let cols = rows[i].children, len = cols.length, j = 0; j < len; ++j) {
71
+ : duffReduce(rows.shift()!.value.children, (acc, el) => push(acc, [el.textContent!]), [] as string[]);
72
+ for (const { value: row } of rows) {
73
+ for (let cols = row.children, len = cols.length, j = 0; j < len; ++j) {
73
74
  if (j > 0 && !aligns[j]) {
74
75
  aligns[j] = aligns[j - 1];
75
76
  }
@@ -1,11 +1,12 @@
1
1
  import { UListParser } 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, fallback, lazy, fmap } from '../../combinator';
4
5
  import { olist_ } from './olist';
5
6
  import { ilist_, ilistitem } from './ilist';
6
7
  import { inline, indexer, indexee, dataindex } from '../inline';
7
8
  import { visualize, trimBlank } from '../visibility';
8
- import { unshift } from 'spica/array';
9
+ import { unwrap } from '../util';
9
10
  import { html, defrag } from 'typed-dom/dom';
10
11
 
11
12
  export const ulist: UListParser = lazy(() => block(validate(
@@ -24,22 +25,25 @@ export const ulist_: UListParser = lazy(() => block(fmap(validate(
24
25
  indent(union([ulist_, olist_, ilist_])),
25
26
  ]),
26
27
  ilistitem),
27
- ns => [html('li', { 'data-index': dataindex(ns) }, defrag(fillFirstLine(ns)))])),
28
+ ns => new List([new Data(html('li', { 'data-index': dataindex(ns) }, defrag(unwrap(fillFirstLine(ns)))))]))),
28
29
  ])))),
29
- es => [format(html('ul', es))])));
30
+ ns => new List([new Data(format(html('ul', unwrap(ns))))]))));
30
31
 
31
32
  export const checkbox = focus(
32
33
  /\[[xX ]\](?=$|[ \n])/y,
33
- ({ context: { source } }) => [[
34
- html('span', { class: 'checkbox' }, source[1].trimStart() ? '☑' : '☐'),
35
- ]]);
34
+ ({ context: { source } }) => new List([
35
+ new Data(html('span', { class: 'checkbox' }, source[1].trimStart() ? '☑' : '☐')),
36
+ ]));
36
37
 
37
- export function fillFirstLine(ns: (HTMLElement | string)[]): (HTMLElement | string)[] {
38
- return ns.length === 1
39
- && typeof ns[0] === 'object'
40
- && ['UL', 'OL'].includes(ns[0].tagName)
41
- ? unshift([html('br')], ns)
42
- : ns;
38
+ export function fillFirstLine(nodes: List<Data<string | HTMLElement>>): List<Data<string | HTMLElement>> {
39
+ const node = nodes.head?.value;
40
+ if (typeof node !== 'object') return nodes;
41
+ switch (node.tagName) {
42
+ case 'UL':
43
+ case 'OL':
44
+ nodes.unshift(new Data(html('br')));
45
+ }
46
+ return nodes;
43
47
  }
44
48
 
45
49
  function format(list: HTMLUListElement): HTMLUListElement {
@@ -1,5 +1,6 @@
1
1
  import { MarkdownParser } from '../../markdown';
2
2
  import { Recursion, Command } from './context';
3
+ import { List, Data } from '../combinator/data/parser';
3
4
  import { union, reset, open, fallback, recover } from '../combinator';
4
5
  import { MAX_SEGMENT_SIZE } from './segment';
5
6
  import { emptyline } from './source';
@@ -113,16 +114,16 @@ function error(parser: BlockParser): BlockParser {
113
114
  return recover<BlockParser>(fallback(
114
115
  open(Command.Error, ({ context: { source, position } }) => { throw new Error(source.slice(position).split('\n', 1)[0]); }),
115
116
  parser),
116
- ({ context: { source, position, id } }, reason) => [[
117
- html('h1',
117
+ ({ context: { source, position, id } }, reason) => new List([
118
+ new Data(html('h1',
118
119
  {
119
120
  id: id !== '' ? `error:${rnd0Z(8)}` : undefined,
120
121
  class: 'error',
121
122
  },
122
123
  reason instanceof Error
123
124
  ? `${reason.name}: ${reason.message}`
124
- : `UnknownError: ${reason}`),
125
- html('pre',
125
+ : `UnknownError: ${reason}`)),
126
+ new Data(html('pre',
126
127
  {
127
128
  class: 'error',
128
129
  translate: 'no',
@@ -130,6 +131,6 @@ function error(parser: BlockParser): BlockParser {
130
131
  source.slice(position)
131
132
  .replace(reg, '')
132
133
  .slice(0, 1001)
133
- .replace(/^(.{997}).{4}$/s, '$1...') || undefined),
134
- ]]);
134
+ .replace(/^(.{997}).{4}$/s, '$1...') || undefined)),
135
+ ]));
135
136
  }
@@ -21,7 +21,8 @@ describe('Unit: parser/header', () => {
21
21
  assert.deepStrictEqual(inspect(parser('---\n\n---'), ctx), undefined);
22
22
  assert.deepStrictEqual(inspect(parser('---\n \n---'), ctx), undefined);
23
23
  assert.deepStrictEqual(inspect(parser('---\n-\n---'), ctx), [['<pre class="invalid" translate="no">---\n-\n---</pre>'], '']);
24
- assert.deepStrictEqual(inspect(parser('----\na: b\n----'), ctx), [['<pre class="invalid" translate="no">----\na: b\n----</pre>'], '']);
24
+ assert.deepStrictEqual(inspect(parser('---\na: b\n----'), ctx), [['<pre class="invalid" translate="no">---\na: b\n----</pre>'], '']);
25
+ assert.deepStrictEqual(inspect(parser('----\na: b\n---'), ctx), [['<pre class="invalid" translate="no">----\na: b\n---</pre>'], '']);
25
26
  assert.deepStrictEqual(inspect(parser(`---\n${'a: b\n'.repeat(101)}---`), ctx), [[`<pre class="invalid" translate="no">---\n${'a: b\n'.repeat(101)}---</pre>`], '']);
26
27
  });
27
28
 
@@ -30,6 +31,7 @@ describe('Unit: parser/header', () => {
30
31
  assert.deepStrictEqual(inspect(parser('---\na: b\n---\n'), ctx), [['<aside class="header"><details open=""><summary>Header</summary><span class="field" data-name="a" data-value="b"><span class="field-name">a</span>: <span class="field-value">b</span>\n</span></details></aside>'], '']);
31
32
  assert.deepStrictEqual(inspect(parser('---\na: b\nC: D e\n---\n'), ctx), [['<aside class="header"><details open=""><summary>Header</summary><span class="field" data-name="a" data-value="b"><span class="field-name">a</span>: <span class="field-value">b</span>\n</span><span class="field" data-name="c" data-value="D e"><span class="field-name">C</span>: <span class="field-value">D e</span>\n</span></details></aside>'], '']);
32
33
  assert.deepStrictEqual(inspect(parser('--- \r\na: b \r\n--- \r\n \r\n \r\na'), ctx), [['<aside class="header"><details open=""><summary>Header</summary><span class="field" data-name="a" data-value="b"><span class="field-name">a</span>: <span class="field-value">b</span>\n</span></details></aside>'], ' \r\na']);
34
+ assert.deepStrictEqual(inspect(parser('----\na: b\n----'), ctx), [['<aside class="header"><details open=""><summary>Header</summary><span class="field" data-name="a" data-value="b"><span class="field-name">a</span>: <span class="field-value">b</span>\n</span></details></aside>'], '']);
33
35
  });
34
36
 
35
37
  });