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/CHANGELOG.md +13 -0
- package/design.md +4 -0
- package/dist/securemark.js +99 -82
- package/index.d.ts +2 -2
- package/markdown.d.ts +44 -42
- package/package-lock.json +245 -231
- package/package.json +5 -5
- package/src/combinator/control/manipulation/indent.test.ts +12 -12
- package/src/combinator/control/manipulation/surround.ts +4 -3
- package/src/parser/block/blockquote.test.ts +1 -1
- package/src/parser/block/extension/aside.test.ts +1 -1
- package/src/parser/block/extension/example.test.ts +2 -2
- package/src/parser/block/extension/table.ts +1 -1
- package/src/parser/block/paragraph.test.ts +4 -12
- package/src/parser/block/paragraph.ts +3 -17
- package/src/parser/block/{paragraph/mention → reply}/cite.test.ts +3 -3
- package/src/parser/block/{paragraph/mention → reply}/cite.ts +6 -6
- package/src/parser/block/{paragraph/mention → reply}/quote.test.ts +3 -3
- package/src/parser/block/{paragraph/mention → reply}/quote.ts +14 -12
- package/src/parser/block/reply.test.ts +22 -0
- package/src/parser/block/reply.ts +27 -0
- package/src/parser/block.ts +3 -0
- package/src/parser/inline/autolink/anchor.ts +3 -1
- package/src/parser/inline/media.ts +9 -9
- package/src/parser/processor/figure.test.ts +25 -25
- package/src/parser/processor/figure.ts +1 -1
- package/src/parser/util.ts +1 -1
- package/src/util/info.test.ts +1 -1
- package/src/util/info.ts +2 -2
- package/src/util/quote.ts +1 -1
- package/src/util/scope.ts +3 -1
- package/src/parser/block/paragraph/mention.ts +0 -9
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "securemark",
|
|
3
|
-
"version": "0.
|
|
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.
|
|
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.
|
|
61
|
-
"npm-check-updates": "^12.5.
|
|
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.
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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': '
|
|
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('
|
|
32
|
-
assert.deepStrictEqual(inspect(parser('>>1')), [['<p><span class="cite">><a href="?comment=1" class="anchor" data-depth="1">>1</a></span></p>'], '']);
|
|
33
|
-
assert.deepStrictEqual(inspect(parser('>>1\na')), [['<p><span class="cite">><a href="?comment=1" class="anchor" data-depth="1">>1</a></span><br>a</p>'], '']);
|
|
34
|
-
assert.deepStrictEqual(inspect(parser('>>1\na\n>>2')), [['<p><span class="cite">><a href="?comment=1" class="anchor" data-depth="1">>1</a></span><br>a<br><a href="?comment=2" class="anchor">>>2</a></p>'], '']);
|
|
35
|
-
assert.deepStrictEqual(inspect(parser('>>1\n>>2')), [['<p><span class="cite">><a href="?comment=1" class="anchor" data-depth="1">>1</a></span><br><span class="cite">><a href="?comment=2" class="anchor" data-depth="1">>2</a></span></p>'], '']);
|
|
36
|
-
assert.deepStrictEqual(inspect(parser('>>1\n> a')), [['<p><span class="cite">><a href="?comment=1" class="anchor" data-depth="1">>1</a></span><br><span class="quote">> a</span></p>'], '']);
|
|
37
|
-
assert.deepStrictEqual(inspect(parser('>>1\n> a\nb')), [['<p><span class="cite">><a href="?comment=1" class="anchor" data-depth="1">>1</a></span><br><span class="quote">> a</span><br>b</p>'], '']);
|
|
38
|
-
assert.deepStrictEqual(inspect(parser('>>1\n> a\n>>2')), [['<p><span class="cite">><a href="?comment=1" class="anchor" data-depth="1">>1</a></span><br><span class="quote">> a</span><br><span class="cite">><a href="?comment=2" class="anchor" data-depth="1">>2</a></span></p>'], '']);
|
|
39
|
-
assert.deepStrictEqual(inspect(parser('>>1\n> a\n>> b')), [['<p><span class="cite">><a href="?comment=1" class="anchor" data-depth="1">>1</a></span><br><span class="quote">> a<br>>> b</span></p>'], '']);
|
|
31
|
+
it('anchor', () => {
|
|
40
32
|
assert.deepStrictEqual(inspect(parser('>>1 a\nb')), [['<p><a href="?comment=1" class="anchor">>>1</a> a<br>b</p>'], '']);
|
|
41
33
|
assert.deepStrictEqual(inspect(parser('>>1 a\n>>2')), [['<p><a href="?comment=1" class="anchor">>>1</a> a<br><a href="?comment=2" class="anchor">>>2</a></p>'], '']);
|
|
42
34
|
assert.deepStrictEqual(inspect(parser('>>1 a\n>>b')), [['<p><a href="?comment=1" class="anchor">>>1</a> a<br><a href="?comment=b" class="anchor">>>b</a></p>'], '']);
|
|
43
|
-
assert.deepStrictEqual(inspect(parser('>>1 a\n>> b')), [['<p><a href="?comment=1" class="anchor">>>1</a> a<br
|
|
35
|
+
assert.deepStrictEqual(inspect(parser('>>1 a\n>> b')), [['<p><a href="?comment=1" class="anchor">>>1</a> a<br>>> b</p>'], '']);
|
|
44
36
|
assert.deepStrictEqual(inspect(parser('>>11.')), [['<p><a href="?comment=11" class="anchor">>>11</a>.</p>'], '']);
|
|
45
37
|
assert.deepStrictEqual(inspect(parser('>>11 a')), [['<p><a href="?comment=11" class="anchor">>>11</a> a</p>'], '']);
|
|
46
38
|
assert.deepStrictEqual(inspect(parser('>>>11 a')), [['<p>><a href="?comment=11" class="anchor">>>11</a> a</p>'], '']);
|
|
47
|
-
assert.deepStrictEqual(inspect(parser('>> a\n>>1')), [['<p
|
|
39
|
+
assert.deepStrictEqual(inspect(parser('>> a\n>>1')), [['<p>>> a<br><a href="?comment=1" class="anchor">>>1</a></p>'], '']);
|
|
48
40
|
assert.deepStrictEqual(inspect(parser('a>>1')), [['<p>a<a href="?comment=1" class="anchor">>>1</a></p>'], '']);
|
|
49
41
|
assert.deepStrictEqual(inspect(parser('a >>1')), [['<p>a <a href="?comment=1" class="anchor">>>1</a></p>'], '']);
|
|
50
42
|
assert.deepStrictEqual(inspect(parser('a\n>>1')), [['<p>a<br><a href="?comment=1" class="anchor">>>1</a></p>'], '']);
|
|
51
43
|
assert.deepStrictEqual(inspect(parser('a\n>>1\nb')), [['<p>a<br><a href="?comment=1" class="anchor">>>1</a><br>b</p>'], '']);
|
|
52
|
-
assert.deepStrictEqual(inspect(parser('a\n>> b\nc')), [['<p>a<br
|
|
44
|
+
assert.deepStrictEqual(inspect(parser('a\n>> b\nc')), [['<p>a<br>>> b<br>c</p>'], '']);
|
|
53
45
|
assert.deepStrictEqual(inspect(parser(' >>1')), [['<p><a href="?comment=1" class="anchor">>>1</a></p>'], '']);
|
|
54
46
|
assert.deepStrictEqual(inspect(parser(' >>>1')), [['<p>><a href="?comment=1" class="anchor">>>1</a></p>'], '']);
|
|
55
47
|
});
|
|
@@ -1,24 +1,10 @@
|
|
|
1
1
|
import { ParagraphParser } from '../block';
|
|
2
|
-
import { union,
|
|
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
|
-
|
|
14
|
-
|
|
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 '
|
|
3
|
-
import { inspect } from '
|
|
2
|
+
import { some } from '../../../combinator';
|
|
3
|
+
import { inspect } from '../../../debug.test';
|
|
4
4
|
|
|
5
|
-
describe('Unit: parser/block/
|
|
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 {
|
|
2
|
-
import { tails, line, validate, creator, reverse, fmap } from '
|
|
3
|
-
import { anchor } from '
|
|
4
|
-
import { str } from '
|
|
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:
|
|
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 '
|
|
3
|
-
import { inspect } from '
|
|
2
|
+
import { some } from '../../../combinator';
|
|
3
|
+
import { inspect } from '../../../debug.test';
|
|
4
4
|
|
|
5
|
-
describe('Unit: parser/block/
|
|
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 {
|
|
2
|
-
import { eval } from '
|
|
3
|
-
import { union, some, block, line, validate, rewrite, creator, lazy, fmap } from '
|
|
4
|
-
import { math } from '
|
|
5
|
-
import { str, anyline } from '
|
|
6
|
-
import { autolink } from '
|
|
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:
|
|
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
|
|
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:
|
|
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 [
|
|
71
|
+
return [nodes, ''];
|
|
70
72
|
};
|
|
71
73
|
|
|
72
|
-
const text:
|
|
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">><a href="?comment=1" class="anchor" data-depth="1">>1</a></span></p>'], '']);
|
|
11
|
+
assert.deepStrictEqual(inspect(parser('>>1\na')), [['<p><span class="cite">><a href="?comment=1" class="anchor" data-depth="1">>1</a></span><br>a</p>'], '']);
|
|
12
|
+
assert.deepStrictEqual(inspect(parser('>>1\na\n>>2')), [['<p><span class="cite">><a href="?comment=1" class="anchor" data-depth="1">>1</a></span><br>a<br><a href="?comment=2" class="anchor">>>2</a></p>'], '']);
|
|
13
|
+
assert.deepStrictEqual(inspect(parser('>>1\n>>2')), [['<p><span class="cite">><a href="?comment=1" class="anchor" data-depth="1">>1</a></span><br><span class="cite">><a href="?comment=2" class="anchor" data-depth="1">>2</a></span></p>'], '']);
|
|
14
|
+
assert.deepStrictEqual(inspect(parser('>>1\n> a')), [['<p><span class="cite">><a href="?comment=1" class="anchor" data-depth="1">>1</a></span><br><span class="quote">> a</span></p>'], '']);
|
|
15
|
+
assert.deepStrictEqual(inspect(parser('>>1\n> a\nb')), [['<p><span class="cite">><a href="?comment=1" class="anchor" data-depth="1">>1</a></span><br><span class="quote">> a</span><br>b</p>'], '']);
|
|
16
|
+
assert.deepStrictEqual(inspect(parser('>>1\n> a\n>>2')), [['<p><span class="cite">><a href="?comment=1" class="anchor" data-depth="1">>1</a></span><br><span class="quote">> a</span><br><span class="cite">><a href="?comment=2" class="anchor" data-depth="1">>2</a></span></p>'], '']);
|
|
17
|
+
assert.deepStrictEqual(inspect(parser('>>1\n> a\n>> b')), [['<p><span class="cite">><a href="?comment=1" class="anchor" data-depth="1">>1</a></span><br><span class="quote">> a<br>>> 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]))]))));
|
package/src/parser/block.ts
CHANGED
|
@@ -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(
|
|
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'),
|