securemark 0.268.2 → 0.269.1
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 +8 -0
- package/dist/index.js +45 -35
- package/markdown.d.ts +59 -41
- package/package.json +6 -6
- package/src/parser/api/bind.test.ts +3 -3
- package/src/parser/api/parse.test.ts +3 -3
- package/src/parser/autolink.test.ts +2 -2
- package/src/parser/autolink.ts +5 -12
- package/src/parser/block/blockquote.test.ts +1 -1
- package/src/parser/block/extension/example.test.ts +1 -1
- package/src/parser/block/paragraph.test.ts +4 -2
- package/src/parser/block/paragraph.ts +3 -2
- package/src/parser/block/reply/quote.test.ts +2 -2
- package/src/parser/block/reply/quote.ts +8 -12
- package/src/parser/inline/autolink/url.test.ts +2 -0
- package/src/parser/inline/autolink/url.ts +13 -2
- package/src/parser/inline/autolink.ts +33 -30
- package/src/parser/inline/extension/indexee.ts +3 -2
- package/src/parser/inline/extension/placeholder.test.ts +1 -1
- package/src/parser/inline/link.ts +8 -3
- package/src/parser/inline/media.ts +6 -1
- package/src/parser/inline/shortmedia.ts +12 -3
- package/src/parser/inline.test.ts +6 -9
- package/src/parser/inline.ts +8 -7
- package/src/parser/processor/footnote.test.ts +17 -17
- package/src/parser/processor/footnote.ts +6 -5
- package/src/parser/source/escapable.ts +5 -1
- package/src/parser/source/text.ts +5 -1
- package/src/parser/source/unescapable.ts +7 -1
- package/src/parser/util.ts +0 -10
- package/src/parser/visibility.ts +1 -2
- package/src/util/quote.test.ts +2 -2
|
@@ -96,7 +96,7 @@ describe('Unit: parser/block/blockquote', () => {
|
|
|
96
96
|
assert.deepStrictEqual(inspect(parser('!>> ## a\n> ## a')), [['<blockquote><blockquote><section><h2>a</h2><h2>References</h2><ol class="references"></ol></section></blockquote><section><h2>a</h2><h2>References</h2><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><h2>References</h2><ol class="references"></ol></section></blockquote><section><dl><dt>a</dt><dd></dd></dl><h2>References</h2><ol class="references"></ol></section></blockquote>'], '']);
|
|
98
98
|
assert.deepStrictEqual(inspect(parser('!>> ~~~figure $test-a\n>> > \n>>\n~~~\n> ~~~figure $test-a\n> > \n>\n[#a]\n~~~')), [['<blockquote><blockquote><section><figure data-type="quote" data-label="test-a" data-group="test" data-number="1"><figcaption><span class="figindex">Test 1. </span><span class="figtext"></span></figcaption><div><blockquote></blockquote></div></figure><h2>References</h2><ol class="references"></ol></section></blockquote><section><figure data-type="quote" data-label="test-a" data-group="test" data-number="1"><figcaption><span class="figindex">Test 1. </span><span class="figtext"><a class="index">a</a></span></figcaption><div><blockquote></blockquote></div></figure><h2>References</h2><ol class="references"></ol></section></blockquote>'], '']);
|
|
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 data-marker="*1">a
|
|
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 data-marker="*1"><span>a</span><sup><a>^1</a></sup></li></ol><h2>References</h2><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 data-marker="*1"><span>a</span><sup><a>^1</a></sup></li></ol><h2>References</h2><ol class="references"></ol></section></blockquote>'], '']);
|
|
100
100
|
});
|
|
101
101
|
|
|
102
102
|
});
|
|
@@ -23,7 +23,7 @@ describe('Unit: parser/block/extension/example', () => {
|
|
|
23
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-type="media" data-label="fig-a" data-group="fig" data-number="1"><figcaption><span class="figindex">Fig. 1. </span><span class="figtext"></span></figcaption><div><a href="https://host" target="_blank"><img class="media" data-src="https://host" alt=""></a></div></figure><h2>References</h2><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><h2>References</h2><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><h2>References</h2><ol class="references"></ol></section></aside>'], '']);
|
|
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 data-marker="*1">a
|
|
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 data-marker="*1"><span>a</span><sup><a>^1</a></sup></li></ol><h2>References</h2><ol class="references"><li><span>b</span><sup><a>^1</a></sup></li></ol></section></aside>'], '']);
|
|
27
27
|
assert.deepStrictEqual(inspect(parser('~~~~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>'], '']);
|
|
28
28
|
assert.deepStrictEqual(inspect(parser('~~~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>'], '']);
|
|
29
29
|
assert.deepStrictEqual(inspect(parser(`~~~example/math\n0${'\n'.repeat(100)}~~~`), '>'), [['<aside class="example" data-type="math">'], '']);
|
|
@@ -30,9 +30,11 @@ describe('Unit: parser/block/paragraph', () => {
|
|
|
30
30
|
assert.deepStrictEqual(inspect(parser('_a\n<wbr>_\nb')), [['<p>_a<br><wbr>_<br>b</p>'], '']);
|
|
31
31
|
assert.deepStrictEqual(inspect(parser('*a\n<wbr>*\nb')), [['<p>*a<br><wbr>*<br>b</p>'], '']);
|
|
32
32
|
assert.deepStrictEqual(inspect(parser('==a\n<wbr>==\nb')), [['<p>==a<br><wbr>==<br>b</p>'], '']);
|
|
33
|
-
assert.deepStrictEqual(inspect(parser('http://host
|
|
33
|
+
assert.deepStrictEqual(inspect(parser('http://host#\\')), [['<p><a class="url" href="http://host#\\" target="_blank">http://host#\\</a></p>'], '']);
|
|
34
34
|
assert.deepStrictEqual(inspect(parser('a\nhttp://host#\\ \nb')), [['<p>a<br><a class="url" href="http://host#\\" target="_blank">http://host#\\</a><br>b</p>'], '']);
|
|
35
|
-
assert.deepStrictEqual(inspect(parser('!http://host
|
|
35
|
+
assert.deepStrictEqual(inspect(parser('!http://host#\\')), [['<p><a href="http://host#\\" target="_blank"><img class="media" data-src="http://host#\\" alt=""></a></p>'], '']);
|
|
36
|
+
assert.deepStrictEqual(inspect(parser('!http://host#\\ a')), [['<p>!<a class="url" href="http://host#" target="_blank">http://host#</a> a</p>'], '']);
|
|
37
|
+
assert.deepStrictEqual(inspect(parser(' !http://host#\\')), [['<p> !<a class="url" href="http://host#" target="_blank">http://host#</a></p>'], '']);
|
|
36
38
|
assert.deepStrictEqual(inspect(parser('\ta')), [['<p>\ta</p>'], '']);
|
|
37
39
|
});
|
|
38
40
|
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { ParagraphParser } from '../block';
|
|
2
|
-
import { union, some, block, trimEnd, fmap } from '../../combinator';
|
|
2
|
+
import { union, some, block, convert, trimEnd, fmap } from '../../combinator';
|
|
3
3
|
import { inline } from '../inline';
|
|
4
4
|
import { visualize } from '../visibility';
|
|
5
5
|
import { html, defrag } from 'typed-dom/dom';
|
|
6
6
|
|
|
7
7
|
export const paragraph: ParagraphParser = block(fmap(
|
|
8
|
-
|
|
8
|
+
convert(source => `\r${source}`,
|
|
9
|
+
visualize(trimEnd(some(union([inline]))))),
|
|
9
10
|
ns => [html('p', defrag(ns))]));
|
|
@@ -55,9 +55,9 @@ describe('Unit: parser/block/reply/quote', () => {
|
|
|
55
55
|
assert.deepStrictEqual(inspect(parser('> $-a, $-b')), [['<span class="quote">> $-a, $-b</span>', '<br>'], '']);
|
|
56
56
|
assert.deepStrictEqual(inspect(parser('> $a=b$')), [['<span class="quote">> <span class="math" translate="no" data-src="$a=b$">$a=b$</span></span>', '<br>'], '']);
|
|
57
57
|
assert.deepStrictEqual(inspect(parser('> ${a}$')), [['<span class="quote">> <span class="math" translate="no" data-src="${a}$">${a}$</span></span>', '<br>'], '']);
|
|
58
|
-
assert.deepStrictEqual(inspect(parser('> http://host
|
|
58
|
+
assert.deepStrictEqual(inspect(parser('> http://host#\\')), [['<span class="quote">> <a class="url" href="http://host#\\" target="_blank">http://host#\\</a></span>', '<br>'], '']);
|
|
59
59
|
assert.deepStrictEqual(inspect(parser('> a\n> http://host#\\ \n> b')), [['<span class="quote">> a<br>> <a class="url" href="http://host#\\" target="_blank">http://host#\\</a> <br>> b</span>', '<br>'], '']);
|
|
60
|
-
assert.deepStrictEqual(inspect(parser('> !http://host
|
|
60
|
+
assert.deepStrictEqual(inspect(parser('> !http://host#\\')), [['<span class="quote">> !<a class="url" href="http://host#\\" target="_blank">http://host#\\</a></span>', '<br>'], '']);
|
|
61
61
|
});
|
|
62
62
|
|
|
63
63
|
});
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import { ReplyParser } from '../../block';
|
|
2
2
|
import { eval } from '../../../combinator/data/parser';
|
|
3
|
-
import { union,
|
|
3
|
+
import { union, some, creation, block, line, validate, rewrite, lazy, fmap } from '../../../combinator';
|
|
4
4
|
import { math } from '../../inline/math';
|
|
5
5
|
import { autolink } from '../../inline/autolink';
|
|
6
6
|
import { linebreak, unescsource, str, anyline } from '../../source';
|
|
7
|
-
import { lineurl } from '../../autolink';
|
|
8
7
|
import { html, defrag } from 'typed-dom/dom';
|
|
9
8
|
|
|
10
9
|
export const syntax = /^>+(?=[^\S\n])|^>(?=[^\s>])|^>+(?=[^\s>])(?![0-9a-z]+(?:-[0-9a-z]+)*(?![0-9A-Za-z@#:]))/;
|
|
@@ -42,7 +41,7 @@ const qblock: ReplyParser.QuoteParser.BlockParser = ({ source, context }) => {
|
|
|
42
41
|
assert(quotes);
|
|
43
42
|
assert(quotes.length > 0);
|
|
44
43
|
const content = lines.reduce((acc, line, i) => acc + line.slice(quotes[i].length), '');
|
|
45
|
-
const nodes = eval(text({ source: content
|
|
44
|
+
const nodes = eval(text({ source: `\r${content}`, context }), []);
|
|
46
45
|
nodes.unshift(quotes.shift()!);
|
|
47
46
|
for (let i = 0; i < nodes.length; ++i) {
|
|
48
47
|
const child = nodes[i] as string | Text | Element;
|
|
@@ -72,12 +71,9 @@ const qblock: ReplyParser.QuoteParser.BlockParser = ({ source, context }) => {
|
|
|
72
71
|
return [nodes, ''];
|
|
73
72
|
};
|
|
74
73
|
|
|
75
|
-
const text: ReplyParser.QuoteParser.TextParser = some(
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
unescsource,
|
|
82
|
-
])),
|
|
83
|
-
])));
|
|
74
|
+
const text: ReplyParser.QuoteParser.TextParser = some(union([
|
|
75
|
+
math, // quote補助関数が残した数式をパースする。他の構文で数式を残す場合はソーステキストを直接使用する。
|
|
76
|
+
autolink,
|
|
77
|
+
linebreak,
|
|
78
|
+
unescsource,
|
|
79
|
+
]));
|
|
@@ -28,6 +28,8 @@ describe('Unit: parser/inline/autolink/url', () => {
|
|
|
28
28
|
assert.deepStrictEqual(inspect(parser('http://a#( )')), [['<a class="url" href="http://a#" target="_blank">http://a#</a>'], '( )']);
|
|
29
29
|
assert.deepStrictEqual(inspect(parser('http://a#(\n)')), [['<a class="url" href="http://a#" target="_blank">http://a#</a>'], '(\n)']);
|
|
30
30
|
assert.deepStrictEqual(inspect(parser('http://[::]')), [['<a class="url" href="http://[::]" target="_blank">http://[::]</a>'], '']);
|
|
31
|
+
assert.deepStrictEqual(inspect(parser('\rhttp://a#\\')), [['<a class="url" href="http://a#\\" target="_blank">http://a#\\</a>'], '']);
|
|
32
|
+
assert.deepStrictEqual(inspect(parser('\rhttp://a#\\\nhttp://b#\\')), [['<a class="url" href="http://a#\\" target="_blank">http://a#\\</a>', '<br>', '<a class="url" href="http://b#\\" target="_blank">http://b#\\</a>'], '']);
|
|
31
33
|
});
|
|
32
34
|
|
|
33
35
|
it('trailing symbols', () => {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { AutolinkParser } from '../../inline';
|
|
2
|
-
import { union, some, creation, precedence, validate, focus, rewrite, convert, surround, open, lazy } from '../../../combinator';
|
|
2
|
+
import { union, tails, some, creation, precedence, validate, focus, rewrite, convert, surround, open, lazy } from '../../../combinator';
|
|
3
3
|
import { unsafelink } from '../link';
|
|
4
|
-
import { unescsource } from '../../source';
|
|
4
|
+
import { linebreak, unescsource, str } from '../../source';
|
|
5
5
|
|
|
6
6
|
const closer = /^[-+*=~^_,.;:!?]*(?=[\\"`|\[\](){}<>]|$)/;
|
|
7
7
|
|
|
@@ -13,6 +13,17 @@ export const url: AutolinkParser.UrlParser = lazy(() => validate(['http://', 'ht
|
|
|
13
13
|
url => `{ ${url} }`,
|
|
14
14
|
union([unsafelink])))));
|
|
15
15
|
|
|
16
|
+
export const lineurl: AutolinkParser.UrlParser.LineUrlParser = open(
|
|
17
|
+
linebreak,
|
|
18
|
+
tails([
|
|
19
|
+
str('!'),
|
|
20
|
+
focus(
|
|
21
|
+
/^https?:\/\/\S+(?=[^\S\n]*(?:$|\n))/,
|
|
22
|
+
convert(
|
|
23
|
+
url => `{ ${url} }`,
|
|
24
|
+
unsafelink)),
|
|
25
|
+
]));
|
|
26
|
+
|
|
16
27
|
const bracket: AutolinkParser.UrlParser.BracketParser = lazy(() => creation(precedence(2, union([
|
|
17
28
|
surround('(', some(union([bracket, unescsource]), ')'), ')', true),
|
|
18
29
|
surround('[', some(union([bracket, unescsource]), ']'), ']', true),
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { AutolinkParser } from '../inline';
|
|
2
2
|
import { union, some, syntax, constraint, validate, focus, fmap } from '../../combinator';
|
|
3
|
-
import { url } from './autolink/url';
|
|
3
|
+
import { url, lineurl } from './autolink/url';
|
|
4
4
|
import { email } from './autolink/email';
|
|
5
5
|
import { channel } from './autolink/channel';
|
|
6
6
|
import { account } from './autolink/account';
|
|
@@ -11,34 +11,37 @@ import { str } from '../source';
|
|
|
11
11
|
import { Syntax, State } from '../context';
|
|
12
12
|
import { stringify } from '../util';
|
|
13
13
|
|
|
14
|
-
export const autolink: AutolinkParser =
|
|
15
|
-
validate(/^(?:[@#>0-9a-z]|\S[#>])/i,
|
|
14
|
+
export const autolink: AutolinkParser =
|
|
15
|
+
validate(/^(?:[@#>0-9a-z\r\n]|\S[#>])/i,
|
|
16
16
|
constraint(State.autolink, false,
|
|
17
17
|
syntax(Syntax.autolink, 1, 1, ~State.shortcut,
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
(
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
18
|
+
union([
|
|
19
|
+
some(union([lineurl])),
|
|
20
|
+
fmap(some(union([
|
|
21
|
+
url,
|
|
22
|
+
email,
|
|
23
|
+
// Escape unmatched email-like strings.
|
|
24
|
+
focus(
|
|
25
|
+
/^[0-9a-z](?:[_.+-](?=[0-9a-z])|[0-9a-z])*(?:@(?:[0-9a-z]+(?:[.-][0-9a-z]+)*)?)*/i,
|
|
26
|
+
({ source }) => {
|
|
27
|
+
if (source.length > 255 || source.includes('@')) return [[source], ''];
|
|
28
|
+
const i = source.indexOf('_');
|
|
29
|
+
if (i === -1) return [[source], ''];
|
|
30
|
+
return [[source.slice(0, i)], source.slice(i)];
|
|
31
|
+
}),
|
|
32
|
+
channel,
|
|
33
|
+
account,
|
|
34
|
+
// Escape unmatched account-like strings.
|
|
35
|
+
str(/^@+[0-9a-z]*(?:-[0-9a-z]+)*/i),
|
|
36
|
+
// Escape invalid leading characters.
|
|
37
|
+
str(new RegExp(/^(?:[^\p{C}\p{S}\p{P}\s]|emoji)(?=#)/u.source.replace('emoji', emoji), 'u')),
|
|
38
|
+
hashtag,
|
|
39
|
+
hashnum,
|
|
40
|
+
// Escape unmatched hashtag-like strings.
|
|
41
|
+
str(new RegExp(/^#+(?:[^\p{C}\p{S}\p{P}\s]|emoji|')*/u.source.replace('emoji', emoji), 'u')),
|
|
42
|
+
// Escape invalid leading characters.
|
|
43
|
+
str(/^[0-9\p{Sc}](?=>)/u),
|
|
44
|
+
anchor,
|
|
45
|
+
])),
|
|
46
|
+
ns => ns.length === 1 ? ns : [stringify(ns)]),
|
|
47
|
+
]))));
|
|
@@ -8,7 +8,7 @@ export function indexee(parser: Parser<HTMLElement, MarkdownParser.Context>, opt
|
|
|
8
8
|
return fmap(parser, ([el], _, { id }) => [define(el, { id: identity(id, text(el, optional)) })]);
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
-
export function identity(id: string | undefined, text: string, name: 'index' | 'mark' = 'index'): string | undefined {
|
|
11
|
+
export function identity(id: string | undefined, text: string, name: 'index' | 'mark' | 'note' = 'index'): string | undefined {
|
|
12
12
|
assert(!id?.match(/[^0-9a-z/-]/i));
|
|
13
13
|
assert(!text.includes('\n'));
|
|
14
14
|
if (id === '') return undefined;
|
|
@@ -20,6 +20,7 @@ export function identity(id: string | undefined, text: string, name: 'index' | '
|
|
|
20
20
|
case 'index':
|
|
21
21
|
return `${name}:${id ?? ''}:${cs.slice(0, 97).join('')}...`;
|
|
22
22
|
case 'mark':
|
|
23
|
+
case 'note':
|
|
23
24
|
return `${name}:${id ?? ''}:${cs.slice(0, 50).join('')}...${cs.slice(-47).join('')}`;
|
|
24
25
|
}
|
|
25
26
|
assert(false);
|
|
@@ -31,7 +32,7 @@ assert(identity(undefined, '0'.repeat(100 - 1) + 1, 'mark')!.slice(6) === '0'.re
|
|
|
31
32
|
assert(identity(undefined, '0'.repeat(100) + 1, 'mark')!.slice(6) === '0'.repeat(50) + '...' + '0'.repeat(47 - 1) + 1);
|
|
32
33
|
assert(identity(undefined, '0'.repeat(200) + 1, 'mark')!.slice(6) === '0'.repeat(50) + '...' + '0'.repeat(47 - 1) + 1);
|
|
33
34
|
|
|
34
|
-
export function text(source:
|
|
35
|
+
export function text(source: Element | DocumentFragment, optional = false): string {
|
|
35
36
|
assert(source instanceof DocumentFragment || !source.matches('.indexer'));
|
|
36
37
|
assert(source.querySelectorAll(':scope > .indexer').length <= 1);
|
|
37
38
|
if (!source.firstChild) return '';
|
|
@@ -48,7 +48,7 @@ describe('Unit: parser/inline/extension/placeholder', () => {
|
|
|
48
48
|
assert.deepStrictEqual(inspect(parser('[^a[% b %][% c %]]')), [['<span class="invalid">a<span class="comment"><input type="checkbox"><span>[% b %]</span></span><span class="comment"><input type="checkbox"><span>[% c %]</span></span></span>'], '']);
|
|
49
49
|
assert.deepStrictEqual(inspect(parser('[^\\]]')), [['<span class="invalid">]</span>'], '']);
|
|
50
50
|
assert.deepStrictEqual(inspect(parser('[^(])]')), [['<span class="invalid"><span class="paren">(])</span></span>'], '']);
|
|
51
|
-
assert.deepStrictEqual(inspect(parser('[^!http://host]')), [['<span class="invalid"
|
|
51
|
+
assert.deepStrictEqual(inspect(parser('[^!http://host]')), [['<span class="invalid">!<a class="url" href="http://host" target="_blank">http://host</a></span>'], '']);
|
|
52
52
|
assert.deepStrictEqual(inspect(parser('[^[% a %]]')), [['<span class="invalid"><span class="comment"><input type="checkbox"><span>[% a %]</span></span></span>'], '']);
|
|
53
53
|
assert.deepStrictEqual(inspect(parser('[^[% a %]b]')), [['<span class="invalid"><span class="comment"><input type="checkbox"><span>[% a %]</span></span>b</span>'], '']);
|
|
54
54
|
});
|
|
@@ -4,7 +4,7 @@ import { Result } from '../../combinator/data/parser';
|
|
|
4
4
|
import { union, inits, tails, sequence, some, constraint, syntax, creation, precedence, validate, surround, open, dup, reverse, lazy, fmap, bind } from '../../combinator';
|
|
5
5
|
import { inline, media, shortmedia } from '../inline';
|
|
6
6
|
import { attributes } from './html';
|
|
7
|
-
import { unescsource, str } from '../source';
|
|
7
|
+
import { linebreak, unescsource, str } from '../source';
|
|
8
8
|
import { Syntax, State } from '../context';
|
|
9
9
|
import { trimNode } from '../visibility';
|
|
10
10
|
import { stringify } from '../util';
|
|
@@ -21,7 +21,7 @@ export const link: LinkParser = lazy(() => validate(['[', '{'], union([
|
|
|
21
21
|
textlink,
|
|
22
22
|
])));
|
|
23
23
|
|
|
24
|
-
const textlink: LinkParser.TextLinkParser = lazy(() =>
|
|
24
|
+
export const textlink: LinkParser.TextLinkParser = lazy(() =>
|
|
25
25
|
constraint(State.link, false,
|
|
26
26
|
syntax(Syntax.link, 2, 10, State.linkers | State.media,
|
|
27
27
|
bind(reverse(tails([
|
|
@@ -37,7 +37,7 @@ const textlink: LinkParser.TextLinkParser = lazy(() =>
|
|
|
37
37
|
return parse(content, params, rest, context);
|
|
38
38
|
}))));
|
|
39
39
|
|
|
40
|
-
const medialink: LinkParser.MediaLinkParser = lazy(() =>
|
|
40
|
+
export const medialink: LinkParser.MediaLinkParser = lazy(() =>
|
|
41
41
|
constraint(State.link | State.media, false,
|
|
42
42
|
syntax(Syntax.link, 2, 10, State.linkers,
|
|
43
43
|
bind(reverse(sequence([
|
|
@@ -50,6 +50,11 @@ const medialink: LinkParser.MediaLinkParser = lazy(() =>
|
|
|
50
50
|
([params, content = []]: [string[], (HTMLElement | string)[]], rest, context) =>
|
|
51
51
|
parse(content, params, rest, context)))));
|
|
52
52
|
|
|
53
|
+
export const linemedialink: LinkParser.LineMediaLinkParser = surround(
|
|
54
|
+
linebreak,
|
|
55
|
+
union([medialink]),
|
|
56
|
+
/^(?=[^\S\n]*(?:$|\n))/);
|
|
57
|
+
|
|
53
58
|
export const unsafelink: LinkParser.UnsafeLinkParser = lazy(() =>
|
|
54
59
|
creation(10, precedence(2,
|
|
55
60
|
bind(reverse(tails([
|
|
@@ -3,7 +3,7 @@ import { union, inits, tails, some, syntax, creation, precedence, constraint, va
|
|
|
3
3
|
import { unsafelink, uri, option as linkoption, resolve } from './link';
|
|
4
4
|
import { attributes } from './html';
|
|
5
5
|
import { unsafehtmlentity } from './htmlentity';
|
|
6
|
-
import { txt, str } from '../source';
|
|
6
|
+
import { txt, linebreak, str } from '../source';
|
|
7
7
|
import { Syntax, State } from '../context';
|
|
8
8
|
import { ReadonlyURL } from 'spica/url';
|
|
9
9
|
import { unshift, push } from 'spica/array';
|
|
@@ -61,6 +61,11 @@ export const media: MediaParser = lazy(() => validate(['![', '!{'], open(
|
|
|
61
61
|
({ source: `{ ${INSECURE_URI}${params.join('')} }${rest}`, context });
|
|
62
62
|
}))))));
|
|
63
63
|
|
|
64
|
+
export const linemedia: MediaParser.LineMediaParser = surround(
|
|
65
|
+
linebreak,
|
|
66
|
+
union([media]),
|
|
67
|
+
/^(?=[^\S\n]*(?:$|\n))/);
|
|
68
|
+
|
|
64
69
|
const bracket: MediaParser.TextParser.BracketParser = lazy(() => creation(union([
|
|
65
70
|
surround(str('('), some(union([unsafehtmlentity, bracket, txt]), ')'), str(')'), true, undefined, ([as, bs = []], rest) => [unshift(as, bs), rest]),
|
|
66
71
|
surround(str('['), some(union([unsafehtmlentity, bracket, txt]), ']'), str(']'), true, undefined, ([as, bs = []], rest) => [unshift(as, bs), rest]),
|
|
@@ -1,12 +1,21 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { union, constraint, rewrite, open, convert } from '../../combinator';
|
|
1
|
+
import { ShortMediaParser } from '../inline';
|
|
2
|
+
import { union, constraint, focus, rewrite, open, convert } from '../../combinator';
|
|
3
3
|
import { url } from './autolink/url';
|
|
4
4
|
import { media } from './media';
|
|
5
|
+
import { linebreak } from '../source';
|
|
5
6
|
import { State } from '../context';
|
|
6
7
|
|
|
7
|
-
export const shortmedia:
|
|
8
|
+
export const shortmedia: ShortMediaParser = rewrite(
|
|
8
9
|
constraint(State.media, false,
|
|
9
10
|
open('!', url)),
|
|
10
11
|
convert(
|
|
11
12
|
source => `!{ ${source.slice(1)} }`,
|
|
12
13
|
union([media])));
|
|
14
|
+
|
|
15
|
+
export const lineshortmedia: ShortMediaParser.LineShortMediaParser = open(
|
|
16
|
+
linebreak,
|
|
17
|
+
focus(
|
|
18
|
+
/^!https?:\/\/\S+(?=[^\S\n]*(?:$|\n))/,
|
|
19
|
+
convert(
|
|
20
|
+
source => `!{ ${source.slice(1)} }`,
|
|
21
|
+
union([media]))));
|
|
@@ -56,11 +56,11 @@ describe('Unit: parser/inline', () => {
|
|
|
56
56
|
assert.deepStrictEqual(inspect(parser('{}')), [['{', '}'], '']);
|
|
57
57
|
assert.deepStrictEqual(inspect(parser('{a}')), [['<a class="url" href="a">a</a>'], '']);
|
|
58
58
|
assert.deepStrictEqual(inspect(parser('{{a}}')), [['<span class="template">{{a}}</span>'], '']);
|
|
59
|
-
assert.deepStrictEqual(inspect(parser('!{}')), [['!', '{', '}'], '']);
|
|
60
|
-
assert.deepStrictEqual(inspect(parser('!{a}')), [['<a href="a" target="_blank"><img class="media" data-src="a" alt=""></a>'], '']);
|
|
61
|
-
assert.deepStrictEqual(inspect(parser('!{{a}}')), [['!', '<span class="template">{{a}}</span>'], '']);
|
|
62
|
-
assert.deepStrictEqual(inspect(parser('!{{{a}}}')), [['!', '<span class="template">{{{a}}}</span>'], '']);
|
|
63
|
-
assert.deepStrictEqual(inspect(parser('!!{a}')), [['!', '<a
|
|
59
|
+
assert.deepStrictEqual(inspect(parser('\r!{}')), [['!', '{', '}'], '']);
|
|
60
|
+
assert.deepStrictEqual(inspect(parser('\r!{a}')), [['<a href="a" target="_blank"><img class="media" data-src="a" alt=""></a>'], '']);
|
|
61
|
+
assert.deepStrictEqual(inspect(parser('\r!{{a}}')), [['!', '<span class="template">{{a}}</span>'], '']);
|
|
62
|
+
assert.deepStrictEqual(inspect(parser('\r!{{{a}}}')), [['!', '<span class="template">{{{a}}}</span>'], '']);
|
|
63
|
+
assert.deepStrictEqual(inspect(parser('\r!!{a}')), [['!', '!', '<a class="url" href="a">a</a>'], '']);
|
|
64
64
|
assert.deepStrictEqual(inspect(parser('${a}')), [['$', '<a class="url" href="a">a</a>'], '']);
|
|
65
65
|
assert.deepStrictEqual(inspect(parser('${{a}}')), [['$', '<span class="template">{{a}}</span>'], '']);
|
|
66
66
|
assert.deepStrictEqual(inspect(parser('${{{a}}}')), [['$', '<span class="template">{{{a}}}</span>'], '']);
|
|
@@ -105,11 +105,8 @@ describe('Unit: parser/inline', () => {
|
|
|
105
105
|
assert.deepStrictEqual(inspect(parser('0http://host')), [['0http', ':', '/', '/', 'host'], '']);
|
|
106
106
|
assert.deepStrictEqual(inspect(parser('0aAhttp://host')), [['0aAhttp', ':', '/', '/', 'host'], '']);
|
|
107
107
|
assert.deepStrictEqual(inspect(parser('?http://host')), [['?', '<a class="url" href="http://host" target="_blank">http://host</a>'], '']);
|
|
108
|
-
assert.deepStrictEqual(inspect(parser('0!http://host')), [['0', '<a href="http://host" target="_blank"
|
|
108
|
+
assert.deepStrictEqual(inspect(parser('0!http://host')), [['0', '!', '<a class="url" href="http://host" target="_blank">http://host</a>'], '']);
|
|
109
109
|
assert.deepStrictEqual(inspect(parser('0?http://host')), [['0', '?', '<a class="url" href="http://host" target="_blank">http://host</a>'], '']);
|
|
110
|
-
assert.deepStrictEqual(inspect(parser('0!!http://host')), [['0', '!', '<a href="http://host" target="_blank"><img class="media" data-src="http://host" alt=""></a>'], '']);
|
|
111
|
-
assert.deepStrictEqual(inspect(parser('0?!http://host')), [['0', '?', '<a href="http://host" target="_blank"><img class="media" data-src="http://host" alt=""></a>'], '']);
|
|
112
|
-
assert.deepStrictEqual(inspect(parser('0!?http://host')), [['0', '!', '?', '<a class="url" href="http://host" target="_blank">http://host</a>'], '']);
|
|
113
110
|
assert.deepStrictEqual(inspect(parser('_http://host')), [['_', '<a class="url" href="http://host" target="_blank">http://host</a>'], '']);
|
|
114
111
|
assert.deepStrictEqual(inspect(parser('_http://host_')), [['<em><a class="url" href="http://host" target="_blank">http://host</a></em>'], '']);
|
|
115
112
|
assert.deepStrictEqual(inspect(parser('*http://host*')), [['<strong><a class="url" href="http://host" target="_blank">http://host</a></strong>'], '']);
|
package/src/parser/inline.ts
CHANGED
|
@@ -7,7 +7,7 @@ import { comment } from './inline/comment';
|
|
|
7
7
|
import { math } from './inline/math';
|
|
8
8
|
import { extension } from './inline/extension';
|
|
9
9
|
import { ruby } from './inline/ruby';
|
|
10
|
-
import {
|
|
10
|
+
import { textlink, linemedialink } from './inline/link';
|
|
11
11
|
import { html } from './inline/html';
|
|
12
12
|
import { insertion } from './inline/insertion';
|
|
13
13
|
import { deletion } from './inline/deletion';
|
|
@@ -15,9 +15,9 @@ import { mark } from './inline/mark';
|
|
|
15
15
|
import { emphasis } from './inline/emphasis';
|
|
16
16
|
import { strong } from './inline/strong';
|
|
17
17
|
import { code } from './inline/code';
|
|
18
|
-
import {
|
|
18
|
+
import { linemedia } from './inline/media';
|
|
19
19
|
import { htmlentity } from './inline/htmlentity';
|
|
20
|
-
import {
|
|
20
|
+
import { lineshortmedia } from './inline/shortmedia';
|
|
21
21
|
import { autolink } from './inline/autolink';
|
|
22
22
|
import { bracket } from './inline/bracket';
|
|
23
23
|
import { text } from './source';
|
|
@@ -41,7 +41,7 @@ export import CodeParser = InlineParser.CodeParser;
|
|
|
41
41
|
export import MediaParser = InlineParser.MediaParser;
|
|
42
42
|
export import HTMLEntityParser = InlineParser.HTMLEntityParser;
|
|
43
43
|
export import UnsafeHTMLEntityParser = InlineParser.UnsafeHTMLEntityParser;
|
|
44
|
-
export import
|
|
44
|
+
export import ShortMediaParser = InlineParser.ShortMediaParser;
|
|
45
45
|
export import AutolinkParser = InlineParser.AutolinkParser;
|
|
46
46
|
export import BracketParser = InlineParser.BracketParser;
|
|
47
47
|
|
|
@@ -53,8 +53,9 @@ export const inline: InlineParser = union([
|
|
|
53
53
|
math,
|
|
54
54
|
extension,
|
|
55
55
|
ruby,
|
|
56
|
-
|
|
57
|
-
|
|
56
|
+
textlink,
|
|
57
|
+
linemedialink,
|
|
58
|
+
linemedia,
|
|
58
59
|
html,
|
|
59
60
|
insertion,
|
|
60
61
|
deletion,
|
|
@@ -63,7 +64,7 @@ export const inline: InlineParser = union([
|
|
|
63
64
|
emphasis,
|
|
64
65
|
code,
|
|
65
66
|
htmlentity,
|
|
66
|
-
|
|
67
|
+
lineshortmedia,
|
|
67
68
|
autolink,
|
|
68
69
|
bracket,
|
|
69
70
|
text
|
|
@@ -37,7 +37,7 @@ describe('Unit: parser/processor/footnote', () => {
|
|
|
37
37
|
footnote.outerHTML,
|
|
38
38
|
html('ol', [
|
|
39
39
|
html('li', { id: 'annotation::def:1' }, [
|
|
40
|
-
'a b',
|
|
40
|
+
html('span', { id: 'note::a_b' }, 'a b'),
|
|
41
41
|
html('sup', [html('a', { href: '#annotation::ref:1' }, '^1')])
|
|
42
42
|
]),
|
|
43
43
|
]).outerHTML);
|
|
@@ -67,11 +67,11 @@ describe('Unit: parser/processor/footnote', () => {
|
|
|
67
67
|
footnote.outerHTML,
|
|
68
68
|
html('ol', [
|
|
69
69
|
html('li', { id: 'annotation::def:1' }, [
|
|
70
|
-
'1',
|
|
70
|
+
html('span', { id: 'note::1' }, '1'),
|
|
71
71
|
html('sup', [html('a', { href: '#annotation::ref:1' }, '^1')])
|
|
72
72
|
]),
|
|
73
73
|
html('li', { id: 'annotation::def:2' }, [
|
|
74
|
-
'12345678901234567890',
|
|
74
|
+
html('span', { id: 'note::12345678901234567890' }, '12345678901234567890'),
|
|
75
75
|
html('sup', [html('a', { href: '#annotation::ref:2' }, '^2')])
|
|
76
76
|
]),
|
|
77
77
|
]).outerHTML);
|
|
@@ -113,22 +113,22 @@ describe('Unit: parser/processor/footnote', () => {
|
|
|
113
113
|
footnote.outerHTML,
|
|
114
114
|
html('ol', [
|
|
115
115
|
html('li', { id: 'annotation::def:1' }, [
|
|
116
|
-
'1',
|
|
116
|
+
html('span', { id: 'note::1' }, '1'),
|
|
117
117
|
html('sup', [html('a', { href: '#annotation::ref:1' }, '^1')])
|
|
118
118
|
]),
|
|
119
119
|
html('li', { id: 'annotation::def:2' }, [
|
|
120
|
-
'2',
|
|
120
|
+
html('span', { id: 'note::2' }, '2'),
|
|
121
121
|
html('sup', [
|
|
122
122
|
html('a', { href: '#annotation::ref:2' }, '^2'),
|
|
123
123
|
html('a', { href: '#annotation::ref:4' }, '^4'),
|
|
124
124
|
]),
|
|
125
125
|
]),
|
|
126
126
|
html('li', { id: 'annotation::def:3' }, [
|
|
127
|
-
'3',
|
|
127
|
+
html('span', { id: 'note::3' }, '3'),
|
|
128
128
|
html('sup', [html('a', { href: '#annotation::ref:3' }, '^3')])
|
|
129
129
|
]),
|
|
130
130
|
html('li', { id: 'annotation::def:4' }, [
|
|
131
|
-
'4',
|
|
131
|
+
html('span', { id: 'note::4' }, '4'),
|
|
132
132
|
html('sup', [html('a', { href: '#annotation::ref:5' }, '^5')])
|
|
133
133
|
]),
|
|
134
134
|
]).outerHTML);
|
|
@@ -151,13 +151,13 @@ describe('Unit: parser/processor/footnote', () => {
|
|
|
151
151
|
assert.deepStrictEqual(
|
|
152
152
|
[...target.children].map(el => el.outerHTML),
|
|
153
153
|
[
|
|
154
|
-
'<blockquote><blockquote><section><p><sup class="annotation disabled" title="a"><span hidden="">a</span><a>*1</a></sup></p><ol class="annotations"><li data-marker="*1">a
|
|
155
|
-
'<aside class="example" data-type="markdown"><pre translate="no">((a))</pre><hr><section><p><sup class="annotation disabled" title="a"><span hidden="">a</span><a>*1</a></sup></p><ol class="annotations"><li data-marker="*1">a
|
|
154
|
+
'<blockquote><blockquote><section><p><sup class="annotation disabled" title="a"><span hidden="">a</span><a>*1</a></sup></p><ol class="annotations"><li data-marker="*1"><span>a</span><sup><a>^1</a></sup></li></ol><h2>References</h2><ol class="references"></ol></section></blockquote><section><p><sup class="annotation disabled" title="a"><span hidden="">a</span><a>*1</a></sup><br>~~~</p><ol class="annotations"><li data-marker="*1"><span>a</span><sup><a>^1</a></sup></li></ol><h2>References</h2><ol class="references"></ol></section></blockquote>',
|
|
155
|
+
'<aside class="example" data-type="markdown"><pre translate="no">((a))</pre><hr><section><p><sup class="annotation disabled" title="a"><span hidden="">a</span><a>*1</a></sup></p><ol class="annotations"><li data-marker="*1"><span>a</span><sup><a>^1</a></sup></li></ol><h2>References</h2><ol class="references"></ol></section></aside>',
|
|
156
156
|
'<p><sup class="annotation" id="annotation::ref:1" title="a"><span hidden="">a</span><a href="#annotation::def:1">*1</a></sup></p>',
|
|
157
157
|
]);
|
|
158
158
|
assert.deepStrictEqual(
|
|
159
159
|
footnote.outerHTML,
|
|
160
|
-
'<ol><li id="annotation::def:1">a
|
|
160
|
+
'<ol><li id="annotation::def:1"><span id="note::a">a</span><sup><a href="#annotation::ref:1">^1</a></sup></li></ol>');
|
|
161
161
|
}
|
|
162
162
|
});
|
|
163
163
|
|
|
@@ -180,7 +180,7 @@ describe('Unit: parser/processor/footnote', () => {
|
|
|
180
180
|
footnote.outerHTML,
|
|
181
181
|
html('ol', [
|
|
182
182
|
html('li', { id: 'annotation:0:def:1' }, [
|
|
183
|
-
'a b',
|
|
183
|
+
html('span', { id: 'note:0:a_b' }, 'a b'),
|
|
184
184
|
html('sup', [html('a', { href: '#annotation:0:ref:1' }, '^1')])
|
|
185
185
|
]),
|
|
186
186
|
]).outerHTML);
|
|
@@ -202,7 +202,7 @@ describe('Unit: parser/processor/footnote', () => {
|
|
|
202
202
|
]).outerHTML,
|
|
203
203
|
html('ol', { class: 'annotations' }, [
|
|
204
204
|
html('li', { id: 'annotation::def:1', 'data-marker': '*1' }, [
|
|
205
|
-
'1',
|
|
205
|
+
html('span', { id: 'note::1' }, '1'),
|
|
206
206
|
html('sup', [html('a', { href: '#annotation::ref:1' }, '^1')])
|
|
207
207
|
]),
|
|
208
208
|
]).outerHTML,
|
|
@@ -220,11 +220,11 @@ describe('Unit: parser/processor/footnote', () => {
|
|
|
220
220
|
]).outerHTML,
|
|
221
221
|
html('ol', { class: 'annotations' }, [
|
|
222
222
|
html('li', { id: 'annotation::def:2', 'data-marker': '*2' }, [
|
|
223
|
-
'2',
|
|
223
|
+
html('span', { id: 'note::2' }, '2'),
|
|
224
224
|
html('sup', [html('a', { href: '#annotation::ref:2' }, '^2')])
|
|
225
225
|
]),
|
|
226
226
|
html('li', { id: 'annotation::def:3', 'data-marker': '*3' }, [
|
|
227
|
-
'3',
|
|
227
|
+
html('span', { id: 'note::3' }, '3'),
|
|
228
228
|
html('sup', [html('a', { href: '#annotation::ref:3' }, '^3')])
|
|
229
229
|
]),
|
|
230
230
|
]).outerHTML,
|
|
@@ -237,7 +237,7 @@ describe('Unit: parser/processor/footnote', () => {
|
|
|
237
237
|
]).outerHTML,
|
|
238
238
|
html('ol', { class: 'annotations' }, [
|
|
239
239
|
html('li', { id: 'annotation::def:4', 'data-marker': '*4' }, [
|
|
240
|
-
'4',
|
|
240
|
+
html('span', { id: 'note::4' }, '4'),
|
|
241
241
|
html('sup', [html('a', { href: '#annotation::ref:4' }, '^4')])
|
|
242
242
|
]),
|
|
243
243
|
]).outerHTML,
|
|
@@ -267,7 +267,7 @@ describe('Unit: parser/processor/footnote', () => {
|
|
|
267
267
|
footnote.outerHTML,
|
|
268
268
|
html('ol', [
|
|
269
269
|
html('li', { id: 'reference::def:1' }, [
|
|
270
|
-
'a b',
|
|
270
|
+
html('span', { id: 'note::a_b' }, 'a b'),
|
|
271
271
|
html('sup', [html('a', { href: '#reference::ref:1' }, '^1')])
|
|
272
272
|
]),
|
|
273
273
|
]).outerHTML);
|
|
@@ -301,7 +301,7 @@ describe('Unit: parser/processor/footnote', () => {
|
|
|
301
301
|
footnote.outerHTML,
|
|
302
302
|
html('ol', [
|
|
303
303
|
html('li', { id: 'reference::def:1' }, [
|
|
304
|
-
'b',
|
|
304
|
+
html('span', { id: 'note::b' }, 'b'),
|
|
305
305
|
html('sup', [
|
|
306
306
|
html('a', { href: '#reference::ref:1' }, '^1'),
|
|
307
307
|
html('a', { href: '#reference::ref:2', title: 'b' }, '^2'),
|