securemark 0.250.0 → 0.253.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 +12 -0
- package/design.md +17 -11
- package/dist/index.js +120 -139
- package/index.d.ts +1 -1
- package/markdown.d.ts +8 -18
- package/package.json +1 -1
- package/src/combinator/control/manipulation/indent.ts +15 -12
- package/src/combinator/control/manipulation/match.ts +2 -3
- package/src/combinator/data/parser.ts +1 -1
- package/src/parser/api/bind.test.ts +6 -6
- package/src/parser/api/parse.test.ts +8 -1
- package/src/parser/api/parse.ts +1 -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/figure.ts +2 -4
- package/src/parser/block/extension/message.ts +0 -2
- package/src/parser/block/ilist.ts +4 -5
- package/src/parser/block/olist.ts +26 -22
- package/src/parser/block/paragraph.test.ts +3 -3
- package/src/parser/block/ulist.ts +3 -13
- package/src/parser/block.ts +0 -3
- 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/code.ts +1 -1
- package/src/parser/inline/comment.ts +1 -1
- package/src/parser/inline/extension/index.ts +4 -5
- package/src/parser/inline/html.ts +3 -3
- package/src/parser/inline/reference.test.ts +58 -58
- package/src/parser/inline/reference.ts +4 -4
- 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 +2 -2
- package/src/parser/processor/footnote.test.ts +60 -2
- package/src/parser/processor/footnote.ts +53 -24
- package/src/parser/source/str.ts +2 -2
- package/src/parser/util.ts +14 -10
- package/src/util/info.ts +4 -4
- package/src/util/toc.ts +12 -16
- package/src/parser/block/indentblock.test.ts +0 -30
- package/src/parser/block/indentblock.ts +0 -13
|
@@ -101,11 +101,11 @@ describe('Unit: parser/inline', () => {
|
|
|
101
101
|
assert.deepStrictEqual(inspect(parser('*++ a ++*')), [['<em><ins> a </ins></em>'], '']);
|
|
102
102
|
assert.deepStrictEqual(inspect(parser('*<small>`a`</small>*')), [['<em><small><code data-src="`a`">a</code></small></em>'], '']);
|
|
103
103
|
assert.deepStrictEqual(inspect(parser('<small>*<bdi>a</bdi>*</small>')), [['<small><em><bdi>a</bdi></em></small>'], '']);
|
|
104
|
-
assert.deepStrictEqual(inspect(parser('<bdi>((<bdi>((a))</bdi>))</bdi>')), [['<bdi><sup class="annotation"><bdi><span class="paren">((a))</span></bdi></sup></bdi>'], '']);
|
|
105
|
-
assert.deepStrictEqual(inspect(parser('<bdi>[[<bdi>[[a]]</bdi>]]</bdi>')), [['<bdi><sup class="reference"><bdi>[[a]]</bdi></sup></bdi>'], '']);
|
|
104
|
+
assert.deepStrictEqual(inspect(parser('<bdi>((<bdi>((a))</bdi>))</bdi>')), [['<bdi><sup class="annotation"><span><bdi><span class="paren">((a))</span></bdi></span></sup></bdi>'], '']);
|
|
105
|
+
assert.deepStrictEqual(inspect(parser('<bdi>[[<bdi>[[a]]</bdi>]]</bdi>')), [['<bdi><sup class="reference"><span><bdi>[[a]]</bdi></span></sup></bdi>'], '']);
|
|
106
106
|
assert.deepStrictEqual(inspect(parser('*[*]')), [['*', '[', '*', ']'], '']);
|
|
107
107
|
assert.deepStrictEqual(inspect(parser('*<*>')), [['<em><</em>', '>'], '']);
|
|
108
|
-
assert.deepStrictEqual(inspect(parser('*a((b))*')), [['<em>a<sup class="annotation">b</sup></em>'], '']);
|
|
108
|
+
assert.deepStrictEqual(inspect(parser('*a((b))*')), [['<em>a<sup class="annotation"><span>b</span></sup></em>'], '']);
|
|
109
109
|
assert.deepStrictEqual(inspect(parser('``a`')), [['``', 'a', '`'], '']);
|
|
110
110
|
assert.deepStrictEqual(inspect(parser('[@a]')), [['[', '<a href="/@a" class="account">@a</a>', ']'], '']);
|
|
111
111
|
assert.deepStrictEqual(inspect(parser('[#1][#2]')), [['<a class="index" href="#index:1">1</a>', '<a class="index" href="#index:2">2</a>'], '']);
|
|
@@ -115,10 +115,10 @@ describe('Unit: parser/inline', () => {
|
|
|
115
115
|
assert.deepStrictEqual(inspect(parser('$-1, $-2')), [['<a class="label" data-label="$-1">$-1</a>', ',', ' ', '<a class="label" data-label="$-2">$-2</a>'], '']);
|
|
116
116
|
assert.deepStrictEqual(inspect(parser('$-1 and $-2')), [['<a class="label" data-label="$-1">$-1</a>', ' ', 'and', ' ', '<a class="label" data-label="$-2">$-2</a>'], '']);
|
|
117
117
|
assert.deepStrictEqual(inspect(parser('$$-1')), [['$', '<a class="label" data-label="$-1">$-1</a>'], '']);
|
|
118
|
-
assert.deepStrictEqual(inspect(parser('[[#a]]')), [['<sup class="reference"><a href="/hashtags/a" class="hashtag">#a</a></sup>'], '']);
|
|
119
|
-
assert.deepStrictEqual(inspect(parser('[[$-1]]')), [['<sup class="reference"><a class="label" data-label="$-1">$-1</a></sup>'], '']);
|
|
120
|
-
assert.deepStrictEqual(inspect(parser('[[#-1]]{b}')), [['<sup class="reference">#-1</sup>', '<a href="b">b</a>'], '']);
|
|
121
|
-
assert.deepStrictEqual(inspect(parser('[[#-1]](b)')), [['<sup class="reference">#-1</sup>', '(', 'b', ')'], '']);
|
|
118
|
+
assert.deepStrictEqual(inspect(parser('[[#a]]')), [['<sup class="reference"><span><a href="/hashtags/a" class="hashtag">#a</a></span></sup>'], '']);
|
|
119
|
+
assert.deepStrictEqual(inspect(parser('[[$-1]]')), [['<sup class="reference"><span><a class="label" data-label="$-1">$-1</a></span></sup>'], '']);
|
|
120
|
+
assert.deepStrictEqual(inspect(parser('[[#-1]]{b}')), [['<sup class="reference"><span>#-1</span></sup>', '<a href="b">b</a>'], '']);
|
|
121
|
+
assert.deepStrictEqual(inspect(parser('[[#-1]](b)')), [['<sup class="reference"><span>#-1</span></sup>', '(', 'b', ')'], '']);
|
|
122
122
|
assert.deepStrictEqual(inspect(parser('[[#-1]a]{b}')), [['<a href="b">[#-1]a</a>'], '']);
|
|
123
123
|
assert.deepStrictEqual(inspect(parser('[[#-1]a](b)')), [['[', '<a class="index" href="#index:-1">-1</a>', 'a', ']', '(', 'b', ')'], '']);
|
|
124
124
|
assert.deepStrictEqual(inspect(parser('[#a]{b}')), [['<a class="index" href="#index:a">a</a>', '<a href="b">b</a>'], '']);
|
|
@@ -142,18 +142,18 @@ describe('Unit: parser/inline', () => {
|
|
|
142
142
|
assert.deepStrictEqual(inspect(parser('${{{a}}}')), [['$', '<span class="template">{{{a}}}</span>'], '']);
|
|
143
143
|
assert.deepStrictEqual(inspect(parser('Di$ney Micro$oft')), [['Di', '$', 'ney', ' ', 'Micro', '$', 'oft'], '']);
|
|
144
144
|
assert.deepStrictEqual(inspect(parser('Di$ney, Micro$oft')), [['Di', '$', 'ney', ',', ' ', 'Micro', '$', 'oft'], '']);
|
|
145
|
-
assert.deepStrictEqual(inspect(parser('(((a))')), [['(', '<sup class="annotation">a</sup>'], '']);
|
|
146
|
-
assert.deepStrictEqual(inspect(parser('((((a))')), [['(', '(', '<sup class="annotation">a</sup>'], '']);
|
|
147
|
-
assert.deepStrictEqual(inspect(parser('((((a))))')), [['<sup class="annotation"><span class="paren">((a))</span></sup>'], '']);
|
|
148
|
-
assert.deepStrictEqual(inspect(parser('"((""))')), [['"', '<sup class="annotation">""</sup>'], '']);
|
|
149
|
-
assert.deepStrictEqual(inspect(parser('[[[a]]')), [['[', '<sup class="reference">a</sup>'], '']);
|
|
150
|
-
assert.deepStrictEqual(inspect(parser('[[[[a]]')), [['[', '[', '<sup class="reference">a</sup>'], '']);
|
|
151
|
-
assert.deepStrictEqual(inspect(parser('[[[[a]]]]')), [['<sup class="reference">[[a]]</sup>'], '']);
|
|
152
|
-
assert.deepStrictEqual(inspect(parser('[[[$-1]]]')), [['<sup class="reference"><a class="label" data-label="$-1">$-1</a></sup>'], '']);
|
|
153
|
-
assert.deepStrictEqual(inspect(parser('[[[]{a}]]')), [['<sup class="reference"><a href="a">a</a></sup>'], '']);
|
|
154
|
-
assert.deepStrictEqual(inspect(parser('[[[a]{b}]]')), [['<sup class="reference"><a href="b">a</a></sup>'], '']);
|
|
145
|
+
assert.deepStrictEqual(inspect(parser('(((a))')), [['(', '<sup class="annotation"><span>a</span></sup>'], '']);
|
|
146
|
+
assert.deepStrictEqual(inspect(parser('((((a))')), [['(', '(', '<sup class="annotation"><span>a</span></sup>'], '']);
|
|
147
|
+
assert.deepStrictEqual(inspect(parser('((((a))))')), [['<sup class="annotation"><span><span class="paren">((a))</span></span></sup>'], '']);
|
|
148
|
+
assert.deepStrictEqual(inspect(parser('"((""))')), [['"', '<sup class="annotation"><span>""</span></sup>'], '']);
|
|
149
|
+
assert.deepStrictEqual(inspect(parser('[[[a]]')), [['[', '<sup class="reference"><span>a</span></sup>'], '']);
|
|
150
|
+
assert.deepStrictEqual(inspect(parser('[[[[a]]')), [['[', '[', '<sup class="reference"><span>a</span></sup>'], '']);
|
|
151
|
+
assert.deepStrictEqual(inspect(parser('[[[[a]]]]')), [['<sup class="reference"><span>[[a]]</span></sup>'], '']);
|
|
152
|
+
assert.deepStrictEqual(inspect(parser('[[[$-1]]]')), [['<sup class="reference"><span><a class="label" data-label="$-1">$-1</a></span></sup>'], '']);
|
|
153
|
+
assert.deepStrictEqual(inspect(parser('[[[]{a}]]')), [['<sup class="reference"><span><a href="a">a</a></span></sup>'], '']);
|
|
154
|
+
assert.deepStrictEqual(inspect(parser('[[[a]{b}]]')), [['<sup class="reference"><span><a href="b">a</a></span></sup>'], '']);
|
|
155
155
|
assert.deepStrictEqual(inspect(parser('[(([a]{#}))]{#}')), [['<a href="#"><span class="paren">(<span class="paren">([a]{#})</span>)</span></a>'], '']);
|
|
156
|
-
assert.deepStrictEqual(inspect(parser('"[[""]]')), [['"', '<sup class="reference">""</sup>'], '']);
|
|
156
|
+
assert.deepStrictEqual(inspect(parser('"[[""]]')), [['"', '<sup class="reference"><span>""</span></sup>'], '']);
|
|
157
157
|
assert.deepStrictEqual(inspect(parser('<http://host>')), [['<', '<a href="http://host" target="_blank">http://host</a>', '>'], '']);
|
|
158
158
|
assert.deepStrictEqual(inspect(parser('<<small>a<</small>')), [['<', '<small>a<</small>'], '']);
|
|
159
159
|
assert.deepStrictEqual(inspect(parser('<sup><sub>a</sub>')), [['<', 'sup', '>', '<sub>a</sub>'], '']);
|
|
@@ -229,8 +229,8 @@ describe('Unit: parser/inline', () => {
|
|
|
229
229
|
assert.deepStrictEqual(inspect(parser('a\n#b')), [['a', '<br>', '<a href="/hashtags/b" class="hashtag">#b</a>'], '']);
|
|
230
230
|
assert.deepStrictEqual(inspect(parser('a\\\n#b')), [['a', '<span class="linebreak"> </span>', '<a href="/hashtags/b" class="hashtag">#b</a>'], '']);
|
|
231
231
|
assert.deepStrictEqual(inspect(parser('*a*#b')), [['<em>a</em>', '<a href="/hashtags/b" class="hashtag">#b</a>'], '']);
|
|
232
|
-
assert.deepStrictEqual(inspect(parser('((a))#b')), [['<sup class="annotation">a</sup>', '<a href="/hashtags/b" class="hashtag">#b</a>'], '']);
|
|
233
|
-
assert.deepStrictEqual(inspect(parser('[[a]]#b')), [['<sup class="reference">a</sup>', '<a href="/hashtags/b" class="hashtag">#b</a>'], '']);
|
|
232
|
+
assert.deepStrictEqual(inspect(parser('((a))#b')), [['<sup class="annotation"><span>a</span></sup>', '<a href="/hashtags/b" class="hashtag">#b</a>'], '']);
|
|
233
|
+
assert.deepStrictEqual(inspect(parser('[[a]]#b')), [['<sup class="reference"><span>a</span></sup>', '<a href="/hashtags/b" class="hashtag">#b</a>'], '']);
|
|
234
234
|
assert.deepStrictEqual(inspect(parser('[#a')), [['[', '<a href="/hashtags/a" class="hashtag">#a</a>'], '']);
|
|
235
235
|
assert.deepStrictEqual(inspect(parser('|#a')), [['|', '<a href="/hashtags/a" class="hashtag">#a</a>'], '']);
|
|
236
236
|
assert.deepStrictEqual(inspect(parser(' #a')), [[' ', '<a href="/hashtags/a" class="hashtag">#a</a>'], '']);
|
|
@@ -10,7 +10,7 @@ describe('Unit: parser/locale', () => {
|
|
|
10
10
|
assert.deepStrictEqual(inspect(parser('。\\\n0')), [['<p>。<span class="linebreak"></span>0</p>'], '']);
|
|
11
11
|
assert.deepStrictEqual(inspect(parser('。 \\\n0')), [['<p>。<span class="linebreak"></span>0</p>'], '']);
|
|
12
12
|
assert.deepStrictEqual(inspect(parser('*。*\\\n0')), [['<p><em>。</em><span class="linebreak"></span>0</p>'], '']);
|
|
13
|
-
assert.deepStrictEqual(inspect(parser('!> 。\\\n0')), [['<blockquote><section><p>。<span class="linebreak"></span>0</p><ol class="
|
|
13
|
+
assert.deepStrictEqual(inspect(parser('!> 。\\\n0')), [['<blockquote><section><p>。<span class="linebreak"></span>0</p><ol class="references"></ol></section></blockquote>'], '']);
|
|
14
14
|
assert.deepStrictEqual(inspect(parser('[。](a)\\\n0')), [['<p><ruby>。<rp>(</rp><rt>a</rt><rp>)</rp></ruby><span class="linebreak"></span>0</p>'], '']);
|
|
15
15
|
assert.deepStrictEqual(inspect(parser('[。 ](a )\\\n0')), [['<p><ruby>。<rp>(</rp><rt>a</rt><rp>)</rp></ruby><span class="linebreak"></span>0</p>'], '']);
|
|
16
16
|
assert.deepStrictEqual(inspect(parser('。<wbr>\\\n0')), [['<p>。<wbr><span class="linebreak"></span>0</p>'], '']);
|
|
@@ -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,14 @@ import { push } from 'spica/array';
|
|
|
6
6
|
|
|
7
7
|
export function* figure(
|
|
8
8
|
target: ParentNode & Node,
|
|
9
|
-
footnotes?: Readonly<{ annotations
|
|
9
|
+
footnotes?: Readonly<{ annotations?: HTMLOListElement; references: HTMLOListElement; }>,
|
|
10
10
|
opts: Readonly<{
|
|
11
11
|
id?: string;
|
|
12
12
|
}> = {},
|
|
13
13
|
): Generator<HTMLAnchorElement | undefined, undefined, undefined> {
|
|
14
14
|
const refs = new MultiMap<string, HTMLAnchorElement>(push(push(push([],
|
|
15
15
|
target.querySelectorAll('a.label:not(.disabled)[data-label]')),
|
|
16
|
-
footnotes?.annotations
|
|
16
|
+
footnotes?.annotations?.querySelectorAll('a.label:not(.disabled)') ?? []),
|
|
17
17
|
footnotes?.references.querySelectorAll('a.label:not(.disabled)') ?? [])
|
|
18
18
|
.map(el => [el.getAttribute('data-label')!, el]));
|
|
19
19
|
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,64 @@
|
|
|
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?: Readonly<{ annotations
|
|
9
|
+
footnotes?: Readonly<{ annotations?: HTMLOListElement; references: HTMLOListElement; }>,
|
|
10
10
|
opts: Readonly<{ id?: string; }> = {},
|
|
11
11
|
): Generator<HTMLAnchorElement | HTMLLIElement | undefined, undefined, undefined> {
|
|
12
|
-
yield* reference(target, footnotes?.references, opts
|
|
13
|
-
yield* annotation(target, footnotes?.annotations, opts
|
|
12
|
+
yield* reference(target, footnotes?.references, opts);
|
|
13
|
+
yield* annotation(target, footnotes?.annotations, opts);
|
|
14
14
|
return;
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
export const annotation = build('annotation', n => `*${n}
|
|
17
|
+
export const annotation = build('annotation', n => `*${n}`, 'h1, h2, h3, h4, h5, h6, aside.aside, hr');
|
|
18
18
|
export const reference = build('reference', (n, abbr) => `[${abbr || n}]`);
|
|
19
19
|
|
|
20
20
|
function build(
|
|
21
|
-
syntax:
|
|
21
|
+
syntax: 'annotation' | 'reference',
|
|
22
22
|
marker: (index: number, abbr: string | undefined) => string,
|
|
23
|
+
splitter?: string,
|
|
23
24
|
) {
|
|
24
25
|
assert(syntax.match(/^[a-z]+$/));
|
|
25
26
|
// Referenceを含むAnnotationの重複排除は両構文が互いに処理済みであることを必要とするため
|
|
26
27
|
// 構文ごとに各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
28
|
return function* (
|
|
34
29
|
target: ParentNode & Node,
|
|
35
30
|
footnote?: HTMLOListElement,
|
|
36
31
|
opts: Readonly<{ id?: string }> = {},
|
|
37
|
-
footnotes: readonly HTMLOListElement[] = [],
|
|
38
32
|
): Generator<HTMLAnchorElement | HTMLLIElement | undefined, undefined, undefined> {
|
|
33
|
+
//assert(syntax !== 'annotation' || !footnote);
|
|
39
34
|
const defs = new Map<string, HTMLLIElement>();
|
|
40
35
|
const buffer = new MultiMap<string, HTMLElement>();
|
|
41
36
|
const titles = new Map<string, string>();
|
|
42
|
-
|
|
37
|
+
// Bug: Firefox
|
|
38
|
+
//const splitters = push([], target.querySelectorAll(`:scope > :is(${splitter ?? '_'})`));
|
|
39
|
+
const splitters = push([], target.querySelectorAll(splitter ?? '_'))
|
|
40
|
+
.filter(el => el.parentNode === target);
|
|
41
|
+
// Bug: Firefox
|
|
42
|
+
//target.querySelectorAll(`:scope > .${syntax}s`).forEach(el => el.remove());
|
|
43
|
+
target.querySelectorAll(`.${syntax}s`).forEach(el => el.parentNode === target && el.remove());
|
|
44
|
+
let offset = 0;
|
|
43
45
|
let style: 'count' | 'abbr';
|
|
44
46
|
for (
|
|
45
47
|
let refs = target.querySelectorAll(`sup.${syntax}:not(.disabled)`),
|
|
46
48
|
i = 0, len = refs.length; i < len; ++i) {
|
|
47
49
|
yield;
|
|
48
50
|
const ref = refs[i];
|
|
49
|
-
|
|
50
|
-
|
|
51
|
+
while (+splitters[0]?.compareDocumentPosition(ref) & Node.DOCUMENT_POSITION_FOLLOWING) {
|
|
52
|
+
if (defs.size > 0) {
|
|
53
|
+
offset += defs.size;
|
|
54
|
+
yield* proc(defs, target.insertBefore(html('ol', { class: `${syntax}s` }), splitters[0] ?? null));
|
|
55
|
+
}
|
|
56
|
+
splitters.shift();
|
|
57
|
+
}
|
|
58
|
+
if (syntax === 'annotation' && ref.closest('#annotations, .annotations, #references, .references')) continue;
|
|
59
|
+
const identifier = `${+!ref.querySelector('.label')}:${ref.getAttribute('data-abbr') || '_' + ref.firstElementChild!.innerHTML}`;
|
|
51
60
|
const abbr = ref.getAttribute('data-abbr') || undefined;
|
|
52
|
-
const content =
|
|
61
|
+
const content = frag(ref.firstElementChild!.cloneNode(true).childNodes);
|
|
53
62
|
style ??= abbr ? 'abbr' : 'count';
|
|
54
63
|
if (style === 'count' ? abbr : !abbr) {
|
|
55
64
|
define(ref, {
|
|
@@ -59,8 +68,16 @@ function build(
|
|
|
59
68
|
'data-invalid-message': `${syntax[0].toUpperCase() + syntax.slice(1)} style must be consistent`,
|
|
60
69
|
});
|
|
61
70
|
}
|
|
62
|
-
if (ref.
|
|
63
|
-
ref
|
|
71
|
+
else if (ref.getAttribute('data-invalid-type') === 'style') {
|
|
72
|
+
define(ref, {
|
|
73
|
+
class: void ref.classList.remove('invalid'),
|
|
74
|
+
'data-invalid-syntax': null,
|
|
75
|
+
'data-invalid-type': null,
|
|
76
|
+
'data-invalid-message': null,
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
if (!ref.firstElementChild!.hasAttribute('hidden')) {
|
|
80
|
+
ref.firstElementChild!.setAttribute('hidden', '');
|
|
64
81
|
}
|
|
65
82
|
else {
|
|
66
83
|
ref.lastChild?.remove();
|
|
@@ -71,9 +88,11 @@ function build(
|
|
|
71
88
|
|| text(content).trim()
|
|
72
89
|
|| content.textContent!.trim()
|
|
73
90
|
|| undefined;
|
|
91
|
+
assert(syntax !== 'annotation' || title);
|
|
74
92
|
title
|
|
75
93
|
? !titles.has(identifier) && titles.set(identifier, title)
|
|
76
94
|
: buffer.set(identifier, ref);
|
|
95
|
+
assert(syntax !== 'annotation' || !buffer.has(identifier));
|
|
77
96
|
const blank = !!abbr && !content.firstChild;
|
|
78
97
|
const refIndex = i + 1;
|
|
79
98
|
const refId = opts.id !== ''
|
|
@@ -82,7 +101,10 @@ function build(
|
|
|
82
101
|
const def = undefined
|
|
83
102
|
|| defs.get(identifier)
|
|
84
103
|
|| defs.set(identifier, html('li',
|
|
85
|
-
{
|
|
104
|
+
{
|
|
105
|
+
id: opts.id !== '' ? `${syntax}:${opts.id ? `${opts.id}:` : ''}def:${defs.size + offset + 1}` : undefined,
|
|
106
|
+
'data-marker': !footnote ? marker(defs.size + offset + 1, abbr) : undefined,
|
|
107
|
+
},
|
|
86
108
|
[content.cloneNode(true), html('sup')]))
|
|
87
109
|
.get(identifier)!;
|
|
88
110
|
assert(def.lastChild);
|
|
@@ -100,7 +122,7 @@ function build(
|
|
|
100
122
|
});
|
|
101
123
|
}
|
|
102
124
|
}
|
|
103
|
-
const defIndex = +def.id.slice(def.id.lastIndexOf(':') + 1) || defs.size;
|
|
125
|
+
const defIndex = +def.id.slice(def.id.lastIndexOf(':') + 1) || defs.size + offset;
|
|
104
126
|
const defId = def.id || undefined;
|
|
105
127
|
define(ref, {
|
|
106
128
|
id: refId,
|
|
@@ -125,13 +147,20 @@ function build(
|
|
|
125
147
|
},
|
|
126
148
|
`^${refIndex}`));
|
|
127
149
|
}
|
|
128
|
-
if (
|
|
150
|
+
if (defs.size > 0 || footnote) {
|
|
151
|
+
yield* proc(defs, footnote ?? target.insertBefore(html('ol', { class: `${syntax}s` }), splitters[0] ?? target.querySelector(':scope > :is(#annotations, #references)')));
|
|
152
|
+
}
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
function* proc(defs: Map<string, HTMLLIElement>, footnote: HTMLOListElement): Generator<HTMLLIElement | undefined, undefined, undefined> {
|
|
129
157
|
const { children } = footnote;
|
|
130
158
|
const size = defs.size;
|
|
131
159
|
let count = 0;
|
|
132
160
|
let length = children.length;
|
|
133
161
|
I:
|
|
134
|
-
for (const def of defs
|
|
162
|
+
for (const [key, def] of defs) {
|
|
163
|
+
defs.delete(key);
|
|
135
164
|
++count;
|
|
136
165
|
while (length > size) {
|
|
137
166
|
const node = children[count - 1] as HTMLLIElement;
|
package/src/parser/source/str.ts
CHANGED
|
@@ -30,13 +30,13 @@ export function stropt(pattern: string | RegExp): Parser<string, Context<StrPars
|
|
|
30
30
|
if (source === '') return;
|
|
31
31
|
return source.slice(0, pattern.length) === pattern
|
|
32
32
|
? [[pattern], source.slice(pattern.length)]
|
|
33
|
-
:
|
|
33
|
+
: undefined;
|
|
34
34
|
})
|
|
35
35
|
: creator(source => {
|
|
36
36
|
if (source === '') return;
|
|
37
37
|
const m = source.match(pattern);
|
|
38
38
|
return m
|
|
39
39
|
? [[m[0]], source.slice(m[0].length)]
|
|
40
|
-
:
|
|
40
|
+
: undefined;
|
|
41
41
|
});
|
|
42
42
|
}
|
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(
|
|
@@ -139,16 +139,20 @@ function isVisible(node: HTMLElement | string, strpos?: number): boolean {
|
|
|
139
139
|
|
|
140
140
|
export function trimBlank<P extends Parser<HTMLElement | string>>(parser: P): P;
|
|
141
141
|
export function trimBlank<T extends HTMLElement | string>(parser: Parser<T>): Parser<T> {
|
|
142
|
-
return
|
|
143
|
-
trimBlankStart(parser),
|
|
144
|
-
trimNodeEnd);
|
|
142
|
+
return trimBlankStart(trimBlankEnd(parser));
|
|
145
143
|
}
|
|
146
|
-
function trimBlankStart<P extends Parser<unknown>>(parser: P): P;
|
|
147
|
-
function trimBlankStart<T>(parser: Parser<T>): Parser<T> {
|
|
144
|
+
export function trimBlankStart<P extends Parser<unknown>>(parser: P): P;
|
|
145
|
+
export function trimBlankStart<T>(parser: Parser<T>): Parser<T> {
|
|
148
146
|
return convert(
|
|
149
147
|
reduce(source => source.replace(regBlankStart, '')),
|
|
150
148
|
parser);
|
|
151
149
|
}
|
|
150
|
+
export function trimBlankEnd<P extends Parser<HTMLElement | string>>(parser: P): P;
|
|
151
|
+
export function trimBlankEnd<T extends HTMLElement | string>(parser: Parser<T>): Parser<T> {
|
|
152
|
+
return fmap(
|
|
153
|
+
parser,
|
|
154
|
+
trimNodeEnd);
|
|
155
|
+
}
|
|
152
156
|
//export function trimNode(nodes: (HTMLElement | string)[]): (HTMLElement | string)[] {
|
|
153
157
|
// return trimNodeStart(trimNodeEnd(nodes));
|
|
154
158
|
//}
|
|
@@ -166,7 +170,7 @@ function trimBlankStart<T>(parser: Parser<T>): Parser<T> {
|
|
|
166
170
|
// }
|
|
167
171
|
// return nodes;
|
|
168
172
|
//}
|
|
169
|
-
|
|
173
|
+
function trimNodeEnd<T extends HTMLElement | string>(nodes: T[]): T[] {
|
|
170
174
|
const skip = nodes.length > 0 &&
|
|
171
175
|
typeof nodes[nodes.length - 1] === 'object' &&
|
|
172
176
|
nodes[nodes.length - 1]['className'] === 'indexer'
|
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
|
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import { indentblock } from './indentblock';
|
|
2
|
-
import { some } from '../../combinator';
|
|
3
|
-
import { inspect } from '../../debug.test';
|
|
4
|
-
|
|
5
|
-
describe('Unit: parser/block/indentblock', () => {
|
|
6
|
-
describe('indentblock', () => {
|
|
7
|
-
const parser = (source: string) => some(indentblock)(source, {});
|
|
8
|
-
|
|
9
|
-
it('invalid', () => {
|
|
10
|
-
assert.deepStrictEqual(inspect(parser('')), undefined);
|
|
11
|
-
assert.deepStrictEqual(inspect(parser('\na')), undefined);
|
|
12
|
-
assert.deepStrictEqual(inspect(parser(' a')), undefined);
|
|
13
|
-
assert.deepStrictEqual(inspect(parser(' \ta')), undefined);
|
|
14
|
-
assert.deepStrictEqual(inspect(parser(' a\nb')), undefined);
|
|
15
|
-
assert.deepStrictEqual(inspect(parser(' a\n b')), undefined);
|
|
16
|
-
});
|
|
17
|
-
|
|
18
|
-
it('valid', () => {
|
|
19
|
-
assert.deepStrictEqual(inspect(parser(' a')), [['<pre class="text">a</pre>'], '']);
|
|
20
|
-
assert.deepStrictEqual(inspect(parser(' a ')), [['<pre class="text">a </pre>'], '']);
|
|
21
|
-
assert.deepStrictEqual(inspect(parser(' a \n')), [['<pre class="text">a </pre>'], '']);
|
|
22
|
-
assert.deepStrictEqual(inspect(parser(' a \n b')), [['<pre class="text">a <br> b</pre>'], '']);
|
|
23
|
-
assert.deepStrictEqual(inspect(parser(' a\\\n b')), [['<pre class="text">a\\<br>b</pre>'], '']);
|
|
24
|
-
assert.deepStrictEqual(inspect(parser('\ta')), [['<pre class="text">a</pre>'], '']);
|
|
25
|
-
assert.deepStrictEqual(inspect(parser('\t a')), [['<pre class="text"> a</pre>'], '']);
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
});
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { IndentBlockParser } from '../block';
|
|
2
|
-
import { union, block, validate, indent, convert } from '../../combinator';
|
|
3
|
-
import { codeblock } from './codeblock';
|
|
4
|
-
|
|
5
|
-
// 空行を含むインデントブロックはインデントの違いによるセグメント分割の境界が視認不能となるため採用しない
|
|
6
|
-
|
|
7
|
-
export const indentblock: IndentBlockParser = block(validate(/^(?: |\t)/, indent(convert(
|
|
8
|
-
source => {
|
|
9
|
-
const fence = (source.match(/^`{3,}(?=[^\S\n]*$)/mg) ?? [])
|
|
10
|
-
.reduce((max, fence) => fence > max ? fence : max, '``') + '`';
|
|
11
|
-
return `${fence}\n${source}\n${fence}`;
|
|
12
|
-
},
|
|
13
|
-
union([codeblock])), true)));
|