securemark 0.258.9 → 0.259.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/design.md +6 -5
- package/dist/index.js +535 -278
- package/markdown.d.ts +4 -3
- package/package.json +1 -1
- package/src/combinator/control/constraint/block.test.ts +5 -5
- package/src/combinator/control/constraint/block.ts +3 -2
- package/src/combinator/control/constraint/contract.ts +7 -5
- package/src/combinator/control/constraint/line.test.ts +6 -6
- package/src/combinator/control/constraint/line.ts +6 -5
- package/src/combinator/control/manipulation/convert.ts +6 -5
- package/src/combinator/control/manipulation/fence.ts +2 -1
- package/src/combinator/control/manipulation/indent.test.ts +14 -14
- package/src/combinator/control/manipulation/indent.ts +5 -5
- package/src/combinator/control/manipulation/lazy.ts +2 -2
- package/src/combinator/control/manipulation/match.ts +3 -2
- package/src/combinator/control/manipulation/recovery.ts +6 -6
- package/src/combinator/control/manipulation/scope.ts +13 -10
- package/src/combinator/control/manipulation/surround.ts +9 -8
- package/src/combinator/control/manipulation/trim.test.ts +9 -9
- package/src/combinator/control/monad/bind.ts +3 -2
- package/src/combinator/data/parser/context/memo.ts +3 -4
- package/src/combinator/data/parser/context.test.ts +9 -9
- package/src/combinator/data/parser/context.ts +38 -34
- package/src/combinator/data/parser/inits.ts +3 -2
- package/src/combinator/data/parser/sequence.test.ts +10 -10
- package/src/combinator/data/parser/sequence.ts +3 -2
- package/src/combinator/data/parser/some.test.ts +13 -13
- package/src/combinator/data/parser/some.ts +3 -2
- package/src/combinator/data/parser/subsequence.test.ts +14 -14
- package/src/combinator/data/parser/union.test.ts +10 -10
- package/src/combinator/data/parser/union.ts +2 -2
- package/src/combinator/data/parser.ts +6 -1
- package/src/parser/api/bind.ts +3 -3
- package/src/parser/api/header.ts +1 -1
- package/src/parser/api/normalize.ts +1 -1
- package/src/parser/api/parse.ts +3 -3
- package/src/parser/autolink.test.ts +1 -1
- package/src/parser/autolink.ts +2 -2
- package/src/parser/block/blockquote.test.ts +1 -1
- package/src/parser/block/blockquote.ts +1 -1
- package/src/parser/block/codeblock.test.ts +1 -1
- package/src/parser/block/codeblock.ts +1 -1
- package/src/parser/block/dlist.test.ts +1 -1
- package/src/parser/block/extension/aside.test.ts +1 -1
- package/src/parser/block/extension/example.test.ts +1 -1
- package/src/parser/block/extension/example.ts +1 -1
- package/src/parser/block/extension/fig.test.ts +1 -1
- package/src/parser/block/extension/figbase.test.ts +1 -1
- package/src/parser/block/extension/figure.test.ts +1 -1
- package/src/parser/block/extension/figure.ts +1 -1
- package/src/parser/block/extension/message.test.ts +1 -1
- package/src/parser/block/extension/message.ts +1 -1
- package/src/parser/block/extension/placeholder.test.ts +1 -1
- package/src/parser/block/extension/table.test.ts +1 -1
- package/src/parser/block/extension/table.ts +1 -1
- package/src/parser/block/extension.test.ts +1 -1
- package/src/parser/block/heading.test.ts +3 -3
- package/src/parser/block/heading.ts +1 -1
- package/src/parser/block/horizontalrule.test.ts +1 -1
- package/src/parser/block/ilist.test.ts +1 -1
- package/src/parser/block/mathblock.test.ts +1 -1
- package/src/parser/block/olist.test.ts +1 -1
- package/src/parser/block/olist.ts +5 -5
- package/src/parser/block/paragraph.test.ts +1 -1
- package/src/parser/block/reply/cite.test.ts +4 -2
- package/src/parser/block/reply/cite.ts +2 -1
- package/src/parser/block/reply/quote.test.ts +1 -1
- package/src/parser/block/reply/quote.ts +2 -2
- package/src/parser/block/reply.test.ts +1 -1
- package/src/parser/block/sidefence.test.ts +1 -1
- package/src/parser/block/table.test.ts +1 -1
- package/src/parser/block/table.ts +1 -1
- package/src/parser/block/ulist.test.ts +1 -1
- package/src/parser/block/ulist.ts +1 -1
- package/src/parser/block.ts +2 -2
- package/src/parser/context.ts +15 -6
- package/src/parser/header.test.ts +1 -1
- package/src/parser/header.ts +3 -3
- package/src/parser/inline/annotation.test.ts +1 -1
- package/src/parser/inline/annotation.ts +3 -4
- package/src/parser/inline/autolink/account.test.ts +1 -1
- package/src/parser/inline/autolink/anchor.test.ts +1 -1
- package/src/parser/inline/autolink/channel.test.ts +1 -1
- package/src/parser/inline/autolink/email.test.ts +1 -1
- package/src/parser/inline/autolink/email.ts +1 -1
- package/src/parser/inline/autolink/hashnum.test.ts +1 -1
- package/src/parser/inline/autolink/hashtag.test.ts +1 -1
- package/src/parser/inline/autolink/url.test.ts +1 -1
- package/src/parser/inline/autolink.ts +1 -1
- package/src/parser/inline/bracket.test.ts +1 -1
- package/src/parser/inline/bracket.ts +8 -8
- package/src/parser/inline/code.test.ts +1 -1
- package/src/parser/inline/code.ts +2 -2
- package/src/parser/inline/comment.test.ts +1 -1
- package/src/parser/inline/comment.ts +2 -2
- package/src/parser/inline/deletion.test.ts +1 -1
- package/src/parser/inline/deletion.ts +2 -2
- package/src/parser/inline/emphasis.test.ts +1 -1
- package/src/parser/inline/emphasis.ts +2 -2
- package/src/parser/inline/emstrong.ts +4 -4
- package/src/parser/inline/escape.ts +3 -3
- package/src/parser/inline/extension/index.test.ts +1 -1
- package/src/parser/inline/extension/index.ts +3 -4
- package/src/parser/inline/extension/indexer.test.ts +1 -1
- package/src/parser/inline/extension/label.test.ts +1 -1
- package/src/parser/inline/extension/placeholder.test.ts +1 -1
- package/src/parser/inline/extension/placeholder.ts +2 -2
- package/src/parser/inline/html.test.ts +1 -1
- package/src/parser/inline/html.ts +2 -2
- package/src/parser/inline/htmlentity.test.ts +1 -1
- package/src/parser/inline/htmlentity.ts +1 -1
- package/src/parser/inline/insertion.test.ts +1 -1
- package/src/parser/inline/insertion.ts +2 -2
- package/src/parser/inline/link.test.ts +1 -1
- package/src/parser/inline/link.ts +14 -22
- package/src/parser/inline/mark.test.ts +1 -1
- package/src/parser/inline/mark.ts +2 -2
- package/src/parser/inline/math.test.ts +1 -1
- package/src/parser/inline/math.ts +1 -1
- package/src/parser/inline/media.test.ts +1 -1
- package/src/parser/inline/media.ts +3 -3
- package/src/parser/inline/reference.test.ts +1 -1
- package/src/parser/inline/reference.ts +3 -4
- package/src/parser/inline/ruby.test.ts +1 -1
- package/src/parser/inline/ruby.ts +5 -5
- package/src/parser/inline/shortmedia.test.ts +1 -1
- package/src/parser/inline/strong.test.ts +1 -1
- package/src/parser/inline/strong.ts +2 -2
- package/src/parser/inline/template.test.ts +1 -1
- package/src/parser/inline/template.ts +2 -2
- package/src/parser/inline.test.ts +1 -1
- package/src/parser/locale.test.ts +1 -1
- package/src/parser/segment.ts +1 -1
- package/src/parser/source/escapable.test.ts +1 -1
- package/src/parser/source/escapable.ts +1 -1
- package/src/parser/source/line.test.ts +1 -1
- package/src/parser/source/line.ts +2 -2
- package/src/parser/source/str.ts +4 -4
- package/src/parser/source/text.test.ts +1 -1
- package/src/parser/source/text.ts +4 -4
- package/src/parser/source/unescapable.test.ts +1 -1
- package/src/parser/source/unescapable.ts +1 -1
- package/src/parser/visibility.ts +13 -13
- package/src/util/quote.ts +1 -1
|
@@ -9,7 +9,7 @@ export function reset<T>(base: Ctx, parser: Parser<T>): Parser<T> {
|
|
|
9
9
|
assert(Object.freeze(base));
|
|
10
10
|
const changes = Object.entries(base);
|
|
11
11
|
const values = Array(changes.length);
|
|
12
|
-
return (source, context) =>
|
|
12
|
+
return ({ source, context }) =>
|
|
13
13
|
apply(parser, source, ObjectCreate(context), changes, values);
|
|
14
14
|
}
|
|
15
15
|
|
|
@@ -19,7 +19,7 @@ export function context<T>(base: Ctx, parser: Parser<T>): Parser<T> {
|
|
|
19
19
|
assert(Object.freeze(base));
|
|
20
20
|
const changes = Object.entries(base);
|
|
21
21
|
const values = Array(changes.length);
|
|
22
|
-
return (source, context) =>
|
|
22
|
+
return ({ source, context }) =>
|
|
23
23
|
apply(parser, source, context, changes, values);
|
|
24
24
|
}
|
|
25
25
|
|
|
@@ -41,7 +41,7 @@ function apply<T>(parser: Parser<T>, source: string, context: Ctx, changes: [str
|
|
|
41
41
|
context[prop] = change[1];
|
|
42
42
|
}
|
|
43
43
|
}
|
|
44
|
-
const result = parser(source, context);
|
|
44
|
+
const result = parser({ source, context });
|
|
45
45
|
if (context) for (let i = 0; i < changes.length; ++i) {
|
|
46
46
|
const change = changes[i];
|
|
47
47
|
const prop = change[0];
|
|
@@ -56,47 +56,47 @@ function apply<T>(parser: Parser<T>, source: string, context: Ctx, changes: [str
|
|
|
56
56
|
return result;
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
-
export function syntax<P extends Parser<unknown>>(syntax: number, precedence: number, cost: number, parser: P): P;
|
|
60
|
-
export function syntax<T>(syntax: number,
|
|
61
|
-
return creation(cost, (
|
|
59
|
+
export function syntax<P extends Parser<unknown>>(syntax: number, precedence: number, cost: number, state: number, parser: P): P;
|
|
60
|
+
export function syntax<T>(syntax: number, prec: number, cost: number, state: number, parser?: Parser<T>): Parser<T> {
|
|
61
|
+
return creation(cost, precedence(prec, input => {
|
|
62
|
+
const { source, context } = input;
|
|
62
63
|
if (source === '') return;
|
|
63
64
|
const memo = context.memo ??= new Memo();
|
|
64
65
|
context.memorable ??= ~0;
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
const
|
|
68
|
-
const
|
|
69
|
-
const cache = syntax && memo.get(position, syntax,
|
|
66
|
+
context.offset ??= 0;
|
|
67
|
+
const position = source.length + context.offset!;
|
|
68
|
+
const st0 = context.state ?? 0;
|
|
69
|
+
const st1 = context.state = st0 | state;
|
|
70
|
+
const cache = syntax && memo.get(position, syntax, st1);
|
|
70
71
|
const result: Result<T> = cache
|
|
71
72
|
? cache.length === 0
|
|
72
73
|
? undefined
|
|
73
74
|
: [cache[0], source.slice(cache[1])]
|
|
74
|
-
: parser!(
|
|
75
|
-
if (syntax &&
|
|
76
|
-
cache ?? memo.set(position, syntax,
|
|
77
|
-
assert.deepStrictEqual(cache && cache, cache && memo.get(position, syntax,
|
|
75
|
+
: parser!(input);
|
|
76
|
+
if (syntax && st0 & context.memorable!) {
|
|
77
|
+
cache ?? memo.set(position, syntax, st1, eval(result), source.length - exec(result, '').length);
|
|
78
|
+
assert.deepStrictEqual(cache && cache, cache && memo.get(position, syntax, st1));
|
|
78
79
|
}
|
|
79
|
-
if (result && !
|
|
80
|
-
assert(!(
|
|
81
|
-
memo.clear(position);
|
|
80
|
+
if (result && !st0 && memo.length! >= position + 2) {
|
|
81
|
+
assert(!(st0 & context.memorable!));
|
|
82
|
+
memo.clear(position + 2);
|
|
82
83
|
}
|
|
83
|
-
context.
|
|
84
|
+
context.state = st0;
|
|
84
85
|
return result;
|
|
85
|
-
});
|
|
86
|
+
}));
|
|
86
87
|
}
|
|
87
88
|
|
|
88
89
|
export function creation<P extends Parser<unknown>>(parser: P): P;
|
|
89
90
|
export function creation<P extends Parser<unknown>>(cost: number, parser: P): P;
|
|
90
91
|
export function creation(cost: number | Parser<unknown>, parser?: Parser<unknown>): Parser<unknown> {
|
|
91
92
|
if (typeof cost === 'function') return creation(1, cost);
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
const { resources = { clock: 1, recursion: 1 } } = context;
|
|
93
|
+
assert(cost > 0);
|
|
94
|
+
return input => {
|
|
95
|
+
const resources = input.context.resources ?? { clock: 1, recursion: 1 };
|
|
96
96
|
if (resources.clock <= 0) throw new Error('Too many creations');
|
|
97
97
|
if (resources.recursion <= 0) throw new Error('Too much recursion');
|
|
98
98
|
--resources.recursion;
|
|
99
|
-
const result = parser!(
|
|
99
|
+
const result = parser!(input);
|
|
100
100
|
++resources.recursion;
|
|
101
101
|
if (result) {
|
|
102
102
|
resources.clock -= cost;
|
|
@@ -107,10 +107,12 @@ export function creation(cost: number | Parser<unknown>, parser?: Parser<unknown
|
|
|
107
107
|
|
|
108
108
|
export function precedence<P extends Parser<unknown>>(precedence: number, parser: P): P;
|
|
109
109
|
export function precedence<T>(precedence: number, parser: Parser<T>): Parser<T> {
|
|
110
|
-
|
|
110
|
+
assert(precedence > 0);
|
|
111
|
+
return input => {
|
|
112
|
+
const { context } = input;
|
|
111
113
|
const p = context.precedence;
|
|
112
114
|
context.precedence = precedence;
|
|
113
|
-
const result = parser(
|
|
115
|
+
const result = parser(input);
|
|
114
116
|
context.precedence = p;
|
|
115
117
|
return result;
|
|
116
118
|
};
|
|
@@ -118,9 +120,9 @@ export function precedence<T>(precedence: number, parser: Parser<T>): Parser<T>
|
|
|
118
120
|
|
|
119
121
|
export function guard<P extends Parser<unknown>>(f: (context: Context<P>) => boolean | number, parser: P): P;
|
|
120
122
|
export function guard<T>(f: (context: Ctx) => boolean | number, parser: Parser<T>): Parser<T> {
|
|
121
|
-
return
|
|
122
|
-
f(context)
|
|
123
|
-
? parser(
|
|
123
|
+
return input =>
|
|
124
|
+
f(input.context)
|
|
125
|
+
? parser(input)
|
|
124
126
|
: undefined;
|
|
125
127
|
}
|
|
126
128
|
|
|
@@ -132,12 +134,13 @@ export function constraint<T>(state: number, positive: boolean | Parser<T>, pars
|
|
|
132
134
|
positive = true;
|
|
133
135
|
}
|
|
134
136
|
assert(state);
|
|
135
|
-
return
|
|
137
|
+
return input => {
|
|
138
|
+
const { context } = input;
|
|
136
139
|
const s = positive
|
|
137
140
|
? state & context.state!
|
|
138
141
|
: state & ~context.state!;
|
|
139
142
|
return s === state
|
|
140
|
-
? parser!(
|
|
143
|
+
? parser!(input)
|
|
141
144
|
: undefined;
|
|
142
145
|
};
|
|
143
146
|
}
|
|
@@ -150,12 +153,13 @@ export function state<T>(state: number, positive: boolean | Parser<T>, parser?:
|
|
|
150
153
|
positive = true;
|
|
151
154
|
}
|
|
152
155
|
assert(state);
|
|
153
|
-
return
|
|
156
|
+
return input => {
|
|
157
|
+
const { context } = input;
|
|
154
158
|
const s = context.state ?? 0;
|
|
155
159
|
context.state = positive
|
|
156
160
|
? s | state
|
|
157
161
|
: s & ~state;
|
|
158
|
-
const result = parser!(
|
|
162
|
+
const result = parser!(input);
|
|
159
163
|
context.state = s;
|
|
160
164
|
return result;
|
|
161
165
|
};
|
|
@@ -6,13 +6,14 @@ export function inits<P extends Parser<unknown>>(parsers: SubParsers<P>, resume?
|
|
|
6
6
|
export function inits<T, D extends Parser<T>[]>(parsers: D, resume?: (nodes: T[], rest: string) => boolean): Parser<T, Ctx, D> {
|
|
7
7
|
assert(parsers.every(f => f));
|
|
8
8
|
if (parsers.length === 1) return parsers[0];
|
|
9
|
-
return
|
|
9
|
+
return input => {
|
|
10
|
+
const { source, context } = input;
|
|
10
11
|
let rest = source;
|
|
11
12
|
let nodes: T[] | undefined;
|
|
12
13
|
for (let i = 0, len = parsers.length; i < len; ++i) {
|
|
13
14
|
if (rest === '') break;
|
|
14
15
|
if (context.delimiters?.match(rest, context.precedence)) break;
|
|
15
|
-
const result = parsers[i](rest, context);
|
|
16
|
+
const result = parsers[i]({ source: rest, context });
|
|
16
17
|
assert(check(rest, result));
|
|
17
18
|
if (!result) break;
|
|
18
19
|
nodes = nodes
|
|
@@ -4,12 +4,12 @@ import { inspect } from '../../../debug.test';
|
|
|
4
4
|
|
|
5
5
|
describe('Unit: combinator/data/parser/sequence', () => {
|
|
6
6
|
describe('sequence', () => {
|
|
7
|
-
const a: Parser<string, never> = source => {
|
|
7
|
+
const a: Parser<string, never> = ({ source }) => {
|
|
8
8
|
return source && source[0] === 'a'
|
|
9
9
|
? [['A'], source.slice(1)]
|
|
10
10
|
: undefined;
|
|
11
11
|
};
|
|
12
|
-
const b: Parser<string, never> = source => {
|
|
12
|
+
const b: Parser<string, never> = ({ source }) => {
|
|
13
13
|
return source && source[0] === 'b'
|
|
14
14
|
? [['B'], source.slice(1)]
|
|
15
15
|
: undefined;
|
|
@@ -18,14 +18,14 @@ describe('Unit: combinator/data/parser/sequence', () => {
|
|
|
18
18
|
|
|
19
19
|
it('basic', () => {
|
|
20
20
|
const parser = ab;
|
|
21
|
-
assert.deepStrictEqual(inspect(parser('', {})), undefined);
|
|
22
|
-
assert.deepStrictEqual(inspect(parser('a', {})), undefined);
|
|
23
|
-
assert.deepStrictEqual(inspect(parser('b', {})), undefined);
|
|
24
|
-
assert.deepStrictEqual(inspect(parser('ab', {})), [['A', 'B'], '']);
|
|
25
|
-
assert.deepStrictEqual(inspect(parser('ba', {})), undefined);
|
|
26
|
-
assert.deepStrictEqual(inspect(parser('aab', {})), undefined);
|
|
27
|
-
assert.deepStrictEqual(inspect(parser('abb', {})), [['A', 'B'], 'b']);
|
|
28
|
-
assert.deepStrictEqual(inspect(parser('bba', {})), undefined);
|
|
21
|
+
assert.deepStrictEqual(inspect(parser({ source: '', context: {} })), undefined);
|
|
22
|
+
assert.deepStrictEqual(inspect(parser({ source: 'a', context: {} })), undefined);
|
|
23
|
+
assert.deepStrictEqual(inspect(parser({ source: 'b', context: {} })), undefined);
|
|
24
|
+
assert.deepStrictEqual(inspect(parser({ source: 'ab', context: {} })), [['A', 'B'], '']);
|
|
25
|
+
assert.deepStrictEqual(inspect(parser({ source: 'ba', context: {} })), undefined);
|
|
26
|
+
assert.deepStrictEqual(inspect(parser({ source: 'aab', context: {} })), undefined);
|
|
27
|
+
assert.deepStrictEqual(inspect(parser({ source: 'abb', context: {} })), [['A', 'B'], 'b']);
|
|
28
|
+
assert.deepStrictEqual(inspect(parser({ source: 'bba', context: {} })), undefined);
|
|
29
29
|
});
|
|
30
30
|
|
|
31
31
|
});
|
|
@@ -6,13 +6,14 @@ export function sequence<P extends Parser<unknown>>(parsers: SubParsers<P>, resu
|
|
|
6
6
|
export function sequence<T, D extends Parser<T>[]>(parsers: D, resume?: (nodes: T[], rest: string) => boolean): Parser<T, Ctx, D> {
|
|
7
7
|
assert(parsers.every(f => f));
|
|
8
8
|
if (parsers.length === 1) return parsers[0];
|
|
9
|
-
return
|
|
9
|
+
return input => {
|
|
10
|
+
const { source, context } = input;
|
|
10
11
|
let rest = source;
|
|
11
12
|
let nodes: T[] | undefined;
|
|
12
13
|
for (let i = 0, len = parsers.length; i < len; ++i) {
|
|
13
14
|
if (rest === '') return;
|
|
14
15
|
if (context.delimiters?.match(rest, context.precedence)) return;
|
|
15
|
-
const result = parsers[i](rest, context);
|
|
16
|
+
const result = parsers[i]({ source: rest, context });
|
|
16
17
|
assert(check(rest, result));
|
|
17
18
|
if (!result) return;
|
|
18
19
|
nodes = nodes
|
|
@@ -5,12 +5,12 @@ import { inspect } from '../../../debug.test';
|
|
|
5
5
|
|
|
6
6
|
describe('Unit: combinator/data/parser/some', () => {
|
|
7
7
|
describe('some', () => {
|
|
8
|
-
const a: Parser<string, never> = source => {
|
|
8
|
+
const a: Parser<string, never> = ({ source }) => {
|
|
9
9
|
return source && source[0] === 'a'
|
|
10
10
|
? [['A'], source.slice(1)]
|
|
11
11
|
: undefined;
|
|
12
12
|
};
|
|
13
|
-
const b: Parser<string, never> = source => {
|
|
13
|
+
const b: Parser<string, never> = ({ source }) => {
|
|
14
14
|
return source && source[0] === 'b'
|
|
15
15
|
? [['B'], source.slice(1)]
|
|
16
16
|
: undefined;
|
|
@@ -19,17 +19,17 @@ describe('Unit: combinator/data/parser/some', () => {
|
|
|
19
19
|
|
|
20
20
|
it('basic', () => {
|
|
21
21
|
const parser = some(ab, /^aaa/);
|
|
22
|
-
assert.deepStrictEqual(inspect(parser('', {})), undefined);
|
|
23
|
-
assert.deepStrictEqual(inspect(parser('a', {})), [['A'], '']);
|
|
24
|
-
assert.deepStrictEqual(inspect(parser('b', {})), [['B'], '']);
|
|
25
|
-
assert.deepStrictEqual(inspect(parser('ab', {})), [['A', 'B'], '']);
|
|
26
|
-
assert.deepStrictEqual(inspect(parser('ba', {})), [['B', 'A'], '']);
|
|
27
|
-
assert.deepStrictEqual(inspect(parser('aab', {})), [['A', 'A', 'B'], '']);
|
|
28
|
-
assert.deepStrictEqual(inspect(parser('bba', {})), [['B', 'B', 'A'], '']);
|
|
29
|
-
assert.deepStrictEqual(inspect(parser('aaa', {})), undefined);
|
|
30
|
-
assert.deepStrictEqual(inspect(parser('bbb', {})), [['B', 'B', 'B'], '']);
|
|
31
|
-
assert.deepStrictEqual(inspect(parser('aaab', {})), undefined);
|
|
32
|
-
assert.deepStrictEqual(inspect(parser('baaa', {})), [['B'], 'aaa']);
|
|
22
|
+
assert.deepStrictEqual(inspect(parser({ source: '', context: {} })), undefined);
|
|
23
|
+
assert.deepStrictEqual(inspect(parser({ source: 'a', context: {} })), [['A'], '']);
|
|
24
|
+
assert.deepStrictEqual(inspect(parser({ source: 'b', context: {} })), [['B'], '']);
|
|
25
|
+
assert.deepStrictEqual(inspect(parser({ source: 'ab', context: {} })), [['A', 'B'], '']);
|
|
26
|
+
assert.deepStrictEqual(inspect(parser({ source: 'ba', context: {} })), [['B', 'A'], '']);
|
|
27
|
+
assert.deepStrictEqual(inspect(parser({ source: 'aab', context: {} })), [['A', 'A', 'B'], '']);
|
|
28
|
+
assert.deepStrictEqual(inspect(parser({ source: 'bba', context: {} })), [['B', 'B', 'A'], '']);
|
|
29
|
+
assert.deepStrictEqual(inspect(parser({ source: 'aaa', context: {} })), undefined);
|
|
30
|
+
assert.deepStrictEqual(inspect(parser({ source: 'bbb', context: {} })), [['B', 'B', 'B'], '']);
|
|
31
|
+
assert.deepStrictEqual(inspect(parser({ source: 'aaab', context: {} })), undefined);
|
|
32
|
+
assert.deepStrictEqual(inspect(parser({ source: 'baaa', context: {} })), [['B'], 'aaa']);
|
|
33
33
|
});
|
|
34
34
|
|
|
35
35
|
});
|
|
@@ -16,7 +16,8 @@ export function some<T>(parser: Parser<T>, end?: string | RegExp | number, delim
|
|
|
16
16
|
matcher: Delimiters.matcher(delimiter),
|
|
17
17
|
precedence,
|
|
18
18
|
}));
|
|
19
|
-
return
|
|
19
|
+
return input => {
|
|
20
|
+
const { source, context } = input;
|
|
20
21
|
if (source === '') return;
|
|
21
22
|
let rest = source;
|
|
22
23
|
let nodes: T[] | undefined;
|
|
@@ -28,7 +29,7 @@ export function some<T>(parser: Parser<T>, end?: string | RegExp | number, delim
|
|
|
28
29
|
if (rest === '') break;
|
|
29
30
|
if (match(rest)) break;
|
|
30
31
|
if (context.delimiters?.match(rest, context.precedence)) break;
|
|
31
|
-
const result = parser(rest, context);
|
|
32
|
+
const result = parser({ source: rest, context });
|
|
32
33
|
assert.doesNotThrow(() => limit < 0 && check(rest, result));
|
|
33
34
|
if (!result) break;
|
|
34
35
|
nodes = nodes
|
|
@@ -4,17 +4,17 @@ import { inspect } from '../../../debug.test';
|
|
|
4
4
|
|
|
5
5
|
describe('Unit: combinator/data/parser/subsequence', () => {
|
|
6
6
|
describe('subsequence', () => {
|
|
7
|
-
const a: Parser<string, never> = source => {
|
|
7
|
+
const a: Parser<string, never> = ({ source }) => {
|
|
8
8
|
return source && source[0] === 'a'
|
|
9
9
|
? [['A'], source.slice(1)]
|
|
10
10
|
: undefined;
|
|
11
11
|
};
|
|
12
|
-
const b: Parser<string, never> = source => {
|
|
12
|
+
const b: Parser<string, never> = ({ source }) => {
|
|
13
13
|
return source && source[0] === 'b'
|
|
14
14
|
? [['B'], source.slice(1)]
|
|
15
15
|
: undefined;
|
|
16
16
|
};
|
|
17
|
-
const c: Parser<string, never> = source => {
|
|
17
|
+
const c: Parser<string, never> = ({ source }) => {
|
|
18
18
|
return source && source[0] === 'c'
|
|
19
19
|
? [['C'], source.slice(1)]
|
|
20
20
|
: undefined;
|
|
@@ -23,17 +23,17 @@ describe('Unit: combinator/data/parser/subsequence', () => {
|
|
|
23
23
|
|
|
24
24
|
it('basic', () => {
|
|
25
25
|
const parser = abc;
|
|
26
|
-
assert.deepStrictEqual(inspect(parser('', {})), undefined);
|
|
27
|
-
assert.deepStrictEqual(inspect(parser('a', {})), [['A'], '']);
|
|
28
|
-
assert.deepStrictEqual(inspect(parser('b', {})), [['B'], '']);
|
|
29
|
-
assert.deepStrictEqual(inspect(parser('c', {})), [['C'], '']);
|
|
30
|
-
assert.deepStrictEqual(inspect(parser('ab', {})), [['A', 'B'], '']);
|
|
31
|
-
assert.deepStrictEqual(inspect(parser('ba', {})), [['B'], 'a']);
|
|
32
|
-
assert.deepStrictEqual(inspect(parser('aab', {})), [['A'], 'ab']);
|
|
33
|
-
assert.deepStrictEqual(inspect(parser('abb', {})), [['A', 'B'], 'b']);
|
|
34
|
-
assert.deepStrictEqual(inspect(parser('bba', {})), [['B'], 'ba']);
|
|
35
|
-
assert.deepStrictEqual(inspect(parser('ac', {})), [['A', 'C'], '']);
|
|
36
|
-
assert.deepStrictEqual(inspect(parser('bc', {})), [['B', 'C'], '']);
|
|
26
|
+
assert.deepStrictEqual(inspect(parser({ source: '', context: {} })), undefined);
|
|
27
|
+
assert.deepStrictEqual(inspect(parser({ source: 'a', context: {} })), [['A'], '']);
|
|
28
|
+
assert.deepStrictEqual(inspect(parser({ source: 'b', context: {} })), [['B'], '']);
|
|
29
|
+
assert.deepStrictEqual(inspect(parser({ source: 'c', context: {} })), [['C'], '']);
|
|
30
|
+
assert.deepStrictEqual(inspect(parser({ source: 'ab', context: {} })), [['A', 'B'], '']);
|
|
31
|
+
assert.deepStrictEqual(inspect(parser({ source: 'ba', context: {} })), [['B'], 'a']);
|
|
32
|
+
assert.deepStrictEqual(inspect(parser({ source: 'aab', context: {} })), [['A'], 'ab']);
|
|
33
|
+
assert.deepStrictEqual(inspect(parser({ source: 'abb', context: {} })), [['A', 'B'], 'b']);
|
|
34
|
+
assert.deepStrictEqual(inspect(parser({ source: 'bba', context: {} })), [['B'], 'ba']);
|
|
35
|
+
assert.deepStrictEqual(inspect(parser({ source: 'ac', context: {} })), [['A', 'C'], '']);
|
|
36
|
+
assert.deepStrictEqual(inspect(parser({ source: 'bc', context: {} })), [['B', 'C'], '']);
|
|
37
37
|
});
|
|
38
38
|
|
|
39
39
|
});
|
|
@@ -4,12 +4,12 @@ import { inspect } from '../../../debug.test';
|
|
|
4
4
|
|
|
5
5
|
describe('Unit: combinator/data/parser/union', () => {
|
|
6
6
|
describe('union', () => {
|
|
7
|
-
const a: Parser<string, never> = source => {
|
|
7
|
+
const a: Parser<string, never> = ({ source }) => {
|
|
8
8
|
return source && source[0] === 'a'
|
|
9
9
|
? [['A'], source.slice(1)]
|
|
10
10
|
: undefined;
|
|
11
11
|
};
|
|
12
|
-
const b: Parser<string, never> = source => {
|
|
12
|
+
const b: Parser<string, never> = ({ source }) => {
|
|
13
13
|
return source && source[0] === 'b'
|
|
14
14
|
? [['B'], source.slice(1)]
|
|
15
15
|
: undefined;
|
|
@@ -18,14 +18,14 @@ describe('Unit: combinator/data/parser/union', () => {
|
|
|
18
18
|
|
|
19
19
|
it('basic', () => {
|
|
20
20
|
const parser = ab;
|
|
21
|
-
assert.deepStrictEqual(inspect(parser('', {})), undefined);
|
|
22
|
-
assert.deepStrictEqual(inspect(parser('a', {})), [['A'], '']);
|
|
23
|
-
assert.deepStrictEqual(inspect(parser('b', {})), [['B'], '']);
|
|
24
|
-
assert.deepStrictEqual(inspect(parser('ab', {})), [['A'], 'b']);
|
|
25
|
-
assert.deepStrictEqual(inspect(parser('ba', {})), [['B'], 'a']);
|
|
26
|
-
assert.deepStrictEqual(inspect(parser('aab', {})), [['A'], 'ab']);
|
|
27
|
-
assert.deepStrictEqual(inspect(parser('abb', {})), [['A'], 'bb']);
|
|
28
|
-
assert.deepStrictEqual(inspect(parser('bba', {})), [['B'], 'ba']);
|
|
21
|
+
assert.deepStrictEqual(inspect(parser({ source: '', context: {} })), undefined);
|
|
22
|
+
assert.deepStrictEqual(inspect(parser({ source: 'a', context: {} })), [['A'], '']);
|
|
23
|
+
assert.deepStrictEqual(inspect(parser({ source: 'b', context: {} })), [['B'], '']);
|
|
24
|
+
assert.deepStrictEqual(inspect(parser({ source: 'ab', context: {} })), [['A'], 'b']);
|
|
25
|
+
assert.deepStrictEqual(inspect(parser({ source: 'ba', context: {} })), [['B'], 'a']);
|
|
26
|
+
assert.deepStrictEqual(inspect(parser({ source: 'aab', context: {} })), [['A'], 'ab']);
|
|
27
|
+
assert.deepStrictEqual(inspect(parser({ source: 'abb', context: {} })), [['A'], 'bb']);
|
|
28
|
+
assert.deepStrictEqual(inspect(parser({ source: 'bba', context: {} })), [['B'], 'ba']);
|
|
29
29
|
});
|
|
30
30
|
|
|
31
31
|
});
|
|
@@ -12,9 +12,9 @@ export function union<T, D extends Parser<T>[]>(parsers: D): Parser<T, Ctx, D> {
|
|
|
12
12
|
default:
|
|
13
13
|
return Function('parsers', [
|
|
14
14
|
'"use strict";',
|
|
15
|
-
'return (
|
|
15
|
+
'return (input, context) =>',
|
|
16
16
|
'0',
|
|
17
|
-
...parsers.map((_, i) => `|| parsers[${i}](
|
|
17
|
+
...parsers.map((_, i) => `|| parsers[${i}](input, context)`),
|
|
18
18
|
].join('\n'))(parsers);
|
|
19
19
|
}
|
|
20
20
|
}
|
|
@@ -2,7 +2,11 @@ import { Delimiters } from './parser/context/delimiter';
|
|
|
2
2
|
import { Memo } from './parser/context/memo';
|
|
3
3
|
|
|
4
4
|
export type Parser<T, C extends Ctx = Ctx, D extends Parser<unknown, C>[] = any>
|
|
5
|
-
= (
|
|
5
|
+
= (input: Input<C>) => Result<T, C, D>;
|
|
6
|
+
export interface Input<C extends Ctx = Ctx> {
|
|
7
|
+
readonly source: string;
|
|
8
|
+
readonly context: C;
|
|
9
|
+
}
|
|
6
10
|
export type Result<T, C extends Ctx = Ctx, D extends Parser<unknown, C>[] = any>
|
|
7
11
|
= readonly [T[], string, C, D]
|
|
8
12
|
| readonly [T[], string]
|
|
@@ -12,6 +16,7 @@ export interface Ctx {
|
|
|
12
16
|
clock: number;
|
|
13
17
|
recursion: number;
|
|
14
18
|
};
|
|
19
|
+
offset?: number;
|
|
15
20
|
precedence?: number;
|
|
16
21
|
delimiters?: Delimiters;
|
|
17
22
|
state?: number;
|
package/src/parser/api/bind.ts
CHANGED
|
@@ -5,7 +5,7 @@ import { eval } from '../../combinator/data/parser';
|
|
|
5
5
|
import { segment, validate, MAX_INPUT_SIZE } from '../segment';
|
|
6
6
|
import { header } from '../header';
|
|
7
7
|
import { block } from '../block';
|
|
8
|
-
import {
|
|
8
|
+
import { State } from '../context';
|
|
9
9
|
import { normalize } from './normalize';
|
|
10
10
|
import { headers } from './header';
|
|
11
11
|
import { figure } from '../processor/figure';
|
|
@@ -24,7 +24,7 @@ export function bind(target: DocumentFragment | HTMLElement | ShadowRoot, settin
|
|
|
24
24
|
let context: MarkdownParser.Context = {
|
|
25
25
|
...settings,
|
|
26
26
|
host: settings.host ?? new ReadonlyURL(location.pathname, location.origin),
|
|
27
|
-
memorable: backtrackable,
|
|
27
|
+
memorable: State.backtrackable,
|
|
28
28
|
};
|
|
29
29
|
if (context.host?.origin === 'null') throw new Error(`Invalid host: ${context.host.href}`);
|
|
30
30
|
assert(!settings.id);
|
|
@@ -77,7 +77,7 @@ export function bind(target: DocumentFragment | HTMLElement | ShadowRoot, settin
|
|
|
77
77
|
for (; index < sourceSegments.length - last; ++index) {
|
|
78
78
|
assert(rev === revision);
|
|
79
79
|
const seg = sourceSegments[index];
|
|
80
|
-
const es = eval(header(seg, { header: index === 0 }) || block(seg, context), []);
|
|
80
|
+
const es = eval(header({ source: seg, context: { header: index === 0 } }) || block({ source: seg, context }), []);
|
|
81
81
|
blocks.splice(index, 0, [seg, es, url]);
|
|
82
82
|
if (es.length === 0) continue;
|
|
83
83
|
// All deletion processes always run after all addition processes have done.
|
package/src/parser/api/header.ts
CHANGED
|
@@ -12,7 +12,7 @@ export function headers(source: string): string[] {
|
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
function parse(source: string): [HTMLElement, string] | [] {
|
|
15
|
-
const result = h(source, {});
|
|
15
|
+
const result = h({ source, context: {} });
|
|
16
16
|
const [el] = eval(result, []);
|
|
17
17
|
return el?.tagName === 'ASIDE'
|
|
18
18
|
? [el, exec(result!)]
|
|
@@ -60,7 +60,7 @@ export const invisibleHTMLEntityNames = [
|
|
|
60
60
|
] as const;
|
|
61
61
|
const unreadableHTMLEntityNames: readonly string[] = invisibleHTMLEntityNames.slice(2);
|
|
62
62
|
const unreadableEscapableCharacters = unreadableHTMLEntityNames
|
|
63
|
-
.map(name => eval(unsafehtmlentity(`&${name};`, {}))![0]);
|
|
63
|
+
.map(name => eval(unsafehtmlentity({ source: `&${name};`, context: {} }))![0]);
|
|
64
64
|
assert(unreadableEscapableCharacters.length === unreadableHTMLEntityNames.length);
|
|
65
65
|
assert(unreadableEscapableCharacters.every(c => c.length === 1));
|
|
66
66
|
const unreadableEscapableCharacter = new RegExp(`[${
|
package/src/parser/api/parse.ts
CHANGED
|
@@ -5,7 +5,7 @@ import { eval } from '../../combinator/data/parser';
|
|
|
5
5
|
import { segment, validate, MAX_SEGMENT_SIZE } from '../segment';
|
|
6
6
|
import { header } from '../header';
|
|
7
7
|
import { block } from '../block';
|
|
8
|
-
import {
|
|
8
|
+
import { State } from '../context';
|
|
9
9
|
import { normalize } from './normalize';
|
|
10
10
|
import { headers } from './header';
|
|
11
11
|
import { figure } from '../processor/figure';
|
|
@@ -30,13 +30,13 @@ export function parse(source: string, opts: Options = {}, context?: MarkdownPars
|
|
|
30
30
|
...context?.resources && {
|
|
31
31
|
resources: context.resources,
|
|
32
32
|
},
|
|
33
|
-
memorable: backtrackable,
|
|
33
|
+
memorable: State.backtrackable,
|
|
34
34
|
};
|
|
35
35
|
if (context.host?.origin === 'null') throw new Error(`Invalid host: ${context.host.href}`);
|
|
36
36
|
const node = frag();
|
|
37
37
|
let index = 0;
|
|
38
38
|
for (const seg of segment(source)) {
|
|
39
|
-
node.append(...eval(header(seg, { header: index++ === 0 }) || block(seg, context), []));
|
|
39
|
+
node.append(...eval(header({ source: seg, context: { header: index++ === 0 } }) || block({ source: seg, context }), []));
|
|
40
40
|
}
|
|
41
41
|
assert(opts.id !== '' || !node.querySelector('[id], .index[href], .label[href], .annotation > a[href], .reference > a[href]'));
|
|
42
42
|
if (opts.test) return node;
|
|
@@ -4,7 +4,7 @@ import { inspect } from '../debug.test';
|
|
|
4
4
|
|
|
5
5
|
describe('Unit: parser/autolink', () => {
|
|
6
6
|
describe('autolink', () => {
|
|
7
|
-
const parser = (source: string) => some(autolink)(source, {});
|
|
7
|
+
const parser = (source: string) => some(autolink)({ source, context: {} });
|
|
8
8
|
|
|
9
9
|
it('basic', () => {
|
|
10
10
|
assert.deepStrictEqual(inspect(parser(' http://host')), [[' ', '<a href="http://host" target="_blank">http://host</a>'], '']);
|
package/src/parser/autolink.ts
CHANGED
|
@@ -7,7 +7,7 @@ export import AutolinkParser = MarkdownParser.AutolinkParser;
|
|
|
7
7
|
|
|
8
8
|
const delimiter = /[@#>0-9A-Za-z\n]|\S[#>]/;
|
|
9
9
|
|
|
10
|
-
export const autolink: AutolinkParser = (source, context) => {
|
|
10
|
+
export const autolink: AutolinkParser = ({ source, context }) => {
|
|
11
11
|
if (source === '') return;
|
|
12
12
|
assert(source[0] !== '\x1B');
|
|
13
13
|
const i = source.search(delimiter);
|
|
@@ -15,7 +15,7 @@ export const autolink: AutolinkParser = (source, context) => {
|
|
|
15
15
|
case -1:
|
|
16
16
|
return [[source], ''];
|
|
17
17
|
case 0:
|
|
18
|
-
return parser(source, context);
|
|
18
|
+
return parser({ source, context });
|
|
19
19
|
default:
|
|
20
20
|
return [[source.slice(0, i)], source.slice(i)];
|
|
21
21
|
}
|
|
@@ -4,7 +4,7 @@ import { inspect } from '../../debug.test';
|
|
|
4
4
|
|
|
5
5
|
describe('Unit: parser/block/blockquote', () => {
|
|
6
6
|
describe('blockquote', () => {
|
|
7
|
-
const parser = (source: string) => some(blockquote)(source, {});
|
|
7
|
+
const parser = (source: string) => some(blockquote)({ source, context: {} });
|
|
8
8
|
|
|
9
9
|
it('invalid', () => {
|
|
10
10
|
assert.deepStrictEqual(inspect(parser('')), undefined);
|
|
@@ -37,7 +37,7 @@ const markdown: BlockquoteParser.MarkdownParser = lazy(() => fmap(
|
|
|
37
37
|
creation(99,
|
|
38
38
|
rewrite(
|
|
39
39
|
some(contentline, opener),
|
|
40
|
-
convert(unindent, (source, context) => {
|
|
40
|
+
convert(unindent, ({ source, context }) => {
|
|
41
41
|
const references = html('ol', { class: 'references' });
|
|
42
42
|
const document = parse(source, {
|
|
43
43
|
id: '',
|
|
@@ -4,7 +4,7 @@ import { inspect } from '../../debug.test';
|
|
|
4
4
|
|
|
5
5
|
describe('Unit: parser/block/codeblock', () => {
|
|
6
6
|
describe('codeblock', () => {
|
|
7
|
-
const parser = (source: string) => some(codeblock)(source, {});
|
|
7
|
+
const parser = (source: string) => some(codeblock)({ source, context: {} });
|
|
8
8
|
|
|
9
9
|
it('invalid', () => {
|
|
10
10
|
assert.deepStrictEqual(inspect(parser('')), undefined);
|
|
@@ -70,6 +70,6 @@ export const codeblock: CodeBlockParser = block(validate('```', fmap(
|
|
|
70
70
|
params.lang
|
|
71
71
|
? context.caches?.code?.get(`${params.lang ?? ''}\n${body.slice(0, -1)}`)?.cloneNode(true).childNodes ||
|
|
72
72
|
body.slice(0, -1) || undefined
|
|
73
|
-
: defrag(eval(some(autolink)(body.slice(0, -1), context), [])));
|
|
73
|
+
: defrag(eval(some(autolink)({ source: body.slice(0, -1), context }), [])));
|
|
74
74
|
return [el];
|
|
75
75
|
})));
|
|
@@ -4,7 +4,7 @@ import { inspect } from '../../debug.test';
|
|
|
4
4
|
|
|
5
5
|
describe('Unit: parser/block/dlist', () => {
|
|
6
6
|
describe('dlist', () => {
|
|
7
|
-
const parser = (source: string) => some(dlist)(source, {});
|
|
7
|
+
const parser = (source: string) => some(dlist)({ source, context: {} });
|
|
8
8
|
|
|
9
9
|
it('invalid', () => {
|
|
10
10
|
assert.deepStrictEqual(inspect(parser('')), undefined);
|
|
@@ -4,7 +4,7 @@ import { inspect } from '../../../debug.test';
|
|
|
4
4
|
|
|
5
5
|
describe('Unit: parser/block/extension/aside', () => {
|
|
6
6
|
describe('aside', () => {
|
|
7
|
-
const parser = (source: string) => some(aside)(source, {});
|
|
7
|
+
const parser = (source: string) => some(aside)({ source, context: {} });
|
|
8
8
|
|
|
9
9
|
it('invalid', () => {
|
|
10
10
|
assert.deepStrictEqual(inspect(parser('~~~aside\n~~~')), [['<pre class="invalid" translate="no">~~~aside\n~~~</pre>'], '']);
|
|
@@ -4,7 +4,7 @@ import { inspect } from '../../../debug.test';
|
|
|
4
4
|
|
|
5
5
|
describe('Unit: parser/block/extension/example', () => {
|
|
6
6
|
describe('example', () => {
|
|
7
|
-
const parser = (source: string) => some(example)(source, {});
|
|
7
|
+
const parser = (source: string) => some(example)({ source, context: {} });
|
|
8
8
|
|
|
9
9
|
it('invalid', () => {
|
|
10
10
|
assert.deepStrictEqual(inspect(parser('~~~example/\n~~~')), undefined);
|
|
@@ -44,7 +44,7 @@ export const example: ExtensionParser.ExampleParser = block(validate('~~~', fmap
|
|
|
44
44
|
html('aside', { class: 'example', 'data-type': 'math' }, [
|
|
45
45
|
html('pre', { translate: 'no' }, body.slice(0, -1)),
|
|
46
46
|
html('hr'),
|
|
47
|
-
eval(mathblock(`$$\n${body}$$`, context), [])[0],
|
|
47
|
+
eval(mathblock({ source: `$$\n${body}$$`, context }), [])[0],
|
|
48
48
|
]),
|
|
49
49
|
];
|
|
50
50
|
default:
|
|
@@ -4,7 +4,7 @@ import { inspect } from '../../../debug.test';
|
|
|
4
4
|
|
|
5
5
|
describe('Unit: parser/block/extension/fig', () => {
|
|
6
6
|
describe('fig', () => {
|
|
7
|
-
const parser = (source: string) => some(fig)(source, {});
|
|
7
|
+
const parser = (source: string) => some(fig)({ source, context: {} });
|
|
8
8
|
|
|
9
9
|
it('invalid', () => {
|
|
10
10
|
assert.deepStrictEqual(inspect(parser('\n!https://host\n')), undefined);
|
|
@@ -4,7 +4,7 @@ import { inspect } from '../../../debug.test';
|
|
|
4
4
|
|
|
5
5
|
describe('Unit: parser/block/extension/figbase', () => {
|
|
6
6
|
describe('figbase', () => {
|
|
7
|
-
const parser = (source: string) => some(figbase)(source, {});
|
|
7
|
+
const parser = (source: string) => some(figbase)({ source, context: {} });
|
|
8
8
|
|
|
9
9
|
it('invalid', () => {
|
|
10
10
|
assert.deepStrictEqual(inspect(parser('\n$-0')), undefined);
|