parser-combinators 1.2.3 → 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.
Files changed (37) hide show
  1. package/dist/parser.js +1 -1
  2. package/dist/parsers/any.js +4 -2
  3. package/dist/parsers/anyString.js +11 -16
  4. package/dist/parsers/index.d.ts +4 -0
  5. package/dist/parsers/index.js +4 -0
  6. package/dist/parsers/many.d.ts +0 -12
  7. package/dist/parsers/many.js +5 -107
  8. package/dist/parsers/oneOrMany.d.ts +5 -0
  9. package/dist/parsers/oneOrMany.js +66 -0
  10. package/dist/parsers/oneOrManyRed.d.ts +5 -0
  11. package/dist/parsers/oneOrManyRed.js +44 -0
  12. package/dist/parsers/readymade.d.ts +7 -0
  13. package/dist/parsers/readymade.js +46 -0
  14. package/dist/parsers/regex.js +1 -1
  15. package/dist/parsers/utilities.js +2 -1
  16. package/dist/parsers/zeroOrMany.d.ts +5 -0
  17. package/dist/parsers/zeroOrMany.js +64 -0
  18. package/dist/types.d.ts +1 -0
  19. package/dist-esm/parser.js +1 -1
  20. package/dist-esm/parsers/any.js +4 -2
  21. package/dist-esm/parsers/anyString.js +11 -16
  22. package/dist-esm/parsers/index.d.ts +4 -0
  23. package/dist-esm/parsers/index.js +4 -0
  24. package/dist-esm/parsers/many.d.ts +0 -12
  25. package/dist-esm/parsers/many.js +5 -104
  26. package/dist-esm/parsers/oneOrMany.d.ts +5 -0
  27. package/dist-esm/parsers/oneOrMany.js +63 -0
  28. package/dist-esm/parsers/oneOrManyRed.d.ts +5 -0
  29. package/dist-esm/parsers/oneOrManyRed.js +41 -0
  30. package/dist-esm/parsers/readymade.d.ts +7 -0
  31. package/dist-esm/parsers/readymade.js +43 -0
  32. package/dist-esm/parsers/regex.js +1 -1
  33. package/dist-esm/parsers/utilities.js +2 -1
  34. package/dist-esm/parsers/zeroOrMany.d.ts +5 -0
  35. package/dist-esm/parsers/zeroOrMany.js +61 -0
  36. package/dist-esm/types.d.ts +1 -0
  37. package/package.json +61 -61
package/dist/parser.js CHANGED
@@ -12,7 +12,7 @@ const types_1 = require("./types");
12
12
  function ParseText(text, parser, path = '') {
13
13
  const res = parser({ text, path, index: 0 });
14
14
  if ((0, types_1.isFailure)(res)) {
15
- throw new types_1.ParseError(`Parse error, expected ${[...res.history].pop()} at char ${res.ctx.index}`, text, res.ctx.index, res.history);
15
+ throw new types_1.ParseError(`Parse error, expected ${res.history[res.history.length - 1]} at char ${res.ctx.index}`, text, res.ctx.index, res.history);
16
16
  }
17
17
  if (res.ctx.index !== text.length) {
18
18
  throw new types_1.ParseError(`Parse error, expected end of text at char ${res.ctx.index}`, text, res.ctx.index, []);
@@ -22,8 +22,10 @@ function any(...parsers) {
22
22
  for (const parser of parsers) {
23
23
  const res = parser(ctx);
24
24
  if ((0, types_1.isFailure)(res)) {
25
- if (res.history.includes('surely')) {
26
- return (0, types_1.failure)(res.ctx, res.expected, res.history.filter(h => h !== 'surely'));
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 (0, types_1.failure)(res.ctx, res.expected, ['any', ...res.history.slice(0, surelyIndex), ...res.history.slice(surelyIndex + 1)]);
27
29
  }
28
30
  expected.push(res);
29
31
  }
@@ -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.
@@ -14,114 +11,15 @@ function many(parser) {
14
11
  while (true) {
15
12
  const res = parser(ctx);
16
13
  if ((0, types_1.isFailure)(res)) {
17
- return (0, types_1.success)(ctx, results);
18
- }
19
- ctx = res.ctx;
20
- results.push(res.value);
21
- }
22
- };
23
- }
24
- /** Parses zero or more occurences of the given parser, separated with the separator parser.
25
- * @returns A parser returning an array of many parses, omitting the separator.
26
- */
27
- function zeroOrMany(item, separator = undefined) {
28
- if (separator) {
29
- return (ctx) => {
30
- const results = [];
31
- const res = item(ctx);
32
- if ((0, types_1.isFailure)(res)) {
33
- return (0, types_1.success)(ctx, results);
34
- }
35
- ctx = res.ctx;
36
- results.push(res.value);
37
- while (true) {
38
- const resSep = separator(ctx);
39
- if ((0, types_1.isFailure)(resSep)) {
40
- return (0, types_1.success)(ctx, results);
41
- }
42
- const res = item(resSep.ctx);
43
- if ((0, types_1.isFailure)(res)) {
44
- return (0, types_1.success)(ctx, results);
45
- }
46
- ctx = res.ctx;
47
- results.push(res.value);
48
- }
49
- };
50
- }
51
- else
52
- return many(item);
53
- }
54
- /** Parses one or more occurences of the given parser, separated with the separator parser.
55
- * @returns A parser returning an array of many parses, omitting the separator.
56
- */
57
- function oneOrMany(item, separator = undefined) {
58
- if (separator) {
59
- return (ctx) => {
60
- const results = [];
61
- const res = item(ctx);
62
- if ((0, types_1.isFailure)(res))
63
- return res;
64
- ctx = res.ctx;
65
- results.push(res.value);
66
- while (true) {
67
- const resSep = separator(ctx);
68
- if ((0, types_1.isFailure)(resSep)) {
69
- return (0, types_1.success)(ctx, results);
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, ['many', ...res.history.slice(0, surelyIndex), ...res.history.slice(surelyIndex + 1)]);
70
18
  }
71
- const res = item(resSep.ctx);
72
- if ((0, types_1.isFailure)(res)) {
73
- return (0, types_1.success)(ctx, results);
74
- }
75
- ctx = res.ctx;
76
- results.push(res.value);
19
+ return (0, types_1.success)(ctx, results);
77
20
  }
78
- };
79
- }
80
- else {
81
- return (ctx) => {
82
- const results = [];
83
- const res = item(ctx);
84
- if ((0, types_1.isFailure)(res))
85
- return res;
86
21
  ctx = res.ctx;
87
22
  results.push(res.value);
88
- while (true) {
89
- const res = item(ctx);
90
- if ((0, types_1.isFailure)(res)) {
91
- return (0, types_1.success)(ctx, results);
92
- }
93
- ctx = res.ctx;
94
- results.push(res.value);
95
- }
96
- };
97
- }
98
- }
99
- /** Parses one or more occurences of the given parser, separated with the separator parser.
100
- * @returns A parser returning the result of many parses, reduced using the `reducer` function passed in.
101
- */
102
- function oneOrManyRed(item, separator, reducer) {
103
- return (ctx) => {
104
- const res = item(ctx);
105
- if ((0, types_1.isFailure)(res))
106
- return res;
107
- ctx = res.ctx;
108
- let result = res.value;
109
- while (true) {
110
- const resSep = separator(ctx);
111
- if ((0, types_1.isFailure)(resSep)) {
112
- return (0, types_1.success)(ctx, result);
113
- }
114
- const res = item(resSep.ctx);
115
- if ((0, types_1.isFailure)(res)) {
116
- return (0, types_1.success)(ctx, result);
117
- }
118
- ctx = res.ctx;
119
- try {
120
- result = reducer(result, res.value, resSep.value);
121
- }
122
- catch {
123
- return (0, types_1.failure)(res.ctx, 'Error while reducing', ['oneOrManyRed']);
124
- }
125
23
  }
126
24
  };
127
25
  }
@@ -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;
@@ -9,7 +9,7 @@ import { isFailure, ParseError } from './types';
9
9
  export function ParseText(text, parser, path = '') {
10
10
  const res = parser({ text, path, index: 0 });
11
11
  if (isFailure(res)) {
12
- throw new ParseError(`Parse error, expected ${[...res.history].pop()} at char ${res.ctx.index}`, text, res.ctx.index, res.history);
12
+ throw new ParseError(`Parse error, expected ${res.history[res.history.length - 1]} at char ${res.ctx.index}`, text, res.ctx.index, res.history);
13
13
  }
14
14
  if (res.ctx.index !== text.length) {
15
15
  throw new ParseError(`Parse error, expected end of text at char ${res.ctx.index}`, text, res.ctx.index, []);
@@ -19,8 +19,10 @@ export function any(...parsers) {
19
19
  for (const parser of parsers) {
20
20
  const res = parser(ctx);
21
21
  if (isFailure(res)) {
22
- if (res.history.includes('surely')) {
23
- return failure(res.ctx, res.expected, res.history.filter(h => h !== 'surely'));
22
+ const surelyIndex = res.history.findIndex(h => h === 'surely');
23
+ // Stryker disable next-line EqualityOperator: The > mutant results in an equivalent mutant
24
+ if (surelyIndex >= 0) {
25
+ return failure(res.ctx, res.expected, ['any', ...res.history.slice(0, surelyIndex), ...res.history.slice(surelyIndex + 1)]);
24
26
  }
25
27
  expected.push(res);
26
28
  }
@@ -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>;
@@ -8,114 +8,15 @@ export function many(parser) {
8
8
  while (true) {
9
9
  const res = parser(ctx);
10
10
  if (isFailure(res)) {
11
- return success(ctx, results);
12
- }
13
- ctx = res.ctx;
14
- results.push(res.value);
15
- }
16
- };
17
- }
18
- /** Parses zero or more occurences of the given parser, separated with the separator parser.
19
- * @returns A parser returning an array of many parses, omitting the separator.
20
- */
21
- export function zeroOrMany(item, separator = undefined) {
22
- if (separator) {
23
- return (ctx) => {
24
- const results = [];
25
- const res = item(ctx);
26
- if (isFailure(res)) {
27
- return success(ctx, results);
28
- }
29
- ctx = res.ctx;
30
- results.push(res.value);
31
- while (true) {
32
- const resSep = separator(ctx);
33
- if (isFailure(resSep)) {
34
- return success(ctx, results);
35
- }
36
- const res = item(resSep.ctx);
37
- if (isFailure(res)) {
38
- return success(ctx, results);
39
- }
40
- ctx = res.ctx;
41
- results.push(res.value);
42
- }
43
- };
44
- }
45
- else
46
- return many(item);
47
- }
48
- /** Parses one or more occurences of the given parser, separated with the separator parser.
49
- * @returns A parser returning an array of many parses, omitting the separator.
50
- */
51
- export function oneOrMany(item, separator = undefined) {
52
- if (separator) {
53
- return (ctx) => {
54
- const results = [];
55
- const res = item(ctx);
56
- if (isFailure(res))
57
- return res;
58
- ctx = res.ctx;
59
- results.push(res.value);
60
- while (true) {
61
- const resSep = separator(ctx);
62
- if (isFailure(resSep)) {
63
- return success(ctx, results);
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, ['many', ...res.history.slice(0, surelyIndex), ...res.history.slice(surelyIndex + 1)]);
64
15
  }
65
- const res = item(resSep.ctx);
66
- if (isFailure(res)) {
67
- return success(ctx, results);
68
- }
69
- ctx = res.ctx;
70
- results.push(res.value);
16
+ return success(ctx, results);
71
17
  }
72
- };
73
- }
74
- else {
75
- return (ctx) => {
76
- const results = [];
77
- const res = item(ctx);
78
- if (isFailure(res))
79
- return res;
80
18
  ctx = res.ctx;
81
19
  results.push(res.value);
82
- while (true) {
83
- const res = item(ctx);
84
- if (isFailure(res)) {
85
- return success(ctx, results);
86
- }
87
- ctx = res.ctx;
88
- results.push(res.value);
89
- }
90
- };
91
- }
92
- }
93
- /** Parses one or more occurences of the given parser, separated with the separator parser.
94
- * @returns A parser returning the result of many parses, reduced using the `reducer` function passed in.
95
- */
96
- export function oneOrManyRed(item, separator, reducer) {
97
- return (ctx) => {
98
- const res = item(ctx);
99
- if (isFailure(res))
100
- return res;
101
- ctx = res.ctx;
102
- let result = res.value;
103
- while (true) {
104
- const resSep = separator(ctx);
105
- if (isFailure(resSep)) {
106
- return success(ctx, result);
107
- }
108
- const res = item(resSep.ctx);
109
- if (isFailure(res)) {
110
- return success(ctx, result);
111
- }
112
- ctx = res.ctx;
113
- try {
114
- result = reducer(result, res.value, resSep.value);
115
- }
116
- catch {
117
- return failure(res.ctx, 'Error while reducing', ['oneOrManyRed']);
118
- }
119
20
  }
120
21
  };
121
22
  }
@@ -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.3",
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
+ }