securemark 0.243.1 → 0.244.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 +13 -0
- package/design.md +1 -0
- package/dist/securemark.js +123 -110
- package/package-lock.json +147 -141
- package/package.json +6 -6
- package/src/combinator/control/manipulation/fence.ts +25 -15
- package/src/combinator/data/parser.ts +2 -0
- package/src/debug.test.ts +6 -4
- package/src/parser/block/codeblock.test.ts +1 -1
- package/src/parser/block/codeblock.ts +9 -6
- package/src/parser/block/extension/aside.ts +8 -5
- package/src/parser/block/extension/example.ts +9 -5
- package/src/parser/block/extension/fig.test.ts +2 -0
- package/src/parser/block/extension/figure.test.ts +3 -1
- package/src/parser/block/extension/figure.ts +8 -24
- package/src/parser/block/extension/message.ts +9 -5
- package/src/parser/block/extension/placeholder.ts +6 -5
- package/src/parser/block/extension/table.ts +8 -5
- package/src/parser/block/mathblock.test.ts +4 -4
- package/src/parser/block/mathblock.ts +11 -8
- package/src/parser/header.test.ts +1 -0
- package/src/parser/inline/bracket.test.ts +18 -2
- package/src/parser/inline/bracket.ts +1 -1
- package/src/parser/inline/html.test.ts +7 -0
- package/src/parser/inline/html.ts +17 -19
- package/src/parser/inline/link.ts +2 -3
- package/src/parser/inline/media.ts +1 -2
- package/src/renderer/render/media/image.ts +2 -2
- package/src/renderer/render/media/video.ts +1 -1
- package/src/renderer/render/media/youtube.ts +1 -0
|
@@ -2,36 +2,46 @@ import { Parser, Ctx } from '../../data/parser';
|
|
|
2
2
|
import { firstline, isEmpty } from '../constraint/line';
|
|
3
3
|
import { unshift } from 'spica/array';
|
|
4
4
|
|
|
5
|
-
export function fence<C extends Ctx, D extends Parser<unknown, C>[]>(opener: RegExp, limit: number, separation
|
|
5
|
+
export function fence<C extends Ctx, D extends Parser<unknown, C>[]>(opener: RegExp, limit: number, separation = true): Parser<string, C, D> {
|
|
6
6
|
return source => {
|
|
7
7
|
if (source === '') return;
|
|
8
8
|
const matches = source.match(opener);
|
|
9
9
|
if (!matches) return;
|
|
10
10
|
assert(matches[0] === firstline(source));
|
|
11
11
|
const delim = matches[1];
|
|
12
|
+
assert(delim && delim === delim.trim());
|
|
12
13
|
if (matches[0].indexOf(delim, delim.length) !== -1) return;
|
|
13
14
|
let rest = source.slice(matches[0].length);
|
|
14
15
|
// Prevent annoying parsing in editing.
|
|
15
16
|
if (isEmpty(firstline(rest)) && firstline(rest.slice(firstline(rest).length)).trimEnd() !== delim) return;
|
|
16
17
|
let block = '';
|
|
17
18
|
let closer = '';
|
|
18
|
-
|
|
19
|
+
let overflow = '';
|
|
20
|
+
for (let count = 1; ; ++count) {
|
|
19
21
|
if (rest === '') break;
|
|
20
|
-
const line =
|
|
21
|
-
|
|
22
|
-
if
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
22
|
+
const line = firstline(rest);
|
|
23
|
+
if ((closer || count > limit + 1) && isEmpty(line)) break;
|
|
24
|
+
if(closer) {
|
|
25
|
+
overflow += line;
|
|
26
|
+
}
|
|
27
|
+
if (!closer && count <= limit + 1 && line.slice(0, delim.length) === delim && line.trimEnd() === delim) {
|
|
28
|
+
closer = line;
|
|
29
|
+
if (isEmpty(firstline(rest.slice(line.length)))) {
|
|
30
|
+
rest = rest.slice(line.length);
|
|
31
|
+
break;
|
|
32
|
+
}
|
|
33
|
+
if (!separation) {
|
|
34
|
+
rest = rest.slice(line.length);
|
|
35
|
+
break;
|
|
36
|
+
}
|
|
37
|
+
assert(!overflow);
|
|
38
|
+
overflow = line;
|
|
39
|
+
}
|
|
40
|
+
if (!overflow) {
|
|
41
|
+
block += line;
|
|
31
42
|
}
|
|
32
|
-
block += line;
|
|
33
43
|
rest = rest.slice(line.length);
|
|
34
44
|
}
|
|
35
|
-
return [unshift([block, closer], matches), rest];
|
|
45
|
+
return [unshift([block, overflow, closer], matches), rest];
|
|
36
46
|
};
|
|
37
47
|
}
|
package/src/debug.test.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Result, eval, exec } from './combinator/data/parser';
|
|
2
2
|
import { html, define } from 'typed-dom/dom';
|
|
3
|
+
import { querySelector, querySelectorAll } from 'typed-dom/query';
|
|
3
4
|
|
|
4
5
|
export function inspect(result: Result<HTMLElement | string>, until: number | string = Infinity): Result<string> {
|
|
5
6
|
return result && [
|
|
@@ -7,14 +8,15 @@ export function inspect(result: Result<HTMLElement | string>, until: number | st
|
|
|
7
8
|
assert(node);
|
|
8
9
|
if (typeof node === 'string') return node;
|
|
9
10
|
node = node.cloneNode(true);
|
|
10
|
-
assert(!node
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
assert(!querySelector(node, '.invalid[data-invalid-message$="."]'));
|
|
12
|
+
querySelectorAll(node, '.invalid').forEach(el => {
|
|
13
|
+
assert(el.matches('[data-invalid-syntax][data-invalid-type][data-invalid-message]'));
|
|
13
14
|
define(el, {
|
|
14
15
|
'data-invalid-syntax': null,
|
|
15
16
|
'data-invalid-type': null,
|
|
16
17
|
'data-invalid-message': null,
|
|
17
|
-
})
|
|
18
|
+
});
|
|
19
|
+
});
|
|
18
20
|
until = typeof until === 'number'
|
|
19
21
|
? until
|
|
20
22
|
: ~(~node.outerHTML.indexOf(until) || -Infinity) + until.length;
|
|
@@ -17,6 +17,7 @@ describe('Unit: parser/block/codeblock', () => {
|
|
|
17
17
|
assert.deepStrictEqual(inspect(parser('```\na\n```\nb')), [['<pre class="invalid" translate="no">```\na\n```\nb</pre>'], '']);
|
|
18
18
|
assert.deepStrictEqual(inspect(parser('```\n\n\n```')), undefined);
|
|
19
19
|
assert.deepStrictEqual(inspect(parser('```a ```\n```')), undefined);
|
|
20
|
+
assert.deepStrictEqual(inspect(parser('```\n```\n```')), [['<pre class="invalid" translate="no">```\n```\n```</pre>'], '']);
|
|
20
21
|
assert.deepStrictEqual(inspect(parser('```\n````')), [['<pre class="invalid" translate="no">```\n````</pre>'], '']);
|
|
21
22
|
assert.deepStrictEqual(inspect(parser('````\n```')), [['<pre class="invalid" translate="no">````\n```</pre>'], '']);
|
|
22
23
|
assert.deepStrictEqual(inspect(parser(' ```\n```')), undefined);
|
|
@@ -30,7 +31,6 @@ describe('Unit: parser/block/codeblock', () => {
|
|
|
30
31
|
assert.deepStrictEqual(inspect(parser('```\na\nb\n```')), [['<pre class="text">a<br>b</pre>'], '']);
|
|
31
32
|
assert.deepStrictEqual(inspect(parser('```\n\\\n```')), [['<pre class="text">\\</pre>'], '']);
|
|
32
33
|
assert.deepStrictEqual(inspect(parser('```\n`\n```')), [['<pre class="text">`</pre>'], '']);
|
|
33
|
-
assert.deepStrictEqual(inspect(parser('```\n```\n```')), [['<pre class="text">```</pre>'], '']);
|
|
34
34
|
assert.deepStrictEqual(inspect(parser('```\n```\n\n```')), [['<pre class="text"></pre>'], '\n```']);
|
|
35
35
|
assert.deepStrictEqual(inspect(parser('```\n````\n```')), [['<pre class="text">````</pre>'], '']);
|
|
36
36
|
assert.deepStrictEqual(inspect(parser('```\n````\n\n```')), [['<pre class="text">````<br></pre>'], '']);
|
|
@@ -17,7 +17,7 @@ export const segment_: CodeBlockParser.SegmentParser = block(validate('```',
|
|
|
17
17
|
export const codeblock: CodeBlockParser = block(validate('```', fmap(
|
|
18
18
|
fence(opener, 300),
|
|
19
19
|
// Bug: Type mismatch between outer and inner.
|
|
20
|
-
([body, closer, opener, delim, param]: string[], _, context) => {
|
|
20
|
+
([body, overflow, closer, opener, delim, param]: string[], _, context) => {
|
|
21
21
|
const params = param.match(/(?:\\.?|\S)+/g)?.reduce<{
|
|
22
22
|
lang?: string;
|
|
23
23
|
path?: string;
|
|
@@ -45,17 +45,20 @@ export const codeblock: CodeBlockParser = block(validate('```', fmap(
|
|
|
45
45
|
}
|
|
46
46
|
}
|
|
47
47
|
name in params
|
|
48
|
-
? params.invalid = `Duplicate ${name}
|
|
48
|
+
? params.invalid = `Duplicate ${name} attribute`
|
|
49
49
|
: params[name] = value;
|
|
50
50
|
return params;
|
|
51
51
|
}, {}) ?? {};
|
|
52
|
-
if (!closer || params.invalid) return [html('pre', {
|
|
52
|
+
if (!closer || overflow || params.invalid) return [html('pre', {
|
|
53
53
|
class: 'invalid',
|
|
54
54
|
translate: 'no',
|
|
55
55
|
'data-invalid-syntax': 'codeblock',
|
|
56
|
-
'data-invalid-type': !closer ? 'fence' : 'argument',
|
|
57
|
-
'data-invalid-message':
|
|
58
|
-
|
|
56
|
+
'data-invalid-type': !closer || overflow ? 'fence' : 'argument',
|
|
57
|
+
'data-invalid-message':
|
|
58
|
+
!closer ? `Missing the closing delimiter "${delim}"` :
|
|
59
|
+
overflow ? `Invalid trailing line after the closing delimiter "${delim}"` :
|
|
60
|
+
params.invalid,
|
|
61
|
+
}, `${opener}${body}${overflow || closer}`)];
|
|
59
62
|
const el = html('pre',
|
|
60
63
|
{
|
|
61
64
|
class: params.lang ? `code language-${params.lang}` : 'text',
|
|
@@ -7,14 +7,17 @@ import { html } from 'typed-dom/dom';
|
|
|
7
7
|
export const aside: ExtensionParser.AsideParser = creator(100, block(validate('~~~', fmap(
|
|
8
8
|
fence(/^(~{3,})aside(?!\S)([^\n]*)(?:$|\n)/, 300),
|
|
9
9
|
// Bug: Type mismatch between outer and inner.
|
|
10
|
-
([body, closer, opener, delim, param]: string[], _, context) => {
|
|
11
|
-
if (!closer || param.trimStart()) return [html('pre', {
|
|
10
|
+
([body, overflow, closer, opener, delim, param]: string[], _, context) => {
|
|
11
|
+
if (!closer || overflow || param.trimStart()) return [html('pre', {
|
|
12
12
|
class: 'invalid',
|
|
13
13
|
translate: 'no',
|
|
14
14
|
'data-invalid-syntax': 'aside',
|
|
15
|
-
'data-invalid-type': !closer ? 'fence' : 'argument',
|
|
16
|
-
'data-invalid-message':
|
|
17
|
-
|
|
15
|
+
'data-invalid-type': !closer || overflow ? 'fence' : 'argument',
|
|
16
|
+
'data-invalid-message':
|
|
17
|
+
!closer ? `Missing the closing delimiter "${delim}"` :
|
|
18
|
+
overflow ? `Invalid trailing line after the closing delimiter "${delim}"` :
|
|
19
|
+
'Invalid argument',
|
|
20
|
+
}, `${opener}${body}${overflow || closer}`)];
|
|
18
21
|
const annotations = html('ol', { class: 'annotations' });
|
|
19
22
|
const references = html('ol', { class: 'references' });
|
|
20
23
|
const document = parse(body.slice(0, -1), {
|
|
@@ -10,14 +10,17 @@ const opener = /^(~{3,})(?:example\/(\S+))?(?!\S)([^\n]*)(?:$|\n)/;
|
|
|
10
10
|
export const example: ExtensionParser.ExampleParser = creator(100, block(validate('~~~', fmap(
|
|
11
11
|
fence(opener, 300),
|
|
12
12
|
// Bug: Type mismatch between outer and inner.
|
|
13
|
-
([body, closer, opener, delim, type = 'markdown', param]: string[], _, context) => {
|
|
14
|
-
if (!closer || param.trimStart()) return [html('pre', {
|
|
13
|
+
([body, overflow, closer, opener, delim, type = 'markdown', param]: string[], _, context) => {
|
|
14
|
+
if (!closer || overflow || param.trimStart()) return [html('pre', {
|
|
15
15
|
class: 'invalid',
|
|
16
16
|
translate: 'no',
|
|
17
17
|
'data-invalid-syntax': 'example',
|
|
18
|
-
'data-invalid-type': !closer ? 'fence' : 'argument',
|
|
19
|
-
'data-invalid-message':
|
|
20
|
-
|
|
18
|
+
'data-invalid-type': !closer || overflow ? 'fence' : 'argument',
|
|
19
|
+
'data-invalid-message':
|
|
20
|
+
!closer ? `Missing the closing delimiter "${delim}"` :
|
|
21
|
+
overflow ? `Invalid trailing line after the closing delimiter "${delim}"` :
|
|
22
|
+
'Invalid argument',
|
|
23
|
+
}, `${opener}${body}${overflow || closer}`)];
|
|
21
24
|
switch (type) {
|
|
22
25
|
case 'markdown': {
|
|
23
26
|
const annotations = html('ol', { class: 'annotations' });
|
|
@@ -52,6 +55,7 @@ export const example: ExtensionParser.ExampleParser = creator(100, block(validat
|
|
|
52
55
|
class: 'invalid',
|
|
53
56
|
translate: 'no',
|
|
54
57
|
'data-invalid-syntax': 'example',
|
|
58
|
+
'data-invalid-type': 'type',
|
|
55
59
|
'data-invalid-message': 'Invalid example type',
|
|
56
60
|
}, `${opener}${body}${closer}`),
|
|
57
61
|
];
|
|
@@ -31,6 +31,8 @@ describe('Unit: parser/block/extension/fig', () => {
|
|
|
31
31
|
assert.deepStrictEqual(inspect(parser('[$group-name]\n```\n~~~\n```')), [['<figure data-type="text" data-label="group-name" data-group="group"><figcaption><span class="figindex"></span></figcaption><div><pre class="text">~~~</pre></div></figure>'], '']);
|
|
32
32
|
assert.deepStrictEqual(inspect(parser('[$group-name]\n$$\n\n$$')), [['<figure data-type="math" data-label="group-name" data-group="group"><figcaption><span class="figindex"></span></figcaption><div><div class="math" translate="no">$$\n\n$$</div></div></figure>'], '']);
|
|
33
33
|
assert.deepStrictEqual(inspect(parser('[$group-name]\n$$\n\n$$\n')), [['<figure data-type="math" data-label="group-name" data-group="group"><figcaption><span class="figindex"></span></figcaption><div><div class="math" translate="no">$$\n\n$$</div></div></figure>'], '']);
|
|
34
|
+
assert.deepStrictEqual(inspect(parser('[$group-name]\n~~~\n~~~')), [['<figure data-type="example" data-label="group-name" data-group="group"><figcaption><span class="figindex"></span></figcaption><div><aside class="example" data-type="markdown"><pre translate="no"></pre><hr><section><ol class="annotations"></ol><ol class="references"></ol></section></aside></div></figure>'], '']);
|
|
35
|
+
assert.deepStrictEqual(inspect(parser('[$group-name]\n~~~\n~~~\n')), [['<figure data-type="example" data-label="group-name" data-group="group"><figcaption><span class="figindex"></span></figcaption><div><aside class="example" data-type="markdown"><pre translate="no"></pre><hr><section><ol class="annotations"></ol><ol class="references"></ol></section></aside></div></figure>'], '']);
|
|
34
36
|
assert.deepStrictEqual(inspect(parser('[$group-name]\n~~~example/markdown\n~~~')), [['<figure data-type="example" data-label="group-name" data-group="group"><figcaption><span class="figindex"></span></figcaption><div><aside class="example" data-type="markdown"><pre translate="no"></pre><hr><section><ol class="annotations"></ol><ol class="references"></ol></section></aside></div></figure>'], '']);
|
|
35
37
|
assert.deepStrictEqual(inspect(parser('[$group-name]\n~~~example/markdown\n~~~\n')), [['<figure data-type="example" data-label="group-name" data-group="group"><figcaption><span class="figindex"></span></figcaption><div><aside class="example" data-type="markdown"><pre translate="no"></pre><hr><section><ol class="annotations"></ol><ol class="references"></ol></section></aside></div></figure>'], '']);
|
|
36
38
|
assert.deepStrictEqual(inspect(parser('[$group-name]\n~~~table\n~~~')), [['<figure data-type="table" data-label="group-name" data-group="group"><figcaption><span class="figindex"></span></figcaption><div><table></table></div></figure>'], '']);
|
|
@@ -17,6 +17,7 @@ describe('Unit: parser/block/extension/figure', () => {
|
|
|
17
17
|
assert.deepStrictEqual(inspect(parser('~~~figure [$group-name]\n!https://host\n\n\n\n~~~')), [['<pre class="invalid" translate="no">~~~figure [$group-name]\n!https://host\n\n\n\n~~~</pre>'], '']);
|
|
18
18
|
assert.deepStrictEqual(inspect(parser('~~~figure [$group-name]\n !https://host\n~~~')), [['<pre class="invalid" translate="no">~~~figure [$group-name]\n !https://host\n~~~</pre>'], '']);
|
|
19
19
|
assert.deepStrictEqual(inspect(parser('~~~figure [$group-name]\n!https://host\n~~~\n~~~')), [['<pre class="invalid" translate="no">~~~figure [$group-name]\n!https://host\n~~~\n~~~</pre>'], '']);
|
|
20
|
+
assert.deepStrictEqual(inspect(parser('~~~figure [$group-name]\n!https://host\n\ncaption\n~~~\n~~~')), [['<pre class="invalid" translate="no">~~~figure [$group-name]\n!https://host\n\ncaption\n~~~\n~~~</pre>'], '']);
|
|
20
21
|
assert.deepStrictEqual(inspect(parser('~~~figure [$group-name]\n!https://host\n~~~~')), [['<pre class="invalid" translate="no">~~~figure [$group-name]\n!https://host\n~~~~</pre>'], '']);
|
|
21
22
|
assert.deepStrictEqual(inspect(parser('~~~~figure [$group-name]\n!https://host\n~~~')), [['<pre class="invalid" translate="no">~~~~figure [$group-name]\n!https://host\n~~~</pre>'], '']);
|
|
22
23
|
assert.deepStrictEqual(inspect(parser('~~~figure [$group-name]a\nhttps://host\n~~~')), [['<pre class="invalid" translate="no">~~~figure [$group-name]a\nhttps://host\n~~~</pre>'], '']);
|
|
@@ -33,7 +34,7 @@ describe('Unit: parser/block/extension/figure', () => {
|
|
|
33
34
|
assert.deepStrictEqual(inspect(parser('~~~figure [$figure-name]\n> \n\n~~~')), [['<figure data-type="quote" data-label="figure-name" data-group="figure" class="invalid"><figcaption><span class="figindex"></span></figcaption><div><blockquote></blockquote></div></figure>'], '']);
|
|
34
35
|
assert.deepStrictEqual(inspect(parser('~~~figure [$table-name]\n> \n\n~~~')), [['<figure data-type="quote" data-label="table-name" data-group="table" class="invalid"><figcaption><span class="figindex"></span></figcaption><div><blockquote></blockquote></div></figure>'], '']);
|
|
35
36
|
assert.deepStrictEqual(inspect(parser(`~~~figure [$group-name]\n0${'\n'.repeat(301)}~~~`), '>'), [['<pre class="invalid" translate="no">'], '']);
|
|
36
|
-
assert.deepStrictEqual(inspect(parser(`~~~figure [$group-name]\n~~~\n0${'\n'.repeat(301)}~~~\n~~~`), '>'), [['<pre class="invalid" translate="no">'], '\n~~~\n
|
|
37
|
+
assert.deepStrictEqual(inspect(parser(`~~~figure [$group-name]\n~~~\n0${'\n'.repeat(301)}~~~\n~~~`), '>'), [['<pre class="invalid" translate="no">'], `${'\n'.repeat(300)}~~~\n~~~`]);
|
|
37
38
|
});
|
|
38
39
|
|
|
39
40
|
it('valid', () => {
|
|
@@ -52,6 +53,7 @@ describe('Unit: parser/block/extension/figure', () => {
|
|
|
52
53
|
assert.deepStrictEqual(inspect(parser('~~~figure [$group-name]\n$$\n\n$$\n~~~')), [['<figure data-type="math" data-label="group-name" data-group="group"><figcaption><span class="figindex"></span></figcaption><div><div class="math" translate="no">$$\n\n$$</div></div></figure>'], '']);
|
|
53
54
|
assert.deepStrictEqual(inspect(parser('~~~figure [$group-name]\n$$\n~~~\n$$\n~~~')), [['<figure data-type="math" data-label="group-name" data-group="group"><figcaption><span class="figindex"></span></figcaption><div><div class="math" translate="no">$$\n~~~\n$$</div></div></figure>'], '']);
|
|
54
55
|
assert.deepStrictEqual(inspect(parser('~~~figure [$group-name]\n$$\n\n$$\n\ncaption\n~~~')), [['<figure data-type="math" data-label="group-name" data-group="group"><figcaption><span class="figindex"></span>caption</figcaption><div><div class="math" translate="no">$$\n\n$$</div></div></figure>'], '']);
|
|
56
|
+
assert.deepStrictEqual(inspect(parser('~~~figure [$group-name]\n~~~\n~~~\n\ncaption\n~~~')), [['<figure data-type="example" data-label="group-name" data-group="group"><figcaption><span class="figindex"></span>caption</figcaption><div><aside class="example" data-type="markdown"><pre translate="no"></pre><hr><section><ol class="annotations"></ol><ol class="references"></ol></section></aside></div></figure>'], '']);
|
|
55
57
|
assert.deepStrictEqual(inspect(parser('~~~figure [$group-name]\n~~~example/markdown\n~~~\n\ncaption\n~~~')), [['<figure data-type="example" data-label="group-name" data-group="group"><figcaption><span class="figindex"></span>caption</figcaption><div><aside class="example" data-type="markdown"><pre translate="no"></pre><hr><section><ol class="annotations"></ol><ol class="references"></ol></section></aside></div></figure>'], '']);
|
|
56
58
|
assert.deepStrictEqual(inspect(parser('~~~figure [$group-name]\n~~~table\n~~~\n\ncaption\n~~~')), [['<figure data-type="table" data-label="group-name" data-group="group"><figcaption><span class="figindex"></span>caption</figcaption><div><table></table></div></figure>'], '']);
|
|
57
59
|
assert.deepStrictEqual(inspect(parser('~~~figure [$group-name]\n> \n~~~\n\n~~~')), [['<figure data-type="quote" data-label="group-name" data-group="group"><figcaption><span class="figindex"></span></figcaption><div><blockquote><pre><br>~~~</pre></blockquote></div></figure>'], '']);
|
|
@@ -48,7 +48,7 @@ export const segment: FigureParser.SegmentParser = block(match(
|
|
|
48
48
|
closer),
|
|
49
49
|
([, fence]) => fence.length, [])));
|
|
50
50
|
|
|
51
|
-
export const figure: FigureParser = block(fallback(rewrite(segment,
|
|
51
|
+
export const figure: FigureParser = block(fallback(rewrite(segment, fmap(
|
|
52
52
|
convert(source => source.slice(source.match(/^~+(?:figure[^\S\n]+)?/)![0].length, source.trimEnd().lastIndexOf('\n')),
|
|
53
53
|
sequence([
|
|
54
54
|
line(sequence([label, str(/^(?=\s).*\n/)])),
|
|
@@ -82,30 +82,10 @@ export const figure: FigureParser = block(fallback(rewrite(segment, fallback(fma
|
|
|
82
82
|
defrag(caption))),
|
|
83
83
|
html('div', [content]),
|
|
84
84
|
])
|
|
85
|
-
]),
|
|
86
|
-
(source, context) => [[
|
|
87
|
-
html('pre', {
|
|
88
|
-
class: 'invalid',
|
|
89
|
-
translate: 'no',
|
|
90
|
-
'data-invalid-syntax': 'figure',
|
|
91
|
-
...
|
|
92
|
-
!seg_label(source.match(/^~+(?:figure[^\S\n]+)?(\[?\$\S+)/)?.[1] ?? '', context) && {
|
|
93
|
-
'data-invalid-type': 'label',
|
|
94
|
-
'data-invalid-message': 'Invalid label',
|
|
95
|
-
} ||
|
|
96
|
-
/^~+(?:figure[^\S\n]+)?(\[?\$\S+)[^\S\n]+\S/.test(source) && {
|
|
97
|
-
'data-invalid-type': 'argument',
|
|
98
|
-
'data-invalid-message': 'Invalid argument',
|
|
99
|
-
} ||
|
|
100
|
-
{
|
|
101
|
-
'data-invalid-type': 'content',
|
|
102
|
-
'data-invalid-message': 'Invalid content',
|
|
103
|
-
},
|
|
104
|
-
}, source),
|
|
105
|
-
], ''])),
|
|
85
|
+
])),
|
|
106
86
|
fmap(
|
|
107
87
|
fence(/^(~{3,})(?:figure|\[?\$\S*)(?!\S)[^\n]*(?:$|\n)/, 300),
|
|
108
|
-
([body, closer, opener, delim]: string[], _, context) => [
|
|
88
|
+
([body, overflow, closer, opener, delim]: string[], _, context) => [
|
|
109
89
|
html('pre', {
|
|
110
90
|
class: 'invalid',
|
|
111
91
|
translate: 'no',
|
|
@@ -115,6 +95,10 @@ export const figure: FigureParser = block(fallback(rewrite(segment, fallback(fma
|
|
|
115
95
|
'data-invalid-type': 'fence',
|
|
116
96
|
'data-invalid-message': `Missing the closing delimiter "${delim}"`,
|
|
117
97
|
} ||
|
|
98
|
+
overflow && {
|
|
99
|
+
'data-invalid-type': 'fence',
|
|
100
|
+
'data-invalid-message': `Invalid trailing line after the closing delimiter "${delim}"`,
|
|
101
|
+
} ||
|
|
118
102
|
!seg_label(opener.match(/^~+(?:figure[^\S\n]+)?(\[?\$\S+)/)?.[1] ?? '', context) && {
|
|
119
103
|
'data-invalid-type': 'label',
|
|
120
104
|
'data-invalid-message': 'Invalid label',
|
|
@@ -127,7 +111,7 @@ export const figure: FigureParser = block(fallback(rewrite(segment, fallback(fma
|
|
|
127
111
|
'data-invalid-type': 'content',
|
|
128
112
|
'data-invalid-message': 'Invalid content',
|
|
129
113
|
},
|
|
130
|
-
}, `${opener}${body}${closer}`),
|
|
114
|
+
}, `${opener}${body}${overflow || closer}`),
|
|
131
115
|
])));
|
|
132
116
|
|
|
133
117
|
function attributes(label: string, param: string, content: HTMLElement, caption: readonly HTMLElement[]): Record<string, string | undefined> {
|
|
@@ -21,14 +21,17 @@ import MessageParser = ExtensionParser.MessageParser;
|
|
|
21
21
|
export const message: MessageParser = block(validate('~~~', fmap(
|
|
22
22
|
fence(/^(~{3,})message\/(\S+)([^\n]*)(?:$|\n)/, 300),
|
|
23
23
|
// Bug: Type mismatch between outer and inner.
|
|
24
|
-
([body, closer, opener, delim, type, param]: string[], _, context) => {
|
|
25
|
-
if (!closer || param.trimStart()) return [html('pre', {
|
|
24
|
+
([body, overflow, closer, opener, delim, type, param]: string[], _, context) => {
|
|
25
|
+
if (!closer || overflow || param.trimStart()) return [html('pre', {
|
|
26
26
|
class: 'invalid',
|
|
27
27
|
translate: 'no',
|
|
28
28
|
'data-invalid-syntax': 'message',
|
|
29
|
-
'data-invalid-type': !closer ? 'fence' : 'argument',
|
|
30
|
-
'data-invalid-message':
|
|
31
|
-
|
|
29
|
+
'data-invalid-type': !closer || overflow ? 'fence' : 'argument',
|
|
30
|
+
'data-invalid-message':
|
|
31
|
+
!closer ? `Missing the closing delimiter "${delim}"` :
|
|
32
|
+
overflow ? `Invalid trailing line after the closing delimiter "${delim}"` :
|
|
33
|
+
'Invalid argument',
|
|
34
|
+
}, `${opener}${body}${overflow || closer}`)];
|
|
32
35
|
switch (type) {
|
|
33
36
|
case 'note':
|
|
34
37
|
case 'caution':
|
|
@@ -39,6 +42,7 @@ export const message: MessageParser = block(validate('~~~', fmap(
|
|
|
39
42
|
class: 'invalid',
|
|
40
43
|
translate: 'no',
|
|
41
44
|
'data-invalid-syntax': 'message',
|
|
45
|
+
'data-invalid-type': 'type',
|
|
42
46
|
'data-invalid-message': 'Invalid message type',
|
|
43
47
|
}, `${opener}${body}${closer}`)];
|
|
44
48
|
}
|
|
@@ -12,12 +12,13 @@ export const segment_: ExtensionParser.PlaceholderParser.SegmentParser = block(v
|
|
|
12
12
|
|
|
13
13
|
export const placeholder: ExtensionParser.PlaceholderParser = block(validate('~~~', fmap(
|
|
14
14
|
fence(opener, Infinity),
|
|
15
|
-
([body, closer, opener, delim]) => [
|
|
15
|
+
([body, overflow, closer, opener, delim]) => [
|
|
16
16
|
html('pre', {
|
|
17
17
|
class: 'invalid',
|
|
18
18
|
translate: 'no',
|
|
19
|
-
'data-invalid-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
19
|
+
'data-invalid-message':
|
|
20
|
+
!closer ? `Missing the closing delimiter "${delim}"` :
|
|
21
|
+
overflow ? `Invalid trailing line after the closing delimiter "${delim}"` :
|
|
22
|
+
'Invalid argument',
|
|
23
|
+
}, `${opener}${body}${overflow || closer}`),
|
|
23
24
|
])));
|
|
@@ -26,14 +26,17 @@ export const segment_: TableParser.SegmentParser = block(validate('~~~',
|
|
|
26
26
|
export const table: TableParser = block(validate('~~~', recover(fmap(
|
|
27
27
|
fence(opener, 10000),
|
|
28
28
|
// Bug: Type mismatch between outer and inner.
|
|
29
|
-
([body, closer, opener, delim, param]: string[], _, context) => {
|
|
30
|
-
if (!closer || param.trimStart()) return [html('pre', {
|
|
29
|
+
([body, overflow, closer, opener, delim, param]: string[], _, context) => {
|
|
30
|
+
if (!closer || overflow || param.trimStart()) return [html('pre', {
|
|
31
31
|
class: 'invalid',
|
|
32
32
|
translate: 'no',
|
|
33
33
|
'data-invalid-syntax': 'table',
|
|
34
|
-
'data-invalid-type': !closer ? 'fence' : 'argument',
|
|
35
|
-
'data-invalid-message':
|
|
36
|
-
|
|
34
|
+
'data-invalid-type': !closer || overflow ? 'fence' : 'argument',
|
|
35
|
+
'data-invalid-message':
|
|
36
|
+
!closer ? `Missing the closing delimiter "${delim}"` :
|
|
37
|
+
overflow ? `Invalid trailing line after the closing delimiter "${delim}"` :
|
|
38
|
+
'Invalid argument',
|
|
39
|
+
}, `${opener}${body}${overflow || closer}`)];
|
|
37
40
|
return eval(parser(body, context)) ?? [html('table')];
|
|
38
41
|
}),
|
|
39
42
|
(source, _, reason) =>
|
|
@@ -19,10 +19,12 @@ describe('Unit: parser/block/mathblock', () => {
|
|
|
19
19
|
assert.deepStrictEqual(inspect(parser('$$ $$\n$$')), undefined);
|
|
20
20
|
assert.deepStrictEqual(inspect(parser('$$lang\n$$')), [['<pre class="invalid" translate="no">$$lang\n$$</pre>'], '']);
|
|
21
21
|
assert.deepStrictEqual(inspect(parser('$$ param\n$$')), [['<pre class="invalid" translate="no">$$ param\n$$</pre>'], '']);
|
|
22
|
+
assert.deepStrictEqual(inspect(parser('$$\n$$\n$$')), [['<pre class="invalid" translate="no">$$\n$$\n$$</pre>'], '']);
|
|
23
|
+
assert.deepStrictEqual(inspect(parser('$$\n$$$')), [['<pre class="invalid" translate="no">$$\n$$$</pre>'], '']);
|
|
22
24
|
assert.deepStrictEqual(inspect(parser('$$$\n$$')), [['<pre class="invalid" translate="no">$$$\n$$</pre>'], '']);
|
|
23
25
|
assert.deepStrictEqual(inspect(parser('$$$\n$$$')), [['<pre class="invalid" translate="no">$$$\n$$$</pre>'], '']);
|
|
24
26
|
assert.deepStrictEqual(inspect(parser(' $$\n$$')), undefined);
|
|
25
|
-
assert.deepStrictEqual(inspect(parser(`$$\n0${'\n'.repeat(
|
|
27
|
+
assert.deepStrictEqual(inspect(parser(`$$\n0${'\n'.repeat(301)}$$`), '>'), [['<pre class="invalid" translate="no">'], '']);
|
|
26
28
|
});
|
|
27
29
|
|
|
28
30
|
it('basic', () => {
|
|
@@ -34,12 +36,10 @@ describe('Unit: parser/block/mathblock', () => {
|
|
|
34
36
|
assert.deepStrictEqual(inspect(parser('$$\n\\\n$$')), [['<div class="math" translate="no">$$\n\\\n$$</div>'], '']);
|
|
35
37
|
assert.deepStrictEqual(inspect(parser('$$\n$\n$$')), [['<div class="math" translate="no">$$\n$\n$$</div>'], '']);
|
|
36
38
|
assert.deepStrictEqual(inspect(parser('$$\n$\n\n$$')), [['<div class="math" translate="no">$$\n$\n\n$$</div>'], '']);
|
|
37
|
-
assert.deepStrictEqual(inspect(parser('$$\n$$\n$$')), [['<div class="math" translate="no">$$\n$$\n$$</div>'], '']);
|
|
38
39
|
assert.deepStrictEqual(inspect(parser('$$\n$$\n\n$$')), [['<div class="math" translate="no">$$\n$$</div>'], '\n$$']);
|
|
39
40
|
assert.deepStrictEqual(inspect(parser('$$\n$$$\n$$')), [['<div class="math" translate="no">$$\n$$$\n$$</div>'], '']);
|
|
40
41
|
assert.deepStrictEqual(inspect(parser('$$\n$$$\n\n$$')), [['<div class="math" translate="no">$$\n$$$\n\n$$</div>'], '']);
|
|
41
|
-
assert.deepStrictEqual(inspect(parser('
|
|
42
|
-
assert.deepStrictEqual(inspect(parser(`$$\n0${'\n'.repeat(100)}$$`), '>'), [['<div class="math" translate="no">'], '']);
|
|
42
|
+
assert.deepStrictEqual(inspect(parser(`$$\n0${'\n'.repeat(300)}$$`), '>'), [['<div class="math" translate="no">'], '']);
|
|
43
43
|
});
|
|
44
44
|
|
|
45
45
|
});
|
|
@@ -6,23 +6,26 @@ import { html } from 'typed-dom/dom';
|
|
|
6
6
|
const opener = /^(\${2,})(?!\$)([^\n]*)(?:$|\n)/;
|
|
7
7
|
|
|
8
8
|
export const segment: MathBlockParser.SegmentParser = block(validate('$$',
|
|
9
|
-
clear(fence(opener,
|
|
9
|
+
clear(fence(opener, 300))));
|
|
10
10
|
|
|
11
11
|
export const segment_: MathBlockParser.SegmentParser = block(validate('$$',
|
|
12
|
-
clear(fence(opener,
|
|
12
|
+
clear(fence(opener, 300, false))), false);
|
|
13
13
|
|
|
14
14
|
export const mathblock: MathBlockParser = block(validate('$$', fmap(
|
|
15
|
-
fence(opener,
|
|
15
|
+
fence(opener, 300),
|
|
16
16
|
// Bug: Type mismatch between outer and inner.
|
|
17
|
-
([body, closer, opener, delim, param]: string[], _, { caches: { math: cache = undefined } = {} }) => [
|
|
18
|
-
delim.length === 2 && closer && param.trimStart() === ''
|
|
17
|
+
([body, overflow, closer, opener, delim, param]: string[], _, { caches: { math: cache = undefined } = {} }) => [
|
|
18
|
+
delim.length === 2 && closer && !overflow && param.trimStart() === ''
|
|
19
19
|
? cache?.get(`${delim}\n${body}${delim}`)?.cloneNode(true) as HTMLDivElement ||
|
|
20
20
|
html('div', { class: 'math', translate: 'no' }, `${delim}\n${body}${delim}`)
|
|
21
21
|
: html('pre', {
|
|
22
22
|
class: 'invalid',
|
|
23
23
|
translate: 'no',
|
|
24
24
|
'data-invalid-syntax': 'mathblock',
|
|
25
|
-
'data-invalid-type': delim.length > 2 ? 'syntax' : !closer ? 'fence' : 'argument',
|
|
26
|
-
'data-invalid-message': delim.length > 2 ? 'Invalid syntax' :
|
|
27
|
-
|
|
25
|
+
'data-invalid-type': delim.length > 2 ? 'syntax' : !closer || overflow ? 'fence' : 'argument',
|
|
26
|
+
'data-invalid-message': delim.length > 2 ? 'Invalid syntax' :
|
|
27
|
+
!closer ? `Missing the closing delimiter "${delim}"` :
|
|
28
|
+
overflow ? `Invalid trailing line after the closing delimiter "${delim}"` :
|
|
29
|
+
'Invalid argument',
|
|
30
|
+
}, `${opener}${body}${overflow || closer}`),
|
|
28
31
|
])));
|
|
@@ -21,6 +21,7 @@ describe('Unit: parser/header', () => {
|
|
|
21
21
|
assert.deepStrictEqual(inspect(parser('---\n \n---')), undefined);
|
|
22
22
|
assert.deepStrictEqual(inspect(parser('---\n-\n---')), [['<pre class="invalid" translate="no">---\n-\n---</pre>'], '']);
|
|
23
23
|
assert.deepStrictEqual(inspect(parser('----\na: b\n----')), [['<pre class="invalid" translate="no">----\na: b\n----</pre>'], '']);
|
|
24
|
+
assert.deepStrictEqual(inspect(parser(`---\n${'a: b\n'.repeat(101)}---`)), [[`<pre class="invalid" translate="no">---\n${'a: b\n'.repeat(101)}---</pre>`], '']);
|
|
24
25
|
});
|
|
25
26
|
|
|
26
27
|
it('basic', () => {
|
|
@@ -16,17 +16,33 @@ describe('Unit: parser/inline/bracket', () => {
|
|
|
16
16
|
assert.deepStrictEqual(inspect(parser('(1)')), [['(', '1', ')'], '']);
|
|
17
17
|
assert.deepStrictEqual(inspect(parser('(10)')), [['(', '10', ')'], '']);
|
|
18
18
|
assert.deepStrictEqual(inspect(parser('(2000)')), [['(', '2000', ')'], '']);
|
|
19
|
-
assert.deepStrictEqual(inspect(parser('(1, 2)')), [['(', '1, 2', ')'], '']);
|
|
20
19
|
assert.deepStrictEqual(inspect(parser('(0-1)')), [['(', '0-1', ')'], '']);
|
|
21
20
|
assert.deepStrictEqual(inspect(parser('(0)-1')), [['(', '0', ')'], '-1']);
|
|
22
21
|
assert.deepStrictEqual(inspect(parser('(0.1)')), [['(', '0.1', ')'], '']);
|
|
23
22
|
assert.deepStrictEqual(inspect(parser('(0.1.2)')), [['(', '0.1.2', ')'], '']);
|
|
24
23
|
assert.deepStrictEqual(inspect(parser('(1.1, 1.2-1.3, 1.4)')), [['(', '1.1, 1.2-1.3, 1.4', ')'], '']);
|
|
24
|
+
assert.deepStrictEqual(inspect(parser('(1 2)')), [['<span class="paren">(1 2)</span>'], '']);
|
|
25
|
+
assert.deepStrictEqual(inspect(parser('(1, 2)')), [['(', '1, 2', ')'], '']);
|
|
26
|
+
assert.deepStrictEqual(inspect(parser('(1a)')), [['(', '1a', ')'], '']);
|
|
25
27
|
assert.deepStrictEqual(inspect(parser('(a)')), [['(', 'a', ')'], '']);
|
|
28
|
+
assert.deepStrictEqual(inspect(parser('(a1)')), [['(', 'a1', ')'], '']);
|
|
29
|
+
assert.deepStrictEqual(inspect(parser('(a-1)')), [['(', 'a-1', ')'], '']);
|
|
30
|
+
assert.deepStrictEqual(inspect(parser('(a.1)')), [['(', 'a.1', ')'], '']);
|
|
31
|
+
assert.deepStrictEqual(inspect(parser('(a b)')), [['<span class="paren">(a b)</span>'], '']);
|
|
32
|
+
assert.deepStrictEqual(inspect(parser('(word)')), [['(', 'word', ')'], '']);
|
|
33
|
+
assert.deepStrictEqual(inspect(parser('(word word)')), [['<span class="paren">(word word)</span>'], '']);
|
|
34
|
+
assert.deepStrictEqual(inspect(parser('(word, word)')), [['(', 'word, word', ')'], '']);
|
|
26
35
|
assert.deepStrictEqual(inspect(parser('(A)')), [['(', 'A', ')'], '']);
|
|
36
|
+
assert.deepStrictEqual(inspect(parser('(Name)')), [['(', 'Name', ')'], '']);
|
|
37
|
+
assert.deepStrictEqual(inspect(parser('(Word Word)')), [['<span class="paren">(Word Word)</span>'], '']);
|
|
38
|
+
assert.deepStrictEqual(inspect(parser('(Name, Name)')), [['(', 'Name, Name', ')'], '']);
|
|
39
|
+
assert.deepStrictEqual(inspect(parser('(ABBR)')), [['(', 'ABBR', ')'], '']);
|
|
40
|
+
assert.deepStrictEqual(inspect(parser('(ABBR, ABBR)')), [['(', 'ABBR, ABBR', ')'], '']);
|
|
27
41
|
assert.deepStrictEqual(inspect(parser('(1,2)')), [['(', '1,2', ')'], '']);
|
|
28
42
|
assert.deepStrictEqual(inspect(parser('(0-1)')), [['(', '0-1', ')'], '']);
|
|
29
|
-
assert.deepStrictEqual(inspect(parser('
|
|
43
|
+
assert.deepStrictEqual(inspect(parser('(0.1)')), [['(', '0.1', ')'], '']);
|
|
44
|
+
assert.deepStrictEqual(inspect(parser('(a)')), [['(', 'a', ')'], '']);
|
|
45
|
+
assert.deepStrictEqual(inspect(parser('(A)')), [['(', 'A', ')'], '']);
|
|
30
46
|
});
|
|
31
47
|
|
|
32
48
|
it('[', () => {
|
|
@@ -6,7 +6,7 @@ import { str } from '../source';
|
|
|
6
6
|
import { html, defrag } from 'typed-dom/dom';
|
|
7
7
|
import { unshift, push } from 'spica/array';
|
|
8
8
|
|
|
9
|
-
const index = /^
|
|
9
|
+
const index = /^[0-9A-Za-z]+(?:(?:[.-]|, )[0-9A-Za-z]+)*/;
|
|
10
10
|
|
|
11
11
|
export const bracket: BracketParser = lazy(() => creator(union([
|
|
12
12
|
surround(str('('), str(index), str(')')),
|
|
@@ -93,22 +93,29 @@ describe('Unit: parser/inline/html', () => {
|
|
|
93
93
|
assert.deepStrictEqual(inspect(parser('<small __proto__>a</small>')), undefined);
|
|
94
94
|
assert.deepStrictEqual(inspect(parser('<small constructor>a</small>')), [['<span class="invalid"><small constructor>a</small></span>'], '']);
|
|
95
95
|
assert.deepStrictEqual(inspect(parser('<small toString>a</small>')), undefined);
|
|
96
|
+
assert.deepStrictEqual(inspect(parser('<small X>a</small>')), undefined);
|
|
97
|
+
assert.deepStrictEqual(inspect(parser('<small x>a</small>')), [['<span class="invalid"><small x>a</small></span>'], '']);
|
|
96
98
|
assert.deepStrictEqual(inspect(parser('<bdo>a</bdo>')), [['<span class="invalid"><bdo>a</bdo></span>'], '']);
|
|
97
99
|
assert.deepStrictEqual(inspect(parser('<bdo >a</bdo>')), [['<span class="invalid"><bdo >a</bdo></span>'], '']);
|
|
98
100
|
assert.deepStrictEqual(inspect(parser('<bdo __proto__>a</bdo>')), undefined);
|
|
99
101
|
assert.deepStrictEqual(inspect(parser('<bdo constructor>a</bdo>')), [['<span class="invalid"><bdo constructor>a</bdo></span>'], '']);
|
|
100
102
|
assert.deepStrictEqual(inspect(parser('<bdo toString>a</bdo>')), undefined);
|
|
103
|
+
assert.deepStrictEqual(inspect(parser('<bdo X>a</bdo>')), undefined);
|
|
104
|
+
assert.deepStrictEqual(inspect(parser('<bdo x>a</bdo>')), [['<span class="invalid"><bdo x>a</bdo></span>'], '']);
|
|
101
105
|
assert.deepStrictEqual(inspect(parser('<bdo dir>a</bdo>')), [['<span class="invalid"><bdo dir>a</bdo></span>'], '']);
|
|
102
106
|
assert.deepStrictEqual(inspect(parser('<bdo dir=>a</bdo>')), undefined);
|
|
103
107
|
assert.deepStrictEqual(inspect(parser('<bdo dir=rtl>a</bdo>')), undefined);
|
|
104
108
|
assert.deepStrictEqual(inspect(parser('<bdo dir=">a</bdo>')), undefined);
|
|
105
109
|
assert.deepStrictEqual(inspect(parser('<bdo dir="">a</bdo>')), [['<span class="invalid"><bdo dir="">a</bdo></span>'], '']);
|
|
106
110
|
assert.deepStrictEqual(inspect(parser('<bdo dir="rtl" dir="rtl">a</bdo>')), [['<span class="invalid"><bdo dir="rtl" dir="rtl">a</bdo></span>'], '']);
|
|
111
|
+
assert.deepStrictEqual(inspect(parser('<bdo diR="rtl">a</bdo>')), undefined);
|
|
107
112
|
assert.deepStrictEqual(inspect(parser('<bdo dir="rtl">a</bdo>')), [['<bdo dir="rtl">a</bdo>'], '']);
|
|
108
113
|
assert.deepStrictEqual(inspect(parser('<bdo dir="rtl" >a</bdo>')), [['<bdo dir="rtl">a</bdo>'], '']);
|
|
109
114
|
assert.deepStrictEqual(inspect(parser('<bdo dir="rtl" >a</bdo>')), [['<bdo dir="rtl">a</bdo>'], '']);
|
|
110
115
|
assert.deepStrictEqual(inspect(parser('<bdo dir="rtl">a</bdo>')), [['<bdo dir="rtl">a</bdo>'], '']);
|
|
111
116
|
assert.deepStrictEqual(inspect(parser('<wbr constructor>')), [['<wbr class="invalid">'], '']);
|
|
117
|
+
assert.deepStrictEqual(inspect(parser('<wbr X>')), undefined);
|
|
118
|
+
assert.deepStrictEqual(inspect(parser('<wbr x>')), [['<wbr class="invalid">'], '']);
|
|
112
119
|
});
|
|
113
120
|
|
|
114
121
|
});
|