securemark 0.243.0 → 0.244.0
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/dist/securemark.js +128 -105
- package/markdown.d.ts +0 -1
- package/package-lock.json +10 -10
- package/package.json +1 -1
- 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 +10 -6
- package/src/parser/block/extension/fig.test.ts +2 -0
- package/src/parser/block/extension/fig.ts +1 -1
- package/src/parser/block/extension/figure.test.ts +22 -21
- package/src/parser/block/extension/figure.ts +60 -39
- package/src/parser/block/extension/message.ts +9 -5
- package/src/parser/block/extension/placeholder.ts +6 -11
- 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/block/table.ts +2 -2
- 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
|
@@ -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
|
])));
|
|
@@ -29,9 +29,9 @@ const row = <P extends CellParser | AlignParser>(parser: P, optional: boolean):
|
|
|
29
29
|
rewrite(contentline, source => [[
|
|
30
30
|
html('tr', {
|
|
31
31
|
class: 'invalid',
|
|
32
|
-
'data-invalid-syntax': '
|
|
32
|
+
'data-invalid-syntax': 'table-row',
|
|
33
33
|
'data-invalid-type': 'syntax',
|
|
34
|
-
'data-invalid-message': '
|
|
34
|
+
'data-invalid-message': 'Missing the start symbol of the table row',
|
|
35
35
|
}, [html('td', source.replace('\n', ''))])
|
|
36
36
|
], ''])));
|
|
37
37
|
|
|
@@ -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
|
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { undefined } from 'spica/global';
|
|
2
|
-
import { isFrozen, ObjectEntries
|
|
2
|
+
import { isFrozen, ObjectEntries } from 'spica/alias';
|
|
3
3
|
import { MarkdownParser } from '../../../markdown';
|
|
4
4
|
import { HTMLParser } from '../inline';
|
|
5
5
|
import { union, some, validate, context, creator, surround, open, match, lazy } from '../../combinator';
|
|
@@ -11,14 +11,14 @@ import { memoize } from 'spica/memoize';
|
|
|
11
11
|
import { Cache } from 'spica/cache';
|
|
12
12
|
import { unshift, push, splice, join } from 'spica/array';
|
|
13
13
|
|
|
14
|
-
const tags =
|
|
14
|
+
const tags = Object.freeze(['wbr', 'sup', 'sub', 'small', 'bdo', 'bdi']);
|
|
15
15
|
const attrspec = {
|
|
16
16
|
bdo: {
|
|
17
|
-
dir:
|
|
17
|
+
dir: Object.freeze(['ltr', 'rtl'] as const),
|
|
18
18
|
},
|
|
19
19
|
} as const;
|
|
20
|
-
|
|
21
|
-
|
|
20
|
+
Object.setPrototypeOf(attrspec, null);
|
|
21
|
+
Object.values(attrspec).forEach(o => Object.setPrototypeOf(o, null));
|
|
22
22
|
|
|
23
23
|
export const html: HTMLParser = lazy(() => creator(validate('<', validate(/^<[a-z]+(?=[^\S\n]|>)/, union([
|
|
24
24
|
match(
|
|
@@ -29,7 +29,7 @@ export const html: HTMLParser = lazy(() => creator(validate('<', validate(/^<[a-
|
|
|
29
29
|
`<${tag}`, some(union([attribute])), /^\s*>/, true,
|
|
30
30
|
([, bs = []], rest) =>
|
|
31
31
|
[[h(tag as 'span', attributes('html', [], attrspec[tag], bs))], rest]),
|
|
32
|
-
([, tag]) => tag)),
|
|
32
|
+
([, tag]) => tags.indexOf(tag), [])),
|
|
33
33
|
match(
|
|
34
34
|
/^(?=<(sup|sub|small)(?=[^\S\n]|>))/,
|
|
35
35
|
memoize(
|
|
@@ -69,7 +69,7 @@ export const html: HTMLParser = lazy(() => creator(validate('<', validate(/^<[a-
|
|
|
69
69
|
str(`</${tag}>`), false,
|
|
70
70
|
([as, bs, cs], rest, context) =>
|
|
71
71
|
[[elem(tag, as, defrag(bs), cs, context)], rest])),
|
|
72
|
-
|
|
72
|
+
([, tag]) => tags.indexOf(tag), [])),
|
|
73
73
|
match(
|
|
74
74
|
/^(?=<(bdo|bdi)(?=[^\S\n]|>))/,
|
|
75
75
|
memoize(
|
|
@@ -82,11 +82,11 @@ export const html: HTMLParser = lazy(() => creator(validate('<', validate(/^<[a-
|
|
|
82
82
|
open(/^\n?/, some(inline, '</'), true),
|
|
83
83
|
]), `</${tag}>`), `</${tag}>`),
|
|
84
84
|
str(`</${tag}>`), false,
|
|
85
|
-
([as, bs, cs], rest) =>
|
|
86
|
-
[[elem(tag, as, defrag(bs), cs,
|
|
85
|
+
([as, bs, cs], rest, context) =>
|
|
86
|
+
[[elem(tag, as, defrag(bs), cs, context)], rest],
|
|
87
87
|
([as, bs], rest) =>
|
|
88
88
|
as.length === 1 ? [unshift(as, bs), rest] : undefined)),
|
|
89
|
-
([, tag]) => tag)),
|
|
89
|
+
([, tag]) => tags.indexOf(tag), [])),
|
|
90
90
|
match(
|
|
91
91
|
/^(?=<([a-z]+)(?=[^\S\n]|>))/,
|
|
92
92
|
memoize(
|
|
@@ -99,12 +99,12 @@ export const html: HTMLParser = lazy(() => creator(validate('<', validate(/^<[a-
|
|
|
99
99
|
open(/^\n?/, some(inline, '</'), true),
|
|
100
100
|
]), `</${tag}>`), `</${tag}>`),
|
|
101
101
|
str(`</${tag}>`), false,
|
|
102
|
-
([as, bs, cs], rest) =>
|
|
103
|
-
[[elem(tag, as, defrag(bs), cs,
|
|
102
|
+
([as, bs, cs], rest, context) =>
|
|
103
|
+
[[elem(tag, as, defrag(bs), cs, context)], rest],
|
|
104
104
|
([as, bs], rest) =>
|
|
105
105
|
as.length === 1 ? [unshift(as, bs), rest] : undefined)),
|
|
106
106
|
([, tag]) => tag,
|
|
107
|
-
new Cache(
|
|
107
|
+
new Cache(10000))),
|
|
108
108
|
])))));
|
|
109
109
|
|
|
110
110
|
export const attribute: HTMLParser.TagParser.AttributeParser = union([
|
|
@@ -133,12 +133,11 @@ function elem(tag: string, as: string[], bs: (HTMLElement | string)[], cs: strin
|
|
|
133
133
|
}
|
|
134
134
|
break;
|
|
135
135
|
}
|
|
136
|
-
|
|
136
|
+
const attrs = attributes('html', [], attrspec[tag], as.slice(1, -1));
|
|
137
137
|
switch (true) {
|
|
138
|
-
case 'data-invalid-syntax' in
|
|
138
|
+
case 'data-invalid-syntax' in attrs:
|
|
139
139
|
return invalid('attribute', 'Invalid HTML attribute', as, bs, cs);
|
|
140
140
|
default:
|
|
141
|
-
assert(attrs);
|
|
142
141
|
return h(tag as 'span', attrs, bs);
|
|
143
142
|
}
|
|
144
143
|
}
|
|
@@ -158,7 +157,7 @@ const requiredAttributes = memoize(
|
|
|
158
157
|
|
|
159
158
|
export function attributes(
|
|
160
159
|
syntax: string,
|
|
161
|
-
classes: string[],
|
|
160
|
+
classes: readonly string[],
|
|
162
161
|
spec: Readonly<Record<string, readonly (string | undefined)[] | undefined>> | undefined,
|
|
163
162
|
params: string[],
|
|
164
163
|
): Record<string, string | undefined> {
|
|
@@ -183,8 +182,7 @@ export function attributes(
|
|
|
183
182
|
}
|
|
184
183
|
invalid ||= !!spec && !requiredAttributes(spec).every(name => name in attrs);
|
|
185
184
|
if (invalid) {
|
|
186
|
-
|
|
187
|
-
attrs['class'] = join(classes, ' ');
|
|
185
|
+
attrs['class'] = join(classes.includes('invalid') ? classes : unshift(classes, ['invalid']), ' ');
|
|
188
186
|
attrs['data-invalid-syntax'] = syntax;
|
|
189
187
|
attrs['data-invalid-type'] = 'argument';
|
|
190
188
|
attrs['data-invalid-message'] = 'Invalid argument';
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import { location, encodeURI, decodeURI, Location } from 'spica/global';
|
|
2
|
-
import { ObjectSetPrototypeOf } from 'spica/alias';
|
|
1
|
+
import { undefined, location, encodeURI, decodeURI, Location } from 'spica/global';
|
|
3
2
|
import { LinkParser } from '../inline';
|
|
4
3
|
import { eval } from '../../combinator/data/parser';
|
|
5
4
|
import { union, inits, tails, some, validate, guard, context, creator, surround, open, dup, reverse, lazy, fmap, bind } from '../../combinator';
|
|
@@ -14,7 +13,7 @@ import { ReadonlyURL } from 'spica/url';
|
|
|
14
13
|
const optspec = {
|
|
15
14
|
rel: ['nofollow'],
|
|
16
15
|
} as const;
|
|
17
|
-
|
|
16
|
+
Object.setPrototypeOf(optspec, null);
|
|
18
17
|
|
|
19
18
|
export const link: LinkParser = lazy(() => creator(10, validate(['[', '{'], '}', '\n', bind(
|
|
20
19
|
guard(context => context.syntax?.inline?.link ?? true,
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { undefined, location } from 'spica/global';
|
|
2
|
-
import { ObjectSetPrototypeOf } from 'spica/alias';
|
|
3
2
|
import { MediaParser } from '../inline';
|
|
4
3
|
import { union, inits, tails, some, validate, verify, guard, creator, surround, open, dup, lazy, fmap, bind } from '../../combinator';
|
|
5
4
|
import { link, uri, option as linkoption, resolve } from './link';
|
|
@@ -16,7 +15,7 @@ const optspec = {
|
|
|
16
15
|
'aspect-ratio': [],
|
|
17
16
|
rel: undefined,
|
|
18
17
|
} as const;
|
|
19
|
-
|
|
18
|
+
Object.setPrototypeOf(optspec, null);
|
|
20
19
|
|
|
21
20
|
export const media: MediaParser = lazy(() => creator(10, validate(['![', '!{'], '}', '\n', bind(verify(fmap(open(
|
|
22
21
|
'!',
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { define } from 'typed-dom/dom';
|
|
2
|
-
import { Collection } from 'spica/collection';
|
|
3
1
|
import { ObjectFromEntries } from 'spica/alias';
|
|
2
|
+
import { Collection } from 'spica/collection';
|
|
3
|
+
import { define } from 'typed-dom/dom';
|
|
4
4
|
|
|
5
5
|
export function image(source: HTMLImageElement, url: URL, cache?: Collection<string, HTMLElement>): HTMLImageElement {
|
|
6
6
|
if (cache?.has(url.href)) return define(
|