@futpib/parser 1.0.4 → 1.0.6
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/.claude/settings.local.json +24 -0
- package/.github/workflows/main.yml +1 -0
- package/build/androidPackageParser.js +30 -32
- package/build/arbitraryDalvikBytecode.d.ts +3 -3
- package/build/arbitraryDalvikBytecode.js +33 -27
- package/build/arbitraryDalvikExecutable.js +55 -17
- package/build/arbitraryJava.d.ts +31 -0
- package/build/arbitraryJava.js +532 -0
- package/build/arbitraryJavaScript.d.ts +3 -0
- package/build/arbitraryJavaScript.js +263 -0
- package/build/arbitraryJavascript.d.ts +3 -0
- package/build/arbitraryJavascript.js +263 -0
- package/build/arbitraryZig.d.ts +3 -0
- package/build/arbitraryZig.js +240 -0
- package/build/arbitraryZipStream.d.ts +1 -1
- package/build/arrayParser.js +72 -13
- package/build/backsmali.d.ts +4 -3
- package/build/backsmali.js +26 -6
- package/build/bash.d.ts +6 -1
- package/build/bashParser.js +131 -90
- package/build/bashParser.test.js +162 -0
- package/build/bashParserEdgeCases.test.d.ts +1 -0
- package/build/bashParserEdgeCases.test.js +117 -0
- package/build/dalvikBytecodeParser/addressConversion.d.ts +110 -0
- package/build/dalvikBytecodeParser/addressConversion.js +334 -0
- package/build/dalvikBytecodeParser/formatParsers.d.ts +7 -6
- package/build/dalvikBytecodeParser/formatParsers.js +13 -14
- package/build/dalvikBytecodeParser.d.ts +60 -31
- package/build/dalvikBytecodeParser.js +92 -35
- package/build/dalvikBytecodeParser.test-d.d.ts +1 -0
- package/build/dalvikBytecodeParser.test-d.js +268 -0
- package/build/dalvikBytecodeUnparser/formatUnparsers.d.ts +9 -8
- package/build/dalvikBytecodeUnparser/formatUnparsers.js +13 -12
- package/build/dalvikBytecodeUnparser.d.ts +2 -2
- package/build/dalvikBytecodeUnparser.js +23 -23
- package/build/dalvikBytecodeUnparser.test.js +7 -7
- package/build/dalvikExecutable.d.ts +3 -3
- package/build/dalvikExecutable.test-d.d.ts +1 -0
- package/build/dalvikExecutable.test-d.js +59 -0
- package/build/dalvikExecutableParser/typedNumbers.d.ts +18 -0
- package/build/dalvikExecutableParser/typedNumbers.js +3 -0
- package/build/dalvikExecutableParser.d.ts +2 -1
- package/build/dalvikExecutableParser.js +96 -77
- package/build/dalvikExecutableParser.test.js +24 -3
- package/build/dalvikExecutableParserAgainstSmaliParser.test.js +3 -0
- package/build/dalvikExecutableUnparser/poolScanners.d.ts +2 -2
- package/build/dalvikExecutableUnparser/sectionUnparsers.d.ts +3 -3
- package/build/dalvikExecutableUnparser/sectionUnparsers.js +26 -11
- package/build/dalvikExecutableUnparser.d.ts +2 -2
- package/build/dalvikExecutableUnparser.test.js +2 -1
- package/build/disjunctionParser.d.ts +5 -3
- package/build/disjunctionParser.js +79 -17
- package/build/disjunctionParser.test-d.d.ts +1 -0
- package/build/disjunctionParser.test-d.js +72 -0
- package/build/elementSwitchParser.d.ts +4 -0
- package/build/{exactElementSwitchParser.js → elementSwitchParser.js} +3 -4
- package/build/elementSwitchParser.test-d.d.ts +1 -0
- package/build/elementSwitchParser.test-d.js +44 -0
- package/build/exactSequenceParser.d.ts +4 -2
- package/build/exactSequenceParser.test-d.d.ts +1 -0
- package/build/exactSequenceParser.test-d.js +36 -0
- package/build/fetchCid.js +2 -66
- package/build/index.d.ts +3 -2
- package/build/index.js +2 -1
- package/build/index.test.js +16 -1
- package/build/inputReader.d.ts +10 -0
- package/build/inputReader.js +36 -0
- package/build/java.d.ts +502 -0
- package/build/java.js +2 -0
- package/build/javaKeyStoreParser.js +14 -17
- package/build/javaParser.d.ts +51 -0
- package/build/javaParser.js +1538 -0
- package/build/javaParser.test.d.ts +1 -0
- package/build/javaParser.test.js +1287 -0
- package/build/javaScript.d.ts +35 -0
- package/build/javaScript.js +1 -0
- package/build/javaScriptParser.d.ts +9 -0
- package/build/javaScriptParser.js +34 -0
- package/build/javaScriptUnparser.d.ts +3 -0
- package/build/javaScriptUnparser.js +4 -0
- package/build/javaScriptUnparser.test.d.ts +1 -0
- package/build/javaScriptUnparser.test.js +24 -0
- package/build/javaUnparser.d.ts +2 -0
- package/build/javaUnparser.js +519 -0
- package/build/javaUnparser.test.d.ts +1 -0
- package/build/javaUnparser.test.js +24 -0
- package/build/javascript.d.ts +35 -0
- package/build/javascript.js +1 -0
- package/build/javascriptParser.d.ts +9 -0
- package/build/javascriptParser.js +34 -0
- package/build/javascriptUnparser.d.ts +3 -0
- package/build/javascriptUnparser.js +4 -0
- package/build/javascriptUnparser.test.d.ts +1 -0
- package/build/javascriptUnparser.test.js +24 -0
- package/build/jsonParser.js +2 -12
- package/build/lazyMessageError.d.ts +3 -0
- package/build/lookaheadParser.js +60 -3
- package/build/negativeLookaheadParser.js +70 -11
- package/build/nonEmptyArrayParser.js +72 -13
- package/build/objectParser.d.ts +12 -0
- package/build/objectParser.js +31 -0
- package/build/objectParser.test-d.d.ts +1 -0
- package/build/objectParser.test-d.js +112 -0
- package/build/objectParser.test.d.ts +1 -0
- package/build/objectParser.test.js +55 -0
- package/build/optionalParser.js +69 -10
- package/build/parser.d.ts +4 -0
- package/build/parser.js +3 -1
- package/build/parser.test.js +114 -1
- package/build/parserConsumedSequenceParser.js +66 -7
- package/build/parserContext.d.ts +6 -0
- package/build/parserContext.js +20 -11
- package/build/parserError.d.ts +119 -27
- package/build/parserError.js +16 -8
- package/build/regexpParser.js +33 -3
- package/build/regexpParser.test.js +31 -0
- package/build/regularExpressionParser.js +35 -15
- package/build/separatedArrayParser.js +73 -14
- package/build/separatedNonEmptyArrayParser.js +73 -14
- package/build/sliceBoundedParser.js +62 -5
- package/build/smaliParser.d.ts +7 -7
- package/build/smaliParser.js +185 -268
- package/build/smaliParser.test.js +58 -0
- package/build/stringEscapes.d.ts +5 -0
- package/build/stringEscapes.js +244 -0
- package/build/symbolicExpression.d.ts +29 -0
- package/build/symbolicExpression.js +1 -0
- package/build/symbolicExpressionParser.d.ts +4 -0
- package/build/symbolicExpressionParser.js +123 -0
- package/build/symbolicExpressionParser.test.d.ts +1 -0
- package/build/symbolicExpressionParser.test.js +289 -0
- package/build/terminatedArrayParser.js +113 -38
- package/build/terminatedArrayParser.test.js +4 -2
- package/build/tupleParser.d.ts +7 -15
- package/build/tupleParser.js +1 -0
- package/build/unionParser.d.ts +5 -3
- package/build/unionParser.js +7 -2
- package/build/unionParser.test-d.d.ts +1 -0
- package/build/unionParser.test-d.js +72 -0
- package/build/unionParser.test.js +10 -11
- package/build/zig.d.ts +280 -0
- package/build/zig.js +2 -0
- package/build/zigParser.d.ts +3 -0
- package/build/zigParser.js +1119 -0
- package/build/zigParser.test.d.ts +1 -0
- package/build/zigParser.test.js +1590 -0
- package/build/zigUnparser.d.ts +2 -0
- package/build/zigUnparser.js +460 -0
- package/build/zigUnparser.test.d.ts +1 -0
- package/build/zigUnparser.test.js +24 -0
- package/build/zipParser.js +19 -32
- package/build/zipUnparser.js +19 -7
- package/build/zipUnparser.test.js +1 -1
- package/node_modules-@types/s-expression/index.d.ts +5 -0
- package/package.json +24 -6
- package/src/androidPackageParser.ts +33 -60
- package/src/arbitraryDalvikBytecode.ts +39 -31
- package/src/arbitraryDalvikExecutable.ts +65 -20
- package/src/arbitraryJava.ts +804 -0
- package/src/arbitraryJavaScript.ts +410 -0
- package/src/arbitraryZig.ts +380 -0
- package/src/arrayParser.ts +1 -3
- package/src/backsmali.ts +35 -4
- package/src/bash.ts +8 -1
- package/src/bashParser.test.ts +258 -0
- package/src/bashParser.ts +180 -143
- package/src/dalvikBytecodeParser/addressConversion.ts +496 -0
- package/src/dalvikBytecodeParser/formatParsers.ts +19 -29
- package/src/dalvikBytecodeParser.test-d.ts +310 -0
- package/src/dalvikBytecodeParser.ts +194 -69
- package/src/dalvikBytecodeUnparser/formatUnparsers.ts +27 -26
- package/src/dalvikBytecodeUnparser.test.ts +7 -7
- package/src/dalvikBytecodeUnparser.ts +31 -30
- package/src/dalvikExecutable.test-d.ts +132 -0
- package/src/dalvikExecutable.ts +3 -3
- package/src/dalvikExecutableParser/typedNumbers.ts +11 -0
- package/src/dalvikExecutableParser.test.ts +37 -3
- package/src/dalvikExecutableParser.test.ts.md +163 -2
- package/src/dalvikExecutableParser.test.ts.snap +0 -0
- package/src/dalvikExecutableParser.ts +121 -139
- package/src/dalvikExecutableParserAgainstSmaliParser.test.ts +4 -0
- package/src/dalvikExecutableUnparser/poolScanners.ts +6 -6
- package/src/dalvikExecutableUnparser/sectionUnparsers.ts +38 -14
- package/src/dalvikExecutableUnparser.test.ts +3 -2
- package/src/dalvikExecutableUnparser.ts +4 -4
- package/src/disjunctionParser.test-d.ts +105 -0
- package/src/disjunctionParser.ts +18 -15
- package/src/elementSwitchParser.test-d.ts +74 -0
- package/src/elementSwitchParser.ts +51 -0
- package/src/exactSequenceParser.test-d.ts +43 -0
- package/src/exactSequenceParser.ts +13 -8
- package/src/fetchCid.ts +2 -76
- package/src/index.test.ts +22 -1
- package/src/index.ts +7 -1
- package/src/inputReader.ts +53 -0
- package/src/java.ts +708 -0
- package/src/javaKeyStoreParser.ts +18 -32
- package/src/javaParser.test.ts +1592 -0
- package/src/javaParser.ts +2640 -0
- package/src/javaScript.ts +36 -0
- package/src/javaScriptParser.ts +57 -0
- package/src/javaScriptUnparser.test.ts +37 -0
- package/src/javaScriptUnparser.ts +7 -0
- package/src/javaUnparser.test.ts +37 -0
- package/src/javaUnparser.ts +640 -0
- package/src/jsonParser.ts +6 -27
- package/src/lookaheadParser.ts +2 -6
- package/src/negativeLookaheadParser.ts +1 -3
- package/src/nonEmptyArrayParser.ts +1 -3
- package/src/objectParser.test-d.ts +152 -0
- package/src/objectParser.test.ts +71 -0
- package/src/objectParser.ts +69 -0
- package/src/optionalParser.ts +1 -3
- package/src/parser.test.ts +151 -4
- package/src/parser.ts +11 -1
- package/src/parserConsumedSequenceParser.ts +2 -4
- package/src/parserContext.ts +26 -11
- package/src/parserError.ts +17 -3
- package/src/regexpParser.test.ts +78 -0
- package/src/regexpParser.ts +35 -3
- package/src/regularExpressionParser.ts +36 -37
- package/src/separatedArrayParser.ts +1 -3
- package/src/separatedNonEmptyArrayParser.ts +1 -3
- package/src/sliceBoundedParser.test.ts +2 -2
- package/src/sliceBoundedParser.ts +15 -19
- package/src/smaliParser.test.ts +64 -0
- package/src/smaliParser.test.ts.md +12 -12
- package/src/smaliParser.test.ts.snap +0 -0
- package/src/smaliParser.ts +246 -534
- package/src/stringEscapes.ts +253 -0
- package/src/symbolicExpression.ts +17 -0
- package/src/symbolicExpressionParser.test.ts +466 -0
- package/src/symbolicExpressionParser.ts +190 -0
- package/src/terminatedArrayParser.test.ts +9 -6
- package/src/terminatedArrayParser.ts +25 -29
- package/src/tupleParser.ts +21 -18
- package/src/unionParser.test-d.ts +105 -0
- package/src/unionParser.test.ts +18 -17
- package/src/unionParser.ts +28 -16
- package/src/zig.ts +411 -0
- package/src/zigParser.test.ts +1693 -0
- package/src/zigParser.ts +1745 -0
- package/src/zigUnparser.test.ts +37 -0
- package/src/zigUnparser.ts +615 -0
- package/src/zipParser.ts +20 -56
- package/src/zipUnparser.test.ts +1 -1
- package/src/zipUnparser.ts +22 -7
- package/tsconfig.json +2 -2
- package/build/exactElementSwitchParser.d.ts +0 -3
- package/src/exactElementSwitchParser.ts +0 -41
|
@@ -19,7 +19,7 @@ export const createTerminatedArrayParserNaive = <ElementOutput, TerminatorOutput
|
|
|
19
19
|
getParserName(terminatorParser, 'anonymousTerminator'),
|
|
20
20
|
);
|
|
21
21
|
|
|
22
|
-
const elementOrTerminatorParser = createUnionParser
|
|
22
|
+
const elementOrTerminatorParser = createUnionParser([
|
|
23
23
|
elementParser,
|
|
24
24
|
promiseCompose(terminatorParser, terminatorValue => new Terminated(terminatorValue)),
|
|
25
25
|
]);
|
|
@@ -51,36 +51,36 @@ export const createTerminatedArrayParser = <ElementOutput, TerminatorOutput, Seq
|
|
|
51
51
|
const elements: ElementOutput[] = [];
|
|
52
52
|
|
|
53
53
|
while (true) {
|
|
54
|
-
|
|
54
|
+
using terminatorParserContext = parserContext.lookahead({
|
|
55
55
|
debugName: getParserName(terminatorParser, 'anonymousTerminator'),
|
|
56
56
|
});
|
|
57
57
|
|
|
58
58
|
try {
|
|
59
59
|
const terminatorValue = await terminatorParser(terminatorParserContext);
|
|
60
60
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
61
|
+
{
|
|
62
|
+
using elementParserContext = parserContext.lookahead({
|
|
63
|
+
debugName: getParserName(elementParser, 'anonymousElement'),
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
try {
|
|
67
|
+
await elementParser(elementParserContext);
|
|
68
|
+
|
|
69
|
+
parserImplementationInvariant(
|
|
70
|
+
false,
|
|
71
|
+
[
|
|
72
|
+
'Both element and terminator parsers matched.',
|
|
73
|
+
'Element parser: %s',
|
|
74
|
+
'Terminator parser: %s',
|
|
75
|
+
],
|
|
76
|
+
getParserName(elementParser, 'anonymousElement'),
|
|
77
|
+
getParserName(terminatorParser, 'anonymousTerminator'),
|
|
78
|
+
);
|
|
79
|
+
} catch (error) {
|
|
80
|
+
if (!(isParserParsingFailedError(error))) {
|
|
81
|
+
throw error;
|
|
82
|
+
}
|
|
81
83
|
}
|
|
82
|
-
} finally {
|
|
83
|
-
elementParserContext.dispose();
|
|
84
84
|
}
|
|
85
85
|
|
|
86
86
|
terminatorParserContext.unlookahead();
|
|
@@ -90,8 +90,6 @@ export const createTerminatedArrayParser = <ElementOutput, TerminatorOutput, Seq
|
|
|
90
90
|
if (!(isParserParsingFailedError(error))) {
|
|
91
91
|
throw error;
|
|
92
92
|
}
|
|
93
|
-
} finally {
|
|
94
|
-
terminatorParserContext.dispose();
|
|
95
93
|
}
|
|
96
94
|
|
|
97
95
|
const element = await elementParser(parserContext);
|
|
@@ -113,7 +111,7 @@ export const createTerminatedArrayParserUnsafe = <ElementOutput, TerminatorOutpu
|
|
|
113
111
|
const elements: ElementOutput[] = [];
|
|
114
112
|
|
|
115
113
|
while (true) {
|
|
116
|
-
|
|
114
|
+
using terminatorParserContext = parserContext.lookahead({
|
|
117
115
|
debugName: getParserName(terminatorParser, 'anonymousTerminator'),
|
|
118
116
|
});
|
|
119
117
|
|
|
@@ -127,8 +125,6 @@ export const createTerminatedArrayParserUnsafe = <ElementOutput, TerminatorOutpu
|
|
|
127
125
|
if (!(isParserParsingFailedError(error))) {
|
|
128
126
|
throw error;
|
|
129
127
|
}
|
|
130
|
-
} finally {
|
|
131
|
-
terminatorParserContext.dispose();
|
|
132
128
|
}
|
|
133
129
|
|
|
134
130
|
const element = await elementParser(parserContext);
|
package/src/tupleParser.ts
CHANGED
|
@@ -1,21 +1,24 @@
|
|
|
1
|
-
import { getParserName, setParserName, type Parser } from './parser.js';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
export function createTupleParser<
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
1
|
+
import { getParserName, setParserName, type Parser, type ParserOutput, type ParserSequence } from './parser.js';
|
|
2
|
+
|
|
3
|
+
// Map tuple of parsers to tuple of their outputs
|
|
4
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
5
|
+
type TupleParserOutput<Parsers extends readonly Parser<any, any, any>[]> = {
|
|
6
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
7
|
+
[K in keyof Parsers]: Parsers[K] extends Parser<any, any, any> ? ParserOutput<Parsers[K]> : never
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
// Infer Sequence from parser array
|
|
11
|
+
type InferSequenceFromParserArray<T extends readonly unknown[]> = ParserSequence<T[number]>;
|
|
12
|
+
|
|
13
|
+
export function createTupleParser<
|
|
14
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
15
|
+
const Parsers extends readonly Parser<any, any, any>[],
|
|
16
|
+
>(
|
|
17
|
+
parsers: Parsers,
|
|
18
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
19
|
+
): Parser<TupleParserOutput<Parsers>, InferSequenceFromParserArray<Parsers>, any> {
|
|
20
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
21
|
+
const tupleParser: Parser<any, any, any> = async parserContext => {
|
|
19
22
|
const values: unknown[] = [];
|
|
20
23
|
|
|
21
24
|
for (const parser of parsers) {
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { expectAssignable, expectType } from 'tsd';
|
|
2
|
+
import { createUnionParser } from './unionParser.js';
|
|
3
|
+
import { type Parser, type ParserOutput } from './parser.js';
|
|
4
|
+
import { createExactSequenceParser } from './exactSequenceParser.js';
|
|
5
|
+
import { createExactElementParser } from './exactElementParser.js';
|
|
6
|
+
import { createFixedLengthSequenceParser } from './fixedLengthSequenceParser.js';
|
|
7
|
+
|
|
8
|
+
// Test: basic union of string parsers - output inferred as string
|
|
9
|
+
{
|
|
10
|
+
const parser = createUnionParser([
|
|
11
|
+
createExactElementParser('a'),
|
|
12
|
+
createExactElementParser('b'),
|
|
13
|
+
]);
|
|
14
|
+
|
|
15
|
+
type Output = ParserOutput<typeof parser>;
|
|
16
|
+
|
|
17
|
+
expectAssignable<string>(null! as Output);
|
|
18
|
+
expectAssignable<Output>(null! as string);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// Test: union preserves literal types when parsers have explicit literal output types
|
|
22
|
+
{
|
|
23
|
+
const parserA: Parser<'a', string> = async () => 'a' as const;
|
|
24
|
+
const parserB: Parser<'b', string> = async () => 'b' as const;
|
|
25
|
+
|
|
26
|
+
const parser = createUnionParser([parserA, parserB]);
|
|
27
|
+
|
|
28
|
+
type Output = ParserOutput<typeof parser>;
|
|
29
|
+
|
|
30
|
+
// Output should be 'a' | 'b', not string
|
|
31
|
+
expectAssignable<'a' | 'b'>(null! as Output);
|
|
32
|
+
expectAssignable<Output>(null! as 'a' | 'b');
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Test: union of parsers with different output types
|
|
36
|
+
{
|
|
37
|
+
const stringParser: Parser<string, string> = createFixedLengthSequenceParser(3);
|
|
38
|
+
const numberParser: Parser<number, string> = () => 42;
|
|
39
|
+
|
|
40
|
+
const parser = createUnionParser([
|
|
41
|
+
stringParser,
|
|
42
|
+
numberParser,
|
|
43
|
+
]);
|
|
44
|
+
|
|
45
|
+
type Output = ParserOutput<typeof parser>;
|
|
46
|
+
|
|
47
|
+
// Output should be string | number
|
|
48
|
+
expectAssignable<string | number>(null! as Output);
|
|
49
|
+
expectAssignable<Output>(null! as string | number);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Test: nested unions
|
|
53
|
+
{
|
|
54
|
+
const inner = createUnionParser([
|
|
55
|
+
createExactElementParser('a'),
|
|
56
|
+
createExactElementParser('b'),
|
|
57
|
+
]);
|
|
58
|
+
|
|
59
|
+
const parser = createUnionParser([
|
|
60
|
+
inner,
|
|
61
|
+
createExactElementParser('c'),
|
|
62
|
+
]);
|
|
63
|
+
|
|
64
|
+
type Output = ParserOutput<typeof parser>;
|
|
65
|
+
|
|
66
|
+
expectAssignable<string>(null! as Output);
|
|
67
|
+
expectAssignable<Output>(null! as string);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Test: sequence type inferred from child parsers
|
|
71
|
+
{
|
|
72
|
+
const parser = createUnionParser([
|
|
73
|
+
createExactSequenceParser('hello'),
|
|
74
|
+
createExactSequenceParser('world'),
|
|
75
|
+
]);
|
|
76
|
+
|
|
77
|
+
type Output = ParserOutput<typeof parser>;
|
|
78
|
+
|
|
79
|
+
// Parser should be for string sequences, output is string (widened from literals)
|
|
80
|
+
expectAssignable<string>(null! as Output);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Test: single parser in union
|
|
84
|
+
{
|
|
85
|
+
const parser = createUnionParser([
|
|
86
|
+
createExactSequenceParser('only'),
|
|
87
|
+
]);
|
|
88
|
+
|
|
89
|
+
type Output = ParserOutput<typeof parser>;
|
|
90
|
+
|
|
91
|
+
// Output is string (widened from literal 'only')
|
|
92
|
+
expectAssignable<string>(null! as Output);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Test: union of object-producing parsers
|
|
96
|
+
{
|
|
97
|
+
const parser1: Parser<{ type: 'a'; value: number }, string> = async () => ({ type: 'a', value: 1 });
|
|
98
|
+
const parser2: Parser<{ type: 'b'; name: string }, string> = async () => ({ type: 'b', name: 'test' });
|
|
99
|
+
|
|
100
|
+
const parser = createUnionParser([parser1, parser2]);
|
|
101
|
+
|
|
102
|
+
type Output = ParserOutput<typeof parser>;
|
|
103
|
+
|
|
104
|
+
expectAssignable<{ type: 'a'; value: number } | { type: 'b'; name: string }>(null! as Output);
|
|
105
|
+
}
|
package/src/unionParser.test.ts
CHANGED
|
@@ -31,26 +31,27 @@ test('union of union of union', async t => {
|
|
|
31
31
|
});
|
|
32
32
|
|
|
33
33
|
test('sync and async child parsers', async t => {
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
-
parserContext.
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
);
|
|
34
|
+
const evenParser: Parser<string, string> = async parserContext => {
|
|
35
|
+
parserContext.invariant(
|
|
36
|
+
parserContext.position % 2 === 0,
|
|
37
|
+
'Expected an even position.',
|
|
38
|
+
);
|
|
40
39
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
parserContext => {
|
|
44
|
-
parserContext.invariant(
|
|
45
|
-
parserContext.position % 2 === 1,
|
|
46
|
-
'Expected an odd position.',
|
|
47
|
-
);
|
|
40
|
+
return parserContext.read(0);
|
|
41
|
+
};
|
|
48
42
|
|
|
49
|
-
|
|
43
|
+
const oddParser: Parser<string, string> = parserContext => {
|
|
44
|
+
parserContext.invariant(
|
|
45
|
+
parserContext.position % 2 === 1,
|
|
46
|
+
'Expected an odd position.',
|
|
47
|
+
);
|
|
50
48
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
49
|
+
parserContext.skip(1);
|
|
50
|
+
|
|
51
|
+
return String.fromCodePoint('A'.codePointAt(0)! + parserContext.position - 1);
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
const parser = createArrayParser(createUnionParser([evenParser, oddParser]));
|
|
54
55
|
|
|
55
56
|
const result = await runParser(parser, 'a?c?', stringParserInputCompanion, {
|
|
56
57
|
errorJoinMode: 'all',
|
package/src/unionParser.ts
CHANGED
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
import { allSettledStream } from './allSettledStream.js';
|
|
2
|
-
import { getParserName, setParserName, type Parser } from './parser.js';
|
|
2
|
+
import { getParserName, setParserName, type Parser, type ParserOutput, type ParserSequence } from './parser.js';
|
|
3
3
|
import { type ParserContext } from './parserContext.js';
|
|
4
4
|
import { isParserParsingFailedError, ParserParsingFailedError } from './parserError.js';
|
|
5
5
|
import { parserImplementationInvariant } from './parserImplementationInvariant.js';
|
|
6
|
-
|
|
6
|
+
|
|
7
|
+
// Union all output types from an array of parsers
|
|
8
|
+
type UnionParserOutput<Parsers extends readonly unknown[]> = ParserOutput<Parsers[number]>;
|
|
9
|
+
|
|
10
|
+
// Infer Sequence from parser array
|
|
11
|
+
type InferSequenceFromParserArray<T extends readonly unknown[]> = ParserSequence<T[number]>;
|
|
7
12
|
|
|
8
13
|
const bigintReplacer = (_key: string, value: unknown) => {
|
|
9
14
|
if (typeof value === 'bigint') {
|
|
@@ -13,24 +18,28 @@ const bigintReplacer = (_key: string, value: unknown) => {
|
|
|
13
18
|
return value;
|
|
14
19
|
};
|
|
15
20
|
|
|
16
|
-
export
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
Element = DeriveSequenceElement<Sequence>,
|
|
21
|
+
export function createUnionParser<
|
|
22
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
23
|
+
const Parsers extends readonly Parser<any, any, any>[],
|
|
20
24
|
>(
|
|
21
|
-
childParsers:
|
|
22
|
-
|
|
25
|
+
childParsers: Parsers,
|
|
26
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
27
|
+
): Parser<UnionParserOutput<Parsers>, InferSequenceFromParserArray<Parsers>> {
|
|
23
28
|
parserImplementationInvariant(childParsers.length > 0, 'Union parser must have at least one child parser.');
|
|
24
29
|
|
|
25
30
|
type TaskContext = {
|
|
26
|
-
|
|
27
|
-
|
|
31
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
32
|
+
childParser: Parser<any, any, any>;
|
|
33
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
34
|
+
childParserContext: ParserContext<any, any>;
|
|
28
35
|
};
|
|
29
36
|
|
|
30
|
-
|
|
37
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
38
|
+
const unionParser: Parser<any, any, any> = async parserContext => {
|
|
31
39
|
let runningChildParserContexts: TaskContext[] = [];
|
|
32
40
|
|
|
33
|
-
|
|
41
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
42
|
+
const createChildParserTask = (childParser: Parser<any, any, any>) => {
|
|
34
43
|
const childParserContext = parserContext.lookahead({
|
|
35
44
|
debugName: getParserName(childParser, 'anonymousUnionChild'),
|
|
36
45
|
});
|
|
@@ -42,7 +51,8 @@ export const createUnionParser = <
|
|
|
42
51
|
|
|
43
52
|
runningChildParserContexts.push(context);
|
|
44
53
|
|
|
45
|
-
|
|
54
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
55
|
+
const getChildParserPromise = (async () => childParser(childParserContext) as Promise<any>);
|
|
46
56
|
|
|
47
57
|
const promise = getChildParserPromise();
|
|
48
58
|
|
|
@@ -52,10 +62,12 @@ export const createUnionParser = <
|
|
|
52
62
|
};
|
|
53
63
|
};
|
|
54
64
|
|
|
55
|
-
|
|
65
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
66
|
+
const childParserResults = allSettledStream<any, TaskContext>(childParsers.map(createChildParserTask));
|
|
56
67
|
|
|
57
68
|
const parserParsingFailedErrors: ParserParsingFailedError[] = [];
|
|
58
|
-
|
|
69
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
70
|
+
const successfulParserOutputs: any[] = [];
|
|
59
71
|
const successfulTaskContexts: TaskContext[] = [];
|
|
60
72
|
let didUnlookahead = false;
|
|
61
73
|
|
|
@@ -127,4 +139,4 @@ export const createUnionParser = <
|
|
|
127
139
|
].join('');
|
|
128
140
|
|
|
129
141
|
return setParserName(unionParser, name);
|
|
130
|
-
}
|
|
142
|
+
}
|