securemark 0.291.1 → 0.293.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/design.md +13 -2
- package/dist/index.js +1353 -908
- package/markdown.d.ts +32 -49
- package/package.json +1 -1
- package/src/combinator/control/constraint/block.test.ts +8 -5
- package/src/combinator/control/constraint/block.ts +9 -9
- package/src/combinator/control/constraint/contract.ts +21 -38
- package/src/combinator/control/constraint/line.test.ts +9 -6
- package/src/combinator/control/constraint/line.ts +21 -22
- package/src/combinator/control/manipulation/clear.ts +3 -4
- package/src/combinator/control/manipulation/convert.ts +29 -13
- package/src/combinator/control/manipulation/fence.ts +20 -15
- package/src/combinator/control/manipulation/indent.test.ts +17 -14
- package/src/combinator/control/manipulation/indent.ts +14 -13
- package/src/combinator/control/manipulation/match.ts +13 -11
- package/src/combinator/control/manipulation/recovery.ts +7 -3
- package/src/combinator/control/manipulation/scope.ts +36 -44
- package/src/combinator/control/manipulation/surround.ts +69 -71
- package/src/combinator/control/manipulation/trim.test.ts +12 -9
- package/src/combinator/control/monad/bind.ts +16 -16
- package/src/combinator/control/monad/fmap.ts +6 -6
- package/src/combinator/data/parser/context/delimiter.ts +10 -8
- package/src/combinator/data/parser/context.test.ts +19 -14
- package/src/combinator/data/parser/context.ts +51 -16
- package/src/combinator/data/parser/inits.ts +13 -14
- package/src/combinator/data/parser/sequence.test.ts +16 -15
- package/src/combinator/data/parser/sequence.ts +13 -14
- package/src/combinator/data/parser/some.test.ts +20 -19
- package/src/combinator/data/parser/some.ts +14 -17
- package/src/combinator/data/parser/subsequence.test.ts +22 -21
- 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 +16 -15
- package/src/combinator/data/parser/union.ts +2 -2
- package/src/combinator/data/parser.ts +65 -28
- package/src/debug.test.ts +3 -3
- package/src/parser/api/bind.ts +3 -3
- package/src/parser/api/header.ts +7 -6
- package/src/parser/api/normalize.ts +2 -2
- package/src/parser/api/parse.test.ts +26 -19
- package/src/parser/api/parse.ts +4 -5
- package/src/parser/autolink.test.ts +19 -17
- package/src/parser/autolink.ts +2 -4
- package/src/parser/block/blockquote.test.ts +86 -84
- package/src/parser/block/blockquote.ts +10 -8
- package/src/parser/block/codeblock.test.ts +58 -56
- package/src/parser/block/codeblock.ts +4 -4
- package/src/parser/block/dlist.test.ts +58 -56
- package/src/parser/block/dlist.ts +6 -6
- package/src/parser/block/extension/aside.test.ts +10 -8
- package/src/parser/block/extension/aside.ts +2 -2
- package/src/parser/block/extension/example.test.ts +20 -18
- package/src/parser/block/extension/example.ts +4 -4
- package/src/parser/block/extension/fig.test.ts +38 -36
- package/src/parser/block/extension/fig.ts +4 -4
- package/src/parser/block/extension/figbase.test.ts +17 -15
- package/src/parser/block/extension/figbase.ts +1 -1
- package/src/parser/block/extension/figure.test.ts +64 -62
- package/src/parser/block/extension/figure.ts +7 -6
- package/src/parser/block/extension/message.test.ts +15 -13
- package/src/parser/block/extension/message.ts +4 -4
- package/src/parser/block/extension/placeholder.test.ts +3 -1
- package/src/parser/block/extension/placeholder.ts +1 -1
- package/src/parser/block/extension/table.test.ts +72 -70
- package/src/parser/block/extension/table.ts +19 -19
- package/src/parser/block/extension.test.ts +3 -1
- package/src/parser/block/extension.ts +2 -2
- package/src/parser/block/heading.test.ts +65 -64
- package/src/parser/block/heading.ts +5 -5
- package/src/parser/block/ilist.test.ts +6 -4
- package/src/parser/block/ilist.ts +7 -7
- package/src/parser/block/mathblock.test.ts +33 -31
- package/src/parser/block/mathblock.ts +2 -2
- package/src/parser/block/mediablock.ts +3 -3
- package/src/parser/block/olist.test.ts +101 -97
- package/src/parser/block/olist.ts +14 -14
- package/src/parser/block/pagebreak.test.ts +17 -15
- package/src/parser/block/pagebreak.ts +2 -2
- package/src/parser/block/paragraph.test.ts +60 -57
- package/src/parser/block/paragraph.ts +2 -2
- package/src/parser/block/reply/cite.test.ts +41 -39
- package/src/parser/block/reply/cite.ts +4 -4
- package/src/parser/block/reply/quote.test.ts +52 -50
- package/src/parser/block/reply/quote.ts +5 -4
- package/src/parser/block/reply.test.ts +21 -19
- package/src/parser/block/reply.ts +3 -3
- package/src/parser/block/sidefence.test.ts +51 -49
- package/src/parser/block/sidefence.ts +3 -3
- package/src/parser/block/table.test.ts +51 -50
- package/src/parser/block/table.ts +14 -14
- package/src/parser/block/ulist.test.ts +53 -50
- package/src/parser/block/ulist.ts +8 -8
- package/src/parser/block.ts +53 -19
- package/src/parser/context.ts +1 -0
- package/src/parser/header.test.ts +22 -21
- package/src/parser/header.ts +28 -16
- package/src/parser/inline/annotation.test.ts +44 -42
- package/src/parser/inline/annotation.ts +2 -2
- package/src/parser/inline/autolink/account.test.ts +33 -30
- package/src/parser/inline/autolink/account.ts +12 -9
- package/src/parser/inline/autolink/anchor.test.ts +23 -21
- package/src/parser/inline/autolink/anchor.ts +21 -17
- package/src/parser/inline/autolink/channel.test.ts +16 -14
- package/src/parser/inline/autolink/channel.ts +40 -15
- package/src/parser/inline/autolink/email.test.ts +38 -36
- package/src/parser/inline/autolink/email.ts +7 -9
- package/src/parser/inline/autolink/hashnum.test.ts +34 -37
- package/src/parser/inline/autolink/hashnum.ts +9 -5
- package/src/parser/inline/autolink/hashtag.test.ts +57 -56
- package/src/parser/inline/autolink/hashtag.ts +10 -7
- package/src/parser/inline/autolink/url.test.ts +75 -75
- package/src/parser/inline/autolink/url.ts +24 -28
- package/src/parser/inline/autolink.ts +21 -24
- package/src/parser/inline/bracket.test.ts +69 -67
- package/src/parser/inline/bracket.ts +35 -35
- package/src/parser/inline/code.test.ts +32 -29
- package/src/parser/inline/code.ts +20 -13
- package/src/parser/inline/deletion.test.ts +29 -27
- package/src/parser/inline/deletion.ts +3 -3
- package/src/parser/inline/emphasis.test.ts +40 -36
- package/src/parser/inline/emphasis.ts +4 -9
- package/src/parser/inline/emstrong.test.ts +102 -96
- package/src/parser/inline/emstrong.ts +93 -45
- package/src/parser/inline/extension/index.test.ts +93 -89
- package/src/parser/inline/extension/index.ts +16 -31
- package/src/parser/inline/extension/indexee.ts +1 -1
- package/src/parser/inline/extension/indexer.test.ts +26 -24
- package/src/parser/inline/extension/indexer.ts +3 -3
- package/src/parser/inline/extension/label.test.ts +34 -32
- package/src/parser/inline/extension/label.ts +1 -1
- package/src/parser/inline/extension/placeholder.test.ts +44 -42
- package/src/parser/inline/extension/placeholder.ts +12 -9
- package/src/parser/inline/html.test.ts +108 -106
- package/src/parser/inline/html.ts +38 -37
- package/src/parser/inline/htmlentity.test.ts +39 -37
- package/src/parser/inline/htmlentity.ts +9 -3
- package/src/parser/inline/insertion.test.ts +29 -27
- package/src/parser/inline/insertion.ts +3 -3
- package/src/parser/inline/italic.test.ts +55 -53
- package/src/parser/inline/italic.ts +3 -3
- package/src/parser/inline/link.test.ts +187 -185
- package/src/parser/inline/link.ts +45 -27
- package/src/parser/inline/mark.test.ts +31 -29
- package/src/parser/inline/mark.ts +4 -4
- package/src/parser/inline/math.test.ts +133 -131
- package/src/parser/inline/math.ts +9 -13
- package/src/parser/inline/media.test.ts +93 -91
- package/src/parser/inline/media.ts +50 -26
- package/src/parser/inline/reference.test.ts +110 -108
- package/src/parser/inline/reference.ts +50 -41
- package/src/parser/inline/remark.test.ts +53 -51
- package/src/parser/inline/remark.ts +5 -5
- package/src/parser/inline/ruby.test.ts +46 -44
- package/src/parser/inline/ruby.ts +26 -27
- package/src/parser/inline/shortmedia.test.ts +11 -9
- package/src/parser/inline/shortmedia.ts +6 -9
- package/src/parser/inline/strong.test.ts +37 -33
- package/src/parser/inline/strong.ts +7 -9
- package/src/parser/inline/template.test.ts +24 -22
- package/src/parser/inline/template.ts +20 -11
- package/src/parser/inline.test.ts +223 -220
- package/src/parser/inline.ts +13 -8
- package/src/parser/segment.ts +13 -8
- package/src/parser/source/escapable.test.ts +24 -22
- package/src/parser/source/escapable.ts +50 -41
- package/src/parser/source/line.test.ts +19 -17
- package/src/parser/source/line.ts +28 -4
- package/src/parser/source/str.ts +18 -23
- package/src/parser/source/text.test.ts +85 -83
- package/src/parser/source/text.ts +78 -54
- package/src/parser/source/unescapable.test.ts +24 -22
- package/src/parser/source/unescapable.ts +42 -33
- package/src/parser/source.ts +1 -1
- package/src/parser/util.ts +39 -36
- package/src/parser/visibility.ts +33 -24
- package/src/util/quote.ts +4 -2
package/markdown.d.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import { Parser, Ctx } from './src/combinator/data/parser';
|
|
2
|
-
import { Command } from './src/parser/context';
|
|
1
|
+
import { Parser, Ctx, CtxOptions } from './src/combinator/data/parser';
|
|
3
2
|
import { Dict } from 'spica/dict';
|
|
4
3
|
|
|
5
4
|
declare abstract class Markdown<T> {
|
|
@@ -13,7 +12,11 @@ export interface MarkdownParser extends
|
|
|
13
12
|
]> {
|
|
14
13
|
}
|
|
15
14
|
export namespace MarkdownParser {
|
|
16
|
-
export interface Context extends Ctx {
|
|
15
|
+
export interface Context extends Ctx, Options {
|
|
16
|
+
buffer?: (string | HTMLElement)[];
|
|
17
|
+
sequential?: boolean;
|
|
18
|
+
}
|
|
19
|
+
export interface Options extends CtxOptions {
|
|
17
20
|
readonly host?: URL;
|
|
18
21
|
readonly url?: URL;
|
|
19
22
|
readonly id?: string;
|
|
@@ -732,18 +735,10 @@ export namespace MarkdownParser {
|
|
|
732
735
|
export interface SignatureParser extends
|
|
733
736
|
Inline<'extension/index/signature'>,
|
|
734
737
|
Parser<string | HTMLElement, Context, [
|
|
735
|
-
|
|
738
|
+
UnsafeHTMLEntityParser,
|
|
739
|
+
SourceParser.TxtParser,
|
|
736
740
|
]> {
|
|
737
741
|
}
|
|
738
|
-
export namespace SignatureParser {
|
|
739
|
-
export interface InternalParser extends
|
|
740
|
-
Inline<'extension/index/signature/internal'>,
|
|
741
|
-
Parser<string, Context, [
|
|
742
|
-
UnsafeHTMLEntityParser,
|
|
743
|
-
SourceParser.TxtParser,
|
|
744
|
-
]> {
|
|
745
|
-
}
|
|
746
|
-
}
|
|
747
742
|
}
|
|
748
743
|
export interface IndexerParser extends
|
|
749
744
|
// [|signature]
|
|
@@ -784,7 +779,7 @@ export namespace MarkdownParser {
|
|
|
784
779
|
// { uri }
|
|
785
780
|
// [abc]{uri nofollow}
|
|
786
781
|
Inline<'link'>,
|
|
787
|
-
Parser<HTMLAnchorElement, Context, [
|
|
782
|
+
Parser<HTMLAnchorElement | HTMLSpanElement, Context, [
|
|
788
783
|
LinkParser.MediaLinkParser,
|
|
789
784
|
LinkParser.TextLinkParser,
|
|
790
785
|
]> {
|
|
@@ -798,7 +793,7 @@ export namespace MarkdownParser {
|
|
|
798
793
|
}
|
|
799
794
|
export interface TextLinkParser extends
|
|
800
795
|
Inline<'link/textlink'>,
|
|
801
|
-
Parser<HTMLAnchorElement, Context, [
|
|
796
|
+
Parser<HTMLAnchorElement | HTMLSpanElement, Context, [
|
|
802
797
|
Parser<(HTMLElement | string)[], Context, [
|
|
803
798
|
InlineParser,
|
|
804
799
|
]>,
|
|
@@ -807,7 +802,7 @@ export namespace MarkdownParser {
|
|
|
807
802
|
}
|
|
808
803
|
export interface MediaLinkParser extends
|
|
809
804
|
Inline<'link/medialink'>,
|
|
810
|
-
Parser<HTMLAnchorElement, Context, [
|
|
805
|
+
Parser<HTMLAnchorElement | HTMLSpanElement, Context, [
|
|
811
806
|
Parser<HTMLElement[], Context, [
|
|
812
807
|
MediaParser,
|
|
813
808
|
ShortMediaParser,
|
|
@@ -979,7 +974,7 @@ export namespace MarkdownParser {
|
|
|
979
974
|
Inline<'insertion'>,
|
|
980
975
|
Parser<HTMLElement | string, Context, [
|
|
981
976
|
InlineParser,
|
|
982
|
-
|
|
977
|
+
InlineParser,
|
|
983
978
|
]> {
|
|
984
979
|
}
|
|
985
980
|
export interface DeletionParser extends
|
|
@@ -987,7 +982,7 @@ export namespace MarkdownParser {
|
|
|
987
982
|
Inline<'deletion'>,
|
|
988
983
|
Parser<HTMLElement | string, Context, [
|
|
989
984
|
InlineParser,
|
|
990
|
-
|
|
985
|
+
InlineParser,
|
|
991
986
|
]> {
|
|
992
987
|
}
|
|
993
988
|
export interface MarkParser extends
|
|
@@ -995,7 +990,7 @@ export namespace MarkdownParser {
|
|
|
995
990
|
Inline<'mark'>,
|
|
996
991
|
Parser<HTMLElement | string, Context, [
|
|
997
992
|
InlineParser,
|
|
998
|
-
|
|
993
|
+
InlineParser,
|
|
999
994
|
]> {
|
|
1000
995
|
}
|
|
1001
996
|
export interface EmStrongParser extends
|
|
@@ -1010,11 +1005,9 @@ export namespace MarkdownParser {
|
|
|
1010
1005
|
// **abc**
|
|
1011
1006
|
Inline<'strong'>,
|
|
1012
1007
|
Parser<HTMLElement | string, Context, [
|
|
1008
|
+
EmphasisParser,
|
|
1009
|
+
InlineParser,
|
|
1013
1010
|
InlineParser,
|
|
1014
|
-
Parser<HTMLElement | string, Context, [
|
|
1015
|
-
EmStrongParser,
|
|
1016
|
-
StrongParser,
|
|
1017
|
-
]>,
|
|
1018
1011
|
]> {
|
|
1019
1012
|
}
|
|
1020
1013
|
export interface EmphasisParser extends
|
|
@@ -1023,11 +1016,7 @@ export namespace MarkdownParser {
|
|
|
1023
1016
|
Parser<HTMLElement | string, Context, [
|
|
1024
1017
|
StrongParser,
|
|
1025
1018
|
InlineParser,
|
|
1026
|
-
|
|
1027
|
-
EmStrongParser,
|
|
1028
|
-
StrongParser,
|
|
1029
|
-
EmphasisParser,
|
|
1030
|
-
]>,
|
|
1019
|
+
InlineParser,
|
|
1031
1020
|
]> {
|
|
1032
1021
|
}
|
|
1033
1022
|
export interface ItalicParser extends
|
|
@@ -1035,7 +1024,7 @@ export namespace MarkdownParser {
|
|
|
1035
1024
|
Inline<'italic'>,
|
|
1036
1025
|
Parser<HTMLElement | string, Context, [
|
|
1037
1026
|
InlineParser,
|
|
1038
|
-
|
|
1027
|
+
InlineParser,
|
|
1039
1028
|
]> {
|
|
1040
1029
|
}
|
|
1041
1030
|
export interface MathParser extends
|
|
@@ -1045,8 +1034,8 @@ export namespace MarkdownParser {
|
|
|
1045
1034
|
Parser<HTMLElement, Context, [
|
|
1046
1035
|
MathParser.BracketParser,
|
|
1047
1036
|
Parser<string, Context, [
|
|
1048
|
-
MathParser.BracketParser,
|
|
1049
1037
|
SourceParser.EscapableSourceParser,
|
|
1038
|
+
MathParser.BracketParser,
|
|
1050
1039
|
]>,
|
|
1051
1040
|
]> {
|
|
1052
1041
|
}
|
|
@@ -1112,23 +1101,17 @@ export namespace MarkdownParser {
|
|
|
1112
1101
|
export interface AutolinkParser extends
|
|
1113
1102
|
Inline<'autolink'>,
|
|
1114
1103
|
Parser<HTMLElement | string, Context, [
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
AutolinkParser.HashtagParser,
|
|
1127
|
-
AutolinkParser.HashnumParser,
|
|
1128
|
-
SourceParser.StrParser,
|
|
1129
|
-
SourceParser.StrParser,
|
|
1130
|
-
AutolinkParser.AnchorParser,
|
|
1131
|
-
]>,
|
|
1104
|
+
AutolinkParser.UrlParser.LineUrlParser,
|
|
1105
|
+
AutolinkParser.UrlParser,
|
|
1106
|
+
AutolinkParser.EmailParser,
|
|
1107
|
+
SourceParser.StrParser,
|
|
1108
|
+
AutolinkParser.ChannelParser,
|
|
1109
|
+
AutolinkParser.AccountParser,
|
|
1110
|
+
SourceParser.StrParser,
|
|
1111
|
+
AutolinkParser.HashtagParser,
|
|
1112
|
+
AutolinkParser.HashnumParser,
|
|
1113
|
+
SourceParser.StrParser,
|
|
1114
|
+
AutolinkParser.AnchorParser,
|
|
1132
1115
|
]> {
|
|
1133
1116
|
}
|
|
1134
1117
|
export namespace AutolinkParser {
|
|
@@ -1182,8 +1165,8 @@ export namespace MarkdownParser {
|
|
|
1182
1165
|
// @user#tag
|
|
1183
1166
|
Inline<'channel'>,
|
|
1184
1167
|
Parser<string | HTMLAnchorElement, Context, [
|
|
1185
|
-
|
|
1186
|
-
|
|
1168
|
+
LinkParser.UnsafeLinkParser,
|
|
1169
|
+
Parser<string, Context, []>,
|
|
1187
1170
|
]> {
|
|
1188
1171
|
}
|
|
1189
1172
|
export interface AccountParser extends
|
package/package.json
CHANGED
|
@@ -1,17 +1,20 @@
|
|
|
1
1
|
import { block } from './block';
|
|
2
|
+
import { input } from '../../data/parser';
|
|
2
3
|
import { inspect } from '../../../debug.test';
|
|
3
4
|
|
|
4
5
|
describe('Unit: combinator/block', () => {
|
|
5
6
|
describe('block', () => {
|
|
7
|
+
const { context: ctx } = input('', {});
|
|
8
|
+
|
|
6
9
|
it('invalid', () => {
|
|
7
|
-
assert.throws(() => block(_ => [[]
|
|
10
|
+
assert.throws(() => block(_ => [[]])(input(' \n', ctx)));
|
|
8
11
|
});
|
|
9
12
|
|
|
10
13
|
it('valid', () => {
|
|
11
|
-
assert.deepStrictEqual(inspect(block(
|
|
12
|
-
assert.deepStrictEqual(inspect(block(
|
|
13
|
-
assert.deepStrictEqual(inspect(block(
|
|
14
|
-
assert.deepStrictEqual(inspect(block(
|
|
14
|
+
assert.deepStrictEqual(inspect(block(({ context }) => { context.position = context.source.length; return [[]]; })(input('\n', ctx)), ctx), [[], '']);
|
|
15
|
+
assert.deepStrictEqual(inspect(block(({ context }) => { context.position = context.source.length; return [[]]; })(input(' \n', ctx)), ctx), [[], '']);
|
|
16
|
+
assert.deepStrictEqual(inspect(block(({ context }) => { context.position = context.source.length; return [[]]; })(input('\n\n', ctx)), ctx), [[], '']);
|
|
17
|
+
assert.deepStrictEqual(inspect(block(({ context }) => { context.position = context.source.length - 1; return [[]]; })(input('\n\n', ctx)), ctx), [[], '\n']);
|
|
15
18
|
});
|
|
16
19
|
|
|
17
20
|
});
|
|
@@ -1,19 +1,19 @@
|
|
|
1
|
-
import { Parser,
|
|
1
|
+
import { Parser, failsafe } from '../../data/parser';
|
|
2
2
|
import { firstline, isBlank } from './line';
|
|
3
3
|
|
|
4
4
|
export function block<P extends Parser<unknown>>(parser: P, separation?: boolean): P;
|
|
5
5
|
export function block<N>(parser: Parser<N>, separation = true): Parser<N> {
|
|
6
6
|
assert(parser);
|
|
7
|
-
return input => {
|
|
8
|
-
const {
|
|
9
|
-
|
|
7
|
+
return failsafe(input => {
|
|
8
|
+
const { context } = input;
|
|
9
|
+
const { source, position } = context;
|
|
10
|
+
if (position === source.length) return;
|
|
10
11
|
const result = parser(input);
|
|
11
12
|
if (result === undefined) return;
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
return rest === '' || source[source.length - rest.length - 1] === '\n'
|
|
13
|
+
if (separation && !isBlank(firstline(source, context.position))) return;
|
|
14
|
+
assert(context.position === source.length || source[context.position - 1] === '\n');
|
|
15
|
+
return context.position === source.length || source[context.position - 1] === '\n'
|
|
16
16
|
? result
|
|
17
17
|
: undefined;
|
|
18
|
-
};
|
|
18
|
+
});
|
|
19
19
|
}
|
|
@@ -1,36 +1,22 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { Parser, Input, Ctx, Node, Context, eval, failsafe } from '../../data/parser';
|
|
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;
|
|
5
5
|
//export function contract<N>(patterns: string | RegExp | (string | RegExp)[], parser: Parser<N>, cond: (nodes: readonly N[], rest: string) => boolean): Parser<N> {
|
|
6
6
|
// return verify(validate(patterns, parser), cond);
|
|
7
7
|
//}
|
|
8
8
|
|
|
9
|
-
export function validate<P extends Parser<unknown>>(
|
|
9
|
+
export function validate<P extends Parser<unknown>>(pattern: string | RegExp, parser: P): P;
|
|
10
10
|
export function validate<P extends Parser<unknown>>(cond: ((input: Input<Context<P>>) => boolean), parser: P): P;
|
|
11
|
-
export function validate<N>(
|
|
12
|
-
if (typeof
|
|
13
|
-
|
|
14
|
-
assert(patterns.length > 0);
|
|
15
|
-
assert(patterns.every(pattern => pattern instanceof RegExp ? !pattern.flags.match(/[gmy]/) && pattern.source.startsWith('^') : true));
|
|
16
|
-
const match: (source: string) => boolean = global.eval([
|
|
17
|
-
'source =>',
|
|
18
|
-
patterns.map(pattern =>
|
|
19
|
-
typeof pattern === 'string'
|
|
20
|
-
? `|| source.slice(0, ${pattern.length}) === '${pattern}'`
|
|
21
|
-
: `|| /${pattern.source}/${pattern.flags}.test(source)`).join('').slice(2),
|
|
22
|
-
].join(''));
|
|
11
|
+
export function validate<N>(pattern: string | RegExp | ((input: Input<Ctx>) => boolean), parser: Parser<N>): Parser<N> {
|
|
12
|
+
if (typeof pattern === 'function') return guard(pattern, parser);
|
|
13
|
+
const match = matcher(pattern, false);
|
|
23
14
|
return input => {
|
|
24
|
-
const {
|
|
25
|
-
|
|
26
|
-
if (
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
if (result === undefined) return;
|
|
30
|
-
assert(exec(result).length < source.length);
|
|
31
|
-
return exec(result).length < source.length
|
|
32
|
-
? result
|
|
33
|
-
: undefined;
|
|
15
|
+
const { context } = input;
|
|
16
|
+
const { source, position } = context;
|
|
17
|
+
if (position === source.length) return;
|
|
18
|
+
if (!match(input)) return;
|
|
19
|
+
return parser(input);
|
|
34
20
|
};
|
|
35
21
|
}
|
|
36
22
|
|
|
@@ -42,19 +28,16 @@ function guard<N>(f: (input: Input<Ctx>) => boolean, parser: Parser<N>): Parser<
|
|
|
42
28
|
: undefined;
|
|
43
29
|
}
|
|
44
30
|
|
|
45
|
-
export function verify<P extends Parser<unknown>>(parser: P, cond: (nodes: readonly Node<P>[],
|
|
46
|
-
export function verify<N>(parser: Parser<N>, cond: (nodes: readonly N[],
|
|
31
|
+
export function verify<P extends Parser<unknown>>(parser: P, cond: (nodes: readonly Node<P>[], context: Context<P>) => boolean): P;
|
|
32
|
+
export function verify<N>(parser: Parser<N>, cond: (nodes: readonly N[], context: Ctx) => boolean): Parser<N> {
|
|
47
33
|
assert(parser);
|
|
48
|
-
return input => {
|
|
49
|
-
const {
|
|
50
|
-
|
|
34
|
+
return failsafe(input => {
|
|
35
|
+
const { context } = input;
|
|
36
|
+
const { source, position } = context;
|
|
37
|
+
if (position === source.length) return;
|
|
51
38
|
const result = parser(input);
|
|
52
|
-
assert(
|
|
53
|
-
if (result
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
return exec(result).length < source.length
|
|
57
|
-
? result
|
|
58
|
-
: undefined;
|
|
59
|
-
};
|
|
39
|
+
assert(context.position > position || !result);
|
|
40
|
+
if (result && !cond(eval(result), context)) return;
|
|
41
|
+
return result;
|
|
42
|
+
});
|
|
60
43
|
}
|
|
@@ -1,18 +1,21 @@
|
|
|
1
|
+
import { input } from '../../data/parser';
|
|
1
2
|
import { line } from './line';
|
|
2
3
|
import { inspect } from '../../../debug.test';
|
|
3
4
|
|
|
4
5
|
describe('Unit: combinator/line', () => {
|
|
5
6
|
describe('line', () => {
|
|
7
|
+
const { context: ctx } = input('', {});
|
|
8
|
+
|
|
6
9
|
it('invalid', () => {
|
|
7
|
-
assert.deepStrictEqual(inspect(line(_ => [[]
|
|
10
|
+
assert.deepStrictEqual(inspect(line(_ => [[]])(input('', ctx)), ctx), undefined);
|
|
8
11
|
});
|
|
9
12
|
|
|
10
13
|
it('valid', () => {
|
|
11
|
-
assert.deepStrictEqual(inspect(line(
|
|
12
|
-
assert.deepStrictEqual(inspect(line(
|
|
13
|
-
assert.deepStrictEqual(inspect(line(
|
|
14
|
-
assert.deepStrictEqual(inspect(line(
|
|
15
|
-
assert.deepStrictEqual(inspect(line(
|
|
14
|
+
assert.deepStrictEqual(inspect(line(({ context }) => { context.position = context.source.length; return [[]]; })(input(' ', ctx)), ctx), [[], '']);
|
|
15
|
+
assert.deepStrictEqual(inspect(line(({ context }) => { context.position = context.source.length; return [[]]; })(input('\n', ctx)), ctx), [[], '']);
|
|
16
|
+
assert.deepStrictEqual(inspect(line(({ context }) => { context.position = context.source.length; return [[]]; })(input('\n\n', ctx)), ctx), [[], '\n']);
|
|
17
|
+
assert.deepStrictEqual(inspect(line(({ context }) => { context.position = context.source.length; return [[]]; })(input(' \n', ctx)), ctx), [[], '']);
|
|
18
|
+
assert.deepStrictEqual(inspect(line(({ context }) => { context.position = context.source.length - 1; return [[]]; })(input(' \n', ctx)), ctx), [[], '']);
|
|
16
19
|
});
|
|
17
20
|
|
|
18
21
|
});
|
|
@@ -1,33 +1,32 @@
|
|
|
1
|
-
import { Parser,
|
|
1
|
+
import { Parser, input, eval, failsafe } from '../../data/parser';
|
|
2
2
|
|
|
3
3
|
export function line<P extends Parser<unknown>>(parser: P): P;
|
|
4
4
|
export function line<N>(parser: Parser<N>): Parser<N> {
|
|
5
5
|
assert(parser);
|
|
6
|
-
return ({
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
return failsafe(({ context }) => {
|
|
7
|
+
const { source, position } = context;
|
|
8
|
+
if (position === source.length) return;
|
|
9
|
+
const line = firstline(source, position);
|
|
9
10
|
context.offset ??= 0;
|
|
10
|
-
context.offset +=
|
|
11
|
-
const result = parser(
|
|
12
|
-
|
|
13
|
-
context.
|
|
11
|
+
context.offset += position;
|
|
12
|
+
const result = parser(input(line, context));
|
|
13
|
+
context.position += position;
|
|
14
|
+
context.position += result && context.position === position ? line.length : 0;
|
|
15
|
+
assert(context.position > position || !result);
|
|
16
|
+
context.source = source;
|
|
17
|
+
context.offset -= position;
|
|
14
18
|
if (result === undefined) return;
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
};
|
|
19
|
+
if (!isBlank(source.slice(context.position, position + line.length))) return;
|
|
20
|
+
context.position = position + line.length;
|
|
21
|
+
return [eval(result)];
|
|
22
|
+
});
|
|
19
23
|
}
|
|
20
24
|
|
|
21
|
-
export function firstline(source: string): string {
|
|
22
|
-
const i = source.indexOf('\n');
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
case 0:
|
|
27
|
-
return '\n';
|
|
28
|
-
default:
|
|
29
|
-
return source.slice(0, i + 1);
|
|
30
|
-
}
|
|
25
|
+
export function firstline(source: string, position: number): string {
|
|
26
|
+
const i = source.indexOf('\n', position);
|
|
27
|
+
return i === -1
|
|
28
|
+
? source.slice(position)
|
|
29
|
+
: source.slice(position, i + 1);
|
|
31
30
|
}
|
|
32
31
|
|
|
33
32
|
export function isBlank(line: string): boolean {
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import { Parser,
|
|
2
|
-
import { fmap } from '../monad/fmap';
|
|
1
|
+
import { Parser, CtxOptions } from '../../data/parser';
|
|
3
2
|
|
|
4
3
|
|
|
5
|
-
export function clear<D extends Parser<unknown, C>[], C extends
|
|
6
|
-
return
|
|
4
|
+
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) && [[]];
|
|
7
6
|
}
|
|
@@ -1,18 +1,34 @@
|
|
|
1
|
-
import { Parser, Ctx, Context,
|
|
1
|
+
import { Parser, 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> {
|
|
5
5
|
assert(parser);
|
|
6
|
-
return (
|
|
7
|
-
|
|
8
|
-
const
|
|
9
|
-
if (
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
6
|
+
return failsafe(input => {
|
|
7
|
+
const { context } = input;
|
|
8
|
+
const { source, position } = context;
|
|
9
|
+
if (position === source.length) return;
|
|
10
|
+
const src = conv(source.slice(position), context);
|
|
11
|
+
if (src === '') {
|
|
12
|
+
if (!empty) return;
|
|
13
|
+
context.position = source.length;
|
|
14
|
+
return [[]];
|
|
15
|
+
}
|
|
16
|
+
assert(source.endsWith(src) || src.endsWith(source, position) || !continuous);
|
|
17
|
+
if (continuous) {
|
|
18
|
+
context.position += source.length - position - src.length;
|
|
19
|
+
const result = parser(input);
|
|
20
|
+
assert(context.position > position || !result);
|
|
21
|
+
context.source = source;
|
|
22
|
+
return result;
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
const { offset, backtracks } = context;
|
|
26
|
+
const result = parser(subinput(src, context));
|
|
27
|
+
context.position = context.source.length
|
|
28
|
+
assert(context.offset === offset);
|
|
29
|
+
assert(context.source === source);
|
|
30
|
+
assert(context.backtracks === backtracks);
|
|
31
|
+
return result;
|
|
32
|
+
}
|
|
33
|
+
});
|
|
18
34
|
}
|
|
@@ -1,37 +1,42 @@
|
|
|
1
|
-
import { Parser, Ctx } from '../../data/parser';
|
|
1
|
+
import { Parser, Ctx, failsafe } from '../../data/parser';
|
|
2
2
|
import { firstline, isBlank } from '../constraint/line';
|
|
3
3
|
import { push } from 'spica/array';
|
|
4
4
|
|
|
5
5
|
export function fence<C extends Ctx, D extends Parser<unknown, C>[]>(opener: RegExp, limit: number, separation = true): Parser<string, C, D> {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
const
|
|
6
|
+
assert(!opener.flags.match(/[gm]/) && opener.sticky && !opener.source.startsWith('^'));
|
|
7
|
+
return failsafe(input => {
|
|
8
|
+
const { context } = input;
|
|
9
|
+
const { source, position } = context;
|
|
10
|
+
if (position === source.length) return;
|
|
11
|
+
opener.lastIndex = position;
|
|
12
|
+
const matches = opener.exec(source);
|
|
9
13
|
if (!matches) return;
|
|
10
|
-
assert(matches[0] === firstline(source));
|
|
14
|
+
assert(matches[0] === firstline(source, position));
|
|
11
15
|
const delim = matches[1];
|
|
12
16
|
assert(delim && delim === delim.trim());
|
|
13
17
|
if (matches[0].includes(delim, delim.length)) return;
|
|
14
|
-
|
|
18
|
+
context.position += matches[0].length;
|
|
15
19
|
// Prevent annoying parsing in editing.
|
|
16
|
-
|
|
20
|
+
const secondline = firstline(source, context.position);
|
|
21
|
+
if (isBlank(secondline) && firstline(source, context.position + secondline.length).trimEnd() !== delim) return;
|
|
17
22
|
let block = '';
|
|
18
23
|
let closer = '';
|
|
19
24
|
let overflow = '';
|
|
20
25
|
for (let count = 1; ; ++count) {
|
|
21
|
-
if (
|
|
22
|
-
const line = firstline(
|
|
26
|
+
if (context.position === source.length) break;
|
|
27
|
+
const line = firstline(source, context.position);
|
|
23
28
|
if ((closer || count > limit + 1) && isBlank(line)) break;
|
|
24
29
|
if(closer) {
|
|
25
30
|
overflow += line;
|
|
26
31
|
}
|
|
27
32
|
if (!closer && count <= limit + 1 && line.slice(0, delim.length) === delim && line.trimEnd() === delim) {
|
|
28
33
|
closer = line;
|
|
29
|
-
if (isBlank(firstline(
|
|
30
|
-
|
|
34
|
+
if (isBlank(firstline(source, context.position + line.length))) {
|
|
35
|
+
context.position += line.length;
|
|
31
36
|
break;
|
|
32
37
|
}
|
|
33
38
|
if (!separation) {
|
|
34
|
-
|
|
39
|
+
context.position += line.length;
|
|
35
40
|
break;
|
|
36
41
|
}
|
|
37
42
|
assert(!overflow);
|
|
@@ -40,8 +45,8 @@ export function fence<C extends Ctx, D extends Parser<unknown, C>[]>(opener: Reg
|
|
|
40
45
|
if (!overflow) {
|
|
41
46
|
block += line;
|
|
42
47
|
}
|
|
43
|
-
|
|
48
|
+
context.position += line.length;
|
|
44
49
|
}
|
|
45
|
-
return [push([block, overflow, closer], matches)
|
|
46
|
-
};
|
|
50
|
+
return [push([block, overflow, closer], matches)];
|
|
51
|
+
});
|
|
47
52
|
}
|
|
@@ -1,23 +1,26 @@
|
|
|
1
1
|
import { indent } from './indent';
|
|
2
|
+
import { input } from '../../data/parser';
|
|
2
3
|
import { inspect } from '../../../debug.test';
|
|
3
4
|
|
|
4
5
|
describe('Unit: combinator/indent', () => {
|
|
5
6
|
describe('indent', () => {
|
|
7
|
+
const { context: ctx } = input('', {});
|
|
8
|
+
|
|
6
9
|
it('valid', () => {
|
|
7
|
-
const parser = indent(({
|
|
8
|
-
assert.deepStrictEqual(inspect(parser(
|
|
9
|
-
assert.deepStrictEqual(inspect(parser(
|
|
10
|
-
assert.deepStrictEqual(inspect(parser(
|
|
11
|
-
assert.deepStrictEqual(inspect(parser(
|
|
12
|
-
assert.deepStrictEqual(inspect(parser(
|
|
13
|
-
assert.deepStrictEqual(inspect(parser(
|
|
14
|
-
assert.deepStrictEqual(inspect(parser(
|
|
15
|
-
assert.deepStrictEqual(inspect(parser(
|
|
16
|
-
assert.deepStrictEqual(inspect(parser(
|
|
17
|
-
assert.deepStrictEqual(inspect(parser(
|
|
18
|
-
assert.deepStrictEqual(inspect(parser(
|
|
19
|
-
assert.deepStrictEqual(inspect(parser(
|
|
20
|
-
assert.deepStrictEqual(inspect(parser(
|
|
10
|
+
const parser = indent(({ context }) => { context.position = context.source.length; return [[context.source]]; });
|
|
11
|
+
assert.deepStrictEqual(inspect(parser(input('', ctx)), ctx), undefined);
|
|
12
|
+
assert.deepStrictEqual(inspect(parser(input(' ', ctx)), ctx), undefined);
|
|
13
|
+
assert.deepStrictEqual(inspect(parser(input(' ', ctx)), ctx), undefined);
|
|
14
|
+
assert.deepStrictEqual(inspect(parser(input('a ', ctx)), ctx), undefined);
|
|
15
|
+
assert.deepStrictEqual(inspect(parser(input(' a\n', ctx)), ctx), [['a'], '']);
|
|
16
|
+
assert.deepStrictEqual(inspect(parser(input(' a ', ctx)), ctx), [['a '], '']);
|
|
17
|
+
assert.deepStrictEqual(inspect(parser(input(' a \n', ctx)), ctx), [['a '], '']);
|
|
18
|
+
assert.deepStrictEqual(inspect(parser(input(' a', ctx)), ctx), [['a'], '']);
|
|
19
|
+
assert.deepStrictEqual(inspect(parser(input(' a\n a', ctx)), ctx), [['a\na'], '']);
|
|
20
|
+
assert.deepStrictEqual(inspect(parser(input(' a\n a', ctx)), ctx), [['a\n a'], '']);
|
|
21
|
+
assert.deepStrictEqual(inspect(parser(input(' a\n a', ctx)), ctx), [['a'], ' a']);
|
|
22
|
+
assert.deepStrictEqual(inspect(parser(input(' \ta', ctx)), ctx), [['\ta'], '']);
|
|
23
|
+
assert.deepStrictEqual(inspect(parser(input('\ta', ctx)), ctx), [['a'], '']);
|
|
21
24
|
});
|
|
22
25
|
|
|
23
26
|
});
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Parser, eval,
|
|
1
|
+
import { Parser, 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';
|
|
@@ -13,27 +13,28 @@ export function indent<N>(opener: RegExp | Parser<N>, parser: Parser<N> | boolea
|
|
|
13
13
|
if (typeof opener === 'function') {
|
|
14
14
|
separation = parser as boolean;
|
|
15
15
|
parser = opener;
|
|
16
|
-
opener =
|
|
16
|
+
opener = /([ \t])\1*/y;
|
|
17
17
|
}
|
|
18
|
+
assert(!opener.flags.match(/[gm]/) && opener.sticky && !opener.source.startsWith('^'));
|
|
18
19
|
assert(parser);
|
|
19
|
-
return bind(block(match(
|
|
20
|
+
return failsafe(bind(block(match(
|
|
20
21
|
opener,
|
|
21
22
|
memoize(
|
|
22
23
|
([indent]) =>
|
|
23
|
-
some(line(open(indent, ({
|
|
24
|
+
some(line(open(indent, ({ context }) => {
|
|
25
|
+
const { source, position } = context;
|
|
26
|
+
context.position = source.length;
|
|
27
|
+
return [[source.slice(position)]];
|
|
28
|
+
}))),
|
|
24
29
|
([indent]) => indent.length * 2 + +(indent[0] === ' '), {})), separation),
|
|
25
|
-
(lines,
|
|
30
|
+
(lines, context) => {
|
|
26
31
|
assert(parser = parser as Parser<N>);
|
|
27
|
-
|
|
28
|
-
//const { backtracks } = context;
|
|
29
|
-
//context.backtracks = {};
|
|
30
|
-
const result = parser({ source: trimBlockEnd(lines.join('')), context });
|
|
31
|
-
//context.backtracks = backtracks;
|
|
32
|
+
const result = parser(subinput(trimBlockEnd(lines.join('')), context));
|
|
32
33
|
assert(result);
|
|
33
|
-
return result
|
|
34
|
-
? [eval(result)
|
|
34
|
+
return result
|
|
35
|
+
? [eval(result)]
|
|
35
36
|
: undefined;
|
|
36
|
-
});
|
|
37
|
+
}));
|
|
37
38
|
}
|
|
38
39
|
|
|
39
40
|
function trimBlockEnd(block: string): string {
|