securemark 0.293.4 → 0.294.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +8 -0
- package/dist/index.js +868 -564
- package/markdown.d.ts +13 -13
- package/package.json +3 -3
- package/src/combinator/control/constraint/block.test.ts +6 -6
- package/src/combinator/control/constraint/contract.ts +3 -3
- package/src/combinator/control/constraint/line.test.ts +7 -7
- package/src/combinator/control/constraint/line.ts +1 -1
- package/src/combinator/control/manipulation/clear.ts +2 -3
- package/src/combinator/control/manipulation/convert.ts +2 -2
- package/src/combinator/control/manipulation/duplicate.ts +4 -5
- package/src/combinator/control/manipulation/fence.ts +2 -2
- package/src/combinator/control/manipulation/indent.test.ts +2 -2
- package/src/combinator/control/manipulation/indent.ts +4 -4
- package/src/combinator/control/manipulation/reverse.ts +2 -2
- package/src/combinator/control/manipulation/scope.ts +3 -4
- package/src/combinator/control/manipulation/surround.ts +14 -15
- package/src/combinator/control/monad/bind.ts +6 -6
- package/src/combinator/control/monad/fmap.ts +7 -7
- package/src/combinator/data/data.ts +135 -0
- package/src/combinator/data/parser/context.test.ts +16 -15
- package/src/combinator/data/parser/context.ts +5 -4
- package/src/combinator/data/parser/inits.ts +6 -7
- package/src/combinator/data/parser/sequence.test.ts +3 -3
- package/src/combinator/data/parser/sequence.ts +6 -7
- package/src/combinator/data/parser/some.test.ts +3 -3
- package/src/combinator/data/parser/some.ts +4 -4
- package/src/combinator/data/parser/subsequence.test.ts +4 -4
- package/src/combinator/data/parser/subsequence.ts +3 -3
- package/src/combinator/data/parser/tails.ts +3 -3
- package/src/combinator/data/parser/union.test.ts +3 -3
- package/src/combinator/data/parser.ts +16 -7
- package/src/debug.test.ts +6 -5
- package/src/parser/api/bind.ts +6 -8
- package/src/parser/api/header.ts +1 -1
- package/src/parser/api/normalize.ts +2 -4
- package/src/parser/api/parse.ts +3 -1
- package/src/parser/block/blockquote.ts +6 -4
- package/src/parser/block/codeblock.ts +8 -7
- package/src/parser/block/dlist.ts +9 -8
- package/src/parser/block/extension/aside.ts +27 -21
- package/src/parser/block/extension/example.ts +29 -26
- package/src/parser/block/extension/fig.ts +1 -1
- package/src/parser/block/extension/figbase.ts +6 -5
- package/src/parser/block/extension/figure.ts +23 -19
- package/src/parser/block/extension/message.ts +35 -24
- package/src/parser/block/extension/placeholder.ts +17 -13
- package/src/parser/block/extension/table.ts +47 -40
- package/src/parser/block/heading.test.ts +3 -12
- package/src/parser/block/heading.ts +12 -8
- package/src/parser/block/ilist.ts +13 -12
- package/src/parser/block/mathblock.ts +21 -17
- package/src/parser/block/mediablock.ts +7 -5
- package/src/parser/block/olist.ts +15 -5
- package/src/parser/block/pagebreak.ts +2 -1
- package/src/parser/block/paragraph.ts +3 -1
- package/src/parser/block/reply/cite.ts +20 -15
- package/src/parser/block/reply/quote.ts +9 -7
- package/src/parser/block/reply.ts +7 -3
- package/src/parser/block/sidefence.ts +8 -7
- package/src/parser/block/table.ts +23 -22
- package/src/parser/block/ulist.ts +16 -12
- package/src/parser/block.ts +7 -6
- package/src/parser/header.test.ts +3 -1
- package/src/parser/header.ts +20 -20
- package/src/parser/inline/annotation.ts +3 -1
- package/src/parser/inline/autolink/account.ts +3 -2
- package/src/parser/inline/autolink/anchor.ts +3 -2
- package/src/parser/inline/autolink/channel.ts +5 -4
- package/src/parser/inline/autolink/email.ts +4 -3
- package/src/parser/inline/autolink/hashnum.ts +3 -2
- package/src/parser/inline/autolink/hashtag.ts +4 -3
- package/src/parser/inline/autolink/url.ts +7 -6
- package/src/parser/inline/bracket.ts +16 -15
- package/src/parser/inline/code.ts +5 -4
- package/src/parser/inline/deletion.ts +5 -5
- package/src/parser/inline/emphasis.ts +4 -3
- package/src/parser/inline/emstrong.test.ts +18 -18
- package/src/parser/inline/emstrong.ts +39 -30
- package/src/parser/inline/extension/index.ts +22 -19
- package/src/parser/inline/extension/indexee.ts +2 -2
- package/src/parser/inline/extension/indexer.ts +2 -1
- package/src/parser/inline/extension/label.ts +7 -3
- package/src/parser/inline/extension/placeholder.ts +6 -6
- package/src/parser/inline/html.ts +27 -28
- package/src/parser/inline/htmlentity.ts +9 -8
- package/src/parser/inline/insertion.ts +5 -5
- package/src/parser/inline/italic.ts +5 -5
- package/src/parser/inline/link.ts +36 -38
- package/src/parser/inline/mark.ts +7 -7
- package/src/parser/inline/math.ts +5 -4
- package/src/parser/inline/media.ts +33 -32
- package/src/parser/inline/reference.ts +19 -20
- package/src/parser/inline/remark.ts +11 -11
- package/src/parser/inline/ruby.ts +50 -53
- package/src/parser/inline/strong.ts +4 -3
- package/src/parser/inline/template.ts +16 -15
- package/src/parser/inline.test.ts +3 -3
- package/src/parser/segment.ts +3 -1
- package/src/parser/source/escapable.ts +9 -8
- package/src/parser/source/line.ts +4 -3
- package/src/parser/source/str.ts +2 -2
- package/src/parser/source/text.ts +19 -26
- package/src/parser/source/unescapable.ts +6 -5
- package/src/parser/util.ts +16 -30
- package/src/parser/visibility.ts +19 -20
package/markdown.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Parser, Ctx, CtxOptions } from './src/combinator/data/parser';
|
|
1
|
+
import { Parser, List, Data, Ctx, CtxOptions } from './src/combinator/data/parser';
|
|
2
2
|
import { Dict } from 'spica/dict';
|
|
3
3
|
|
|
4
4
|
declare abstract class Markdown<T> {
|
|
@@ -13,7 +13,7 @@ export interface MarkdownParser extends
|
|
|
13
13
|
}
|
|
14
14
|
export namespace MarkdownParser {
|
|
15
15
|
export interface Context extends Ctx, Options {
|
|
16
|
-
buffer?: (string | HTMLElement)
|
|
16
|
+
buffer?: List<Data<(string | HTMLElement)>>;
|
|
17
17
|
sequential?: boolean;
|
|
18
18
|
}
|
|
19
19
|
export interface Options extends CtxOptions {
|
|
@@ -434,7 +434,7 @@ export namespace MarkdownParser {
|
|
|
434
434
|
}
|
|
435
435
|
export interface RowParser extends
|
|
436
436
|
Block<'extension/table/row'>,
|
|
437
|
-
Parser<[
|
|
437
|
+
Parser<List<Data<[string[], string[]?] | HTMLTableCellElement>>, Context, [
|
|
438
438
|
Parser<[string[], string[]?], Context, [
|
|
439
439
|
AlignParser,
|
|
440
440
|
]>,
|
|
@@ -448,7 +448,7 @@ export namespace MarkdownParser {
|
|
|
448
448
|
}
|
|
449
449
|
export interface AlignParser extends
|
|
450
450
|
Block<'extension/table/align'>,
|
|
451
|
-
Parser<string[], Context, [
|
|
451
|
+
Parser<[string[], string[]?], Context, [
|
|
452
452
|
SourceParser.StrParser,
|
|
453
453
|
]> {
|
|
454
454
|
}
|
|
@@ -792,7 +792,7 @@ export namespace MarkdownParser {
|
|
|
792
792
|
export interface TextLinkParser extends
|
|
793
793
|
Inline<'link/textlink'>,
|
|
794
794
|
Parser<HTMLAnchorElement | HTMLSpanElement, Context, [
|
|
795
|
-
Parser<
|
|
795
|
+
Parser<List<Data<string | HTMLElement>>, Context, [
|
|
796
796
|
InlineParser,
|
|
797
797
|
]>,
|
|
798
798
|
LinkParser.ParameterParser,
|
|
@@ -801,7 +801,7 @@ export namespace MarkdownParser {
|
|
|
801
801
|
export interface MediaLinkParser extends
|
|
802
802
|
Inline<'link/medialink'>,
|
|
803
803
|
Parser<HTMLAnchorElement | HTMLSpanElement, Context, [
|
|
804
|
-
Parser<HTMLElement
|
|
804
|
+
Parser<List<Data<HTMLElement>>, Context, [
|
|
805
805
|
MediaParser,
|
|
806
806
|
ShortMediaParser,
|
|
807
807
|
]>,
|
|
@@ -817,7 +817,7 @@ export namespace MarkdownParser {
|
|
|
817
817
|
}
|
|
818
818
|
export interface ContentParser extends
|
|
819
819
|
Inline<'link/content'>,
|
|
820
|
-
Parser<
|
|
820
|
+
Parser<List<Data<string | HTMLElement>>, Context, [
|
|
821
821
|
MediaParser,
|
|
822
822
|
ShortMediaParser,
|
|
823
823
|
InlineParser,
|
|
@@ -825,13 +825,13 @@ export namespace MarkdownParser {
|
|
|
825
825
|
}
|
|
826
826
|
export interface TextParser extends
|
|
827
827
|
Inline<'link/text'>,
|
|
828
|
-
Parser<string
|
|
828
|
+
Parser<List<Data<string>>, Context, [
|
|
829
829
|
SourceParser.UnescapableSourceParser,
|
|
830
830
|
]> {
|
|
831
831
|
}
|
|
832
832
|
export interface ParameterParser extends
|
|
833
833
|
Inline<'link/parameter'>,
|
|
834
|
-
Parser<string
|
|
834
|
+
Parser<List<Data<string>>, Context, [
|
|
835
835
|
LinkParser.ParameterParser.UriParser,
|
|
836
836
|
LinkParser.ParameterParser.OptionParser,
|
|
837
837
|
]> {
|
|
@@ -866,7 +866,7 @@ export namespace MarkdownParser {
|
|
|
866
866
|
export namespace MediaParser {
|
|
867
867
|
export interface TextParser extends
|
|
868
868
|
Inline<'media/text'>,
|
|
869
|
-
Parser<string
|
|
869
|
+
Parser<List<Data<string>>, Context, [
|
|
870
870
|
UnsafeHTMLEntityParser,
|
|
871
871
|
TextParser.BracketParser,
|
|
872
872
|
SourceParser.TxtParser,
|
|
@@ -900,7 +900,7 @@ export namespace MarkdownParser {
|
|
|
900
900
|
}
|
|
901
901
|
export interface ParameterParser extends
|
|
902
902
|
Inline<'media/parameter'>,
|
|
903
|
-
Parser<string
|
|
903
|
+
Parser<List<Data<string>>, Context, [
|
|
904
904
|
LinkParser.ParameterParser.UriParser,
|
|
905
905
|
ParameterParser.OptionParser,
|
|
906
906
|
]> {
|
|
@@ -919,8 +919,8 @@ export namespace MarkdownParser {
|
|
|
919
919
|
// [AB](a b)
|
|
920
920
|
Inline<'ruby'>,
|
|
921
921
|
Parser<HTMLElement, Context, [
|
|
922
|
-
Parser<string
|
|
923
|
-
Parser<string
|
|
922
|
+
Parser<List<Data<string>>, Context, []>,
|
|
923
|
+
Parser<List<Data<string>>, Context, []>,
|
|
924
924
|
]> {
|
|
925
925
|
}
|
|
926
926
|
export namespace RubyParser {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "securemark",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.294.0",
|
|
4
4
|
"description": "Secure markdown renderer working on browsers for user input data.",
|
|
5
5
|
"private": false,
|
|
6
6
|
"homepage": "https://github.com/falsandtru/securemark",
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"LICENSE"
|
|
29
29
|
],
|
|
30
30
|
"dependencies": {
|
|
31
|
-
"spica": "0.0.
|
|
31
|
+
"spica": "0.0.807"
|
|
32
32
|
},
|
|
33
33
|
"devDependencies": {
|
|
34
34
|
"@types/dompurify": "3.0.5",
|
|
@@ -55,7 +55,7 @@
|
|
|
55
55
|
"npm-check-updates": "^17.0.2",
|
|
56
56
|
"semver": "^7.6.3",
|
|
57
57
|
"ts-loader": "^9.5.1",
|
|
58
|
-
"typed-dom": "0.0.
|
|
58
|
+
"typed-dom": "0.0.351",
|
|
59
59
|
"typescript": "5.4.5",
|
|
60
60
|
"webpack": "^5.93.0",
|
|
61
61
|
"webpack-cli": "^5.1.4",
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { block } from './block';
|
|
2
|
-
import { input } from '../../data/parser';
|
|
2
|
+
import { List, Data, input } from '../../data/parser';
|
|
3
3
|
import { inspect } from '../../../debug.test';
|
|
4
4
|
|
|
5
5
|
describe('Unit: combinator/block', () => {
|
|
@@ -7,14 +7,14 @@ describe('Unit: combinator/block', () => {
|
|
|
7
7
|
const { context: ctx } = input('', {});
|
|
8
8
|
|
|
9
9
|
it('invalid', () => {
|
|
10
|
-
assert.throws(() => block(_ =>
|
|
10
|
+
assert.throws(() => block(_ => new List<Data<string>>())(input(' \n', ctx)));
|
|
11
11
|
});
|
|
12
12
|
|
|
13
13
|
it('valid', () => {
|
|
14
|
-
assert.deepStrictEqual(inspect(block(({ context }) => { context.position = context.source.length; return
|
|
15
|
-
assert.deepStrictEqual(inspect(block(({ context }) => { context.position = context.source.length; return
|
|
16
|
-
assert.deepStrictEqual(inspect(block(({ context }) => { context.position = context.source.length; return
|
|
17
|
-
assert.deepStrictEqual(inspect(block(({ context }) => { context.position = context.source.length - 1; return
|
|
14
|
+
assert.deepStrictEqual(inspect(block(({ context }) => { context.position = context.source.length; return new List<Data<string>>(); })(input('\n', ctx)), ctx), [[], '']);
|
|
15
|
+
assert.deepStrictEqual(inspect(block(({ context }) => { context.position = context.source.length; return new List<Data<string>>(); })(input(' \n', ctx)), ctx), [[], '']);
|
|
16
|
+
assert.deepStrictEqual(inspect(block(({ context }) => { context.position = context.source.length; return new List<Data<string>>(); })(input('\n\n', ctx)), ctx), [[], '']);
|
|
17
|
+
assert.deepStrictEqual(inspect(block(({ context }) => { context.position = context.source.length - 1; return new List<Data<string>>(); })(input('\n\n', ctx)), ctx), [[], '\n']);
|
|
18
18
|
});
|
|
19
19
|
|
|
20
20
|
});
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Parser, Input, Ctx, Node, Context, eval, failsafe } from '../../data/parser';
|
|
1
|
+
import { Parser, Input, List, Data, Ctx, Node, Context, eval, failsafe } from '../../data/parser';
|
|
2
2
|
import { matcher } from '../../../combinator';
|
|
3
3
|
|
|
4
4
|
//export function contract<P extends Parser<unknown>>(patterns: string | RegExp | (string | RegExp)[], parser: P, cond: (nodes: readonly Data<P>[], rest: string) => boolean): P;
|
|
@@ -28,8 +28,8 @@ function guard<N>(f: (input: Input<Ctx>) => boolean, parser: Parser<N>): Parser<
|
|
|
28
28
|
: undefined;
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
-
export function verify<P extends Parser<unknown>>(parser: P, cond: (nodes:
|
|
32
|
-
export function verify<N>(parser: Parser<N>, cond: (nodes:
|
|
31
|
+
export function verify<P extends Parser<unknown>>(parser: P, cond: (nodes: List<Data<Node<P>>>, context: Context<P>) => boolean): P;
|
|
32
|
+
export function verify<N>(parser: Parser<N>, cond: (nodes: List<Data<N>>, context: Ctx) => boolean): Parser<N> {
|
|
33
33
|
assert(parser);
|
|
34
34
|
return failsafe(input => {
|
|
35
35
|
const { context } = input;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { input } from '../../data/parser';
|
|
1
|
+
import { List, Data, input } from '../../data/parser';
|
|
2
2
|
import { line } from './line';
|
|
3
3
|
import { inspect } from '../../../debug.test';
|
|
4
4
|
|
|
@@ -7,15 +7,15 @@ describe('Unit: combinator/line', () => {
|
|
|
7
7
|
const { context: ctx } = input('', {});
|
|
8
8
|
|
|
9
9
|
it('invalid', () => {
|
|
10
|
-
assert.deepStrictEqual(inspect(line(_ =>
|
|
10
|
+
assert.deepStrictEqual(inspect(line(_ => new List<Data<string>>())(input('', ctx)), ctx), undefined);
|
|
11
11
|
});
|
|
12
12
|
|
|
13
13
|
it('valid', () => {
|
|
14
|
-
assert.deepStrictEqual(inspect(line(({ context }) => { context.position = context.source.length; return
|
|
15
|
-
assert.deepStrictEqual(inspect(line(({ context }) => { context.position = context.source.length; return
|
|
16
|
-
assert.deepStrictEqual(inspect(line(({ context }) => { context.position = context.source.length; return
|
|
17
|
-
assert.deepStrictEqual(inspect(line(({ context }) => { context.position = context.source.length; return
|
|
18
|
-
assert.deepStrictEqual(inspect(line(({ context }) => { context.position = context.source.length - 1; return
|
|
14
|
+
assert.deepStrictEqual(inspect(line(({ context }) => { context.position = context.source.length; return new List<Data<string>>(); })(input(' ', ctx)), ctx), [[], '']);
|
|
15
|
+
assert.deepStrictEqual(inspect(line(({ context }) => { context.position = context.source.length; return new List<Data<string>>(); })(input('\n', ctx)), ctx), [[], '']);
|
|
16
|
+
assert.deepStrictEqual(inspect(line(({ context }) => { context.position = context.source.length; return new List<Data<string>>(); })(input('\n\n', ctx)), ctx), [[], '\n']);
|
|
17
|
+
assert.deepStrictEqual(inspect(line(({ context }) => { context.position = context.source.length; return new List<Data<string>>(); })(input(' \n', ctx)), ctx), [[], '']);
|
|
18
|
+
assert.deepStrictEqual(inspect(line(({ context }) => { context.position = context.source.length - 1; return new List<Data<string>>(); })(input(' \n', ctx)), ctx), [[], '']);
|
|
19
19
|
});
|
|
20
20
|
|
|
21
21
|
});
|
|
@@ -18,7 +18,7 @@ export function line<N>(parser: Parser<N>): Parser<N> {
|
|
|
18
18
|
if (result === undefined) return;
|
|
19
19
|
if (!isBlank(source.slice(context.position, position + line.length))) return;
|
|
20
20
|
context.position = position + line.length;
|
|
21
|
-
return
|
|
21
|
+
return eval(result);
|
|
22
22
|
});
|
|
23
23
|
}
|
|
24
24
|
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import { Parser, CtxOptions } from '../../data/parser';
|
|
2
|
-
|
|
1
|
+
import { Parser, List, CtxOptions } from '../../data/parser';
|
|
3
2
|
|
|
4
3
|
export function clear<D extends Parser<unknown, C>[], C extends CtxOptions>(parser: Parser<unknown, C, D>): Parser<never, C, D> {
|
|
5
|
-
return input => parser(input) &&
|
|
4
|
+
return input => parser(input) && new List();
|
|
6
5
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Parser, Ctx, Context, subinput, failsafe } from '../../data/parser';
|
|
1
|
+
import { Parser, List, Ctx, Context, subinput, failsafe } from '../../data/parser';
|
|
2
2
|
|
|
3
3
|
export function convert<P extends Parser<unknown>>(conv: (source: string, context: Context<P>) => string, parser: P, continuous: boolean, empty?: boolean): P;
|
|
4
4
|
export function convert<N>(conv: (source: string, context: Ctx) => string, parser: Parser<N>, continuous: boolean, empty = false): Parser<N> {
|
|
@@ -11,7 +11,7 @@ export function convert<N>(conv: (source: string, context: Ctx) => string, parse
|
|
|
11
11
|
if (src === '') {
|
|
12
12
|
if (!empty) return;
|
|
13
13
|
context.position = source.length;
|
|
14
|
-
return
|
|
14
|
+
return new List();
|
|
15
15
|
}
|
|
16
16
|
assert(source.endsWith(src) || src.endsWith(source, position) || !continuous);
|
|
17
17
|
if (continuous) {
|
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import { Parser,
|
|
1
|
+
import { Parser, List, Data, Ctx } from '../../data/parser';
|
|
2
2
|
import { fmap } from '../monad/fmap';
|
|
3
3
|
|
|
4
|
-
export function dup<
|
|
5
|
-
export function dup<N
|
|
6
|
-
|
|
7
|
-
return fmap(parser, nodes => [nodes]);
|
|
4
|
+
export function dup<N, C extends Ctx, D extends Parser<unknown, C>[]>(parser: Parser<N, C, D>): Parser<List<Data<N>>, C, D>;
|
|
5
|
+
export function dup<N>(parser: Parser<N>): Parser<List<Data<N>>> {
|
|
6
|
+
return fmap(parser, nodes => new List([new Data(nodes)]));
|
|
8
7
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Parser, Ctx, failsafe } from '../../data/parser';
|
|
1
|
+
import { Parser, List, Data, Ctx, failsafe } from '../../data/parser';
|
|
2
2
|
import { firstline, isBlank } from '../constraint/line';
|
|
3
3
|
import { push } from 'spica/array';
|
|
4
4
|
|
|
@@ -47,6 +47,6 @@ export function fence<C extends Ctx, D extends Parser<unknown, C>[]>(opener: Reg
|
|
|
47
47
|
}
|
|
48
48
|
context.position += line.length;
|
|
49
49
|
}
|
|
50
|
-
return
|
|
50
|
+
return new List(push([block, overflow, closer], matches).map(str => new Data(str)));
|
|
51
51
|
});
|
|
52
52
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { indent } from './indent';
|
|
2
|
-
import { input } from '../../data/parser';
|
|
2
|
+
import { List, Data, input } from '../../data/parser';
|
|
3
3
|
import { inspect } from '../../../debug.test';
|
|
4
4
|
|
|
5
5
|
describe('Unit: combinator/indent', () => {
|
|
@@ -7,7 +7,7 @@ describe('Unit: combinator/indent', () => {
|
|
|
7
7
|
const { context: ctx } = input('', {});
|
|
8
8
|
|
|
9
9
|
it('valid', () => {
|
|
10
|
-
const parser = indent(({ context }) => { context.position = context.source.length; return [
|
|
10
|
+
const parser = indent(({ context }) => { context.position = context.source.length; return new List([new Data(context.source)]); });
|
|
11
11
|
assert.deepStrictEqual(inspect(parser(input('', ctx)), ctx), undefined);
|
|
12
12
|
assert.deepStrictEqual(inspect(parser(input(' ', ctx)), ctx), undefined);
|
|
13
13
|
assert.deepStrictEqual(inspect(parser(input(' ', ctx)), ctx), undefined);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Parser, subinput, eval, failsafe } from '../../data/parser';
|
|
1
|
+
import { Parser, List, Data, subinput, eval, failsafe } from '../../data/parser';
|
|
2
2
|
import { some } from '../../data/parser/some';
|
|
3
3
|
import { block } from '../constraint/block';
|
|
4
4
|
import { line } from '../constraint/line';
|
|
@@ -24,15 +24,15 @@ export function indent<N>(opener: RegExp | Parser<N>, parser: Parser<N> | boolea
|
|
|
24
24
|
some(line(open(indent, ({ context }) => {
|
|
25
25
|
const { source, position } = context;
|
|
26
26
|
context.position = source.length;
|
|
27
|
-
return [
|
|
27
|
+
return new List([new Data(source.slice(position))]);
|
|
28
28
|
}))),
|
|
29
29
|
([indent]) => indent.length * 2 + +(indent[0] === ' '), {})), separation),
|
|
30
30
|
(lines, context) => {
|
|
31
31
|
assert(parser = parser as Parser<N>);
|
|
32
|
-
const result = parser(subinput(trimBlockEnd(lines.
|
|
32
|
+
const result = parser(subinput(trimBlockEnd(lines.foldl((acc, node) => acc + node.value, '')), context));
|
|
33
33
|
assert(result);
|
|
34
34
|
return result
|
|
35
|
-
?
|
|
35
|
+
? eval(result)
|
|
36
36
|
: undefined;
|
|
37
37
|
}));
|
|
38
38
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { Parser } from '../../data/parser';
|
|
1
|
+
import { Parser, List, Data } from '../../data/parser';
|
|
2
2
|
import { fmap } from '../monad/fmap';
|
|
3
3
|
|
|
4
4
|
export function reverse<P extends Parser<unknown>>(parser: P): P;
|
|
5
5
|
export function reverse<N>(parser: Parser<N>): Parser<N> {
|
|
6
|
-
return fmap(parser, nodes => nodes.
|
|
6
|
+
return fmap(parser, nodes => nodes.foldr((node, acc) => acc.push(nodes.delete(node)) && acc, new List<Data<N>>()));
|
|
7
7
|
}
|
|
8
8
|
|
|
@@ -8,7 +8,7 @@ export function focus<N>(scope: string | RegExp, parser: Parser<N>): Parser<N> {
|
|
|
8
8
|
return failsafe(({ context }) => {
|
|
9
9
|
const { source, position } = context;
|
|
10
10
|
if (position === source.length) return;
|
|
11
|
-
const src = eval(match({ context }))?.
|
|
11
|
+
const src = eval(match({ context }))?.head?.value ?? '';
|
|
12
12
|
assert(source.startsWith(src, position));
|
|
13
13
|
if (src === '') return;
|
|
14
14
|
context.range = src.length;
|
|
@@ -21,7 +21,7 @@ export function focus<N>(scope: string | RegExp, parser: Parser<N>): Parser<N> {
|
|
|
21
21
|
context.source = source;
|
|
22
22
|
context.offset -= position;
|
|
23
23
|
if (result === undefined) return;
|
|
24
|
-
return
|
|
24
|
+
return eval(result);
|
|
25
25
|
});
|
|
26
26
|
}
|
|
27
27
|
|
|
@@ -48,7 +48,6 @@ export function rewrite<N>(scope: Parser<unknown>, parser: Parser<N>): Parser<N>
|
|
|
48
48
|
context.source = source;
|
|
49
49
|
context.offset -= position;
|
|
50
50
|
if (res2 === undefined) return;
|
|
51
|
-
|
|
52
|
-
return [eval(res2)];
|
|
51
|
+
return eval(res2);
|
|
53
52
|
});
|
|
54
53
|
}
|
|
@@ -1,40 +1,39 @@
|
|
|
1
|
-
import { Parser, Result, Ctx, Node, Context, SubParsers, SubNode, IntermediateParser, eval, failsafe } from '../../data/parser';
|
|
1
|
+
import { Parser, Result, List, Data, Ctx, Node, Context, SubParsers, SubNode, IntermediateParser, eval, failsafe } from '../../data/parser';
|
|
2
2
|
import { matcher, clear } from '../../../combinator';
|
|
3
|
-
import { unshift, push } from 'spica/array';
|
|
4
3
|
|
|
5
4
|
export function surround<P extends Parser<unknown>, S = string>(
|
|
6
5
|
opener: string | RegExp | Parser<S, Context<P>>, parser: IntermediateParser<P>, closer: string | RegExp | Parser<S, Context<P>>,
|
|
7
6
|
optional?: false,
|
|
8
|
-
f?: (rss: [S
|
|
9
|
-
g?: (rss: [S
|
|
7
|
+
f?: (rss: [List<Data<S>>, List<Data<SubNode<P>>>, List<Data<S>>], context: Context<P>) => Result<Node<P>, Context<P>, SubParsers<P>>,
|
|
8
|
+
g?: (rss: [List<Data<S>>, List<Data<SubNode<P>>> | undefined], context: Context<P>) => Result<Node<P>, Context<P>, SubParsers<P>>,
|
|
10
9
|
backtracks?: readonly number[],
|
|
11
10
|
): P;
|
|
12
11
|
export function surround<P extends Parser<unknown>, S = string>(
|
|
13
12
|
opener: string | RegExp | Parser<S, Context<P>>, parser: IntermediateParser<P>, closer: string | RegExp | Parser<S, Context<P>>,
|
|
14
13
|
optional?: boolean,
|
|
15
|
-
f?: (rss: [S
|
|
16
|
-
g?: (rss: [S
|
|
14
|
+
f?: (rss: [List<Data<S>>, List<Data<SubNode<P>>> | undefined, List<Data<S>>], context: Context<P>) => Result<Node<P>, Context<P>, SubParsers<P>>,
|
|
15
|
+
g?: (rss: [List<Data<S>>, List<Data<SubNode<P>>> | undefined], context: Context<P>) => Result<Node<P>, Context<P>, SubParsers<P>>,
|
|
17
16
|
backtracks?: readonly number[],
|
|
18
17
|
): P;
|
|
19
18
|
export function surround<P extends Parser<unknown>, S = string>(
|
|
20
19
|
opener: string | RegExp | Parser<S, Context<P>>, parser: P, closer: string | RegExp | Parser<S, Context<P>>,
|
|
21
20
|
optional?: false,
|
|
22
|
-
f?: (rss: [S
|
|
23
|
-
g?: (rss: [S
|
|
21
|
+
f?: (rss: [List<Data<S>>, List<Data<Node<P>>>, List<Data<S>>], context: Context<P>) => Result<Node<P>, Context<P>, SubParsers<P>>,
|
|
22
|
+
g?: (rss: [List<Data<S>>, List<Data<Node<P>>> | undefined], context: Context<P>) => Result<Node<P>, Context<P>, SubParsers<P>>,
|
|
24
23
|
backtracks?: readonly number[],
|
|
25
24
|
): P;
|
|
26
25
|
export function surround<P extends Parser<unknown>, S = string>(
|
|
27
26
|
opener: string | RegExp | Parser<S, Context<P>>, parser: P, closer: string | RegExp | Parser<S, Context<P>>,
|
|
28
27
|
optional?: boolean,
|
|
29
|
-
f?: (rss: [S
|
|
30
|
-
g?: (rss: [S
|
|
28
|
+
f?: (rss: [List<Data<S>>, List<Data<Node<P>>> | undefined, List<Data<S>>], context: Context<P>) => Result<Node<P>, Context<P>, SubParsers<P>>,
|
|
29
|
+
g?: (rss: [List<Data<S>>, List<Data<Node<P>>> | undefined], context: Context<P>) => Result<Node<P>, Context<P>, SubParsers<P>>,
|
|
31
30
|
backtracks?: readonly number[],
|
|
32
31
|
): P;
|
|
33
32
|
export function surround<N>(
|
|
34
33
|
opener: string | RegExp | Parser<N>, parser: Parser<N>, closer: string | RegExp | Parser<N>,
|
|
35
34
|
optional: boolean = false,
|
|
36
|
-
f?: (rss: [N
|
|
37
|
-
g?: (rss: [N
|
|
35
|
+
f?: (rss: [List<Data<N>>, List<Data<N>>, List<Data<N>>], context: Ctx) => Result<N>,
|
|
36
|
+
g?: (rss: [List<Data<N>>, List<Data<N>> | undefined], context: Ctx) => Result<N>,
|
|
38
37
|
backtracks: readonly number[] = [],
|
|
39
38
|
): Parser<N> {
|
|
40
39
|
switch (typeof opener) {
|
|
@@ -88,7 +87,7 @@ export function surround<N>(
|
|
|
88
87
|
context.range = context.position - position;
|
|
89
88
|
const result = f
|
|
90
89
|
? f([nodesO, nodesM!, nodesC], context)
|
|
91
|
-
:
|
|
90
|
+
: nodesO.import(nodesM ?? new List()).import(nodesC);
|
|
92
91
|
if (result) {
|
|
93
92
|
context.linebreak ||= linebreak;
|
|
94
93
|
}
|
|
@@ -157,8 +156,8 @@ export function setBacktrack(
|
|
|
157
156
|
position: number,
|
|
158
157
|
length: number = 1,
|
|
159
158
|
): void {
|
|
160
|
-
|
|
161
|
-
|
|
159
|
+
// 以降バックトラックの可能性がなく記録不要の場合もあるが判別が面倒なので省略
|
|
160
|
+
const { source } = context;
|
|
162
161
|
if (position === source.length) return;
|
|
163
162
|
if (length === 0) return;
|
|
164
163
|
for (const backtrack of backtracks) {
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { Parser, Result, Ctx, Node, Context, SubParsers, SubNode, IntermediateParser, eval, failsafe } from '../../data/parser';
|
|
1
|
+
import { Parser, Result, List, Data, Ctx, Node, Context, SubParsers, SubNode, IntermediateParser, eval, failsafe } from '../../data/parser';
|
|
2
2
|
|
|
3
|
-
export function bind<P extends Parser<unknown>>(parser: IntermediateParser<P>, f: (nodes: SubNode<P
|
|
4
|
-
export function bind<P extends Parser<unknown>>(parser: P, f: (nodes: Node<P
|
|
5
|
-
export function bind<N, P extends Parser<unknown>>(parser: Parser<N, Context<P>, SubParsers<P>>, f: (nodes: N
|
|
6
|
-
export function bind<U, P extends Parser<unknown>>(parser: P, f: (nodes: Node<P
|
|
7
|
-
export function bind<N, U>(parser: Parser<N>, f: (nodes: N
|
|
3
|
+
export function bind<P extends Parser<unknown>>(parser: IntermediateParser<P>, f: (nodes: List<Data<SubNode<P>>>, context: Context<P>) => Result<Node<P>, Context<P>, SubParsers<P>>): P;
|
|
4
|
+
export function bind<P extends Parser<unknown>>(parser: P, f: (nodes: List<Data<Node<P>>>, context: Context<P>) => Result<Node<P>, Context<P>, SubParsers<P>>): P;
|
|
5
|
+
export function bind<N, P extends Parser<unknown>>(parser: Parser<N, Context<P>, SubParsers<P>>, f: (nodes: List<Data<N>>, context: Context<P>) => Result<Node<P>, Context<P>, SubParsers<P>>): P;
|
|
6
|
+
export function bind<U, P extends Parser<unknown>>(parser: P, f: (nodes: List<Data<Node<P>>>, context: Context<P>) => Result<U, Context<P>, SubParsers<P>>): Parser<U, Context<P>, SubParsers<P>>;
|
|
7
|
+
export function bind<N, U>(parser: Parser<N>, f: (nodes: List<Data<N>>, context: Ctx) => Result<U>): Parser<U> {
|
|
8
8
|
assert(parser);
|
|
9
9
|
return failsafe(input => {
|
|
10
10
|
const { context } = input;
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { Parser, Ctx, SubParsers, Node, Context, IntermediateParser, SubNode } from '../../data/parser';
|
|
1
|
+
import { Parser, List, Data, Ctx, SubParsers, Node, Context, IntermediateParser, SubNode } from '../../data/parser';
|
|
2
2
|
import { bind } from './bind';
|
|
3
3
|
|
|
4
|
-
export function fmap<P extends Parser<unknown>>(parser: IntermediateParser<P>, f: (nodes: SubNode<P
|
|
5
|
-
export function fmap<P extends Parser<unknown>>(parser: P, f: (nodes: Node<P
|
|
6
|
-
export function fmap<N, P extends Parser<unknown>>(parser: Parser<N, Context<P>, SubParsers<P>>, f: (nodes: N
|
|
7
|
-
export function fmap<U, P extends Parser<unknown>>(parser: P, f: (nodes: Node<P
|
|
8
|
-
export function fmap<N, U>(parser: Parser<N>, f: (nodes: N
|
|
9
|
-
return bind(parser, (nodes, context) =>
|
|
4
|
+
export function fmap<P extends Parser<unknown>>(parser: IntermediateParser<P>, f: (nodes: List<Data<SubNode<P>>>, context: Context<P>) => List<Data<Node<P>>>): P;
|
|
5
|
+
export function fmap<P extends Parser<unknown>>(parser: P, f: (nodes: List<Data<Node<P>>>, context: Context<P>) => List<Data<Node<P>>>): P;
|
|
6
|
+
export function fmap<N, P extends Parser<unknown>>(parser: Parser<N, Context<P>, SubParsers<P>>, f: (nodes: List<Data<N>>, context: Context<P>) => List<Data<Node<P>>>): P;
|
|
7
|
+
export function fmap<U, P extends Parser<unknown>>(parser: P, f: (nodes: List<Data<Node<P>>>, context: Context<P>) => List<Data<U>>): Parser<U, Context<P>, SubParsers<P>>;
|
|
8
|
+
export function fmap<N, U>(parser: Parser<N>, f: (nodes: List<Data<N>>, context: Ctx) => List<Data<U>>): Parser<U> {
|
|
9
|
+
return bind(parser, (nodes, context) => f(nodes, context));
|
|
10
10
|
}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
// Memory-efficient flexible list.
|
|
2
|
+
|
|
3
|
+
export class List<N extends List.Node = List.Node> {
|
|
4
|
+
constructor(nodes?: ArrayLike<N>) {
|
|
5
|
+
if (nodes === undefined) return;
|
|
6
|
+
for (let i = 0; i < nodes.length; ++i) {
|
|
7
|
+
this.push(nodes[i]);
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
public length = 0;
|
|
11
|
+
public head?: N = undefined;
|
|
12
|
+
public get tail(): N | undefined {
|
|
13
|
+
return this.head?.next;
|
|
14
|
+
}
|
|
15
|
+
public get last(): N | undefined {
|
|
16
|
+
return this.head?.prev;
|
|
17
|
+
}
|
|
18
|
+
public insert(node: N, before?: N): N {
|
|
19
|
+
assert(!node.next);
|
|
20
|
+
if (++this.length === 1) {
|
|
21
|
+
return this.head = node.next = node.prev = node;
|
|
22
|
+
}
|
|
23
|
+
assert(node !== before);
|
|
24
|
+
const next = node.next = before ?? this.head!;
|
|
25
|
+
const prev = node.prev = next.prev!;
|
|
26
|
+
return next.prev = prev.next = node;
|
|
27
|
+
}
|
|
28
|
+
public delete(node: N): N {
|
|
29
|
+
assert(node.next);
|
|
30
|
+
assert(this.length > 0);
|
|
31
|
+
if (--this.length === 0) {
|
|
32
|
+
this.head = undefined;
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
const { next, prev } = node;
|
|
36
|
+
if (node === this.head) {
|
|
37
|
+
this.head = next;
|
|
38
|
+
}
|
|
39
|
+
// Error if not used.
|
|
40
|
+
prev!.next = next;
|
|
41
|
+
next!.prev = prev;
|
|
42
|
+
}
|
|
43
|
+
node.next = node.prev = undefined;
|
|
44
|
+
return node;
|
|
45
|
+
}
|
|
46
|
+
public unshift(node: N): N {
|
|
47
|
+
assert(!node.next);
|
|
48
|
+
return this.head = this.insert(node, this.head);
|
|
49
|
+
}
|
|
50
|
+
public push(node: N): N {
|
|
51
|
+
assert(!node.next);
|
|
52
|
+
return this.insert(node, this.head);
|
|
53
|
+
}
|
|
54
|
+
public shift(): N | undefined {
|
|
55
|
+
if (this.length === 0) return;
|
|
56
|
+
return this.delete(this.head!);
|
|
57
|
+
}
|
|
58
|
+
public pop(): N | undefined {
|
|
59
|
+
if (this.length === 0) return;
|
|
60
|
+
return this.delete(this.head!.prev!);
|
|
61
|
+
}
|
|
62
|
+
public import(list: List<N>, before?: N): this {
|
|
63
|
+
assert(list !== this);
|
|
64
|
+
if (list.length === 0) return this;
|
|
65
|
+
if (this.length === 0) {
|
|
66
|
+
this.head = list.head;
|
|
67
|
+
this.length += list.length;
|
|
68
|
+
list.clear();
|
|
69
|
+
return this;
|
|
70
|
+
}
|
|
71
|
+
const head = list.head!;
|
|
72
|
+
const last = list.last!;
|
|
73
|
+
const next = last.next = before ?? this.head!;
|
|
74
|
+
const prev = head.prev = next.prev!;
|
|
75
|
+
next.prev = last;
|
|
76
|
+
prev.next = head;
|
|
77
|
+
this.length += list.length;
|
|
78
|
+
list.clear();
|
|
79
|
+
return this;
|
|
80
|
+
}
|
|
81
|
+
public clear(): void {
|
|
82
|
+
this.length = 0;
|
|
83
|
+
this.head = undefined;
|
|
84
|
+
}
|
|
85
|
+
public *[Symbol.iterator](): Iterator<N, undefined, undefined> {
|
|
86
|
+
for (let node = this.head; node && this.head;) {
|
|
87
|
+
const next = node.next;
|
|
88
|
+
yield node;
|
|
89
|
+
node = next;
|
|
90
|
+
if (node === this.head) break;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
public flatMap<T extends List.Node>(f: (node: N) => List<T>): List<T> {
|
|
94
|
+
const acc = new List<T>();
|
|
95
|
+
for (let node = this.head; node && this.head;) {
|
|
96
|
+
const next = node.next;
|
|
97
|
+
acc.import(f(node));
|
|
98
|
+
node = next;
|
|
99
|
+
if (node === this.head) break;
|
|
100
|
+
}
|
|
101
|
+
return acc;
|
|
102
|
+
}
|
|
103
|
+
public foldl<T>(f: (acc: T, node: N) => T, acc: T): T {
|
|
104
|
+
for (let node = this.head; node && this.head;) {
|
|
105
|
+
const next = node.next;
|
|
106
|
+
acc = f(acc, node);
|
|
107
|
+
node = next;
|
|
108
|
+
if (node === this.head) break;
|
|
109
|
+
}
|
|
110
|
+
return acc;
|
|
111
|
+
}
|
|
112
|
+
public foldr<T>(f: (node: N, acc: T) => T, acc: T): T {
|
|
113
|
+
for (let node = this.head?.prev; node && this.head;) {
|
|
114
|
+
const prev = node.prev;
|
|
115
|
+
acc = f(node, acc);
|
|
116
|
+
if (node === this.head) break;
|
|
117
|
+
node = prev;
|
|
118
|
+
}
|
|
119
|
+
return acc;
|
|
120
|
+
}
|
|
121
|
+
public find(f: (node: N) => unknown): N | undefined {
|
|
122
|
+
for (let node = this.head; node && this.head;) {
|
|
123
|
+
const next = node.next;
|
|
124
|
+
if (f(node)) return node;
|
|
125
|
+
node = next;
|
|
126
|
+
if (node === this.head) break;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
export namespace List {
|
|
131
|
+
export class Node {
|
|
132
|
+
public next?: this = undefined;
|
|
133
|
+
public prev?: this = undefined;
|
|
134
|
+
}
|
|
135
|
+
}
|