securemark 0.242.0 → 0.243.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.
package/markdown.d.ts CHANGED
@@ -87,6 +87,7 @@ export namespace MarkdownParser {
87
87
  BlockParser.CodeBlockParser,
88
88
  BlockParser.MathBlockParser,
89
89
  BlockParser.ExtensionParser,
90
+ BlockParser.SidefenceParser,
90
91
  BlockParser.BlockquoteParser,
91
92
  BlockParser.ReplyParser,
92
93
  BlockParser.ParagraphParser,
@@ -227,6 +228,22 @@ export namespace MarkdownParser {
227
228
  ]> {
228
229
  }
229
230
  }
231
+ export interface SidefenceParser extends
232
+ // | abc
233
+ Block<'sidefence'>,
234
+ Parser<HTMLQuoteElement, Context, [
235
+ SidefenceParser.SourceParser,
236
+ ]> {
237
+ }
238
+ export namespace SidefenceParser {
239
+ export interface SourceParser extends
240
+ Block<'sidefence/source'>,
241
+ Parser<HTMLQuoteElement, Context, [
242
+ SourceParser,
243
+ AutolinkParser,
244
+ ]> {
245
+ }
246
+ }
230
247
  export interface TableParser extends
231
248
  // |Head|
232
249
  // |:--:|
@@ -356,6 +373,7 @@ export namespace MarkdownParser {
356
373
  PlaceholderParser,
357
374
  InlineParser.MediaParser,
358
375
  InlineParser.ShortmediaParser,
376
+ Parser<HTMLElement, Context, []>,
359
377
  ]>,
360
378
  SourceParser.EmptyLineParser,
361
379
  InlineParser,
@@ -371,8 +389,8 @@ export namespace MarkdownParser {
371
389
  Parser<never, Context, [
372
390
  CodeBlockParser.SegmentParser,
373
391
  MathBlockParser.SegmentParser,
374
- BlockquoteParser.SegmentParser,
375
392
  TableParser.SegmentParser,
393
+ BlockquoteParser.SegmentParser,
376
394
  PlaceholderParser.SegmentParser,
377
395
  SourceParser.ContentLineParser,
378
396
  ]>,
@@ -401,8 +419,8 @@ export namespace MarkdownParser {
401
419
  Parser<never, Context, [
402
420
  CodeBlockParser.SegmentParser,
403
421
  MathBlockParser.SegmentParser,
404
- BlockquoteParser.SegmentParser,
405
422
  TableParser.SegmentParser,
423
+ BlockquoteParser.SegmentParser,
406
424
  PlaceholderParser.SegmentParser,
407
425
  SourceParser.ContentLineParser,
408
426
  ]>,
@@ -495,6 +513,7 @@ export namespace MarkdownParser {
495
513
  BlockParser.IndentBlockParser,
496
514
  BlockParser.CodeBlockParser,
497
515
  BlockParser.MathBlockParser,
516
+ BlockParser.SidefenceParser,
498
517
  BlockParser.BlockquoteParser,
499
518
  BlockParser.ParagraphParser,
500
519
  ]> {
package/package-lock.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "securemark",
3
- "version": "0.242.0",
3
+ "version": "0.243.0",
4
4
  "lockfileVersion": 1,
5
5
  "requires": true,
6
6
  "dependencies": {
@@ -1784,9 +1784,9 @@
1784
1784
  "dev": true
1785
1785
  },
1786
1786
  "cacache": {
1787
- "version": "16.0.6",
1788
- "resolved": "https://registry.npmjs.org/cacache/-/cacache-16.0.6.tgz",
1789
- "integrity": "sha512-9a/MLxGaw3LEGes0HaPez2RgZWDV6X0jrgChsuxfEh8xoDoYGxaGrkMe7Dlyjrb655tA/b8fX0qlUg6Ii5MBvw==",
1787
+ "version": "16.0.7",
1788
+ "resolved": "https://registry.npmjs.org/cacache/-/cacache-16.0.7.tgz",
1789
+ "integrity": "sha512-a4zfQpp5vm4Ipdvbj+ZrPonikRhm6WBEd4zT1Yc1DXsmAxrPgDwWBLF/u/wTVXSFPIgOJ1U3ghSa2Xm4s3h28w==",
1790
1790
  "dev": true,
1791
1791
  "requires": {
1792
1792
  "@npmcli/fs": "^2.1.0",
@@ -3075,9 +3075,9 @@
3075
3075
  "dev": true
3076
3076
  },
3077
3077
  "electron-to-chromium": {
3078
- "version": "1.4.123",
3079
- "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.123.tgz",
3080
- "integrity": "sha512-0pHGE53WkYoFbsgwYcVKEpWa6jbzlvkohIEA2CUoZ9b5KC+w/zlMiQHvW/4IBcOh7YoEFqRNavgTk02TBoUTUw==",
3078
+ "version": "1.4.124",
3079
+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.124.tgz",
3080
+ "integrity": "sha512-VhaE9VUYU6d2eIb+4xf83CATD+T+3bTzvxvlADkQE+c2hisiw3sZmvEDtsW704+Zky9WZGhBuQXijDVqSriQLA==",
3081
3081
  "dev": true
3082
3082
  },
3083
3083
  "elliptic": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "securemark",
3
- "version": "0.242.0",
3
+ "version": "0.243.0",
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",
@@ -15,14 +15,8 @@ export const blockquote: BlockquoteParser = lazy(() => block(rewrite(segment, un
15
15
  ]))));
16
16
 
17
17
  const opener = /^(?=>>+(?:$|\s))/;
18
-
19
18
  const indent = block(open(opener, some(contentline, /^>(?:$|\s)/)), false);
20
-
21
- function unindent(source: string): string {
22
- return source
23
- .replace(/\n$/, '')
24
- .replace(/^>(?:$|\s|(?=>+(?:$|\s)))/mg, '');
25
- }
19
+ const unindent = (source: string) => source.replace(/(^|\n)>(?:[^\S\n]|(?=>*(?:$|\s)))|\n$/g, '$1');
26
20
 
27
21
  const source: BlockquoteParser.SourceParser = lazy(() => fmap(
28
22
  some(creator(union([
@@ -1,12 +1,12 @@
1
1
  import { ExtensionParser } from '../../block';
2
- import { union, sequence, some, block, line, validate, rewrite, close, convert } from '../../../combinator';
2
+ import { union, sequence, some, block, line, validate, verify, rewrite, close, convert } from '../../../combinator';
3
3
  import { contentline } from '../../source';
4
4
  import { figure } from './figure';
5
5
  import { segment as seg_label } from '../../inline/extension/label';
6
6
  import { segment as seg_code } from '../codeblock';
7
7
  import { segment as seg_math } from '../mathblock';
8
- import { segment as seg_blockquote } from '../blockquote';
9
8
  import { segment as seg_table } from './table';
9
+ import { segment as seg_blockquote } from '../blockquote';
10
10
  import { segment as seg_placeholder } from './placeholder';
11
11
 
12
12
  import FigParser = ExtensionParser.FigParser;
@@ -17,17 +17,18 @@ export const segment: FigParser.SegmentParser = block(validate(['[$', '$'],
17
17
  union([
18
18
  seg_code,
19
19
  seg_math,
20
- seg_blockquote,
21
20
  seg_table,
21
+ seg_blockquote,
22
22
  seg_placeholder,
23
23
  some(contentline),
24
24
  ]),
25
25
  ])));
26
26
 
27
- export const fig: FigParser = block(rewrite(segment, convert(
27
+ export const fig: FigParser = block(rewrite(segment, verify(convert(
28
28
  source => {
29
29
  const fence = (/^[^\n]*\n!?>+\s/.test(source) && source.match(/^~{3,}(?=[^\S\n]*$)/mg) || [])
30
30
  .reduce((max, fence) => fence > max ? fence : max, '~~') + '~';
31
31
  return `${fence}figure ${source}\n\n${fence}`;
32
32
  },
33
- union([figure]))));
33
+ union([figure])),
34
+ ([el]) => el.className !== 'invalid' || el.getAttribute('data-invalid-type') !== 'content')));
@@ -10,19 +10,19 @@ describe('Unit: parser/block/extension/figure', () => {
10
10
  assert.deepStrictEqual(inspect(parser('~~~figure\n!https://host\n~~~')), undefined);
11
11
  assert.deepStrictEqual(inspect(parser('~~~figure $group-name]\n!https://host\n~~~')), [['<figure data-type="media" data-label="group-name" data-group="group" class="invalid"><figcaption><span class="figindex"></span></figcaption><div><a href="https://host" target="_blank"><img class="media" data-src="https://host" alt=""></a></div></figure>'], '']);
12
12
  assert.deepStrictEqual(inspect(parser('~~~figure [$group-name\n!https://host\n~~~')), undefined);
13
- assert.deepStrictEqual(inspect(parser('~~~figure [$group-name]\nhttps://host\n~~~')), undefined);
14
- assert.deepStrictEqual(inspect(parser('~~~figure [$group-name]\n!https://host\\\n~~~')), undefined);
15
- assert.deepStrictEqual(inspect(parser('~~~figure [$group-name]\n!https://host\n\\\n~~~')), undefined);
16
- assert.deepStrictEqual(inspect(parser('~~~figure [$group-name]\n!https://host\na\n~~~')), undefined);
13
+ assert.deepStrictEqual(inspect(parser('~~~figure [$group-name]\nhttps://host\n~~~')), [['<figure data-type="invalid" data-label="group-name" data-group="group" class="invalid"><figcaption><span class="figindex"></span></figcaption><div><br></div></figure>'], '']);
14
+ assert.deepStrictEqual(inspect(parser('~~~figure [$group-name]\n!https://host\\\n~~~')), [['<figure data-type="invalid" data-label="group-name" data-group="group" class="invalid"><figcaption><span class="figindex"></span></figcaption><div><br></div></figure>'], '']);
15
+ assert.deepStrictEqual(inspect(parser('~~~figure [$group-name]\n!https://host\n\\\n~~~')), [['<figure data-type="invalid" data-label="group-name" data-group="group" class="invalid"><figcaption><span class="figindex"></span></figcaption><div><br></div></figure>'], '']);
16
+ assert.deepStrictEqual(inspect(parser('~~~figure [$group-name]\n!https://host\na\n~~~')), [['<figure data-type="invalid" data-label="group-name" data-group="group" class="invalid"><figcaption><span class="figindex"></span></figcaption><div><br></div></figure>'], '']);
17
17
  assert.deepStrictEqual(inspect(parser('~~~figure [$group-name]\n!https://host\n\n\n\n~~~')), undefined);
18
- assert.deepStrictEqual(inspect(parser('~~~figure [$group-name]\n !https://host\n~~~')), undefined);
18
+ assert.deepStrictEqual(inspect(parser('~~~figure [$group-name]\n !https://host\n~~~')), [['<figure data-type="invalid" data-label="group-name" data-group="group" class="invalid"><figcaption><span class="figindex"></span></figcaption><div><br></div></figure>'], '']);
19
19
  assert.deepStrictEqual(inspect(parser('~~~figure [$group-name]\n\n!https://host\n~~~')), undefined);
20
20
  assert.deepStrictEqual(inspect(parser('~~~figure [$group-name]\n!https://host\n~~~\n~~~')), undefined);
21
21
  assert.deepStrictEqual(inspect(parser('~~~figure [$group-name]\n!https://host\n~~~~')), undefined);
22
22
  assert.deepStrictEqual(inspect(parser('~~~~figure [$group-name]\n!https://host\n~~~')), undefined);
23
- assert.deepStrictEqual(inspect(parser('~~~figure [$group-name]a\nhttps://host\n~~~')), undefined);
23
+ assert.deepStrictEqual(inspect(parser('~~~figure [$group-name]a\nhttps://host\n~~~')), [['<figure data-type="invalid" data-label="group-name" data-group="group" class="invalid"><figcaption><span class="figindex"></span></figcaption><div><br></div></figure>'], '']);
24
24
  assert.deepStrictEqual(inspect(parser('~~~figure [$group-name]a\n!https://host\n~~~')), [['<figure data-type="media" data-label="group-name" data-group="group" class="invalid"><figcaption><span class="figindex"></span></figcaption><div><a href="https://host" target="_blank"><img class="media" data-src="https://host" alt=""></a></div></figure>'], '']);
25
- assert.deepStrictEqual(inspect(parser('~~~figure [$group-name] a\nhttps://host\n~~~')), undefined);
25
+ assert.deepStrictEqual(inspect(parser('~~~figure [$group-name] a\nhttps://host\n~~~')), [['<figure data-type="invalid" data-label="group-name" data-group="group" class="invalid"><figcaption><span class="figindex"></span></figcaption><div><br></div></figure>'], '']);
26
26
  assert.deepStrictEqual(inspect(parser('~~~figure [$group-name] a\n!https://host\n~~~')), [['<figure data-type="media" data-label="group-name" data-group="group" class="invalid"><figcaption><span class="figindex"></span></figcaption><div><a href="https://host" target="_blank"><img class="media" data-src="https://host" alt=""></a></div></figure>'], '']);
27
27
  assert.deepStrictEqual(inspect(parser('~~~figure a[$group-name]\n!https://host\n~~~')), undefined);
28
28
  assert.deepStrictEqual(inspect(parser('~~~figure a [$group-name]\n!https://host\n~~~')), undefined);
@@ -34,8 +34,8 @@ export const segment: FigureParser.SegmentParser = block(match(
34
34
  union([
35
35
  seg_code,
36
36
  seg_math,
37
- seg_blockquote,
38
37
  seg_table,
38
+ seg_blockquote,
39
39
  seg_placeholder,
40
40
  some(contentline, closer),
41
41
  ]),
@@ -65,8 +65,9 @@ export const figure: FigureParser = block(rewrite(segment, fmap(
65
65
  table,
66
66
  blockquote,
67
67
  placeholder,
68
- line(media),
69
- line(shortmedia),
68
+ block(line(media)),
69
+ block(line(shortmedia)),
70
+ fmap(some(contentline), () => [html('br')]),
70
71
  ])),
71
72
  emptyline,
72
73
  block(localize(
@@ -103,6 +104,9 @@ function attributes(label: string, param: string, content: HTMLElement, caption:
103
104
  case 'A':
104
105
  type = 'media';
105
106
  break;
107
+ case 'BR':
108
+ type = 'invalid';
109
+ break;
106
110
  case 'text':
107
111
  case 'code':
108
112
  case 'math':
@@ -113,6 +117,10 @@ function attributes(label: string, param: string, content: HTMLElement, caption:
113
117
  assert(false);
114
118
  }
115
119
  const invalid =
120
+ type === 'invalid' && content.tagName === 'BR' && {
121
+ 'data-invalid-type': 'content',
122
+ 'data-invalid-message': 'Invalid content',
123
+ } ||
116
124
  /^[^-]+-(?:[0-9]+\.)*0$/.test(label) && {
117
125
  'data-invalid-type': 'label',
118
126
  'data-invalid-message': 'The last part of the fixed label numbers must not be 0',
@@ -10,6 +10,7 @@ import { table } from '../table';
10
10
  import { indentblock } from '../indentblock';
11
11
  import { codeblock } from '../codeblock';
12
12
  import { mathblock } from '../mathblock';
13
+ import { sidefence } from '../sidefence';
13
14
  import { blockquote } from '../blockquote';
14
15
  import { paragraph } from '../paragraph';
15
16
  import { html } from 'typed-dom/dom';
@@ -69,6 +70,7 @@ const content: MessageParser.ContentParser = union([
69
70
  indentblock,
70
71
  codeblock,
71
72
  mathblock,
73
+ sidefence,
72
74
  blockquote,
73
75
  paragraph,
74
76
  ]);
@@ -1,5 +1,6 @@
1
1
  import { ExtensionParser } from '../../block';
2
2
  import { block, validate, fence, clear, fmap } from '../../../combinator';
3
+ import { segment as label } from '../../inline/extension/label';
3
4
  import { html } from 'typed-dom/dom';
4
5
 
5
6
  const opener = /^(~{3,})(?!~)[^\n]*(?:$|\n)/;
@@ -12,12 +13,17 @@ export const segment_: ExtensionParser.PlaceholderParser.SegmentParser = block(v
12
13
 
13
14
  export const placeholder: ExtensionParser.PlaceholderParser = block(validate('~~~', fmap(
14
15
  fence(opener, Infinity),
15
- ([body, closer, opener, delim]) => [
16
+ ([body, closer, opener, delim]: string[], _, context) => [
16
17
  html('pre', {
17
18
  class: 'invalid',
18
19
  translate: 'no',
19
20
  'data-invalid-syntax': 'extension',
20
21
  'data-invalid-type': !closer ? 'fence' : 'syntax',
21
- 'data-invalid-message': !closer ? `Missing the closing delimiter "${delim}"` : 'Invalid syntax',
22
+ 'data-invalid-message': !closer ? `Missing the closing delimiter "${delim}"` : 'Invalid extension name',
23
+ ...closer && (opener.slice(delim.length).split(/\s/, 1)[0] === 'figure' || label(opener.slice(delim.length), context)) && {
24
+ 'data-invalid-syntax': 'figure',
25
+ 'data-invalid-type': 'content',
26
+ 'data-invalid-message': 'Invalid content',
27
+ },
22
28
  }, `${opener}${body}${closer}`)
23
29
  ])));
@@ -0,0 +1,66 @@
1
+ import { sidefence } from './sidefence';
2
+ import { some } from '../../combinator';
3
+ import { inspect } from '../../debug.test';
4
+
5
+ describe('Unit: parser/block/sidefence', () => {
6
+ describe('sidefence', () => {
7
+ const parser = (source: string) => some(sidefence)(source, {});
8
+
9
+ it('invalid', () => {
10
+ assert.deepStrictEqual(inspect(parser('')), undefined);
11
+ assert.deepStrictEqual(inspect(parser('\n')), undefined);
12
+ assert.deepStrictEqual(inspect(parser('|')), undefined);
13
+ assert.deepStrictEqual(inspect(parser('|a')), undefined);
14
+ assert.deepStrictEqual(inspect(parser('|\n')), undefined);
15
+ assert.deepStrictEqual(inspect(parser(' | ')), undefined);
16
+ assert.deepStrictEqual(inspect(parser('||')), undefined);
17
+ });
18
+
19
+ it('basic', () => {
20
+ assert.deepStrictEqual(inspect(parser('| ')), [['<blockquote class="invalid"></blockquote>'], '']);
21
+ assert.deepStrictEqual(inspect(parser('| \\')), [['<blockquote class="invalid"><pre>\\</pre></blockquote>'], '']);
22
+ assert.deepStrictEqual(inspect(parser('| \\\n')), [['<blockquote class="invalid"><pre>\\</pre></blockquote>'], '']);
23
+ assert.deepStrictEqual(inspect(parser('| a')), [['<blockquote class="invalid"><pre>a</pre></blockquote>'], '']);
24
+ assert.deepStrictEqual(inspect(parser('| a\n')), [['<blockquote class="invalid"><pre>a</pre></blockquote>'], '']);
25
+ assert.deepStrictEqual(inspect(parser('| a\nb')), undefined);
26
+ assert.deepStrictEqual(inspect(parser('| a\n b ')), undefined);
27
+ assert.deepStrictEqual(inspect(parser('| a\n|')), [['<blockquote class="invalid"><pre>a<br></pre></blockquote>'], '']);
28
+ assert.deepStrictEqual(inspect(parser('| a\n>>1')), undefined);
29
+ assert.deepStrictEqual(inspect(parser('| a\n| b ')), [['<blockquote class="invalid"><pre>a<br>b </pre></blockquote>'], '']);
30
+ assert.deepStrictEqual(inspect(parser('| a\n|\n')), [['<blockquote class="invalid"><pre>a<br></pre></blockquote>'], '']);
31
+ assert.deepStrictEqual(inspect(parser('| a\n|\nb')), undefined);
32
+ assert.deepStrictEqual(inspect(parser('| a\n|\n b ')), undefined);
33
+ assert.deepStrictEqual(inspect(parser('| a\n|\n|')), [['<blockquote class="invalid"><pre>a<br><br></pre></blockquote>'], '']);
34
+ assert.deepStrictEqual(inspect(parser('| a\n|\n>>1')), undefined);
35
+ assert.deepStrictEqual(inspect(parser('| a\n|\n| b ')), [['<blockquote class="invalid"><pre>a<br><br>b </pre></blockquote>'], '']);
36
+ assert.deepStrictEqual(inspect(parser('| a\\\nb')), undefined);
37
+ assert.deepStrictEqual(inspect(parser('| a ')), [['<blockquote class="invalid"><pre> a </pre></blockquote>'], '']);
38
+ assert.deepStrictEqual(inspect(parser('| \na')), undefined);
39
+ assert.deepStrictEqual(inspect(parser('|\na')), undefined);
40
+ assert.deepStrictEqual(inspect(parser('|\n a')), undefined);
41
+ assert.deepStrictEqual(inspect(parser('|\n|')), [['<blockquote class="invalid"><pre><br></pre></blockquote>'], '']);
42
+ assert.deepStrictEqual(inspect(parser('|\n| a')), [['<blockquote class="invalid"><pre><br>a</pre></blockquote>'], '']);
43
+ assert.deepStrictEqual(inspect(parser('| http://host')), [['<blockquote class="invalid"><pre><a href="http://host" target="_blank">http://host</a></pre></blockquote>'], '']);
44
+ assert.deepStrictEqual(inspect(parser('| !http://host')), [['<blockquote class="invalid"><pre>!<a href="http://host" target="_blank">http://host</a></pre></blockquote>'], '']);
45
+ assert.deepStrictEqual(inspect(parser('| #a')), [['<blockquote class="invalid"><pre><a href="/hashtags/a" class="hashtag">#a</a></pre></blockquote>'], '']);
46
+ assert.deepStrictEqual(inspect(parser('| @a#b')), [['<blockquote class="invalid"><pre><a href="/@a?ch=b" class="channel">@a#b</a></pre></blockquote>'], '']);
47
+ assert.deepStrictEqual(inspect(parser('| >>1\n| | b')), [['<blockquote class="invalid"><pre><a href="?at=1" class="anchor">&gt;&gt;1</a><br>| b</pre></blockquote>'], '']);
48
+ assert.deepStrictEqual(inspect(parser('| >>1\n| | b\n| c')), [['<blockquote class="invalid"><pre><a href="?at=1" class="anchor">&gt;&gt;1</a><br>| b<br>c</pre></blockquote>'], '']);
49
+ });
50
+
51
+ it('nest', () => {
52
+ assert.deepStrictEqual(inspect(parser('| a\n||')), [['<blockquote class="invalid"><pre>a</pre><blockquote></blockquote></blockquote>'], '']);
53
+ assert.deepStrictEqual(inspect(parser('| a\n|| b\n| c')), [['<blockquote class="invalid"><pre>a</pre><blockquote><pre>b</pre></blockquote><pre>c</pre></blockquote>'], '']);
54
+ assert.deepStrictEqual(inspect(parser('| a\n|| b\n|| c')), [['<blockquote class="invalid"><pre>a</pre><blockquote><pre>b<br>c</pre></blockquote></blockquote>'], '']);
55
+ assert.deepStrictEqual(inspect(parser('| a\n|| b\n||| c')), [['<blockquote class="invalid"><pre>a</pre><blockquote><pre>b</pre><blockquote><pre>c</pre></blockquote></blockquote></blockquote>'], '']);
56
+ assert.deepStrictEqual(inspect(parser('|| a')), [['<blockquote class="invalid"><blockquote><pre>a</pre></blockquote></blockquote>'], '']);
57
+ assert.deepStrictEqual(inspect(parser('|| a\n|')), [['<blockquote class="invalid"><blockquote><pre>a</pre></blockquote></blockquote>'], '']);
58
+ assert.deepStrictEqual(inspect(parser('|| a\n| b')), [['<blockquote class="invalid"><blockquote><pre>a</pre></blockquote><pre>b</pre></blockquote>'], '']);
59
+ assert.deepStrictEqual(inspect(parser('|| a\n||| b\n| c')), [['<blockquote class="invalid"><blockquote><pre>a</pre><blockquote><pre>b</pre></blockquote></blockquote><pre>c</pre></blockquote>'], '']);
60
+ assert.deepStrictEqual(inspect(parser('|| a\n| b\n||| c')), [['<blockquote class="invalid"><blockquote><pre>a</pre></blockquote><pre>b</pre><blockquote><blockquote><pre>c</pre></blockquote></blockquote></blockquote>'], '']);
61
+ assert.deepStrictEqual(inspect(parser('||| a\n|| b\n| c')), [['<blockquote class="invalid"><blockquote><blockquote><pre>a</pre></blockquote><pre>b</pre></blockquote><pre>c</pre></blockquote>'], '']);
62
+ });
63
+
64
+ });
65
+
66
+ });
@@ -0,0 +1,31 @@
1
+ import { SidefenceParser } from '../block';
2
+ import { union, some, block, focus, rewrite, creator, convert, lazy, fmap } from '../../combinator';
3
+ import { autolink } from '../autolink';
4
+ import { contentline } from '../source';
5
+ import { html, define, defrag } from 'typed-dom/dom';
6
+
7
+ export const sidefence: SidefenceParser = lazy(() => block(fmap(focus(
8
+ /^(?=\|+(?:[^\S\n]|\n\|))(?:\|+(?:[^\S\n][^\n]*)?(?:$|\n))+$/,
9
+ union([source])),
10
+ ([el]) => [
11
+ define(el, {
12
+ class: 'invalid',
13
+ 'data-invalid-syntax': 'sidefence',
14
+ 'data-invalid-type': 'syntax',
15
+ 'data-invalid-message': 'Reserved syntax',
16
+ }),
17
+ ])));
18
+
19
+ const opener = /^(?=\|\|+(?:$|\s))/;
20
+ const unindent = (source: string) => source.replace(/(^|\n)\|(?:[^\S\n]|(?=\|*(?:$|\s)))|\n$/g, '$1');
21
+
22
+ const source: SidefenceParser.SourceParser = lazy(() => fmap(
23
+ some(creator(union([
24
+ focus(
25
+ /^(?:\|\|+(?:[^\S\n][^\n]*)?(?:$|\n))+/,
26
+ convert(unindent, source)),
27
+ rewrite(
28
+ some(contentline, opener),
29
+ convert(unindent, fmap(some(autolink), ns => [html('pre', defrag(ns))]))),
30
+ ]))),
31
+ ns => [html('blockquote', ns)]));
@@ -13,6 +13,7 @@ import { indentblock } from './block/indentblock';
13
13
  import { codeblock } from './block/codeblock';
14
14
  import { mathblock } from './block/mathblock';
15
15
  import { extension } from './block/extension';
16
+ import { sidefence } from './block/sidefence';
16
17
  import { blockquote } from './block/blockquote';
17
18
  import { reply } from './block/reply';
18
19
  import { paragraph } from './block/paragraph';
@@ -31,6 +32,7 @@ export import IndentBlockParser = BlockParser.IndentBlockParser;
31
32
  export import CodeBlockParser = BlockParser.CodeBlockParser;
32
33
  export import MathBlockParser = BlockParser.MathBlockParser;
33
34
  export import ExtensionParser = BlockParser.ExtensionParser;
35
+ export import SidefenceParser = BlockParser.SidefenceParser;
34
36
  export import BlockquoteParser = BlockParser.BlockquoteParser;
35
37
  export import ReplyParser = BlockParser.ReplyParser;
36
38
  export import ParagraphParser = BlockParser.ParagraphParser;
@@ -50,6 +52,7 @@ export const block: BlockParser = creator(error(
50
52
  codeblock,
51
53
  mathblock,
52
54
  extension,
55
+ sidefence,
53
56
  blockquote,
54
57
  reply,
55
58
  paragraph
@@ -14,12 +14,12 @@ export const placeholder: ExtensionParser.PlaceholderParser = lazy(() => creator
14
14
  str(/^\[[:^]/),
15
15
  startTight(some(union([inline]), ']')),
16
16
  str(']'), false,
17
- ([, bs], rest) => [[
17
+ ([as, bs], rest) => [[
18
18
  html('span', {
19
19
  class: 'invalid',
20
20
  'data-invalid-syntax': 'extension',
21
21
  'data-invalid-type': 'syntax',
22
- 'data-invalid-message': 'Invalid symbol',
22
+ 'data-invalid-message': `Reserved start symbol "${as[0][1]}" cannot be used in "[]"`,
23
23
  }, defrag(bs)),
24
24
  ], rest],
25
25
  ([as, bs], rest) => [unshift(as, bs), rest]))));