securemark 0.300.0 → 0.300.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 +4 -0
- package/dist/index.js +197 -113
- package/package.json +1 -1
- package/src/api/bind.ts +2 -2
- package/src/api/parse.ts +2 -2
- package/src/combinator/control/inits.ts +13 -4
- package/src/combinator/control/sequence.ts +3 -1
- package/src/combinator/control/state.ts +1 -10
- package/src/combinator/control/union.ts +16 -3
- package/src/combinator/parser.ts +18 -8
- package/src/combinator/process/fence.ts +3 -3
- package/src/combinator/process/surround.ts +2 -0
- package/src/parser/block/codeblock.test.ts +0 -2
- package/src/parser/block/codeblock.ts +3 -3
- package/src/parser/block/extension/aside.test.ts +0 -1
- package/src/parser/block/extension/aside.ts +1 -1
- package/src/parser/block/extension/example.test.ts +0 -2
- package/src/parser/block/extension/example.ts +1 -1
- package/src/parser/block/extension/figure.test.ts +0 -4
- package/src/parser/block/extension/figure.ts +1 -1
- package/src/parser/block/extension/message.test.ts +0 -1
- package/src/parser/block/extension/message.ts +1 -1
- package/src/parser/block/extension/placeholder.ts +3 -3
- package/src/parser/block/extension/table.test.ts +0 -1
- package/src/parser/block/extension/table.ts +3 -3
- package/src/parser/block/mathblock.test.ts +0 -2
- package/src/parser/block/mathblock.ts +3 -3
- package/src/parser/context.ts +9 -12
- package/src/parser/document.ts +1 -1
- package/src/parser/inline/autolink/url.ts +4 -4
- package/src/parser/inline/math.ts +1 -1
- package/src/parser/inline/media.ts +4 -4
- package/src/parser/inline/ruby.ts +45 -8
- package/src/parser/inline/template.ts +4 -4
- package/src/parser/source/escapable.ts +0 -1
- package/src/parser/source/text.ts +14 -43
- package/src/parser/source/unescapable.ts +0 -1
- package/src/parser/source/whitespace.ts +36 -0
- package/src/parser/source.ts +1 -0
- package/src/parser/visibility.ts +2 -1
package/package.json
CHANGED
package/src/api/bind.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ParserSettings, Progress } from '../..';
|
|
2
2
|
import { Input, Options, Segment } from '../parser/context';
|
|
3
|
-
import { Output,
|
|
3
|
+
import { Output, run } from '../combinator/parser';
|
|
4
4
|
import { segment } from '../parser/segment';
|
|
5
5
|
import { block } from '../parser/block';
|
|
6
6
|
import { headers } from './header';
|
|
@@ -74,7 +74,7 @@ export function bind(target: DocumentFragment | HTMLElement | ShadowRoot, settin
|
|
|
74
74
|
assert(rev === revision);
|
|
75
75
|
const seg = sourceSegments[index];
|
|
76
76
|
options.segment = sourceSegmentAttrs[index] | Segment.write;
|
|
77
|
-
for (const _ of run(block,
|
|
77
|
+
for (const _ of run(block, new Input(options, seg), output)) {
|
|
78
78
|
yield { type: 'break' };
|
|
79
79
|
}
|
|
80
80
|
assert(output.data.length === 1);
|
package/src/api/parse.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ParserOptions } from '../..';
|
|
2
|
-
import { Input, Options
|
|
2
|
+
import { Input, Options } from '../parser/context';
|
|
3
3
|
import { Output, run } from '../combinator/parser';
|
|
4
4
|
import { document } from '../parser/document';
|
|
5
5
|
import { ReadonlyURL } from 'spica/url';
|
|
@@ -23,7 +23,7 @@ export function* parse(source: string, opts: Opts = {}, options?: Options): Gene
|
|
|
23
23
|
if (options.id?.match(/[^0-9a-z/-]/i)) throw new Error('Invalid ID: ID must be alphanumeric');
|
|
24
24
|
if (options.host?.origin === 'null') throw new Error(`Invalid host: ${options.host.href}`);
|
|
25
25
|
const output = new Output<DocumentFragment>();
|
|
26
|
-
for (const _ of run(document,
|
|
26
|
+
for (const _ of run(document, new Input(options, source), output)) yield;
|
|
27
27
|
assert(output.data.length === 1);
|
|
28
28
|
assert(output.peek().length === 1);
|
|
29
29
|
return output.peek().head!.value;
|
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
import { Parser, SubParsers } from '../parser';
|
|
1
|
+
import { Parser, SubParsers, Result } from '../parser';
|
|
2
2
|
import { union } from './union';
|
|
3
3
|
import { sequence } from './sequence';
|
|
4
|
-
import { recovery } from './state';
|
|
5
4
|
|
|
6
5
|
export function inits<P extends Parser>(parsers: Parser.SubParsers<P>): P;
|
|
7
6
|
export function inits<T>(parsers: SubParsers<T>): Parser<T> {
|
|
8
7
|
assert(parsers.every(f => f));
|
|
9
8
|
switch (parsers.length) {
|
|
10
9
|
case 0:
|
|
10
|
+
assert(false);
|
|
11
11
|
return (_, output) => output.context;
|
|
12
12
|
case 1:
|
|
13
|
-
return
|
|
13
|
+
return parsers[0];
|
|
14
14
|
default:
|
|
15
15
|
return parsers.reduceRight((acc, parser, i) =>
|
|
16
16
|
sequence([
|
|
@@ -19,8 +19,17 @@ export function inits<T>(parsers: SubParsers<T>): Parser<T> {
|
|
|
19
19
|
? acc
|
|
20
20
|
: union([
|
|
21
21
|
acc,
|
|
22
|
-
recovery
|
|
22
|
+
recovery,
|
|
23
23
|
]),
|
|
24
24
|
]));
|
|
25
25
|
}
|
|
26
26
|
}
|
|
27
|
+
|
|
28
|
+
const recovery: Parser<never> = (_, output) => {
|
|
29
|
+
if (output.state) {
|
|
30
|
+
output.state = true;
|
|
31
|
+
// @ts-expect-error
|
|
32
|
+
output.context ??= Result.succ;
|
|
33
|
+
}
|
|
34
|
+
return output.context;
|
|
35
|
+
};
|
|
@@ -6,8 +6,10 @@ export function sequence<T>(parsers: SubParsers<T>): Parser<T> {
|
|
|
6
6
|
assert(parsers.every(f => f));
|
|
7
7
|
switch (parsers.length) {
|
|
8
8
|
case 0:
|
|
9
|
+
assert(false);
|
|
10
|
+
return (_, output) => output.context;
|
|
9
11
|
case 1:
|
|
10
|
-
return
|
|
12
|
+
return parsers[0];
|
|
11
13
|
default:
|
|
12
14
|
return parsers.reduceRight((acc, parser) => always([
|
|
13
15
|
parser,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Parser, SubParsers
|
|
1
|
+
import { Parser, SubParsers } from '../parser';
|
|
2
2
|
|
|
3
3
|
export function then<P extends Parser>(success: P, failure: P): P;
|
|
4
4
|
export function then<T>(success: Parser<T>, failure: Parser<T>): Parser<T> {
|
|
@@ -31,12 +31,3 @@ export function force<T>(parser: Parser<T>): Parser<T> {
|
|
|
31
31
|
? output.context
|
|
32
32
|
: parser(input, output);
|
|
33
33
|
}
|
|
34
|
-
|
|
35
|
-
export function recovery<P extends Parser>(parser?: P): P;
|
|
36
|
-
export function recovery<T>(parser: Parser<T> = () => Result.succ): Parser<T> {
|
|
37
|
-
return (input, output) => {
|
|
38
|
-
output.state = true;
|
|
39
|
-
output.context = Result.succ;
|
|
40
|
-
return parser(input, output);
|
|
41
|
-
};
|
|
42
|
-
}
|
|
@@ -1,14 +1,15 @@
|
|
|
1
|
-
import { Parser, SubParsers } from '../parser';
|
|
2
|
-
import { failure, always
|
|
1
|
+
import { Parser, SubParsers, Result } from '../parser';
|
|
2
|
+
import { failure, always } from './state';
|
|
3
3
|
|
|
4
4
|
export function union<P extends Parser>(parsers: Parser.SubParsers<P>): P;
|
|
5
5
|
export function union<T>(parsers: SubParsers<T>): Parser<T> {
|
|
6
6
|
assert(parsers.every(f => f));
|
|
7
7
|
switch (parsers.length) {
|
|
8
8
|
case 0:
|
|
9
|
+
assert(false);
|
|
9
10
|
return (_, output) => output.context;
|
|
10
11
|
case 1:
|
|
11
|
-
return
|
|
12
|
+
return parsers[0];
|
|
12
13
|
default:
|
|
13
14
|
return parsers.reduceRight((acc, parser) => always([
|
|
14
15
|
parser,
|
|
@@ -16,3 +17,15 @@ export function union<T>(parsers: SubParsers<T>): Parser<T> {
|
|
|
16
17
|
]));
|
|
17
18
|
}
|
|
18
19
|
}
|
|
20
|
+
|
|
21
|
+
function recovery<P extends Parser>(parser: P): P;
|
|
22
|
+
function recovery<T>(parser: Parser<T>): Parser<T> {
|
|
23
|
+
return (input, output) => {
|
|
24
|
+
if (!output.state) {
|
|
25
|
+
output.state = true;
|
|
26
|
+
// @ts-expect-error
|
|
27
|
+
output.context ??= Result.succ;
|
|
28
|
+
}
|
|
29
|
+
return parser(input, output);
|
|
30
|
+
};
|
|
31
|
+
}
|
package/src/combinator/parser.ts
CHANGED
|
@@ -140,7 +140,7 @@ export class Output<T> {
|
|
|
140
140
|
assert(data.length > 0);
|
|
141
141
|
}
|
|
142
142
|
public state: boolean = true;
|
|
143
|
-
public context: Result.Succ | Result.Fail = Result.succ;
|
|
143
|
+
public readonly context: Result.Succ | Result.Fail = Result.succ;
|
|
144
144
|
public error?: Error = undefined;
|
|
145
145
|
public peek(): List<Node<T>> {
|
|
146
146
|
assert(this.data.length > 0);
|
|
@@ -222,17 +222,24 @@ export function* run
|
|
|
222
222
|
time = Date.now();
|
|
223
223
|
}
|
|
224
224
|
if (output.state && output.error) {
|
|
225
|
-
output.state
|
|
226
|
-
|
|
225
|
+
if (output.state) {
|
|
226
|
+
output.state = false;
|
|
227
|
+
// @ts-expect-error
|
|
228
|
+
output.context = Result.fail;
|
|
229
|
+
}
|
|
227
230
|
}
|
|
228
231
|
const input = scope.peek();
|
|
229
232
|
//assert(input.position <= input.source.length);
|
|
230
|
-
const
|
|
233
|
+
const parser = queue.pop();
|
|
234
|
+
const result = parser(input, output);
|
|
231
235
|
|
|
232
236
|
if (result) {
|
|
233
237
|
//assert(result.every(f => f));
|
|
234
|
-
output.state
|
|
235
|
-
|
|
238
|
+
if (!output.state) {
|
|
239
|
+
output.state = true;
|
|
240
|
+
// @ts-expect-error
|
|
241
|
+
output.context ??= Result.succ;
|
|
242
|
+
}
|
|
236
243
|
if (result.length !== 0) {
|
|
237
244
|
if (queue.length !== 0) {
|
|
238
245
|
queue.memory = input.memory;
|
|
@@ -249,8 +256,11 @@ export function* run
|
|
|
249
256
|
if (result === Result.skip) {
|
|
250
257
|
queue.length = 0;
|
|
251
258
|
}
|
|
252
|
-
output.state
|
|
253
|
-
|
|
259
|
+
if (output.state) {
|
|
260
|
+
output.state = false;
|
|
261
|
+
// @ts-expect-error
|
|
262
|
+
output.context = Result.fail;
|
|
263
|
+
}
|
|
254
264
|
}
|
|
255
265
|
|
|
256
266
|
if (queue.length !== 0) continue;
|
|
@@ -2,7 +2,7 @@ import { Parser, SubParsers, Input, List, Node } from '../parser';
|
|
|
2
2
|
import { spend } from '../effect/clock';
|
|
3
3
|
import { firstline, isEmptyline } from './line';
|
|
4
4
|
|
|
5
|
-
export function fence<I extends Input, S extends SubParsers<never, I>>(opener: RegExp, write: boolean,
|
|
5
|
+
export function fence<I extends Input, S extends SubParsers<never, I>>(opener: RegExp, write: boolean, separation = true): Parser<string, I, S> {
|
|
6
6
|
assert(!opener.flags.match(/[gm]/) && opener.sticky && !opener.source.startsWith('^'));
|
|
7
7
|
return (input, output) => {
|
|
8
8
|
const { source, position } = input;
|
|
@@ -29,11 +29,11 @@ export function fence<I extends Input, S extends SubParsers<never, I>>(opener: R
|
|
|
29
29
|
for (let count = 1; ; ++count) {
|
|
30
30
|
if (input.position === source.length) break;
|
|
31
31
|
const line = firstline(source, input.position);
|
|
32
|
-
if (
|
|
32
|
+
if (closer && isEmptyline(line, 0)) break;
|
|
33
33
|
if(closer) {
|
|
34
34
|
overflow += line;
|
|
35
35
|
}
|
|
36
|
-
if (!closer &&
|
|
36
|
+
if (!closer && line.startsWith(delim) && line.trimEnd() === delim) {
|
|
37
37
|
closer = line;
|
|
38
38
|
if (isEmptyline(source, input.position + line.length)) {
|
|
39
39
|
input.position += line.length;
|
|
@@ -136,6 +136,7 @@ export function surround<T>(
|
|
|
136
136
|
const o = output.pop();
|
|
137
137
|
if (!g) return;
|
|
138
138
|
output.state = true;
|
|
139
|
+
// @ts-expect-error
|
|
139
140
|
output.context = Result.succ;
|
|
140
141
|
return g([o, state ? m : undefined], input, output);
|
|
141
142
|
}
|
|
@@ -156,6 +157,7 @@ export function surround<T>(
|
|
|
156
157
|
wbs && setBacktrack(input, wbs, position);
|
|
157
158
|
if (!g) return;
|
|
158
159
|
output.state = true;
|
|
160
|
+
// @ts-expect-error
|
|
159
161
|
output.context = Result.succ;
|
|
160
162
|
return g([o, state ? m : undefined], input, output);
|
|
161
163
|
}
|
|
@@ -22,7 +22,6 @@ describe('Unit: parser/block/codeblock', () => {
|
|
|
22
22
|
assert.deepStrictEqual(inspect(parser, input('```\n````')), [['<pre class="invalid" translate="no">```\n````</pre>'], '']);
|
|
23
23
|
assert.deepStrictEqual(inspect(parser, input('````\n```')), [['<pre class="invalid" translate="no">````\n```</pre>'], '']);
|
|
24
24
|
assert.deepStrictEqual(inspect(parser, input(' ```\n```')), undefined);
|
|
25
|
-
assert.deepStrictEqual(inspect(parser, input(`\`\`\`\n0${'\n'.repeat(301)}\`\`\``), '>'), [['<pre class="invalid" translate="no">'], '']);
|
|
26
25
|
});
|
|
27
26
|
|
|
28
27
|
it('basic', () => {
|
|
@@ -44,7 +43,6 @@ describe('Unit: parser/block/codeblock', () => {
|
|
|
44
43
|
assert.deepStrictEqual(inspect(parser, input('```\n!http://host)\n```')), [['<pre class="text">!<a class="url" href="http://host)" target="_blank">http://host)</a></pre>'], '']);
|
|
45
44
|
assert.deepStrictEqual(inspect(parser, input('```\n#a\n```')), [['<pre class="text"><a class="hashtag" href="/hashtags/a">#a</a></pre>'], '']);
|
|
46
45
|
assert.deepStrictEqual(inspect(parser, input('```\n@a#b\n```')), [['<pre class="text"><a class="channel" href="/@a?ch=b">@a#b</a></pre>'], '']);
|
|
47
|
-
assert.deepStrictEqual(inspect(parser, input(`\`\`\`\n0${'\n'.repeat(300)}\`\`\``), '>'), [['<pre class="text">'], '']);
|
|
48
46
|
});
|
|
49
47
|
|
|
50
48
|
it('attribute', () => {
|
|
@@ -9,13 +9,13 @@ const opener = /(`{3,})(?!`)([^\r\n]*)(?:$|\r?\n)/y;
|
|
|
9
9
|
const language = /^[0-9a-z]+(?:-[a-z][0-9a-z]*)*$/i;
|
|
10
10
|
|
|
11
11
|
export const segment: CodeBlockParser.SegmentParser = block(
|
|
12
|
-
fence(opener, false
|
|
12
|
+
fence(opener, false));
|
|
13
13
|
|
|
14
14
|
export const segment_: CodeBlockParser.SegmentParser = block(
|
|
15
|
-
fence(opener, false,
|
|
15
|
+
fence(opener, false, false), false);
|
|
16
16
|
|
|
17
17
|
export const codeblock: CodeBlockParser = block(inits([
|
|
18
|
-
fence(opener, true
|
|
18
|
+
fence(opener, true),
|
|
19
19
|
(input, output) => {
|
|
20
20
|
const [body, overflow, closer, opener, delim, param] = unwrap(output.pop()) as string[];
|
|
21
21
|
const params = param.match(/(?:\\.?|\S)+/g)?.reduce<{
|
|
@@ -11,7 +11,6 @@ describe('Unit: parser/block/extension/aside', () => {
|
|
|
11
11
|
assert.deepStrictEqual(inspect(parser, input('~~~aside\n~~~')), [['<pre class="invalid" translate="no">~~~aside\n~~~</pre>'], '']);
|
|
12
12
|
assert.deepStrictEqual(inspect(parser, input('~~~aside\n# \n~~~')), [['<pre class="invalid" translate="no">~~~aside\n# \n~~~</pre>'], '']);
|
|
13
13
|
assert.deepStrictEqual(inspect(parser, input('~~~aside a\n# 0\n~~~')), [['<pre class="invalid" translate="no">~~~aside a\n# 0\n~~~</pre>'], '']);
|
|
14
|
-
assert.deepStrictEqual(inspect(parser, input(`~~~aside\n# 0${'\n'.repeat(301)}~~~`), '>'), [['<pre class="invalid" translate="no">'], '']);
|
|
15
14
|
});
|
|
16
15
|
|
|
17
16
|
it('valid', () => {
|
|
@@ -14,7 +14,7 @@ interface Memory {
|
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
export const aside: ExtensionParser.AsideParser = block(recursion(Recursion.block, inits([
|
|
17
|
-
fence(/(~{3,})aside(?!\S)([^\r\n]*)(?:$|\r?\n)/y, true
|
|
17
|
+
fence(/(~{3,})aside(?!\S)([^\r\n]*)(?:$|\r?\n)/y, true),
|
|
18
18
|
(input: Input<Memory>, output) => {
|
|
19
19
|
const [body, overflow, closer, opener, delim, param] = unwrap(output.pop()) as string[];
|
|
20
20
|
if (!closer || overflow || param.trimStart()) {
|
|
@@ -11,7 +11,6 @@ describe('Unit: parser/block/extension/example', () => {
|
|
|
11
11
|
assert.deepStrictEqual(inspect(parser, input('~~~example/\n~~~')), undefined);
|
|
12
12
|
assert.deepStrictEqual(inspect(parser, input('~~~example/a\n~~~')), [['<pre class="invalid" translate="no">~~~example/a\n~~~</pre>'], '']);
|
|
13
13
|
assert.deepStrictEqual(inspect(parser, input('~~~example/markdown a\n~~~')), [['<pre class="invalid" translate="no">~~~example/markdown a\n~~~</pre>'], '']);
|
|
14
|
-
assert.deepStrictEqual(inspect(parser, input(`~~~example/markdown\n0${'\n'.repeat(301)}~~~`), '>'), [['<pre class="invalid" translate="no">'], '']);
|
|
15
14
|
});
|
|
16
15
|
|
|
17
16
|
it('valid', () => {
|
|
@@ -27,7 +26,6 @@ describe('Unit: parser/block/extension/example', () => {
|
|
|
27
26
|
assert.deepStrictEqual(inspect(parser, input('~~~example/markdown\n((a))[[b]]\n~~~')), [['<aside class="example" data-type="markdown"><pre translate="no">((a))[[b]]</pre><hr><section><p><sup class="annotation local" id="annotation:random:ref:a:1" title="a"><a href="#annotation:random:def:a:1">*1</a></sup><sup class="reference local" id="reference:random:ref:b:1" title="b"><a href="#reference:random:def:b">[1]</a></sup></p><ol class="annotations"><li id="annotation:random:def:a:1" data-marker="*1"><span>a</span><sup><a href="#annotation:random:ref:a:1">^1</a></sup></li></ol><h2>References</h2><ol class="references"><li id="reference:random:def:b"><span>b</span><sup><a href="#reference:random:ref:b:1">^1</a></sup></li></ol></section></aside>'], '']);
|
|
28
27
|
assert.deepStrictEqual(inspect(parser, input('~~~~example/markdown\na\n~~~~')), [['<aside class="example" data-type="markdown"><pre translate="no">a</pre><hr><section><p>a</p><h2>References</h2><ol class="references"></ol></section></aside>'], '']);
|
|
29
28
|
assert.deepStrictEqual(inspect(parser, input('~~~example/math\na\n~~~')), [['<aside class="example" data-type="math"><pre translate="no">a</pre><hr><div class="math" translate="no">$$\na\n$$</div></aside>'], '']);
|
|
30
|
-
assert.deepStrictEqual(inspect(parser, input(`~~~example/math\n0${'\n'.repeat(100)}~~~`), '>'), [['<aside class="example" data-type="math">'], '']);
|
|
31
29
|
});
|
|
32
30
|
|
|
33
31
|
});
|
|
@@ -12,7 +12,7 @@ interface Memory {
|
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
export const example: ExtensionParser.ExampleParser = block(recursion(Recursion.block, inits([
|
|
15
|
-
fence(/(~{3,})(?:example\/(\S+))?(?!\S)([^\r\n]*)(?:$|\r?\n)/y, true
|
|
15
|
+
fence(/(~{3,})(?:example\/(\S+))?(?!\S)([^\r\n]*)(?:$|\r?\n)/y, true),
|
|
16
16
|
(input: Input<Memory>, output) => {
|
|
17
17
|
const [body, overflow, closer, opener, delim, type = 'markdown', param] = unwrap(output.pop()) as string[];
|
|
18
18
|
if (!closer || overflow || param.trimStart()) return output.append(
|
|
@@ -33,8 +33,6 @@ describe('Unit: parser/block/extension/figure', () => {
|
|
|
33
33
|
assert.deepStrictEqual(inspect(parser, input('~~~figure [$fig-name]\n> \n\n~~~')), [['<figure data-type="quote" data-label="fig-name" data-group="fig" class="invalid"><figcaption><span class="figindex"></span><span class="figtext"></span></figcaption><div><blockquote></blockquote></div></figure>'], '']);
|
|
34
34
|
assert.deepStrictEqual(inspect(parser, input('~~~figure [$figure-name]\n> \n\n~~~')), [['<figure data-type="quote" data-label="figure-name" data-group="figure" class="invalid"><figcaption><span class="figindex"></span><span class="figtext"></span></figcaption><div><blockquote></blockquote></div></figure>'], '']);
|
|
35
35
|
assert.deepStrictEqual(inspect(parser, input('~~~figure [$table-name]\n> \n\n~~~')), [['<figure data-type="quote" data-label="table-name" data-group="table" class="invalid"><figcaption><span class="figindex"></span><span class="figtext"></span></figcaption><div><blockquote></blockquote></div></figure>'], '']);
|
|
36
|
-
assert.deepStrictEqual(inspect(parser, input(`~~~figure [$group-name]\n0${'\n'.repeat(301)}~~~`), '>'), [['<pre class="invalid" translate="no">'], '']);
|
|
37
|
-
assert.deepStrictEqual(inspect(parser, input(`~~~figure [$group-name]\n~~~\n0${'\n'.repeat(301)}~~~\n~~~`), '>'), [['<pre class="invalid" translate="no">'], `${'\n'.repeat(300)}~~~\n~~~`]);
|
|
38
36
|
});
|
|
39
37
|
|
|
40
38
|
it('valid', () => {
|
|
@@ -70,8 +68,6 @@ describe('Unit: parser/block/extension/figure', () => {
|
|
|
70
68
|
assert.deepStrictEqual(inspect(parser, input('~~~figure [$-0.0]\n$$\n\n$$\n~~~')), [['<figure data-type="math" data-label="$-0.0" data-group="$" class="invalid"><figcaption><span class="figindex"></span><span class="figtext"></span></figcaption><div><div class="math" translate="no">$$\n\n$$</div></div></figure>'], '']);
|
|
71
69
|
assert.deepStrictEqual(inspect(parser, input('~~~figure [$-name]\n!https://host\n~~~')), [['<figure data-type="media" data-label="$-name" data-group="$" class="invalid"><figcaption><span class="figindex"></span><span class="figtext"></span></figcaption><div><a href="https://host" target="_blank"><img class="media" data-src="https://host" alt="https://host"></a></div></figure>'], '']);
|
|
72
70
|
assert.deepStrictEqual(inspect(parser, input('~~~figure [$-name]\n$$\n\n$$\n\ncaption\n~~~')), [['<figure data-type="math" data-label="$-name" data-group="$" class="invalid"><figcaption><span class="figindex"></span><span class="figtext">caption</span></figcaption><div><div class="math" translate="no">$$\n\n$$</div></div></figure>'], '']);
|
|
73
|
-
assert.deepStrictEqual(inspect(parser, input(`~~~figure [$group-name]\n${'> \n'.repeat(500)}\n~~~`), '>'), [['<figure data-type="quote" data-label="group-name" data-group="group">'], '']);
|
|
74
|
-
assert.deepStrictEqual(inspect(parser, input(`~~~figure [$group-name]\n~~~\n0${'\n'.repeat(300)}~~~\n~~~`), '>'), [['<figure data-type="example" data-label="group-name" data-group="group">'], '']);
|
|
75
71
|
});
|
|
76
72
|
|
|
77
73
|
});
|
|
@@ -84,7 +84,7 @@ export const figure: FigureParser = block(fallback(rewrite(segment, fmap(
|
|
|
84
84
|
]);
|
|
85
85
|
})),
|
|
86
86
|
inits([
|
|
87
|
-
fence(/(~{3,})(?:figure(?=$|[ \r\n])|\[?\$)[^\r\n]*(?:$|\r?\n)/y, true
|
|
87
|
+
fence(/(~{3,})(?:figure(?=$|[ \r\n])|\[?\$)[^\r\n]*(?:$|\r?\n)/y, true),
|
|
88
88
|
(_, output) => {
|
|
89
89
|
const [body, overflow, closer, opener, delim] = unwrap(output.pop()) as string[];
|
|
90
90
|
const violation =
|
|
@@ -12,7 +12,6 @@ describe('Unit: parser/block/extension/message', () => {
|
|
|
12
12
|
assert.deepStrictEqual(inspect(parser, input('~~~message/\n~~~')), undefined);
|
|
13
13
|
assert.deepStrictEqual(inspect(parser, input('~~~message/a\n~~~')), [['<pre class="invalid" translate="no">~~~message/a\n~~~</pre>'], '']);
|
|
14
14
|
assert.deepStrictEqual(inspect(parser, input('~~~message/note a\n~~~')), [['<pre class="invalid" translate="no">~~~message/note a\n~~~</pre>'], '']);
|
|
15
|
-
assert.deepStrictEqual(inspect(parser, input(`~~~message/note\n0${'\n'.repeat(301)}~~~`), '>'), [['<pre class="invalid" translate="no">'], '']);
|
|
16
15
|
});
|
|
17
16
|
|
|
18
17
|
it('valid', () => {
|
|
@@ -20,7 +20,7 @@ import { html } from 'typed-dom/dom';
|
|
|
20
20
|
import MessageParser = ExtensionParser.MessageParser;
|
|
21
21
|
|
|
22
22
|
export const message: MessageParser = block(inits([
|
|
23
|
-
fence(/(~{3,})message\/(\S+)(?!\S)([^\r\n]*)(?:$|\r?\n)/y, true
|
|
23
|
+
fence(/(~{3,})message\/(\S+)(?!\S)([^\r\n]*)(?:$|\r?\n)/y, true),
|
|
24
24
|
(input, output) => {
|
|
25
25
|
const [body, overflow, closer, opener, delim, type, param] = unwrap(output.pop()) as string[];
|
|
26
26
|
if (!closer || overflow || param.trimStart()) {
|
|
@@ -7,13 +7,13 @@ import { html } from 'typed-dom/dom';
|
|
|
7
7
|
const opener = /(~{3,})(?!~)[^\r\n]*(?:$|\r?\n)/y;
|
|
8
8
|
|
|
9
9
|
export const segment: ExtensionParser.PlaceholderParser.SegmentParser = block(
|
|
10
|
-
fence(opener, false
|
|
10
|
+
fence(opener, false));
|
|
11
11
|
|
|
12
12
|
export const segment_: ExtensionParser.PlaceholderParser.SegmentParser = block(
|
|
13
|
-
fence(opener, false,
|
|
13
|
+
fence(opener, false, false), false);
|
|
14
14
|
|
|
15
15
|
export const placeholder: ExtensionParser.PlaceholderParser = block(inits([
|
|
16
|
-
fence(opener, true
|
|
16
|
+
fence(opener, true),
|
|
17
17
|
(_, output) => {
|
|
18
18
|
const [body, overflow, closer, opener, delim] = unwrap(output.pop()) as string[];
|
|
19
19
|
return output.append(
|
|
@@ -10,7 +10,6 @@ describe('Unit: parser/block/extension/table', () => {
|
|
|
10
10
|
|
|
11
11
|
it('invalid', () => {
|
|
12
12
|
assert.deepStrictEqual(inspect(parser, input('~~~table a\n-\n~~~')), [['<pre class="invalid" translate="no">~~~table a\n-\n~~~</pre>'], '']);
|
|
13
|
-
assert.deepStrictEqual(inspect(parser, input(`~~~table\n0${'\n'.repeat(10001)}~~~`), '>'), [['<pre class="invalid" translate="no">'], '']);
|
|
14
13
|
});
|
|
15
14
|
|
|
16
15
|
it('data', () => {
|
|
@@ -18,13 +18,13 @@ import CellParser = TableParser.CellParser;
|
|
|
18
18
|
const opener = /(~{3,})table(?:\/(\S+))?(?!\S)([^\r\n]*)(?:$|\r?\n)/y;
|
|
19
19
|
|
|
20
20
|
export const segment: TableParser.SegmentParser = block(
|
|
21
|
-
fence(opener, false
|
|
21
|
+
fence(opener, false));
|
|
22
22
|
|
|
23
23
|
export const segment_: TableParser.SegmentParser = block(
|
|
24
|
-
fence(opener, false,
|
|
24
|
+
fence(opener, false, false), false);
|
|
25
25
|
|
|
26
26
|
export const table: TableParser = block(inits([
|
|
27
|
-
fence(opener, true
|
|
27
|
+
fence(opener, true),
|
|
28
28
|
(_, output) => {
|
|
29
29
|
const [body, overflow, closer, opener, delim, type, param] = unwrap(output.pop()) as string[];
|
|
30
30
|
if (!closer || overflow || param.trimStart()) return output.append(
|
|
@@ -25,7 +25,6 @@ describe('Unit: parser/block/mathblock', () => {
|
|
|
25
25
|
assert.deepStrictEqual(inspect(parser, input('$$$\n$$')), [['<pre class="invalid" translate="no">$$$\n$$</pre>'], '']);
|
|
26
26
|
assert.deepStrictEqual(inspect(parser, input('$$$\n$$$')), [['<pre class="invalid" translate="no">$$$\n$$$</pre>'], '']);
|
|
27
27
|
assert.deepStrictEqual(inspect(parser, input(' $$\n$$')), undefined);
|
|
28
|
-
assert.deepStrictEqual(inspect(parser, input(`$$\n0${'\n'.repeat(301)}$$`), '>'), [['<pre class="invalid" translate="no">'], '']);
|
|
29
28
|
});
|
|
30
29
|
|
|
31
30
|
it('basic', () => {
|
|
@@ -40,7 +39,6 @@ describe('Unit: parser/block/mathblock', () => {
|
|
|
40
39
|
assert.deepStrictEqual(inspect(parser, input('$$\n$$\n\n$$')), [['<div class="math" translate="no">$$\n$$</div>'], '\n$$']);
|
|
41
40
|
assert.deepStrictEqual(inspect(parser, input('$$\n$$$\n$$')), [['<div class="math" translate="no">$$\n$$$\n$$</div>'], '']);
|
|
42
41
|
assert.deepStrictEqual(inspect(parser, input('$$\n$$$\n\n$$')), [['<div class="math" translate="no">$$\n$$$\n\n$$</div>'], '']);
|
|
43
|
-
assert.deepStrictEqual(inspect(parser, input(`$$\n0${'\n'.repeat(300)}$$`), '>'), [['<div class="math" translate="no">'], '']);
|
|
44
42
|
});
|
|
45
43
|
|
|
46
44
|
});
|
|
@@ -7,13 +7,13 @@ import { html } from 'typed-dom/dom';
|
|
|
7
7
|
const opener = /(\${2,})(?!\$)([^\r\n]*)(?:$|\r?\n)/y;
|
|
8
8
|
|
|
9
9
|
export const segment: MathBlockParser.SegmentParser = block(
|
|
10
|
-
fence(opener, false
|
|
10
|
+
fence(opener, false));
|
|
11
11
|
|
|
12
12
|
export const segment_: MathBlockParser.SegmentParser = block(
|
|
13
|
-
fence(opener, false,
|
|
13
|
+
fence(opener, false, false), false);
|
|
14
14
|
|
|
15
15
|
export const mathblock: MathBlockParser = block(inits([
|
|
16
|
-
fence(opener, true
|
|
16
|
+
fence(opener, true),
|
|
17
17
|
({ caches: { math: cache = undefined } = {} }, output) => {
|
|
18
18
|
const [body, overflow, closer, opener, delim, param] = unwrap(output.pop()) as string[];
|
|
19
19
|
return output.append(
|
package/src/parser/context.ts
CHANGED
|
@@ -8,13 +8,14 @@ export function input(source: string, input: Input = new Input()): Input {
|
|
|
8
8
|
export class Input<M extends object = object> extends Ipt<M> {
|
|
9
9
|
constructor(
|
|
10
10
|
options: Partial<Input> = {},
|
|
11
|
+
source?: string,
|
|
11
12
|
) {
|
|
12
13
|
super(options);
|
|
13
14
|
const {
|
|
14
15
|
segment,
|
|
15
16
|
header,
|
|
16
17
|
local,
|
|
17
|
-
|
|
18
|
+
whitespace,
|
|
18
19
|
host,
|
|
19
20
|
url,
|
|
20
21
|
id,
|
|
@@ -22,20 +23,21 @@ export class Input<M extends object = object> extends Ipt<M> {
|
|
|
22
23
|
caches,
|
|
23
24
|
test,
|
|
24
25
|
} = options;
|
|
26
|
+
this.source = source ?? options.source ?? '';
|
|
25
27
|
this.resources ??= {
|
|
26
28
|
clock: -1,
|
|
27
29
|
interval: 200,
|
|
28
30
|
recursions: [
|
|
29
|
-
10 || Recursion.
|
|
31
|
+
10 || Recursion.document,
|
|
30
32
|
100 || Recursion.block,
|
|
31
33
|
100 || Recursion.inline,
|
|
32
|
-
100 || Recursion.
|
|
34
|
+
100 || Recursion.bracket,
|
|
33
35
|
],
|
|
34
36
|
};
|
|
35
37
|
this.segment = segment ?? Segment.unknown;
|
|
36
38
|
this.header = header ?? true;
|
|
37
39
|
this.local = local ?? false;
|
|
38
|
-
this.
|
|
40
|
+
this.whitespace = whitespace ?? false;
|
|
39
41
|
this.host = host;
|
|
40
42
|
this.url = url;
|
|
41
43
|
this.id = id;
|
|
@@ -51,7 +53,7 @@ export class Input<M extends object = object> extends Ipt<M> {
|
|
|
51
53
|
public override segment: Segment;
|
|
52
54
|
public header: boolean;
|
|
53
55
|
public local: boolean;
|
|
54
|
-
public
|
|
56
|
+
public whitespace: boolean;
|
|
55
57
|
public recursion = new RecursionCounter(2);
|
|
56
58
|
public readonly host?: URL;
|
|
57
59
|
public readonly url?: URL;
|
|
@@ -115,10 +117,10 @@ export const enum State {
|
|
|
115
117
|
}
|
|
116
118
|
|
|
117
119
|
export const enum Recursion {
|
|
118
|
-
|
|
120
|
+
document,
|
|
119
121
|
block,
|
|
120
122
|
inline,
|
|
121
|
-
|
|
123
|
+
bracket,
|
|
122
124
|
}
|
|
123
125
|
|
|
124
126
|
export const enum Backtrack {
|
|
@@ -134,12 +136,7 @@ export const enum Backtrack {
|
|
|
134
136
|
}
|
|
135
137
|
|
|
136
138
|
export const enum Command {
|
|
137
|
-
Error = '\x07',
|
|
138
139
|
Cancel = '\x18',
|
|
139
140
|
Escape = '\x1B',
|
|
140
141
|
Separator = '\x1F',
|
|
141
142
|
}
|
|
142
|
-
|
|
143
|
-
export const CmdRegExp = {
|
|
144
|
-
Error: /\x07/g,
|
|
145
|
-
} as const;
|
package/src/parser/document.ts
CHANGED
|
@@ -29,7 +29,7 @@ export const document: MarkdownParser = (() => {
|
|
|
29
29
|
output.push();
|
|
30
30
|
return output.context;
|
|
31
31
|
},
|
|
32
|
-
recursion(Recursion.
|
|
32
|
+
recursion(Recursion.document, force(() => loop)),
|
|
33
33
|
(input, output) => {
|
|
34
34
|
assert(input.position === input.source.length);
|
|
35
35
|
const doc = frag(unwrap(output.pop()));
|
|
@@ -39,12 +39,12 @@ export const lineurl: AutolinkParser.UrlParser.LineUrlParser = lazy(() => focus(
|
|
|
39
39
|
])));
|
|
40
40
|
|
|
41
41
|
const bracket: AutolinkParser.UrlParser.BracketParser = lazy(() => backtrack(union([
|
|
42
|
-
surround(str('('), recursion(Recursion.
|
|
42
|
+
surround(str('('), recursion(Recursion.bracket, some(union([bracket, unescsource]), ')')), str(')'),
|
|
43
43
|
true, [3 | Backtrack.unescapable]),
|
|
44
|
-
surround(str('['), recursion(Recursion.
|
|
44
|
+
surround(str('['), recursion(Recursion.bracket, some(union([bracket, unescsource]), ']')), str(']'),
|
|
45
45
|
true, [3 | Backtrack.unescapable]),
|
|
46
|
-
surround(str('{'), recursion(Recursion.
|
|
46
|
+
surround(str('{'), recursion(Recursion.bracket, some(union([bracket, unescsource]), '}')), str('}'),
|
|
47
47
|
true, [3 | Backtrack.unescapable]),
|
|
48
|
-
surround(str('"'), precedence(2, recursion(Recursion.
|
|
48
|
+
surround(str('"'), precedence(2, recursion(Recursion.bracket, some(unescsource, '"'))), str('"'),
|
|
49
49
|
true, [3 | Backtrack.unescapable]),
|
|
50
50
|
])));
|
|
@@ -41,7 +41,7 @@ export const math: MathParser = lazy(() => rewrite(
|
|
|
41
41
|
|
|
42
42
|
const bracket: MathParser.BracketParser = lazy(() => backtrack(surround(
|
|
43
43
|
str('{'),
|
|
44
|
-
recursion(Recursion.
|
|
44
|
+
recursion(Recursion.bracket,
|
|
45
45
|
some(union([
|
|
46
46
|
bracket,
|
|
47
47
|
some(escsource, /[{}$\r\n]|(?<=[0-9A-Za-z]):\/\/[[0-9A-Za-z]/y),
|
|
@@ -107,13 +107,13 @@ export const media: MediaParser = lazy(() => constraint(State.media, backtrack(o
|
|
|
107
107
|
})))));
|
|
108
108
|
|
|
109
109
|
const bracket: MediaParser.TextParser.BracketParser = lazy(() => union([
|
|
110
|
-
surround(str('('), recursion(Recursion.
|
|
110
|
+
surround(str('('), recursion(Recursion.bracket, some(union([unsafehtmlentity, bracket, txt]), ')')), str(')'),
|
|
111
111
|
true, [], undefined, () => Result.succ),
|
|
112
|
-
surround(str('['), recursion(Recursion.
|
|
112
|
+
surround(str('['), recursion(Recursion.bracket, some(union([unsafehtmlentity, bracket, txt]), ']')), str(']'),
|
|
113
113
|
true, [], undefined, () => Result.succ),
|
|
114
|
-
surround(str('{'), recursion(Recursion.
|
|
114
|
+
surround(str('{'), recursion(Recursion.bracket, some(union([unsafehtmlentity, bracket, txt]), '}')), str('}'),
|
|
115
115
|
true, [], undefined, () => Result.succ),
|
|
116
|
-
surround(str('"'), precedence(2, recursion(Recursion.
|
|
116
|
+
surround(str('"'), precedence(2, recursion(Recursion.bracket, some(union([unsafehtmlentity, txt]), '"'))), str('"'),
|
|
117
117
|
true, [], undefined, () => Result.succ),
|
|
118
118
|
]));
|
|
119
119
|
|