securemark 0.298.2 → 0.298.4
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 +8 -0
- package/design.md +1 -5
- package/dist/index.js +153 -153
- package/package.json +1 -1
- package/src/combinator/control/constraint/line.ts +1 -1
- package/src/combinator/control/manipulation/match.ts +1 -1
- package/src/combinator/data/delimiter.ts +42 -37
- package/src/combinator/data/parser/context.ts +4 -2
- package/src/combinator/data/parser/inits.ts +1 -1
- package/src/combinator/data/parser/sequence.ts +1 -1
- package/src/combinator/data/parser/some.ts +4 -3
- package/src/parser/api/bind.ts +17 -22
- package/src/parser/api/header.ts +1 -1
- package/src/parser/api/parse.test.ts +7 -10
- package/src/parser/api/parse.ts +27 -31
- package/src/parser/block/codeblock.ts +1 -1
- package/src/parser/block/extension/fig.ts +1 -1
- package/src/parser/block/extension/figure.ts +1 -1
- package/src/parser/block/extension/message.ts +1 -1
- package/src/parser/block/extension/placeholder.ts +1 -1
- package/src/parser/block/extension/table.ts +1 -1
- package/src/parser/block/heading.test.ts +2 -2
- package/src/parser/block/heading.ts +1 -1
- package/src/parser/block/mathblock.ts +1 -1
- package/src/parser/block/table.test.ts +1 -1
- package/src/parser/block.ts +64 -82
- package/src/parser/context.ts +20 -0
- package/src/parser/header.test.ts +1 -0
- package/src/parser/header.ts +3 -3
- package/src/parser/inline/annotation.test.ts +19 -19
- package/src/parser/inline/annotation.ts +10 -7
- package/src/parser/inline/autolink.ts +3 -3
- package/src/parser/inline/bracket.test.ts +11 -11
- package/src/parser/inline/bracket.ts +7 -17
- package/src/parser/inline/emphasis.test.ts +2 -2
- package/src/parser/inline/emstrong.test.ts +3 -3
- package/src/parser/inline/extension/index.test.ts +1 -1
- package/src/parser/inline/html.test.ts +5 -1
- package/src/parser/inline/html.ts +61 -53
- package/src/parser/inline/italic.test.ts +1 -1
- package/src/parser/inline/link.test.ts +1 -1
- package/src/parser/inline/reference.test.ts +1 -1
- package/src/parser/inline/strong.test.ts +2 -2
- package/src/parser/inline.test.ts +14 -14
- package/src/parser/inline.ts +7 -1
- package/src/parser/processor/note.ts +1 -1
- package/src/parser/segment.ts +13 -15
- package/src/parser/source/escapable.ts +0 -1
- package/src/parser/source/line.ts +6 -4
- package/src/parser/source/text.ts +4 -5
package/src/parser/block.ts
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { MarkdownParser } from '../../markdown';
|
|
2
|
-
import { Segment,
|
|
2
|
+
import { Segment, Command } from './context';
|
|
3
3
|
import { List, Node } from '../combinator/data/parser';
|
|
4
|
-
import { union,
|
|
5
|
-
import { MAX_SEGMENT_SIZE } from './segment';
|
|
4
|
+
import { union, firstline, recover } from '../combinator';
|
|
6
5
|
import { header } from './header';
|
|
7
6
|
import { emptysegment } from './source';
|
|
8
7
|
import { pagebreak } from './block/pagebreak';
|
|
@@ -43,88 +42,71 @@ export import MediaBlockParser = BlockParser.MediaBlockParser;
|
|
|
43
42
|
export import ReplyParser = BlockParser.ReplyParser;
|
|
44
43
|
export import ParagraphParser = BlockParser.ParagraphParser;
|
|
45
44
|
|
|
46
|
-
export const block: BlockParser =
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
45
|
+
export const block: BlockParser = error(union([
|
|
46
|
+
emptysegment,
|
|
47
|
+
input => {
|
|
48
|
+
const { source, position, segment } = input;
|
|
49
|
+
if (position === source.length) return;
|
|
50
|
+
switch (segment ^ Segment.write) {
|
|
51
|
+
case Segment.heading:
|
|
52
|
+
return heading(input);
|
|
53
|
+
case Segment.fig:
|
|
54
|
+
return fig(input);
|
|
55
|
+
case Segment.figure:
|
|
56
|
+
return figure(input);
|
|
57
|
+
}
|
|
58
|
+
const char = source[position];
|
|
59
|
+
switch (char) {
|
|
60
|
+
case Command.Error:
|
|
61
|
+
throw new Error(firstline(source, position + 1).trimEnd());
|
|
62
|
+
case '=':
|
|
63
|
+
if (source.startsWith('===', position)) return pagebreak(input);
|
|
64
|
+
break;
|
|
65
|
+
case '`':
|
|
66
|
+
if (source.startsWith('```', position)) return codeblock(input);
|
|
67
|
+
break;
|
|
68
|
+
case '~':
|
|
69
|
+
if (source.startsWith('~~~', position)) return extension(input);
|
|
70
|
+
if (source[position + 1] === ' ') return dlist(input);
|
|
71
|
+
break;
|
|
72
|
+
case '-':
|
|
73
|
+
if (source.startsWith('---', position)) return header(input);
|
|
74
|
+
if (source[position + 1] === ' ') return ulist(input) || ilist(input);
|
|
75
|
+
break;
|
|
76
|
+
case '+':
|
|
77
|
+
case '*':
|
|
78
|
+
if (source[position + 1] === ' ') return ilist(input);
|
|
79
|
+
break;
|
|
80
|
+
case '[':
|
|
81
|
+
switch (source[position + 1]) {
|
|
82
|
+
case '$':
|
|
83
|
+
return figbase(input);
|
|
84
|
+
case '!':
|
|
85
|
+
return mediablock(input);
|
|
86
|
+
}
|
|
87
|
+
break;
|
|
88
|
+
case '!':
|
|
89
|
+
if (source[position + 1] === '>') return blockquote(input);
|
|
90
|
+
return mediablock(input);
|
|
91
|
+
case '>':
|
|
92
|
+
if (source[position + 1] === '>') return blockquote(input) || reply(input);
|
|
93
|
+
return blockquote(input);
|
|
94
|
+
case '$':
|
|
95
|
+
if (source[position + 1] === '$') return mathblock(input);
|
|
96
|
+
return figbase(input);
|
|
97
|
+
case '|':
|
|
98
|
+
return table(input) || sidefence(input);
|
|
99
|
+
case '(':
|
|
100
|
+
return olist(input);
|
|
101
|
+
default:
|
|
102
|
+
if ('0' <= char && char <= '9') return olist(input);
|
|
103
|
+
}
|
|
62
104
|
},
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
input => {
|
|
66
|
-
const { source, position, segment } = input;
|
|
67
|
-
if (position === source.length) return;
|
|
68
|
-
switch (segment ^ Segment.write) {
|
|
69
|
-
case Segment.heading:
|
|
70
|
-
return heading(input);
|
|
71
|
-
case Segment.fig:
|
|
72
|
-
return fig(input);
|
|
73
|
-
case Segment.figure:
|
|
74
|
-
return figure(input);
|
|
75
|
-
}
|
|
76
|
-
const fst = source[position];
|
|
77
|
-
switch (fst) {
|
|
78
|
-
case Command.Error:
|
|
79
|
-
throw new Error(firstline(source, position + 1).trimEnd());
|
|
80
|
-
case '=':
|
|
81
|
-
if (source.startsWith('===', position)) return pagebreak(input);
|
|
82
|
-
break;
|
|
83
|
-
case '`':
|
|
84
|
-
if (source.startsWith('```', position)) return codeblock(input);
|
|
85
|
-
break;
|
|
86
|
-
case '~':
|
|
87
|
-
if (source.startsWith('~~~', position)) return extension(input);
|
|
88
|
-
if (source[position + 1] === ' ') return dlist(input);
|
|
89
|
-
break;
|
|
90
|
-
case '-':
|
|
91
|
-
if (source.startsWith('---', position)) return header(input);
|
|
92
|
-
if (source[position + 1] === ' ') return ulist(input) || ilist(input);
|
|
93
|
-
break;
|
|
94
|
-
case '+':
|
|
95
|
-
case '*':
|
|
96
|
-
if (source[position + 1] === ' ') return ilist(input);
|
|
97
|
-
break;
|
|
98
|
-
case '[':
|
|
99
|
-
switch (source[position + 1]) {
|
|
100
|
-
case '$':
|
|
101
|
-
return figbase(input);
|
|
102
|
-
case '!':
|
|
103
|
-
return mediablock(input);
|
|
104
|
-
}
|
|
105
|
-
break;
|
|
106
|
-
case '!':
|
|
107
|
-
if (source[position + 1] === '>') return blockquote(input);
|
|
108
|
-
return mediablock(input);
|
|
109
|
-
case '>':
|
|
110
|
-
if (source[position + 1] === '>') return blockquote(input) || reply(input);
|
|
111
|
-
return blockquote(input);
|
|
112
|
-
case '$':
|
|
113
|
-
if (source[position + 1] === '$') return mathblock(input);
|
|
114
|
-
return figbase(input);
|
|
115
|
-
case '|':
|
|
116
|
-
return table(input) || sidefence(input);
|
|
117
|
-
case '(':
|
|
118
|
-
return olist(input);
|
|
119
|
-
default:
|
|
120
|
-
if ('0' <= fst && fst <= '9') return olist(input);
|
|
121
|
-
}
|
|
122
|
-
},
|
|
123
|
-
paragraph
|
|
124
|
-
])));
|
|
105
|
+
paragraph
|
|
106
|
+
]));
|
|
125
107
|
|
|
126
108
|
function error(parser: BlockParser): BlockParser {
|
|
127
|
-
const reg = new RegExp(String.raw`^${Command.Error}[^\n]*\n`)
|
|
109
|
+
const reg = new RegExp(String.raw`^${Command.Error}[^\r\n]*\r?\n`)
|
|
128
110
|
return recover<BlockParser>(
|
|
129
111
|
parser,
|
|
130
112
|
({ source, position, id }, reason) => new List([
|
package/src/parser/context.ts
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { List, Node, Context as Ctx } from '../../src/combinator/data/parser';
|
|
2
2
|
import { Dict } from 'spica/dict';
|
|
3
3
|
|
|
4
|
+
export const MAX_SEGMENT_SIZE = 100_000; // 100,000 bytes (Max value size of FDB)
|
|
5
|
+
export const MAX_INPUT_SIZE = MAX_SEGMENT_SIZE * 10;
|
|
6
|
+
|
|
4
7
|
export class Context extends Ctx {
|
|
5
8
|
constructor(
|
|
6
9
|
options: Partial<Context> = {},
|
|
@@ -17,6 +20,19 @@ export class Context extends Ctx {
|
|
|
17
20
|
id,
|
|
18
21
|
caches,
|
|
19
22
|
} = options;
|
|
23
|
+
this.resources ??= {
|
|
24
|
+
// バックトラックのせいで文字数制限を受けないようにする。
|
|
25
|
+
clock: MAX_SEGMENT_SIZE * (6 + 1),
|
|
26
|
+
recursions: [
|
|
27
|
+
5 || Recursion.block,
|
|
28
|
+
20 || Recursion.blockquote,
|
|
29
|
+
40 || Recursion.listitem,
|
|
30
|
+
20 || Recursion.inline,
|
|
31
|
+
20 || Recursion.annotation,
|
|
32
|
+
20 || Recursion.bracket,
|
|
33
|
+
20 || Recursion.terminal,
|
|
34
|
+
],
|
|
35
|
+
};
|
|
20
36
|
this.segment = segment ?? Segment.unknown;
|
|
21
37
|
this.local = local ?? false;
|
|
22
38
|
this.sequential = sequential ?? false;
|
|
@@ -27,6 +43,10 @@ export class Context extends Ctx {
|
|
|
27
43
|
this.id = id;
|
|
28
44
|
this.caches = caches;
|
|
29
45
|
}
|
|
46
|
+
public override readonly resources?: {
|
|
47
|
+
clock: number;
|
|
48
|
+
recursions: number[];
|
|
49
|
+
};
|
|
30
50
|
public override segment: Segment;
|
|
31
51
|
public local: boolean;
|
|
32
52
|
public sequential: boolean;
|
|
@@ -27,6 +27,7 @@ describe('Unit: parser/header', () => {
|
|
|
27
27
|
assert.deepStrictEqual(inspect(parser, input('---\na: b\n---', new Context())), [['<aside class="header"><details open=""><summary>Header</summary><span class="field" data-name="a" data-value="b"><span class="field-name">a</span>: <span class="field-value">b</span>\n</span></details></aside>'], '']);
|
|
28
28
|
assert.deepStrictEqual(inspect(parser, input('---\na: b\n---\n', new Context())), [['<aside class="header"><details open=""><summary>Header</summary><span class="field" data-name="a" data-value="b"><span class="field-name">a</span>: <span class="field-value">b</span>\n</span></details></aside>'], '']);
|
|
29
29
|
assert.deepStrictEqual(inspect(parser, input('---\na: b\nC: D e\n---\n', new Context())), [['<aside class="header"><details open=""><summary>Header</summary><span class="field" data-name="a" data-value="b"><span class="field-name">a</span>: <span class="field-value">b</span>\n</span><span class="field" data-name="c" data-value="D e"><span class="field-name">C</span>: <span class="field-value">D e</span>\n</span></details></aside>'], '']);
|
|
30
|
+
assert.deepStrictEqual(inspect(parser, input('---\r\na: b\r\nC: D e\r\n---\r\n', new Context())), [['<aside class="header"><details open=""><summary>Header</summary><span class="field" data-name="a" data-value="b"><span class="field-name">a</span>: <span class="field-value">b</span>\n</span><span class="field" data-name="c" data-value="D e"><span class="field-name">C</span>: <span class="field-value">D e</span>\n</span></details></aside>'], '']);
|
|
30
31
|
assert.deepStrictEqual(inspect(parser, input('----\na: b\n----', new Context())), [['<aside class="header"><details open=""><summary>Header</summary><span class="field" data-name="a" data-value="b"><span class="field-name">a</span>: <span class="field-value">b</span>\n</span></details></aside>'], '']);
|
|
31
32
|
});
|
|
32
33
|
|
package/src/parser/header.ts
CHANGED
|
@@ -7,12 +7,12 @@ import { normalize } from './api/normalize';
|
|
|
7
7
|
import { html, defrag } from 'typed-dom/dom';
|
|
8
8
|
|
|
9
9
|
export const header: MarkdownParser.HeaderParser = lazy(() => validate(
|
|
10
|
-
/---+[^\S\n]*\n(?=\S)/y,
|
|
10
|
+
/---+[^\S\r\n]*\r?\n(?=\S)/y,
|
|
11
11
|
inits([
|
|
12
12
|
block(
|
|
13
13
|
union([
|
|
14
14
|
validate(context => context.header,
|
|
15
|
-
focus(/(---+)[^\S\n]*\n(?:[a-z][0-9a-z]*(?:-[0-9a-z]+)*:[ \t]+\S[^\n]*\n){1,100}\1[^\S\n]*(?:$|\n)/yi,
|
|
15
|
+
focus(/(---+)[^\S\r\n]*\r?\n(?:[a-z][0-9a-z]*(?:-[0-9a-z]+)*:[ \t]+\S[^\r\n]*\r?\n){1,100}\1[^\S\r\n]*(?:$|\r?\n)/yi,
|
|
16
16
|
convert(source =>
|
|
17
17
|
normalize(source.slice(source.indexOf('\n') + 1, source.trimEnd().lastIndexOf('\n'))),
|
|
18
18
|
fmap(
|
|
@@ -36,7 +36,7 @@ export const header: MarkdownParser.HeaderParser = lazy(() => validate(
|
|
|
36
36
|
]);
|
|
37
37
|
},
|
|
38
38
|
])),
|
|
39
|
-
clear(str(/[^\S\n]*\n/y)),
|
|
39
|
+
clear(str(/[^\S\r\n]*\r?\n/y)),
|
|
40
40
|
])));
|
|
41
41
|
|
|
42
42
|
const field: MarkdownParser.HeaderParser.FieldParser = line(({ source, position }) => {
|
|
@@ -13,17 +13,17 @@ describe('Unit: parser/inline/annotation', () => {
|
|
|
13
13
|
assert.deepStrictEqual(inspect(parser, input('(', new Context())), undefined);
|
|
14
14
|
assert.deepStrictEqual(inspect(parser, input('()', new Context())), undefined);
|
|
15
15
|
assert.deepStrictEqual(inspect(parser, input('((', new Context())), undefined);
|
|
16
|
-
assert.deepStrictEqual(inspect(parser, input('(())', new Context())), [['<span class="
|
|
17
|
-
assert.deepStrictEqual(inspect(parser, input('(()))', new Context())), [['<span class="
|
|
18
|
-
assert.deepStrictEqual(inspect(parser, input('(("))', new Context())), [['<span class="
|
|
19
|
-
assert.deepStrictEqual(inspect(parser, input('((a', new Context())), [['<span class="
|
|
20
|
-
assert.deepStrictEqual(inspect(parser, input('((!', new Context())), [['<span class="
|
|
21
|
-
assert.deepStrictEqual(inspect(parser, input('((a)', new Context())), [['<span class="
|
|
22
|
-
assert.deepStrictEqual(inspect(parser, input('((!)', new Context())), [['<span class="
|
|
23
|
-
assert.deepStrictEqual(inspect(parser, input('((a)b)', new Context())), [['<span class="
|
|
24
|
-
assert.deepStrictEqual(inspect(parser, input('((!)b)', new Context())), [['<span class="
|
|
25
|
-
assert.deepStrictEqual(inspect(parser, input('(([))', new Context())), [['<span class="
|
|
26
|
-
assert.deepStrictEqual(inspect(parser, input('(([%))', new Context())), [['<span class="
|
|
16
|
+
assert.deepStrictEqual(inspect(parser, input('(())', new Context())), [['<span class="paren">(<span class="paren">()</span>)</span>'], '']);
|
|
17
|
+
assert.deepStrictEqual(inspect(parser, input('(()))', new Context())), [['<span class="paren">(<span class="paren">()</span>)</span>'], ')']);
|
|
18
|
+
assert.deepStrictEqual(inspect(parser, input('(("))', new Context())), [['<span class="paren">(<span class="paren">("))</span></span>'], '']);
|
|
19
|
+
assert.deepStrictEqual(inspect(parser, input('((a', new Context())), [['<span class="paren">(<span class="paren">(a</span></span>'], '']);
|
|
20
|
+
assert.deepStrictEqual(inspect(parser, input('((!', new Context())), [['<span class="paren">(<span class="paren">(!</span></span>'], '']);
|
|
21
|
+
assert.deepStrictEqual(inspect(parser, input('((a)', new Context())), [['<span class="paren">(<span class="paren">(a)</span></span>'], '']);
|
|
22
|
+
assert.deepStrictEqual(inspect(parser, input('((!)', new Context())), [['<span class="paren">(<span class="paren">(!)</span></span>'], '']);
|
|
23
|
+
assert.deepStrictEqual(inspect(parser, input('((a)b)', new Context())), [['<span class="paren">(<span class="paren">(a)</span>b)</span>'], '']);
|
|
24
|
+
assert.deepStrictEqual(inspect(parser, input('((!)b)', new Context())), [['<span class="paren">(<span class="paren">(!)</span>b)</span>'], '']);
|
|
25
|
+
assert.deepStrictEqual(inspect(parser, input('(([))', new Context())), [['<span class="paren">(<span class="paren">([))</span></span>'], '']);
|
|
26
|
+
assert.deepStrictEqual(inspect(parser, input('(([%))', new Context())), [['<span class="paren">(<span class="paren">([%))</span></span>'], '']);
|
|
27
27
|
assert.deepStrictEqual(inspect(parser, input('(( ))', new Context())), undefined);
|
|
28
28
|
assert.deepStrictEqual(inspect(parser, input('(( a))', new Context())), undefined);
|
|
29
29
|
assert.deepStrictEqual(inspect(parser, input('(( a ))', new Context())), undefined);
|
|
@@ -37,13 +37,13 @@ describe('Unit: parser/inline/annotation', () => {
|
|
|
37
37
|
assert.deepStrictEqual(inspect(parser, input('((a\nb))', new Context())), [['<span class="bracket">(<span class="bracket">(a<br>b)</span>)</span>'], '']);
|
|
38
38
|
assert.deepStrictEqual(inspect(parser, input('((a\\\nb))', new Context())), [['<span class="bracket">(<span class="bracket">(a<br>b)</span>)</span>'], '']);
|
|
39
39
|
assert.deepStrictEqual(inspect(parser, input('((*a\nb*))', new Context())), [['<span class="bracket">(<span class="bracket">(<em>a<br>b</em>)</span>)</span>'], '']);
|
|
40
|
-
assert.deepStrictEqual(inspect(parser, input('((\\))', new Context())), [['<span class="
|
|
41
|
-
assert.deepStrictEqual(inspect(parser, input('(((a))', new Context())), [['<span class="
|
|
42
|
-
assert.deepStrictEqual(inspect(parser, input('(((!))', new Context())), [['<span class="
|
|
43
|
-
assert.deepStrictEqual(inspect(parser, input('(((*a*))', new Context())), [['<span class="
|
|
44
|
-
assert.deepStrictEqual(inspect(parser, input('(((((a))))', new Context())), [['<span class="
|
|
45
|
-
assert.deepStrictEqual(inspect(parser, input('(((((!))))', new Context())), [['<span class="
|
|
46
|
-
assert.deepStrictEqual(inspect(parser, input('(((((*a*))))', new Context())), [['<span class="
|
|
40
|
+
assert.deepStrictEqual(inspect(parser, input('((\\))', new Context())), [['<span class="paren">(<span class="paren">())</span></span>'], '']);
|
|
41
|
+
assert.deepStrictEqual(inspect(parser, input('(((a))', new Context())), [['<span class="paren">(<sup class="annotation"><span>a</span></sup></span>'], '']);
|
|
42
|
+
assert.deepStrictEqual(inspect(parser, input('(((!))', new Context())), [['<span class="paren">(<sup class="annotation"><span>!</span></sup></span>'], '']);
|
|
43
|
+
assert.deepStrictEqual(inspect(parser, input('(((*a*))', new Context())), [['<span class="paren">(<sup class="annotation"><span><em>a</em></span></sup></span>'], '']);
|
|
44
|
+
assert.deepStrictEqual(inspect(parser, input('(((((a))))', new Context())), [['<span class="paren">(<sup class="annotation"><span><sup class="annotation"><span>a</span></sup></span></sup></span>'], '']);
|
|
45
|
+
assert.deepStrictEqual(inspect(parser, input('(((((!))))', new Context())), [['<span class="paren">(<sup class="annotation"><span><sup class="annotation"><span>!</span></sup></span></sup></span>'], '']);
|
|
46
|
+
assert.deepStrictEqual(inspect(parser, input('(((((*a*))))', new Context())), [['<span class="paren">(<sup class="annotation"><span><sup class="annotation"><span><em>a</em></span></sup></span></sup></span>'], '']);
|
|
47
47
|
assert.deepStrictEqual(inspect(parser, input(' ((a))', new Context())), undefined);
|
|
48
48
|
});
|
|
49
49
|
|
|
@@ -61,7 +61,7 @@ describe('Unit: parser/inline/annotation', () => {
|
|
|
61
61
|
assert.deepStrictEqual(inspect(parser, input('((@a))', new Context())), [['<sup class="annotation"><span><a class="account" href="/@a">@a</a></span></sup>'], '']);
|
|
62
62
|
assert.deepStrictEqual(inspect(parser, input('((http://host))', new Context())), [['<sup class="annotation"><span><a class="url" href="http://host" target="_blank">http://host</a></span></sup>'], '']);
|
|
63
63
|
assert.deepStrictEqual(inspect(parser, input('((![]{a}))', new Context())), [['<sup class="annotation"><span>!<a class="url" href="a">a</a></span></sup>'], '']);
|
|
64
|
-
assert.deepStrictEqual(inspect(parser, input('((a(())))', new Context())), [['<sup class="annotation"><span>a<span class="
|
|
64
|
+
assert.deepStrictEqual(inspect(parser, input('((a(())))', new Context())), [['<sup class="annotation"><span>a<span class="paren">(<span class="paren">()</span>)</span></span></sup>'], '']);
|
|
65
65
|
assert.deepStrictEqual(inspect(parser, input('((a[[]]))', new Context())), [['<sup class="annotation"><span>a[[]]</span></sup>'], '']);
|
|
66
66
|
assert.deepStrictEqual(inspect(parser, input('(([[a] ]))', new Context())), [['<sup class="annotation"><span>[[a] ]</span></sup>'], '']);
|
|
67
67
|
assert.deepStrictEqual(inspect(parser, input('(((a)))', new Context())), [['<sup class="annotation"><span><span class="paren">(a)</span></span></sup>'], '']);
|
|
@@ -3,7 +3,7 @@ import { State, Recursion } from '../context';
|
|
|
3
3
|
import { List, Node } from '../../combinator/data/parser';
|
|
4
4
|
import { union, some, recursions, precedence, constraint, surround, open, lazy } from '../../combinator';
|
|
5
5
|
import { inline } from '../inline';
|
|
6
|
-
import { bracketname
|
|
6
|
+
import { bracketname } from './bracket';
|
|
7
7
|
import { beforeNonblank, trimBlankNodeEnd } from '../visibility';
|
|
8
8
|
import { unwrap } from '../util';
|
|
9
9
|
import { html, defrag } from 'typed-dom/dom';
|
|
@@ -36,8 +36,8 @@ export const annotation: AnnotationParser = lazy(() => constraint(State.annotati
|
|
|
36
36
|
ns.push(new Node(')'));
|
|
37
37
|
return new List([
|
|
38
38
|
new Node(html('span',
|
|
39
|
-
{ class:
|
|
40
|
-
['(', html('span', { class:
|
|
39
|
+
{ class: bracketname(context, 1, 1) },
|
|
40
|
+
['(', html('span', { class: bracketname(context, 2, 2) }, defrag(unwrap(ns))), ')']))
|
|
41
41
|
]);
|
|
42
42
|
}
|
|
43
43
|
const depth = MAX_DEPTH - (resources?.recursions[Recursion.annotation] ?? resources?.recursions.at(-1) ?? MAX_DEPTH);
|
|
@@ -71,7 +71,7 @@ export const annotation: AnnotationParser = lazy(() => constraint(State.annotati
|
|
|
71
71
|
recursion.add(depth);
|
|
72
72
|
return new List([
|
|
73
73
|
new Node(html('span',
|
|
74
|
-
{ class: '
|
|
74
|
+
{ class: 'paren' },
|
|
75
75
|
['(', html('sup', { class: 'annotation' }, [html('span', bs.head.value.childNodes)])]))
|
|
76
76
|
]);
|
|
77
77
|
}
|
|
@@ -80,7 +80,7 @@ export const annotation: AnnotationParser = lazy(() => constraint(State.annotati
|
|
|
80
80
|
recursion.add(depth);
|
|
81
81
|
return new List([
|
|
82
82
|
new Node(html('span',
|
|
83
|
-
{ class: '
|
|
83
|
+
{ class: 'paren' },
|
|
84
84
|
['(', html('sup', { class: 'annotation' }, [html('span', [bs.head.value])])]))
|
|
85
85
|
]);
|
|
86
86
|
}
|
|
@@ -94,7 +94,7 @@ export const annotation: AnnotationParser = lazy(() => constraint(State.annotati
|
|
|
94
94
|
}
|
|
95
95
|
bs = new List([
|
|
96
96
|
new Node(html('span',
|
|
97
|
-
{ class: bracketname(context,
|
|
97
|
+
{ class: bracketname(context, 2, context.position - position) },
|
|
98
98
|
defrag(unwrap(bs))))
|
|
99
99
|
]);
|
|
100
100
|
bs.unshift(new Node('('));
|
|
@@ -103,8 +103,11 @@ export const annotation: AnnotationParser = lazy(() => constraint(State.annotati
|
|
|
103
103
|
cs && bs.import(cs);
|
|
104
104
|
bs.push(new Node(')'));
|
|
105
105
|
context.position += 1;
|
|
106
|
+
context.range += 1;
|
|
106
107
|
}
|
|
107
|
-
return new List([new Node(html('span',
|
|
108
|
+
return new List([new Node(html('span',
|
|
109
|
+
{ class: bracketname(context, 1, context.position - position) },
|
|
110
|
+
defrag(unwrap(bs))))]);
|
|
108
111
|
})));
|
|
109
112
|
|
|
110
113
|
const parser = lazy(() => precedence(1, some(inline, ')', [[')', 1]])));
|
|
@@ -14,8 +14,8 @@ export const autolink: AutolinkParser = lazy(() =>
|
|
|
14
14
|
input => {
|
|
15
15
|
const { source, position } = input;
|
|
16
16
|
if (position === source.length) return;
|
|
17
|
-
const
|
|
18
|
-
switch (
|
|
17
|
+
const char = source[position];
|
|
18
|
+
switch (char) {
|
|
19
19
|
case '@':
|
|
20
20
|
return account(input);
|
|
21
21
|
case '#':
|
|
@@ -41,6 +41,6 @@ export const autolink: AutolinkParser = lazy(() =>
|
|
|
41
41
|
}
|
|
42
42
|
return url(input) || email(input);
|
|
43
43
|
default:
|
|
44
|
-
if (isAlphanumeric(
|
|
44
|
+
if (isAlphanumeric(char)) return email(input);
|
|
45
45
|
}
|
|
46
46
|
}));
|
|
@@ -23,30 +23,30 @@ describe('Unit: parser/inline/bracket', () => {
|
|
|
23
23
|
assert.deepStrictEqual(inspect(parser, input('(1, 2)', new Context())), [['<span class="paren">(1, 2)</span>'], '']);
|
|
24
24
|
assert.deepStrictEqual(inspect(parser, input('(1.1-1.2)', new Context())), [['<span class="paren">(1.1-1.2)</span>'], '']);
|
|
25
25
|
assert.deepStrictEqual(inspect(parser, input('(1.1, 1.2)', new Context())), [['<span class="paren">(1.1, 1.2)</span>'], '']);
|
|
26
|
-
assert.deepStrictEqual(inspect(parser, input('(1 2)', new Context())), [['<span class="
|
|
26
|
+
assert.deepStrictEqual(inspect(parser, input('(1 2)', new Context())), [['<span class="paren">(1 2)</span>'], '']);
|
|
27
27
|
assert.deepStrictEqual(inspect(parser, input('(1a)', new Context())), [['<span class="paren">(1a)</span>'], '']);
|
|
28
28
|
assert.deepStrictEqual(inspect(parser, input('(a)', new Context())), [['<span class="paren">(a)</span>'], '']);
|
|
29
29
|
assert.deepStrictEqual(inspect(parser, input('(a1)', new Context())), [['<span class="paren">(a1)</span>'], '']);
|
|
30
30
|
assert.deepStrictEqual(inspect(parser, input('(a-1)', new Context())), [['<span class="paren">(a-1)</span>'], '']);
|
|
31
31
|
assert.deepStrictEqual(inspect(parser, input('(a.1)', new Context())), [['<span class="paren">(a.1)</span>'], '']);
|
|
32
|
-
assert.deepStrictEqual(inspect(parser, input('(a b)', new Context())), [['<span class="
|
|
32
|
+
assert.deepStrictEqual(inspect(parser, input('(a b)', new Context())), [['<span class="paren">(a b)</span>'], '']);
|
|
33
33
|
assert.deepStrictEqual(inspect(parser, input('(word)', new Context())), [['<span class="paren">(word)</span>'], '']);
|
|
34
|
-
assert.deepStrictEqual(inspect(parser, input('(word word)', new Context())), [['<span class="
|
|
34
|
+
assert.deepStrictEqual(inspect(parser, input('(word word)', new Context())), [['<span class="paren">(word word)</span>'], '']);
|
|
35
35
|
assert.deepStrictEqual(inspect(parser, input('(word, word)', new Context())), [['<span class="paren">(word, word)</span>'], '']);
|
|
36
36
|
assert.deepStrictEqual(inspect(parser, input('(A)', new Context())), [['<span class="paren">(A)</span>'], '']);
|
|
37
37
|
assert.deepStrictEqual(inspect(parser, input('(Name)', new Context())), [['<span class="paren">(Name)</span>'], '']);
|
|
38
|
-
assert.deepStrictEqual(inspect(parser, input('(Word word)', new Context())), [['<span class="
|
|
39
|
-
assert.deepStrictEqual(inspect(parser, input('(Word Word)', new Context())), [['<span class="
|
|
38
|
+
assert.deepStrictEqual(inspect(parser, input('(Word word)', new Context())), [['<span class="paren">(Word word)</span>'], '']);
|
|
39
|
+
assert.deepStrictEqual(inspect(parser, input('(Word Word)', new Context())), [['<span class="paren">(Word Word)</span>'], '']);
|
|
40
40
|
assert.deepStrictEqual(inspect(parser, input('(Name, Name)', new Context())), [['<span class="paren">(Name, Name)</span>'], '']);
|
|
41
41
|
assert.deepStrictEqual(inspect(parser, input('(ABBR)', new Context())), [['<span class="paren">(ABBR)</span>'], '']);
|
|
42
42
|
assert.deepStrictEqual(inspect(parser, input('(ABBR, ABBR)', new Context())), [['<span class="paren">(ABBR, ABBR)</span>'], '']);
|
|
43
43
|
assert.deepStrictEqual(inspect(parser, input(`(${'0'.repeat(16)})`, new Context())), [[`<span class="paren">(${'0'.repeat(16)})</span>`], '']);
|
|
44
44
|
assert.deepStrictEqual(inspect(parser, input(`(${'0'.repeat(17)})`, new Context())), [[`<span class="bracket">(${'0'.repeat(17)})</span>`], '']);
|
|
45
|
-
assert.deepStrictEqual(inspect(parser, input('(\\a)', new Context())), [['<span class="
|
|
46
|
-
assert.deepStrictEqual(inspect(parser, input('(==)', new Context())), [['<span class="
|
|
47
|
-
assert.deepStrictEqual(inspect(parser, input('(()', new Context())), [['<span class="
|
|
45
|
+
assert.deepStrictEqual(inspect(parser, input('(\\a)', new Context())), [['<span class="paren">(a)</span>'], '']);
|
|
46
|
+
assert.deepStrictEqual(inspect(parser, input('(==)', new Context())), [['<span class="paren">(==)</span>'], '']);
|
|
47
|
+
assert.deepStrictEqual(inspect(parser, input('(()', new Context())), [['<span class="paren">(<span class="paren">()</span></span>'], '']);
|
|
48
48
|
assert.deepStrictEqual(inspect(parser, input('("(\n))"(")', new Context())), [['<span class="bracket">("<span class="paren">(</span><br>)</span>'], ')"(")']);
|
|
49
|
-
assert.deepStrictEqual(inspect(parser, input('($)$', new Context())), [['<span class="
|
|
49
|
+
assert.deepStrictEqual(inspect(parser, input('($)$', new Context())), [['<span class="paren">(<span class="math" translate="no" data-src="$)$">$)$</span></span>'], '']);
|
|
50
50
|
assert.deepStrictEqual(inspect(parser, input(')', new Context())), undefined);
|
|
51
51
|
assert.deepStrictEqual(inspect(parser, input('(1,2)', new Context())), [['<span class="paren">(1,2)</span>'], '']);
|
|
52
52
|
assert.deepStrictEqual(inspect(parser, input('(0-1)', new Context())), [['<span class="paren">(0-1)</span>'], '']);
|
|
@@ -85,8 +85,8 @@ describe('Unit: parser/inline/bracket', () => {
|
|
|
85
85
|
assert.deepStrictEqual(inspect(parser, input('"a', new Context())), [['"', 'a'], '']);
|
|
86
86
|
assert.deepStrictEqual(inspect(parser, input('"a"', new Context())), [['"', 'a', '"'], '']);
|
|
87
87
|
assert.deepStrictEqual(inspect(parser, input('"(")"', new Context())), [['"', '<span class="paren">(</span>', '"'], ')"']);
|
|
88
|
-
assert.deepStrictEqual(inspect(parser, input('"(("', new Context())), [['"', '<span class="
|
|
89
|
-
assert.deepStrictEqual(inspect(parser, input('"(\\")"', new Context())), [['"', '<span class="
|
|
88
|
+
assert.deepStrictEqual(inspect(parser, input('"(("', new Context())), [['"', '<span class="paren">(<span class="paren">(</span></span>', '"'], '']);
|
|
89
|
+
assert.deepStrictEqual(inspect(parser, input('"(\\")"', new Context())), [['"', '<span class="paren">(")</span>', '"'], '']);
|
|
90
90
|
assert.deepStrictEqual(inspect(parser, input('"(\n)"(")', new Context())), [['"', '<span class="paren">(</span>'], '\n)"(")']);
|
|
91
91
|
assert.deepStrictEqual(inspect(parser, input('"\n"', new Context())), [['"'], '\n"']);
|
|
92
92
|
assert.deepStrictEqual(inspect(parser, input('"\n"(")', new Context())), [['"'], '\n"(")']);
|
|
@@ -8,19 +8,9 @@ import { str } from '../source';
|
|
|
8
8
|
import { unwrap } from '../util';
|
|
9
9
|
import { html, defrag } from 'typed-dom/dom';
|
|
10
10
|
|
|
11
|
-
export
|
|
12
|
-
const
|
|
13
|
-
|
|
14
|
-
.replace(/[09AZaz.]|\-(?!\w)/g, c => String.fromCodePoint(c.codePointAt(0)! + 0xFEE0)),
|
|
15
|
-
'y');
|
|
16
|
-
export function bracketname(context: Context, syntax: RegExp, opener: number, closer: number): string {
|
|
17
|
-
const { source, position, range, linebreak } = context;
|
|
18
|
-
syntax.lastIndex = position - range + opener;
|
|
19
|
-
return range - opener - closer === 0
|
|
20
|
-
|| linebreak === 0
|
|
21
|
-
&& range - opener - closer <= 16
|
|
22
|
-
&& syntax.test(source)
|
|
23
|
-
&& syntax.lastIndex === position - closer
|
|
11
|
+
export function bracketname(context: Context, opener: number, closer: number): string {
|
|
12
|
+
const { range, linebreak } = context;
|
|
13
|
+
return range - opener - closer === 0 || linebreak === 0 && range - opener - closer <= 16
|
|
24
14
|
? 'paren'
|
|
25
15
|
: 'bracket';
|
|
26
16
|
}
|
|
@@ -54,12 +44,12 @@ const p1 = lazy(() => surround(
|
|
|
54
44
|
true, [],
|
|
55
45
|
([as, bs = new List(), cs], context) => new List([
|
|
56
46
|
new Node(html('span',
|
|
57
|
-
{ class: bracketname(context,
|
|
47
|
+
{ class: bracketname(context, 1, 1) },
|
|
58
48
|
defrag(unwrap(as.import(bs as List<Node<string>>).import(cs)))))
|
|
59
49
|
]),
|
|
60
50
|
([as, bs = new List()], context) => new List([
|
|
61
51
|
new Node(html('span',
|
|
62
|
-
{ class: bracketname(context,
|
|
52
|
+
{ class: bracketname(context, 1, 0) },
|
|
63
53
|
defrag(unwrap(as.import(bs as List<Node<string>>)))))
|
|
64
54
|
])));
|
|
65
55
|
|
|
@@ -70,12 +60,12 @@ const p2 = lazy(() => surround(
|
|
|
70
60
|
true, [],
|
|
71
61
|
([as, bs = new List(), cs], context) => new List([
|
|
72
62
|
new Node(html('span',
|
|
73
|
-
{ class: bracketname(context,
|
|
63
|
+
{ class: bracketname(context, 1, 1) },
|
|
74
64
|
defrag(unwrap(as.import(bs as List<Node<string>>).import(cs)))))
|
|
75
65
|
]),
|
|
76
66
|
([as, bs = new List()], context) => new List([
|
|
77
67
|
new Node(html('span',
|
|
78
|
-
{ class: bracketname(context,
|
|
68
|
+
{ class: bracketname(context, 1, 0) },
|
|
79
69
|
defrag(unwrap(as.import(bs as List<Node<string>>)))))
|
|
80
70
|
])));
|
|
81
71
|
|
|
@@ -51,8 +51,8 @@ describe('Unit: parser/inline/emphasis', () => {
|
|
|
51
51
|
assert.deepStrictEqual(inspect(parser, input('*a**b**c*', new Context())), [['<em>a<strong>b</strong>c</em>'], '']);
|
|
52
52
|
assert.deepStrictEqual(inspect(parser, input('*a**b**c*d', new Context())), [['<em>a<strong>b</strong>c</em>'], 'd']);
|
|
53
53
|
assert.deepStrictEqual(inspect(parser, input('*`a`*', new Context())), [['<em><code data-src="`a`">a</code></em>'], '']);
|
|
54
|
-
assert.deepStrictEqual(inspect(parser, input('*(*a*)*', new Context())), [['<em><span class="
|
|
55
|
-
assert.deepStrictEqual(inspect(parser, input('*(**a**)*', new Context())), [['<em><span class="
|
|
54
|
+
assert.deepStrictEqual(inspect(parser, input('*(*a*)*', new Context())), [['<em><span class="paren">(<em>a</em>)</span></em>'], '']);
|
|
55
|
+
assert.deepStrictEqual(inspect(parser, input('*(**a**)*', new Context())), [['<em><span class="paren">(<strong>a</strong>)</span></em>'], '']);
|
|
56
56
|
});
|
|
57
57
|
|
|
58
58
|
});
|
|
@@ -37,9 +37,9 @@ describe('Unit: parser/inline/emstrong', () => {
|
|
|
37
37
|
|
|
38
38
|
it('nest', () => {
|
|
39
39
|
assert.deepStrictEqual(inspect(parser, input('***`a`***', new Context())), [['<em><strong><code data-src="`a`">a</code></strong></em>'], '']);
|
|
40
|
-
assert.deepStrictEqual(inspect(parser, input('***(*a*)***', new Context())), [['<em><strong><span class="
|
|
41
|
-
assert.deepStrictEqual(inspect(parser, input('***(**a**)***', new Context())), [['<em><strong><span class="
|
|
42
|
-
assert.deepStrictEqual(inspect(parser, input('***(***a***)***', new Context())), [['<em><strong><span class="
|
|
40
|
+
assert.deepStrictEqual(inspect(parser, input('***(*a*)***', new Context())), [['<em><strong><span class="paren">(<em>a</em>)</span></strong></em>'], '']);
|
|
41
|
+
assert.deepStrictEqual(inspect(parser, input('***(**a**)***', new Context())), [['<em><strong><span class="paren">(<strong>a</strong>)</span></strong></em>'], '']);
|
|
42
|
+
assert.deepStrictEqual(inspect(parser, input('***(***a***)***', new Context())), [['<em><strong><span class="paren">(<em><strong>a</strong></em>)</span></strong></em>'], '']);
|
|
43
43
|
assert.deepStrictEqual(inspect(parser, input('***a*', new Context())), [['**', '<em>a</em>'], '']);
|
|
44
44
|
assert.deepStrictEqual(inspect(parser, input('***a*b', new Context())), [['**', '<em>a</em>', 'b'], '']);
|
|
45
45
|
assert.deepStrictEqual(inspect(parser, input('***a*b*', new Context())), [['**', '<em>a</em>', 'b'], '*']);
|
|
@@ -72,7 +72,7 @@ describe('Unit: parser/inline/extension/index', () => {
|
|
|
72
72
|
assert.deepStrictEqual(inspect(parser, input('[#!http://host]', new Context())), [['<a class="index" href="#index::!http://host">!http://host</a>'], '']);
|
|
73
73
|
assert.deepStrictEqual(inspect(parser, input('[#[% %]]', new Context())), [['<a class="index"><span class="remark"><input type="checkbox"><span>[% %]</span></span></a>'], '']);
|
|
74
74
|
assert.deepStrictEqual(inspect(parser, input('[#[% a %]]', new Context())), [['<a class="index"><span class="remark"><input type="checkbox"><span>[% a %]</span></span></a>'], '']);
|
|
75
|
-
assert.deepStrictEqual(inspect(parser, input('[#a((b))]', new Context())), [['<a class="index" href="#index::a((b))">a<span class="
|
|
75
|
+
assert.deepStrictEqual(inspect(parser, input('[#a((b))]', new Context())), [['<a class="index" href="#index::a((b))">a<span class="paren">(<span class="paren">(b)</span>)</span></a>'], '']);
|
|
76
76
|
assert.deepStrictEqual(inspect(parser, input('[#a[[b]]]', new Context())), [['<a class="index" href="#index::a[[b]]">a[[b]]</a>'], '']);
|
|
77
77
|
});
|
|
78
78
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { html } from './html';
|
|
1
|
+
import { html, TAGS } from './html';
|
|
2
2
|
import { some } from '../../combinator';
|
|
3
3
|
import { input } from '../../combinator/data/parser';
|
|
4
4
|
import { Context } from '../context';
|
|
@@ -8,6 +8,10 @@ describe('Unit: parser/inline/html', () => {
|
|
|
8
8
|
describe('html', () => {
|
|
9
9
|
const parser = some(html);
|
|
10
10
|
|
|
11
|
+
it('hash', () => {
|
|
12
|
+
assert(TAGS.every(tag => parser(input(`<${tag}>`, new Context()))));
|
|
13
|
+
});
|
|
14
|
+
|
|
11
15
|
it('xss', () => {
|
|
12
16
|
assert.deepStrictEqual(inspect(parser, input('<script>', new Context())), [['<span class="invalid"><script></span>'], '']);
|
|
13
17
|
assert.deepStrictEqual(inspect(parser, input('<script>alert()<script>', new Context())), [['<span class="invalid"><script>alert()<script></span>'], '']);
|