tarsec 0.0.13 → 0.0.15

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/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export * from "./parsers";
2
- export * from "./combinators";
3
- export * from "./trace";
4
- export * from "./types";
1
+ export * from "./parsers.js";
2
+ export * from "./combinators.js";
3
+ export * from "./trace.js";
4
+ export * from "./types.js";
package/dist/index.js CHANGED
@@ -1,30 +1,4 @@
1
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
2
- if (k2 === undefined) k2 = k;
3
- var desc = Object.getOwnPropertyDescriptor(m, k);
4
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
5
- desc = { enumerable: true, get: function() { return m[k]; } };
6
- }
7
- Object.defineProperty(o, k2, desc);
8
- }) : (function(o, m, k, k2) {
9
- if (k2 === undefined) k2 = k;
10
- o[k2] = m[k];
11
- }));
12
- var __exportStar = (this && this.__exportStar) || function(m, exports) {
13
- for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
14
- };
15
- (function (factory) {
16
- if (typeof module === "object" && typeof module.exports === "object") {
17
- var v = factory(require, exports);
18
- if (v !== undefined) module.exports = v;
19
- }
20
- else if (typeof define === "function" && define.amd) {
21
- define(["require", "exports", "./parsers", "./combinators", "./trace", "./types"], factory);
22
- }
23
- })(function (require, exports) {
24
- "use strict";
25
- Object.defineProperty(exports, "__esModule", { value: true });
26
- __exportStar(require("./parsers"), exports);
27
- __exportStar(require("./combinators"), exports);
28
- __exportStar(require("./trace"), exports);
29
- __exportStar(require("./types"), exports);
30
- });
1
+ export * from "./parsers.js";
2
+ export * from "./combinators.js";
3
+ export * from "./trace.js";
4
+ export * from "./types.js";
@@ -1,2 +1,2 @@
1
- import { WithinResult, Parser } from "../types";
1
+ import { WithinResult, Parser } from "../types.js";
2
2
  export declare function within(parser: Parser<string>): Parser<WithinResult[]>;
@@ -1,51 +1,37 @@
1
- (function (factory) {
2
- if (typeof module === "object" && typeof module.exports === "object") {
3
- var v = factory(require, exports);
4
- if (v !== undefined) module.exports = v;
5
- }
6
- else if (typeof define === "function" && define.amd) {
7
- define(["require", "exports", "../trace", "../types"], factory);
8
- }
9
- })(function (require, exports) {
10
- "use strict";
11
- Object.defineProperty(exports, "__esModule", { value: true });
12
- exports.within = void 0;
13
- const trace_1 = require("../trace");
14
- const types_1 = require("../types");
15
- function within(parser) {
16
- return (0, trace_1.trace)("within", (input) => {
17
- let start = 0;
18
- let current = 0;
19
- const results = [];
20
- while (current < input.length) {
21
- const parsed = parser(input.slice(current));
22
- if (parsed.success) {
23
- const unmatchedValue = input.slice(start, current);
24
- if (unmatchedValue.length > 0) {
25
- results.push({
26
- type: "unmatched",
27
- value: unmatchedValue,
28
- });
29
- }
1
+ import { trace } from "../trace.js";
2
+ import { success } from "../types.js";
3
+ export function within(parser) {
4
+ return trace("within", (input) => {
5
+ let start = 0;
6
+ let current = 0;
7
+ const results = [];
8
+ while (current < input.length) {
9
+ const parsed = parser(input.slice(current));
10
+ if (parsed.success) {
11
+ const unmatchedValue = input.slice(start, current);
12
+ if (unmatchedValue.length > 0) {
30
13
  results.push({
31
- type: "matched",
32
- value: parsed.result,
14
+ type: "unmatched",
15
+ value: unmatchedValue,
33
16
  });
34
- current += parsed.result.length;
35
- start = current;
36
17
  }
37
- else {
38
- current += 1;
39
- }
40
- }
41
- if (start < current) {
42
18
  results.push({
43
- type: "unmatched",
44
- value: input.slice(start, current),
19
+ type: "matched",
20
+ value: parsed.result,
45
21
  });
22
+ current += parsed.result.length;
23
+ start = current;
24
+ }
25
+ else {
26
+ current += 1;
46
27
  }
47
- return (0, types_1.success)(results, "");
48
- });
49
- }
50
- exports.within = within;
51
- });
28
+ }
29
+ if (start < current) {
30
+ results.push({
31
+ type: "unmatched",
32
+ value: input.slice(start, current),
33
+ });
34
+ }
35
+ return success(results, "");
36
+ });
37
+ }
package/dist/parsers.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { Parser } from "./types";
2
- export { within as betweenWithin } from "./parsers/within";
1
+ import { CaptureParser, Parser, Prettify } from "./types.js";
2
+ export { within as betweenWithin } from "./parsers/within.js";
3
3
  /**
4
4
  * Takes a character. Returns a parser that parses that character.
5
5
  *
@@ -10,10 +10,16 @@ export declare function char<const S extends string>(c: S): Parser<S>;
10
10
  /**
11
11
  * Takes a string. Returns a parser that parses that string.
12
12
  *
13
- * @param s - string to parse
13
+ * @param s - string to match on
14
14
  * @returns - parser that parses the given string
15
15
  */
16
16
  export declare function str<const S extends string>(s: S): Parser<S>;
17
+ /**
18
+ * Like `str`, but case insensitive.
19
+ * @param s - string to match on, case insensitive
20
+ * @returns - parser that matches the given string, case insensitive
21
+ */
22
+ export declare function istr<const S extends string>(s: S): Parser<S>;
17
23
  /**
18
24
  * Takes a string. Returns a parser that parses
19
25
  * one of the characters in that string.
@@ -44,11 +50,11 @@ export declare const space: Parser<string>;
44
50
  export declare const spaces: Parser<string>;
45
51
  /** A parser that matches one digit. */
46
52
  export declare const digit: Parser<string>;
47
- /** A parser that matches one letter, currently lowercase only. */
53
+ /** A parser that matches one letter, case insensitive. */
48
54
  export declare const letter: Parser<string>;
49
- /** A parser that matches one digit or letter, currently lowercase only. */
55
+ /** A parser that matches one digit or letter, case insensitive. */
50
56
  export declare const alphanum: Parser<string>;
51
- /** A parser that matches one lowercase word. */
57
+ /** A parser that matches one word, case insensitive. */
52
58
  export declare const word: Parser<string>;
53
59
  /** A parser that matches one or more digits. */
54
60
  export declare const num: Parser<string>;
@@ -64,4 +70,76 @@ export declare const eof: Parser<null>;
64
70
  * Returns the string as the result, including the quotes.
65
71
  */
66
72
  export declare const quotedString: Parser<string>;
67
- export declare function regexParser(str: string | RegExp): Parser<string>;
73
+ /**
74
+ * Returns a parser that matches a regex. If you pass in a string,
75
+ * it will get converted to a regex. The regex should always match from the start of the input.
76
+ * If you pass in a string, a `^` will get prepended to it.
77
+ *
78
+ * @param str - regex string or RegExp instance to match
79
+ * @param options - regex options (i = ignore case, g = global, m = multiline, u = unicode)
80
+ * @returns - parser that matches the given regex
81
+ */
82
+ export declare function regexParser(str: string | RegExp, options?: string): Parser<string>;
83
+ /**
84
+ * Like `regexParser`, but you can name your capture groups
85
+ * and get them back as the result instead.
86
+ * Fails if it doesn't have the same number of names as capture groups.
87
+ *
88
+ * @param str - regex string or RegExp instance to match
89
+ * @param options - string of regex options (i = ignore case, g = global, m = multiline, u = unicode)
90
+ * @param captureNames - names of the captures
91
+ * @returns - parser that matches the given regex
92
+ */
93
+ export declare function captureRegex<const T extends string[]>(str: string | RegExp, options?: string, ...captureNames: T): Parser<Prettify<Record<(typeof captureNames)[number], string>>>;
94
+ /**
95
+ * Return a parser that takes a key and a value.
96
+ * The parser consumes no input and always succeeds,
97
+ * and returns `null` as the result. It also returns a captures object
98
+ * with that key-value pair set. This is useful when you need to inject
99
+ * a key-value pair into captures for a `seq`.
100
+ *
101
+ * For example, here is a Markdown heading parser.
102
+
103
+ * ```ts
104
+ * export const headingParser: Parser<Heading> = seqC(
105
+ * capture(count(char("#")), "level"),
106
+ * spaces,
107
+ * capture(many1Till(or(char("\n"), eof)), "content")
108
+ * );
109
+ ```
110
+ *
111
+ * This parser returns
112
+ *
113
+ * ```ts
114
+ * {
115
+ * level: number,
116
+ * content: string
117
+ * }
118
+ * ```
119
+ * but the type of heading is actually
120
+ *
121
+ * ```ts
122
+ * type Heading = {
123
+ * type: "heading";
124
+ * level: number;
125
+ * content: string;
126
+ * };
127
+ * ```
128
+ *
129
+ * The `type` key is missing. You can use `set` to inject the `type`
130
+ * key-value pair into captures:
131
+ *
132
+ * ```ts
133
+ * export const headingParser: Parser<Heading> = seqC(
134
+ * set("type", "heading"),
135
+ * capture(count(char("#")), "level"),
136
+ * spaces,
137
+ * capture(many1Till(or(char("\n"), eof)), "content")
138
+ * );
139
+ * ```
140
+ *
141
+ * @param key - key to set on captures object
142
+ * @param value - value to set on captures object
143
+ * @returns
144
+ */
145
+ export declare function set<const K extends string, const V>(key: K, value: V): CaptureParser<null, Record<K, V>>;
package/dist/parsers.js CHANGED
@@ -1,151 +1,248 @@
1
- (function (factory) {
2
- if (typeof module === "object" && typeof module.exports === "object") {
3
- var v = factory(require, exports);
4
- if (v !== undefined) module.exports = v;
1
+ import { many1WithJoin, manyWithJoin, seq } from "./combinators.js";
2
+ import { trace } from "./trace.js";
3
+ import { captureSuccess, failure, success, } from "./types.js";
4
+ import { escape } from "./utils.js";
5
+ export { within as betweenWithin } from "./parsers/within.js";
6
+ /**
7
+ * Takes a character. Returns a parser that parses that character.
8
+ *
9
+ * @param c - character to parse
10
+ * @returns - parser that parses the given character
11
+ */
12
+ export function char(c) {
13
+ return trace(`char(${escape(c)})`, (input) => {
14
+ if (input.length === 0) {
15
+ return {
16
+ success: false,
17
+ rest: input,
18
+ message: "unexpected end of input",
19
+ };
20
+ }
21
+ if (input[0] === c) {
22
+ return success(c, input.slice(1));
23
+ }
24
+ return failure(`expected ${escape(c)}, got ${escape(input[0])}`, input);
25
+ });
26
+ }
27
+ /**
28
+ * Takes a string. Returns a parser that parses that string.
29
+ *
30
+ * @param s - string to match on
31
+ * @returns - parser that parses the given string
32
+ */
33
+ export function str(s) {
34
+ return trace(`str(${escape(s)})`, (input) => {
35
+ if (input.substring(0, s.length) === s) {
36
+ return success(s, input.slice(s.length));
37
+ }
38
+ return failure(`expected ${s}, got ${input.substring(0, s.length)}`, input);
39
+ });
40
+ }
41
+ /**
42
+ * Like `str`, but case insensitive.
43
+ * @param s - string to match on, case insensitive
44
+ * @returns - parser that matches the given string, case insensitive
45
+ */
46
+ export function istr(s) {
47
+ return trace(`istr(${escape(s)})`, (input) => {
48
+ if (input.substring(0, s.length).toLocaleLowerCase() === s.toLocaleLowerCase()) {
49
+ return success(input.substring(0, s.length), input.slice(s.length));
50
+ }
51
+ return failure(`expected ${s}, got ${input.substring(0, s.length)}`, input);
52
+ });
53
+ }
54
+ /**
55
+ * Takes a string. Returns a parser that parses
56
+ * one of the characters in that string.
57
+ *
58
+ * @param chars - string of possible characters
59
+ * @returns - parser that parses one of the given characters
60
+ */
61
+ export function oneOf(chars) {
62
+ return trace(`oneOf(${escape(chars)})`, (input) => {
63
+ if (input.length === 0) {
64
+ return failure("unexpected end of input", input);
65
+ }
66
+ const c = input[0];
67
+ if (chars.includes(c)) {
68
+ return char(c)(input);
69
+ }
70
+ return failure(`expected one of ${escape(chars)}, got ${c}`, input);
71
+ });
72
+ }
73
+ /**
74
+ * Takes a string. Returns a parser that parses one character
75
+ * that's not any of the characters in the given string
76
+ *
77
+ * @param chars - string of characters to avoid
78
+ * @returns - parser that parses a character that is not in the given string
79
+ */
80
+ export function noneOf(chars) {
81
+ return trace(`noneOf(${escape(chars)})`, (input) => {
82
+ if (input.length === 0) {
83
+ return failure("unexpected end of input", input);
84
+ }
85
+ if (chars.includes(input[0])) {
86
+ return failure(`expected none of ${escape(chars)}, got ${input[0]}`, input);
87
+ }
88
+ return char(input[0])(input);
89
+ });
90
+ }
91
+ /**
92
+ * A parser that parses any one character.
93
+ * Fails on empty strings, succeeds otherwise.
94
+ *
95
+ * @param input - input string
96
+ * @returns - ParserResult
97
+ */
98
+ export const anyChar = trace("anyChar", (input) => {
99
+ if (input.length === 0) {
100
+ return failure("unexpected end of input", input);
5
101
  }
6
- else if (typeof define === "function" && define.amd) {
7
- define(["require", "exports", "./combinators", "./trace", "./types", "./utils", "./parsers/within"], factory);
102
+ return success(input[0], input.slice(1));
103
+ });
104
+ /** A parser that matches one of " \t\n\r". */
105
+ export const space = oneOf(" \t\n\r");
106
+ /** A parser that matches one or more spaces. */
107
+ export const spaces = many1WithJoin(space);
108
+ /** A parser that matches one digit. */
109
+ export const digit = oneOf("0123456789");
110
+ /** A parser that matches one letter, case insensitive. */
111
+ export const letter = oneOf("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
112
+ /** A parser that matches one digit or letter, case insensitive. */
113
+ export const alphanum = oneOf("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789");
114
+ /** A parser that matches one word, case insensitive. */
115
+ export const word = regexParser("^[a-z]+", "ui");
116
+ /** A parser that matches one or more digits. */
117
+ export const num = regexParser("^[0-9]+");
118
+ /** A parser that matches one single or double quote. */
119
+ export const quote = oneOf(`'"`);
120
+ /** A parser that matches one tab character. */
121
+ export const tab = char("\t");
122
+ /** A parser that matches one newline ("\n" only) character. */
123
+ export const newline = char("\n");
124
+ /** A parser that succeeds on an empty string. Returns `null` as the result. */
125
+ export const eof = (input) => {
126
+ if (input === "") {
127
+ return success(null, input);
8
128
  }
9
- })(function (require, exports) {
10
- "use strict";
11
- Object.defineProperty(exports, "__esModule", { value: true });
12
- exports.regexParser = exports.quotedString = exports.eof = exports.newline = exports.tab = exports.quote = exports.num = exports.word = exports.alphanum = exports.letter = exports.digit = exports.spaces = exports.space = exports.anyChar = exports.noneOf = exports.oneOf = exports.str = exports.char = exports.betweenWithin = void 0;
13
- const combinators_1 = require("./combinators");
14
- const trace_1 = require("./trace");
15
- const types_1 = require("./types");
16
- const utils_1 = require("./utils");
17
- var within_1 = require("./parsers/within");
18
- Object.defineProperty(exports, "betweenWithin", { enumerable: true, get: function () { return within_1.within; } });
19
- /**
20
- * Takes a character. Returns a parser that parses that character.
21
- *
22
- * @param c - character to parse
23
- * @returns - parser that parses the given character
24
- */
25
- function char(c) {
26
- return (0, trace_1.trace)(`char(${(0, utils_1.escape)(c)})`, (input) => {
27
- if (input.length === 0) {
28
- return {
29
- success: false,
30
- rest: input,
31
- message: "unexpected end of input",
32
- };
33
- }
34
- if (input[0] === c) {
35
- return (0, types_1.success)(c, input.slice(1));
36
- }
37
- return (0, types_1.failure)(`expected ${(0, utils_1.escape)(c)}, got ${(0, utils_1.escape)(input[0])}`, input);
38
- });
129
+ return failure("expected end of input", input);
130
+ };
131
+ /** A parser that matches a quoted string, in single or double quotes.
132
+ * Returns the string as the result, including the quotes.
133
+ */
134
+ export const quotedString = seq([quote, manyWithJoin(noneOf(`"'`)), quote], (results) => results.join(""));
135
+ /**
136
+ * Returns a parser that matches a regex. If you pass in a string,
137
+ * it will get converted to a regex. The regex should always match from the start of the input.
138
+ * If you pass in a string, a `^` will get prepended to it.
139
+ *
140
+ * @param str - regex string or RegExp instance to match
141
+ * @param options - regex options (i = ignore case, g = global, m = multiline, u = unicode)
142
+ * @returns - parser that matches the given regex
143
+ */
144
+ export function regexParser(str, options = "") {
145
+ let re;
146
+ if (typeof str === "string") {
147
+ re = new RegExp(str.startsWith("^") ? str : `^${str}`, options);
39
148
  }
40
- exports.char = char;
41
- /**
42
- * Takes a string. Returns a parser that parses that string.
43
- *
44
- * @param s - string to parse
45
- * @returns - parser that parses the given string
46
- */
47
- function str(s) {
48
- return (0, trace_1.trace)(`str(${(0, utils_1.escape)(s)})`, (input) => {
49
- if (input.substring(0, s.length) === s) {
50
- return (0, types_1.success)(s, input.slice(s.length));
51
- }
52
- return (0, types_1.failure)(`expected ${s}, got ${input.substring(0, s.length)}`, input);
53
- });
149
+ else {
150
+ re = str;
54
151
  }
55
- exports.str = str;
56
- /**
57
- * Takes a string. Returns a parser that parses
58
- * one of the characters in that string.
59
- *
60
- * @param chars - string of possible characters
61
- * @returns - parser that parses one of the given characters
62
- */
63
- function oneOf(chars) {
64
- return (0, trace_1.trace)(`oneOf(${(0, utils_1.escape)(chars)})`, (input) => {
65
- if (input.length === 0) {
66
- return (0, types_1.failure)("unexpected end of input", input);
67
- }
68
- const c = input[0];
69
- if (chars.includes(c)) {
70
- return char(c)(input);
71
- }
72
- return (0, types_1.failure)(`expected one of ${(0, utils_1.escape)(chars)}, got ${c}`, input);
73
- });
152
+ return trace(`regex(${str})`, (input) => {
153
+ const match = input.match(re);
154
+ if (match) {
155
+ return success(match[0], input.slice(match[0].length));
156
+ }
157
+ return failure(`expected ${str}, got ${input.slice(0, 10)}`, input);
158
+ });
159
+ }
160
+ /**
161
+ * Like `regexParser`, but you can name your capture groups
162
+ * and get them back as the result instead.
163
+ * Fails if it doesn't have the same number of names as capture groups.
164
+ *
165
+ * @param str - regex string or RegExp instance to match
166
+ * @param options - string of regex options (i = ignore case, g = global, m = multiline, u = unicode)
167
+ * @param captureNames - names of the captures
168
+ * @returns - parser that matches the given regex
169
+ */
170
+ export function captureRegex(str, options = "", ...captureNames) {
171
+ let re;
172
+ if (typeof str === "string") {
173
+ re = new RegExp(str.startsWith("^") ? str : `^${str}`, options);
74
174
  }
75
- exports.oneOf = oneOf;
76
- /**
77
- * Takes a string. Returns a parser that parses one character
78
- * that's not any of the characters in the given string
79
- *
80
- * @param chars - string of characters to avoid
81
- * @returns - parser that parses a character that is not in the given string
82
- */
83
- function noneOf(chars) {
84
- return (0, trace_1.trace)(`noneOf(${(0, utils_1.escape)(chars)})`, (input) => {
85
- if (input.length === 0) {
86
- return (0, types_1.failure)("unexpected end of input", input);
175
+ else {
176
+ re = str;
177
+ }
178
+ return trace(`captureRegex(${str})`, (input) => {
179
+ const match = input.match(re);
180
+ if (match) {
181
+ if (match.slice(1).length > captureNames.length) {
182
+ return failure(`more capture groups than names. ${match.slice(1).length} capture groups, ${captureNames.length} names`, input);
87
183
  }
88
- if (chars.includes(input[0])) {
89
- return (0, types_1.failure)(`expected none of ${(0, utils_1.escape)(chars)}, got ${input[0]}`, input);
184
+ if (match.slice(1).length < captureNames.length) {
185
+ return failure(`fewer capture groups than names. ${match.slice(1).length} capture groups, ${captureNames.length} names`, input);
90
186
  }
91
- return char(input[0])(input);
92
- });
93
- }
94
- exports.noneOf = noneOf;
95
- /**
96
- * A parser that parses any one character.
97
- * Fails on empty strings, succeeds otherwise.
98
- *
99
- * @param input - input string
100
- * @returns - ParserResult
101
- */
102
- exports.anyChar = (0, trace_1.trace)("anyChar", (input) => {
103
- if (input.length === 0) {
104
- return (0, types_1.failure)("unexpected end of input", input);
187
+ const captures = Object.assign({}, Object.fromEntries(match.slice(1).map((value, index) => [captureNames[index], value])));
188
+ return success(captures, input.slice(match[0].length));
105
189
  }
106
- return (0, types_1.success)(input[0], input.slice(1));
190
+ return failure(`expected ${str}, got ${input.slice(0, 10)}`, input);
107
191
  });
108
- /** A parser that matches one of " \t\n\r". */
109
- exports.space = oneOf(" \t\n\r");
110
- /** A parser that matches one or more spaces. */
111
- exports.spaces = (0, combinators_1.many1WithJoin)(exports.space);
112
- /** A parser that matches one digit. */
113
- exports.digit = oneOf("0123456789");
114
- /** A parser that matches one letter, currently lowercase only. */
115
- exports.letter = oneOf("abcdefghijklmnopqrstuvwxyz");
116
- /** A parser that matches one digit or letter, currently lowercase only. */
117
- exports.alphanum = oneOf("abcdefghijklmnopqrstuvwxyz0123456789");
118
- /** A parser that matches one lowercase word. */
119
- exports.word = (0, combinators_1.many1WithJoin)(exports.letter);
120
- /** A parser that matches one or more digits. */
121
- exports.num = (0, combinators_1.many1WithJoin)(exports.digit);
122
- /** A parser that matches one single or double quote. */
123
- exports.quote = oneOf(`'"`);
124
- /** A parser that matches one tab character. */
125
- exports.tab = char("\t");
126
- /** A parser that matches one newline ("\n" only) character. */
127
- exports.newline = char("\n");
128
- /** A parser that succeeds on an empty string. Returns `null` as the result. */
129
- const eof = (input) => {
130
- if (input === "") {
131
- return (0, types_1.success)(null, input);
132
- }
133
- return (0, types_1.failure)("expected end of input", input);
134
- };
135
- exports.eof = eof;
136
- /** A parser that matches a quoted string, in single or double quotes.
137
- * Returns the string as the result, including the quotes.
138
- */
139
- exports.quotedString = (0, combinators_1.seq)([exports.quote, (0, combinators_1.manyWithJoin)(noneOf(`"'`)), exports.quote], (results) => results.join(""));
140
- function regexParser(str) {
141
- const re = typeof str === "string" ? new RegExp(`^(${str})`) : str;
142
- return (0, trace_1.trace)(`regex(${str})`, (input) => {
143
- const match = input.match(re);
144
- if (match) {
145
- return (0, types_1.success)(match[0], input.slice(match[0].length));
146
- }
147
- return (0, types_1.failure)(`expected ${str}, got ${input.slice(0, 10)}`, input);
148
- });
149
- }
150
- exports.regexParser = regexParser;
151
- });
192
+ }
193
+ /**
194
+ * Return a parser that takes a key and a value.
195
+ * The parser consumes no input and always succeeds,
196
+ * and returns `null` as the result. It also returns a captures object
197
+ * with that key-value pair set. This is useful when you need to inject
198
+ * a key-value pair into captures for a `seq`.
199
+ *
200
+ * For example, here is a Markdown heading parser.
201
+
202
+ * ```ts
203
+ * export const headingParser: Parser<Heading> = seqC(
204
+ * capture(count(char("#")), "level"),
205
+ * spaces,
206
+ * capture(many1Till(or(char("\n"), eof)), "content")
207
+ * );
208
+ ```
209
+ *
210
+ * This parser returns
211
+ *
212
+ * ```ts
213
+ * {
214
+ * level: number,
215
+ * content: string
216
+ * }
217
+ * ```
218
+ * but the type of heading is actually
219
+ *
220
+ * ```ts
221
+ * type Heading = {
222
+ * type: "heading";
223
+ * level: number;
224
+ * content: string;
225
+ * };
226
+ * ```
227
+ *
228
+ * The `type` key is missing. You can use `set` to inject the `type`
229
+ * key-value pair into captures:
230
+ *
231
+ * ```ts
232
+ * export const headingParser: Parser<Heading> = seqC(
233
+ * set("type", "heading"),
234
+ * capture(count(char("#")), "level"),
235
+ * spaces,
236
+ * capture(many1Till(or(char("\n"), eof)), "content")
237
+ * );
238
+ * ```
239
+ *
240
+ * @param key - key to set on captures object
241
+ * @param value - value to set on captures object
242
+ * @returns
243
+ */
244
+ export function set(key, value) {
245
+ return trace(`set(${key}, ${value})`, (input) => {
246
+ return captureSuccess(null, input, { [key]: value });
247
+ });
248
+ }