parser-combinators 1.2.5 → 1.2.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.
@@ -23,6 +23,7 @@ function any(...parsers) {
23
23
  const res = parser(ctx);
24
24
  if ((0, types_1.isFailure)(res)) {
25
25
  const surelyIndex = res.history.findIndex(h => h === 'surely');
26
+ // Stryker disable next-line EqualityOperator: The > mutant results in an equivalent mutant
26
27
  if (surelyIndex >= 0) {
27
28
  return (0, types_1.failure)(res.ctx, res.expected, ['any', ...res.history.slice(0, surelyIndex), ...res.history.slice(surelyIndex + 1)]);
28
29
  }
@@ -26,14 +26,7 @@ function createSearchTree(matches) {
26
26
  }
27
27
  function addMatchToTree(node, match, idIndex, charIndex = 0) {
28
28
  if (charIndex >= match[0].length) {
29
- if (node.matchIndex != undefined) {
30
- if (node.matchIndex > idIndex) {
31
- node.matchIndex = idIndex;
32
- }
33
- }
34
- else {
35
- node.matchIndex = idIndex;
36
- }
29
+ node.matchIndex ??= idIndex;
37
30
  }
38
31
  else {
39
32
  const char = match[0][charIndex];
@@ -51,15 +44,17 @@ function addMatchToTree(node, match, idIndex, charIndex = 0) {
51
44
  }
52
45
  }
53
46
  else {
54
- const charNode = node.get(char) ?? newNode;
55
- node.set(char, charNode);
56
- const lower = node.get(lowercase);
57
- if (lower === node.get(uppercase)) {
58
- const copy = new Map(lower.entries());
59
- copy.matchIndex = lower.matchIndex;
60
- node.set(uppercase, copy);
47
+ node.set(char, node.get(char) ?? newNode);
48
+ if (lowercase !== uppercase) {
49
+ const lower = node.get(lowercase);
50
+ const upper = node.get(uppercase);
51
+ if (lower != null && lower === upper) {
52
+ const copy = new Map(lower.entries());
53
+ copy.matchIndex = lower.matchIndex;
54
+ node.set(uppercase, copy);
55
+ }
61
56
  }
62
- addMatchToTree(charNode, match, idIndex, charIndex + 1);
57
+ addMatchToTree(node.get(char), match, idIndex, charIndex + 1);
63
58
  }
64
59
  }
65
60
  }
@@ -2,6 +2,9 @@ export * from './any';
2
2
  export * from './between';
3
3
  export * from './exhaust';
4
4
  export * from './many';
5
+ export * from './zeroOrMany';
6
+ export * from './oneOrMany';
7
+ export * from './oneOrManyRed';
5
8
  export * from './map';
6
9
  export * from './opt';
7
10
  export * from './regex';
@@ -10,3 +13,4 @@ export { str, stri } from './str';
10
13
  export * from './recovery';
11
14
  export * from './utilities';
12
15
  export * from './values';
16
+ export * from './readymade';
@@ -19,6 +19,9 @@ __exportStar(require("./any"), exports);
19
19
  __exportStar(require("./between"), exports);
20
20
  __exportStar(require("./exhaust"), exports);
21
21
  __exportStar(require("./many"), exports);
22
+ __exportStar(require("./zeroOrMany"), exports);
23
+ __exportStar(require("./oneOrMany"), exports);
24
+ __exportStar(require("./oneOrManyRed"), exports);
22
25
  __exportStar(require("./map"), exports);
23
26
  __exportStar(require("./opt"), exports);
24
27
  __exportStar(require("./regex"), exports);
@@ -29,3 +32,4 @@ Object.defineProperty(exports, "stri", { enumerable: true, get: function () { re
29
32
  __exportStar(require("./recovery"), exports);
30
33
  __exportStar(require("./utilities"), exports);
31
34
  __exportStar(require("./values"), exports);
35
+ __exportStar(require("./readymade"), exports);
@@ -3,15 +3,3 @@ import { Parser } from "../types";
3
3
  * @returns A parser returning an array of many parses.
4
4
  */
5
5
  export declare function many<T>(parser: Parser<T>): Parser<T[]>;
6
- /** Parses zero or more occurences of the given parser, separated with the separator parser.
7
- * @returns A parser returning an array of many parses, omitting the separator.
8
- */
9
- export declare function zeroOrMany<T, V>(item: Parser<T>, separator?: Parser<V> | undefined): Parser<T[]>;
10
- /** Parses one or more occurences of the given parser, separated with the separator parser.
11
- * @returns A parser returning an array of many parses, omitting the separator.
12
- */
13
- export declare function oneOrMany<T, V>(item: Parser<T>, separator?: Parser<V> | undefined): Parser<T[]>;
14
- /** Parses one or more occurences of the given parser, separated with the separator parser.
15
- * @returns A parser returning the result of many parses, reduced using the `reducer` function passed in.
16
- */
17
- export declare function oneOrManyRed<T, V, U = T>(item: Parser<T>, separator: Parser<V>, reducer: (left: U | T, right: T, sep: V) => U): Parser<U | T>;
@@ -1,9 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.many = many;
4
- exports.zeroOrMany = zeroOrMany;
5
- exports.oneOrMany = oneOrMany;
6
- exports.oneOrManyRed = oneOrManyRed;
7
4
  const types_1 = require("../types");
8
5
  /** Parses zero or more occurences of the given parser.
9
6
  * @returns A parser returning an array of many parses.
@@ -15,6 +12,7 @@ function many(parser) {
15
12
  const res = parser(ctx);
16
13
  if ((0, types_1.isFailure)(res)) {
17
14
  const surelyIndex = res.history.findIndex(h => h === 'surely');
15
+ // Stryker disable next-line EqualityOperator: The > mutant results in an equivalent mutant
18
16
  if (surelyIndex >= 0) {
19
17
  return (0, types_1.failure)(res.ctx, res.expected, ['many', ...res.history.slice(0, surelyIndex), ...res.history.slice(surelyIndex + 1)]);
20
18
  }
@@ -25,139 +23,3 @@ function many(parser) {
25
23
  }
26
24
  };
27
25
  }
28
- /** Parses zero or more occurences of the given parser, separated with the separator parser.
29
- * @returns A parser returning an array of many parses, omitting the separator.
30
- */
31
- function zeroOrMany(item, separator = undefined) {
32
- if (separator) {
33
- return (ctx) => {
34
- const results = [];
35
- const res = item(ctx);
36
- if ((0, types_1.isFailure)(res)) {
37
- const surelyIndex = res.history.findIndex(h => h === 'surely');
38
- if (surelyIndex >= 0) {
39
- return (0, types_1.failure)(res.ctx, res.expected, ['zeroOrMany', ...res.history.slice(0, surelyIndex), ...res.history.slice(surelyIndex + 1)]);
40
- }
41
- return (0, types_1.success)(ctx, results);
42
- }
43
- ctx = res.ctx;
44
- results.push(res.value);
45
- while (true) {
46
- const resSep = separator(ctx);
47
- if ((0, types_1.isFailure)(resSep)) {
48
- const surelyIndex = resSep.history.findIndex(h => h === 'surely');
49
- if (surelyIndex >= 0) {
50
- return (0, types_1.failure)(resSep.ctx, resSep.expected, ['zeroOrMany', ...resSep.history.slice(0, surelyIndex), ...resSep.history.slice(surelyIndex + 1)]);
51
- }
52
- return (0, types_1.success)(ctx, results);
53
- }
54
- const res = item(resSep.ctx);
55
- if ((0, types_1.isFailure)(res)) {
56
- const surelyIndex = res.history.findIndex(h => h === 'surely');
57
- if (surelyIndex >= 0) {
58
- return (0, types_1.failure)(res.ctx, res.expected, ['zeroOrMany', ...res.history.slice(0, surelyIndex), ...res.history.slice(surelyIndex + 1)]);
59
- }
60
- return (0, types_1.success)(ctx, results);
61
- }
62
- ctx = res.ctx;
63
- results.push(res.value);
64
- }
65
- };
66
- }
67
- else
68
- return many(item);
69
- }
70
- /** Parses one or more occurences of the given parser, separated with the separator parser.
71
- * @returns A parser returning an array of many parses, omitting the separator.
72
- */
73
- function oneOrMany(item, separator = undefined) {
74
- if (separator) {
75
- return (ctx) => {
76
- const results = [];
77
- const res = item(ctx);
78
- if ((0, types_1.isFailure)(res))
79
- return res;
80
- ctx = res.ctx;
81
- results.push(res.value);
82
- while (true) {
83
- const resSep = separator(ctx);
84
- if ((0, types_1.isFailure)(resSep)) {
85
- const surelyIndex = resSep.history.findIndex(h => h === 'surely');
86
- if (surelyIndex >= 0) {
87
- return (0, types_1.failure)(resSep.ctx, resSep.expected, ['oneOrMany', ...resSep.history.slice(0, surelyIndex), ...resSep.history.slice(surelyIndex + 1)]);
88
- }
89
- return (0, types_1.success)(ctx, results);
90
- }
91
- const res = item(resSep.ctx);
92
- if ((0, types_1.isFailure)(res)) {
93
- const surelyIndex = res.history.findIndex(h => h === 'surely');
94
- if (surelyIndex >= 0) {
95
- return (0, types_1.failure)(res.ctx, res.expected, ['oneOrMany', ...res.history.slice(0, surelyIndex), ...res.history.slice(surelyIndex + 1)]);
96
- }
97
- return (0, types_1.success)(ctx, results);
98
- }
99
- ctx = res.ctx;
100
- results.push(res.value);
101
- }
102
- };
103
- }
104
- else {
105
- return (ctx) => {
106
- const results = [];
107
- const res = item(ctx);
108
- if ((0, types_1.isFailure)(res))
109
- return res;
110
- ctx = res.ctx;
111
- results.push(res.value);
112
- while (true) {
113
- const res = item(ctx);
114
- if ((0, types_1.isFailure)(res)) {
115
- const surelyIndex = res.history.findIndex(h => h === 'surely');
116
- if (surelyIndex >= 0) {
117
- return (0, types_1.failure)(res.ctx, res.expected, ['oneOrMany', ...res.history.slice(0, surelyIndex), ...res.history.slice(surelyIndex + 1)]);
118
- }
119
- return (0, types_1.success)(ctx, results);
120
- }
121
- ctx = res.ctx;
122
- results.push(res.value);
123
- }
124
- };
125
- }
126
- }
127
- /** Parses one or more occurences of the given parser, separated with the separator parser.
128
- * @returns A parser returning the result of many parses, reduced using the `reducer` function passed in.
129
- */
130
- function oneOrManyRed(item, separator, reducer) {
131
- return (ctx) => {
132
- const res = item(ctx);
133
- if ((0, types_1.isFailure)(res))
134
- return res;
135
- ctx = res.ctx;
136
- let result = res.value;
137
- while (true) {
138
- const resSep = separator(ctx);
139
- if ((0, types_1.isFailure)(resSep)) {
140
- const surelyIndex = resSep.history.findIndex(h => h === 'surely');
141
- if (surelyIndex >= 0) {
142
- return (0, types_1.failure)(resSep.ctx, resSep.expected, ['oneOrManyRed', ...resSep.history.slice(0, surelyIndex), ...resSep.history.slice(surelyIndex + 1)]);
143
- }
144
- return (0, types_1.success)(ctx, result);
145
- }
146
- const res = item(resSep.ctx);
147
- if ((0, types_1.isFailure)(res)) {
148
- const surelyIndex = res.history.findIndex(h => h === 'surely');
149
- if (surelyIndex >= 0) {
150
- return (0, types_1.failure)(res.ctx, res.expected, ['oneOrManyRed', ...res.history.slice(0, surelyIndex), ...res.history.slice(surelyIndex + 1)]);
151
- }
152
- return (0, types_1.success)(ctx, result);
153
- }
154
- ctx = res.ctx;
155
- try {
156
- result = reducer(result, res.value, resSep.value);
157
- }
158
- catch {
159
- return (0, types_1.failure)(res.ctx, 'Error while reducing', ['oneOrManyRed']);
160
- }
161
- }
162
- };
163
- }
@@ -0,0 +1,5 @@
1
+ import { Parser } from "../types";
2
+ /** Parses one or more occurences of the given parser, separated with the separator parser.
3
+ * @returns A parser returning an array of many parses, omitting the separator.
4
+ */
5
+ export declare function oneOrMany<T, V>(item: Parser<T>, separator?: Parser<V> | undefined): Parser<T[]>;
@@ -0,0 +1,66 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.oneOrMany = oneOrMany;
4
+ const types_1 = require("../types");
5
+ /** Parses one or more occurences of the given parser, separated with the separator parser.
6
+ * @returns A parser returning an array of many parses, omitting the separator.
7
+ */
8
+ function oneOrMany(item, separator = undefined) {
9
+ if (separator) {
10
+ return (ctx) => {
11
+ const results = [];
12
+ const res = item(ctx);
13
+ if ((0, types_1.isFailure)(res)) {
14
+ return (0, types_1.failure)(res.ctx, res.expected, ['oneOrMany', ...res.history]);
15
+ }
16
+ ctx = res.ctx;
17
+ results.push(res.value);
18
+ while (true) {
19
+ const resSep = separator(ctx);
20
+ if ((0, types_1.isFailure)(resSep)) {
21
+ const surelyIndex = resSep.history.findIndex(h => h === 'surely');
22
+ // Stryker disable next-line EqualityOperator: The > mutant results in an equivalent mutant
23
+ if (surelyIndex >= 0) {
24
+ return (0, types_1.failure)(resSep.ctx, resSep.expected, ['oneOrMany', ...resSep.history.slice(0, surelyIndex), ...resSep.history.slice(surelyIndex + 1)]);
25
+ }
26
+ return (0, types_1.success)(ctx, results);
27
+ }
28
+ const res = item(resSep.ctx);
29
+ if ((0, types_1.isFailure)(res)) {
30
+ const surelyIndex = res.history.findIndex(h => h === 'surely');
31
+ // Stryker disable next-line EqualityOperator: The > mutant results in an equivalent mutant
32
+ if (surelyIndex >= 0) {
33
+ return (0, types_1.failure)(res.ctx, res.expected, ['oneOrMany', ...res.history.slice(0, surelyIndex), ...res.history.slice(surelyIndex + 1)]);
34
+ }
35
+ return (0, types_1.success)(ctx, results);
36
+ }
37
+ ctx = res.ctx;
38
+ results.push(res.value);
39
+ }
40
+ };
41
+ }
42
+ else {
43
+ return (ctx) => {
44
+ const results = [];
45
+ const res = item(ctx);
46
+ if ((0, types_1.isFailure)(res)) {
47
+ return (0, types_1.failure)(res.ctx, res.expected, ['oneOrMany', ...res.history]);
48
+ }
49
+ ctx = res.ctx;
50
+ results.push(res.value);
51
+ while (true) {
52
+ const res = item(ctx);
53
+ if ((0, types_1.isFailure)(res)) {
54
+ const surelyIndex = res.history.findIndex(h => h === 'surely');
55
+ // Stryker disable next-line EqualityOperator: The > mutant results in an equivalent mutant
56
+ if (surelyIndex >= 0) {
57
+ return (0, types_1.failure)(res.ctx, res.expected, ['oneOrMany', ...res.history.slice(0, surelyIndex), ...res.history.slice(surelyIndex + 1)]);
58
+ }
59
+ return (0, types_1.success)(ctx, results);
60
+ }
61
+ ctx = res.ctx;
62
+ results.push(res.value);
63
+ }
64
+ };
65
+ }
66
+ }
@@ -0,0 +1,5 @@
1
+ import { Parser } from "../types";
2
+ /** Parses one or more occurences of the given parser, separated with the separator parser.
3
+ * @returns A parser returning the result of many parses, reduced using the `reducer` function passed in.
4
+ */
5
+ export declare function oneOrManyRed<T, V, U = T>(item: Parser<T>, separator: Parser<V>, reducer: (left: U | T, right: T, sep: V) => U): Parser<U | T>;
@@ -0,0 +1,44 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.oneOrManyRed = oneOrManyRed;
4
+ const types_1 = require("../types");
5
+ /** Parses one or more occurences of the given parser, separated with the separator parser.
6
+ * @returns A parser returning the result of many parses, reduced using the `reducer` function passed in.
7
+ */
8
+ function oneOrManyRed(item, separator, reducer) {
9
+ return (ctx) => {
10
+ const res = item(ctx);
11
+ if ((0, types_1.isFailure)(res)) {
12
+ return (0, types_1.failure)(res.ctx, res.expected, ['oneOrManyRed', ...res.history]);
13
+ }
14
+ ctx = res.ctx;
15
+ let result = res.value;
16
+ while (true) {
17
+ const resSep = separator(ctx);
18
+ if ((0, types_1.isFailure)(resSep)) {
19
+ const surelyIndex = resSep.history.findIndex(h => h === 'surely');
20
+ // Stryker disable next-line EqualityOperator: The > mutant results in an equivalent mutant
21
+ if (surelyIndex >= 0) {
22
+ return (0, types_1.failure)(resSep.ctx, resSep.expected, ['oneOrManyRed', ...resSep.history.slice(0, surelyIndex), ...resSep.history.slice(surelyIndex + 1)]);
23
+ }
24
+ return (0, types_1.success)(ctx, result);
25
+ }
26
+ const res = item(resSep.ctx);
27
+ if ((0, types_1.isFailure)(res)) {
28
+ const surelyIndex = res.history.findIndex(h => h === 'surely');
29
+ // Stryker disable next-line EqualityOperator: The > mutant results in an equivalent mutant
30
+ if (surelyIndex >= 0) {
31
+ return (0, types_1.failure)(res.ctx, res.expected, ['oneOrManyRed', ...res.history.slice(0, surelyIndex), ...res.history.slice(surelyIndex + 1)]);
32
+ }
33
+ return (0, types_1.success)(ctx, result);
34
+ }
35
+ ctx = res.ctx;
36
+ try {
37
+ result = reducer(result, res.value, resSep.value);
38
+ }
39
+ catch {
40
+ return (0, types_1.failure)(res.ctx, 'Error while reducing', ['oneOrManyRed']);
41
+ }
42
+ }
43
+ };
44
+ }
@@ -0,0 +1,7 @@
1
+ import { Parser } from "../types";
2
+ export type Json = string | number | boolean | null | {
3
+ [key: number]: Json;
4
+ } | {
5
+ [key: string]: Json;
6
+ };
7
+ export declare const json: Parser<Json>;
@@ -0,0 +1,46 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.json = void 0;
4
+ const any_1 = require("./any");
5
+ const between_1 = require("./between");
6
+ const zeroOrMany_1 = require("./zeroOrMany");
7
+ const map_1 = require("./map");
8
+ const regex_1 = require("./regex");
9
+ const seq_1 = require("./seq");
10
+ const str_1 = require("./str");
11
+ const utilities_1 = require("./utilities");
12
+ const WhiteSpace = (0, regex_1.regex)(/\s*/m, 'whitespace');
13
+ const True = (0, map_1.map)((0, str_1.str)("true"), () => true);
14
+ const False = (0, map_1.map)((0, str_1.str)("false"), () => false);
15
+ const Null = (0, map_1.map)((0, str_1.str)("null"), () => null);
16
+ const LCurly = (0, str_1.str)("{");
17
+ const RCurly = (0, utilities_1.surely)((0, str_1.str)("}"));
18
+ const LSquare = (0, str_1.str)("[");
19
+ const RSquare = (0, utilities_1.surely)((0, str_1.str)("]"));
20
+ const Quote = (0, str_1.str)('"');
21
+ const Comma = (0, str_1.str)(",");
22
+ const Colon = (0, utilities_1.surely)((0, str_1.str)(":"));
23
+ const replacements = {
24
+ '\\\\': '\\',
25
+ '\\0': '\0',
26
+ '\\b': '\b',
27
+ '\\f': '\f',
28
+ '\\n': '\n',
29
+ '\\r': '\r',
30
+ '\\t': '\t',
31
+ '\\v': '\v',
32
+ '\\"': '"'
33
+ };
34
+ const StringLiteral = (0, between_1.between)(Quote, (0, map_1.map)((0, regex_1.regex)(/(?:[^\\"]|\\(?:[0bfnrtv"\\]|u[0-9a-fA-F]{4}))*/, 'string literal'), str => str.replace(/\\(?:[0bfnrtv"\\]|u[0-9a-fA-F]{4})/g, function (replace) {
35
+ const tabled = replacements[replace];
36
+ if (tabled != null) {
37
+ return tabled;
38
+ }
39
+ return String.fromCharCode(parseInt(replace.slice(2), 16));
40
+ })), Quote);
41
+ const NumberLiteral = (0, map_1.map)((0, regex_1.regex)(/-?(?:0|(?:[1-9]\d*))(?:\.\d+)?(?:[eE][+-]?\d+)?/, 'number literal'), parseFloat);
42
+ const JArray = (0, utilities_1.lazy)(() => (0, map_1.map)((0, seq_1.seq)(LSquare, (0, utilities_1.surely)((0, seq_1.seq)(WhiteSpace, (0, zeroOrMany_1.zeroOrMany)(Value, (0, seq_1.seq)(WhiteSpace, Comma, WhiteSpace)), WhiteSpace, RSquare))), (data) => data[1][1]));
43
+ const JObject = (0, utilities_1.lazy)(() => (0, map_1.map)((0, seq_1.seq)(LCurly, (0, utilities_1.surely)((0, seq_1.seq)(WhiteSpace, (0, zeroOrMany_1.zeroOrMany)(ObjectEntry, (0, seq_1.seq)(WhiteSpace, Comma, WhiteSpace)), WhiteSpace, RCurly))), data => Object.fromEntries(data[1][1])));
44
+ const Value = (0, any_1.any)(StringLiteral, NumberLiteral, JObject, JArray, True, False, Null);
45
+ const ObjectEntry = (0, map_1.map)((0, seq_1.seq)(StringLiteral, (0, utilities_1.surely)((0, seq_1.seq)(WhiteSpace, Colon, WhiteSpace, Value))), ([key, rest]) => [key, rest[3]]);
46
+ exports.json = (0, between_1.between)(WhiteSpace, Value, WhiteSpace);
@@ -10,7 +10,7 @@ function regex(match, expected) {
10
10
  return (ctx) => {
11
11
  regexp.lastIndex = ctx.index;
12
12
  const regexMatch = regexp.exec(ctx.text);
13
- if (regexMatch !== null && regexMatch.index === ctx.index) {
13
+ if (regexMatch !== null) {
14
14
  return (0, types_1.success)({ ...ctx, index: ctx.index + regexMatch[0].length }, regexMatch[0]);
15
15
  }
16
16
  else {
@@ -15,7 +15,8 @@ function ref(parser, check, expected) {
15
15
  return (ctx) => {
16
16
  const res = parser(ctx);
17
17
  if (!(0, types_1.isFailure)(res) && !check(res.value)) {
18
- return (0, types_1.failure)(res.ctx, expected ?? 'check', [`ref: ${expected ?? 'check'}`]);
18
+ const phrase = expected ?? 'check';
19
+ return (0, types_1.failure)(res.ctx, phrase, [`ref: ${phrase}`]);
19
20
  }
20
21
  return res;
21
22
  };
@@ -0,0 +1,5 @@
1
+ import { Parser } from "../types";
2
+ /** Parses zero or more occurences of the given parser, separated with the separator parser.
3
+ * @returns A parser returning an array of many parses, omitting the separator.
4
+ */
5
+ export declare function zeroOrMany<T, V>(item: Parser<T>, separator?: Parser<V> | undefined): Parser<T[]>;
@@ -0,0 +1,64 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.zeroOrMany = zeroOrMany;
4
+ const types_1 = require("../types");
5
+ /** Parses zero or more occurences of the given parser, separated with the separator parser.
6
+ * @returns A parser returning an array of many parses, omitting the separator.
7
+ */
8
+ function zeroOrMany(item, separator = undefined) {
9
+ if (separator) {
10
+ return (ctx) => {
11
+ const results = [];
12
+ const res = item(ctx);
13
+ if ((0, types_1.isFailure)(res)) {
14
+ const surelyIndex = res.history.findIndex(h => h === 'surely');
15
+ // Stryker disable next-line EqualityOperator: The > mutant results in an equivalent mutant
16
+ if (surelyIndex >= 0) {
17
+ return (0, types_1.failure)(res.ctx, res.expected, ['zeroOrMany', ...res.history.slice(0, surelyIndex), ...res.history.slice(surelyIndex + 1)]);
18
+ }
19
+ return (0, types_1.success)(ctx, results);
20
+ }
21
+ ctx = res.ctx;
22
+ results.push(res.value);
23
+ while (true) {
24
+ const resSep = separator(ctx);
25
+ if ((0, types_1.isFailure)(resSep)) {
26
+ const surelyIndex = resSep.history.findIndex(h => h === 'surely');
27
+ // Stryker disable next-line EqualityOperator: The > mutant results in an equivalent mutant
28
+ if (surelyIndex >= 0) {
29
+ return (0, types_1.failure)(resSep.ctx, resSep.expected, ['zeroOrMany', ...resSep.history.slice(0, surelyIndex), ...resSep.history.slice(surelyIndex + 1)]);
30
+ }
31
+ return (0, types_1.success)(ctx, results);
32
+ }
33
+ const res = item(resSep.ctx);
34
+ if ((0, types_1.isFailure)(res)) {
35
+ const surelyIndex = res.history.findIndex(h => h === 'surely');
36
+ // Stryker disable next-line EqualityOperator: The > mutant results in an equivalent mutant
37
+ if (surelyIndex >= 0) {
38
+ return (0, types_1.failure)(res.ctx, res.expected, ['zeroOrMany', ...res.history.slice(0, surelyIndex), ...res.history.slice(surelyIndex + 1)]);
39
+ }
40
+ return (0, types_1.success)(ctx, results);
41
+ }
42
+ ctx = res.ctx;
43
+ results.push(res.value);
44
+ }
45
+ };
46
+ }
47
+ else
48
+ return (ctx) => {
49
+ const results = [];
50
+ while (true) {
51
+ const res = item(ctx);
52
+ if ((0, types_1.isFailure)(res)) {
53
+ const surelyIndex = res.history.findIndex(h => h === 'surely');
54
+ // Stryker disable next-line EqualityOperator: The > mutant results in an equivalent mutant
55
+ if (surelyIndex >= 0) {
56
+ return (0, types_1.failure)(res.ctx, res.expected, ['zeroOrMany', ...res.history.slice(0, surelyIndex), ...res.history.slice(surelyIndex + 1)]);
57
+ }
58
+ return (0, types_1.success)(ctx, results);
59
+ }
60
+ ctx = res.ctx;
61
+ results.push(res.value);
62
+ }
63
+ };
64
+ }
package/dist/types.d.ts CHANGED
@@ -16,6 +16,7 @@ export type Failure = Readonly<{
16
16
  ctx: Context;
17
17
  history: string[];
18
18
  }>;
19
+ export type ParseResult<T extends Parser<unknown>> = T extends Parser<infer P> ? P : never;
19
20
  export type TokenRange = {
20
21
  start: number;
21
22
  end: number;
@@ -20,6 +20,7 @@ export function any(...parsers) {
20
20
  const res = parser(ctx);
21
21
  if (isFailure(res)) {
22
22
  const surelyIndex = res.history.findIndex(h => h === 'surely');
23
+ // Stryker disable next-line EqualityOperator: The > mutant results in an equivalent mutant
23
24
  if (surelyIndex >= 0) {
24
25
  return failure(res.ctx, res.expected, ['any', ...res.history.slice(0, surelyIndex), ...res.history.slice(surelyIndex + 1)]);
25
26
  }
@@ -23,14 +23,7 @@ function createSearchTree(matches) {
23
23
  }
24
24
  function addMatchToTree(node, match, idIndex, charIndex = 0) {
25
25
  if (charIndex >= match[0].length) {
26
- if (node.matchIndex != undefined) {
27
- if (node.matchIndex > idIndex) {
28
- node.matchIndex = idIndex;
29
- }
30
- }
31
- else {
32
- node.matchIndex = idIndex;
33
- }
26
+ node.matchIndex ??= idIndex;
34
27
  }
35
28
  else {
36
29
  const char = match[0][charIndex];
@@ -48,15 +41,17 @@ function addMatchToTree(node, match, idIndex, charIndex = 0) {
48
41
  }
49
42
  }
50
43
  else {
51
- const charNode = node.get(char) ?? newNode;
52
- node.set(char, charNode);
53
- const lower = node.get(lowercase);
54
- if (lower === node.get(uppercase)) {
55
- const copy = new Map(lower.entries());
56
- copy.matchIndex = lower.matchIndex;
57
- node.set(uppercase, copy);
44
+ node.set(char, node.get(char) ?? newNode);
45
+ if (lowercase !== uppercase) {
46
+ const lower = node.get(lowercase);
47
+ const upper = node.get(uppercase);
48
+ if (lower != null && lower === upper) {
49
+ const copy = new Map(lower.entries());
50
+ copy.matchIndex = lower.matchIndex;
51
+ node.set(uppercase, copy);
52
+ }
58
53
  }
59
- addMatchToTree(charNode, match, idIndex, charIndex + 1);
54
+ addMatchToTree(node.get(char), match, idIndex, charIndex + 1);
60
55
  }
61
56
  }
62
57
  }
@@ -2,6 +2,9 @@ export * from './any';
2
2
  export * from './between';
3
3
  export * from './exhaust';
4
4
  export * from './many';
5
+ export * from './zeroOrMany';
6
+ export * from './oneOrMany';
7
+ export * from './oneOrManyRed';
5
8
  export * from './map';
6
9
  export * from './opt';
7
10
  export * from './regex';
@@ -10,3 +13,4 @@ export { str, stri } from './str';
10
13
  export * from './recovery';
11
14
  export * from './utilities';
12
15
  export * from './values';
16
+ export * from './readymade';
@@ -2,6 +2,9 @@ export * from './any';
2
2
  export * from './between';
3
3
  export * from './exhaust';
4
4
  export * from './many';
5
+ export * from './zeroOrMany';
6
+ export * from './oneOrMany';
7
+ export * from './oneOrManyRed';
5
8
  export * from './map';
6
9
  export * from './opt';
7
10
  export * from './regex';
@@ -10,3 +13,4 @@ export { str, stri } from './str';
10
13
  export * from './recovery';
11
14
  export * from './utilities';
12
15
  export * from './values';
16
+ export * from './readymade';
@@ -3,15 +3,3 @@ import { Parser } from "../types";
3
3
  * @returns A parser returning an array of many parses.
4
4
  */
5
5
  export declare function many<T>(parser: Parser<T>): Parser<T[]>;
6
- /** Parses zero or more occurences of the given parser, separated with the separator parser.
7
- * @returns A parser returning an array of many parses, omitting the separator.
8
- */
9
- export declare function zeroOrMany<T, V>(item: Parser<T>, separator?: Parser<V> | undefined): Parser<T[]>;
10
- /** Parses one or more occurences of the given parser, separated with the separator parser.
11
- * @returns A parser returning an array of many parses, omitting the separator.
12
- */
13
- export declare function oneOrMany<T, V>(item: Parser<T>, separator?: Parser<V> | undefined): Parser<T[]>;
14
- /** Parses one or more occurences of the given parser, separated with the separator parser.
15
- * @returns A parser returning the result of many parses, reduced using the `reducer` function passed in.
16
- */
17
- export declare function oneOrManyRed<T, V, U = T>(item: Parser<T>, separator: Parser<V>, reducer: (left: U | T, right: T, sep: V) => U): Parser<U | T>;
@@ -9,6 +9,7 @@ export function many(parser) {
9
9
  const res = parser(ctx);
10
10
  if (isFailure(res)) {
11
11
  const surelyIndex = res.history.findIndex(h => h === 'surely');
12
+ // Stryker disable next-line EqualityOperator: The > mutant results in an equivalent mutant
12
13
  if (surelyIndex >= 0) {
13
14
  return failure(res.ctx, res.expected, ['many', ...res.history.slice(0, surelyIndex), ...res.history.slice(surelyIndex + 1)]);
14
15
  }
@@ -19,139 +20,3 @@ export function many(parser) {
19
20
  }
20
21
  };
21
22
  }
22
- /** Parses zero or more occurences of the given parser, separated with the separator parser.
23
- * @returns A parser returning an array of many parses, omitting the separator.
24
- */
25
- export function zeroOrMany(item, separator = undefined) {
26
- if (separator) {
27
- return (ctx) => {
28
- const results = [];
29
- const res = item(ctx);
30
- if (isFailure(res)) {
31
- const surelyIndex = res.history.findIndex(h => h === 'surely');
32
- if (surelyIndex >= 0) {
33
- return failure(res.ctx, res.expected, ['zeroOrMany', ...res.history.slice(0, surelyIndex), ...res.history.slice(surelyIndex + 1)]);
34
- }
35
- return success(ctx, results);
36
- }
37
- ctx = res.ctx;
38
- results.push(res.value);
39
- while (true) {
40
- const resSep = separator(ctx);
41
- if (isFailure(resSep)) {
42
- const surelyIndex = resSep.history.findIndex(h => h === 'surely');
43
- if (surelyIndex >= 0) {
44
- return failure(resSep.ctx, resSep.expected, ['zeroOrMany', ...resSep.history.slice(0, surelyIndex), ...resSep.history.slice(surelyIndex + 1)]);
45
- }
46
- return success(ctx, results);
47
- }
48
- const res = item(resSep.ctx);
49
- if (isFailure(res)) {
50
- const surelyIndex = res.history.findIndex(h => h === 'surely');
51
- if (surelyIndex >= 0) {
52
- return failure(res.ctx, res.expected, ['zeroOrMany', ...res.history.slice(0, surelyIndex), ...res.history.slice(surelyIndex + 1)]);
53
- }
54
- return success(ctx, results);
55
- }
56
- ctx = res.ctx;
57
- results.push(res.value);
58
- }
59
- };
60
- }
61
- else
62
- return many(item);
63
- }
64
- /** Parses one or more occurences of the given parser, separated with the separator parser.
65
- * @returns A parser returning an array of many parses, omitting the separator.
66
- */
67
- export function oneOrMany(item, separator = undefined) {
68
- if (separator) {
69
- return (ctx) => {
70
- const results = [];
71
- const res = item(ctx);
72
- if (isFailure(res))
73
- return res;
74
- ctx = res.ctx;
75
- results.push(res.value);
76
- while (true) {
77
- const resSep = separator(ctx);
78
- if (isFailure(resSep)) {
79
- const surelyIndex = resSep.history.findIndex(h => h === 'surely');
80
- if (surelyIndex >= 0) {
81
- return failure(resSep.ctx, resSep.expected, ['oneOrMany', ...resSep.history.slice(0, surelyIndex), ...resSep.history.slice(surelyIndex + 1)]);
82
- }
83
- return success(ctx, results);
84
- }
85
- const res = item(resSep.ctx);
86
- if (isFailure(res)) {
87
- const surelyIndex = res.history.findIndex(h => h === 'surely');
88
- if (surelyIndex >= 0) {
89
- return failure(res.ctx, res.expected, ['oneOrMany', ...res.history.slice(0, surelyIndex), ...res.history.slice(surelyIndex + 1)]);
90
- }
91
- return success(ctx, results);
92
- }
93
- ctx = res.ctx;
94
- results.push(res.value);
95
- }
96
- };
97
- }
98
- else {
99
- return (ctx) => {
100
- const results = [];
101
- const res = item(ctx);
102
- if (isFailure(res))
103
- return res;
104
- ctx = res.ctx;
105
- results.push(res.value);
106
- while (true) {
107
- const res = item(ctx);
108
- if (isFailure(res)) {
109
- const surelyIndex = res.history.findIndex(h => h === 'surely');
110
- if (surelyIndex >= 0) {
111
- return failure(res.ctx, res.expected, ['oneOrMany', ...res.history.slice(0, surelyIndex), ...res.history.slice(surelyIndex + 1)]);
112
- }
113
- return success(ctx, results);
114
- }
115
- ctx = res.ctx;
116
- results.push(res.value);
117
- }
118
- };
119
- }
120
- }
121
- /** Parses one or more occurences of the given parser, separated with the separator parser.
122
- * @returns A parser returning the result of many parses, reduced using the `reducer` function passed in.
123
- */
124
- export function oneOrManyRed(item, separator, reducer) {
125
- return (ctx) => {
126
- const res = item(ctx);
127
- if (isFailure(res))
128
- return res;
129
- ctx = res.ctx;
130
- let result = res.value;
131
- while (true) {
132
- const resSep = separator(ctx);
133
- if (isFailure(resSep)) {
134
- const surelyIndex = resSep.history.findIndex(h => h === 'surely');
135
- if (surelyIndex >= 0) {
136
- return failure(resSep.ctx, resSep.expected, ['oneOrManyRed', ...resSep.history.slice(0, surelyIndex), ...resSep.history.slice(surelyIndex + 1)]);
137
- }
138
- return success(ctx, result);
139
- }
140
- const res = item(resSep.ctx);
141
- if (isFailure(res)) {
142
- const surelyIndex = res.history.findIndex(h => h === 'surely');
143
- if (surelyIndex >= 0) {
144
- return failure(res.ctx, res.expected, ['oneOrManyRed', ...res.history.slice(0, surelyIndex), ...res.history.slice(surelyIndex + 1)]);
145
- }
146
- return success(ctx, result);
147
- }
148
- ctx = res.ctx;
149
- try {
150
- result = reducer(result, res.value, resSep.value);
151
- }
152
- catch {
153
- return failure(res.ctx, 'Error while reducing', ['oneOrManyRed']);
154
- }
155
- }
156
- };
157
- }
@@ -0,0 +1,5 @@
1
+ import { Parser } from "../types";
2
+ /** Parses one or more occurences of the given parser, separated with the separator parser.
3
+ * @returns A parser returning an array of many parses, omitting the separator.
4
+ */
5
+ export declare function oneOrMany<T, V>(item: Parser<T>, separator?: Parser<V> | undefined): Parser<T[]>;
@@ -0,0 +1,63 @@
1
+ import { failure, isFailure, success } from "../types";
2
+ /** Parses one or more occurences of the given parser, separated with the separator parser.
3
+ * @returns A parser returning an array of many parses, omitting the separator.
4
+ */
5
+ export function oneOrMany(item, separator = undefined) {
6
+ if (separator) {
7
+ return (ctx) => {
8
+ const results = [];
9
+ const res = item(ctx);
10
+ if (isFailure(res)) {
11
+ return failure(res.ctx, res.expected, ['oneOrMany', ...res.history]);
12
+ }
13
+ ctx = res.ctx;
14
+ results.push(res.value);
15
+ while (true) {
16
+ const resSep = separator(ctx);
17
+ if (isFailure(resSep)) {
18
+ const surelyIndex = resSep.history.findIndex(h => h === 'surely');
19
+ // Stryker disable next-line EqualityOperator: The > mutant results in an equivalent mutant
20
+ if (surelyIndex >= 0) {
21
+ return failure(resSep.ctx, resSep.expected, ['oneOrMany', ...resSep.history.slice(0, surelyIndex), ...resSep.history.slice(surelyIndex + 1)]);
22
+ }
23
+ return success(ctx, results);
24
+ }
25
+ const res = item(resSep.ctx);
26
+ if (isFailure(res)) {
27
+ const surelyIndex = res.history.findIndex(h => h === 'surely');
28
+ // Stryker disable next-line EqualityOperator: The > mutant results in an equivalent mutant
29
+ if (surelyIndex >= 0) {
30
+ return failure(res.ctx, res.expected, ['oneOrMany', ...res.history.slice(0, surelyIndex), ...res.history.slice(surelyIndex + 1)]);
31
+ }
32
+ return success(ctx, results);
33
+ }
34
+ ctx = res.ctx;
35
+ results.push(res.value);
36
+ }
37
+ };
38
+ }
39
+ else {
40
+ return (ctx) => {
41
+ const results = [];
42
+ const res = item(ctx);
43
+ if (isFailure(res)) {
44
+ return failure(res.ctx, res.expected, ['oneOrMany', ...res.history]);
45
+ }
46
+ ctx = res.ctx;
47
+ results.push(res.value);
48
+ while (true) {
49
+ const res = item(ctx);
50
+ if (isFailure(res)) {
51
+ const surelyIndex = res.history.findIndex(h => h === 'surely');
52
+ // Stryker disable next-line EqualityOperator: The > mutant results in an equivalent mutant
53
+ if (surelyIndex >= 0) {
54
+ return failure(res.ctx, res.expected, ['oneOrMany', ...res.history.slice(0, surelyIndex), ...res.history.slice(surelyIndex + 1)]);
55
+ }
56
+ return success(ctx, results);
57
+ }
58
+ ctx = res.ctx;
59
+ results.push(res.value);
60
+ }
61
+ };
62
+ }
63
+ }
@@ -0,0 +1,5 @@
1
+ import { Parser } from "../types";
2
+ /** Parses one or more occurences of the given parser, separated with the separator parser.
3
+ * @returns A parser returning the result of many parses, reduced using the `reducer` function passed in.
4
+ */
5
+ export declare function oneOrManyRed<T, V, U = T>(item: Parser<T>, separator: Parser<V>, reducer: (left: U | T, right: T, sep: V) => U): Parser<U | T>;
@@ -0,0 +1,41 @@
1
+ import { failure, isFailure, success } from "../types";
2
+ /** Parses one or more occurences of the given parser, separated with the separator parser.
3
+ * @returns A parser returning the result of many parses, reduced using the `reducer` function passed in.
4
+ */
5
+ export function oneOrManyRed(item, separator, reducer) {
6
+ return (ctx) => {
7
+ const res = item(ctx);
8
+ if (isFailure(res)) {
9
+ return failure(res.ctx, res.expected, ['oneOrManyRed', ...res.history]);
10
+ }
11
+ ctx = res.ctx;
12
+ let result = res.value;
13
+ while (true) {
14
+ const resSep = separator(ctx);
15
+ if (isFailure(resSep)) {
16
+ const surelyIndex = resSep.history.findIndex(h => h === 'surely');
17
+ // Stryker disable next-line EqualityOperator: The > mutant results in an equivalent mutant
18
+ if (surelyIndex >= 0) {
19
+ return failure(resSep.ctx, resSep.expected, ['oneOrManyRed', ...resSep.history.slice(0, surelyIndex), ...resSep.history.slice(surelyIndex + 1)]);
20
+ }
21
+ return success(ctx, result);
22
+ }
23
+ const res = item(resSep.ctx);
24
+ if (isFailure(res)) {
25
+ const surelyIndex = res.history.findIndex(h => h === 'surely');
26
+ // Stryker disable next-line EqualityOperator: The > mutant results in an equivalent mutant
27
+ if (surelyIndex >= 0) {
28
+ return failure(res.ctx, res.expected, ['oneOrManyRed', ...res.history.slice(0, surelyIndex), ...res.history.slice(surelyIndex + 1)]);
29
+ }
30
+ return success(ctx, result);
31
+ }
32
+ ctx = res.ctx;
33
+ try {
34
+ result = reducer(result, res.value, resSep.value);
35
+ }
36
+ catch {
37
+ return failure(res.ctx, 'Error while reducing', ['oneOrManyRed']);
38
+ }
39
+ }
40
+ };
41
+ }
@@ -0,0 +1,7 @@
1
+ import { Parser } from "../types";
2
+ export type Json = string | number | boolean | null | {
3
+ [key: number]: Json;
4
+ } | {
5
+ [key: string]: Json;
6
+ };
7
+ export declare const json: Parser<Json>;
@@ -0,0 +1,43 @@
1
+ import { any } from "./any";
2
+ import { between } from "./between";
3
+ import { zeroOrMany } from "./zeroOrMany";
4
+ import { map } from "./map";
5
+ import { regex } from "./regex";
6
+ import { seq } from "./seq";
7
+ import { str } from "./str";
8
+ import { lazy, surely } from "./utilities";
9
+ const WhiteSpace = regex(/\s*/m, 'whitespace');
10
+ const True = map(str("true"), () => true);
11
+ const False = map(str("false"), () => false);
12
+ const Null = map(str("null"), () => null);
13
+ const LCurly = str("{");
14
+ const RCurly = surely(str("}"));
15
+ const LSquare = str("[");
16
+ const RSquare = surely(str("]"));
17
+ const Quote = str('"');
18
+ const Comma = str(",");
19
+ const Colon = surely(str(":"));
20
+ const replacements = {
21
+ '\\\\': '\\',
22
+ '\\0': '\0',
23
+ '\\b': '\b',
24
+ '\\f': '\f',
25
+ '\\n': '\n',
26
+ '\\r': '\r',
27
+ '\\t': '\t',
28
+ '\\v': '\v',
29
+ '\\"': '"'
30
+ };
31
+ const StringLiteral = between(Quote, map(regex(/(?:[^\\"]|\\(?:[0bfnrtv"\\]|u[0-9a-fA-F]{4}))*/, 'string literal'), str => str.replace(/\\(?:[0bfnrtv"\\]|u[0-9a-fA-F]{4})/g, function (replace) {
32
+ const tabled = replacements[replace];
33
+ if (tabled != null) {
34
+ return tabled;
35
+ }
36
+ return String.fromCharCode(parseInt(replace.slice(2), 16));
37
+ })), Quote);
38
+ const NumberLiteral = map(regex(/-?(?:0|(?:[1-9]\d*))(?:\.\d+)?(?:[eE][+-]?\d+)?/, 'number literal'), parseFloat);
39
+ const JArray = lazy(() => map(seq(LSquare, surely(seq(WhiteSpace, zeroOrMany(Value, seq(WhiteSpace, Comma, WhiteSpace)), WhiteSpace, RSquare))), (data) => data[1][1]));
40
+ const JObject = lazy(() => map(seq(LCurly, surely(seq(WhiteSpace, zeroOrMany(ObjectEntry, seq(WhiteSpace, Comma, WhiteSpace)), WhiteSpace, RCurly))), data => Object.fromEntries(data[1][1])));
41
+ const Value = any(StringLiteral, NumberLiteral, JObject, JArray, True, False, Null);
42
+ const ObjectEntry = map(seq(StringLiteral, surely(seq(WhiteSpace, Colon, WhiteSpace, Value))), ([key, rest]) => [key, rest[3]]);
43
+ export const json = between(WhiteSpace, Value, WhiteSpace);
@@ -7,7 +7,7 @@ export function regex(match, expected) {
7
7
  return (ctx) => {
8
8
  regexp.lastIndex = ctx.index;
9
9
  const regexMatch = regexp.exec(ctx.text);
10
- if (regexMatch !== null && regexMatch.index === ctx.index) {
10
+ if (regexMatch !== null) {
11
11
  return success({ ...ctx, index: ctx.index + regexMatch[0].length }, regexMatch[0]);
12
12
  }
13
13
  else {
@@ -6,7 +6,8 @@ export function ref(parser, check, expected) {
6
6
  return (ctx) => {
7
7
  const res = parser(ctx);
8
8
  if (!isFailure(res) && !check(res.value)) {
9
- return failure(res.ctx, expected ?? 'check', [`ref: ${expected ?? 'check'}`]);
9
+ const phrase = expected ?? 'check';
10
+ return failure(res.ctx, phrase, [`ref: ${phrase}`]);
10
11
  }
11
12
  return res;
12
13
  };
@@ -0,0 +1,5 @@
1
+ import { Parser } from "../types";
2
+ /** Parses zero or more occurences of the given parser, separated with the separator parser.
3
+ * @returns A parser returning an array of many parses, omitting the separator.
4
+ */
5
+ export declare function zeroOrMany<T, V>(item: Parser<T>, separator?: Parser<V> | undefined): Parser<T[]>;
@@ -0,0 +1,61 @@
1
+ import { failure, isFailure, success } from "../types";
2
+ /** Parses zero or more occurences of the given parser, separated with the separator parser.
3
+ * @returns A parser returning an array of many parses, omitting the separator.
4
+ */
5
+ export function zeroOrMany(item, separator = undefined) {
6
+ if (separator) {
7
+ return (ctx) => {
8
+ const results = [];
9
+ const res = item(ctx);
10
+ if (isFailure(res)) {
11
+ const surelyIndex = res.history.findIndex(h => h === 'surely');
12
+ // Stryker disable next-line EqualityOperator: The > mutant results in an equivalent mutant
13
+ if (surelyIndex >= 0) {
14
+ return failure(res.ctx, res.expected, ['zeroOrMany', ...res.history.slice(0, surelyIndex), ...res.history.slice(surelyIndex + 1)]);
15
+ }
16
+ return success(ctx, results);
17
+ }
18
+ ctx = res.ctx;
19
+ results.push(res.value);
20
+ while (true) {
21
+ const resSep = separator(ctx);
22
+ if (isFailure(resSep)) {
23
+ const surelyIndex = resSep.history.findIndex(h => h === 'surely');
24
+ // Stryker disable next-line EqualityOperator: The > mutant results in an equivalent mutant
25
+ if (surelyIndex >= 0) {
26
+ return failure(resSep.ctx, resSep.expected, ['zeroOrMany', ...resSep.history.slice(0, surelyIndex), ...resSep.history.slice(surelyIndex + 1)]);
27
+ }
28
+ return success(ctx, results);
29
+ }
30
+ const res = item(resSep.ctx);
31
+ if (isFailure(res)) {
32
+ const surelyIndex = res.history.findIndex(h => h === 'surely');
33
+ // Stryker disable next-line EqualityOperator: The > mutant results in an equivalent mutant
34
+ if (surelyIndex >= 0) {
35
+ return failure(res.ctx, res.expected, ['zeroOrMany', ...res.history.slice(0, surelyIndex), ...res.history.slice(surelyIndex + 1)]);
36
+ }
37
+ return success(ctx, results);
38
+ }
39
+ ctx = res.ctx;
40
+ results.push(res.value);
41
+ }
42
+ };
43
+ }
44
+ else
45
+ return (ctx) => {
46
+ const results = [];
47
+ while (true) {
48
+ const res = item(ctx);
49
+ if (isFailure(res)) {
50
+ const surelyIndex = res.history.findIndex(h => h === 'surely');
51
+ // Stryker disable next-line EqualityOperator: The > mutant results in an equivalent mutant
52
+ if (surelyIndex >= 0) {
53
+ return failure(res.ctx, res.expected, ['zeroOrMany', ...res.history.slice(0, surelyIndex), ...res.history.slice(surelyIndex + 1)]);
54
+ }
55
+ return success(ctx, results);
56
+ }
57
+ ctx = res.ctx;
58
+ results.push(res.value);
59
+ }
60
+ };
61
+ }
@@ -16,6 +16,7 @@ export type Failure = Readonly<{
16
16
  ctx: Context;
17
17
  history: string[];
18
18
  }>;
19
+ export type ParseResult<T extends Parser<unknown>> = T extends Parser<infer P> ? P : never;
19
20
  export type TokenRange = {
20
21
  start: number;
21
22
  end: number;
package/package.json CHANGED
@@ -1,61 +1,61 @@
1
- {
2
- "name": "parser-combinators",
3
- "version": "1.2.5",
4
- "license": "ISC",
5
- "maintainers": [
6
- "Micha_i"
7
- ],
8
- "repository": {
9
- "type": "git",
10
- "url": "git+https://github.com/michalusio/Parser.git"
11
- },
12
- "bugs": {
13
- "url": "https://github.com/michalusio/Parser/issues"
14
- },
15
- "homepage": "https://github.com/michalusio/Parser#readme",
16
- "description": "A library of parser combinators, with which you can create your own parsers. The library will be continuously improved in time.",
17
- "scripts": {
18
- "start": "tsc && node .",
19
- "lint": "eslint src --ext .ts",
20
- "build": "tsc",
21
- "build-esm": "tsc --project tsconfig.esm.json",
22
- "bundle": "npm run lint && npm run build && npm run build-esm",
23
- "test:mutate": "stryker run",
24
- "test:unit": "mocha",
25
- "test": "nyc -e '.ts' --r html -r lcov -r text npm run test:unit"
26
- },
27
- "author": "Micha_i <isalski.michal@gmail.com> (https://github.com/michalusio)",
28
- "main": "./dist/index.js",
29
- "types": "./dist/index.d.ts",
30
- "type": "commonjs",
31
- "engines": {
32
- "node": ">=18"
33
- },
34
- "devDependencies": {
35
- "@stryker-mutator/core": "^9.4.0",
36
- "@stryker-mutator/mocha-runner": "^9.4.0",
37
- "@stryker-mutator/typescript-checker": "^9.4.0",
38
- "@types/mocha": "10.0.10",
39
- "@types/node": "25.0.9",
40
- "cross-env": "10.1.0",
41
- "esbuild": "0.27.2",
42
- "eslint": "9.39.2",
43
- "mocha": "11.7.5",
44
- "nyc": "17.1.0",
45
- "ts-node": "10.9.2",
46
- "typescript": "5.9.3",
47
- "typescript-eslint": "8.53.0"
48
- },
49
- "keywords": [
50
- "parser",
51
- "combinator",
52
- "parser-combinator",
53
- "parsing",
54
- "combining",
55
- "functional"
56
- ],
57
- "prettier": {
58
- "tabWidth": 4,
59
- "useTabs": false
60
- }
61
- }
1
+ {
2
+ "name": "parser-combinators",
3
+ "version": "1.2.6",
4
+ "license": "ISC",
5
+ "maintainers": [
6
+ "Micha_i"
7
+ ],
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/michalusio/Parser.git"
11
+ },
12
+ "bugs": {
13
+ "url": "https://github.com/michalusio/Parser/issues"
14
+ },
15
+ "homepage": "https://github.com/michalusio/Parser#readme",
16
+ "description": "A library of parser combinators, with which you can create your own parsers. The library will be continuously improved in time.",
17
+ "scripts": {
18
+ "start": "tsc && node .",
19
+ "lint": "eslint src --ext .ts",
20
+ "build": "tsc",
21
+ "build-esm": "tsc --project tsconfig.esm.json",
22
+ "bundle": "npm run lint && npm run build && npm run build-esm",
23
+ "test:mutate": "stryker run",
24
+ "test:unit": "mocha",
25
+ "test": "nyc -e '.ts' --r html -r lcov -r text npm run test:unit"
26
+ },
27
+ "author": "Micha_i <isalski.michal@gmail.com> (https://github.com/michalusio)",
28
+ "main": "./dist/index.js",
29
+ "types": "./dist/index.d.ts",
30
+ "type": "commonjs",
31
+ "engines": {
32
+ "node": ">=18"
33
+ },
34
+ "devDependencies": {
35
+ "@stryker-mutator/core": "^9.5.0",
36
+ "@stryker-mutator/mocha-runner": "^9.5.0",
37
+ "@stryker-mutator/typescript-checker": "^9.5.0",
38
+ "@types/mocha": "10.0.10",
39
+ "@types/node": "25.1.0",
40
+ "cross-env": "10.1.0",
41
+ "esbuild": "0.27.2",
42
+ "eslint": "9.39.2",
43
+ "mocha": "11.7.5",
44
+ "nyc": "17.1.0",
45
+ "ts-node": "10.9.2",
46
+ "typescript": "5.9.3",
47
+ "typescript-eslint": "8.54.0"
48
+ },
49
+ "keywords": [
50
+ "parser",
51
+ "combinator",
52
+ "parser-combinator",
53
+ "parsing",
54
+ "combining",
55
+ "functional"
56
+ ],
57
+ "prettier": {
58
+ "tabWidth": 4,
59
+ "useTabs": false
60
+ }
61
+ }