tarsec 0.0.15 → 0.0.16
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/dist/combinators.d.ts +17 -1
- package/dist/combinators.js +48 -1
- package/dist/parsers.d.ts +67 -0
- package/dist/parsers.js +93 -0
- package/dist/types.d.ts +42 -14
- package/dist/types.js +17 -0
- package/package.json +2 -1
package/dist/combinators.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { CaptureParser, GeneralParser, InferManyReturnType, MergedCaptures, MergedResults, Parser, PickParserType, PlainObject } from "./types.js";
|
|
1
|
+
import { CaptureParser, GeneralParser, InferManyReturnType, MergedCaptures, MergedResults, Parser, ParserResult, PickParserType, PickParserTypeArray, PlainObject } from "./types.js";
|
|
2
2
|
/**
|
|
3
3
|
* Takes a parser and runs it zero or more times, returning the results as an array.
|
|
4
4
|
* If the parser is a capture parser, it returns the captures as an array in this form:
|
|
@@ -260,3 +260,19 @@ export declare function seqC<const T extends readonly GeneralParser<any, any>[]>
|
|
|
260
260
|
* @returns - true if the parser matches the input and consumes all input, false otherwise
|
|
261
261
|
*/
|
|
262
262
|
export declare function match(input: string, parser: GeneralParser<any, any>): boolean;
|
|
263
|
+
export declare function ifElse<const IF extends GeneralParser<any, any, I>, const ELSE extends GeneralParser<any, any, I>, I = string>(condition: boolean, ifParser: IF, elseParser: ELSE): IF | ELSE;
|
|
264
|
+
/**
|
|
265
|
+
* Apply multiple parsers to the same input and collect all the results.
|
|
266
|
+
* Consumes no input.
|
|
267
|
+
*
|
|
268
|
+
* @param parsers - parsers to try
|
|
269
|
+
* @returns
|
|
270
|
+
*/
|
|
271
|
+
export declare function manyParsers<const T extends readonly GeneralParser<any, any>[]>(...parsers: T): Parser<ParserResult<MergedResults<T>>[]>;
|
|
272
|
+
/**
|
|
273
|
+
* Runs all the given parsers. If they all succeed, returns their results as an array.
|
|
274
|
+
* Otherwise fails. Consumes no input.
|
|
275
|
+
* @param parsers - parsers to try
|
|
276
|
+
* @returns - An array of results, or a failure.
|
|
277
|
+
*/
|
|
278
|
+
export declare function and<const I, const T extends readonly GeneralParser<any, any>[]>(...parsers: T): PickParserTypeArray<T, I>;
|
package/dist/combinators.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { within } from "./parsers/within.js";
|
|
2
2
|
import { trace } from "./trace.js";
|
|
3
|
-
import { captureSuccess, createTree, failure, isCaptureResult, success, } from "./types.js";
|
|
3
|
+
import { captureSuccess, createTree, failure, isCaptureResult, isSuccess, success, } from "./types.js";
|
|
4
4
|
import { escape, findAncestorWithNextParser, popMany } from "./utils.js";
|
|
5
5
|
/**
|
|
6
6
|
* Takes a parser and runs it zero or more times, returning the results as an array.
|
|
@@ -615,3 +615,50 @@ export function match(input, parser) {
|
|
|
615
615
|
const result = parser(input);
|
|
616
616
|
return result.success && result.rest === "";
|
|
617
617
|
}
|
|
618
|
+
export function ifElse(condition, ifParser, elseParser) {
|
|
619
|
+
return trace(`ifElse(${escape(condition)})`, (input) => {
|
|
620
|
+
if (condition) {
|
|
621
|
+
return ifParser(input);
|
|
622
|
+
}
|
|
623
|
+
return elseParser(input);
|
|
624
|
+
});
|
|
625
|
+
}
|
|
626
|
+
/**
|
|
627
|
+
* Apply multiple parsers to the same input and collect all the results.
|
|
628
|
+
* Consumes no input.
|
|
629
|
+
*
|
|
630
|
+
* @param parsers - parsers to try
|
|
631
|
+
* @returns
|
|
632
|
+
*/
|
|
633
|
+
export function manyParsers(...parsers) {
|
|
634
|
+
return trace(`manyParsers()`, (input) => {
|
|
635
|
+
const results = [];
|
|
636
|
+
for (let i = 0; i < parsers.length; i++) {
|
|
637
|
+
let result = parsers[i](input);
|
|
638
|
+
results.push(result);
|
|
639
|
+
}
|
|
640
|
+
if (results.some(isSuccess)) {
|
|
641
|
+
return success(results, input);
|
|
642
|
+
}
|
|
643
|
+
return failure("no parsers succeeded", input);
|
|
644
|
+
});
|
|
645
|
+
}
|
|
646
|
+
/**
|
|
647
|
+
* Runs all the given parsers. If they all succeed, returns their results as an array.
|
|
648
|
+
* Otherwise fails. Consumes no input.
|
|
649
|
+
* @param parsers - parsers to try
|
|
650
|
+
* @returns - An array of results, or a failure.
|
|
651
|
+
*/
|
|
652
|
+
export function and(...parsers) {
|
|
653
|
+
return trace(`and()`, (input) => {
|
|
654
|
+
const results = manyParsers(...parsers)(input);
|
|
655
|
+
if (results.success) {
|
|
656
|
+
const successes = results.result.filter(isSuccess);
|
|
657
|
+
if (successes.length === results.result.length) {
|
|
658
|
+
return success(results.result.map((r) => r.result), input);
|
|
659
|
+
}
|
|
660
|
+
return failure("not all parsers succeeded", input);
|
|
661
|
+
}
|
|
662
|
+
return results;
|
|
663
|
+
});
|
|
664
|
+
}
|
package/dist/parsers.d.ts
CHANGED
|
@@ -143,3 +143,70 @@ export declare function captureRegex<const T extends string[]>(str: string | Reg
|
|
|
143
143
|
* @returns
|
|
144
144
|
*/
|
|
145
145
|
export declare function set<const K extends string, const V>(key: K, value: V): CaptureParser<null, Record<K, V>>;
|
|
146
|
+
/**
|
|
147
|
+
* A parser that always succeeds with the given value.
|
|
148
|
+
* @param value - value to succeed with
|
|
149
|
+
* @returns value
|
|
150
|
+
*/
|
|
151
|
+
export declare function succeed<T, I = string>(value: T): Parser<T>;
|
|
152
|
+
/**
|
|
153
|
+
* A parser that always fails with the given message.
|
|
154
|
+
* @param message - message to fail with
|
|
155
|
+
* @returns failure
|
|
156
|
+
*/
|
|
157
|
+
export declare function fail<I = string>(message: string): Parser<never>;
|
|
158
|
+
/**
|
|
159
|
+
* Takes a string. Succeeds if the given input contains that string.
|
|
160
|
+
* Consumes no input.
|
|
161
|
+
*
|
|
162
|
+
* @param substr - substring to find
|
|
163
|
+
* @returns - parser that succeeds if the given input contains that string
|
|
164
|
+
*/
|
|
165
|
+
export declare function includes<const S extends string>(substr: S): Parser<S>;
|
|
166
|
+
/**
|
|
167
|
+
* Like `includes`, but case-insensitive.
|
|
168
|
+
*
|
|
169
|
+
* @param substr - substring to find
|
|
170
|
+
* @returns - parser that succeeds if the given input contains that string
|
|
171
|
+
*/
|
|
172
|
+
export declare function iIncludes<const S extends string>(substr: S): Parser<S>;
|
|
173
|
+
/**
|
|
174
|
+
* Returns a parser that takes some input, runs the transformer function over it,
|
|
175
|
+
* and returns the result as `rest`, so it can be chained to another parser.
|
|
176
|
+
* It always returns null as its result. Always succeeds.
|
|
177
|
+
*
|
|
178
|
+
* `shape` is useful for modifying the user's input before running parsers over it.
|
|
179
|
+
* For example, here is a parser that takes in a chapter
|
|
180
|
+
* and checks that its title starts with "Once upon a time"
|
|
181
|
+
*
|
|
182
|
+
* ```ts
|
|
183
|
+
* const parser = seqR(
|
|
184
|
+
* shape((c: Chapter) => c.title),
|
|
185
|
+
* istr("Once upon a time"),
|
|
186
|
+
* )
|
|
187
|
+
* );
|
|
188
|
+
* ```
|
|
189
|
+
*
|
|
190
|
+
* Now you might be thinking, why not just use the chapter's title as input?
|
|
191
|
+
* `shape` is most useful when you want to parse multiple properties.
|
|
192
|
+
*
|
|
193
|
+
* ```ts
|
|
194
|
+
* const titleParser = seqR(
|
|
195
|
+
* shape((c: Chapter) => c.title),
|
|
196
|
+
* istr("Once upon a time"),
|
|
197
|
+
* );
|
|
198
|
+
*
|
|
199
|
+
* const textParser = seqR(
|
|
200
|
+
* shape((c: Chapter) => c.text),
|
|
201
|
+
* istr("There was a princess"),
|
|
202
|
+
* );
|
|
203
|
+
*
|
|
204
|
+
* const parser = and(titleParser, textParser);
|
|
205
|
+
* ```
|
|
206
|
+
*
|
|
207
|
+
* `parser` now takes a chapter as input and parses its title and text correctly.
|
|
208
|
+
*
|
|
209
|
+
* @param transformer - function to transform the input
|
|
210
|
+
* @returns a parser that takes some input and runs the transformer function over it
|
|
211
|
+
*/
|
|
212
|
+
export declare function shape<const X, const I>(transformer: (item: X) => I): Parser<null>;
|
package/dist/parsers.js
CHANGED
|
@@ -246,3 +246,96 @@ export function set(key, value) {
|
|
|
246
246
|
return captureSuccess(null, input, { [key]: value });
|
|
247
247
|
});
|
|
248
248
|
}
|
|
249
|
+
/**
|
|
250
|
+
* A parser that always succeeds with the given value.
|
|
251
|
+
* @param value - value to succeed with
|
|
252
|
+
* @returns value
|
|
253
|
+
*/
|
|
254
|
+
export function succeed(value) {
|
|
255
|
+
return trace(`succeed(${value})`, (input) => {
|
|
256
|
+
return success(value, input);
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
/**
|
|
260
|
+
* A parser that always fails with the given message.
|
|
261
|
+
* @param message - message to fail with
|
|
262
|
+
* @returns failure
|
|
263
|
+
*/
|
|
264
|
+
export function fail(message) {
|
|
265
|
+
return trace(`fail(${message})`, (input) => {
|
|
266
|
+
return failure(message, input);
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
/**
|
|
270
|
+
* Takes a string. Succeeds if the given input contains that string.
|
|
271
|
+
* Consumes no input.
|
|
272
|
+
*
|
|
273
|
+
* @param substr - substring to find
|
|
274
|
+
* @returns - parser that succeeds if the given input contains that string
|
|
275
|
+
*/
|
|
276
|
+
export function includes(substr) {
|
|
277
|
+
return trace(`includes(${substr})`, (input) => {
|
|
278
|
+
if (input.includes(substr)) {
|
|
279
|
+
return success(substr, input);
|
|
280
|
+
}
|
|
281
|
+
return failure(`expected ${escape(input)} to include ${escape(substr)}`, input);
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
/**
|
|
285
|
+
* Like `includes`, but case-insensitive.
|
|
286
|
+
*
|
|
287
|
+
* @param substr - substring to find
|
|
288
|
+
* @returns - parser that succeeds if the given input contains that string
|
|
289
|
+
*/
|
|
290
|
+
export function iIncludes(substr) {
|
|
291
|
+
return trace(`iIncludes(${substr})`, (input) => {
|
|
292
|
+
if (input.toLowerCase().includes(substr.toLowerCase())) {
|
|
293
|
+
return success(substr, input);
|
|
294
|
+
}
|
|
295
|
+
return failure(`expected "${input}" to include "${substr}" (case-insensitive)`, input);
|
|
296
|
+
});
|
|
297
|
+
}
|
|
298
|
+
/**
|
|
299
|
+
* Returns a parser that takes some input, runs the transformer function over it,
|
|
300
|
+
* and returns the result as `rest`, so it can be chained to another parser.
|
|
301
|
+
* It always returns null as its result. Always succeeds.
|
|
302
|
+
*
|
|
303
|
+
* `shape` is useful for modifying the user's input before running parsers over it.
|
|
304
|
+
* For example, here is a parser that takes in a chapter
|
|
305
|
+
* and checks that its title starts with "Once upon a time"
|
|
306
|
+
*
|
|
307
|
+
* ```ts
|
|
308
|
+
* const parser = seqR(
|
|
309
|
+
* shape((c: Chapter) => c.title),
|
|
310
|
+
* istr("Once upon a time"),
|
|
311
|
+
* )
|
|
312
|
+
* );
|
|
313
|
+
* ```
|
|
314
|
+
*
|
|
315
|
+
* Now you might be thinking, why not just use the chapter's title as input?
|
|
316
|
+
* `shape` is most useful when you want to parse multiple properties.
|
|
317
|
+
*
|
|
318
|
+
* ```ts
|
|
319
|
+
* const titleParser = seqR(
|
|
320
|
+
* shape((c: Chapter) => c.title),
|
|
321
|
+
* istr("Once upon a time"),
|
|
322
|
+
* );
|
|
323
|
+
*
|
|
324
|
+
* const textParser = seqR(
|
|
325
|
+
* shape((c: Chapter) => c.text),
|
|
326
|
+
* istr("There was a princess"),
|
|
327
|
+
* );
|
|
328
|
+
*
|
|
329
|
+
* const parser = and(titleParser, textParser);
|
|
330
|
+
* ```
|
|
331
|
+
*
|
|
332
|
+
* `parser` now takes a chapter as input and parses its title and text correctly.
|
|
333
|
+
*
|
|
334
|
+
* @param transformer - function to transform the input
|
|
335
|
+
* @returns a parser that takes some input and runs the transformer function over it
|
|
336
|
+
*/
|
|
337
|
+
export function shape(transformer) {
|
|
338
|
+
return trace(`shape()`, (_input) => {
|
|
339
|
+
return success(null, transformer(_input));
|
|
340
|
+
});
|
|
341
|
+
}
|
package/dist/types.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
/** A generic object type. */
|
|
2
2
|
export type PlainObject = Record<string, unknown>;
|
|
3
3
|
/** Represents a parse success with no captures. */
|
|
4
|
-
export type ParserSuccess<T> = {
|
|
4
|
+
export type ParserSuccess<T, R = string> = {
|
|
5
5
|
success: true;
|
|
6
6
|
result: T;
|
|
7
|
-
rest:
|
|
7
|
+
rest: R;
|
|
8
8
|
nextParser?: Parser<any>;
|
|
9
9
|
};
|
|
10
10
|
/** Represents a parse success with captures. Notice nextParser is also a CaptureParser. */
|
|
@@ -16,27 +16,47 @@ export type CaptureParserSuccess<T, C extends PlainObject> = {
|
|
|
16
16
|
nextParser?: CaptureParser<any, any>;
|
|
17
17
|
};
|
|
18
18
|
/** Represents a parse failure. */
|
|
19
|
-
export type ParserFailure = {
|
|
19
|
+
export type ParserFailure<R = string> = {
|
|
20
20
|
success: false;
|
|
21
|
-
rest:
|
|
21
|
+
rest: R;
|
|
22
22
|
message: string;
|
|
23
23
|
};
|
|
24
|
-
export type ParserResult<T> = ParserSuccess<T> | ParserFailure
|
|
25
|
-
export type CaptureParserResult<T, C extends PlainObject> = CaptureParserSuccess<T, C> | ParserFailure
|
|
26
|
-
/** A parser is any function that takes
|
|
27
|
-
export type Parser<T> = (input:
|
|
28
|
-
/** A
|
|
24
|
+
export type ParserResult<T, R = string> = ParserSuccess<T, R> | ParserFailure<R>;
|
|
25
|
+
export type CaptureParserResult<T, C extends PlainObject, R = string> = CaptureParserSuccess<T, C> | ParserFailure<R>;
|
|
26
|
+
/** A parser is any function that takes an arg and returns a ParserResult. */
|
|
27
|
+
export type Parser<T, I = string> = (input: I) => ParserResult<T>;
|
|
28
|
+
/** A string parser is any function that takes a string and returns a ParserResult. */
|
|
29
|
+
export type StringParser<T> = (input: string) => ParserResult<T>;
|
|
30
|
+
/** A capture parser is any function that takes an arg and returns a CaptureParserResult.
|
|
29
31
|
* A CaptureParserResult is the same as a ParserResult, except it also includes captures,
|
|
30
32
|
* i.e. matches selected using `capture`. */
|
|
31
|
-
export type CaptureParser<T, C extends PlainObject> = (input:
|
|
32
|
-
|
|
33
|
+
export type CaptureParser<T, C extends PlainObject, I = string> = (input: I) => CaptureParserResult<T, C>;
|
|
34
|
+
/** A string capture parser is any function that takes a string and returns a CaptureParserResult. */
|
|
35
|
+
export type StringCaptureParser<T, C extends PlainObject> = (input: string) => CaptureParserResult<T, C>;
|
|
36
|
+
export type GeneralParser<T, C extends PlainObject, I = string> = Parser<T, I> | CaptureParser<T, C, I>;
|
|
37
|
+
export type GeneralStringParser<T, C extends PlainObject> = Parser<T, string> | CaptureParser<T, C, string>;
|
|
33
38
|
export declare function isCaptureResult<T, C extends PlainObject>(result: ParserResult<T>): result is CaptureParserSuccess<T, C>;
|
|
39
|
+
/**
|
|
40
|
+
* This typed function is helpful in filtering out the successes
|
|
41
|
+
* from an array of results while preserving type information. For example:
|
|
42
|
+
*
|
|
43
|
+
* ```
|
|
44
|
+
* // type is ParserSuccess[]
|
|
45
|
+
* results.filter(isSuccess);
|
|
46
|
+
*
|
|
47
|
+
* // type is ParserResult[]
|
|
48
|
+
* results.filter(r => r.success);
|
|
49
|
+
* ```
|
|
50
|
+
* @param result - a parser result
|
|
51
|
+
* @returns - true if the result is a success, otherwise false
|
|
52
|
+
*/
|
|
53
|
+
export declare function isSuccess<T, R = string>(result: ParserResult<T, R>): result is ParserSuccess<T, R>;
|
|
34
54
|
/** Convenience function to return a ParserSuccess */
|
|
35
|
-
export declare function success<T>(result: T, rest:
|
|
55
|
+
export declare function success<T, R = string>(result: T, rest: R): ParserSuccess<T, R>;
|
|
36
56
|
/** Convenience function to return a CaptureParserSuccess */
|
|
37
57
|
export declare function captureSuccess<T, C extends PlainObject>(result: T, rest: string, captures: C): CaptureParserSuccess<T, C>;
|
|
38
58
|
/** Convenience function to return a ParserFailure */
|
|
39
|
-
export declare function failure(message: string, rest:
|
|
59
|
+
export declare function failure<R = string>(message: string, rest: R): ParserFailure<R>;
|
|
40
60
|
/** Prettify an intersected type, to make it easier to read. */
|
|
41
61
|
export type Prettify<T> = {
|
|
42
62
|
[K in keyof T]: T[K];
|
|
@@ -71,7 +91,15 @@ export type HasCaptureParsers<T extends readonly GeneralParser<any, any>[]> = Ex
|
|
|
71
91
|
* the result and capture types. This is useful for a combinator like `or`
|
|
72
92
|
* which is not able to infer its return type correctly.
|
|
73
93
|
*/
|
|
74
|
-
export type PickParserType<T extends readonly GeneralParser<any, any>[]
|
|
94
|
+
export type PickParserType<T extends readonly GeneralParser<any, any>[], I = string> = I extends string ? PickParserTypeString<T> : PickParserTypeGeneral<T, I>;
|
|
95
|
+
/** split out to make types more readable */
|
|
96
|
+
export type PickParserTypeGeneral<T extends readonly GeneralParser<any, any>[], I = string> = HasCaptureParsers<T> extends true ? CaptureParser<MergedResults<T>, UnionOfCaptures<T>, I> : Parser<MergedResults<T>, I>;
|
|
97
|
+
export type PickParserTypeString<T extends readonly GeneralParser<any, any>[]> = HasCaptureParsers<T> extends true ? StringCaptureParser<MergedResults<T>, UnionOfCaptures<T>> : StringParser<MergedResults<T>>;
|
|
98
|
+
/**
|
|
99
|
+
* Like `PickParserType`, but the result is an array of the result types,
|
|
100
|
+
* instead of just a union.
|
|
101
|
+
*/
|
|
102
|
+
export type PickParserTypeArray<T extends readonly GeneralParser<any, any>[], I = string> = HasCaptureParsers<T> extends true ? CaptureParser<MergedResults<T>, UnionOfCaptures<T>, I> : Parser<MergedResults<T>[], I>;
|
|
75
103
|
/** This is used to generate a return type for the `many` and `many1` combinators.
|
|
76
104
|
* Given a parser we want to apply `many` to. Suppose its type is `Parser<string>`.
|
|
77
105
|
* This will return `Parser<string[]>` as the return type.
|
package/dist/types.js
CHANGED
|
@@ -1,6 +1,23 @@
|
|
|
1
1
|
export function isCaptureResult(result) {
|
|
2
2
|
return "captures" in result;
|
|
3
3
|
}
|
|
4
|
+
/**
|
|
5
|
+
* This typed function is helpful in filtering out the successes
|
|
6
|
+
* from an array of results while preserving type information. For example:
|
|
7
|
+
*
|
|
8
|
+
* ```
|
|
9
|
+
* // type is ParserSuccess[]
|
|
10
|
+
* results.filter(isSuccess);
|
|
11
|
+
*
|
|
12
|
+
* // type is ParserResult[]
|
|
13
|
+
* results.filter(r => r.success);
|
|
14
|
+
* ```
|
|
15
|
+
* @param result - a parser result
|
|
16
|
+
* @returns - true if the result is a success, otherwise false
|
|
17
|
+
*/
|
|
18
|
+
export function isSuccess(result) {
|
|
19
|
+
return result.success;
|
|
20
|
+
}
|
|
4
21
|
/** Convenience function to return a ParserSuccess */
|
|
5
22
|
export function success(result, rest) {
|
|
6
23
|
return { success: true, result, rest };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tarsec",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.16",
|
|
4
4
|
"description": "A parser combinator library for TypeScript, inspired by Parsec.",
|
|
5
5
|
"homepage": "https://github.com/egonSchiele/tarsec",
|
|
6
6
|
"scripts": {
|
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
"require": "./dist/index.js"
|
|
22
22
|
}
|
|
23
23
|
},
|
|
24
|
+
"type": "module",
|
|
24
25
|
"types": "./dist/index.d.ts",
|
|
25
26
|
"keywords": ["parser", "parser combinator", "parsec"],
|
|
26
27
|
"author": "",
|