securemark 0.252.0 → 0.253.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.json +7 -1
- package/CHANGELOG.md +12 -0
- package/design.md +17 -11
- package/dist/index.js +121 -116
- package/index.d.ts +7 -8
- package/markdown.d.ts +6 -5
- package/package.json +9 -9
- package/src/combinator/data/parser.ts +1 -1
- package/src/parser/api/bind.test.ts +8 -8
- package/src/parser/api/bind.ts +1 -1
- package/src/parser/api/parse.test.ts +2 -1
- package/src/parser/api/parse.ts +0 -1
- package/src/parser/block/blockquote.test.ts +31 -31
- package/src/parser/block/blockquote.ts +1 -3
- package/src/parser/block/extension/aside.test.ts +3 -3
- package/src/parser/block/extension/aside.ts +0 -3
- package/src/parser/block/extension/example.test.ts +11 -11
- package/src/parser/block/extension/example.ts +1 -3
- package/src/parser/block/extension/fig.test.ts +5 -5
- package/src/parser/block/extension/figure.test.ts +2 -2
- package/src/parser/block/extension/message.test.ts +7 -7
- package/src/parser/block/extension/message.ts +2 -2
- package/src/parser/block/extension/table.ts +6 -2
- package/src/parser/block/ilist.ts +4 -5
- package/src/parser/block/olist.ts +24 -20
- package/src/parser/block/ulist.ts +3 -13
- package/src/parser/inline/annotation.test.ts +18 -18
- package/src/parser/inline/annotation.ts +1 -1
- package/src/parser/inline/autolink/hashnum.ts +1 -1
- package/src/parser/inline/autolink/hashtag.ts +5 -5
- package/src/parser/inline/autolink.ts +2 -2
- package/src/parser/inline/html.test.ts +9 -6
- package/src/parser/inline/html.ts +11 -13
- package/src/parser/inline/reference.test.ts +58 -58
- package/src/parser/inline/reference.ts +1 -1
- package/src/parser/inline.test.ts +20 -20
- package/src/parser/locale.test.ts +1 -1
- package/src/parser/processor/figure.test.ts +3 -3
- package/src/parser/processor/figure.ts +3 -6
- package/src/parser/processor/footnote.test.ts +60 -2
- package/src/parser/processor/footnote.ts +56 -26
- package/src/parser/util.ts +4 -4
- package/src/renderer/render/code.ts +2 -2
- package/src/renderer/render/math.ts +2 -2
- package/src/renderer/render/media/image.ts +2 -2
- package/src/renderer/render/media.ts +2 -2
- package/src/util/info.ts +4 -4
- package/src/util/toc.ts +12 -16
|
@@ -117,8 +117,8 @@ describe('Unit: parser/processor/figure', () => {
|
|
|
117
117
|
assert.deepStrictEqual(
|
|
118
118
|
[...target.children].map(el => el.outerHTML),
|
|
119
119
|
[
|
|
120
|
-
'<blockquote><blockquote><section><figure data-type="quote" data-label="test-a" data-group="test" data-number="1"><figcaption><span class="figindex">Test 1. </span></figcaption><div><blockquote></blockquote></div></figure><ol class="
|
|
121
|
-
'<aside class="example" data-type="markdown"><pre translate="no">~~~figure $test-a\n> \n\n~~~\n\n$test-a</pre><hr><section><figure data-type="quote" data-label="test-a" data-group="test" data-number="1"><figcaption><span class="figindex">Test 1. </span></figcaption><div><blockquote></blockquote></div></figure><p><a class="label disabled" data-label="test-a">Test 1</a></p><ol class="
|
|
120
|
+
'<blockquote><blockquote><section><figure data-type="quote" data-label="test-a" data-group="test" data-number="1"><figcaption><span class="figindex">Test 1. </span></figcaption><div><blockquote></blockquote></div></figure><ol class="references"></ol></section></blockquote><section><figure data-type="quote" data-label="test-a" data-group="test" data-number="1"><figcaption><span class="figindex">Test 1. </span></figcaption><div><blockquote></blockquote></div></figure><ol class="references"></ol></section></blockquote>',
|
|
121
|
+
'<aside class="example" data-type="markdown"><pre translate="no">~~~figure $test-a\n> \n\n~~~\n\n$test-a</pre><hr><section><figure data-type="quote" data-label="test-a" data-group="test" data-number="1"><figcaption><span class="figindex">Test 1. </span></figcaption><div><blockquote></blockquote></div></figure><p><a class="label disabled" data-label="test-a">Test 1</a></p><ol class="references"></ol></section></aside>',
|
|
122
122
|
'<figure data-type="quote" data-label="test-b" data-group="test" data-number="1" id="label:test-b"><figcaption><span class="figindex">Test 1. </span></figcaption><div><blockquote></blockquote></div></figure>',
|
|
123
123
|
'<figure data-type="quote" data-label="test-a" data-group="test" data-number="2" id="label:test-a"><figcaption><span class="figindex">Test 2. </span></figcaption><div><blockquote></blockquote></div></figure>',
|
|
124
124
|
]);
|
|
@@ -173,7 +173,7 @@ describe('Unit: parser/processor/figure', () => {
|
|
|
173
173
|
'<h2 id="index:0">0</h2>',
|
|
174
174
|
'<figure data-type="quote" data-label="test-1" data-group="test" data-number="1" id="label:test-1"><figcaption><span class="figindex">Test 1. </span></figcaption><div><blockquote></blockquote></div></figure>',
|
|
175
175
|
'<h2 id="index:0">0</h2>',
|
|
176
|
-
'<blockquote><section><h2>0</h2><ol class="
|
|
176
|
+
'<blockquote><section><h2>0</h2><ol class="references"></ol></section></blockquote>',
|
|
177
177
|
'<figure data-type="quote" data-label="test-b" data-group="test" data-number="2.1" id="label:test-b"><figcaption><span class="figindex">Test 2.1. </span></figcaption><div><blockquote></blockquote></div></figure>',
|
|
178
178
|
'<h2 id="index:0">0</h2>',
|
|
179
179
|
'<figure data-label="$-0.0.0" data-group="$" class="invalid" data-invalid-syntax="figure" data-invalid-type="argument" data-invalid-message="Base index must be $-x.0 format"></figure>',
|
|
@@ -6,14 +6,11 @@ import { push } from 'spica/array';
|
|
|
6
6
|
|
|
7
7
|
export function* figure(
|
|
8
8
|
target: ParentNode & Node,
|
|
9
|
-
footnotes?:
|
|
10
|
-
opts:
|
|
11
|
-
id?: string;
|
|
12
|
-
}> = {},
|
|
9
|
+
footnotes?: { readonly references: HTMLOListElement; },
|
|
10
|
+
opts: { readonly id?: string; } = {},
|
|
13
11
|
): Generator<HTMLAnchorElement | undefined, undefined, undefined> {
|
|
14
|
-
const refs = new MultiMap<string, HTMLAnchorElement>(push(push(
|
|
12
|
+
const refs = new MultiMap<string, HTMLAnchorElement>(push(push([],
|
|
15
13
|
target.querySelectorAll('a.label:not(.disabled)[data-label]')),
|
|
16
|
-
footnotes?.annotations.querySelectorAll('a.label:not(.disabled)') ?? []),
|
|
17
14
|
footnotes?.references.querySelectorAll('a.label:not(.disabled)') ?? [])
|
|
18
15
|
.map(el => [el.getAttribute('data-label')!, el]));
|
|
19
16
|
const labels = new Set<string>();
|
|
@@ -151,8 +151,8 @@ describe('Unit: parser/processor/footnote', () => {
|
|
|
151
151
|
assert.deepStrictEqual(
|
|
152
152
|
[...target.children].map(el => el.outerHTML),
|
|
153
153
|
[
|
|
154
|
-
'<blockquote><blockquote><section><p><sup class="annotation disabled" title="a"><span hidden="">a</span><a>*1</a></sup></p><ol class="annotations"><li>a<sup><a>^1</a></sup></li></ol><ol class="references"></ol></section></blockquote><section><p><sup class="annotation disabled" title="a"><span hidden="">a</span><a>*1</a></sup><br>~~~</p><ol class="annotations"><li>a<sup><a>^1</a></sup></li></ol><ol class="references"></ol></section></blockquote>',
|
|
155
|
-
'<aside class="example" data-type="markdown"><pre translate="no">((a))</pre><hr><section><p><sup class="annotation disabled" title="a"><span hidden="">a</span><a>*1</a></sup></p><ol class="annotations"><li>a<sup><a>^1</a></sup></li></ol><ol class="references"></ol></section></aside>',
|
|
154
|
+
'<blockquote><blockquote><section><p><sup class="annotation disabled" title="a"><span hidden="">a</span><a>*1</a></sup></p><ol class="annotations"><li data-marker="*1">a<sup><a>^1</a></sup></li></ol><ol class="references"></ol></section></blockquote><section><p><sup class="annotation disabled" title="a"><span hidden="">a</span><a>*1</a></sup><br>~~~</p><ol class="annotations"><li data-marker="*1">a<sup><a>^1</a></sup></li></ol><ol class="references"></ol></section></blockquote>',
|
|
155
|
+
'<aside class="example" data-type="markdown"><pre translate="no">((a))</pre><hr><section><p><sup class="annotation disabled" title="a"><span hidden="">a</span><a>*1</a></sup></p><ol class="annotations"><li data-marker="*1">a<sup><a>^1</a></sup></li></ol><ol class="references"></ol></section></aside>',
|
|
156
156
|
'<p><sup class="annotation" id="annotation:ref:1" title="a"><span hidden="">a</span><a href="#annotation:def:1">*1</a></sup></p>',
|
|
157
157
|
]);
|
|
158
158
|
assert.deepStrictEqual(
|
|
@@ -187,6 +187,64 @@ describe('Unit: parser/processor/footnote', () => {
|
|
|
187
187
|
}
|
|
188
188
|
});
|
|
189
189
|
|
|
190
|
+
it('split', () => {
|
|
191
|
+
const target = parse('((1))\n\n## a\n\n## b\n\n((2))((3))\n\n## c\n\n((4))');
|
|
192
|
+
for (let i = 0; i < 3; ++i) {
|
|
193
|
+
[...annotation(target)];
|
|
194
|
+
assert.deepStrictEqual(
|
|
195
|
+
[...target.children].map(el => el.outerHTML),
|
|
196
|
+
[
|
|
197
|
+
html('p', [
|
|
198
|
+
html('sup', { class: "annotation", id: "annotation:ref:1", title: "1" }, [
|
|
199
|
+
html('span', { hidden: '' }, '1'),
|
|
200
|
+
html('a', { href: "#annotation:def:1" }, '*1')
|
|
201
|
+
]),
|
|
202
|
+
]).outerHTML,
|
|
203
|
+
html('ol', { class: 'annotations' }, [
|
|
204
|
+
html('li', { id: 'annotation:def:1', 'data-marker': '*1' }, [
|
|
205
|
+
'1',
|
|
206
|
+
html('sup', [html('a', { href: '#annotation:ref:1' }, '^1')])
|
|
207
|
+
]),
|
|
208
|
+
]).outerHTML,
|
|
209
|
+
html('h2', { id: 'index:a' }, 'a').outerHTML,
|
|
210
|
+
html('h2', { id: 'index:b' }, 'b').outerHTML,
|
|
211
|
+
html('p', [
|
|
212
|
+
html('sup', { class: "annotation", id: "annotation:ref:2", title: "2" }, [
|
|
213
|
+
html('span', { hidden: '' }, '2'),
|
|
214
|
+
html('a', { href: "#annotation:def:2" }, '*2')
|
|
215
|
+
]),
|
|
216
|
+
html('sup', { class: "annotation", id: "annotation:ref:3", title: "3" }, [
|
|
217
|
+
html('span', { hidden: '' }, '3'),
|
|
218
|
+
html('a', { href: "#annotation:def:3" }, '*3')
|
|
219
|
+
]),
|
|
220
|
+
]).outerHTML,
|
|
221
|
+
html('ol', { class: 'annotations' }, [
|
|
222
|
+
html('li', { id: 'annotation:def:2', 'data-marker': '*2' }, [
|
|
223
|
+
'2',
|
|
224
|
+
html('sup', [html('a', { href: '#annotation:ref:2' }, '^2')])
|
|
225
|
+
]),
|
|
226
|
+
html('li', { id: 'annotation:def:3', 'data-marker': '*3' }, [
|
|
227
|
+
'3',
|
|
228
|
+
html('sup', [html('a', { href: '#annotation:ref:3' }, '^3')])
|
|
229
|
+
]),
|
|
230
|
+
]).outerHTML,
|
|
231
|
+
html('h2', { id: 'index:c' }, 'c').outerHTML,
|
|
232
|
+
html('p', [
|
|
233
|
+
html('sup', { class: "annotation", id: "annotation:ref:4", title: "4" }, [
|
|
234
|
+
html('span', { hidden: '' }, '4'),
|
|
235
|
+
html('a', { href: "#annotation:def:4" }, '*4')
|
|
236
|
+
]),
|
|
237
|
+
]).outerHTML,
|
|
238
|
+
html('ol', { class: 'annotations' }, [
|
|
239
|
+
html('li', { id: 'annotation:def:4', 'data-marker': '*4' }, [
|
|
240
|
+
'4',
|
|
241
|
+
html('sup', [html('a', { href: '#annotation:ref:4' }, '^4')])
|
|
242
|
+
]),
|
|
243
|
+
]).outerHTML,
|
|
244
|
+
]);
|
|
245
|
+
}
|
|
246
|
+
});
|
|
247
|
+
|
|
190
248
|
});
|
|
191
249
|
|
|
192
250
|
describe('reference', () => {
|
|
@@ -1,55 +1,65 @@
|
|
|
1
|
-
import { undefined, Infinity, Map,
|
|
1
|
+
import { undefined, Infinity, Map, Node } from 'spica/global';
|
|
2
2
|
import { text } from '../inline/extension/indexee';
|
|
3
3
|
import { frag, html, define } from 'typed-dom/dom';
|
|
4
4
|
import { MultiMap } from 'spica/multimap';
|
|
5
|
-
import {
|
|
5
|
+
import { push } from 'spica/array';
|
|
6
6
|
|
|
7
7
|
export function* footnote(
|
|
8
8
|
target: ParentNode & Node,
|
|
9
|
-
footnotes?:
|
|
10
|
-
opts:
|
|
9
|
+
footnotes?: { readonly annotations?: HTMLOListElement; readonly references: HTMLOListElement; },
|
|
10
|
+
opts: { readonly id?: string; } = {},
|
|
11
|
+
bottom: Node | null = null,
|
|
11
12
|
): Generator<HTMLAnchorElement | HTMLLIElement | undefined, undefined, undefined> {
|
|
12
|
-
yield* reference(target, footnotes?.references, opts,
|
|
13
|
-
yield* annotation(target, footnotes?.annotations, opts,
|
|
13
|
+
yield* reference(target, footnotes?.references, opts, bottom);
|
|
14
|
+
yield* annotation(target, footnotes?.annotations, opts, bottom);
|
|
14
15
|
return;
|
|
15
16
|
}
|
|
16
17
|
|
|
17
|
-
export const annotation = build('annotation', n => `*${n}
|
|
18
|
+
export const annotation = build('annotation', n => `*${n}`, 'h1, h2, h3, h4, h5, h6, aside.aside, hr');
|
|
18
19
|
export const reference = build('reference', (n, abbr) => `[${abbr || n}]`);
|
|
19
20
|
|
|
20
21
|
function build(
|
|
21
|
-
syntax:
|
|
22
|
+
syntax: 'annotation' | 'reference',
|
|
22
23
|
marker: (index: number, abbr: string | undefined) => string,
|
|
24
|
+
splitter?: string,
|
|
23
25
|
) {
|
|
24
26
|
assert(syntax.match(/^[a-z]+$/));
|
|
25
27
|
// Referenceを含むAnnotationの重複排除は両構文が互いに処理済みであることを必要とするため
|
|
26
28
|
// 構文ごとに各1回の処理では不可能
|
|
27
|
-
const identify = memoize<HTMLElement, string>(
|
|
28
|
-
ref => `${+!ref.querySelector('.label')}:${ref.getAttribute('data-abbr') || '_' + ref.innerHTML}`,
|
|
29
|
-
new WeakMap());
|
|
30
|
-
const contentify = memoize<HTMLElement, DocumentFragment>(
|
|
31
|
-
ref => frag(ref.cloneNode(true).childNodes),
|
|
32
|
-
new WeakMap());
|
|
33
29
|
return function* (
|
|
34
30
|
target: ParentNode & Node,
|
|
35
31
|
footnote?: HTMLOListElement,
|
|
36
|
-
opts:
|
|
37
|
-
|
|
32
|
+
opts: { readonly id?: string } = {},
|
|
33
|
+
bottom: Node | null = null,
|
|
38
34
|
): Generator<HTMLAnchorElement | HTMLLIElement | undefined, undefined, undefined> {
|
|
39
35
|
const defs = new Map<string, HTMLLIElement>();
|
|
40
36
|
const buffer = new MultiMap<string, HTMLElement>();
|
|
41
37
|
const titles = new Map<string, string>();
|
|
42
|
-
|
|
38
|
+
// Bug: Firefox
|
|
39
|
+
//const splitters = push([], target.querySelectorAll(`:scope > :is(${splitter ?? '_'})`));
|
|
40
|
+
const splitters = push([], target.querySelectorAll(splitter ?? '_'))
|
|
41
|
+
.filter(el => el.parentNode === target);
|
|
42
|
+
// Bug: Firefox
|
|
43
|
+
//target.querySelectorAll(`:scope > .${syntax}s`).forEach(el => el.remove());
|
|
44
|
+
target.querySelectorAll(`.${syntax}s`).forEach(el => el.parentNode === target && el.remove());
|
|
45
|
+
let offset = 0;
|
|
43
46
|
let style: 'count' | 'abbr';
|
|
44
47
|
for (
|
|
45
48
|
let refs = target.querySelectorAll(`sup.${syntax}:not(.disabled)`),
|
|
46
49
|
i = 0, len = refs.length; i < len; ++i) {
|
|
47
50
|
yield;
|
|
48
51
|
const ref = refs[i];
|
|
49
|
-
|
|
50
|
-
|
|
52
|
+
while (+splitters[0]?.compareDocumentPosition(ref) & Node.DOCUMENT_POSITION_FOLLOWING) {
|
|
53
|
+
if (defs.size > 0) {
|
|
54
|
+
offset += defs.size;
|
|
55
|
+
yield* proc(defs, target.insertBefore(html('ol', { class: `${syntax}s` }), splitters[0] ?? null));
|
|
56
|
+
}
|
|
57
|
+
splitters.shift();
|
|
58
|
+
}
|
|
59
|
+
if (syntax === 'annotation' && ref.closest('#annotations, .annotations, #references, .references')) continue;
|
|
60
|
+
const identifier = `${+!ref.querySelector('.label')}:${ref.getAttribute('data-abbr') || '_' + ref.firstElementChild!.innerHTML}`;
|
|
51
61
|
const abbr = ref.getAttribute('data-abbr') || undefined;
|
|
52
|
-
const content =
|
|
62
|
+
const content = frag(ref.firstElementChild!.cloneNode(true).childNodes);
|
|
53
63
|
style ??= abbr ? 'abbr' : 'count';
|
|
54
64
|
if (style === 'count' ? abbr : !abbr) {
|
|
55
65
|
define(ref, {
|
|
@@ -59,8 +69,16 @@ function build(
|
|
|
59
69
|
'data-invalid-message': `${syntax[0].toUpperCase() + syntax.slice(1)} style must be consistent`,
|
|
60
70
|
});
|
|
61
71
|
}
|
|
62
|
-
if (ref.
|
|
63
|
-
ref
|
|
72
|
+
else if (ref.getAttribute('data-invalid-type') === 'style') {
|
|
73
|
+
define(ref, {
|
|
74
|
+
class: void ref.classList.remove('invalid'),
|
|
75
|
+
'data-invalid-syntax': null,
|
|
76
|
+
'data-invalid-type': null,
|
|
77
|
+
'data-invalid-message': null,
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
if (!ref.firstElementChild!.hasAttribute('hidden')) {
|
|
81
|
+
ref.firstElementChild!.setAttribute('hidden', '');
|
|
64
82
|
}
|
|
65
83
|
else {
|
|
66
84
|
ref.lastChild?.remove();
|
|
@@ -71,9 +89,11 @@ function build(
|
|
|
71
89
|
|| text(content).trim()
|
|
72
90
|
|| content.textContent!.trim()
|
|
73
91
|
|| undefined;
|
|
92
|
+
assert(syntax !== 'annotation' || title);
|
|
74
93
|
title
|
|
75
94
|
? !titles.has(identifier) && titles.set(identifier, title)
|
|
76
95
|
: buffer.set(identifier, ref);
|
|
96
|
+
assert(syntax !== 'annotation' || !buffer.has(identifier));
|
|
77
97
|
const blank = !!abbr && !content.firstChild;
|
|
78
98
|
const refIndex = i + 1;
|
|
79
99
|
const refId = opts.id !== ''
|
|
@@ -82,7 +102,10 @@ function build(
|
|
|
82
102
|
const def = undefined
|
|
83
103
|
|| defs.get(identifier)
|
|
84
104
|
|| defs.set(identifier, html('li',
|
|
85
|
-
{
|
|
105
|
+
{
|
|
106
|
+
id: opts.id !== '' ? `${syntax}:${opts.id ? `${opts.id}:` : ''}def:${defs.size + offset + 1}` : undefined,
|
|
107
|
+
'data-marker': !footnote ? marker(defs.size + offset + 1, abbr) : undefined,
|
|
108
|
+
},
|
|
86
109
|
[content.cloneNode(true), html('sup')]))
|
|
87
110
|
.get(identifier)!;
|
|
88
111
|
assert(def.lastChild);
|
|
@@ -100,7 +123,7 @@ function build(
|
|
|
100
123
|
});
|
|
101
124
|
}
|
|
102
125
|
}
|
|
103
|
-
const defIndex = +def.id.slice(def.id.lastIndexOf(':') + 1) || defs.size;
|
|
126
|
+
const defIndex = +def.id.slice(def.id.lastIndexOf(':') + 1) || defs.size + offset;
|
|
104
127
|
const defId = def.id || undefined;
|
|
105
128
|
define(ref, {
|
|
106
129
|
id: refId,
|
|
@@ -125,13 +148,20 @@ function build(
|
|
|
125
148
|
},
|
|
126
149
|
`^${refIndex}`));
|
|
127
150
|
}
|
|
128
|
-
if (
|
|
151
|
+
if (defs.size > 0 || footnote) {
|
|
152
|
+
yield* proc(defs, footnote ?? target.insertBefore(html('ol', { class: `${syntax}s` }), splitters[0] ?? bottom));
|
|
153
|
+
}
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
function* proc(defs: Map<string, HTMLLIElement>, footnote: HTMLOListElement): Generator<HTMLLIElement | undefined, undefined, undefined> {
|
|
129
158
|
const { children } = footnote;
|
|
130
159
|
const size = defs.size;
|
|
131
160
|
let count = 0;
|
|
132
161
|
let length = children.length;
|
|
133
162
|
I:
|
|
134
|
-
for (const def of defs
|
|
163
|
+
for (const [key, def] of defs) {
|
|
164
|
+
defs.delete(key);
|
|
135
165
|
++count;
|
|
136
166
|
while (length > size) {
|
|
137
167
|
const node = children[count - 1] as HTMLLIElement;
|
package/src/parser/util.ts
CHANGED
|
@@ -8,8 +8,8 @@ import { invisibleHTMLEntityNames } from './api/normalize';
|
|
|
8
8
|
import { reduce } from 'spica/memoize';
|
|
9
9
|
import { push } from 'spica/array';
|
|
10
10
|
|
|
11
|
-
export const regBlankStart = new RegExp(
|
|
12
|
-
|
|
11
|
+
export const regBlankStart = new RegExp(
|
|
12
|
+
/^(?:\\?[^\S\n]|&IHN;|<wbr>)+/.source.replace('IHN', `(?:${invisibleHTMLEntityNames.join('|')})`));
|
|
13
13
|
|
|
14
14
|
export function blankWith(delimiter: string | RegExp): RegExp;
|
|
15
15
|
export function blankWith(starting: '' | '\n', delimiter: string | RegExp): RegExp;
|
|
@@ -25,8 +25,8 @@ export function blankWith(starting: '' | '\n', delimiter?: string | RegExp): Reg
|
|
|
25
25
|
|
|
26
26
|
export function visualize<P extends Parser<HTMLElement | string>>(parser: P): P;
|
|
27
27
|
export function visualize<T extends HTMLElement | string>(parser: Parser<T>): Parser<T> {
|
|
28
|
-
const blankline = new RegExp(
|
|
29
|
-
|
|
28
|
+
const blankline = new RegExp(
|
|
29
|
+
/^(?:\\$|\\?[^\S\n]|&IHN;|<wbr>)+$/.source.replace('IHN', `(?:${invisibleHTMLEntityNames.join('|')})`),
|
|
30
30
|
'gm');
|
|
31
31
|
return union([
|
|
32
32
|
convert(
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import Prism from 'prismjs';
|
|
2
|
-
import {
|
|
2
|
+
import { Dict } from 'spica/dict';
|
|
3
3
|
|
|
4
|
-
export function code(target: HTMLElement, cache?:
|
|
4
|
+
export function code(target: HTMLElement, cache?: Dict<string, HTMLElement>): void {
|
|
5
5
|
assert(target.children.length === 0);
|
|
6
6
|
const source = target.textContent!;
|
|
7
7
|
Prism.highlightElement(target, false, () =>
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { undefined } from 'spica/global';
|
|
2
|
-
import {
|
|
2
|
+
import { Dict } from 'spica/dict';
|
|
3
3
|
import { html, define } from 'typed-dom/dom';
|
|
4
4
|
|
|
5
|
-
export function math(target: HTMLElement, cache?:
|
|
5
|
+
export function math(target: HTMLElement, cache?: Dict<string, HTMLElement>): void {
|
|
6
6
|
assert(target.children.length === 0);
|
|
7
7
|
const source = target.textContent!;
|
|
8
8
|
queue(target, () => {
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { Object } from 'spica/global';
|
|
2
|
-
import {
|
|
2
|
+
import { Dict } from 'spica/dict';
|
|
3
3
|
import { define } from 'typed-dom/dom';
|
|
4
4
|
|
|
5
|
-
export function image(source: HTMLImageElement, url: URL, cache?:
|
|
5
|
+
export function image(source: HTMLImageElement, url: URL, cache?: Dict<string, HTMLElement>): HTMLImageElement {
|
|
6
6
|
if (cache?.has(url.href)) return define(
|
|
7
7
|
cache.get(url.href)!.cloneNode(true) as HTMLImageElement,
|
|
8
8
|
Object.fromEntries([...source.attributes]
|
|
@@ -5,7 +5,7 @@ import { pdf } from './media/pdf';
|
|
|
5
5
|
import { video } from './media/video';
|
|
6
6
|
import { audio } from './media/audio';
|
|
7
7
|
import { image } from './media/image';
|
|
8
|
-
import {
|
|
8
|
+
import { Dict } from 'spica/dict';
|
|
9
9
|
import { ReadonlyURL } from 'spica/url';
|
|
10
10
|
import { reduce } from 'spica/memoize';
|
|
11
11
|
|
|
@@ -14,7 +14,7 @@ type MediaOptions = NonNullable<RenderingOptions['media']>;
|
|
|
14
14
|
const extend = reduce((opts: MediaOptions): MediaOptions =>
|
|
15
15
|
({ twitter, youtube, pdf, video, audio, image, ...opts }));
|
|
16
16
|
|
|
17
|
-
export function media(base: string, source: HTMLImageElement, opts: MediaOptions, cache?:
|
|
17
|
+
export function media(base: string, source: HTMLImageElement, opts: MediaOptions, cache?: Dict<string, HTMLElement>): HTMLElement | undefined {
|
|
18
18
|
assert(source.matches('img:not([src])[data-src]'));
|
|
19
19
|
opts = extend(opts);
|
|
20
20
|
const url = new ReadonlyURL(source.getAttribute('data-src')!, base);
|
package/src/util/info.ts
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { Info } from '../..';
|
|
2
2
|
import { scope } from './scope';
|
|
3
|
-
import {
|
|
3
|
+
import { push } from 'spica/array';
|
|
4
4
|
|
|
5
5
|
export function info(source: DocumentFragment | HTMLElement | ShadowRoot): Info {
|
|
6
6
|
const match = scope(source, '.invalid');
|
|
7
7
|
return {
|
|
8
|
-
url: find<HTMLAnchorElement>('a:not(
|
|
8
|
+
url: find<HTMLAnchorElement>('a:not(:is(.email, .account, .channel, .hashtag, .hashnum, .anchor))')
|
|
9
9
|
.filter(el => ['http:', 'https:'].includes(el.protocol)),
|
|
10
|
-
tel: find<HTMLAnchorElement>('a:not(
|
|
10
|
+
tel: find<HTMLAnchorElement>('a:not(:is(.email, .account, .channel, .hashtag, .hashnum, .anchor))')
|
|
11
11
|
.filter(el => ['tel:'].includes(el.protocol)),
|
|
12
12
|
email: find('a.email'),
|
|
13
13
|
account: find('a.account'),
|
|
@@ -20,7 +20,7 @@ export function info(source: DocumentFragment | HTMLElement | ShadowRoot): Info
|
|
|
20
20
|
};
|
|
21
21
|
|
|
22
22
|
function find<T extends HTMLElement>(selector: string): T[] {
|
|
23
|
-
return querySelectorAll<T>(
|
|
23
|
+
return push([], source.querySelectorAll<T>(selector))
|
|
24
24
|
.filter(match);
|
|
25
25
|
}
|
|
26
26
|
}
|
package/src/util/toc.ts
CHANGED
|
@@ -1,26 +1,22 @@
|
|
|
1
|
-
import { undefined
|
|
1
|
+
import { undefined } from 'spica/global';
|
|
2
2
|
import { html } from 'typed-dom/dom';
|
|
3
3
|
import { push } from 'spica/array';
|
|
4
4
|
|
|
5
5
|
// Bug: Firefox
|
|
6
6
|
//const selector = 'h1 h2 h3 h4 h5 h6 aside.aside'.split(' ').map(s => `:scope > ${s}[id]`).join();
|
|
7
|
-
const selector = 'h1 h2 h3 h4 h5 h6 aside.aside
|
|
7
|
+
const selector = ':is(h1, h2, h3, h4, h5, h6, aside.aside)[id]';
|
|
8
8
|
|
|
9
9
|
export function toc(source: DocumentFragment | HTMLElement | ShadowRoot): HTMLUListElement {
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
hs[i] = el as HTMLHeadingElement;
|
|
21
|
-
continue;
|
|
22
|
-
}
|
|
23
|
-
}
|
|
10
|
+
const hs = push([], source.querySelectorAll(selector))
|
|
11
|
+
.map(el => {
|
|
12
|
+
assert(el.parentNode === source);
|
|
13
|
+
switch (el.tagName) {
|
|
14
|
+
case 'ASIDE':
|
|
15
|
+
return html(el.firstElementChild!.tagName.toLowerCase() as 'h1', { id: el.id, class: 'aside' }, el.firstElementChild!.cloneNode(true).childNodes);
|
|
16
|
+
default:
|
|
17
|
+
return el as HTMLHeadingElement;
|
|
18
|
+
}
|
|
19
|
+
});
|
|
24
20
|
return parse(cons(hs));
|
|
25
21
|
}
|
|
26
22
|
|