securemark 0.299.3 → 0.300.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 (241) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/design.md +0 -6
  3. package/dist/index.js +3479 -2750
  4. package/index.d.ts +2 -1
  5. package/index.ts +2 -2
  6. package/markdown.d.ts +209 -183
  7. package/package.json +1 -1
  8. package/src/{parser/api → api}/bind.test.ts +2 -24
  9. package/src/{parser/api → api}/bind.ts +18 -13
  10. package/src/{parser/api → api}/body.test.ts +1 -1
  11. package/src/{parser/api → api}/cache.ts +1 -1
  12. package/src/{parser/api → api}/header.test.ts +1 -1
  13. package/src/{parser/api → api}/header.ts +9 -6
  14. package/src/{parser/api → api}/normalize.test.ts +1 -1
  15. package/src/{parser/api → api}/parse.test.ts +120 -124
  16. package/src/api/parse.ts +30 -0
  17. package/src/api/run.ts +6 -0
  18. package/src/{parser/api.ts → api.ts} +1 -0
  19. package/src/combinator/control/inits.ts +26 -0
  20. package/src/combinator/control/sequence.test.ts +38 -0
  21. package/src/combinator/control/sequence.ts +17 -0
  22. package/src/combinator/control/some.test.ts +41 -0
  23. package/src/combinator/{data/parser → control}/some.ts +39 -26
  24. package/src/combinator/control/state.ts +42 -0
  25. package/src/combinator/control/subsequence.test.ts +47 -0
  26. package/src/combinator/control/subsequence.ts +16 -0
  27. package/src/combinator/control/tails.ts +8 -0
  28. package/src/combinator/control/union.test.ts +37 -0
  29. package/src/combinator/control/union.ts +18 -0
  30. package/src/combinator/{data/delimiter.ts → delimiter.ts} +40 -60
  31. package/src/combinator/effect/backtrack.ts +64 -0
  32. package/src/combinator/effect/clock.ts +10 -0
  33. package/src/combinator/effect/precedence.ts +50 -0
  34. package/src/combinator/effect/recursion.ts +30 -0
  35. package/src/combinator/effect/scope.ts +100 -0
  36. package/src/combinator/effect/state.ts +72 -0
  37. package/src/combinator/{data/node.ts → parser/list.ts} +38 -13
  38. package/src/combinator/parser.ts +293 -0
  39. package/src/combinator/process/bind.ts +34 -0
  40. package/src/combinator/process/block.test.ts +20 -0
  41. package/src/combinator/process/block.ts +33 -0
  42. package/src/combinator/process/clear.ts +16 -0
  43. package/src/combinator/process/contract.ts +35 -0
  44. package/src/combinator/process/duplicate.ts +7 -0
  45. package/src/combinator/process/error.ts +13 -0
  46. package/src/combinator/{control/manipulation → process}/fallback.ts +3 -3
  47. package/src/combinator/process/fence.ts +59 -0
  48. package/src/combinator/process/fmap.ts +10 -0
  49. package/src/combinator/process/indent.test.ts +31 -0
  50. package/src/combinator/process/indent.ts +51 -0
  51. package/src/combinator/process/lazy.ts +8 -0
  52. package/src/combinator/process/line.test.ts +21 -0
  53. package/src/combinator/process/line.ts +55 -0
  54. package/src/combinator/process/match.ts +37 -0
  55. package/src/combinator/process/reverse.ts +7 -0
  56. package/src/combinator/process/scope.ts +102 -0
  57. package/src/combinator/process/surround.ts +271 -0
  58. package/src/combinator.ts +28 -24
  59. package/src/debug.test.ts +11 -8
  60. package/src/parser/autolink.test.ts +17 -18
  61. package/src/parser/block/blockquote.test.ts +78 -79
  62. package/src/parser/block/blockquote.ts +32 -25
  63. package/src/parser/block/codeblock.test.ts +56 -57
  64. package/src/parser/block/codeblock.ts +44 -26
  65. package/src/parser/block/dlist.test.ts +56 -57
  66. package/src/parser/block/dlist.ts +5 -5
  67. package/src/parser/block/extension/aside.test.ts +8 -9
  68. package/src/parser/block/extension/aside.ts +76 -47
  69. package/src/parser/block/extension/example.test.ts +18 -19
  70. package/src/parser/block/extension/example.ts +88 -48
  71. package/src/parser/block/extension/fig.test.ts +37 -36
  72. package/src/parser/block/extension/fig.ts +20 -25
  73. package/src/parser/block/extension/figbase.test.ts +18 -19
  74. package/src/parser/block/extension/figbase.ts +3 -3
  75. package/src/parser/block/extension/figure.test.ts +62 -63
  76. package/src/parser/block/extension/figure.ts +23 -21
  77. package/src/parser/block/extension/message.test.ts +13 -14
  78. package/src/parser/block/extension/message.ts +52 -39
  79. package/src/parser/block/extension/placeholder.test.ts +13 -13
  80. package/src/parser/block/extension/placeholder.ts +23 -21
  81. package/src/parser/block/extension/table.test.ts +70 -71
  82. package/src/parser/block/extension/table.ts +43 -31
  83. package/src/parser/block/extension.test.ts +24 -24
  84. package/src/parser/block/extension.ts +3 -3
  85. package/src/parser/block/heading.test.ts +58 -59
  86. package/src/parser/block/heading.ts +19 -18
  87. package/src/parser/block/ilist.test.ts +8 -8
  88. package/src/parser/block/ilist.ts +9 -7
  89. package/src/parser/block/mathblock.test.ts +31 -32
  90. package/src/parser/block/mathblock.ts +24 -23
  91. package/src/parser/block/mediablock.ts +7 -7
  92. package/src/parser/block/olist.test.ts +102 -103
  93. package/src/parser/block/olist.ts +11 -12
  94. package/src/parser/block/pagebreak.test.ts +15 -16
  95. package/src/parser/block/pagebreak.ts +5 -5
  96. package/src/parser/block/paragraph.test.ts +57 -58
  97. package/src/parser/block/paragraph.ts +1 -1
  98. package/src/parser/block/reply/cite.test.ts +39 -40
  99. package/src/parser/block/reply/cite.ts +5 -5
  100. package/src/parser/block/reply/quote.test.ts +50 -51
  101. package/src/parser/block/reply/quote.ts +8 -7
  102. package/src/parser/block/reply.test.ts +19 -20
  103. package/src/parser/block/reply.ts +2 -2
  104. package/src/parser/block/sidefence.test.ts +41 -48
  105. package/src/parser/block/sidefence.ts +17 -11
  106. package/src/parser/block/table.test.ts +48 -49
  107. package/src/parser/block/table.ts +10 -9
  108. package/src/parser/block/ulist.test.ts +52 -53
  109. package/src/parser/block/ulist.ts +9 -8
  110. package/src/parser/block.ts +63 -51
  111. package/src/parser/context.ts +35 -32
  112. package/src/parser/document.ts +48 -0
  113. package/src/parser/header.test.ts +19 -20
  114. package/src/parser/header.ts +31 -25
  115. package/src/parser/inline/annotation.test.ts +49 -50
  116. package/src/parser/inline/annotation.ts +14 -16
  117. package/src/parser/inline/autolink/account.test.ts +32 -33
  118. package/src/parser/inline/autolink/account.ts +18 -19
  119. package/src/parser/inline/autolink/anchor.test.ts +21 -22
  120. package/src/parser/inline/autolink/anchor.ts +7 -8
  121. package/src/parser/inline/autolink/channel.test.ts +14 -15
  122. package/src/parser/inline/autolink/email.test.ts +36 -37
  123. package/src/parser/inline/autolink/email.ts +6 -6
  124. package/src/parser/inline/autolink/hashnum.test.ts +32 -33
  125. package/src/parser/inline/autolink/hashnum.ts +7 -8
  126. package/src/parser/inline/autolink/hashtag.test.ts +59 -60
  127. package/src/parser/inline/autolink/hashtag.ts +8 -9
  128. package/src/parser/inline/autolink/url.test.ts +75 -76
  129. package/src/parser/inline/autolink/url.ts +13 -14
  130. package/src/parser/inline/autolink.ts +24 -11
  131. package/src/parser/inline/bracket.test.ts +73 -74
  132. package/src/parser/inline/bracket.ts +88 -63
  133. package/src/parser/inline/code.test.ts +30 -31
  134. package/src/parser/inline/code.ts +6 -6
  135. package/src/parser/inline/deletion.test.ts +27 -28
  136. package/src/parser/inline/deletion.ts +5 -5
  137. package/src/parser/inline/emphasis.test.ts +39 -40
  138. package/src/parser/inline/emphasis.ts +5 -5
  139. package/src/parser/inline/emstrong.test.ts +101 -102
  140. package/src/parser/inline/emstrong.ts +103 -85
  141. package/src/parser/inline/extension/index.test.ts +91 -92
  142. package/src/parser/inline/extension/index.ts +17 -13
  143. package/src/parser/inline/extension/indexee.ts +4 -4
  144. package/src/parser/inline/extension/indexer.test.ts +23 -24
  145. package/src/parser/inline/extension/indexer.ts +6 -5
  146. package/src/parser/inline/extension/label.test.ts +32 -33
  147. package/src/parser/inline/extension/label.ts +14 -5
  148. package/src/parser/inline/extension/placeholder.test.ts +42 -43
  149. package/src/parser/inline/extension/placeholder.ts +8 -9
  150. package/src/parser/inline/html.test.ts +109 -109
  151. package/src/parser/inline/html.ts +27 -27
  152. package/src/parser/inline/htmlentity.test.ts +37 -38
  153. package/src/parser/inline/htmlentity.ts +6 -7
  154. package/src/parser/inline/insertion.test.ts +27 -28
  155. package/src/parser/inline/insertion.ts +5 -5
  156. package/src/parser/inline/italic.test.ts +55 -56
  157. package/src/parser/inline/italic.ts +5 -5
  158. package/src/parser/inline/link.test.ts +186 -187
  159. package/src/parser/inline/link.ts +31 -32
  160. package/src/parser/inline/mark.test.ts +31 -32
  161. package/src/parser/inline/mark.ts +6 -6
  162. package/src/parser/inline/math.test.ts +140 -141
  163. package/src/parser/inline/math.ts +6 -7
  164. package/src/parser/inline/media.test.ts +92 -93
  165. package/src/parser/inline/media.ts +32 -38
  166. package/src/parser/inline/reference.test.ts +111 -112
  167. package/src/parser/inline/reference.ts +61 -32
  168. package/src/parser/inline/remark.test.ts +49 -50
  169. package/src/parser/inline/remark.ts +13 -13
  170. package/src/parser/inline/ruby.test.ts +49 -50
  171. package/src/parser/inline/ruby.ts +60 -49
  172. package/src/parser/inline/shortmedia.test.ts +9 -10
  173. package/src/parser/inline/shortmedia.ts +11 -9
  174. package/src/parser/inline/strong.test.ts +36 -37
  175. package/src/parser/inline/strong.ts +5 -5
  176. package/src/parser/inline/template.test.ts +22 -23
  177. package/src/parser/inline/template.ts +13 -16
  178. package/src/parser/inline.test.ts +225 -226
  179. package/src/parser/inline.ts +68 -34
  180. package/src/parser/node.ts +1 -1
  181. package/src/parser/parser.ts +51 -0
  182. package/src/parser/repeat.ts +118 -91
  183. package/src/parser/segment.test.ts +0 -11
  184. package/src/parser/segment.ts +25 -28
  185. package/src/parser/source/escapable.test.ts +23 -24
  186. package/src/parser/source/escapable.ts +20 -20
  187. package/src/parser/source/line.test.ts +17 -18
  188. package/src/parser/source/line.ts +19 -24
  189. package/src/parser/source/str.ts +17 -10
  190. package/src/parser/source/text.test.ts +88 -89
  191. package/src/parser/source/text.ts +19 -20
  192. package/src/parser/source/unescapable.test.ts +23 -24
  193. package/src/parser/source/unescapable.ts +16 -16
  194. package/src/parser/util.ts +1 -1
  195. package/src/parser/visibility.ts +36 -15
  196. package/src/{parser/processor → processor}/figure.test.ts +23 -23
  197. package/src/{parser/processor → processor}/figure.ts +20 -12
  198. package/src/{parser/processor → processor}/note.test.ts +15 -15
  199. package/src/{parser/processor → processor}/note.ts +6 -4
  200. package/src/renderer/render/media/pdf.ts +2 -2
  201. package/src/renderer/render/media/twitter.ts +2 -2
  202. package/src/renderer/render/media.test.ts +12 -13
  203. package/src/renderer/render.test.ts +11 -11
  204. package/src/util/info.test.ts +2 -2
  205. package/src/util/quote.test.ts +3 -3
  206. package/src/util/quote.ts +6 -5
  207. package/src/util/toc.test.ts +12 -12
  208. package/src/combinator/control/constraint/block.test.ts +0 -20
  209. package/src/combinator/control/constraint/block.ts +0 -28
  210. package/src/combinator/control/constraint/contract.ts +0 -27
  211. package/src/combinator/control/constraint/line.test.ts +0 -21
  212. package/src/combinator/control/constraint/line.ts +0 -42
  213. package/src/combinator/control/manipulation/clear.ts +0 -5
  214. package/src/combinator/control/manipulation/convert.ts +0 -22
  215. package/src/combinator/control/manipulation/duplicate.ts +0 -7
  216. package/src/combinator/control/manipulation/fence.ts +0 -54
  217. package/src/combinator/control/manipulation/indent.test.ts +0 -31
  218. package/src/combinator/control/manipulation/indent.ts +0 -39
  219. package/src/combinator/control/manipulation/lazy.ts +0 -8
  220. package/src/combinator/control/manipulation/match.ts +0 -27
  221. package/src/combinator/control/manipulation/recovery.ts +0 -18
  222. package/src/combinator/control/manipulation/reverse.ts +0 -8
  223. package/src/combinator/control/manipulation/scope.ts +0 -61
  224. package/src/combinator/control/manipulation/surround.ts +0 -223
  225. package/src/combinator/control/monad/bind.ts +0 -26
  226. package/src/combinator/control/monad/fmap.ts +0 -10
  227. package/src/combinator/data/parser/context.ts +0 -96
  228. package/src/combinator/data/parser/inits.ts +0 -20
  229. package/src/combinator/data/parser/sequence.test.ts +0 -33
  230. package/src/combinator/data/parser/sequence.ts +0 -20
  231. package/src/combinator/data/parser/some.test.ts +0 -37
  232. package/src/combinator/data/parser/subsequence.test.ts +0 -41
  233. package/src/combinator/data/parser/subsequence.ts +0 -13
  234. package/src/combinator/data/parser/tails.ts +0 -8
  235. package/src/combinator/data/parser/union.test.ts +0 -33
  236. package/src/combinator/data/parser/union.ts +0 -18
  237. package/src/combinator/data/parser.ts +0 -144
  238. package/src/parser/api/parse.ts +0 -48
  239. package/src/parser.ts +0 -1
  240. /package/src/{parser/api → api}/body.ts +0 -0
  241. /package/src/{parser/api → api}/normalize.ts +0 -0
@@ -1,7 +1,7 @@
1
1
  import { MarkdownParser } from '../../markdown';
2
- import { Segment, Command } from './context';
3
- import { List, Node } from '../combinator/data/parser';
4
- import { union, firstline, recover } from '../combinator';
2
+ import { Segment } from './context';
3
+ import { List, Node } from '../combinator/parser';
4
+ import { union, lazy, always } from '../combinator';
5
5
  import { header } from './header';
6
6
  import { emptysegment } from './source';
7
7
  import { pagebreak } from './block/pagebreak';
@@ -42,90 +42,102 @@ export import MediaBlockParser = BlockParser.MediaBlockParser;
42
42
  export import ReplyParser = BlockParser.ReplyParser;
43
43
  export import ParagraphParser = BlockParser.ParagraphParser;
44
44
 
45
- export const block: BlockParser = error(union([
45
+ const p1 = lazy(() => union([
46
+ ulist,
47
+ ilist,
48
+ ]));
49
+ const p2 = lazy(() => union([
50
+ blockquote,
51
+ reply,
52
+ ]));
53
+ const p3 = lazy(() => union([
54
+ table,
55
+ sidefence,
56
+ ]));
57
+ export const block: BlockParser = lazy(() => error(union([
46
58
  emptysegment,
47
- input => {
59
+ (input, output) => {
48
60
  const { source, position, segment } = input;
49
61
  if (position === source.length) return;
50
- switch (segment ^ Segment.write) {
62
+ switch (segment & ~Segment.write) {
51
63
  case Segment.heading:
52
- return heading(input);
64
+ return heading(input, output);
53
65
  case Segment.fig:
54
- return fig(input);
66
+ return fig(input, output);
55
67
  case Segment.figure:
56
- return figure(input);
68
+ return figure(input, output);
57
69
  }
58
70
  const char = source[position];
59
71
  switch (char) {
60
- case Command.Error:
61
- throw new Error(firstline(source, position + 1).trimEnd());
62
72
  case '=':
63
- if (source.startsWith('===', position)) return pagebreak(input);
73
+ if (source.startsWith('===', position)) return pagebreak(input, output);
64
74
  break;
65
75
  case '`':
66
- if (source.startsWith('```', position)) return codeblock(input);
76
+ if (source.startsWith('```', position)) return codeblock(input, output);
67
77
  break;
68
78
  case '~':
69
- if (source.startsWith('~~~', position)) return extension(input);
70
- if (source[position + 1] === ' ') return dlist(input);
79
+ if (source.startsWith('~~~', position)) return extension(input, output);
80
+ if (source[position + 1] === ' ') return dlist(input, output);
71
81
  break;
72
82
  case '-':
73
- if (source.startsWith('---', position)) return header(input);
74
- if (source[position + 1] === ' ') return ulist(input) || ilist(input);
83
+ if (source.startsWith('---', position)) return header(input, output);
84
+ if (source[position + 1] === ' ') return p1(input, output);
75
85
  break;
76
86
  case '+':
77
87
  case '*':
78
- if (source[position + 1] === ' ') return ilist(input);
88
+ if (source[position + 1] === ' ') return ilist(input, output);
79
89
  break;
80
90
  case '[':
81
91
  switch (source[position + 1]) {
82
92
  case '$':
83
- return figbase(input);
93
+ return figbase(input, output);
84
94
  case '!':
85
- return mediablock(input);
95
+ return mediablock(input, output);
86
96
  }
87
97
  break;
88
98
  case '!':
89
- if (source[position + 1] === '>') return blockquote(input);
90
- return mediablock(input);
99
+ if (source[position + 1] === '>') return blockquote(input, output);
100
+ return mediablock(input, output);
91
101
  case '>':
92
- if (source[position + 1] === '>') return blockquote(input) || reply(input);
93
- return blockquote(input);
102
+ if (source[position + 1] === '>') return p2(input, output);
103
+ return blockquote(input, output);
94
104
  case '$':
95
- if (source[position + 1] === '$') return mathblock(input);
96
- return figbase(input);
105
+ if (source[position + 1] === '$') return mathblock(input, output);
106
+ return figbase(input, output);
97
107
  case '|':
98
- return table(input) || sidefence(input);
108
+ return p3(input, output);
99
109
  case '(':
100
- return olist(input);
110
+ return olist(input, output);
101
111
  default:
102
- if (char <= '9' && '0' <= char) return olist(input);
112
+ if (char <= '9' && '0' <= char) return olist(input, output);
103
113
  }
104
114
  },
105
115
  paragraph
106
- ]));
116
+ ])));
107
117
 
108
118
  function error(parser: BlockParser): BlockParser {
109
- const reg = new RegExp(String.raw`^${Command.Error}[^\r\n]*\r?\n`)
110
- return recover<BlockParser>(
119
+ return always([
111
120
  parser,
112
- ({ source, position, id }, reason) => new List([
113
- new Node(html('h1',
114
- {
115
- id: id !== '' ? `error:${rnd0Z(8)}` : undefined,
116
- class: 'error',
117
- },
118
- reason instanceof Error
119
- ? `${reason.name}: ${reason.message}`
120
- : `UnknownError: ${reason}`)),
121
- new Node(html('pre',
122
- {
123
- class: 'error',
124
- translate: 'no',
125
- },
126
- source.slice(position)
127
- .replace(reg, '')
128
- .slice(0, 1001)
129
- .replace(/^(.{997}).{4}$/s, '$1...') || undefined)),
130
- ]));
121
+ ({ source, position, id }, output) => {
122
+ const { error } = output;
123
+ if (!error) return output.context;
124
+ output.error = undefined;
125
+ return output.import(new List([
126
+ new Node(html('h1',
127
+ {
128
+ id: id !== '' ? `error:${rnd0Z(8)}` : undefined,
129
+ class: 'error',
130
+ },
131
+ `${error.name}: ${error.message}`)),
132
+ new Node(html('pre',
133
+ {
134
+ class: 'error',
135
+ translate: 'no',
136
+ },
137
+ source.slice(position)
138
+ .slice(0, 1001)
139
+ .replace(/^(.{997}).{4}$/s, '$1...') || undefined)),
140
+ ]));
141
+ },
142
+ ]);
131
143
  }
@@ -1,67 +1,72 @@
1
- import { List, Node, Context as Ctx } from '../../src/combinator/data/parser';
1
+ import { Input as Ipt, input as ipt } from '../combinator/parser';
2
2
  import { Dict } from 'spica/dict';
3
3
 
4
- export const MAX_SEGMENT_SIZE = 100_000; // 100,000 bytes (Max value size of FDB)
5
- export const MAX_INPUT_SIZE = MAX_SEGMENT_SIZE * 10;
4
+ export function input(source: string, input: Input = new Input()): Input {
5
+ return ipt(source, input);
6
+ }
6
7
 
7
- export class Context extends Ctx {
8
+ export class Input<M extends object = object> extends Ipt<M> {
8
9
  constructor(
9
- options: Partial<Context> = {},
10
+ options: Partial<Input> = {},
10
11
  ) {
11
12
  super(options);
12
13
  const {
13
14
  segment,
15
+ header,
14
16
  local,
15
17
  sequential,
16
- buffer,
17
- header,
18
18
  host,
19
19
  url,
20
20
  id,
21
+ notes,
21
22
  caches,
23
+ test,
22
24
  } = options;
23
- this.resources = options.resources ?? {
24
- // バックトラックのせいで文字数制限を受けないようにする。
25
- clock: MAX_SEGMENT_SIZE * (5 + 1),
25
+ this.resources ??= {
26
+ clock: -1,
27
+ interval: 200,
26
28
  recursions: [
27
- 5 || Recursion.block,
28
- 20 || Recursion.blockquote,
29
- 40 || Recursion.listitem,
30
- 20 || Recursion.inline,
31
- 20 || Recursion.bracket,
32
- 20 || Recursion.terminal,
29
+ 10 || Recursion.scope,
30
+ 100 || Recursion.block,
31
+ 100 || Recursion.inline,
32
+ 100 || Recursion.terminal,
33
33
  ],
34
34
  };
35
35
  this.segment = segment ?? Segment.unknown;
36
+ this.header = header ?? true;
36
37
  this.local = local ?? false;
37
38
  this.sequential = sequential ?? false;
38
- this.buffer = buffer ?? new List();
39
- this.header = header ?? true;
40
39
  this.host = host;
41
40
  this.url = url;
42
41
  this.id = id;
42
+ this.notes = notes;
43
43
  this.caches = caches;
44
+ this.test = test ?? false;
44
45
  }
45
46
  public override readonly resources: {
46
47
  clock: number;
47
48
  recursions: number[];
49
+ interval?: number;
48
50
  };
49
51
  public override segment: Segment;
52
+ public header: boolean;
50
53
  public local: boolean;
51
54
  public sequential: boolean;
52
- public buffer: List<Node<(string | HTMLElement)>>;
53
55
  public recursion = new RecursionCounter(2);
54
- public readonly header: boolean;
55
56
  public readonly host?: URL;
56
57
  public readonly url?: URL;
57
- public readonly id?: string;
58
+ public id?: string;
59
+ public notes?: {
60
+ readonly references: HTMLOListElement;
61
+ };
58
62
  public readonly caches?: {
59
63
  readonly code?: Dict<string, HTMLElement>;
60
64
  readonly math?: Dict<string, HTMLElement>;
61
65
  readonly media?: Dict<string, HTMLElement>;
62
66
  };
67
+ public test: boolean;
63
68
  }
64
- export type Options = Partial<Context>;
69
+ export type Options = Partial<Input>;
65
70
 
66
71
  class RecursionCounter {
67
72
  constructor(
@@ -70,11 +75,11 @@ class RecursionCounter {
70
75
  }
71
76
  private readonly stack: number[] = [];
72
77
  private index = 0;
73
- public add(depth: number): void {
78
+ public add(depth: number): Error | undefined {
74
79
  const { stack } = this
75
- for (; this.index > 0 && stack[this.index - 1] <= depth; --this.index);
80
+ for (; this.index > 0 && stack[this.index - 1] >= depth; --this.index);
76
81
  // 内側から数えるので無効化処理できずエラーを投げるしかない。
77
- if (this.index === this.limit) throw new Error(`Too much recursion`);
82
+ if (this.index === this.limit) return new Error(`Too much recursion`);
78
83
  stack[this.index] = depth;
79
84
  ++this.index;
80
85
  }
@@ -82,12 +87,12 @@ class RecursionCounter {
82
87
 
83
88
  export const enum Segment {
84
89
  unknown = 0,
90
+ read = 0,
85
91
  write = 1,
86
- nonempty = 0,
87
92
  empty = 1 << 1,
88
- heading = 3 << 1,
89
- fig = 4 << 1,
90
- figure = 5 << 1,
93
+ heading = 2 << 1,
94
+ fig = 3 << 1,
95
+ figure = 4 << 1,
91
96
  }
92
97
 
93
98
  export const enum State {
@@ -110,11 +115,9 @@ export const enum State {
110
115
  }
111
116
 
112
117
  export const enum Recursion {
118
+ scope,
113
119
  block,
114
- blockquote,
115
- listitem,
116
120
  inline,
117
- bracket,
118
121
  terminal,
119
122
  }
120
123
 
@@ -0,0 +1,48 @@
1
+ import { MarkdownParser } from '../../markdown';
2
+ import { Input, Recursion } from './context';
3
+ import { Parser, Node } from '../combinator/parser';
4
+ import { always, force, recursion } from '../combinator';
5
+ import { build } from './parser';
6
+ import { parser as segment } from './segment';
7
+ import { block } from './block';
8
+ import { unwrap, randomID } from './util';
9
+ import { figure } from '../processor/figure';
10
+ import { note } from '../processor/note';
11
+ import { frag, html } from 'typed-dom/dom';
12
+
13
+ export const document: MarkdownParser = (() => {
14
+ interface Memory {
15
+ readonly interpolation?: boolean;
16
+ readonly references: HTMLOListElement;
17
+ }
18
+ const loop = build(segment, block);
19
+ return always<Parser<DocumentFragment | HTMLElement, Input<Memory>>>([
20
+ (input, output) => {
21
+ input.id =
22
+ input.id === '' ? '' :
23
+ input.local ? randomID() :
24
+ input.id;
25
+ input.memory = input.notes ?? {
26
+ interpolation: true,
27
+ references: html('ol', { class: 'references' }),
28
+ };
29
+ output.push();
30
+ return output.context;
31
+ },
32
+ recursion(Recursion.scope, force(() => loop)),
33
+ (input, output) => {
34
+ assert(input.position === input.source.length);
35
+ const doc = frag(unwrap(output.pop()));
36
+ output.append(new Node(doc));
37
+ assert(input.id !== '' || !doc.querySelector('[id], .index[href], .label[href], .annotation > a[href], .reference > a[href]'));
38
+ if (input.test && !input.local) return output.context;
39
+ const { memory } = input;
40
+ const orphan = !memory.references.parentNode;
41
+ orphan && doc.appendChild(memory.references);
42
+ for (const _ of figure(doc, memory, input));
43
+ for (const _ of note(doc, memory, input));
44
+ orphan && !memory.interpolation && memory.references.remove();
45
+ return output.context;
46
+ },
47
+ ]);
48
+ })();
@@ -1,6 +1,5 @@
1
1
  import { header } from './header';
2
- import { input } from '../combinator/data/parser';
3
- import { Context } from './context';
2
+ import { input } from './context';
4
3
  import { inspect } from '../debug.test';
5
4
 
6
5
  describe('Unit: parser/header', () => {
@@ -8,27 +7,27 @@ describe('Unit: parser/header', () => {
8
7
  const parser = header;
9
8
 
10
9
  it('invalid', () => {
11
- assert.deepStrictEqual(inspect(parser, input('', new Context())), undefined);
12
- assert.deepStrictEqual(inspect(parser, input('---', new Context())), undefined);
13
- assert.deepStrictEqual(inspect(parser, input('---\n', new Context())), undefined);
14
- assert.deepStrictEqual(inspect(parser, input('---\n---', new Context())), [['<pre class="invalid" translate="no">---\n---</pre>'], '']);
15
- assert.deepStrictEqual(inspect(parser, input('---\na: b\n', new Context())), [['<pre class="invalid" translate="no">---\na: b\n</pre>'], '']);
16
- assert.deepStrictEqual(inspect(parser, input('---\na: b\n---c', new Context())), [['<pre class="invalid" translate="no">---\na: b\n---c</pre>'], '']);
17
- assert.deepStrictEqual(inspect(parser, input('---\na: b\n---\nc', new Context())), undefined);
18
- assert.deepStrictEqual(inspect(parser, input('---\n\n---', new Context())), undefined);
19
- assert.deepStrictEqual(inspect(parser, input('---\n \n---', new Context())), undefined);
20
- assert.deepStrictEqual(inspect(parser, input('---\n-\n---', new Context())), [['<pre class="invalid" translate="no">---\n-\n---</pre>'], '']);
21
- assert.deepStrictEqual(inspect(parser, input('---\na: b\n----', new Context())), [['<pre class="invalid" translate="no">---\na: b\n----</pre>'], '']);
22
- assert.deepStrictEqual(inspect(parser, input('----\na: b\n---', new Context())), [['<pre class="invalid" translate="no">----\na: b\n---</pre>'], '']);
23
- assert.deepStrictEqual(inspect(parser, input(`---\n${'a: b\n'.repeat(101)}---`, new Context())), [[`<pre class="invalid" translate="no">---\n${'a: b\n'.repeat(101)}---</pre>`], '']);
10
+ assert.deepStrictEqual(inspect(parser, input('')), undefined);
11
+ assert.deepStrictEqual(inspect(parser, input('---')), undefined);
12
+ assert.deepStrictEqual(inspect(parser, input('---\n')), undefined);
13
+ assert.deepStrictEqual(inspect(parser, input('---\n---')), [['<pre class="invalid" translate="no">---\n---</pre>'], '']);
14
+ assert.deepStrictEqual(inspect(parser, input('---\na: b\n')), [['<pre class="invalid" translate="no">---\na: b\n</pre>'], '']);
15
+ assert.deepStrictEqual(inspect(parser, input('---\na: b\n---c')), [['<pre class="invalid" translate="no">---\na: b\n---c</pre>'], '']);
16
+ assert.deepStrictEqual(inspect(parser, input('---\na: b\n---\nc')), undefined);
17
+ assert.deepStrictEqual(inspect(parser, input('---\n\n---')), undefined);
18
+ assert.deepStrictEqual(inspect(parser, input('---\n \n---')), undefined);
19
+ assert.deepStrictEqual(inspect(parser, input('---\n-\n---')), [['<pre class="invalid" translate="no">---\n-\n---</pre>'], '']);
20
+ assert.deepStrictEqual(inspect(parser, input('---\na: b\n----')), [['<pre class="invalid" translate="no">---\na: b\n----</pre>'], '']);
21
+ assert.deepStrictEqual(inspect(parser, input('----\na: b\n---')), [['<pre class="invalid" translate="no">----\na: b\n---</pre>'], '']);
22
+ assert.deepStrictEqual(inspect(parser, input(`---\n${'a: b\n'.repeat(101)}---`)), [[`<pre class="invalid" translate="no">---\n${'a: b\n'.repeat(101)}---</pre>`], '']);
24
23
  });
25
24
 
26
25
  it('basic', () => {
27
- assert.deepStrictEqual(inspect(parser, input('---\na: b\n---', new Context())), [['<aside class="header"><details open=""><summary>Header</summary><div class="field" data-name="a" data-value="b"><span class="field-name">a</span>: <span class="field-value">b</span></div></details></aside>'], '']);
28
- assert.deepStrictEqual(inspect(parser, input('---\na: b\n---\n', new Context())), [['<aside class="header"><details open=""><summary>Header</summary><div class="field" data-name="a" data-value="b"><span class="field-name">a</span>: <span class="field-value">b</span></div></details></aside>'], '']);
29
- assert.deepStrictEqual(inspect(parser, input('---\na: b\nC: D e\n---\n', new Context())), [['<aside class="header"><details open=""><summary>Header</summary><div class="field" data-name="a" data-value="b"><span class="field-name">a</span>: <span class="field-value">b</span></div><div class="field" data-name="c" data-value="D e"><span class="field-name">C</span>: <span class="field-value">D e</span></div></details></aside>'], '']);
30
- assert.deepStrictEqual(inspect(parser, input('---\r\na: b\r\nC: D e\r\n---\r\n', new Context())), [['<aside class="header"><details open=""><summary>Header</summary><div class="field" data-name="a" data-value="b"><span class="field-name">a</span>: <span class="field-value">b</span></div><div class="field" data-name="c" data-value="D e"><span class="field-name">C</span>: <span class="field-value">D e</span></div></details></aside>'], '']);
31
- assert.deepStrictEqual(inspect(parser, input('----\na: b\n----', new Context())), [['<aside class="header"><details open=""><summary>Header</summary><div class="field" data-name="a" data-value="b"><span class="field-name">a</span>: <span class="field-value">b</span></div></details></aside>'], '']);
26
+ assert.deepStrictEqual(inspect(parser, input('---\na: b\n---')), [['<aside class="header"><details open=""><summary>Header</summary><div class="field" data-name="a" data-value="b"><span class="field-name">a</span>: <span class="field-value">b</span></div></details></aside>'], '']);
27
+ assert.deepStrictEqual(inspect(parser, input('---\na: b\n---\n')), [['<aside class="header"><details open=""><summary>Header</summary><div class="field" data-name="a" data-value="b"><span class="field-name">a</span>: <span class="field-value">b</span></div></details></aside>'], '']);
28
+ assert.deepStrictEqual(inspect(parser, input('---\na: b\nC: D e\n---\n')), [['<aside class="header"><details open=""><summary>Header</summary><div class="field" data-name="a" data-value="b"><span class="field-name">a</span>: <span class="field-value">b</span></div><div class="field" data-name="c" data-value="D e"><span class="field-name">C</span>: <span class="field-value">D e</span></div></details></aside>'], '']);
29
+ assert.deepStrictEqual(inspect(parser, input('---\r\na: b\r\nC: D e\r\n---\r\n')), [['<aside class="header"><details open=""><summary>Header</summary><div class="field" data-name="a" data-value="b"><span class="field-name">a</span>: <span class="field-value">b</span></div><div class="field" data-name="c" data-value="D e"><span class="field-name">C</span>: <span class="field-value">D e</span></div></details></aside>'], '']);
30
+ assert.deepStrictEqual(inspect(parser, input('----\na: b\n----')), [['<aside class="header"><details open=""><summary>Header</summary><div class="field" data-name="a" data-value="b"><span class="field-name">a</span>: <span class="field-value">b</span></div></details></aside>'], '']);
32
31
  });
33
32
 
34
33
  });
@@ -1,8 +1,9 @@
1
1
  import { MarkdownParser } from '../../markdown';
2
- import { List, Node } from '../combinator/data/parser';
3
- import { union, inits, some, block, line, validate, focus, clear, convert, lazy, fmap } from '../combinator';
2
+ import { List, Node } from '../combinator/parser';
3
+ import { union, inits, some, scope, block, line, validate, focus, clear, lazy, fmap } from '../combinator';
4
4
  import { str } from './source';
5
5
  import { unwrap, invalid } from './util';
6
+ import { ReadonlyURL } from 'spica/url';
6
7
  import { html, defrag } from 'typed-dom/dom';
7
8
 
8
9
  export const header: MarkdownParser.HeaderParser = lazy(() => validate(
@@ -10,42 +11,47 @@ export const header: MarkdownParser.HeaderParser = lazy(() => validate(
10
11
  inits([
11
12
  block(
12
13
  union([
13
- validate(context => context.header,
14
- focus(/(---+)[^\S\r\n]*\r?\n(?:[a-z][0-9a-z]*(?:-[0-9a-z]+)*:[ \t]+\S[^\r\n]*\r?\n){1,32}\1[^\S\r\n]*(?:$|\r?\n)/yi,
15
- convert(source =>
16
- source.slice(source.indexOf('\n') + 1, source.trimEnd().lastIndexOf('\n')),
17
- fmap(
18
- some(union([field])),
19
- ns => new List([
20
- new Node(html('aside', { class: 'header' }, [
21
- html('details',
22
- { open: '' },
23
- defrag(unwrap(ns.unshift(new Node(html('summary', 'Header'))) && ns))),
24
- ])),
25
- ]))))),
26
- context => {
27
- const { source, position } = context;
28
- context.position += source.length;
29
- return new List([
14
+ validate(
15
+ input => input.header,
16
+ focus(/(---+)[^\S\r\n]*\r?\n(?:[a-z][0-9a-z]*(?:-[0-9a-z]+)*:[ \t]+\S[^\r\n]*\r?\n){1,32}\1[^\S\r\n]*(?:$|\r?\n)/yi,
17
+ scope(
18
+ ({ source }) => source.slice(source.indexOf('\n') + 1, source.trimEnd().lastIndexOf('\n')),
19
+ fmap(
20
+ some(union([field])),
21
+ ns => new List([
22
+ new Node(html('aside', { class: 'header' }, [
23
+ html('details',
24
+ { open: '' },
25
+ defrag(unwrap(ns.unshift(new Node(html('summary', 'Header')))))),
26
+ ])),
27
+ ])),
28
+ false))),
29
+ (input, output) => {
30
+ const { source, position } = input;
31
+ input.position += source.length;
32
+ return output.append(
30
33
  new Node(html('pre', {
31
34
  class: 'invalid',
32
35
  translate: 'no',
33
36
  ...invalid('header', 'syntax', 'Invalid syntax'),
34
- }, source.slice(position))),
35
- ]);
37
+ }, source.slice(position))));
36
38
  },
37
39
  ])),
38
40
  clear(str(/[^\S\r\n]*\r?\n/y)),
39
41
  ])));
40
42
 
41
- const field: MarkdownParser.HeaderParser.FieldParser = line(({ source, position }) => {
43
+ const field: MarkdownParser.HeaderParser.FieldParser = line((input, output) => {
44
+ const { source, position } = input;
42
45
  const name = source.slice(position, source.indexOf(':', position));
43
46
  const value = source.slice(position + name.length + 1).trim();
44
- return new List([
47
+ if (name.toLowerCase() === 'url') {
48
+ // @ts-expect-error
49
+ input.url = new ReadonlyURL(value as ':');
50
+ }
51
+ return output.append(
45
52
  new Node(html('div', { class: 'field', 'data-name': name.toLowerCase(), 'data-value': value }, [
46
53
  html('span', { class: 'field-name' }, name),
47
54
  ': ',
48
55
  html('span', { class: 'field-value' }, value),
49
- ])),
50
- ]);
56
+ ])));
51
57
  });