securemark 0.288.0 → 0.288.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 +8 -0
- package/dist/index.js +7261 -7317
- package/markdown.d.ts +1 -7
- package/package.json +1 -1
- package/src/combinator/control/manipulation/surround.ts +5 -0
- package/src/combinator/data/parser/context/delimiter.ts +2 -2
- package/src/combinator/data/parser.ts +1 -0
- package/src/parser/api/parse.test.ts +2 -2
- package/src/parser/block/codeblock.ts +9 -6
- package/src/parser/block/extension/aside.ts +7 -8
- package/src/parser/block/extension/example.ts +7 -8
- package/src/parser/block/extension/figure.ts +77 -74
- package/src/parser/block/extension/message.ts +7 -8
- package/src/parser/block/extension/placeholder.ts +6 -3
- package/src/parser/block/extension/table.ts +13 -24
- package/src/parser/block/heading.test.ts +1 -1
- package/src/parser/block/heading.ts +2 -3
- package/src/parser/block/ilist.ts +17 -7
- package/src/parser/block/mathblock.ts +8 -6
- package/src/parser/block/mediablock.ts +5 -8
- package/src/parser/block/olist.ts +5 -7
- package/src/parser/block/reply/cite.ts +2 -6
- package/src/parser/block/reply/quote.ts +3 -2
- package/src/parser/block/reply.ts +1 -1
- package/src/parser/block/sidefence.ts +2 -3
- package/src/parser/block/table.ts +2 -3
- package/src/parser/block/ulist.ts +3 -17
- package/src/parser/context.ts +1 -2
- package/src/parser/header.ts +2 -3
- package/src/parser/inline/annotation.test.ts +1 -0
- package/src/parser/inline/bracket.ts +18 -24
- package/src/parser/inline/extension/index.test.ts +1 -1
- package/src/parser/inline/extension/index.ts +17 -7
- package/src/parser/inline/extension/indexee.ts +2 -3
- package/src/parser/inline/extension/indexer.test.ts +2 -1
- package/src/parser/inline/extension/placeholder.ts +2 -3
- package/src/parser/inline/html.ts +21 -23
- package/src/parser/inline/htmlentity.ts +6 -8
- package/src/parser/inline/link.test.ts +4 -0
- package/src/parser/inline/link.ts +3 -5
- package/src/parser/inline/math.ts +3 -3
- package/src/parser/inline/media.test.ts +17 -13
- package/src/parser/inline/media.ts +15 -9
- package/src/parser/inline/reference.ts +3 -7
- package/src/parser/inline/ruby.ts +4 -5
- package/src/parser/inline.test.ts +5 -3
- package/src/parser/source/escapable.test.ts +5 -5
- package/src/parser/source/escapable.ts +7 -1
- package/src/parser/source/str.ts +4 -6
- package/src/parser/source/text.ts +1 -0
- package/src/parser/source/unescapable.test.ts +5 -5
- package/src/parser/source/unescapable.ts +13 -8
- package/src/parser/util.ts +12 -0
- package/src/parser/visibility.ts +2 -3
|
@@ -7,10 +7,10 @@ describe('Unit: parser/inline/media', () => {
|
|
|
7
7
|
const parser = (source: string) => some(media)({ source, context: {} });
|
|
8
8
|
|
|
9
9
|
it('xss', () => {
|
|
10
|
-
assert.deepStrictEqual(inspect(parser('![]{javascript:alert}')), [['<img class="
|
|
11
|
-
assert.deepStrictEqual(inspect(parser('![]{vbscript:alert}')), [['<img class="
|
|
12
|
-
assert.deepStrictEqual(inspect(parser('![]{data:text/html;base64,PHNjcmlwdD5hbGVydCgnWFNTJyk8L3NjcmlwdD4K}')), [['<img class="
|
|
13
|
-
assert.deepStrictEqual(inspect(parser('![]{any:alert}')), [['<img class="
|
|
10
|
+
assert.deepStrictEqual(inspect(parser('![]{javascript:alert}')), [['<img class="invalid" data-src="javascript:alert" alt="">'], '']);
|
|
11
|
+
assert.deepStrictEqual(inspect(parser('![]{vbscript:alert}')), [['<img class="invalid" data-src="vbscript:alert" alt="">'], '']);
|
|
12
|
+
assert.deepStrictEqual(inspect(parser('![]{data:text/html;base64,PHNjcmlwdD5hbGVydCgnWFNTJyk8L3NjcmlwdD4K}')), [['<img class="invalid" data-src="data:text/html;base64,PHNjcmlwdD5hbGVydCgnWFNTJyk8L3NjcmlwdD4K" alt="">'], '']);
|
|
13
|
+
assert.deepStrictEqual(inspect(parser('![]{any:alert}')), [['<img class="invalid" data-src="any:alert" alt="">'], '']);
|
|
14
14
|
assert.deepStrictEqual(inspect(parser('![]{"}')), [['<a href=""" target="_blank"><img class="media" data-src=""" alt=""></a>'], '']);
|
|
15
15
|
assert.deepStrictEqual(inspect(parser('![]{\\}')), [['<a href="\\" target="_blank"><img class="media" data-src="\\" alt=""></a>'], '']);
|
|
16
16
|
assert.deepStrictEqual(inspect(parser('![\\"]{/}')), [['<a href="/" target="_blank"><img class="media" data-src="/" alt="""></a>'], '']);
|
|
@@ -30,6 +30,8 @@ describe('Unit: parser/inline/media', () => {
|
|
|
30
30
|
assert.deepStrictEqual(inspect(parser('![]{ }')), undefined);
|
|
31
31
|
assert.deepStrictEqual(inspect(parser('![]]{/}')), undefined);
|
|
32
32
|
assert.deepStrictEqual(inspect(parser('![]{{}')), undefined);
|
|
33
|
+
assert.deepStrictEqual(inspect(parser('![]{}}')), undefined);
|
|
34
|
+
assert.deepStrictEqual(inspect(parser('![]{{}}')), undefined);
|
|
33
35
|
assert.deepStrictEqual(inspect(parser('![]{{b}}')), undefined);
|
|
34
36
|
assert.deepStrictEqual(inspect(parser('![]{b\nc}')), undefined);
|
|
35
37
|
assert.deepStrictEqual(inspect(parser('![]{a\\\nc}')), undefined);
|
|
@@ -42,20 +44,20 @@ describe('Unit: parser/inline/media', () => {
|
|
|
42
44
|
assert.deepStrictEqual(inspect(parser('![\\ ]{b}')), undefined);
|
|
43
45
|
assert.deepStrictEqual(inspect(parser('![\\\n]{b}')), undefined);
|
|
44
46
|
assert.deepStrictEqual(inspect(parser('![	]{b}')), undefined);
|
|
45
|
-
assert.deepStrictEqual(inspect(parser('![&a;]{b}')), [['<img class="
|
|
47
|
+
assert.deepStrictEqual(inspect(parser('![&a;]{b}')), [['<img class="invalid" data-src="b" alt="&a;">'], '']);
|
|
46
48
|
assert.deepStrictEqual(inspect(parser('![[]{b}')), undefined);
|
|
47
49
|
assert.deepStrictEqual(inspect(parser('![]]{b}')), undefined);
|
|
48
50
|
assert.deepStrictEqual(inspect(parser('![a]{}')), undefined);
|
|
49
51
|
assert.deepStrictEqual(inspect(parser('![a\nb]{b}')), undefined);
|
|
50
52
|
assert.deepStrictEqual(inspect(parser('![a\\\nb]{b}')), undefined);
|
|
51
|
-
assert.deepStrictEqual(inspect(parser('![]{ttp://host}')), [['<img class="
|
|
52
|
-
assert.deepStrictEqual(inspect(parser('![]{tel:1234567890}')), [['<img class="
|
|
53
|
-
//assert.deepStrictEqual(inspect(parser('![]{http://[::ffff:0:0%1]}')), [['<img class="
|
|
54
|
-
//assert.deepStrictEqual(inspect(parser('![]{http://[::ffff:0:0/96]}')), [['<img class="
|
|
55
|
-
assert.deepStrictEqual(inspect(parser('![]{.}')), [['<img class="
|
|
56
|
-
assert.deepStrictEqual(inspect(parser('![]{..}')), [['<img class="
|
|
57
|
-
assert.deepStrictEqual(inspect(parser('![]{../}')), [['<img class="
|
|
58
|
-
assert.deepStrictEqual(inspect(parser('![]{/../b}')), [['<img class="
|
|
53
|
+
assert.deepStrictEqual(inspect(parser('![]{ttp://host}')), [['<img class="invalid" data-src="ttp://host" alt="">'], '']);
|
|
54
|
+
assert.deepStrictEqual(inspect(parser('![]{tel:1234567890}')), [['<img class="invalid" data-src="tel:1234567890" alt="">'], '']);
|
|
55
|
+
//assert.deepStrictEqual(inspect(parser('![]{http://[::ffff:0:0%1]}')), [['<img class="invalid" alt="">'], '']);
|
|
56
|
+
//assert.deepStrictEqual(inspect(parser('![]{http://[::ffff:0:0/96]}')), [['<img class="invalid" alt="">'], '']);
|
|
57
|
+
assert.deepStrictEqual(inspect(parser('![]{.}')), [['<img class="invalid" data-src="." alt="">'], '']);
|
|
58
|
+
assert.deepStrictEqual(inspect(parser('![]{..}')), [['<img class="invalid" data-src=".." alt="">'], '']);
|
|
59
|
+
assert.deepStrictEqual(inspect(parser('![]{../}')), [['<img class="invalid" data-src="../" alt="">'], '']);
|
|
60
|
+
assert.deepStrictEqual(inspect(parser('![]{/../b}')), [['<img class="invalid" data-src="/../b" alt="">'], '']);
|
|
59
61
|
assert.deepStrictEqual(inspect(parser(' ![]{b}')), undefined);
|
|
60
62
|
assert.deepStrictEqual(inspect(parser('[]{/}')), undefined);
|
|
61
63
|
});
|
|
@@ -69,6 +71,8 @@ describe('Unit: parser/inline/media', () => {
|
|
|
69
71
|
assert.deepStrictEqual(inspect(parser('![]{ b }')), [['<a href="b" target="_blank"><img class="media" data-src="b" alt=""></a>'], '']);
|
|
70
72
|
assert.deepStrictEqual(inspect(parser('![]{ b }')), [['<a href="b" target="_blank"><img class="media" data-src="b" alt=""></a>'], '']);
|
|
71
73
|
assert.deepStrictEqual(inspect(parser('![]{ b }')), [['<a href="b" target="_blank"><img class="media" data-src="b" alt=""></a>'], '']);
|
|
74
|
+
assert.deepStrictEqual(inspect(parser('![]{"}')), [['<a href=""" target="_blank"><img class="media" data-src=""" alt=""></a>'], '']);
|
|
75
|
+
assert.deepStrictEqual(inspect(parser('![]{"}"}')), [['<a href=""" target="_blank"><img class="media" data-src=""" alt=""></a>'], '"}']);
|
|
72
76
|
assert.deepStrictEqual(inspect(parser('![]{\\}')), [['<a href="\\" target="_blank"><img class="media" data-src="\\" alt=""></a>'], '']);
|
|
73
77
|
assert.deepStrictEqual(inspect(parser('![]{\\ }')), [['<a href="\\" target="_blank"><img class="media" data-src="\\" alt=""></a>'], '']);
|
|
74
78
|
assert.deepStrictEqual(inspect(parser('![]{\\b}')), [['<a href="\\b" target="_blank"><img class="media" data-src="\\b" alt=""></a>'], '']);
|
|
@@ -5,7 +5,7 @@ import { unsafelink, uri, option as linkoption, resolve } from './link';
|
|
|
5
5
|
import { attributes } from './html';
|
|
6
6
|
import { unsafehtmlentity } from './htmlentity';
|
|
7
7
|
import { txt, linebreak, str } from '../source';
|
|
8
|
-
import {
|
|
8
|
+
import { invalid } from '../util';
|
|
9
9
|
import { ReadonlyURL } from 'spica/url';
|
|
10
10
|
import { push } from 'spica/array';
|
|
11
11
|
import { html, define } from 'typed-dom/dom';
|
|
@@ -51,7 +51,7 @@ export const media: MediaParser = lazy(() => constraint(State.media, false, vali
|
|
|
51
51
|
|| (cache = context.caches?.media?.get(url.href)?.cloneNode(true))
|
|
52
52
|
|| html('img', { class: 'media', 'data-src': url.source, alt: text });
|
|
53
53
|
assert(!el.matches('.invalid'));
|
|
54
|
-
cache?.hasAttribute('alt') && cache
|
|
54
|
+
cache?.hasAttribute('alt') && cache.setAttribute('alt', text);
|
|
55
55
|
if (!sanitize(el, url, text)) return [[el], rest];
|
|
56
56
|
assert(!el.matches('.invalid'));
|
|
57
57
|
define(el, attributes('media', push([], el.classList), optspec, params));
|
|
@@ -98,19 +98,25 @@ function sanitize(target: HTMLElement, uri: ReadonlyURL, alt: string): boolean {
|
|
|
98
98
|
case 'https:':
|
|
99
99
|
assert(uri.host);
|
|
100
100
|
if (/\/\.\.?(?:\/|$)/.test('/' + uri.source.slice(0, uri.source.search(/[?#]|$/)))) {
|
|
101
|
-
|
|
102
|
-
|
|
101
|
+
define(target, {
|
|
102
|
+
class: 'invalid',
|
|
103
|
+
...invalid('media', 'argument',
|
|
104
|
+
'Dot-segments cannot be used in media paths; use subresource paths instead')
|
|
105
|
+
});
|
|
103
106
|
return false;
|
|
104
107
|
}
|
|
105
108
|
break;
|
|
106
109
|
default:
|
|
107
|
-
|
|
110
|
+
define(target, { class: 'invalid', ...invalid('media', 'argument', 'Invalid protocol') });
|
|
108
111
|
return false;
|
|
109
112
|
}
|
|
110
|
-
if (alt.includes(Command.
|
|
111
|
-
define(target, {
|
|
112
|
-
|
|
113
|
-
|
|
113
|
+
if (alt.includes(Command.Error)) {
|
|
114
|
+
define(target, {
|
|
115
|
+
class: 'invalid',
|
|
116
|
+
alt: target.getAttribute('alt')?.replace(CmdRegExp.Error, ''),
|
|
117
|
+
...invalid('media', 'argument',
|
|
118
|
+
`Cannot use invalid HTML entitiy "${alt.match(/&[0-9A-Za-z]+;/)![0]}"`)
|
|
119
|
+
});
|
|
114
120
|
return false;
|
|
115
121
|
}
|
|
116
122
|
return true;
|
|
@@ -6,9 +6,10 @@ import { str } from '../source';
|
|
|
6
6
|
import { blank, trimBlankStart, trimBlankNodeEnd } from '../visibility';
|
|
7
7
|
import { html, defrag } from 'typed-dom/dom';
|
|
8
8
|
import { unshift } from 'spica/array';
|
|
9
|
+
import { invalid } from '../util';
|
|
9
10
|
|
|
10
11
|
export const reference: ReferenceParser = lazy(() => constraint(State.reference, false, surround(
|
|
11
|
-
'[[',
|
|
12
|
+
str('[['),
|
|
12
13
|
precedence(1, state(State.annotation | State.reference | State.media,
|
|
13
14
|
subsequence([
|
|
14
15
|
abbr,
|
|
@@ -38,12 +39,7 @@ const abbr: ReferenceParser.AbbrParser = surround(
|
|
|
38
39
|
function attributes(ns: (string | HTMLElement)[]): Record<string, string | undefined> {
|
|
39
40
|
switch (ns[0]) {
|
|
40
41
|
case '':
|
|
41
|
-
return {
|
|
42
|
-
class: 'invalid',
|
|
43
|
-
'data-invalid-syntax': 'reference',
|
|
44
|
-
'data-invalid-type': 'syntax',
|
|
45
|
-
'data-invalid-message': 'Invalid abbreviation',
|
|
46
|
-
};
|
|
42
|
+
return { class: 'invalid', ...invalid('reference', 'syntax', 'Invalid abbreviation') };
|
|
47
43
|
case '\n':
|
|
48
44
|
const abbr = ns[1] as string;
|
|
49
45
|
ns[0] = ns[1] = '';
|
|
@@ -5,6 +5,7 @@ import { sequence, surround, dup, lazy, fmap } from '../../combinator';
|
|
|
5
5
|
import { unsafehtmlentity } from './htmlentity';
|
|
6
6
|
import { text as txt, str } from '../source';
|
|
7
7
|
import { isTightNodeStart } from '../visibility';
|
|
8
|
+
import { invalid } from '../util';
|
|
8
9
|
import { unshift, push } from 'spica/array';
|
|
9
10
|
import { html, defrag } from 'typed-dom/dom';
|
|
10
11
|
|
|
@@ -100,13 +101,11 @@ function attributes(texts: string[], rubies: string[]): Record<string, string> {
|
|
|
100
101
|
let attrs: Record<string, string> | undefined;
|
|
101
102
|
for (const ss of [texts, rubies]) {
|
|
102
103
|
for (let i = 0; i < ss.length; ++i) {
|
|
103
|
-
if (!ss[i].includes(Command.
|
|
104
|
-
ss[i] = ss[i].replace(CmdRegExp.
|
|
104
|
+
if (!ss[i].includes(Command.Error)) continue;
|
|
105
|
+
ss[i] = ss[i].replace(CmdRegExp.Error, '');
|
|
105
106
|
attrs ??= {
|
|
106
107
|
class: 'invalid',
|
|
107
|
-
|
|
108
|
-
'data-invalid-type': ss === texts ? 'content' : 'argument',
|
|
109
|
-
'data-invalid-message': 'Invalid HTML entity',
|
|
108
|
+
...invalid('ruby', ss === texts ? 'content' : 'argument', 'Invalid HTML entity'),
|
|
110
109
|
};
|
|
111
110
|
}
|
|
112
111
|
}
|
|
@@ -72,6 +72,9 @@ describe('Unit: parser/inline', () => {
|
|
|
72
72
|
assert.deepStrictEqual(inspect(parser('***a*b*c***')), [['<strong><em>a</em>b<em>c</em></strong>'], '']);
|
|
73
73
|
assert.deepStrictEqual(inspect(parser('*(*a*)*')), [['<em><span class="paren">(<em>a</em>)</span></em>'], '']);
|
|
74
74
|
assert.deepStrictEqual(inspect(parser('**(**a**)**')), [['<strong><span class="paren">(<strong>a</strong>)</span></strong>'], '']);
|
|
75
|
+
assert.deepStrictEqual(inspect(parser('*[*]')), [['*', '[', '*', ']'], '']);
|
|
76
|
+
assert.deepStrictEqual(inspect(parser('*<*>')), [['<em><</em>', '>'], '']);
|
|
77
|
+
assert.deepStrictEqual(inspect(parser('*a((b))*')), [['<em>a<sup class="annotation"><span>b</span></sup></em>'], '']);
|
|
75
78
|
assert.deepStrictEqual(inspect(parser('*++ ++*')), [['<em><ins> </ins></em>'], '']);
|
|
76
79
|
assert.deepStrictEqual(inspect(parser('*++ a ++*')), [['<em><ins> a </ins></em>'], '']);
|
|
77
80
|
assert.deepStrictEqual(inspect(parser('*++ a ++*')), [['<em><ins> a </ins></em>'], '']);
|
|
@@ -81,9 +84,6 @@ describe('Unit: parser/inline', () => {
|
|
|
81
84
|
assert.deepStrictEqual(inspect(parser('<bdi>[[<bdi>[[a]]</bdi>]]</bdi>')), [['<bdi><sup class="reference"><span><bdi>[[a]]</bdi></span></sup></bdi>'], '']);
|
|
82
85
|
assert.deepStrictEqual(inspect(parser('<bdi>[#</bdi>]')), [['<bdi>[#</bdi>', ']'], '']);
|
|
83
86
|
assert.deepStrictEqual(inspect(parser('"<bdi>("")</bdi>')), [['"', '<bdi><span class="paren">("")</span></bdi>'], '']);
|
|
84
|
-
assert.deepStrictEqual(inspect(parser('*[*]')), [['*', '[', '*', ']'], '']);
|
|
85
|
-
assert.deepStrictEqual(inspect(parser('*<*>')), [['<em><</em>', '>'], '']);
|
|
86
|
-
assert.deepStrictEqual(inspect(parser('*a((b))*')), [['<em>a<sup class="annotation"><span>b</span></sup></em>'], '']);
|
|
87
87
|
assert.deepStrictEqual(inspect(parser('++\na\n++\n~~\nb\n~~\nc')), [['<ins><br>a</ins>', '<br>', '<del><br>b</del>', '<br>', 'c'], '']);
|
|
88
88
|
assert.deepStrictEqual(inspect(parser('``a`')), [['``', 'a', '`'], '']);
|
|
89
89
|
assert.deepStrictEqual(inspect(parser('[@a]')), [['[', '<a class="account" href="/@a">@a</a>', ']'], '']);
|
|
@@ -127,6 +127,8 @@ describe('Unit: parser/inline', () => {
|
|
|
127
127
|
assert.deepStrictEqual(inspect(parser('((${))}$')), [['(', '(', '<span class="math" translate="no" data-src="${))}$">${))}$</span>'], '']);
|
|
128
128
|
assert.deepStrictEqual(inspect(parser('((a\nb))')), [['<span class="paren">(<span class="paren">(a<br>b)</span>)</span>'], '']);
|
|
129
129
|
assert.deepStrictEqual(inspect(parser('(((a\nb)))')), [['<span class="paren">(<span class="paren">(<span class="paren">(a<br>b)</span>)</span>)</span>'], '']);
|
|
130
|
+
assert.deepStrictEqual(inspect(parser('(([[a] ]))')), [['<sup class="annotation"><span>[[a] ]</span></sup>'], '']);
|
|
131
|
+
assert.deepStrictEqual(inspect(parser('(([["*(*"] ]))')), [['<sup class="annotation"><span>[["*(*"] ]</span></sup>'], '']);
|
|
130
132
|
assert.deepStrictEqual(inspect(parser('(([:a\n]')), [['(', '(', '<span class="invalid">a<br></span>'], '']);
|
|
131
133
|
assert.deepStrictEqual(inspect(parser('"((""))')), [['"', '(', '(', '"', '"', ')', ')'], '']);
|
|
132
134
|
assert.deepStrictEqual(inspect(parser('[[[a]]')), [['[', '<sup class="reference"><span>a</span></sup>'], '']);
|
|
@@ -20,13 +20,13 @@ describe('Unit: parser/source/escsource', () => {
|
|
|
20
20
|
assert.deepStrictEqual(inspect(parser(' ')), [[' '], '']);
|
|
21
21
|
assert.deepStrictEqual(inspect(parser(' ')), [[' ', ' '], '']);
|
|
22
22
|
assert.deepStrictEqual(inspect(parser(' ')), [[' ', ' '], '']);
|
|
23
|
-
assert.deepStrictEqual(inspect(parser(' \n')), [[' ', '\n'], '']);
|
|
24
|
-
assert.deepStrictEqual(inspect(parser(' \n')), [[' ', ' ', '\n'], '']);
|
|
25
|
-
assert.deepStrictEqual(inspect(parser(' \n')), [[' ', ' ', '\n'], '']);
|
|
23
|
+
//assert.deepStrictEqual(inspect(parser(' \n')), [[' ', '\n'], '']);
|
|
24
|
+
//assert.deepStrictEqual(inspect(parser(' \n')), [[' ', ' ', '\n'], '']);
|
|
25
|
+
//assert.deepStrictEqual(inspect(parser(' \n')), [[' ', ' ', '\n'], '']);
|
|
26
26
|
});
|
|
27
27
|
|
|
28
28
|
it('linebreak', () => {
|
|
29
|
-
assert.deepStrictEqual(inspect(parser('\n\n')), [['\n', '\n'], '']);
|
|
29
|
+
//assert.deepStrictEqual(inspect(parser('\n\n')), [['\n', '\n'], '']);
|
|
30
30
|
});
|
|
31
31
|
|
|
32
32
|
it('\\', () => {
|
|
@@ -39,7 +39,7 @@ describe('Unit: parser/source/escsource', () => {
|
|
|
39
39
|
assert.deepStrictEqual(inspect(parser('\\a')), [['\\a'], '']);
|
|
40
40
|
assert.deepStrictEqual(inspect(parser('\\$')), [['\\$'], '']);
|
|
41
41
|
assert.deepStrictEqual(inspect(parser('\\ ')), [['\\ '], '']);
|
|
42
|
-
assert.deepStrictEqual(inspect(parser('\\\n')), [['\\', '\n'], '']);
|
|
42
|
+
//assert.deepStrictEqual(inspect(parser('\\\n')), [['\\', '\n'], '']);
|
|
43
43
|
});
|
|
44
44
|
|
|
45
45
|
});
|
|
@@ -20,19 +20,25 @@ export const escsource: EscapableSourceParser = ({ source, context }) => {
|
|
|
20
20
|
consume(-1, context);
|
|
21
21
|
return [[], source.slice(1)];
|
|
22
22
|
case Command.Escape:
|
|
23
|
+
assert(false);
|
|
23
24
|
consume(1, context);
|
|
24
25
|
return [[source.slice(1, 2)], source.slice(2)];
|
|
25
26
|
case '\\':
|
|
26
27
|
switch (source[1]) {
|
|
27
28
|
case undefined:
|
|
29
|
+
return [[source[0]], ''];
|
|
28
30
|
case '\n':
|
|
29
31
|
return [[source[0]], source.slice(1)];
|
|
30
32
|
default:
|
|
31
33
|
consume(1, context);
|
|
32
34
|
return [[source.slice(0, 2)], source.slice(2)];
|
|
33
35
|
}
|
|
36
|
+
case '\n':
|
|
37
|
+
assert(false);
|
|
38
|
+
return [[source[0]], source.slice(1)];
|
|
34
39
|
default:
|
|
35
|
-
|
|
40
|
+
assert(source[0] !== '\n');
|
|
41
|
+
const b = source[0].trimStart() === '';
|
|
36
42
|
const i = b
|
|
37
43
|
? source.search(nonWhitespace)
|
|
38
44
|
: 1;
|
package/src/parser/source/str.ts
CHANGED
|
@@ -19,11 +19,9 @@ export function str(pattern: string | RegExp, not?: string): Parser<string, Cont
|
|
|
19
19
|
: ({ source, context }) => {
|
|
20
20
|
if (source === '') return;
|
|
21
21
|
const m = source.match(pattern);
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
return m
|
|
26
|
-
? [[m[0]], source.slice(m[0].length)]
|
|
27
|
-
: undefined;
|
|
22
|
+
if (m === null) return;
|
|
23
|
+
count && consume(m[0].length, context);
|
|
24
|
+
if (not && source.slice(m[0].length, m[0].length + not.length) === not) return;
|
|
25
|
+
return [[m[0]], source.slice(m[0].length)];
|
|
28
26
|
};
|
|
29
27
|
}
|
|
@@ -20,13 +20,13 @@ describe('Unit: parser/source/unescapable', () => {
|
|
|
20
20
|
assert.deepStrictEqual(inspect(parser(' ')), [[' '], '']);
|
|
21
21
|
assert.deepStrictEqual(inspect(parser(' ')), [[' ', ' '], '']);
|
|
22
22
|
assert.deepStrictEqual(inspect(parser(' ')), [[' ', ' '], '']);
|
|
23
|
-
assert.deepStrictEqual(inspect(parser(' \n')), [[' ', '\n'], '']);
|
|
24
|
-
assert.deepStrictEqual(inspect(parser(' \n')), [[' ', ' ', '\n'], '']);
|
|
25
|
-
assert.deepStrictEqual(inspect(parser(' \n')), [[' ', ' ', '\n'], '']);
|
|
23
|
+
//assert.deepStrictEqual(inspect(parser(' \n')), [[' ', '\n'], '']);
|
|
24
|
+
//assert.deepStrictEqual(inspect(parser(' \n')), [[' ', ' ', '\n'], '']);
|
|
25
|
+
//assert.deepStrictEqual(inspect(parser(' \n')), [[' ', ' ', '\n'], '']);
|
|
26
26
|
});
|
|
27
27
|
|
|
28
28
|
it('linebreak', () => {
|
|
29
|
-
assert.deepStrictEqual(inspect(parser('\n\n')), [['\n', '\n'], '']);
|
|
29
|
+
//assert.deepStrictEqual(inspect(parser('\n\n')), [['\n', '\n'], '']);
|
|
30
30
|
});
|
|
31
31
|
|
|
32
32
|
it('\\', () => {
|
|
@@ -39,7 +39,7 @@ describe('Unit: parser/source/unescapable', () => {
|
|
|
39
39
|
assert.deepStrictEqual(inspect(parser('\\a')), [['\\', 'a'], '']);
|
|
40
40
|
assert.deepStrictEqual(inspect(parser('\\`')), [['\\', '`'], '']);
|
|
41
41
|
assert.deepStrictEqual(inspect(parser('\\ ')), [['\\', ' '], '']);
|
|
42
|
-
assert.deepStrictEqual(inspect(parser('\\\n')), [['\\', '\n'], '']);
|
|
42
|
+
//assert.deepStrictEqual(inspect(parser('\\\n')), [['\\', '\n'], '']);
|
|
43
43
|
});
|
|
44
44
|
|
|
45
45
|
});
|
|
@@ -18,17 +18,22 @@ export const unescsource: UnescapableSourceParser = ({ source, context }) => {
|
|
|
18
18
|
consume(-1, context);
|
|
19
19
|
return [[], source.slice(1)];
|
|
20
20
|
case Command.Escape:
|
|
21
|
-
assert(
|
|
21
|
+
assert(false);
|
|
22
22
|
consume(1, context);
|
|
23
23
|
return [[source.slice(1, 2)], source.slice(2)];
|
|
24
|
+
case '\n':
|
|
25
|
+
assert(false);
|
|
26
|
+
return [[source[0]], source.slice(1)];
|
|
27
|
+
default:
|
|
28
|
+
assert(source[0] !== '\n');
|
|
29
|
+
const b = source[0].trimStart() === '';
|
|
30
|
+
const i = b || isAlphanumeric(source[0])
|
|
31
|
+
? source.search(b ? nonWhitespace : nonAlphanumeric) || 1
|
|
32
|
+
: 1;
|
|
33
|
+
assert(i > 0);
|
|
34
|
+
consume(i - 1, context);
|
|
35
|
+
return [[source.slice(0, i - +b || 1)], source.slice(i - +b || 1)];
|
|
24
36
|
}
|
|
25
|
-
const b = source[0] !== '\n' && source[0].trimStart() === '';
|
|
26
|
-
const i = b || isAlphanumeric(source[0])
|
|
27
|
-
? source.search(b ? nonWhitespace : nonAlphanumeric) || 1
|
|
28
|
-
: 1;
|
|
29
|
-
assert(i > 0);
|
|
30
|
-
consume(i - 1, context);
|
|
31
|
-
return [[source.slice(0, i - +b || 1)], source.slice(i - +b || 1)];
|
|
32
37
|
}
|
|
33
38
|
default:
|
|
34
39
|
consume(i, context);
|
package/src/parser/util.ts
CHANGED
|
@@ -75,6 +75,18 @@ export function repeat<T extends HTMLElement | string>(symbol: string, parser: P
|
|
|
75
75
|
};
|
|
76
76
|
}
|
|
77
77
|
|
|
78
|
+
export function invalid(
|
|
79
|
+
syntax: string,
|
|
80
|
+
type: string,
|
|
81
|
+
message: string,
|
|
82
|
+
): Record<string, string> {
|
|
83
|
+
return {
|
|
84
|
+
'data-invalid-syntax': syntax,
|
|
85
|
+
'data-invalid-type': type,
|
|
86
|
+
'data-invalid-message': message,
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
|
|
78
90
|
export function markInvalid<T extends Element>(
|
|
79
91
|
el: T,
|
|
80
92
|
syntax: string,
|
package/src/parser/visibility.ts
CHANGED
|
@@ -5,7 +5,6 @@ import { union, some, verify, convert, fmap } from '../combinator';
|
|
|
5
5
|
import { unsafehtmlentity } from './inline/htmlentity';
|
|
6
6
|
import { linebreak, unescsource } from './source';
|
|
7
7
|
import { invisibleHTMLEntityNames } from './api/normalize';
|
|
8
|
-
import { reduce } from 'spica/memoize';
|
|
9
8
|
import { push } from 'spica/array';
|
|
10
9
|
|
|
11
10
|
export namespace blank {
|
|
@@ -78,7 +77,7 @@ export function tightStart<T>(parser: Parser<T>, except?: string): Parser<T> {
|
|
|
78
77
|
? parser(input)
|
|
79
78
|
: undefined;
|
|
80
79
|
}
|
|
81
|
-
|
|
80
|
+
function isTightStart(input: Input<MarkdownParser.Context>, except?: string): boolean {
|
|
82
81
|
const { source } = input;
|
|
83
82
|
if (source === '') return true;
|
|
84
83
|
if (except && source.slice(0, except.length) === except) return false;
|
|
@@ -109,7 +108,7 @@ const isTightStart = reduce((input: Input<MarkdownParser.Context>, except?: stri
|
|
|
109
108
|
default:
|
|
110
109
|
return source[0].trimStart() !== '';
|
|
111
110
|
}
|
|
112
|
-
}
|
|
111
|
+
}
|
|
113
112
|
|
|
114
113
|
export function isLooseNodeStart(nodes: readonly (HTMLElement | string)[]): boolean {
|
|
115
114
|
if (nodes.length === 0) return true;
|