securemark 0.231.2 → 0.232.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "securemark",
3
- "version": "0.231.2",
3
+ "version": "0.232.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",
@@ -51,17 +51,17 @@
51
51
  "gulp-rename": "^2.0.0",
52
52
  "gulp-unassert": "^2.0.0",
53
53
  "karma": "^6.3.17",
54
- "karma-chrome-launcher": "^3.1.0",
54
+ "karma-chrome-launcher": "^3.1.1",
55
55
  "karma-coverage-istanbul-instrumenter": "^1.0.4",
56
56
  "karma-coverage-istanbul-reporter": "^3.0.3",
57
57
  "karma-espower-preprocessor": "^1.2.0",
58
58
  "karma-firefox-launcher": "^2.1.2",
59
59
  "karma-mocha": "^2.0.1",
60
- "mocha": "^9.2.1",
61
- "npm-check-updates": "^12.5.2",
60
+ "mocha": "^9.2.2",
61
+ "npm-check-updates": "^12.5.4",
62
62
  "power-assert": "^1.6.1",
63
63
  "semver": "^7.3.5",
64
- "spica": "0.0.511",
64
+ "spica": "0.0.515",
65
65
  "tsify": "^5.0.4",
66
66
  "typed-dom": "0.0.249",
67
67
  "typescript": "4.6.2",
@@ -4,18 +4,18 @@ import { inspect } from '../../../debug.test';
4
4
  describe('Unit: combinator/indent', () => {
5
5
  describe('indent', () => {
6
6
  it('valid', () => {
7
- const parser = indent(s => [[s], '']);
8
- assert.deepStrictEqual(inspect(parser('')), undefined);
9
- assert.deepStrictEqual(inspect(parser(' ')), undefined);
10
- assert.deepStrictEqual(inspect(parser(' ')), undefined);
11
- assert.deepStrictEqual(inspect(parser('a ')), undefined);
12
- assert.deepStrictEqual(inspect(parser(' a ')), [['a '], '']);
13
- assert.deepStrictEqual(inspect(parser(' a ')), [['a '], '']);
14
- assert.deepStrictEqual(inspect(parser(' a\n a')), [['a\na'], '']);
15
- assert.deepStrictEqual(inspect(parser(' a\n a')), [['a\n a'], '']);
16
- assert.deepStrictEqual(inspect(parser(' a\n a')), [['a'], ' a']);
17
- assert.deepStrictEqual(inspect(parser(' \ta')), [['\ta'], '']);
18
- assert.deepStrictEqual(inspect(parser('\ta')), [['a'], '']);
7
+ const parser = indent((s, _) => [[s], '']);
8
+ assert.deepStrictEqual(inspect(parser('', {})), undefined);
9
+ assert.deepStrictEqual(inspect(parser(' ', {})), undefined);
10
+ assert.deepStrictEqual(inspect(parser(' ', {})), undefined);
11
+ assert.deepStrictEqual(inspect(parser('a ', {})), undefined);
12
+ assert.deepStrictEqual(inspect(parser(' a ', {})), [['a '], '']);
13
+ assert.deepStrictEqual(inspect(parser(' a ', {})), [['a '], '']);
14
+ assert.deepStrictEqual(inspect(parser(' a\n a', {})), [['a\na'], '']);
15
+ assert.deepStrictEqual(inspect(parser(' a\n a', {})), [['a\n a'], '']);
16
+ assert.deepStrictEqual(inspect(parser(' a\n a', {})), [['a'], ' a']);
17
+ assert.deepStrictEqual(inspect(parser(' \ta', {})), [['\ta'], '']);
18
+ assert.deepStrictEqual(inspect(parser('\ta', {})), [['a'], '']);
19
19
  });
20
20
 
21
21
  });
@@ -1,6 +1,7 @@
1
1
  import { undefined } from 'spica/global';
2
2
  import { Parser, Result, Ctx, Tree, Context, SubParsers, SubTree, IntermediateParser, eval, exec, check } from '../../data/parser';
3
3
  import { fmap } from '../monad/fmap';
4
+ import { creator } from './resource';
4
5
  import { unshift, push } from 'spica/array';
5
6
 
6
7
  export function surround<P extends Parser<unknown>, S = string>(
@@ -68,14 +69,14 @@ export function surround<T>(
68
69
  function match(pattern: string | RegExp): (source: string, context: Ctx) => [never[], string] | undefined {
69
70
  switch (typeof pattern) {
70
71
  case 'string':
71
- return source => source.slice(0, pattern.length) === pattern ? [[], source.slice(pattern.length)] : undefined;
72
+ return creator(source => source.slice(0, pattern.length) === pattern ? [[], source.slice(pattern.length)] : undefined);
72
73
  case 'object':
73
- return source => {
74
+ return creator(source => {
74
75
  const m = source.match(pattern);
75
76
  return m
76
77
  ? [[], source.slice(m[0].length)]
77
78
  : undefined;
78
- };
79
+ });
79
80
  }
80
81
  }
81
82
 
@@ -95,7 +95,7 @@ describe('Unit: parser/block/blockquote', () => {
95
95
  assert.deepStrictEqual(inspect(parser('!>\n> a')), [['<blockquote><section><p>a</p><ol class="annotations"></ol><ol class="references"></ol></section></blockquote>'], '']);
96
96
  assert.deepStrictEqual(inspect(parser('!>> ## a\n> ## a')), [['<blockquote><blockquote><section><h2>a</h2><ol class="annotations"></ol><ol class="references"></ol></section></blockquote><section><h2>a</h2><ol class="annotations"></ol><ol class="references"></ol></section></blockquote>'], '']);
97
97
  assert.deepStrictEqual(inspect(parser('!>> ~ a\n> ~ a')), [['<blockquote><blockquote><section><dl><dt>a</dt><dd></dd></dl><ol class="annotations"></ol><ol class="references"></ol></section></blockquote><section><dl><dt>a</dt><dd></dd></dl><ol class="annotations"></ol><ol class="references"></ol></section></blockquote>'], '']);
98
- assert.deepStrictEqual(inspect(parser('!>> ~~~figure $fig-a\n>> > \n>>\n~~~\n> ~~~figure $fig-a\n> > \n>\n[#a]\n~~~')), [['<blockquote><blockquote><section><figure data-label="fig-a" data-group="fig" data-number="1"><div class="figcontent"><blockquote></blockquote></div><span class="figindex">Fig. 1: </span><figcaption></figcaption></figure><ol class="annotations"></ol><ol class="references"></ol></section></blockquote><section><figure data-label="fig-a" data-group="fig" data-number="1"><div class="figcontent"><blockquote></blockquote></div><span class="figindex">Fig. 1: </span><figcaption><a class="index">a</a></figcaption></figure><ol class="annotations"></ol><ol class="references"></ol></section></blockquote>'], '']);
98
+ assert.deepStrictEqual(inspect(parser('!>> ~~~figure $fig-a\n>> > \n>>\n~~~\n> ~~~figure $fig-a\n> > \n>\n[#a]\n~~~')), [['<blockquote><blockquote><section><figure data-label="fig-a" data-group="fig" data-number="1"><div class="figcontent"><blockquote></blockquote></div><span class="figindex">Fig. 1. </span><figcaption></figcaption></figure><ol class="annotations"></ol><ol class="references"></ol></section></blockquote><section><figure data-label="fig-a" data-group="fig" data-number="1"><div class="figcontent"><blockquote></blockquote></div><span class="figindex">Fig. 1. </span><figcaption><a class="index">a</a></figcaption></figure><ol class="annotations"></ol><ol class="references"></ol></section></blockquote>'], '']);
99
99
  assert.deepStrictEqual(inspect(parser('!>> ((a))\n> ((a))')), [['<blockquote><blockquote><section><p><sup class="annotation disabled" title="a"><span hidden="">a</span><a>*1</a></sup></p><ol class="annotations"><li>a<sup><a>^1</a></sup></li></ol><ol class="references"></ol></section></blockquote><section><p><sup class="annotation disabled" title="a"><span hidden="">a</span><a>*1</a></sup></p><ol class="annotations"><li>a<sup><a>^1</a></sup></li></ol><ol class="references"></ol></section></blockquote>'], '']);
100
100
  });
101
101
 
@@ -16,7 +16,7 @@ describe('Unit: parser/block/extension/aside', () => {
16
16
  it('valid', () => {
17
17
  assert.deepStrictEqual(inspect(parser('~~~aside\n# 0\n~~~')), [['<aside id="index:0" class="aside"><h1>0</h1><ol class="annotations"></ol><ol class="references"></ol></aside>'], '']);
18
18
  assert.deepStrictEqual(inspect(parser('~~~aside\n## 0\n~~~')), [['<aside id="index:0" class="aside"><h2>0</h2><ol class="annotations"></ol><ol class="references"></ol></aside>'], '']);
19
- assert.deepStrictEqual(inspect(parser('~~~aside\n# 0\n\n$-0.0\n\n## 1\n\n$fig-a\n> \n~~~')), [['<aside id="index:0" class="aside"><h1>0</h1><figure data-label="$-0.0" data-group="$" hidden="" data-number="0.0"></figure><h2>1</h2><figure data-label="fig-a" data-group="fig" data-number="1.1"><div class="figcontent"><blockquote></blockquote></div><span class="figindex">Fig. 1.1: </span><figcaption></figcaption></figure><ol class="annotations"></ol><ol class="references"></ol></aside>'], '']);
19
+ assert.deepStrictEqual(inspect(parser('~~~aside\n# 0\n\n$-0.0\n\n## 1\n\n$fig-a\n> \n~~~')), [['<aside id="index:0" class="aside"><h1>0</h1><figure data-label="$-0.0" data-group="$" hidden="" data-number="0.0"></figure><h2>1</h2><figure data-label="fig-a" data-group="fig" data-number="1.1"><div class="figcontent"><blockquote></blockquote></div><span class="figindex">Fig. 1.1. </span><figcaption></figcaption></figure><ol class="annotations"></ol><ol class="references"></ol></aside>'], '']);
20
20
  });
21
21
 
22
22
  });
@@ -19,8 +19,8 @@ describe('Unit: parser/block/extension/example', () => {
19
19
  assert.deepStrictEqual(inspect(parser('~~~example/markdown\n\n~~~')), [['<aside class="example" data-type="markdown"><pre translate="no"></pre><hr><section><ol class="annotations"></ol><ol class="references"></ol></section></aside>'], '']);
20
20
  assert.deepStrictEqual(inspect(parser('~~~example/markdown\na\n~~~')), [['<aside class="example" data-type="markdown"><pre translate="no">a</pre><hr><section><p>a</p><ol class="annotations"></ol><ol class="references"></ol></section></aside>'], '']);
21
21
  assert.deepStrictEqual(inspect(parser('~~~example/markdown\n*a\nb*\n~~~')), [['<aside class="example" data-type="markdown"><pre translate="no">*a\nb*</pre><hr><section><p><em>a<br>b</em></p><ol class="annotations"></ol><ol class="references"></ol></section></aside>'], '']);
22
- assert.deepStrictEqual(inspect(parser('~~~example/markdown\n$fig-a\n!https://host\n~~~')), [['<aside class="example" data-type="markdown"><pre translate="no">$fig-a\n!https://host</pre><hr><section><figure data-label="fig-a" data-group="fig" data-number="1"><div class="figcontent"><a href="https://host" target="_blank"><img class="media" data-src="https://host" alt=""></a></div><span class="figindex">Fig. 1: </span><figcaption></figcaption></figure><ol class="annotations"></ol><ol class="references"></ol></section></aside>'], '']);
23
- assert.deepStrictEqual(inspect(parser('~~~example/markdown\n[$fig-a]\n!https://host\n~~~')), [['<aside class="example" data-type="markdown"><pre translate="no">[$fig-a]\n!https://host</pre><hr><section><figure data-label="fig-a" data-group="fig" data-number="1"><div class="figcontent"><a href="https://host" target="_blank"><img class="media" data-src="https://host" alt=""></a></div><span class="figindex">Fig. 1: </span><figcaption></figcaption></figure><ol class="annotations"></ol><ol class="references"></ol></section></aside>'], '']);
22
+ assert.deepStrictEqual(inspect(parser('~~~example/markdown\n$fig-a\n!https://host\n~~~')), [['<aside class="example" data-type="markdown"><pre translate="no">$fig-a\n!https://host</pre><hr><section><figure data-label="fig-a" data-group="fig" data-number="1"><div class="figcontent"><a href="https://host" target="_blank"><img class="media" data-src="https://host" alt=""></a></div><span class="figindex">Fig. 1. </span><figcaption></figcaption></figure><ol class="annotations"></ol><ol class="references"></ol></section></aside>'], '']);
23
+ assert.deepStrictEqual(inspect(parser('~~~example/markdown\n[$fig-a]\n!https://host\n~~~')), [['<aside class="example" data-type="markdown"><pre translate="no">[$fig-a]\n!https://host</pre><hr><section><figure data-label="fig-a" data-group="fig" data-number="1"><div class="figcontent"><a href="https://host" target="_blank"><img class="media" data-src="https://host" alt=""></a></div><span class="figindex">Fig. 1. </span><figcaption></figcaption></figure><ol class="annotations"></ol><ol class="references"></ol></section></aside>'], '']);
24
24
  assert.deepStrictEqual(inspect(parser('~~~example/markdown\n## a\n~~~')), [['<aside class="example" data-type="markdown"><pre translate="no">## a</pre><hr><section><h2>a</h2><ol class="annotations"></ol><ol class="references"></ol></section></aside>'], '']);
25
25
  assert.deepStrictEqual(inspect(parser('~~~example/markdown\n~ a\n~~~')), [['<aside class="example" data-type="markdown"><pre translate="no">~ a</pre><hr><section><dl><dt>a</dt><dd></dd></dl><ol class="annotations"></ol><ol class="references"></ol></section></aside>'], '']);
26
26
  assert.deepStrictEqual(inspect(parser('~~~example/markdown\n((a))[[b]]\n~~~')), [['<aside class="example" data-type="markdown"><pre translate="no">((a))[[b]]</pre><hr><section><p><sup class="annotation disabled" title="a"><span hidden="">a</span><a>*1</a></sup><sup class="reference disabled" title="b"><span hidden="">b</span><a>[1]</a></sup></p><ol class="annotations"><li>a<sup><a>^1</a></sup></li></ol><ol class="references"><li>b<sup><a>^1</a></sup></li></ol></section></aside>'], '']);
@@ -127,7 +127,7 @@ function attributes(source: string) {
127
127
  ? { 'data-highlight-level': +highlight! > 1 ? highlight : undefined }
128
128
  : {
129
129
  'data-invalid-syntax': 'table',
130
- 'data-invalid-type': 'highlight',
130
+ 'data-invalid-type': 'syntax',
131
131
  'data-invalid-description': 'Too much highlight level.',
132
132
  },
133
133
  };
@@ -28,28 +28,20 @@ describe('Unit: parser/block/paragraph', () => {
28
28
  assert.deepStrictEqual(inspect(parser(' a')), [['<p>a</p>'], '']);
29
29
  });
30
30
 
31
- it('mention', () => {
32
- assert.deepStrictEqual(inspect(parser('>>1')), [['<p><span class="cite">&gt;<a href="?comment=1" class="anchor" data-depth="1">&gt;1</a></span></p>'], '']);
33
- assert.deepStrictEqual(inspect(parser('>>1\na')), [['<p><span class="cite">&gt;<a href="?comment=1" class="anchor" data-depth="1">&gt;1</a></span><br>a</p>'], '']);
34
- assert.deepStrictEqual(inspect(parser('>>1\na\n>>2')), [['<p><span class="cite">&gt;<a href="?comment=1" class="anchor" data-depth="1">&gt;1</a></span><br>a<br><a href="?comment=2" class="anchor">&gt;&gt;2</a></p>'], '']);
35
- assert.deepStrictEqual(inspect(parser('>>1\n>>2')), [['<p><span class="cite">&gt;<a href="?comment=1" class="anchor" data-depth="1">&gt;1</a></span><br><span class="cite">&gt;<a href="?comment=2" class="anchor" data-depth="1">&gt;2</a></span></p>'], '']);
36
- assert.deepStrictEqual(inspect(parser('>>1\n> a')), [['<p><span class="cite">&gt;<a href="?comment=1" class="anchor" data-depth="1">&gt;1</a></span><br><span class="quote">&gt; a</span></p>'], '']);
37
- assert.deepStrictEqual(inspect(parser('>>1\n> a\nb')), [['<p><span class="cite">&gt;<a href="?comment=1" class="anchor" data-depth="1">&gt;1</a></span><br><span class="quote">&gt; a</span><br>b</p>'], '']);
38
- assert.deepStrictEqual(inspect(parser('>>1\n> a\n>>2')), [['<p><span class="cite">&gt;<a href="?comment=1" class="anchor" data-depth="1">&gt;1</a></span><br><span class="quote">&gt; a</span><br><span class="cite">&gt;<a href="?comment=2" class="anchor" data-depth="1">&gt;2</a></span></p>'], '']);
39
- assert.deepStrictEqual(inspect(parser('>>1\n> a\n>> b')), [['<p><span class="cite">&gt;<a href="?comment=1" class="anchor" data-depth="1">&gt;1</a></span><br><span class="quote">&gt; a<br>&gt;&gt; b</span></p>'], '']);
31
+ it('anchor', () => {
40
32
  assert.deepStrictEqual(inspect(parser('>>1 a\nb')), [['<p><a href="?comment=1" class="anchor">&gt;&gt;1</a> a<br>b</p>'], '']);
41
33
  assert.deepStrictEqual(inspect(parser('>>1 a\n>>2')), [['<p><a href="?comment=1" class="anchor">&gt;&gt;1</a> a<br><a href="?comment=2" class="anchor">&gt;&gt;2</a></p>'], '']);
42
34
  assert.deepStrictEqual(inspect(parser('>>1 a\n>>b')), [['<p><a href="?comment=1" class="anchor">&gt;&gt;1</a> a<br><a href="?comment=b" class="anchor">&gt;&gt;b</a></p>'], '']);
43
- assert.deepStrictEqual(inspect(parser('>>1 a\n>> b')), [['<p><a href="?comment=1" class="anchor">&gt;&gt;1</a> a<br><span class="quote">&gt;&gt; b</span></p>'], '']);
35
+ assert.deepStrictEqual(inspect(parser('>>1 a\n>> b')), [['<p><a href="?comment=1" class="anchor">&gt;&gt;1</a> a<br>&gt;&gt; b</p>'], '']);
44
36
  assert.deepStrictEqual(inspect(parser('>>11.')), [['<p><a href="?comment=11" class="anchor">&gt;&gt;11</a>.</p>'], '']);
45
37
  assert.deepStrictEqual(inspect(parser('>>11 a')), [['<p><a href="?comment=11" class="anchor">&gt;&gt;11</a> a</p>'], '']);
46
38
  assert.deepStrictEqual(inspect(parser('>>>11 a')), [['<p>&gt;<a href="?comment=11" class="anchor">&gt;&gt;11</a> a</p>'], '']);
47
- assert.deepStrictEqual(inspect(parser('>> a\n>>1')), [['<p><span class="quote">&gt;&gt; a</span><br><a href="?comment=1" class="anchor">&gt;&gt;1</a></p>'], '']);
39
+ assert.deepStrictEqual(inspect(parser('>> a\n>>1')), [['<p>&gt;&gt; a<br><a href="?comment=1" class="anchor">&gt;&gt;1</a></p>'], '']);
48
40
  assert.deepStrictEqual(inspect(parser('a>>1')), [['<p>a<a href="?comment=1" class="anchor">&gt;&gt;1</a></p>'], '']);
49
41
  assert.deepStrictEqual(inspect(parser('a >>1')), [['<p>a <a href="?comment=1" class="anchor">&gt;&gt;1</a></p>'], '']);
50
42
  assert.deepStrictEqual(inspect(parser('a\n>>1')), [['<p>a<br><a href="?comment=1" class="anchor">&gt;&gt;1</a></p>'], '']);
51
43
  assert.deepStrictEqual(inspect(parser('a\n>>1\nb')), [['<p>a<br><a href="?comment=1" class="anchor">&gt;&gt;1</a><br>b</p>'], '']);
52
- assert.deepStrictEqual(inspect(parser('a\n>> b\nc')), [['<p>a<br><span class="quote">&gt;&gt; b</span><br>c</p>'], '']);
44
+ assert.deepStrictEqual(inspect(parser('a\n>> b\nc')), [['<p>a<br>&gt;&gt; b<br>c</p>'], '']);
53
45
  assert.deepStrictEqual(inspect(parser(' >>1')), [['<p><a href="?comment=1" class="anchor">&gt;&gt;1</a></p>'], '']);
54
46
  assert.deepStrictEqual(inspect(parser(' >>>1')), [['<p>&gt;<a href="?comment=1" class="anchor">&gt;&gt;1</a></p>'], '']);
55
47
  });
@@ -1,24 +1,10 @@
1
1
  import { ParagraphParser } from '../block';
2
- import { union, subsequence, some, block, rewrite, trim, fmap } from '../../combinator';
3
- import { mention } from './paragraph/mention';
4
- import { quote, syntax as delimiter } from './paragraph/mention/quote';
2
+ import { union, some, block, trim, fmap } from '../../combinator';
5
3
  import { inline } from '../inline';
6
- import { anyline } from '../source';
7
4
  import { localize } from '../locale';
8
5
  import { visualize } from '../util';
9
6
  import { html, defrag } from 'typed-dom';
10
- import { push, pop } from 'spica/array';
11
7
 
12
8
  export const paragraph: ParagraphParser = block(localize(fmap(
13
- subsequence([
14
- some(mention),
15
- some(union([
16
- quote,
17
- fmap(
18
- rewrite(
19
- some(anyline, delimiter),
20
- trim(visualize(some(inline)))),
21
- ns => push(ns, [html('br')])),
22
- ])),
23
- ]),
24
- ns => [html('p', defrag(pop(ns)[0]))])));
9
+ trim(visualize(some(union([inline])))),
10
+ ns => [html('p', defrag(ns))])));
@@ -1,8 +1,8 @@
1
1
  import { cite } from './cite';
2
- import { some } from '../../../../combinator';
3
- import { inspect } from '../../../../debug.test';
2
+ import { some } from '../../../combinator';
3
+ import { inspect } from '../../../debug.test';
4
4
 
5
- describe('Unit: parser/block/paragraph/mention/cite', () => {
5
+ describe('Unit: parser/block/reply/cite', () => {
6
6
  describe('cite', () => {
7
7
  const parser = (source: string) => some(cite)(source, {});
8
8
 
@@ -1,14 +1,14 @@
1
- import { ParagraphParser } from '../../../block';
2
- import { tails, line, validate, creator, reverse, fmap } from '../../../../combinator';
3
- import { anchor } from '../../../inline/autolink/anchor';
4
- import { str } from '../../../source';
1
+ import { ReplyParser } from '../../block';
2
+ import { tails, line, validate, creator, reverse, fmap } from '../../../combinator';
3
+ import { anchor, syntax } from '../../inline/autolink/anchor';
4
+ import { str } from '../../source';
5
5
  import { html, define, defrag } from 'typed-dom';
6
6
 
7
- export const cite: ParagraphParser.MentionParser.CiteParser = creator(line(fmap(validate(
7
+ export const cite: ReplyParser.CiteParser = creator(line(fmap(validate(
8
8
  '>>',
9
9
  reverse(tails([
10
10
  str(/^>*(?=>>)/),
11
- anchor,
11
+ validate(new RegExp(`${syntax.source}[^\S\n]*(?:$|\n)`), anchor),
12
12
  ]))),
13
13
  ([el, quotes = '']: [HTMLElement, string?]) => [
14
14
  html('span', { class: 'cite' }, defrag([
@@ -1,8 +1,8 @@
1
1
  import { quote } from './quote';
2
- import { some } from '../../../../combinator';
3
- import { inspect } from '../../../../debug.test';
2
+ import { some } from '../../../combinator';
3
+ import { inspect } from '../../../debug.test';
4
4
 
5
- describe('Unit: parser/block/paragraph/mention/quote', () => {
5
+ describe('Unit: parser/block/reply/quote', () => {
6
6
  describe('quote', () => {
7
7
  const parser = (source: string) => some(quote)(source, {});
8
8
 
@@ -1,14 +1,14 @@
1
- import { ParagraphParser } from '../../../block';
2
- import { eval } from '../../../../combinator/data/parser';
3
- import { union, some, block, line, validate, rewrite, creator, lazy, fmap } from '../../../../combinator';
4
- import { math } from '../../../inline/math';
5
- import { str, anyline } from '../../../source';
6
- import { autolink } from '../../../autolink';
1
+ import { ReplyParser } from '../../block';
2
+ import { eval } from '../../../combinator/data/parser';
3
+ import { union, some, block, line, validate, rewrite, creator, lazy, fmap } from '../../../combinator';
4
+ import { math } from '../../inline/math';
5
+ import { str, anyline } from '../../source';
6
+ import { autolink } from '../../autolink';
7
7
  import { html, defrag } from 'typed-dom';
8
8
 
9
9
  export const syntax = /^>+(?=[^\S\n])|^>(?=[^\s>])|^>+(?=[^\s>])(?![0-9a-z]+(?:-[0-9a-z]+)*(?![0-9A-Za-z@#:]))/;
10
10
 
11
- export const quote: ParagraphParser.MentionParser.QuoteParser = lazy(() => creator(block(fmap(validate(
11
+ export const quote: ReplyParser.QuoteParser = lazy(() => creator(block(fmap(validate(
12
12
  '>',
13
13
  union([
14
14
  rewrite(
@@ -20,7 +20,7 @@ export const quote: ParagraphParser.MentionParser.QuoteParser = lazy(() => creat
20
20
  ])),
21
21
  (ns: [string, ...(string | HTMLElement)[]]) => [
22
22
  html('span',
23
- ns.length > 1 || /^>+(?=[^\S\n])/.test(ns[0])
23
+ ns.length > 1
24
24
  ? { class: 'quote' }
25
25
  : {
26
26
  class: 'quote invalid',
@@ -28,12 +28,12 @@ export const quote: ParagraphParser.MentionParser.QuoteParser = lazy(() => creat
28
28
  'data-invalid-type': 'syntax',
29
29
  'data-invalid-description': `Missing the whitespace after "${ns[0].split(/[^>]/, 1)[0]}".`,
30
30
  },
31
- ns),
31
+ defrag(ns)),
32
32
  html('br'),
33
33
  ]),
34
34
  false)));
35
35
 
36
- const qblock: ParagraphParser.MentionParser.QuoteParser.BlockParser = (source, context) => {
36
+ const qblock: ReplyParser.QuoteParser.BlockParser = (source, context) => {
37
37
  source = source.replace(/\n$/, '');
38
38
  const lines = source.match(/^.*\n?/mg)!;
39
39
  assert(lines);
@@ -64,12 +64,14 @@ const qblock: ParagraphParser.MentionParser.QuoteParser.BlockParser = (source, c
64
64
  continue;
65
65
  }
66
66
  }
67
+ nodes.unshift('');
68
+ assert(nodes.length > 1);
67
69
  assert(nodes.every(n => typeof n === 'string' || n instanceof HTMLElement));
68
70
  assert(quotes.length === 0);
69
- return [defrag(nodes), ''];
71
+ return [nodes, ''];
70
72
  };
71
73
 
72
- const text: ParagraphParser.MentionParser.QuoteParser.TextParser = union([
74
+ const text: ReplyParser.QuoteParser.TextParser = union([
73
75
  math,
74
76
  autolink,
75
77
  ]);
@@ -0,0 +1,22 @@
1
+ import { reply } from './reply';
2
+ import { some } from '../../combinator';
3
+ import { inspect } from '../../debug.test';
4
+
5
+ describe('Unit: parser/block/reply', () => {
6
+ describe('reply', () => {
7
+ const parser = (source: string) => some(reply)(source, {});
8
+
9
+ it('basic', () => {
10
+ assert.deepStrictEqual(inspect(parser('>>1')), [['<p><span class="cite">&gt;<a href="?comment=1" class="anchor" data-depth="1">&gt;1</a></span></p>'], '']);
11
+ assert.deepStrictEqual(inspect(parser('>>1\na')), [['<p><span class="cite">&gt;<a href="?comment=1" class="anchor" data-depth="1">&gt;1</a></span><br>a</p>'], '']);
12
+ assert.deepStrictEqual(inspect(parser('>>1\na\n>>2')), [['<p><span class="cite">&gt;<a href="?comment=1" class="anchor" data-depth="1">&gt;1</a></span><br>a<br><a href="?comment=2" class="anchor">&gt;&gt;2</a></p>'], '']);
13
+ assert.deepStrictEqual(inspect(parser('>>1\n>>2')), [['<p><span class="cite">&gt;<a href="?comment=1" class="anchor" data-depth="1">&gt;1</a></span><br><span class="cite">&gt;<a href="?comment=2" class="anchor" data-depth="1">&gt;2</a></span></p>'], '']);
14
+ assert.deepStrictEqual(inspect(parser('>>1\n> a')), [['<p><span class="cite">&gt;<a href="?comment=1" class="anchor" data-depth="1">&gt;1</a></span><br><span class="quote">&gt; a</span></p>'], '']);
15
+ assert.deepStrictEqual(inspect(parser('>>1\n> a\nb')), [['<p><span class="cite">&gt;<a href="?comment=1" class="anchor" data-depth="1">&gt;1</a></span><br><span class="quote">&gt; a</span><br>b</p>'], '']);
16
+ assert.deepStrictEqual(inspect(parser('>>1\n> a\n>>2')), [['<p><span class="cite">&gt;<a href="?comment=1" class="anchor" data-depth="1">&gt;1</a></span><br><span class="quote">&gt; a</span><br><span class="cite">&gt;<a href="?comment=2" class="anchor" data-depth="1">&gt;2</a></span></p>'], '']);
17
+ assert.deepStrictEqual(inspect(parser('>>1\n> a\n>> b')), [['<p><span class="cite">&gt;<a href="?comment=1" class="anchor" data-depth="1">&gt;1</a></span><br><span class="quote">&gt; a<br>&gt;&gt; b</span></p>'], '']);
18
+ });
19
+
20
+ });
21
+
22
+ });
@@ -0,0 +1,27 @@
1
+ import { ReplyParser } from '../block';
2
+ import { inits, subsequence, some, block, validate, rewrite, trim, fmap } from '../../combinator';
3
+ import { cite } from './reply/cite';
4
+ import { quote, syntax as delimiter } from './reply/quote';
5
+ import { inline } from '../inline';
6
+ import { anyline } from '../source';
7
+ import { localize } from '../locale';
8
+ import { visualize } from '../util';
9
+ import { html, defrag } from 'typed-dom';
10
+ import { push, pop } from 'spica/array';
11
+
12
+ export const reply: ReplyParser = block(validate('>', localize(fmap(
13
+ inits([
14
+ some(inits([
15
+ cite,
16
+ quote,
17
+ ])),
18
+ some(subsequence([
19
+ some(quote),
20
+ fmap(
21
+ rewrite(
22
+ some(anyline, delimiter),
23
+ trim(visualize(some(inline)))),
24
+ ns => push(ns, [html('br')])),
25
+ ])),
26
+ ]),
27
+ ns => [html('p', defrag(pop(ns)[0]))]))));
@@ -13,6 +13,7 @@ import { blockquote } from './block/blockquote';
13
13
  import { codeblock } from './block/codeblock';
14
14
  import { mathblock } from './block/mathblock';
15
15
  import { extension } from './block/extension';
16
+ import { reply } from './block/reply';
16
17
  import { paragraph } from './block/paragraph';
17
18
  import { html } from 'typed-dom';
18
19
  import { rnd0Z } from 'spica/random';
@@ -29,6 +30,7 @@ export import CodeBlockParser = BlockParser.CodeBlockParser;
29
30
  export import MathBlockParser = BlockParser.MathBlockParser;
30
31
  export import ExtensionParser = BlockParser.ExtensionParser;
31
32
  export import BlockquoteParser = BlockParser.BlockquoteParser;
33
+ export import ReplyParser = BlockParser.ReplyParser;
32
34
  export import ParagraphParser = BlockParser.ParagraphParser;
33
35
 
34
36
  export const block: BlockParser = creator(error(
@@ -46,6 +48,7 @@ export const block: BlockParser = creator(error(
46
48
  mathblock,
47
49
  extension,
48
50
  blockquote,
51
+ reply,
49
52
  paragraph
50
53
  ]))));
51
54
 
@@ -4,8 +4,10 @@ import { link } from '../link';
4
4
  import { str } from '../../source';
5
5
  import { define } from 'typed-dom';
6
6
 
7
+ export const syntax = /^>>[0-9a-z]+(?:-[0-9a-z]+)*(?![0-9A-Za-z@#:])/;
8
+
7
9
  export const anchor: AutolinkParser.AnchorParser = lazy(() => validate('>>', fmap(rewrite(
8
- str(/^>>[0-9a-z]+(?:-[0-9a-z]+)*(?![0-9A-Za-z@#:])/),
10
+ str(syntax),
9
11
  context({ syntax: { inline: {
10
12
  link: true,
11
13
  autolink: false,
@@ -73,6 +73,15 @@ function sanitize(target: HTMLElement, uri: ReadonlyURL, alt: string): boolean {
73
73
  case 'http:':
74
74
  case 'https:':
75
75
  assert(uri.host);
76
+ if (/\/\.\.?(?:\/|$)/.test('/' + uri.source.slice(0, uri.source.search(/[?#]|$/)))) {
77
+ define(target, {
78
+ class: void target.classList.add('invalid'),
79
+ 'data-invalid-syntax': 'media',
80
+ 'data-invalid-type': 'argument',
81
+ 'data-invalid-description': 'Dot-segments cannot be used in media paths; use subresource paths instead.',
82
+ });
83
+ return false;
84
+ }
76
85
  break;
77
86
  default:
78
87
  define(target, {
@@ -83,15 +92,6 @@ function sanitize(target: HTMLElement, uri: ReadonlyURL, alt: string): boolean {
83
92
  });
84
93
  return false;
85
94
  }
86
- if (/\/\.\.?(?:\/|$)/.test('/' + uri.source.slice(0, uri.source.search(/[?#]|$/)))) {
87
- define(target, {
88
- class: void target.classList.add('invalid'),
89
- 'data-invalid-syntax': 'media',
90
- 'data-invalid-type': 'argument',
91
- 'data-invalid-description': 'Dot-segments cannot be used in media paths; use subresource paths instead.',
92
- });
93
- return false;
94
- }
95
95
  if (alt.includes('\0')) {
96
96
  define(target, {
97
97
  class: void target.classList.add('invalid'),