securemark 0.300.0 → 0.300.2

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 (45) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/dist/index.js +237 -161
  3. package/index.d.ts +1 -1
  4. package/markdown.d.ts +3 -10
  5. package/package.json +1 -1
  6. package/src/api/bind.ts +6 -6
  7. package/src/api/parse.ts +2 -2
  8. package/src/combinator/control/inits.ts +13 -4
  9. package/src/combinator/control/sequence.ts +3 -1
  10. package/src/combinator/control/state.ts +1 -10
  11. package/src/combinator/control/union.ts +16 -3
  12. package/src/combinator/parser.ts +18 -8
  13. package/src/combinator/process/fence.ts +23 -33
  14. package/src/combinator/process/line.ts +1 -1
  15. package/src/combinator/process/surround.ts +2 -0
  16. package/src/parser/block/codeblock.test.ts +0 -2
  17. package/src/parser/block/codeblock.ts +4 -4
  18. package/src/parser/block/extension/aside.test.ts +0 -1
  19. package/src/parser/block/extension/aside.ts +2 -2
  20. package/src/parser/block/extension/example.test.ts +0 -2
  21. package/src/parser/block/extension/example.ts +2 -2
  22. package/src/parser/block/extension/fig.ts +5 -7
  23. package/src/parser/block/extension/figure.test.ts +0 -4
  24. package/src/parser/block/extension/figure.ts +6 -7
  25. package/src/parser/block/extension/message.test.ts +0 -1
  26. package/src/parser/block/extension/message.ts +2 -2
  27. package/src/parser/block/extension/placeholder.ts +4 -4
  28. package/src/parser/block/extension/table.test.ts +0 -1
  29. package/src/parser/block/extension/table.ts +2 -8
  30. package/src/parser/block/extension.ts +1 -2
  31. package/src/parser/block/mathblock.test.ts +0 -2
  32. package/src/parser/block/mathblock.ts +4 -4
  33. package/src/parser/context.ts +9 -12
  34. package/src/parser/document.ts +1 -1
  35. package/src/parser/inline/autolink/url.ts +4 -4
  36. package/src/parser/inline/math.ts +1 -1
  37. package/src/parser/inline/media.ts +4 -4
  38. package/src/parser/inline/ruby.ts +45 -8
  39. package/src/parser/inline/template.ts +4 -4
  40. package/src/parser/source/escapable.ts +0 -1
  41. package/src/parser/source/text.ts +14 -43
  42. package/src/parser/source/unescapable.ts +0 -1
  43. package/src/parser/source/whitespace.ts +36 -0
  44. package/src/parser/source.ts +1 -0
  45. package/src/parser/visibility.ts +2 -1
package/index.d.ts CHANGED
@@ -44,7 +44,7 @@ export type Progress =
44
44
  | { readonly type: 'block'; readonly value: HTMLElement; }
45
45
  | { readonly type: 'figure'; readonly value: HTMLAnchorElement; }
46
46
  | { readonly type: 'note'; readonly value: HTMLLIElement | HTMLElement; }
47
- | { readonly type: 'break'; }
47
+ | { readonly type: 'break'; readonly value: 'segment' | 'block' | 'parser' | 'figure' | 'note'; }
48
48
  | { readonly type: 'cancel'; };
49
49
 
50
50
  export interface RenderingOptions {
package/markdown.d.ts CHANGED
@@ -325,7 +325,6 @@ export namespace MarkdownParser {
325
325
  Parser<string, Input, [
326
326
  FigParser.SegmentParser,
327
327
  FigureParser.SegmentParser,
328
- TableParser.SegmentParser,
329
328
  PlaceholderParser.SegmentParser,
330
329
  ]> {
331
330
  }
@@ -350,8 +349,8 @@ export namespace MarkdownParser {
350
349
  MathBlockParser,
351
350
  ExampleParser,
352
351
  TableParser,
353
- BlockquoteParser,
354
352
  PlaceholderParser,
353
+ BlockquoteParser,
355
354
  InlineParser.MediaParser,
356
355
  InlineParser.ShortMediaParser.LineShortMediaParser,
357
356
  ]>,
@@ -369,9 +368,8 @@ export namespace MarkdownParser {
369
368
  Parser<never, Input, [
370
369
  CodeBlockParser.SegmentParser,
371
370
  MathBlockParser.SegmentParser,
372
- TableParser.SegmentParser,
373
- BlockquoteParser.SegmentParser,
374
371
  PlaceholderParser.SegmentParser,
372
+ BlockquoteParser.SegmentParser,
375
373
  SourceParser.ContentLineParser,
376
374
  ]>,
377
375
  SourceParser.EmptyLineParser,
@@ -399,9 +397,8 @@ export namespace MarkdownParser {
399
397
  Parser<never, Input, [
400
398
  CodeBlockParser.SegmentParser,
401
399
  MathBlockParser.SegmentParser,
402
- TableParser.SegmentParser,
403
- BlockquoteParser.SegmentParser,
404
400
  PlaceholderParser.SegmentParser,
401
+ BlockquoteParser.SegmentParser,
405
402
  SourceParser.ContentLineParser,
406
403
  ]>,
407
404
  ]> {
@@ -427,10 +424,6 @@ export namespace MarkdownParser {
427
424
  ]> {
428
425
  }
429
426
  export namespace TableParser {
430
- export interface SegmentParser extends
431
- Block<'extension/table/segment'>,
432
- Parser<never, Input, []> {
433
- }
434
427
  export interface GridTableParser extends
435
428
  Block<'extension/table/gridtable'>,
436
429
  Parser<HTMLElement, Input, [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "securemark",
3
- "version": "0.300.0",
3
+ "version": "0.300.2",
4
4
  "description": "Secure markdown renderer working on browsers for user input data.",
5
5
  "private": false,
6
6
  "homepage": "https://github.com/falsandtru/securemark",
package/src/api/bind.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { ParserSettings, Progress } from '../..';
2
2
  import { Input, Options, Segment } from '../parser/context';
3
- import { Output, subinput, run } from '../combinator/parser';
3
+ import { Output, run } from '../combinator/parser';
4
4
  import { segment } from '../parser/segment';
5
5
  import { block } from '../parser/block';
6
6
  import { headers } from './header';
@@ -74,8 +74,8 @@ export function bind(target: DocumentFragment | HTMLElement | ShadowRoot, settin
74
74
  assert(rev === revision);
75
75
  const seg = sourceSegments[index];
76
76
  options.segment = sourceSegmentAttrs[index] | Segment.write;
77
- for (const _ of run(block, subinput(seg, new Input(options)), output)) {
78
- yield { type: 'break' };
77
+ for (const _ of run(block, new Input(options, seg), output)) {
78
+ yield { type: 'break', value: 'block' };
79
79
  }
80
80
  assert(output.data.length === 1);
81
81
  const es = output.pop()
@@ -124,20 +124,20 @@ export function bind(target: DocumentFragment | HTMLElement | ShadowRoot, settin
124
124
  yield { type: 'block', value: el };
125
125
  if (rev !== revision) return yield { type: 'cancel' };
126
126
  }
127
- yield { type: 'break' };
127
+ yield { type: 'break', value: 'parser' };
128
128
  if (rev !== revision) return yield { type: 'cancel' };
129
129
  for (const el of figure(next(0)?.parentNode ?? target, settings.notes, options)) {
130
130
  assert(rev === revision);
131
131
  el
132
132
  ? yield { type: 'figure', value: el }
133
- : yield { type: 'break' };
133
+ : yield { type: 'break', value: 'figure' };
134
134
  if (rev !== revision) return yield { type: 'cancel' };
135
135
  }
136
136
  for (const el of note(next(0)?.parentNode ?? target, settings.notes, options, bottom)) {
137
137
  assert(rev === revision);
138
138
  el
139
139
  ? yield { type: 'note', value: el }
140
- : yield { type: 'break' };
140
+ : yield { type: 'break', value: 'note' };
141
141
  if (rev !== revision) return yield { type: 'cancel' };
142
142
  }
143
143
  }
package/src/api/parse.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { ParserOptions } from '../..';
2
- import { Input, Options, input } from '../parser/context';
2
+ import { Input, Options } from '../parser/context';
3
3
  import { Output, run } from '../combinator/parser';
4
4
  import { document } from '../parser/document';
5
5
  import { ReadonlyURL } from 'spica/url';
@@ -23,7 +23,7 @@ export function* parse(source: string, opts: Opts = {}, options?: Options): Gene
23
23
  if (options.id?.match(/[^0-9a-z/-]/i)) throw new Error('Invalid ID: ID must be alphanumeric');
24
24
  if (options.host?.origin === 'null') throw new Error(`Invalid host: ${options.host.href}`);
25
25
  const output = new Output<DocumentFragment>();
26
- for (const _ of run(document, input(source, new Input(options)), output)) yield;
26
+ for (const _ of run(document, new Input(options, source), output)) yield;
27
27
  assert(output.data.length === 1);
28
28
  assert(output.peek().length === 1);
29
29
  return output.peek().head!.value;
@@ -1,16 +1,16 @@
1
- import { Parser, SubParsers } from '../parser';
1
+ import { Parser, SubParsers, Result } from '../parser';
2
2
  import { union } from './union';
3
3
  import { sequence } from './sequence';
4
- import { recovery } from './state';
5
4
 
6
5
  export function inits<P extends Parser>(parsers: Parser.SubParsers<P>): P;
7
6
  export function inits<T>(parsers: SubParsers<T>): Parser<T> {
8
7
  assert(parsers.every(f => f));
9
8
  switch (parsers.length) {
10
9
  case 0:
10
+ assert(false);
11
11
  return (_, output) => output.context;
12
12
  case 1:
13
- return () => parsers;
13
+ return parsers[0];
14
14
  default:
15
15
  return parsers.reduceRight((acc, parser, i) =>
16
16
  sequence([
@@ -19,8 +19,17 @@ export function inits<T>(parsers: SubParsers<T>): Parser<T> {
19
19
  ? acc
20
20
  : union([
21
21
  acc,
22
- recovery(),
22
+ recovery,
23
23
  ]),
24
24
  ]));
25
25
  }
26
26
  }
27
+
28
+ const recovery: Parser<never> = (_, output) => {
29
+ if (output.state) {
30
+ output.state = true;
31
+ // @ts-expect-error
32
+ output.context ??= Result.succ;
33
+ }
34
+ return output.context;
35
+ };
@@ -6,8 +6,10 @@ export function sequence<T>(parsers: SubParsers<T>): Parser<T> {
6
6
  assert(parsers.every(f => f));
7
7
  switch (parsers.length) {
8
8
  case 0:
9
+ assert(false);
10
+ return (_, output) => output.context;
9
11
  case 1:
10
- return () => parsers;
12
+ return parsers[0];
11
13
  default:
12
14
  return parsers.reduceRight((acc, parser) => always([
13
15
  parser,
@@ -1,4 +1,4 @@
1
- import { Parser, SubParsers, Result } from '../parser';
1
+ import { Parser, SubParsers } from '../parser';
2
2
 
3
3
  export function then<P extends Parser>(success: P, failure: P): P;
4
4
  export function then<T>(success: Parser<T>, failure: Parser<T>): Parser<T> {
@@ -31,12 +31,3 @@ export function force<T>(parser: Parser<T>): Parser<T> {
31
31
  ? output.context
32
32
  : parser(input, output);
33
33
  }
34
-
35
- export function recovery<P extends Parser>(parser?: P): P;
36
- export function recovery<T>(parser: Parser<T> = () => Result.succ): Parser<T> {
37
- return (input, output) => {
38
- output.state = true;
39
- output.context = Result.succ;
40
- return parser(input, output);
41
- };
42
- }
@@ -1,14 +1,15 @@
1
- import { Parser, SubParsers } from '../parser';
2
- import { failure, always, recovery } from './state';
1
+ import { Parser, SubParsers, Result } from '../parser';
2
+ import { failure, always } from './state';
3
3
 
4
4
  export function union<P extends Parser>(parsers: Parser.SubParsers<P>): P;
5
5
  export function union<T>(parsers: SubParsers<T>): Parser<T> {
6
6
  assert(parsers.every(f => f));
7
7
  switch (parsers.length) {
8
8
  case 0:
9
+ assert(false);
9
10
  return (_, output) => output.context;
10
11
  case 1:
11
- return () => parsers;
12
+ return parsers[0];
12
13
  default:
13
14
  return parsers.reduceRight((acc, parser) => always([
14
15
  parser,
@@ -16,3 +17,15 @@ export function union<T>(parsers: SubParsers<T>): Parser<T> {
16
17
  ]));
17
18
  }
18
19
  }
20
+
21
+ function recovery<P extends Parser>(parser: P): P;
22
+ function recovery<T>(parser: Parser<T>): Parser<T> {
23
+ return (input, output) => {
24
+ if (!output.state) {
25
+ output.state = true;
26
+ // @ts-expect-error
27
+ output.context ??= Result.succ;
28
+ }
29
+ return parser(input, output);
30
+ };
31
+ }
@@ -140,7 +140,7 @@ export class Output<T> {
140
140
  assert(data.length > 0);
141
141
  }
142
142
  public state: boolean = true;
143
- public context: Result.Succ | Result.Fail = Result.succ;
143
+ public readonly context: Result.Succ | Result.Fail = Result.succ;
144
144
  public error?: Error = undefined;
145
145
  public peek(): List<Node<T>> {
146
146
  assert(this.data.length > 0);
@@ -222,17 +222,24 @@ export function* run
222
222
  time = Date.now();
223
223
  }
224
224
  if (output.state && output.error) {
225
- output.state = false;
226
- output.context = Result.fail;
225
+ if (output.state) {
226
+ output.state = false;
227
+ // @ts-expect-error
228
+ output.context = Result.fail;
229
+ }
227
230
  }
228
231
  const input = scope.peek();
229
232
  //assert(input.position <= input.source.length);
230
- const result = queue.pop()(input, output);
233
+ const parser = queue.pop();
234
+ const result = parser(input, output);
231
235
 
232
236
  if (result) {
233
237
  //assert(result.every(f => f));
234
- output.state = true;
235
- output.context = Result.succ;
238
+ if (!output.state) {
239
+ output.state = true;
240
+ // @ts-expect-error
241
+ output.context ??= Result.succ;
242
+ }
236
243
  if (result.length !== 0) {
237
244
  if (queue.length !== 0) {
238
245
  queue.memory = input.memory;
@@ -249,8 +256,11 @@ export function* run
249
256
  if (result === Result.skip) {
250
257
  queue.length = 0;
251
258
  }
252
- output.state = false;
253
- output.context = Result.fail;
259
+ if (output.state) {
260
+ output.state = false;
261
+ // @ts-expect-error
262
+ output.context = Result.fail;
263
+ }
254
264
  }
255
265
 
256
266
  if (queue.length !== 0) continue;
@@ -2,15 +2,15 @@ import { Parser, SubParsers, Input, List, Node } from '../parser';
2
2
  import { spend } from '../effect/clock';
3
3
  import { firstline, isEmptyline } from './line';
4
4
 
5
- export function fence<I extends Input, S extends SubParsers<never, I>>(opener: RegExp, write: boolean, limit: number, separation = true): Parser<string, I, S> {
5
+ export function fence<I extends Input, S extends SubParsers<never, I>>(opener: RegExp, write: boolean, separation = true): Parser<string, I, S> {
6
6
  assert(!opener.flags.match(/[gm]/) && opener.sticky && !opener.source.startsWith('^'));
7
7
  return (input, output) => {
8
- const { source, position } = input;
9
- if (position === source.length) return;
10
- opener.lastIndex = position;
8
+ const { source } = input;
9
+ if (input.position === source.length) return;
10
+ opener.lastIndex = input.position;
11
11
  const matches = opener.exec(source);
12
12
  if (!matches) return;
13
- assert(matches[0] === firstline(source, position));
13
+ assert(matches[0] === firstline(source, input.position));
14
14
  spend(input, output, matches[0].length);
15
15
  const delim = matches[1];
16
16
  assert(delim && delim === delim.trim());
@@ -23,37 +23,27 @@ export function fence<I extends Input, S extends SubParsers<never, I>>(opener: R
23
23
  input.position -= matches[0].length;
24
24
  return;
25
25
  }
26
+ const { position } = input;
26
27
  let body = '';
27
28
  let closer = '';
28
- let overflow = '';
29
- for (let count = 1; ; ++count) {
30
- if (input.position === source.length) break;
31
- const line = firstline(source, input.position);
32
- if ((closer || count > limit + 1) && isEmptyline(line, 0)) break;
33
- if(closer) {
34
- overflow += line;
35
- }
36
- if (!closer && count <= limit + 1 && line.startsWith(delim) && line.trimEnd() === delim) {
37
- closer = line;
38
- if (isEmptyline(source, input.position + line.length)) {
39
- input.position += line.length;
40
- break;
41
- }
42
- if (!separation) {
43
- input.position += line.length;
44
- break;
45
- }
46
- assert(!overflow);
47
- overflow = line;
48
- }
49
- if (!overflow) {
50
- body += line;
51
- }
52
- input.position += line.length;
29
+ assert(matches[0].endsWith('\n'));
30
+ for (input.position -= 1; ;) {
31
+ input.position = source.indexOf(`\n${delim}`, input.position) + 1 || source.length;
32
+ if (!isEmptyline(source, input.position + delim.length)) continue;
33
+ body = source.slice(position, input.position);
34
+ closer = firstline(source, input.position);
35
+ input.position += closer.length;
36
+ break;
37
+ }
38
+ if (separation) for (; !isEmptyline(source, input.position);) {
39
+ input.position = source.indexOf('\n', input.position) + 1 || source.length;
40
+ }
41
+ if (write) {
42
+ const overflow = source.slice(position + body.length + closer.length, input.position);
43
+ output.push(
44
+ new List([body, overflow, closer].map(str => new Node(str)))
45
+ .import(new List(matches.map(str => new Node(str)))));
53
46
  }
54
- write && output.push(
55
- new List([body, overflow, closer].map(str => new Node(str)))
56
- .import(new List(matches.map(str => new Node(str)))));
57
47
  return output.context;
58
48
  };
59
49
  }
@@ -49,7 +49,7 @@ export function firstline(source: string, position: number): string {
49
49
  const emptyline = /[^\S\r\n]*(?:$|\r?\n)/y;
50
50
  export function isEmptyline(source: string, position: number): boolean {
51
51
  emptyline.lastIndex = position;
52
- return source.length === position
52
+ return position >= source.length
53
53
  || source[position] === '\n'
54
54
  || emptyline.test(source);
55
55
  }
@@ -136,6 +136,7 @@ export function surround<T>(
136
136
  const o = output.pop();
137
137
  if (!g) return;
138
138
  output.state = true;
139
+ // @ts-expect-error
139
140
  output.context = Result.succ;
140
141
  return g([o, state ? m : undefined], input, output);
141
142
  }
@@ -156,6 +157,7 @@ export function surround<T>(
156
157
  wbs && setBacktrack(input, wbs, position);
157
158
  if (!g) return;
158
159
  output.state = true;
160
+ // @ts-expect-error
159
161
  output.context = Result.succ;
160
162
  return g([o, state ? m : undefined], input, output);
161
163
  }
@@ -22,7 +22,6 @@ describe('Unit: parser/block/codeblock', () => {
22
22
  assert.deepStrictEqual(inspect(parser, input('```\n````')), [['<pre class="invalid" translate="no">```\n````</pre>'], '']);
23
23
  assert.deepStrictEqual(inspect(parser, input('````\n```')), [['<pre class="invalid" translate="no">````\n```</pre>'], '']);
24
24
  assert.deepStrictEqual(inspect(parser, input(' ```\n```')), undefined);
25
- assert.deepStrictEqual(inspect(parser, input(`\`\`\`\n0${'\n'.repeat(301)}\`\`\``), '>'), [['<pre class="invalid" translate="no">'], '']);
26
25
  });
27
26
 
28
27
  it('basic', () => {
@@ -44,7 +43,6 @@ describe('Unit: parser/block/codeblock', () => {
44
43
  assert.deepStrictEqual(inspect(parser, input('```\n!http://host)\n```')), [['<pre class="text">!<a class="url" href="http://host)" target="_blank">http://host)</a></pre>'], '']);
45
44
  assert.deepStrictEqual(inspect(parser, input('```\n#a\n```')), [['<pre class="text"><a class="hashtag" href="/hashtags/a">#a</a></pre>'], '']);
46
45
  assert.deepStrictEqual(inspect(parser, input('```\n@a#b\n```')), [['<pre class="text"><a class="channel" href="/@a?ch=b">@a#b</a></pre>'], '']);
47
- assert.deepStrictEqual(inspect(parser, input(`\`\`\`\n0${'\n'.repeat(300)}\`\`\``), '>'), [['<pre class="text">'], '']);
48
46
  });
49
47
 
50
48
  it('attribute', () => {
@@ -9,13 +9,13 @@ const opener = /(`{3,})(?!`)([^\r\n]*)(?:$|\r?\n)/y;
9
9
  const language = /^[0-9a-z]+(?:-[a-z][0-9a-z]*)*$/i;
10
10
 
11
11
  export const segment: CodeBlockParser.SegmentParser = block(
12
- fence(opener, false, 300));
12
+ fence(opener, false));
13
13
 
14
14
  export const segment_: CodeBlockParser.SegmentParser = block(
15
- fence(opener, false, 300, false), false);
15
+ fence(opener, false, false), false);
16
16
 
17
17
  export const codeblock: CodeBlockParser = block(inits([
18
- fence(opener, true, 300),
18
+ fence(opener, true),
19
19
  (input, output) => {
20
20
  const [body, overflow, closer, opener, delim, param] = unwrap(output.pop()) as string[];
21
21
  const params = param.match(/(?:\\.?|\S)+/g)?.reduce<{
@@ -64,7 +64,7 @@ export const codeblock: CodeBlockParser = block(inits([
64
64
  ? `Invalid trailing line after the closing delimiter "${delim}"`
65
65
  : params.invalid!),
66
66
  },
67
- `${opener}${body}${overflow || closer}`)));
67
+ `${opener}${body}${closer}${overflow}`)));
68
68
  return;
69
69
  }
70
70
  const src = body.slice(0, body.at(-2) === '\r' ? -2 : -1);
@@ -11,7 +11,6 @@ describe('Unit: parser/block/extension/aside', () => {
11
11
  assert.deepStrictEqual(inspect(parser, input('~~~aside\n~~~')), [['<pre class="invalid" translate="no">~~~aside\n~~~</pre>'], '']);
12
12
  assert.deepStrictEqual(inspect(parser, input('~~~aside\n# \n~~~')), [['<pre class="invalid" translate="no">~~~aside\n# \n~~~</pre>'], '']);
13
13
  assert.deepStrictEqual(inspect(parser, input('~~~aside a\n# 0\n~~~')), [['<pre class="invalid" translate="no">~~~aside a\n# 0\n~~~</pre>'], '']);
14
- assert.deepStrictEqual(inspect(parser, input(`~~~aside\n# 0${'\n'.repeat(301)}~~~`), '>'), [['<pre class="invalid" translate="no">'], '']);
15
14
  });
16
15
 
17
16
  it('valid', () => {
@@ -14,7 +14,7 @@ interface Memory {
14
14
  }
15
15
 
16
16
  export const aside: ExtensionParser.AsideParser = block(recursion(Recursion.block, inits([
17
- fence(/(~{3,})aside(?!\S)([^\r\n]*)(?:$|\r?\n)/y, true, 300),
17
+ fence(/(~{3,})aside(?!\S)([^\r\n]*)(?:$|\r?\n)/y, true),
18
18
  (input: Input<Memory>, output) => {
19
19
  const [body, overflow, closer, opener, delim, param] = unwrap(output.pop()) as string[];
20
20
  if (!closer || overflow || param.trimStart()) {
@@ -30,7 +30,7 @@ export const aside: ExtensionParser.AsideParser = block(recursion(Recursion.bloc
30
30
  overflow ? `Invalid trailing line after the closing delimiter "${delim}"` :
31
31
  'Invalid argument'),
32
32
  },
33
- `${opener}${body}${overflow || closer}`)));
33
+ `${opener}${body}${closer}${overflow}`)));
34
34
  return;
35
35
  }
36
36
  input.memory = {
@@ -11,7 +11,6 @@ describe('Unit: parser/block/extension/example', () => {
11
11
  assert.deepStrictEqual(inspect(parser, input('~~~example/\n~~~')), undefined);
12
12
  assert.deepStrictEqual(inspect(parser, input('~~~example/a\n~~~')), [['<pre class="invalid" translate="no">~~~example/a\n~~~</pre>'], '']);
13
13
  assert.deepStrictEqual(inspect(parser, input('~~~example/markdown a\n~~~')), [['<pre class="invalid" translate="no">~~~example/markdown a\n~~~</pre>'], '']);
14
- assert.deepStrictEqual(inspect(parser, input(`~~~example/markdown\n0${'\n'.repeat(301)}~~~`), '>'), [['<pre class="invalid" translate="no">'], '']);
15
14
  });
16
15
 
17
16
  it('valid', () => {
@@ -27,7 +26,6 @@ describe('Unit: parser/block/extension/example', () => {
27
26
  assert.deepStrictEqual(inspect(parser, input('~~~example/markdown\n((a))[[b]]\n~~~')), [['<aside class="example" data-type="markdown"><pre translate="no">((a))[[b]]</pre><hr><section><p><sup class="annotation local" id="annotation:random:ref:a:1" title="a"><a href="#annotation:random:def:a:1">*1</a></sup><sup class="reference local" id="reference:random:ref:b:1" title="b"><a href="#reference:random:def:b">[1]</a></sup></p><ol class="annotations"><li id="annotation:random:def:a:1" data-marker="*1"><span>a</span><sup><a href="#annotation:random:ref:a:1">^1</a></sup></li></ol><h2>References</h2><ol class="references"><li id="reference:random:def:b"><span>b</span><sup><a href="#reference:random:ref:b:1">^1</a></sup></li></ol></section></aside>'], '']);
28
27
  assert.deepStrictEqual(inspect(parser, input('~~~~example/markdown\na\n~~~~')), [['<aside class="example" data-type="markdown"><pre translate="no">a</pre><hr><section><p>a</p><h2>References</h2><ol class="references"></ol></section></aside>'], '']);
29
28
  assert.deepStrictEqual(inspect(parser, input('~~~example/math\na\n~~~')), [['<aside class="example" data-type="math"><pre translate="no">a</pre><hr><div class="math" translate="no">$$\na\n$$</div></aside>'], '']);
30
- assert.deepStrictEqual(inspect(parser, input(`~~~example/math\n0${'\n'.repeat(100)}~~~`), '>'), [['<aside class="example" data-type="math">'], '']);
31
29
  });
32
30
 
33
31
  });
@@ -12,7 +12,7 @@ interface Memory {
12
12
  }
13
13
 
14
14
  export const example: ExtensionParser.ExampleParser = block(recursion(Recursion.block, inits([
15
- fence(/(~{3,})(?:example\/(\S+))?(?!\S)([^\r\n]*)(?:$|\r?\n)/y, true, 300),
15
+ fence(/(~{3,})(?:example\/(\S+))?(?!\S)([^\r\n]*)(?:$|\r?\n)/y, true),
16
16
  (input: Input<Memory>, output) => {
17
17
  const [body, overflow, closer, opener, delim, type = 'markdown', param] = unwrap(output.pop()) as string[];
18
18
  if (!closer || overflow || param.trimStart()) return output.append(
@@ -27,7 +27,7 @@ export const example: ExtensionParser.ExampleParser = block(recursion(Recursion.
27
27
  overflow ? `Invalid trailing line after the closing delimiter "${delim}"` :
28
28
  'Invalid argument'),
29
29
  },
30
- `${opener}${body}${overflow || closer}`)));
30
+ `${opener}${body}${closer}${overflow}`)));
31
31
  switch (type) {
32
32
  case 'markdown': {
33
33
  input.memory = {
@@ -1,30 +1,28 @@
1
1
  import { ExtensionParser } from '../../block';
2
2
  import { Segment } from '../../context';
3
3
  import { Result } from '../../../combinator/parser';
4
- import { union, sequence, some, always, backtrack, block, line, rewrite, close } from '../../../combinator';
4
+ import { union, sequence, some, always, block, line, rewrite, close } from '../../../combinator';
5
5
  import { contentline } from '../../source';
6
6
  import { figure } from './figure';
7
7
  import { segment as seg_label } from '../../inline/extension/label';
8
8
  import { segment as seg_code } from '../codeblock';
9
9
  import { segment as seg_math } from '../mathblock';
10
- import { segment as seg_table } from './table';
11
- import { segment as seg_blockquote } from '../blockquote';
12
10
  import { segment as seg_placeholder } from './placeholder';
11
+ import { segment as seg_blockquote } from '../blockquote';
13
12
 
14
13
  import FigParser = ExtensionParser.FigParser;
15
14
 
16
- export const segment: FigParser.SegmentParser = backtrack(block(
15
+ export const segment: FigParser.SegmentParser = block(
17
16
  sequence([
18
17
  line(close(seg_label, /(?!\S)[^\r\n]*\r?\n/y), false),
19
18
  union([
20
19
  seg_code,
21
20
  seg_math,
22
- seg_table,
23
- seg_blockquote,
24
21
  seg_placeholder,
22
+ seg_blockquote,
25
23
  some(contentline),
26
24
  ]),
27
- ]), true, Segment.fig));
25
+ ]), true, Segment.fig);
28
26
 
29
27
  export const fig: FigParser = block(rewrite(segment, always([
30
28
  (input, output) => {
@@ -33,8 +33,6 @@ describe('Unit: parser/block/extension/figure', () => {
33
33
  assert.deepStrictEqual(inspect(parser, input('~~~figure [$fig-name]\n> \n\n~~~')), [['<figure data-type="quote" data-label="fig-name" data-group="fig" class="invalid"><figcaption><span class="figindex"></span><span class="figtext"></span></figcaption><div><blockquote></blockquote></div></figure>'], '']);
34
34
  assert.deepStrictEqual(inspect(parser, input('~~~figure [$figure-name]\n> \n\n~~~')), [['<figure data-type="quote" data-label="figure-name" data-group="figure" class="invalid"><figcaption><span class="figindex"></span><span class="figtext"></span></figcaption><div><blockquote></blockquote></div></figure>'], '']);
35
35
  assert.deepStrictEqual(inspect(parser, input('~~~figure [$table-name]\n> \n\n~~~')), [['<figure data-type="quote" data-label="table-name" data-group="table" class="invalid"><figcaption><span class="figindex"></span><span class="figtext"></span></figcaption><div><blockquote></blockquote></div></figure>'], '']);
36
- assert.deepStrictEqual(inspect(parser, input(`~~~figure [$group-name]\n0${'\n'.repeat(301)}~~~`), '>'), [['<pre class="invalid" translate="no">'], '']);
37
- assert.deepStrictEqual(inspect(parser, input(`~~~figure [$group-name]\n~~~\n0${'\n'.repeat(301)}~~~\n~~~`), '>'), [['<pre class="invalid" translate="no">'], `${'\n'.repeat(300)}~~~\n~~~`]);
38
36
  });
39
37
 
40
38
  it('valid', () => {
@@ -70,8 +68,6 @@ describe('Unit: parser/block/extension/figure', () => {
70
68
  assert.deepStrictEqual(inspect(parser, input('~~~figure [$-0.0]\n$$\n\n$$\n~~~')), [['<figure data-type="math" data-label="$-0.0" data-group="$" class="invalid"><figcaption><span class="figindex"></span><span class="figtext"></span></figcaption><div><div class="math" translate="no">$$\n\n$$</div></div></figure>'], '']);
71
69
  assert.deepStrictEqual(inspect(parser, input('~~~figure [$-name]\n!https://host\n~~~')), [['<figure data-type="media" data-label="$-name" data-group="$" class="invalid"><figcaption><span class="figindex"></span><span class="figtext"></span></figcaption><div><a href="https://host" target="_blank"><img class="media" data-src="https://host" alt="https://host"></a></div></figure>'], '']);
72
70
  assert.deepStrictEqual(inspect(parser, input('~~~figure [$-name]\n$$\n\n$$\n\ncaption\n~~~')), [['<figure data-type="math" data-label="$-name" data-group="$" class="invalid"><figcaption><span class="figindex"></span><span class="figtext">caption</span></figcaption><div><div class="math" translate="no">$$\n\n$$</div></div></figure>'], '']);
73
- assert.deepStrictEqual(inspect(parser, input(`~~~figure [$group-name]\n${'> \n'.repeat(500)}\n~~~`), '>'), [['<figure data-type="quote" data-label="group-name" data-group="group">'], '']);
74
- assert.deepStrictEqual(inspect(parser, input(`~~~figure [$group-name]\n~~~\n0${'\n'.repeat(300)}~~~\n~~~`), '>'), [['<figure data-type="example" data-label="group-name" data-group="group">'], '']);
75
71
  });
76
72
 
77
73
  });
@@ -10,9 +10,9 @@ import { table as styled_table } from '../table';
10
10
  import { codeblock, segment_ as seg_code } from '../codeblock';
11
11
  import { mathblock, segment_ as seg_math } from '../mathblock';
12
12
  import { example } from './example';
13
- import { table, segment_ as seg_table } from './table';
14
- import { blockquote, segment as seg_blockquote } from '../blockquote';
13
+ import { table } from './table';
15
14
  import { placeholder, segment_ as seg_placeholder } from './placeholder';
15
+ import { blockquote, segment as seg_blockquote } from '../blockquote';
16
16
  import { inline, media, lineshortmedia } from '../../inline';
17
17
  import { visualize, trimBlank } from '../../visibility';
18
18
  import { unwrap, invalid } from '../../util';
@@ -32,9 +32,8 @@ export const segment: FigureParser.SegmentParser = block(match(
32
32
  union([
33
33
  seg_code,
34
34
  seg_math,
35
- seg_table,
36
- seg_blockquote,
37
35
  seg_placeholder,
36
+ seg_blockquote,
38
37
  some(contentline, closer),
39
38
  ]),
40
39
  emptyline,
@@ -60,8 +59,8 @@ export const figure: FigureParser = block(fallback(rewrite(segment, fmap(
60
59
  mathblock,
61
60
  example,
62
61
  table,
63
- blockquote,
64
62
  placeholder,
63
+ blockquote,
65
64
  line(media, false),
66
65
  line(lineshortmedia, false),
67
66
  ])),
@@ -84,7 +83,7 @@ export const figure: FigureParser = block(fallback(rewrite(segment, fmap(
84
83
  ]);
85
84
  })),
86
85
  inits([
87
- fence(/(~{3,})(?:figure(?=$|[ \r\n])|\[?\$)[^\r\n]*(?:$|\r?\n)/y, true, 300),
86
+ fence(/(~{3,})(?:figure(?=$|[ \r\n])|\[?\$)[^\r\n]*(?:$|\r?\n)/y, true),
88
87
  (_, output) => {
89
88
  const [body, overflow, closer, opener, delim] = unwrap(output.pop()) as string[];
90
89
  const violation =
@@ -115,7 +114,7 @@ export const figure: FigureParser = block(fallback(rewrite(segment, fmap(
115
114
  translate: 'no',
116
115
  ...invalid('figure', violation[0], violation[1]),
117
116
  },
118
- `${opener}${body}${overflow || closer}`)));
117
+ `${opener}${body}${closer}${overflow}`)));
119
118
  },
120
119
  ])));
121
120
 
@@ -12,7 +12,6 @@ describe('Unit: parser/block/extension/message', () => {
12
12
  assert.deepStrictEqual(inspect(parser, input('~~~message/\n~~~')), undefined);
13
13
  assert.deepStrictEqual(inspect(parser, input('~~~message/a\n~~~')), [['<pre class="invalid" translate="no">~~~message/a\n~~~</pre>'], '']);
14
14
  assert.deepStrictEqual(inspect(parser, input('~~~message/note a\n~~~')), [['<pre class="invalid" translate="no">~~~message/note a\n~~~</pre>'], '']);
15
- assert.deepStrictEqual(inspect(parser, input(`~~~message/note\n0${'\n'.repeat(301)}~~~`), '>'), [['<pre class="invalid" translate="no">'], '']);
16
15
  });
17
16
 
18
17
  it('valid', () => {
@@ -20,7 +20,7 @@ import { html } from 'typed-dom/dom';
20
20
  import MessageParser = ExtensionParser.MessageParser;
21
21
 
22
22
  export const message: MessageParser = block(inits([
23
- fence(/(~{3,})message\/(\S+)(?!\S)([^\r\n]*)(?:$|\r?\n)/y, true, 300),
23
+ fence(/(~{3,})message\/(\S+)(?!\S)([^\r\n]*)(?:$|\r?\n)/y, true),
24
24
  (input, output) => {
25
25
  const [body, overflow, closer, opener, delim, type, param] = unwrap(output.pop()) as string[];
26
26
  if (!closer || overflow || param.trimStart()) {
@@ -36,7 +36,7 @@ export const message: MessageParser = block(inits([
36
36
  overflow ? `Invalid trailing line after the closing delimiter "${delim}"` :
37
37
  'Invalid argument'),
38
38
  },
39
- `${opener}${body}${overflow || closer}`)));
39
+ `${opener}${body}${closer}${overflow}`)));
40
40
  return;
41
41
  }
42
42
  switch (type) {