securemark 0.221.0 → 0.224.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 +16 -0
- package/dist/securemark.js +187 -174
- package/package-lock.json +411 -894
- package/package.json +13 -13
- package/src/parser/api/parse.test.ts +0 -8
- package/src/parser/block/paragraph/mention/cite.ts +3 -3
- package/src/parser/inline/annotation.test.ts +2 -2
- package/src/parser/inline/annotation.ts +4 -4
- package/src/parser/inline/emphasis.ts +2 -2
- package/src/parser/inline/emstrong.ts +4 -4
- package/src/parser/inline/extension/index.ts +2 -2
- package/src/parser/inline/html.test.ts +13 -13
- package/src/parser/inline/html.ts +6 -6
- package/src/parser/inline/link.test.ts +46 -25
- package/src/parser/inline/link.ts +23 -25
- package/src/parser/inline/mark.ts +2 -2
- package/src/parser/inline/math.ts +2 -2
- package/src/parser/inline/media.test.ts +27 -16
- package/src/parser/inline/media.ts +33 -22
- package/src/parser/inline/reference.test.ts +2 -2
- package/src/parser/inline/reference.ts +6 -6
- package/src/parser/inline/ruby.ts +2 -2
- package/src/parser/inline/strong.ts +2 -2
- package/src/parser/util.ts +49 -10
- package/src/renderer/render/math.ts +1 -1
- package/src/renderer/render.ts +1 -2
- package/tsconfig.json +6 -0
|
@@ -29,26 +29,34 @@ describe('Unit: parser/inline/media', () => {
|
|
|
29
29
|
assert.deepStrictEqual(inspect(parser('![]{ }')), undefined);
|
|
30
30
|
assert.deepStrictEqual(inspect(parser('![]]{/}')), undefined);
|
|
31
31
|
assert.deepStrictEqual(inspect(parser('![]{{}')), undefined);
|
|
32
|
-
assert.deepStrictEqual(inspect(parser('![]{{
|
|
33
|
-
assert.deepStrictEqual(inspect(parser('![]{
|
|
34
|
-
assert.deepStrictEqual(inspect(parser('![]{a\\\
|
|
35
|
-
assert.deepStrictEqual(inspect(parser('![]{
|
|
36
|
-
assert.deepStrictEqual(inspect(parser('![]{
|
|
37
|
-
assert.deepStrictEqual(inspect(parser('![ ]{
|
|
38
|
-
assert.deepStrictEqual(inspect(parser('![
|
|
39
|
-
assert.deepStrictEqual(inspect(parser('![
|
|
40
|
-
assert.deepStrictEqual(inspect(parser('![
|
|
32
|
+
assert.deepStrictEqual(inspect(parser('![]{{b}}')), undefined);
|
|
33
|
+
assert.deepStrictEqual(inspect(parser('![]{b\nc}')), undefined);
|
|
34
|
+
assert.deepStrictEqual(inspect(parser('![]{a\\\nc}')), undefined);
|
|
35
|
+
assert.deepStrictEqual(inspect(parser('![]{ b}')), undefined);
|
|
36
|
+
assert.deepStrictEqual(inspect(parser('![]{ b\n}')), undefined);
|
|
37
|
+
assert.deepStrictEqual(inspect(parser('![ ]{}')), undefined);
|
|
38
|
+
assert.deepStrictEqual(inspect(parser('![ ]{b}')), undefined);
|
|
39
|
+
assert.deepStrictEqual(inspect(parser('![ ]{b}')), undefined);
|
|
40
|
+
assert.deepStrictEqual(inspect(parser('![\n]{b}')), undefined);
|
|
41
|
+
assert.deepStrictEqual(inspect(parser('![\\ ]{b}')), undefined);
|
|
42
|
+
assert.deepStrictEqual(inspect(parser('![\\\n]{b}')), undefined);
|
|
43
|
+
assert.deepStrictEqual(inspect(parser('![	]{b}')), undefined);
|
|
44
|
+
assert.deepStrictEqual(inspect(parser('![[]{b}')), undefined);
|
|
45
|
+
assert.deepStrictEqual(inspect(parser('![]]{b}')), undefined);
|
|
41
46
|
assert.deepStrictEqual(inspect(parser('![a]{}')), undefined);
|
|
42
|
-
assert.deepStrictEqual(inspect(parser('![ a]{
|
|
43
|
-
assert.deepStrictEqual(inspect(parser('![ a ]{
|
|
44
|
-
assert.deepStrictEqual(inspect(parser('![
|
|
45
|
-
assert.deepStrictEqual(inspect(parser('![a
|
|
46
|
-
assert.deepStrictEqual(inspect(parser('![a\\\nb]{#}')), undefined);
|
|
47
|
+
assert.deepStrictEqual(inspect(parser('![\\ a ]{b}')), undefined);
|
|
48
|
+
assert.deepStrictEqual(inspect(parser('![ \\ a ]{b}')), undefined);
|
|
49
|
+
assert.deepStrictEqual(inspect(parser('![a\nb]{b}')), undefined);
|
|
50
|
+
assert.deepStrictEqual(inspect(parser('![a\\\nb]{b}')), undefined);
|
|
47
51
|
assert.deepStrictEqual(inspect(parser('![]{ttp://host}')), [['<img class="media invalid" data-src="ttp://host" alt="">'], '']);
|
|
48
52
|
assert.deepStrictEqual(inspect(parser('![]{tel:1234567890}')), [['<img class="media invalid" data-src="tel:1234567890" alt="">'], '']);
|
|
49
53
|
//assert.deepStrictEqual(inspect(parser('![]{http://[::ffff:0:0%1]}')), [['<img class="media invalid" alt="">'], '']);
|
|
50
54
|
//assert.deepStrictEqual(inspect(parser('![]{http://[::ffff:0:0/96]}')), [['<img class="media invalid" alt="">'], '']);
|
|
51
|
-
assert.deepStrictEqual(inspect(parser('
|
|
55
|
+
assert.deepStrictEqual(inspect(parser('![]{.}')), [['<img class="media invalid" data-src="." alt="">'], '']);
|
|
56
|
+
assert.deepStrictEqual(inspect(parser('![]{..}')), [['<img class="media invalid" data-src=".." alt="">'], '']);
|
|
57
|
+
assert.deepStrictEqual(inspect(parser('![]{../}')), [['<img class="media invalid" data-src="../" alt="">'], '']);
|
|
58
|
+
assert.deepStrictEqual(inspect(parser('![]{/../b}')), [['<img class="media invalid" data-src="/../b" alt="">'], '']);
|
|
59
|
+
assert.deepStrictEqual(inspect(parser(' ![]{b}')), undefined);
|
|
52
60
|
assert.deepStrictEqual(inspect(parser('[]{/}')), undefined);
|
|
53
61
|
});
|
|
54
62
|
|
|
@@ -61,8 +69,11 @@ describe('Unit: parser/inline/media', () => {
|
|
|
61
69
|
assert.deepStrictEqual(inspect(parser('![]{\\}')), [['<a href="\\" target="_blank"><img class="media" data-src="\\" alt=""></a>'], '']);
|
|
62
70
|
assert.deepStrictEqual(inspect(parser('![]{\\ }')), [['<a href="\\" target="_blank"><img class="media" data-src="\\" alt=""></a>'], '']);
|
|
63
71
|
assert.deepStrictEqual(inspect(parser('![]{\\b}')), [['<a href="\\b" target="_blank"><img class="media" data-src="\\b" alt=""></a>'], '']);
|
|
64
|
-
assert.deepStrictEqual(inspect(parser('![]{
|
|
72
|
+
assert.deepStrictEqual(inspect(parser('![]{?/../}')), [[`<a href="?/../" target="_blank"><img class="media" data-src="?/../" alt=""></a>`], '']);
|
|
73
|
+
assert.deepStrictEqual(inspect(parser('![]{#/../}')), [[`<a href="#/../" target="_blank"><img class="media" data-src="#/../" alt=""></a>`], '']);
|
|
65
74
|
assert.deepStrictEqual(inspect(parser('![]{^/b}')), [[`<a href="/b" target="_blank"><img class="media" data-src="/b" alt=""></a>`], '']);
|
|
75
|
+
assert.deepStrictEqual(inspect(parser('![ a]{b}')), [['<a href="b" target="_blank"><img class="media" data-src="b" alt="a"></a>'], '']);
|
|
76
|
+
assert.deepStrictEqual(inspect(parser('![ a ]{b}')), [['<a href="b" target="_blank"><img class="media" data-src="b" alt="a"></a>'], '']);
|
|
66
77
|
assert.deepStrictEqual(inspect(parser('![a ]{b}')), [['<a href="b" target="_blank"><img class="media" data-src="b" alt="a"></a>'], '']);
|
|
67
78
|
assert.deepStrictEqual(inspect(parser('![a ]{b}')), [['<a href="b" target="_blank"><img class="media" data-src="b" alt="a"></a>'], '']);
|
|
68
79
|
assert.deepStrictEqual(inspect(parser('![a b]{c}')), [['<a href="c" target="_blank"><img class="media" data-src="c" alt="a b"></a>'], '']);
|
|
@@ -6,7 +6,6 @@ import { link, uri, option as linkoption, resolve } from './link';
|
|
|
6
6
|
import { attributes } from './html';
|
|
7
7
|
import { htmlentity } from './htmlentity';
|
|
8
8
|
import { txt, str } from '../source';
|
|
9
|
-
import { verifyStartTight } from '../util';
|
|
10
9
|
import { html, define } from 'typed-dom';
|
|
11
10
|
import { ReadonlyURL } from 'spica/url';
|
|
12
11
|
import { unshift, push, join } from 'spica/array';
|
|
@@ -24,28 +23,29 @@ export const media: MediaParser = lazy(() => creator(10, bind(verify(fmap(open(
|
|
|
24
23
|
validate(['[', '{'], '}', '\n',
|
|
25
24
|
guard(context => context.syntax?.inline?.media ?? true,
|
|
26
25
|
tails([
|
|
27
|
-
dup(surround(/^\[(
|
|
26
|
+
dup(surround(/^\[(?!\s*\\\s)/, some(union([htmlentity, bracket, txt]), ']', /^\\?\n/), ']', true)),
|
|
28
27
|
dup(surround(/^{(?![{}])/, inits([uri, some(option)]), /^[^\S\n]?}/)),
|
|
29
28
|
])))),
|
|
30
|
-
([as, bs]) => bs ? [[join(as)], bs] : [[''], as]),
|
|
31
|
-
([[text]]) =>
|
|
29
|
+
([as, bs]) => bs ? [[join(as).trim() || join(as)], bs] : [[''], as]),
|
|
30
|
+
([[text]]) => text === '' || text.trim() !== ''),
|
|
32
31
|
([[text], params], rest, context) => {
|
|
33
32
|
const INSECURE_URI = params.shift()!;
|
|
34
33
|
assert(INSECURE_URI === INSECURE_URI.trim());
|
|
35
34
|
assert(!INSECURE_URI.match(/\s/));
|
|
36
35
|
const url = new ReadonlyURL(
|
|
37
|
-
resolve(INSECURE_URI, context.host
|
|
36
|
+
resolve(INSECURE_URI, context.host ?? location, context.url ?? context.host ?? location),
|
|
38
37
|
context.host?.href || location.href);
|
|
39
|
-
|
|
40
|
-
const
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
if (!
|
|
45
|
-
|
|
38
|
+
let cache: HTMLElement | undefined;
|
|
39
|
+
const el = undefined
|
|
40
|
+
|| (cache = context.caches?.media?.get(url.href)?.cloneNode(true))
|
|
41
|
+
|| html('img', { class: 'media', 'data-src': url.source, alt: text });
|
|
42
|
+
assert(!el.matches('.invalid'));
|
|
43
|
+
if (!cache && !sanitize(url, el)) return [[el], rest];
|
|
44
|
+
assert(!el.matches('.invalid'));
|
|
45
|
+
cache?.hasAttribute('alt') && cache?.setAttribute('alt', text);
|
|
46
46
|
define(el, attributes('media', push([], el.classList), optspec, params));
|
|
47
47
|
assert(el.matches('img') || !el.matches('.invalid'));
|
|
48
|
-
if (context.syntax?.inline?.link === false ||
|
|
48
|
+
if (context.syntax?.inline?.link === false || cache && cache.tagName !== 'IMG') return [[el], rest];
|
|
49
49
|
return fmap(
|
|
50
50
|
link as MediaParser,
|
|
51
51
|
([link]) => [define(link, { target: '_blank' }, [el])])
|
|
@@ -67,18 +67,29 @@ const option: MediaParser.ParameterParser.OptionParser = union([
|
|
|
67
67
|
|
|
68
68
|
function sanitize(uri: ReadonlyURL, target: HTMLElement): boolean {
|
|
69
69
|
assert(target.tagName === 'IMG');
|
|
70
|
+
assert(!target.matches('.invalid'));
|
|
71
|
+
if (/\/\.\.?(?:\/|$)/.test('/' + uri.source.slice(0, uri.source.search(/[?#]|$/)))) {
|
|
72
|
+
define(target, {
|
|
73
|
+
class: void target.classList.add('invalid'),
|
|
74
|
+
'data-invalid-syntax': 'media',
|
|
75
|
+
'data-invalid-type': 'argument',
|
|
76
|
+
'data-invalid-description': 'Dot-segments cannot be used in media paths; use subresource paths instead.',
|
|
77
|
+
});
|
|
78
|
+
return false;
|
|
79
|
+
}
|
|
70
80
|
switch (uri.protocol) {
|
|
71
81
|
case 'http:':
|
|
72
82
|
case 'https:':
|
|
73
83
|
assert(uri.host);
|
|
74
|
-
|
|
84
|
+
break;
|
|
85
|
+
default:
|
|
86
|
+
define(target, {
|
|
87
|
+
class: void target.classList.add('invalid'),
|
|
88
|
+
'data-invalid-syntax': 'media',
|
|
89
|
+
'data-invalid-type': 'argument',
|
|
90
|
+
'data-invalid-description': 'Invalid protocol.',
|
|
91
|
+
});
|
|
92
|
+
return false;
|
|
75
93
|
}
|
|
76
|
-
|
|
77
|
-
define(target, {
|
|
78
|
-
class: void target.classList.add('invalid'),
|
|
79
|
-
'data-invalid-syntax': 'media',
|
|
80
|
-
'data-invalid-type': 'argument',
|
|
81
|
-
'data-invalid-description': 'Invalid protocol.',
|
|
82
|
-
});
|
|
83
|
-
return false;
|
|
94
|
+
return true;
|
|
84
95
|
}
|
|
@@ -14,8 +14,6 @@ describe('Unit: parser/inline/reference', () => {
|
|
|
14
14
|
assert.deepStrictEqual(inspect(parser('[[]]')), undefined);
|
|
15
15
|
assert.deepStrictEqual(inspect(parser('[[]]]')), undefined);
|
|
16
16
|
assert.deepStrictEqual(inspect(parser('[[ ]]')), undefined);
|
|
17
|
-
assert.deepStrictEqual(inspect(parser('[[ a]]')), undefined);
|
|
18
|
-
assert.deepStrictEqual(inspect(parser('[[ a ]]')), undefined);
|
|
19
17
|
assert.deepStrictEqual(inspect(parser('[[\n]]')), undefined);
|
|
20
18
|
assert.deepStrictEqual(inspect(parser('[[\na]]')), undefined);
|
|
21
19
|
assert.deepStrictEqual(inspect(parser('[[\\ a]]')), undefined);
|
|
@@ -34,6 +32,8 @@ describe('Unit: parser/inline/reference', () => {
|
|
|
34
32
|
});
|
|
35
33
|
|
|
36
34
|
it('basic', () => {
|
|
35
|
+
assert.deepStrictEqual(inspect(parser('[[ a]]')), [['<sup class="reference">a</sup>'], '']);
|
|
36
|
+
assert.deepStrictEqual(inspect(parser('[[ a ]]')), [['<sup class="reference">a</sup>'], '']);
|
|
37
37
|
assert.deepStrictEqual(inspect(parser('[[a]]')), [['<sup class="reference">a</sup>'], '']);
|
|
38
38
|
assert.deepStrictEqual(inspect(parser('[[a ]]')), [['<sup class="reference">a</sup>'], '']);
|
|
39
39
|
assert.deepStrictEqual(inspect(parser('[[a ]]')), [['<sup class="reference">a</sup>'], '']);
|
|
@@ -3,13 +3,13 @@ import { ReferenceParser } from '../inline';
|
|
|
3
3
|
import { union, subsequence, some, validate, verify, focus, guard, context, creator, surround, lazy, fmap } from '../../combinator';
|
|
4
4
|
import { inline } from '../inline';
|
|
5
5
|
import { str } from '../source';
|
|
6
|
-
import {
|
|
6
|
+
import { startLoose, isStartLoose, trimNode, stringify } from '../util';
|
|
7
7
|
import { html, defrag } from 'typed-dom';
|
|
8
8
|
|
|
9
9
|
export const reference: ReferenceParser = lazy(() => creator(validate('[[', ']]', '\n', fmap(surround(
|
|
10
10
|
'[[',
|
|
11
11
|
guard(context => context.syntax?.inline?.reference ?? true,
|
|
12
|
-
|
|
12
|
+
startLoose(
|
|
13
13
|
context({ syntax: { inline: {
|
|
14
14
|
annotation: false,
|
|
15
15
|
reference: false,
|
|
@@ -24,15 +24,15 @@ export const reference: ReferenceParser = lazy(() => creator(validate('[[', ']]'
|
|
|
24
24
|
abbr,
|
|
25
25
|
focus('^', c => [['', c], '']),
|
|
26
26
|
some(inline, ']', /^\\?\n/),
|
|
27
|
-
])))),
|
|
27
|
+
])), ']]')),
|
|
28
28
|
']]'),
|
|
29
|
-
ns => [html('sup', attributes(ns),
|
|
29
|
+
ns => [html('sup', attributes(ns), trimNode(defrag(ns)))]))));
|
|
30
30
|
|
|
31
31
|
const abbr: ReferenceParser.AbbrParser = creator(fmap(verify(surround(
|
|
32
32
|
'^',
|
|
33
33
|
union([str(/^(?![0-9]+\s?[|\]])[0-9A-Za-z]+(?:(?:-|(?=\W)(?!'\d)'?(?!\.\d)\.?(?!,\S),? ?)[0-9A-Za-z]+)*(?:-|'?\.?,? ?)?/)]),
|
|
34
|
-
/^\|?(?=]])|^\|[^\S\n]
|
|
35
|
-
(_, rest, context) =>
|
|
34
|
+
/^\|?(?=]])|^\|[^\S\n]/),
|
|
35
|
+
(_, rest, context) => isStartLoose(rest, context)),
|
|
36
36
|
([source]) => [html('abbr', source)]));
|
|
37
37
|
|
|
38
38
|
function attributes(ns: (string | HTMLElement)[]): Record<string, string | undefined> {
|
|
@@ -4,7 +4,7 @@ import { eval, exec } from '../../combinator/data/parser';
|
|
|
4
4
|
import { sequence, validate, verify, focus, creator, surround, lazy, bind } from '../../combinator';
|
|
5
5
|
import { htmlentity } from './htmlentity';
|
|
6
6
|
import { text as txt } from '../source';
|
|
7
|
-
import {
|
|
7
|
+
import { isStartTightNodes } from '../util';
|
|
8
8
|
import { html, defrag } from 'typed-dom';
|
|
9
9
|
import { unshift, push, join } from 'spica/array';
|
|
10
10
|
|
|
@@ -14,7 +14,7 @@ export const ruby: RubyParser = lazy(() => creator(bind(verify(
|
|
|
14
14
|
surround('[', focus(/^(?:\\[^\n]|[^\[\]\n])+(?=]\()/, text), ']'),
|
|
15
15
|
surround('(', focus(/^(?:\\[^\n]|[^\(\)\n])+(?=\))/, text), ')'),
|
|
16
16
|
])),
|
|
17
|
-
([texts]) =>
|
|
17
|
+
([texts]) => isStartTightNodes(texts)),
|
|
18
18
|
([texts, rubies], rest) => {
|
|
19
19
|
const tail = typeof texts[texts.length - 1] === 'object'
|
|
20
20
|
? [texts.pop()!]
|
|
@@ -3,7 +3,7 @@ import { union, some, creator, surround, close, lazy } from '../../combinator';
|
|
|
3
3
|
import { inline } from '../inline';
|
|
4
4
|
import { emphasis } from './emphasis';
|
|
5
5
|
import { str } from '../source';
|
|
6
|
-
import { startTight,
|
|
6
|
+
import { startTight, isEndTightNodes, trimEndBR } from '../util';
|
|
7
7
|
import { html, defrag } from 'typed-dom';
|
|
8
8
|
import { unshift } from 'spica/array';
|
|
9
9
|
|
|
@@ -12,7 +12,7 @@ export const strong: StrongParser = lazy(() => creator(surround(close(
|
|
|
12
12
|
startTight(some(union([emphasis, some(inline, '*'), str('*')]), '**')),
|
|
13
13
|
str('**'), false,
|
|
14
14
|
([as, bs, cs], rest) =>
|
|
15
|
-
|
|
15
|
+
isEndTightNodes(bs)
|
|
16
16
|
? [[html('strong', defrag(trimEndBR(bs)))], rest]
|
|
17
17
|
: [unshift(as, bs), cs[0] + rest],
|
|
18
18
|
([as, bs], rest) => [unshift(as, bs), rest])));
|
package/src/parser/util.ts
CHANGED
|
@@ -70,6 +70,19 @@ function hasVisible(
|
|
|
70
70
|
return false;
|
|
71
71
|
}
|
|
72
72
|
|
|
73
|
+
export function startLoose<P extends Parser<HTMLElement | string>>(parser: P, except?: string): P;
|
|
74
|
+
export function startLoose<T extends HTMLElement | string>(parser: Parser<T>, except?: string): Parser<T> {
|
|
75
|
+
return (source, context) =>
|
|
76
|
+
isStartLoose(source, context, except)
|
|
77
|
+
? parser(source, context)
|
|
78
|
+
: undefined;
|
|
79
|
+
}
|
|
80
|
+
export function isStartLoose(source: string, context: MarkdownParser.Context, except?: string): boolean {
|
|
81
|
+
source &&= source.replace(/^[^\S\n]+/, '');
|
|
82
|
+
if (source === '') return true;
|
|
83
|
+
return source.slice(0, except?.length ?? 0) !== except
|
|
84
|
+
&& isStartTight(source, context);
|
|
85
|
+
}
|
|
73
86
|
export function startTight<P extends Parser<unknown>>(parser: P): P;
|
|
74
87
|
export function startTight<T>(parser: Parser<T>): Parser<T> {
|
|
75
88
|
return (source, context) =>
|
|
@@ -77,8 +90,7 @@ export function startTight<T>(parser: Parser<T>): Parser<T> {
|
|
|
77
90
|
? parser(source, context)
|
|
78
91
|
: undefined;
|
|
79
92
|
}
|
|
80
|
-
|
|
81
|
-
export function isStartTight(source: string, context: MarkdownParser.Context): boolean {
|
|
93
|
+
function isStartTight(source: string, context: MarkdownParser.Context): boolean {
|
|
82
94
|
if (source === '') return true;
|
|
83
95
|
switch (source[0]) {
|
|
84
96
|
case ' ':
|
|
@@ -117,11 +129,11 @@ export function isStartTight(source: string, context: MarkdownParser.Context): b
|
|
|
117
129
|
return source[0].trimStart() !== '';
|
|
118
130
|
}
|
|
119
131
|
}
|
|
120
|
-
export function
|
|
132
|
+
export function isStartTightNodes(nodes: readonly (HTMLElement | string)[]): boolean {
|
|
121
133
|
if (nodes.length === 0) return true;
|
|
122
|
-
return isVisible(nodes[0]);
|
|
134
|
+
return isVisible(nodes[0], 0);
|
|
123
135
|
}
|
|
124
|
-
export function
|
|
136
|
+
export function isEndTightNodes(nodes: readonly (HTMLElement | string)[]): boolean {
|
|
125
137
|
if (nodes.length === 0) return true;
|
|
126
138
|
const last = nodes.length - 1;
|
|
127
139
|
return typeof nodes[last] === 'string' && (nodes[last] as string).length > 1
|
|
@@ -130,12 +142,13 @@ export function verifyEndTight(nodes: readonly (HTMLElement | string)[]): boolea
|
|
|
130
142
|
: isVisible(nodes[last], -1) || last === 0 ||
|
|
131
143
|
isVisible(nodes[last - 1], -1);
|
|
132
144
|
}
|
|
133
|
-
function isVisible(node: HTMLElement | string, position
|
|
145
|
+
function isVisible(node: HTMLElement | string, position?: number): boolean {
|
|
134
146
|
if (!node) return false;
|
|
135
147
|
switch (typeof node) {
|
|
136
148
|
case 'string':
|
|
137
|
-
|
|
138
|
-
|
|
149
|
+
const char = position === undefined
|
|
150
|
+
? node
|
|
151
|
+
: node[position >= 0 ? position : node.length + position];
|
|
139
152
|
assert(char);
|
|
140
153
|
switch (char) {
|
|
141
154
|
case ' ':
|
|
@@ -160,8 +173,34 @@ function isVisible(node: HTMLElement | string, position = 0): boolean {
|
|
|
160
173
|
}
|
|
161
174
|
}
|
|
162
175
|
|
|
163
|
-
export function
|
|
164
|
-
|
|
176
|
+
export function trimNode(nodes: (HTMLElement | string)[]): (HTMLElement | string)[] {
|
|
177
|
+
return trimNodeStart(trimNodeEnd(nodes));
|
|
178
|
+
}
|
|
179
|
+
function trimNodeStart(nodes: (HTMLElement | string)[]): (HTMLElement | string)[] {
|
|
180
|
+
const skip = nodes.length > 0 &&
|
|
181
|
+
typeof nodes[nodes.length - 1] === 'object' &&
|
|
182
|
+
nodes[nodes.length - 1]['className'] === 'indexer'
|
|
183
|
+
? [nodes.pop()!]
|
|
184
|
+
: [];
|
|
185
|
+
for (
|
|
186
|
+
let first = nodes[0];
|
|
187
|
+
nodes.length > 0 &&
|
|
188
|
+
!isVisible(first, 0) &&
|
|
189
|
+
!(typeof first === 'object' && first.className === 'comment');
|
|
190
|
+
) {
|
|
191
|
+
assert(nodes.length > 0);
|
|
192
|
+
if (typeof first === 'string') {
|
|
193
|
+
const pos = first.length - first.trimStart().length;
|
|
194
|
+
if (pos > 0) {
|
|
195
|
+
nodes[0] = first.slice(pos);
|
|
196
|
+
break;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
nodes.pop();
|
|
200
|
+
}
|
|
201
|
+
return push(nodes, skip);
|
|
202
|
+
}
|
|
203
|
+
export function trimNodeEnd(nodes: (HTMLElement | string)[]): (HTMLElement | string)[] {
|
|
165
204
|
const skip = nodes.length > 0 &&
|
|
166
205
|
typeof nodes[nodes.length - 1] === 'object' &&
|
|
167
206
|
nodes[nodes.length - 1]['className'] === 'indexer'
|
|
@@ -13,7 +13,7 @@ export function math(target: HTMLElement, cache?: Collection<string, HTMLElement
|
|
|
13
13
|
|
|
14
14
|
async function queue(target: HTMLElement, callback = () => undefined): Promise<void> {
|
|
15
15
|
// @ts-ignore
|
|
16
|
-
MathJax.typesetPromise
|
|
16
|
+
!MathJax.typesetPromise && await MathJax.startup.promise;
|
|
17
17
|
// @ts-ignore
|
|
18
18
|
MathJax.typesetPromise([target]).then(callback);
|
|
19
19
|
}
|
package/src/renderer/render.ts
CHANGED
|
@@ -12,7 +12,6 @@ const extend = reduce((opts: RenderingOptions): RenderingOptions =>
|
|
|
12
12
|
|
|
13
13
|
export function render(source: HTMLElement, opts: RenderingOptions = {}): void {
|
|
14
14
|
opts = extend(opts);
|
|
15
|
-
if (source.classList.contains('invalid')) return;
|
|
16
15
|
const base = location.href;
|
|
17
16
|
if (source.matches(selector)) return void render_(base, source, opts);
|
|
18
17
|
for (
|
|
@@ -23,7 +22,7 @@ export function render(source: HTMLElement, opts: RenderingOptions = {}): void {
|
|
|
23
22
|
}
|
|
24
23
|
|
|
25
24
|
function render_(base: string, source: HTMLElement, opts: RenderingOptions): void {
|
|
26
|
-
|
|
25
|
+
if (source.classList.contains('invalid')) return;
|
|
27
26
|
try {
|
|
28
27
|
switch (true) {
|
|
29
28
|
case !!opts.code
|