securemark 0.296.1 → 0.296.3
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/dist/index.js +162 -124
- package/package.json +1 -1
- package/src/combinator/control/constraint/contract.ts +4 -3
- package/src/combinator/control/manipulation/scope.ts +1 -1
- package/src/combinator/control/manipulation/surround.ts +32 -16
- package/src/combinator/data/delimiter.ts +82 -6
- package/src/combinator/data/parser/context.test.ts +2 -2
- package/src/combinator/data/parser/context.ts +12 -36
- package/src/parser/api/bind.ts +6 -6
- package/src/parser/api/parse.ts +1 -1
- package/src/parser/inline/annotation.ts +3 -3
- package/src/parser/inline/deletion.ts +1 -1
- package/src/parser/inline/emphasis.ts +4 -4
- package/src/parser/inline/emstrong.test.ts +1 -0
- package/src/parser/inline/emstrong.ts +3 -3
- package/src/parser/inline/extension/index.ts +2 -3
- package/src/parser/inline/extension/placeholder.ts +2 -2
- package/src/parser/inline/insertion.ts +1 -1
- package/src/parser/inline/italic.test.ts +1 -0
- package/src/parser/inline/italic.ts +2 -2
- package/src/parser/inline/link.ts +3 -3
- package/src/parser/inline/mark.test.ts +1 -0
- package/src/parser/inline/mark.ts +4 -4
- package/src/parser/inline/reference.ts +3 -3
- package/src/parser/inline/strong.ts +4 -4
- package/src/parser/source/str.ts +4 -4
- package/src/parser/util.ts +7 -4
- package/src/parser/visibility.ts +13 -28
|
@@ -1,50 +1,64 @@
|
|
|
1
1
|
import { Parser, Result, List, Node, Context, failsafe } from '../../data/parser';
|
|
2
|
-
import {
|
|
2
|
+
import { tester } from '../../data/delimiter';
|
|
3
3
|
|
|
4
4
|
export function surround<P extends Parser, S = string>(
|
|
5
|
-
opener: string | RegExp | Parser<S, Parser.Context<P>>,
|
|
5
|
+
opener: string | RegExp | Parser<S, Parser.Context<P>>,
|
|
6
|
+
parser: Parser.IntermediateParser<P>,
|
|
7
|
+
closer: string | RegExp | Parser<S, Parser.Context<P>>,
|
|
6
8
|
optional?: false,
|
|
7
9
|
backtracks?: readonly number[],
|
|
8
10
|
f?: (rss: [List<Node<S>>, List<Node<Parser.SubNode<P>>>, List<Node<S>>], context: Parser.Context<P>) => Result<Parser.Node<P>, Parser.Context<P>, Parser.SubParsers<P>>,
|
|
9
11
|
g?: (rss: [List<Node<S>>, List<Node<Parser.SubNode<P>>> | undefined], context: Parser.Context<P>) => Result<Parser.Node<P>, Parser.Context<P>, Parser.SubParsers<P>>,
|
|
10
12
|
): P;
|
|
11
13
|
export function surround<P extends Parser, S = string>(
|
|
12
|
-
opener: string | RegExp | Parser<S, Parser.Context<P>>,
|
|
14
|
+
opener: string | RegExp | Parser<S, Parser.Context<P>>,
|
|
15
|
+
parser: Parser.IntermediateParser<P>,
|
|
16
|
+
closer: string | RegExp | Parser<S, Parser.Context<P>>,
|
|
13
17
|
optional?: boolean,
|
|
14
18
|
backtracks?: readonly number[],
|
|
15
19
|
f?: (rss: [List<Node<S>>, List<Node<Parser.SubNode<P>>> | undefined, List<Node<S>>], context: Parser.Context<P>) => Result<Parser.Node<P>, Parser.Context<P>, Parser.SubParsers<P>>,
|
|
16
20
|
g?: (rss: [List<Node<S>>, List<Node<Parser.SubNode<P>>> | undefined], context: Parser.Context<P>) => Result<Parser.Node<P>, Parser.Context<P>, Parser.SubParsers<P>>,
|
|
17
21
|
): P;
|
|
18
22
|
export function surround<P extends Parser, S = string>(
|
|
19
|
-
opener: string | RegExp | Parser<S, Parser.Context<P>>,
|
|
23
|
+
opener: string | RegExp | Parser<S, Parser.Context<P>>,
|
|
24
|
+
parser: P,
|
|
25
|
+
closer: string | RegExp | Parser<S, Parser.Context<P>>,
|
|
20
26
|
optional?: false,
|
|
21
27
|
backtracks?: readonly number[],
|
|
22
28
|
f?: (rss: [List<Node<S>>, List<Node<Parser.Node<P>>>, List<Node<S>>], context: Parser.Context<P>) => Result<Parser.Node<P>, Parser.Context<P>, Parser.SubParsers<P>>,
|
|
23
29
|
g?: (rss: [List<Node<S>>, List<Node<Parser.Node<P>>> | undefined], context: Parser.Context<P>) => Result<Parser.Node<P>, Parser.Context<P>, Parser.SubParsers<P>>,
|
|
24
30
|
): P;
|
|
25
31
|
export function surround<P extends Parser, S = string>(
|
|
26
|
-
opener: string | RegExp | Parser<S, Parser.Context<P>>,
|
|
32
|
+
opener: string | RegExp | Parser<S, Parser.Context<P>>,
|
|
33
|
+
parser: P,
|
|
34
|
+
closer: string | RegExp | Parser<S, Parser.Context<P>>,
|
|
27
35
|
optional?: boolean,
|
|
28
36
|
backtracks?: readonly number[],
|
|
29
37
|
f?: (rss: [List<Node<S>>, List<Node<Parser.Node<P>>> | undefined, List<Node<S>>], context: Parser.Context<P>) => Result<Parser.Node<P>, Parser.Context<P>, Parser.SubParsers<P>>,
|
|
30
38
|
g?: (rss: [List<Node<S>>, List<Node<Parser.Node<P>>> | undefined], context: Parser.Context<P>) => Result<Parser.Node<P>, Parser.Context<P>, Parser.SubParsers<P>>,
|
|
31
39
|
): P;
|
|
32
40
|
export function surround<P extends Parser<string>, S = string>(
|
|
33
|
-
opener: string | RegExp | Parser<S, Parser.Context<P>>,
|
|
41
|
+
opener: string | RegExp | Parser<S, Parser.Context<P>>,
|
|
42
|
+
parser: string | RegExp | P,
|
|
43
|
+
closer: string | RegExp | Parser<S, Parser.Context<P>>,
|
|
34
44
|
optional?: false,
|
|
35
45
|
backtracks?: readonly number[],
|
|
36
46
|
f?: (rss: [List<Node<S>>, List<Node<Parser.Node<P>>>, List<Node<S>>], context: Parser.Context<P>) => Result<Parser.Node<P>, Parser.Context<P>, Parser.SubParsers<P>>,
|
|
37
47
|
g?: (rss: [List<Node<S>>, List<Node<Parser.Node<P>>> | undefined], context: Parser.Context<P>) => Result<Parser.Node<P>, Parser.Context<P>, Parser.SubParsers<P>>,
|
|
38
48
|
): P;
|
|
39
49
|
export function surround<P extends Parser<string>, S = string>(
|
|
40
|
-
opener: string | RegExp | Parser<S, Parser.Context<P>>,
|
|
50
|
+
opener: string | RegExp | Parser<S, Parser.Context<P>>,
|
|
51
|
+
parser: string | RegExp | P,
|
|
52
|
+
closer: string | RegExp | Parser<S, Parser.Context<P>>,
|
|
41
53
|
optional?: boolean,
|
|
42
54
|
backtracks?: readonly number[],
|
|
43
55
|
f?: (rss: [List<Node<S>>, List<Node<Parser.Node<P>>> | undefined, List<Node<S>>], context: Parser.Context<P>) => Result<Parser.Node<P>, Parser.Context<P>, Parser.SubParsers<P>>,
|
|
44
56
|
g?: (rss: [List<Node<S>>, List<Node<Parser.Node<P>>> | undefined], context: Parser.Context<P>) => Result<Parser.Node<P>, Parser.Context<P>, Parser.SubParsers<P>>,
|
|
45
57
|
): P;
|
|
46
58
|
export function surround<N>(
|
|
47
|
-
opener: string | RegExp | Parser<N>,
|
|
59
|
+
opener: string | RegExp | Parser<N>,
|
|
60
|
+
parser: string | RegExp | Parser<N>,
|
|
61
|
+
closer: string | RegExp | Parser<N>,
|
|
48
62
|
optional: boolean = false,
|
|
49
63
|
backtracks: readonly number[] = [],
|
|
50
64
|
f?: (rss: [List<Node<N>>, List<Node<N>>, List<Node<N>>], context: Context) => Result<N>,
|
|
@@ -53,19 +67,19 @@ export function surround<N>(
|
|
|
53
67
|
switch (typeof opener) {
|
|
54
68
|
case 'string':
|
|
55
69
|
case 'object':
|
|
56
|
-
opener =
|
|
70
|
+
opener = tester(opener, true);
|
|
57
71
|
}
|
|
58
72
|
assert(opener);
|
|
59
73
|
switch (typeof parser) {
|
|
60
74
|
case 'string':
|
|
61
75
|
case 'object':
|
|
62
|
-
parser =
|
|
76
|
+
parser = tester(parser, true);
|
|
63
77
|
}
|
|
64
78
|
assert(parser);
|
|
65
79
|
switch (typeof closer) {
|
|
66
80
|
case 'string':
|
|
67
81
|
case 'object':
|
|
68
|
-
closer =
|
|
82
|
+
closer = tester(closer, true);
|
|
69
83
|
}
|
|
70
84
|
assert(closer);
|
|
71
85
|
const [blen, rbs, wbs] = reduce(backtracks);
|
|
@@ -76,7 +90,7 @@ export function surround<N>(
|
|
|
76
90
|
const { linebreak } = context;
|
|
77
91
|
context.linebreak = 0;
|
|
78
92
|
const nodesO = opener(input);
|
|
79
|
-
if (
|
|
93
|
+
if (nodesO === undefined) {
|
|
80
94
|
return void revert(context, linebreak);
|
|
81
95
|
}
|
|
82
96
|
if (rbs && isBacktrack(context, rbs, position, blen)) {
|
|
@@ -84,14 +98,14 @@ export function surround<N>(
|
|
|
84
98
|
}
|
|
85
99
|
const nodesM = context.position < source.length ? parser(input) : undefined;
|
|
86
100
|
context.range = context.position - position;
|
|
87
|
-
if (
|
|
101
|
+
if (nodesM === undefined && !optional) {
|
|
88
102
|
wbs && setBacktrack(context, wbs, position);
|
|
89
103
|
const result = g?.([nodesO, nodesM], context);
|
|
90
104
|
return result || void revert(context, linebreak);
|
|
91
105
|
}
|
|
92
|
-
const nodesC =
|
|
106
|
+
const nodesC = optional || nodesM ? closer(input) : undefined;
|
|
93
107
|
context.range = context.position - position;
|
|
94
|
-
if (
|
|
108
|
+
if (nodesC === undefined) {
|
|
95
109
|
wbs && setBacktrack(context, wbs, position);
|
|
96
110
|
const result = g?.([nodesO, nodesM], context);
|
|
97
111
|
return result || void revert(context, linebreak);
|
|
@@ -102,7 +116,9 @@ export function surround<N>(
|
|
|
102
116
|
context.range = context.position - position;
|
|
103
117
|
const result = f
|
|
104
118
|
? f([nodesO, nodesM!, nodesC], context)
|
|
105
|
-
:
|
|
119
|
+
: nodesM
|
|
120
|
+
? nodesO.import(nodesM).import(nodesC)
|
|
121
|
+
: nodesO.import(nodesC);
|
|
106
122
|
if (result) {
|
|
107
123
|
context.linebreak ||= linebreak;
|
|
108
124
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { Input, Context } from './parser';
|
|
2
|
-
import {
|
|
1
|
+
import { Parser, Input, List, Node, Context } from './parser';
|
|
2
|
+
import { consume } from './parser/context';
|
|
3
3
|
|
|
4
4
|
interface Delimiter {
|
|
5
5
|
readonly memory: Delimiter[];
|
|
@@ -33,11 +33,11 @@ export class Delimiters {
|
|
|
33
33
|
return () => undefined;
|
|
34
34
|
case 'string':
|
|
35
35
|
case 'object':
|
|
36
|
-
const
|
|
37
|
-
const verify = after ?
|
|
36
|
+
const test = tester(pattern, false);
|
|
37
|
+
const verify = after ? tester(after, false) : undefined;
|
|
38
38
|
return verify
|
|
39
|
-
? input =>
|
|
40
|
-
: input =>
|
|
39
|
+
? input => test(input) !== undefined && verify(input) !== undefined || undefined
|
|
40
|
+
: input => test(input) !== undefined || undefined;
|
|
41
41
|
}
|
|
42
42
|
}
|
|
43
43
|
private readonly tree: Record<number, Delimiter[]> = {};
|
|
@@ -150,3 +150,79 @@ export class Delimiters {
|
|
|
150
150
|
return false;
|
|
151
151
|
}
|
|
152
152
|
}
|
|
153
|
+
|
|
154
|
+
export function matcher(pattern: string | RegExp, advance: boolean, after?: Parser<string>): Parser<string> {
|
|
155
|
+
assert(pattern instanceof RegExp ? !pattern.flags.match(/[gm]/) && pattern.sticky && !pattern.source.startsWith('^') : true);
|
|
156
|
+
const count = typeof pattern === 'object'
|
|
157
|
+
? /[^^\\*+][*+]/.test(pattern.source)
|
|
158
|
+
: false;
|
|
159
|
+
switch (typeof pattern) {
|
|
160
|
+
case 'string':
|
|
161
|
+
if (pattern === '') return () => new List([new Node(pattern)]);
|
|
162
|
+
return input => {
|
|
163
|
+
const { context } = input;
|
|
164
|
+
const { source, position } = context;
|
|
165
|
+
if (!source.startsWith(pattern, position)) return;
|
|
166
|
+
if (advance) {
|
|
167
|
+
context.position += pattern.length;
|
|
168
|
+
}
|
|
169
|
+
const next = after?.(input);
|
|
170
|
+
return after
|
|
171
|
+
? next && new List([new Node(pattern)]).import(next)
|
|
172
|
+
: new List([new Node(pattern)]);
|
|
173
|
+
};
|
|
174
|
+
case 'object':
|
|
175
|
+
assert(pattern.sticky);
|
|
176
|
+
return input => {
|
|
177
|
+
const { context } = input;
|
|
178
|
+
const { source, position } = context;
|
|
179
|
+
pattern.lastIndex = position;
|
|
180
|
+
if (!pattern.test(source)) return;
|
|
181
|
+
const src = source.slice(position, pattern.lastIndex);
|
|
182
|
+
count && consume(src.length, context);
|
|
183
|
+
if (advance) {
|
|
184
|
+
context.position += src.length;
|
|
185
|
+
}
|
|
186
|
+
const next = after?.(input);
|
|
187
|
+
return after
|
|
188
|
+
? next && new List([new Node(src)]).import(next)
|
|
189
|
+
: new List([new Node(src)]);
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
export function tester(pattern: string | RegExp, advance: boolean, after?: Parser<unknown>): Parser<never> {
|
|
195
|
+
assert(pattern instanceof RegExp ? !pattern.flags.match(/[gm]/) && pattern.sticky && !pattern.source.startsWith('^') : true);
|
|
196
|
+
const count = typeof pattern === 'object'
|
|
197
|
+
? /[^^\\*+][*+]/.test(pattern.source)
|
|
198
|
+
: false;
|
|
199
|
+
switch (typeof pattern) {
|
|
200
|
+
case 'string':
|
|
201
|
+
if (pattern === '') return () => new List();
|
|
202
|
+
return input => {
|
|
203
|
+
const { context } = input;
|
|
204
|
+
const { source, position } = context;
|
|
205
|
+
if (!source.startsWith(pattern, position)) return;
|
|
206
|
+
if (advance) {
|
|
207
|
+
context.position += pattern.length;
|
|
208
|
+
}
|
|
209
|
+
if (after && after(input) === undefined) return;
|
|
210
|
+
return new List();
|
|
211
|
+
};
|
|
212
|
+
case 'object':
|
|
213
|
+
assert(pattern.sticky);
|
|
214
|
+
return input => {
|
|
215
|
+
const { context } = input;
|
|
216
|
+
const { source, position } = context;
|
|
217
|
+
pattern.lastIndex = position;
|
|
218
|
+
if (!pattern.test(source)) return;
|
|
219
|
+
const len = pattern.lastIndex - position;
|
|
220
|
+
count && consume(len, context);
|
|
221
|
+
if (advance) {
|
|
222
|
+
context.position += len;
|
|
223
|
+
}
|
|
224
|
+
if (after && after(input) === undefined) return;
|
|
225
|
+
return new List();
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
}
|
|
@@ -21,9 +21,9 @@ describe('Unit: combinator/data/parser/context', () => {
|
|
|
21
21
|
const ctx: Ctx = new Context();
|
|
22
22
|
assert.deepStrictEqual([...unwrap(reset(base, parser)(input('123', ctx))!)], [3, 2, 1]);
|
|
23
23
|
assert(base.resources?.clock === 3);
|
|
24
|
-
assert(ctx.resources?.clock ===
|
|
24
|
+
assert(ctx.resources?.clock === 0);
|
|
25
25
|
assert.throws(() => reset(base, parser)(input('1234', ctx)));
|
|
26
|
-
assert(ctx.resources?.clock ===
|
|
26
|
+
assert(ctx.resources?.clock === 0);
|
|
27
27
|
});
|
|
28
28
|
|
|
29
29
|
it('node', () => {
|
|
@@ -1,16 +1,25 @@
|
|
|
1
|
-
import { Parser, Result,
|
|
1
|
+
import { Parser, Result, Context, Options } from '../../data/parser';
|
|
2
2
|
import { min } from 'spica/alias';
|
|
3
3
|
import { clone } from 'spica/assign';
|
|
4
4
|
|
|
5
5
|
export function reset<P extends Parser>(base: Options, parser: P): P;
|
|
6
6
|
export function reset<N>(base: Context, parser: Parser<N>): Parser<N> {
|
|
7
|
+
return input => {
|
|
8
|
+
const { context } = input;
|
|
9
|
+
// @ts-expect-error
|
|
10
|
+
context.resources ??= {
|
|
11
|
+
clock: base.resources?.clock,
|
|
12
|
+
recursions: base.resources?.recursions.slice(),
|
|
13
|
+
};
|
|
14
|
+
context.backtracks = {};
|
|
15
|
+
return parser(input);
|
|
16
|
+
};
|
|
7
17
|
assert(Object.getPrototypeOf(base) === Object.prototype);
|
|
8
18
|
assert(Object.freeze(base));
|
|
9
19
|
const changes = Object.entries(base);
|
|
10
20
|
const values = Array(changes.length);
|
|
11
21
|
return ({ context }) =>
|
|
12
|
-
|
|
13
|
-
apply(parser, { ...context }, changes, values, true);
|
|
22
|
+
apply(parser, context, changes, values, true);
|
|
14
23
|
}
|
|
15
24
|
|
|
16
25
|
export function context<P extends Parser>(base: Options, parser: P): P;
|
|
@@ -158,36 +167,3 @@ export function constraint<N>(state: number, positive: boolean | Parser<N>, pars
|
|
|
158
167
|
: undefined;
|
|
159
168
|
};
|
|
160
169
|
}
|
|
161
|
-
|
|
162
|
-
export function matcher(pattern: string | RegExp, advance: boolean, verify?: (source: string, position: number, range: number) => boolean): Parser<string> {
|
|
163
|
-
assert(pattern instanceof RegExp ? !pattern.flags.match(/[gm]/) && pattern.sticky && !pattern.source.startsWith('^') : true);
|
|
164
|
-
const count = typeof pattern === 'object'
|
|
165
|
-
? /[^^\\*+][*+]/.test(pattern.source)
|
|
166
|
-
: false;
|
|
167
|
-
switch (typeof pattern) {
|
|
168
|
-
case 'string':
|
|
169
|
-
return ({ context }) => {
|
|
170
|
-
const { source, position } = context;
|
|
171
|
-
if (!source.startsWith(pattern, position)) return;
|
|
172
|
-
if (verify?.(source, position, pattern.length) === false) return;
|
|
173
|
-
if (advance) {
|
|
174
|
-
context.position += pattern.length;
|
|
175
|
-
}
|
|
176
|
-
return new List([new Node(pattern)]);
|
|
177
|
-
};
|
|
178
|
-
case 'object':
|
|
179
|
-
assert(pattern.sticky);
|
|
180
|
-
return ({ context }) => {
|
|
181
|
-
const { source, position } = context;
|
|
182
|
-
pattern.lastIndex = position;
|
|
183
|
-
if (!pattern.test(source)) return;
|
|
184
|
-
const src = source.slice(position, pattern.lastIndex);
|
|
185
|
-
count && consume(src.length, context);
|
|
186
|
-
if (verify?.(source, position, src.length) === false) return;
|
|
187
|
-
if (advance) {
|
|
188
|
-
context.position += src.length;
|
|
189
|
-
}
|
|
190
|
-
return new List([new Node(src)]);
|
|
191
|
-
};
|
|
192
|
-
}
|
|
193
|
-
}
|
package/src/parser/api/bind.ts
CHANGED
|
@@ -8,7 +8,7 @@ import { headers } from './header';
|
|
|
8
8
|
import { figure } from '../processor/figure';
|
|
9
9
|
import { note } from '../processor/note';
|
|
10
10
|
import { ReadonlyURL } from 'spica/url';
|
|
11
|
-
import {
|
|
11
|
+
import { splice } from 'spica/array';
|
|
12
12
|
|
|
13
13
|
interface Settings extends ParserSettings {
|
|
14
14
|
}
|
|
@@ -29,8 +29,8 @@ export function bind(target: DocumentFragment | HTMLElement | ShadowRoot, settin
|
|
|
29
29
|
if (context.host?.origin === 'null') throw new Error(`Invalid host: ${context.host.href}`);
|
|
30
30
|
type Block = readonly [segment: string, blocks: readonly HTMLElement[], url: string];
|
|
31
31
|
const blocks: Block[] = [];
|
|
32
|
-
const adds: [HTMLElement, Node | null][] = [];
|
|
33
|
-
const dels: [HTMLElement][] = [];
|
|
32
|
+
const adds: (readonly [HTMLElement, Node | null])[] = [];
|
|
33
|
+
const dels: (readonly [HTMLElement])[] = [];
|
|
34
34
|
const bottom = target.firstChild;
|
|
35
35
|
let revision: symbol | undefined;
|
|
36
36
|
return {
|
|
@@ -75,7 +75,7 @@ export function bind(target: DocumentFragment | HTMLElement | ShadowRoot, settin
|
|
|
75
75
|
for (; index < sourceSegments.length - last; ++index) {
|
|
76
76
|
assert(rev === revision);
|
|
77
77
|
const seg = sourceSegments[index];
|
|
78
|
-
const es = block(input(seg, context))
|
|
78
|
+
const es = block(input(seg, new Context(context)))
|
|
79
79
|
?.foldl<HTMLElement[]>((acc, { value }) => void acc.push(value) || acc, []) ?? [];
|
|
80
80
|
// @ts-expect-error
|
|
81
81
|
context.header = false;
|
|
@@ -83,7 +83,7 @@ export function bind(target: DocumentFragment | HTMLElement | ShadowRoot, settin
|
|
|
83
83
|
if (es.length === 0) continue;
|
|
84
84
|
// All deletion processes always run after all addition processes have done.
|
|
85
85
|
// Therefore any `base` node will never be unavailable by deletions until all the dependent `el` nodes are added.
|
|
86
|
-
push(
|
|
86
|
+
adds.push(...es.map(el => [el, base] as const));
|
|
87
87
|
adds.reverse();
|
|
88
88
|
for (; adds.length > 0;) {
|
|
89
89
|
assert(rev === revision);
|
|
@@ -98,7 +98,7 @@ export function bind(target: DocumentFragment | HTMLElement | ShadowRoot, settin
|
|
|
98
98
|
assert(rev === revision);
|
|
99
99
|
const es = refuse[i][1];
|
|
100
100
|
if (es.length === 0) continue;
|
|
101
|
-
push(
|
|
101
|
+
dels.push(...es.map(el => [el] as const));
|
|
102
102
|
}
|
|
103
103
|
assert(blocks.length === sourceSegments.length);
|
|
104
104
|
adds.reverse();
|
package/src/parser/api/parse.ts
CHANGED
|
@@ -34,7 +34,7 @@ export function parse(source: string, options: Options = {}, context?: Context):
|
|
|
34
34
|
context.header = true;
|
|
35
35
|
for (const seg of segment(source)) {
|
|
36
36
|
node.append(
|
|
37
|
-
...block(input(seg, context))
|
|
37
|
+
...block(input(seg, new Context(context)))
|
|
38
38
|
?.foldl<HTMLElement[]>((acc, { value }) => void acc.push(value) || acc, []) ?? []);
|
|
39
39
|
// @ts-expect-error
|
|
40
40
|
context.header = false;
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import { AnnotationParser } from '../inline';
|
|
2
2
|
import { State, Backtrack } from '../context';
|
|
3
3
|
import { List, Node } from '../../combinator/data/parser';
|
|
4
|
-
import { union, some, precedence, state, constraint, surround, setBacktrack, lazy } from '../../combinator';
|
|
4
|
+
import { union, some, precedence, state, constraint, surround, close, setBacktrack, lazy } from '../../combinator';
|
|
5
5
|
import { inline } from '../inline';
|
|
6
6
|
import { beforeNonblank, trimBlankNodeEnd } from '../visibility';
|
|
7
7
|
import { unwrap } from '../util';
|
|
8
8
|
import { html, defrag } from 'typed-dom/dom';
|
|
9
9
|
|
|
10
10
|
export const annotation: AnnotationParser = lazy(() => constraint(State.annotation, surround(
|
|
11
|
-
'((',
|
|
11
|
+
close('((', beforeNonblank),
|
|
12
12
|
precedence(1, state(State.annotation,
|
|
13
|
-
|
|
13
|
+
some(union([inline]), ')', [[')', 1]]))),
|
|
14
14
|
'))',
|
|
15
15
|
false,
|
|
16
16
|
[2, 1 | Backtrack.common, 3 | Backtrack.doublebracket],
|
|
@@ -8,7 +8,7 @@ import { unwrap, repeat } from '../util';
|
|
|
8
8
|
import { html, defrag } from 'typed-dom/dom';
|
|
9
9
|
|
|
10
10
|
export const deletion: DeletionParser = lazy(() =>
|
|
11
|
-
precedence(0, recursion(Recursion.inline, repeat('~~', surround(
|
|
11
|
+
precedence(0, recursion(Recursion.inline, repeat('~~', '', surround(
|
|
12
12
|
'',
|
|
13
13
|
some(union([
|
|
14
14
|
some(inline, blankWith('\n', '~~')),
|
|
@@ -5,17 +5,17 @@ import { union, some, recursion, precedence, surround, lazy } from '../../combin
|
|
|
5
5
|
import { inline } from '../inline';
|
|
6
6
|
import { strong } from './strong';
|
|
7
7
|
import { str } from '../source';
|
|
8
|
-
import {
|
|
8
|
+
import { beforeNonblankWith, afterNonblank } from '../visibility';
|
|
9
9
|
import { unwrap } from '../util';
|
|
10
10
|
import { html, defrag } from 'typed-dom/dom';
|
|
11
11
|
|
|
12
12
|
export const emphasis: EmphasisParser = lazy(() => surround(
|
|
13
|
-
str('*', (
|
|
13
|
+
str('*', beforeNonblankWith(/(?!\*)/)),
|
|
14
14
|
precedence(0, recursion(Recursion.inline,
|
|
15
|
-
|
|
15
|
+
some(union([
|
|
16
16
|
some(inline, '*', afterNonblank),
|
|
17
17
|
strong,
|
|
18
|
-
]))))
|
|
18
|
+
])))),
|
|
19
19
|
str('*'),
|
|
20
20
|
false, [],
|
|
21
21
|
([, bs]) => new List([new Node(html('em', defrag(unwrap(bs))))]),
|
|
@@ -114,6 +114,7 @@ describe('Unit: parser/inline/emstrong', () => {
|
|
|
114
114
|
assert.deepStrictEqual(inspect(parser, input('******a*b ***', new Context())), [['*****', '<em>a</em>', 'b ', '***'], '']);
|
|
115
115
|
assert.deepStrictEqual(inspect(parser, input('******a*b ****', new Context())), [['*****', '<em>a</em>', 'b ', '****'], '']);
|
|
116
116
|
assert.deepStrictEqual(inspect(parser, input('******a*b *****', new Context())), [['*****', '<em>a</em>', 'b ', '*****'], '']);
|
|
117
|
+
assert.deepStrictEqual(inspect(parser, input('******a*** b***', new Context())), [['<em><strong><em><strong>a</strong></em> b</strong></em>'], '']);
|
|
117
118
|
});
|
|
118
119
|
|
|
119
120
|
});
|
|
@@ -23,9 +23,9 @@ const subemphasis: Parser.IntermediateParser<EmphasisParser> = lazy(() => some(u
|
|
|
23
23
|
// 可能な限り早く閉じるよう解析しなければならない。
|
|
24
24
|
// このため終端記号の後ろを見て終端を中止し同じ構文を再帰的に適用してはならない。
|
|
25
25
|
export const emstrong: EmStrongParser = lazy(() =>
|
|
26
|
-
precedence(0, recursion(Recursion.inline, repeat('***', surround(
|
|
26
|
+
precedence(0, recursion(Recursion.inline, repeat('***', beforeNonblank, surround(
|
|
27
27
|
'',
|
|
28
|
-
|
|
28
|
+
some(union([some(inline, '*', afterNonblank)])),
|
|
29
29
|
strs('*', 3),
|
|
30
30
|
false, [],
|
|
31
31
|
([, bs, cs], context): Result<Parser.Node<EmStrongParser>, Parser.Context<EmStrongParser>> => {
|
|
@@ -33,7 +33,7 @@ export const emstrong: EmStrongParser = lazy(() =>
|
|
|
33
33
|
const { buffer } = context;
|
|
34
34
|
switch (cs.head!.value) {
|
|
35
35
|
case '***':
|
|
36
|
-
return bs;
|
|
36
|
+
return buffer.import(bs);
|
|
37
37
|
case '**':
|
|
38
38
|
return bind<EmphasisParser>(
|
|
39
39
|
subemphasis,
|
|
@@ -13,13 +13,12 @@ import { html, define, defrag } from 'typed-dom/dom';
|
|
|
13
13
|
import IndexParser = ExtensionParser.IndexParser;
|
|
14
14
|
|
|
15
15
|
export const index: IndexParser = lazy(() => constraint(State.index, fmap(indexee(surround(
|
|
16
|
-
str('[#'),
|
|
16
|
+
str('[#', beforeNonblank),
|
|
17
17
|
precedence(1, state(State.linkers,
|
|
18
|
-
beforeNonblank(
|
|
19
18
|
some(inits([
|
|
20
19
|
inline,
|
|
21
20
|
signature,
|
|
22
|
-
]), ']', [[']', 1]])))
|
|
21
|
+
]), ']', [[']', 1]]))),
|
|
23
22
|
str(']'),
|
|
24
23
|
false,
|
|
25
24
|
[3 | Backtrack.common],
|
|
@@ -14,9 +14,9 @@ import { html } from 'typed-dom/dom';
|
|
|
14
14
|
|
|
15
15
|
export const placeholder: ExtensionParser.PlaceholderParser = lazy(() => surround(
|
|
16
16
|
// ^はabbrで使用済みだが^:などのようにして分離使用可能
|
|
17
|
-
str(/\[[:^|]/y),
|
|
17
|
+
str(/\[[:^|]/y, beforeNonblank),
|
|
18
18
|
precedence(1, recursion(Recursion.inline,
|
|
19
|
-
|
|
19
|
+
some(union([inline]), ']', [[']', 1]]))),
|
|
20
20
|
str(']'),
|
|
21
21
|
false,
|
|
22
22
|
[3 | Backtrack.common],
|
|
@@ -8,7 +8,7 @@ import { unwrap, repeat } from '../util';
|
|
|
8
8
|
import { html, defrag } from 'typed-dom/dom';
|
|
9
9
|
|
|
10
10
|
export const insertion: InsertionParser = lazy(() =>
|
|
11
|
-
precedence(0, recursion(Recursion.inline, repeat('++', surround(
|
|
11
|
+
precedence(0, recursion(Recursion.inline, repeat('++', '', surround(
|
|
12
12
|
'',
|
|
13
13
|
some(union([
|
|
14
14
|
some(inline, blankWith('\n', '++')),
|
|
@@ -57,6 +57,7 @@ describe('Unit: parser/inline/italic', () => {
|
|
|
57
57
|
assert.deepStrictEqual(inspect(parser, input('//////a/////b', new Context())), [['///', '<i>a</i>', '//b'], '']);
|
|
58
58
|
assert.deepStrictEqual(inspect(parser, input('//////a//////', new Context())), [['<i><i>a</i></i>'], '']);
|
|
59
59
|
assert.deepStrictEqual(inspect(parser, input('//////a///b///', new Context())), [['<i><i>a</i>b</i>'], '']);
|
|
60
|
+
assert.deepStrictEqual(inspect(parser, input('//////a/// b///', new Context())), [['<i><i>a</i> b</i>'], '']);
|
|
60
61
|
assert.deepStrictEqual(inspect(parser, input('///a ///b//////', new Context())), [['<i>a <i>b</i></i>'], '']);
|
|
61
62
|
assert.deepStrictEqual(inspect(parser, input('///- ///b//////', new Context())), [['<i>- <i>b</i></i>'], '']);
|
|
62
63
|
assert.deepStrictEqual(inspect(parser, input('///a\\ ///b//////', new Context())), [['<i>a <i>b</i></i>'], '']);
|
|
@@ -11,9 +11,9 @@ import { html, defrag } from 'typed-dom/dom';
|
|
|
11
11
|
// 斜体は単語に使うとかえって見づらく読み飛ばしやすくなるため使わないべきであり
|
|
12
12
|
// ある程度の長さのある文に使うのが望ましい。
|
|
13
13
|
export const italic: ItalicParser = lazy(() =>
|
|
14
|
-
precedence(0, recursion(Recursion.inline, repeat('///', surround(
|
|
14
|
+
precedence(0, recursion(Recursion.inline, repeat('///', beforeNonblank, surround(
|
|
15
15
|
'',
|
|
16
|
-
|
|
16
|
+
some(union([inline]), '///', afterNonblank),
|
|
17
17
|
'///',
|
|
18
18
|
false, [],
|
|
19
19
|
([, bs], { buffer }) => buffer.import(bs),
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { LinkParser } from '../inline';
|
|
2
2
|
import { Context, State, Backtrack, Command } from '../context';
|
|
3
3
|
import { List, Node } from '../../combinator/data/parser';
|
|
4
|
-
import { union, inits, sequence, subsequence, some, consume, precedence, state, constraint, surround, open, setBacktrack, dup, lazy, fmap, bind } from '../../combinator';
|
|
4
|
+
import { union, inits, sequence, subsequence, some, consume, precedence, state, constraint, surround, open, close, setBacktrack, dup, lazy, fmap, bind } from '../../combinator';
|
|
5
5
|
import { inline, media, shortmedia } from '../inline';
|
|
6
6
|
import { attributes } from './html';
|
|
7
7
|
import { str } from '../source';
|
|
@@ -18,9 +18,9 @@ Object.setPrototypeOf(optspec, null);
|
|
|
18
18
|
export const textlink: LinkParser.TextLinkParser = lazy(() => bind(
|
|
19
19
|
subsequence([
|
|
20
20
|
constraint(State.link, state(State.linkers, dup(surround(
|
|
21
|
-
'[',
|
|
21
|
+
close('[', beforeNonblank),
|
|
22
22
|
precedence(1,
|
|
23
|
-
|
|
23
|
+
some(union([inline]), ']', [[']', 1]])),
|
|
24
24
|
']',
|
|
25
25
|
true,
|
|
26
26
|
[3 | Backtrack.common | Backtrack.link, 2 | Backtrack.ruby],
|
|
@@ -44,6 +44,7 @@ describe('Unit: parser/inline/mark', () => {
|
|
|
44
44
|
assert.deepStrictEqual(inspect(parser, input('==a	==b====', new Context())), [['<mark id="mark::a_b=33Mw2l">a\t<mark>b</mark></mark>', '<a href="#mark::a_b=33Mw2l"></a>'], '']);
|
|
45
45
|
assert.deepStrictEqual(inspect(parser, input('==a<wbr>==b====', new Context())), [['<mark id="mark::ab">a<wbr><mark>b</mark></mark>', '<a href="#mark::ab"></a>'], '']);
|
|
46
46
|
assert.deepStrictEqual(inspect(parser, input('==*==a==*==', new Context())), [['<mark id="mark::a"><em><mark>a</mark></em></mark>', '<a href="#mark::a"></a>'], '']);
|
|
47
|
+
assert.deepStrictEqual(inspect(parser, input('====a== b==', new Context())), [['<mark id="mark::a_b"><mark>a</mark> b</mark>', '<a href="#mark::a_b"></a>'], '']);
|
|
47
48
|
});
|
|
48
49
|
|
|
49
50
|
});
|
|
@@ -9,16 +9,16 @@ import { unwrap, repeat } from '../util';
|
|
|
9
9
|
import { html, define, defrag } from 'typed-dom/dom';
|
|
10
10
|
|
|
11
11
|
export const mark: MarkParser = lazy(() =>
|
|
12
|
-
precedence(0, recursion(Recursion.inline, repeat('==', surround(
|
|
12
|
+
precedence(0, recursion(Recursion.inline, repeat('==', beforeNonblank, surround(
|
|
13
13
|
'',
|
|
14
|
-
|
|
14
|
+
state(State.mark, some(union([inline]), '==', afterNonblank)),
|
|
15
15
|
'==',
|
|
16
16
|
false, [],
|
|
17
17
|
([, bs], { buffer }) => buffer.import(bs),
|
|
18
18
|
([, bs], { buffer }) => bs && buffer.import(bs).push(new Node(Command.Cancel)) && buffer),
|
|
19
|
-
(nodes, { id, state }) => {
|
|
19
|
+
(nodes, { id, state }, nest) => {
|
|
20
20
|
const el = html('mark', defrag(unwrap(nodes)));
|
|
21
|
-
if (state & State.linkers) return new List([new Node(el)]);
|
|
21
|
+
if (state & State.linkers || nest) return new List([new Node(el)]);
|
|
22
22
|
define(el, { id: identity('mark', id, signature(el)) });
|
|
23
23
|
return el.id
|
|
24
24
|
? new List([new Node(el), new Node(html('a', { href: `#${el.id}` }))])
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ReferenceParser } from '../inline';
|
|
2
2
|
import { State, Backtrack, Command } from '../context';
|
|
3
3
|
import { List, Node } from '../../combinator/data/parser';
|
|
4
|
-
import { union, subsequence, some, precedence, state, constraint, surround, isBacktrack, setBacktrack, lazy } from '../../combinator';
|
|
4
|
+
import { union, subsequence, some, precedence, state, constraint, surround, open, isBacktrack, setBacktrack, lazy } from '../../combinator';
|
|
5
5
|
import { inline } from '../inline';
|
|
6
6
|
import { textlink } from './link';
|
|
7
7
|
import { str } from '../source';
|
|
@@ -10,11 +10,11 @@ import { unwrap, invalid } from '../util';
|
|
|
10
10
|
import { html, defrag } from 'typed-dom/dom';
|
|
11
11
|
|
|
12
12
|
export const reference: ReferenceParser = lazy(() => constraint(State.reference, surround(
|
|
13
|
-
|
|
13
|
+
'[[',
|
|
14
14
|
precedence(1, state(State.annotation | State.reference,
|
|
15
15
|
subsequence([
|
|
16
16
|
abbr,
|
|
17
|
-
beforeNonblank
|
|
17
|
+
open(beforeNonblank, some(inline, ']', [[']', 1]])),
|
|
18
18
|
]))),
|
|
19
19
|
']]',
|
|
20
20
|
false,
|
|
@@ -5,17 +5,17 @@ import { union, some, recursion, precedence, surround, lazy } from '../../combin
|
|
|
5
5
|
import { inline } from '../inline';
|
|
6
6
|
import { emphasis } from './emphasis';
|
|
7
7
|
import { str } from '../source';
|
|
8
|
-
import {
|
|
8
|
+
import { beforeNonblankWith, afterNonblank } from '../visibility';
|
|
9
9
|
import { unwrap } from '../util';
|
|
10
10
|
import { html, defrag } from 'typed-dom/dom';
|
|
11
11
|
|
|
12
12
|
export const strong: StrongParser = lazy(() => surround(
|
|
13
|
-
str('**', (
|
|
13
|
+
str('**', beforeNonblankWith(/(?!\*)/)),
|
|
14
14
|
precedence(0, recursion(Recursion.inline,
|
|
15
|
-
|
|
15
|
+
some(union([
|
|
16
16
|
some(inline, '*', afterNonblank),
|
|
17
17
|
emphasis,
|
|
18
|
-
]))))
|
|
18
|
+
])))),
|
|
19
19
|
str('**'),
|
|
20
20
|
false, [],
|
|
21
21
|
([, bs]) => new List([new Node(html('strong', defrag(unwrap(bs))))]),
|
package/src/parser/source/str.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { StrParser } from '../source';
|
|
2
2
|
import { Parser, List, Node } from '../../combinator/data/parser';
|
|
3
|
-
import { matcher } from '../../combinator';
|
|
3
|
+
import { matcher, tester } from '../../combinator/data/delimiter';
|
|
4
4
|
|
|
5
|
-
export function str(pattern: string | RegExp,
|
|
6
|
-
export function str(pattern: string | RegExp,
|
|
7
|
-
return matcher(pattern, true,
|
|
5
|
+
export function str(pattern: string | RegExp, after?: string | RegExp): StrParser;
|
|
6
|
+
export function str(pattern: string | RegExp, after?: string | RegExp): Parser<string> {
|
|
7
|
+
return matcher(pattern, true, after ? tester(after, false) : undefined);
|
|
8
8
|
}
|
|
9
9
|
|
|
10
10
|
export function strs(pattern: string, limit?: number): StrParser;
|