securemark 0.289.6 → 0.290.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 +4 -0
- package/dist/index.js +57 -283
- package/markdown.d.ts +11 -12
- package/package.json +1 -1
- package/src/parser/api/parse.test.ts +3 -3
- package/src/parser/block/extension/example.test.ts +2 -2
- package/src/parser/block/extension/fig.test.ts +8 -8
- package/src/parser/block/extension/figure.test.ts +14 -14
- package/src/parser/block/paragraph.test.ts +4 -0
- package/src/parser/inline/autolink/url.test.ts +2 -2
- package/src/parser/inline/bracket.test.ts +1 -0
- package/src/parser/inline/html.test.ts +4 -4
- package/src/parser/inline/html.ts +12 -25
- package/src/parser/inline/link.test.ts +17 -17
- package/src/parser/inline/link.ts +18 -6
- package/src/parser/inline/media.test.ts +45 -46
- package/src/parser/inline/media.ts +37 -28
- package/src/parser/inline/shortmedia.test.ts +2 -2
- package/src/parser/inline/template.test.ts +2 -2
- package/src/parser/inline/template.ts +6 -7
- package/src/parser/inline.test.ts +1 -0
- package/src/parser/source/escapable.test.ts +5 -5
- package/src/parser/source/escapable.ts +2 -2
- package/src/parser/source/unescapable.test.ts +5 -5
- package/src/parser/source/unescapable.ts +2 -2
- package/src/renderer/render/media.test.ts +3 -3
|
@@ -50,16 +50,23 @@ export const media: MediaParser = lazy(() => constraint(State.media, false, vali
|
|
|
50
50
|
const INSECURE_URI = params.shift()!;
|
|
51
51
|
assert(INSECURE_URI === INSECURE_URI.trim());
|
|
52
52
|
assert(!INSECURE_URI.match(/\s/));
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
53
|
+
// altが空だとエラーが見えないため埋める。
|
|
54
|
+
text ||= INSECURE_URI;
|
|
55
|
+
let uri: ReadonlyURL | undefined;
|
|
56
|
+
try {
|
|
57
|
+
uri = new ReadonlyURL(
|
|
58
|
+
resolve(INSECURE_URI, context.host ?? location, context.url ?? context.host ?? location),
|
|
59
|
+
context.host?.href || location.href);
|
|
60
|
+
}
|
|
61
|
+
catch {
|
|
62
|
+
}
|
|
56
63
|
let cache: HTMLElement | undefined;
|
|
57
64
|
const el = undefined
|
|
58
|
-
|| (cache = context.caches?.media?.get(
|
|
59
|
-
|| html('img', { class: 'media', 'data-src':
|
|
65
|
+
|| uri && (cache = context.caches?.media?.get(uri.href)?.cloneNode(true))
|
|
66
|
+
|| html('img', { class: 'media', 'data-src': uri?.source });
|
|
60
67
|
assert(!el.matches('.invalid'));
|
|
61
|
-
|
|
62
|
-
if (!sanitize(el,
|
|
68
|
+
el.setAttribute('alt', text);
|
|
69
|
+
if (!sanitize(el, uri, text)) return [[el], rest];
|
|
63
70
|
assert(!el.matches('.invalid'));
|
|
64
71
|
define(el, attributes('media', push([], el.classList), optspec, params));
|
|
65
72
|
assert(el.matches('img') || !el.matches('.invalid'));
|
|
@@ -97,34 +104,36 @@ const option: MediaParser.ParameterParser.OptionParser = lazy(() => union([
|
|
|
97
104
|
linkoption,
|
|
98
105
|
]));
|
|
99
106
|
|
|
100
|
-
function sanitize(target: HTMLElement, uri: ReadonlyURL, alt: string): boolean {
|
|
107
|
+
function sanitize(target: HTMLElement, uri: ReadonlyURL | undefined, alt: string): boolean {
|
|
101
108
|
assert(target.tagName === 'IMG');
|
|
102
109
|
assert(!target.matches('.invalid'));
|
|
103
|
-
|
|
110
|
+
let type: string;
|
|
111
|
+
let message: string;
|
|
112
|
+
if (!alt.includes(Command.Error)) switch (uri?.protocol) {
|
|
113
|
+
case undefined:
|
|
114
|
+
type = 'argument';
|
|
115
|
+
message = 'Invalid URI';
|
|
116
|
+
break;
|
|
104
117
|
case 'http:':
|
|
105
118
|
case 'https:':
|
|
106
119
|
assert(uri.host);
|
|
107
|
-
if (
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
...invalid('media', 'argument',
|
|
111
|
-
'Dot-segments cannot be used in media paths; use subresource paths instead')
|
|
112
|
-
});
|
|
113
|
-
return false;
|
|
114
|
-
}
|
|
120
|
+
if (!/\/\.\.?(?:\/|$)/.test('/' + uri.source.slice(0, uri.source.search(/[?#]|$/)))) return true;
|
|
121
|
+
type = 'argument';
|
|
122
|
+
message = 'Dot-segments cannot be used in media paths; use subresource paths instead';
|
|
115
123
|
break;
|
|
116
124
|
default:
|
|
117
|
-
|
|
118
|
-
|
|
125
|
+
type = 'argument';
|
|
126
|
+
message = 'Invalid protocol';
|
|
119
127
|
}
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
...invalid('media', 'argument',
|
|
125
|
-
`Cannot use invalid HTML entitiy "${alt.match(/&[0-9A-Za-z]+;/)![0]}"`)
|
|
126
|
-
});
|
|
127
|
-
return false;
|
|
128
|
+
else {
|
|
129
|
+
target.setAttribute('alt', alt.replace(CmdRegExp.Error, ''));
|
|
130
|
+
type = 'argument';
|
|
131
|
+
message = `Invalid HTML entitiy "${alt.match(/&[0-9A-Za-z]+;/)![0]}"`;
|
|
128
132
|
}
|
|
129
|
-
|
|
133
|
+
define(target, {
|
|
134
|
+
'data-src': null,
|
|
135
|
+
class: 'invalid',
|
|
136
|
+
...invalid('link', type, message),
|
|
137
|
+
});
|
|
138
|
+
return false;
|
|
130
139
|
}
|
|
@@ -16,8 +16,8 @@ describe('Unit: parser/inline/shortmedia', () => {
|
|
|
16
16
|
});
|
|
17
17
|
|
|
18
18
|
it('basic', () => {
|
|
19
|
-
assert.deepStrictEqual(inspect(parser('!http://host')), [['<a href="http://host" target="_blank"><img class="media" data-src="http://host" alt=""></a>'], '']);
|
|
20
|
-
assert.deepStrictEqual(inspect(parser('!https://host')), [['<a href="https://host" target="_blank"><img class="media" data-src="https://host" alt=""></a>'], '']);
|
|
19
|
+
assert.deepStrictEqual(inspect(parser('!http://host')), [['<a href="http://host" target="_blank"><img class="media" data-src="http://host" alt="http://host"></a>'], '']);
|
|
20
|
+
assert.deepStrictEqual(inspect(parser('!https://host')), [['<a href="https://host" target="_blank"><img class="media" data-src="https://host" alt="https://host"></a>'], '']);
|
|
21
21
|
});
|
|
22
22
|
|
|
23
23
|
});
|
|
@@ -12,8 +12,6 @@ describe('Unit: parser/inline/template', () => {
|
|
|
12
12
|
assert.deepStrictEqual(inspect(parser('{}')), undefined);
|
|
13
13
|
assert.deepStrictEqual(inspect(parser('{{')), undefined);
|
|
14
14
|
assert.deepStrictEqual(inspect(parser('{{\\}}')), undefined);
|
|
15
|
-
assert.deepStrictEqual(inspect(parser('{{\n}}')), undefined);
|
|
16
|
-
assert.deepStrictEqual(inspect(parser('{{\\\n}}')), undefined);
|
|
17
15
|
assert.deepStrictEqual(inspect(parser('{{a}b}')), undefined);
|
|
18
16
|
assert.deepStrictEqual(inspect(parser('{{{a}}')), undefined);
|
|
19
17
|
assert.deepStrictEqual(inspect(parser(' {{}}')), undefined);
|
|
@@ -24,6 +22,8 @@ describe('Unit: parser/inline/template', () => {
|
|
|
24
22
|
assert.deepStrictEqual(inspect(parser('{{}}}')), [['<span class="template">{{}}</span>'], '}']);
|
|
25
23
|
assert.deepStrictEqual(inspect(parser('{{ }}')), [['<span class="template">{{ }}</span>'], '']);
|
|
26
24
|
assert.deepStrictEqual(inspect(parser('{{ a }}')), [['<span class="template">{{ a }}</span>'], '']);
|
|
25
|
+
assert.deepStrictEqual(inspect(parser('{{\n}}')), [['<span class="template">{{<br>}}</span>'], '']);
|
|
26
|
+
assert.deepStrictEqual(inspect(parser('{{\\\n}}')), [['<span class="template">{{\\<br>}}</span>'], '']);
|
|
27
27
|
assert.deepStrictEqual(inspect(parser('{{a}}')), [['<span class="template">{{a}}</span>'], '']);
|
|
28
28
|
assert.deepStrictEqual(inspect(parser('{{a b}}')), [['<span class="template">{{a b}}</span>'], '']);
|
|
29
29
|
assert.deepStrictEqual(inspect(parser('{{\\}}}')), [['<span class="template">{{\\}}}</span>'], '']);
|
|
@@ -2,18 +2,17 @@ import { TemplateParser } from '../inline';
|
|
|
2
2
|
import { Recursion, Backtrack } from '../context';
|
|
3
3
|
import { union, some, recursion, precedence, surround, lazy } from '../../combinator';
|
|
4
4
|
import { escsource, str } from '../source';
|
|
5
|
-
import {
|
|
5
|
+
import { unshift, push } from 'spica/array';
|
|
6
|
+
import { html, defrag } from 'typed-dom/dom';
|
|
6
7
|
|
|
7
8
|
export const template: TemplateParser = lazy(() => surround(
|
|
8
|
-
'{{',
|
|
9
|
+
str('{{'),
|
|
9
10
|
precedence(1,
|
|
10
11
|
some(union([bracket, escsource]), '}')),
|
|
11
|
-
'}}',
|
|
12
|
+
str('}}'),
|
|
12
13
|
true,
|
|
13
|
-
([,
|
|
14
|
-
|
|
15
|
-
? [[html('span', { class: 'template' }, `{{${ns.join('')}}}`)], rest]
|
|
16
|
-
: undefined,
|
|
14
|
+
([as, bs = [], cs], rest) =>
|
|
15
|
+
[[html('span', { class: 'template' }, defrag(push(unshift(as, bs), cs)))], rest],
|
|
17
16
|
undefined,
|
|
18
17
|
[3 | Backtrack.doublebracket, 1 | Backtrack.bracket]));
|
|
19
18
|
|
|
@@ -139,6 +139,7 @@ describe('Unit: parser/inline', () => {
|
|
|
139
139
|
assert.deepStrictEqual(inspect(parser('(([[a] ]))')), [['<sup class="annotation"><span>[[a] ]</span></sup>'], '']);
|
|
140
140
|
assert.deepStrictEqual(inspect(parser('(([["*(*"] ]))')), [['<sup class="annotation"><span>[["*(*"] ]</span></sup>'], '']);
|
|
141
141
|
assert.deepStrictEqual(inspect(parser('(([:a\n]')), [['(', '(', '<span class="invalid">a<br></span>'], '']);
|
|
142
|
+
assert.deepStrictEqual(inspect(parser('(({{\n}}')), [['(', '(', '<span class="template">{{<br>}}</span>'], '']);
|
|
142
143
|
assert.deepStrictEqual(inspect(parser('"((""))')), [['"', '(', '(', '"', '"', ')', ')'], '']);
|
|
143
144
|
assert.deepStrictEqual(inspect(parser('[[[a]]')), [['[', '<sup class="reference"><span>a</span></sup>'], '']);
|
|
144
145
|
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
|
-
|
|
24
|
-
|
|
25
|
-
|
|
23
|
+
assert.deepStrictEqual(inspect(parser(' \n')), [[' ', '<br>'], '']);
|
|
24
|
+
assert.deepStrictEqual(inspect(parser(' \n')), [[' ', ' ', '<br>'], '']);
|
|
25
|
+
assert.deepStrictEqual(inspect(parser(' \n')), [[' ', ' ', '<br>'], '']);
|
|
26
26
|
});
|
|
27
27
|
|
|
28
28
|
it('linebreak', () => {
|
|
29
|
-
|
|
29
|
+
assert.deepStrictEqual(inspect(parser('\n\n')), [['<br>', '<br>'], '']);
|
|
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
|
-
|
|
42
|
+
assert.deepStrictEqual(inspect(parser('\\\n')), [['\\', '<br>'], '']);
|
|
43
43
|
});
|
|
44
44
|
|
|
45
45
|
});
|
|
@@ -2,6 +2,7 @@ import { EscapableSourceParser } from '../source';
|
|
|
2
2
|
import { Command } from '../context';
|
|
3
3
|
import { consume } from '../../combinator';
|
|
4
4
|
import { nonWhitespace } from './text';
|
|
5
|
+
import { html } from 'typed-dom/dom';
|
|
5
6
|
|
|
6
7
|
const delimiter = /[\s\x00-\x2F\x3A-\x40\x5B-\x60\x7B-\x7F]/;
|
|
7
8
|
|
|
@@ -20,7 +21,6 @@ export const escsource: EscapableSourceParser = ({ source, context }) => {
|
|
|
20
21
|
consume(-1, context);
|
|
21
22
|
return [[], source.slice(1)];
|
|
22
23
|
case Command.Escape:
|
|
23
|
-
assert(false);
|
|
24
24
|
consume(1, context);
|
|
25
25
|
return [[source.slice(1, 2)], source.slice(2)];
|
|
26
26
|
case '\\':
|
|
@@ -35,7 +35,7 @@ export const escsource: EscapableSourceParser = ({ source, context }) => {
|
|
|
35
35
|
}
|
|
36
36
|
case '\n':
|
|
37
37
|
context.linebreak ??= source.length;
|
|
38
|
-
return [[
|
|
38
|
+
return [[html('br')], source.slice(1)];
|
|
39
39
|
default:
|
|
40
40
|
assert(source[0] !== '\n');
|
|
41
41
|
const b = source[0].trimStart() === '';
|
|
@@ -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
|
-
|
|
24
|
-
|
|
25
|
-
|
|
23
|
+
assert.deepStrictEqual(inspect(parser(' \n')), [[' ', '<br>'], '']);
|
|
24
|
+
assert.deepStrictEqual(inspect(parser(' \n')), [[' ', ' ', '<br>'], '']);
|
|
25
|
+
assert.deepStrictEqual(inspect(parser(' \n')), [[' ', ' ', '<br>'], '']);
|
|
26
26
|
});
|
|
27
27
|
|
|
28
28
|
it('linebreak', () => {
|
|
29
|
-
|
|
29
|
+
assert.deepStrictEqual(inspect(parser('\n\n')), [['<br>', '<br>'], '']);
|
|
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
|
-
|
|
42
|
+
assert.deepStrictEqual(inspect(parser('\\\n')), [['\\', '<br>'], '']);
|
|
43
43
|
});
|
|
44
44
|
|
|
45
45
|
});
|
|
@@ -2,6 +2,7 @@ import { UnescapableSourceParser } from '../source';
|
|
|
2
2
|
import { Command } from '../context';
|
|
3
3
|
import { consume } from '../../combinator';
|
|
4
4
|
import { delimiter, nonWhitespace, nonAlphanumeric, isAlphanumeric } from './text';
|
|
5
|
+
import { html } from 'typed-dom/dom';
|
|
5
6
|
|
|
6
7
|
export const unescsource: UnescapableSourceParser = ({ source, context }) => {
|
|
7
8
|
if (source === '') return;
|
|
@@ -18,12 +19,11 @@ export const unescsource: UnescapableSourceParser = ({ source, context }) => {
|
|
|
18
19
|
consume(-1, context);
|
|
19
20
|
return [[], source.slice(1)];
|
|
20
21
|
case Command.Escape:
|
|
21
|
-
assert(false);
|
|
22
22
|
consume(1, context);
|
|
23
23
|
return [[source.slice(1, 2)], source.slice(2)];
|
|
24
24
|
case '\n':
|
|
25
25
|
context.linebreak ??= source.length;
|
|
26
|
-
return [[
|
|
26
|
+
return [[html('br')], source.slice(1)];
|
|
27
27
|
default:
|
|
28
28
|
assert(source[0] !== '\n');
|
|
29
29
|
const b = source[0].trimStart() === '';
|
|
@@ -39,9 +39,9 @@ describe('Unit: renderer/render/media', () => {
|
|
|
39
39
|
});
|
|
40
40
|
|
|
41
41
|
it('image', () => {
|
|
42
|
-
assert(media(location.href, parse('!{/ 4x3}').querySelector('img')!, {}, caches.media)!.matches(`[src="/"][alt=""][width="4"][height="3"]:not([aspect-ratio])`));
|
|
43
|
-
assert(media(location.href, parse('!{/ 4:3}').querySelector('img')!, {}, caches.media)!.matches(`[src="/"][alt=""][aspect-ratio="4/3"]:not([width]):not([height])`));
|
|
44
|
-
assert(media(location.href, parse('!{/ 4x3}').querySelector('img')!, {}, caches.media)!.matches(`[src="/"][alt=""][width="4"][height="3"]:not([aspect-ratio])`));
|
|
42
|
+
assert(media(location.href, parse('!{/ 4x3}').querySelector('img')!, {}, caches.media)!.matches(`[src="/"][alt="/"][width="4"][height="3"]:not([aspect-ratio])`));
|
|
43
|
+
assert(media(location.href, parse('!{/ 4:3}').querySelector('img')!, {}, caches.media)!.matches(`[src="/"][alt="/"][aspect-ratio="4/3"]:not([width]):not([height])`));
|
|
44
|
+
assert(media(location.href, parse('!{/ 4x3}').querySelector('img')!, {}, caches.media)!.matches(`[src="/"][alt="/"][width="4"][height="3"]:not([aspect-ratio])`));
|
|
45
45
|
});
|
|
46
46
|
|
|
47
47
|
});
|