@elyukai/utils 0.2.8 → 0.2.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +13 -0
- package/dist/array/filters.js +4 -4
- package/dist/array/generators.js +2 -2
- package/dist/array/reductions.js +2 -2
- package/dist/async.js +2 -2
- package/dist/classList.js +1 -1
- package/dist/equality.js +3 -8
- package/dist/function.js +2 -2
- package/dist/maybe.js +2 -4
- package/dist/nullable.js +1 -1
- package/dist/object.js +1 -1
- package/dist/parser.d.ts +146 -0
- package/dist/parser.js +219 -0
- package/dist/reader.js +10 -10
- package/dist/result.js +3 -3
- package/dist/state.d.ts +51 -0
- package/dist/state.js +79 -0
- package/dist/stateParser.d.ts +143 -0
- package/dist/stateParser.js +219 -0
- package/dist/string/number.js +3 -11
- package/dist/string.js +6 -13
- package/package.json +5 -5
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,19 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file. See [commit-and-tag-version](https://github.com/absolute-version/commit-and-tag-version) for commit guidelines.
|
|
4
4
|
|
|
5
|
+
## [0.2.9](https://github.com/elyukai/ts-utils/compare/v0.2.8...v0.2.9) (2026-03-02)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
### Features
|
|
9
|
+
|
|
10
|
+
* add simple parser combinator class ([33ead55](https://github.com/elyukai/ts-utils/commit/33ead55758fb5cb8dc20de2d53a69f1973ec3c3e))
|
|
11
|
+
* extend parser, add state and combine both ([dd9a3f6](https://github.com/elyukai/ts-utils/commit/dd9a3f680c2b80658aff19103ecbfa3a4d81bdaf))
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
### Bug Fixes
|
|
15
|
+
|
|
16
|
+
* slow type ([e8d6fb6](https://github.com/elyukai/ts-utils/commit/e8d6fb63e79937a01b8f15441147bc2b72686e97))
|
|
17
|
+
|
|
5
18
|
## [0.2.8](https://github.com/elyukai/ts-utils/compare/v0.2.7...v0.2.8) (2026-02-24)
|
|
6
19
|
|
|
7
20
|
## [0.2.7](https://github.com/elyukai/ts-utils/compare/v0.2.6...v0.2.7) (2026-02-24)
|
package/dist/array/filters.js
CHANGED
|
@@ -11,17 +11,17 @@ export const unique = (arr) => Array.from(new Set(arr));
|
|
|
11
11
|
/**
|
|
12
12
|
* Checks if there are any duplicate elements in the array.
|
|
13
13
|
*/
|
|
14
|
-
export const anySame = (arr, equalityCheck = (a, b) => a === b) => arr.some((item, index) => arr.findIndex(
|
|
14
|
+
export const anySame = (arr, equalityCheck = (a, b) => a === b) => arr.some((item, index) => arr.findIndex(other => equalityCheck(item, other)) !== index);
|
|
15
15
|
/**
|
|
16
16
|
* Checks if there are any duplicate elements in the array and returns an array
|
|
17
17
|
* of found duplicates where the values are the indices of these values.
|
|
18
18
|
*/
|
|
19
19
|
export const anySameIndices = (arr, equalityCheck = (a, b) => a === b) => arr.reduce((acc, item, index) => {
|
|
20
|
-
const firstIndex = arr.findIndex(
|
|
20
|
+
const firstIndex = arr.findIndex(other => equalityCheck(item, other));
|
|
21
21
|
if (firstIndex === index) {
|
|
22
22
|
return acc;
|
|
23
23
|
}
|
|
24
|
-
const accIndex = acc.findIndex(
|
|
24
|
+
const accIndex = acc.findIndex(accElem => accElem[0] === firstIndex);
|
|
25
25
|
return accIndex === -1
|
|
26
26
|
? [...acc, [firstIndex, index]]
|
|
27
27
|
: // eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- The index must exist according to the findIndex above
|
|
@@ -34,4 +34,4 @@ export const anySameIndices = (arr, equalityCheck = (a, b) => a === b) => arr.re
|
|
|
34
34
|
* @param equalityCheck An optional function to determine if two elements are considered the same. Defaults to strict shallow equality.
|
|
35
35
|
* @returns `true` if all elements in the array are the same, otherwise `false`.
|
|
36
36
|
*/
|
|
37
|
-
export const allSame = (arr, equalityCheck = (a, b) => a === b) => isNotEmpty(arr) ? arr.every(
|
|
37
|
+
export const allSame = (arr, equalityCheck = (a, b) => a === b) => (isNotEmpty(arr) ? arr.every(item => equalityCheck(item, arr[0])) : true);
|
package/dist/array/generators.js
CHANGED
|
@@ -12,6 +12,6 @@
|
|
|
12
12
|
*/
|
|
13
13
|
export const flatCombine = (arr) => arr.length === 0
|
|
14
14
|
? []
|
|
15
|
-
: arr.slice(1).reduce((acc, elem) => elem.flatMap(
|
|
15
|
+
: arr.slice(1).reduce((acc, elem) => elem.flatMap(elemInner => acc.map(accElem => [...accElem, elemInner])),
|
|
16
16
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- it is checked before if the array is empty
|
|
17
|
-
arr[0].map(
|
|
17
|
+
arr[0].map(elem => [elem]));
|
package/dist/array/reductions.js
CHANGED
|
@@ -50,7 +50,7 @@ export const countBy = (arr, fn) => arr.reduce((acc, value, index) => {
|
|
|
50
50
|
*/
|
|
51
51
|
export const countByMany = (arr, fn) => arr.reduce((acc, value, index) => {
|
|
52
52
|
const keys = fn(value, index);
|
|
53
|
-
unique(keys).forEach(
|
|
53
|
+
unique(keys).forEach(key => {
|
|
54
54
|
acc[key] = (acc[key] ?? 0) + 1;
|
|
55
55
|
});
|
|
56
56
|
return acc;
|
|
@@ -59,4 +59,4 @@ export const countByMany = (arr, fn) => arr.reduce((acc, value, index) => {
|
|
|
59
59
|
* Returns `true` if the array contains at least `minCount` elements that
|
|
60
60
|
* satisfy the given predicate, `false` otherwise.
|
|
61
61
|
*/
|
|
62
|
-
export const someCount = (arr, predicate, minCount) => reduceWhile(arr, (acc, value) => (predicate(value) ? acc + 1 : acc),
|
|
62
|
+
export const someCount = (arr, predicate, minCount) => reduceWhile(arr, (acc, value) => (predicate(value) ? acc + 1 : acc), acc => acc >= minCount, 0) >= minCount;
|
package/dist/async.js
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
* await wait(1000); // Waits for 1 second
|
|
13
13
|
* ```
|
|
14
14
|
*/
|
|
15
|
-
export const wait = (delay) => new Promise(
|
|
15
|
+
export const wait = (delay) => new Promise(resolve => setTimeout(resolve, delay));
|
|
16
16
|
/**
|
|
17
17
|
* A simple async map to process tasks with a concurrency limit.
|
|
18
18
|
* @param tasks The list of tasks to process.
|
|
@@ -36,7 +36,7 @@ export const mapAsync = (tasks, worker, concurrency) => new Promise((resolve, re
|
|
|
36
36
|
const task = tasks[currentIndex];
|
|
37
37
|
activeCount++;
|
|
38
38
|
worker(task)
|
|
39
|
-
.then(
|
|
39
|
+
.then(result => {
|
|
40
40
|
results[currentIndex] = result;
|
|
41
41
|
resolvedCount++;
|
|
42
42
|
activeCount--;
|
package/dist/classList.js
CHANGED
package/dist/equality.js
CHANGED
|
@@ -31,8 +31,7 @@ export const notEqual = (a, b) => !Object.is(a, b);
|
|
|
31
31
|
*
|
|
32
32
|
* Use {@link deepEqual} for a deep equality check.
|
|
33
33
|
*/
|
|
34
|
-
export const arrayEqual = (arr1, arr2) => arr1.length === arr2.length &&
|
|
35
|
-
arr1.every((value, index) => equal(value, arr2[index]));
|
|
34
|
+
export const arrayEqual = (arr1, arr2) => arr1.length === arr2.length && arr1.every((value, index) => equal(value, arr2[index]));
|
|
36
35
|
/**
|
|
37
36
|
* Checks two values for value equality. This is a deep equality check that
|
|
38
37
|
* works for all types, including objects and arrays. For objects, it only
|
|
@@ -42,16 +41,12 @@ export const deepEqual = (a, b) => {
|
|
|
42
41
|
if (equal(a, b)) {
|
|
43
42
|
return true;
|
|
44
43
|
}
|
|
45
|
-
if (typeof a === "object" &&
|
|
46
|
-
typeof b === "object" &&
|
|
47
|
-
a !== null &&
|
|
48
|
-
b !== null) {
|
|
44
|
+
if (typeof a === "object" && typeof b === "object" && a !== null && b !== null) {
|
|
49
45
|
const keys = Object.keys(a);
|
|
50
46
|
if (keys.length !== Object.keys(b).length) {
|
|
51
47
|
return false;
|
|
52
48
|
}
|
|
53
|
-
return keys.every(
|
|
54
|
-
deepEqual(a[key], b[key]));
|
|
49
|
+
return keys.every(key => key in b && deepEqual(a[key], b[key]));
|
|
55
50
|
}
|
|
56
51
|
return false;
|
|
57
52
|
};
|
package/dist/function.js
CHANGED
|
@@ -16,12 +16,12 @@ export const constant = (value) => () => value;
|
|
|
16
16
|
* Returns a function that applies the given predicates to the given value and
|
|
17
17
|
* returns `true` if all predicates return `true`.
|
|
18
18
|
*/
|
|
19
|
-
export const andEvery = (...predicates) => (value) => predicates.every(
|
|
19
|
+
export const andEvery = (...predicates) => (value) => predicates.every(predicate => predicate(value));
|
|
20
20
|
/**
|
|
21
21
|
* Returns a function that combines predicate functions disjunctionally.
|
|
22
22
|
*/
|
|
23
23
|
export function orSome(...predicates) {
|
|
24
|
-
return
|
|
24
|
+
return value => predicates.some(predicate => predicate(value));
|
|
25
25
|
}
|
|
26
26
|
/**
|
|
27
27
|
* Returns a function that applies the given predicate to the given value and
|
package/dist/maybe.js
CHANGED
|
@@ -33,12 +33,10 @@ export const map = (maybe, f) => isJust(maybe) ? Just(f(maybe.value)) : Nothing;
|
|
|
33
33
|
/**
|
|
34
34
|
* Chains a result to a new result.
|
|
35
35
|
*/
|
|
36
|
-
export const then = (maybe, f) =>
|
|
36
|
+
export const then = (maybe, f) => isJust(maybe) ? f(maybe.value) : maybe;
|
|
37
37
|
/**
|
|
38
38
|
* Combines two maybes into one maybe. If both maybes contain a value, the
|
|
39
39
|
* values are combined using the provided function. If at least one maybe
|
|
40
40
|
* contains nothing, nothing is returned.
|
|
41
41
|
*/
|
|
42
|
-
export const combine = (maybe1, maybe2, f) => isJust(maybe1) && isJust(maybe2)
|
|
43
|
-
? Just(f(maybe1.value, maybe2.value))
|
|
44
|
-
: Nothing;
|
|
42
|
+
export const combine = (maybe1, maybe2, f) => (isJust(maybe1) && isJust(maybe2) ? Just(f(maybe1.value, maybe2.value)) : Nothing);
|
package/dist/nullable.js
CHANGED
|
@@ -13,7 +13,7 @@ export const isNotNullish = (value) => !isNullish(value);
|
|
|
13
13
|
/**
|
|
14
14
|
* Maps a value to another value if it is not `null` or `undefined`.
|
|
15
15
|
*/
|
|
16
|
-
export const mapNullable = (value, map) =>
|
|
16
|
+
export const mapNullable = (value, map) => isNotNullish(value) ? map(value) : value;
|
|
17
17
|
/**
|
|
18
18
|
* Maps a value to another value if it is not `null` or `undefined`, otherwise
|
|
19
19
|
* returns a default value.
|
package/dist/object.js
CHANGED
|
@@ -24,7 +24,7 @@ export const mapObject = (object, map) => {
|
|
|
24
24
|
* Keys not present in the keys array will be placed at the end in their original order.
|
|
25
25
|
*/
|
|
26
26
|
export const sortObjectKeysByIndex = (obj, keys) => Object.fromEntries([
|
|
27
|
-
...keys.flatMap(
|
|
27
|
+
...keys.flatMap(key => (obj[key] === undefined ? [] : [[key, obj[key]]])),
|
|
28
28
|
...Object.entries(obj).filter(([key]) => !keys.includes(key)),
|
|
29
29
|
]);
|
|
30
30
|
/**
|
package/dist/parser.d.ts
ADDED
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A simple parser combinator.
|
|
3
|
+
* @module
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* The type `ParserResult<T>` represents the result of parsing a string using a parser. It is an array of tuples, where each tuple contains a parsed element of type T and the remaining unparsed string. If the parser fails to parse the input according to the defined rules, it returns an empty array.
|
|
7
|
+
*/
|
|
8
|
+
export type ParserResult<T> = [parsed: T, remaining: string][];
|
|
9
|
+
/**
|
|
10
|
+
* A class that serves as a parser combinator, allowing you to build complex parsers by combining simpler ones. The parser takes a string input and produces an array of tuples, where each tuple contains a parsed element of type T and the remaining unparsed string. If the parser fails to parse the input according to the defined rules, it returns an empty array.
|
|
11
|
+
*/
|
|
12
|
+
export declare class Parser<T> {
|
|
13
|
+
#private;
|
|
14
|
+
/**
|
|
15
|
+
* Returns a parser that applies the given function to the syntax string if it is not empty.
|
|
16
|
+
*/
|
|
17
|
+
constructor(fn: (syntax: string) => ParserResult<T>);
|
|
18
|
+
/**
|
|
19
|
+
* Parses a single character.
|
|
20
|
+
*/
|
|
21
|
+
static item: Parser<string>;
|
|
22
|
+
/**
|
|
23
|
+
* Returns a parser that always succeeds with the given element, without consuming any input.
|
|
24
|
+
*/
|
|
25
|
+
static of<T>(element: T): Parser<T>;
|
|
26
|
+
/**
|
|
27
|
+
* Transforms the result of this parser using the given function, without consuming any additional input.
|
|
28
|
+
*/
|
|
29
|
+
map<U>(f: (result: T) => U): Parser<U>;
|
|
30
|
+
/**
|
|
31
|
+
* Chains this parser with another parser that depends on the result of this parser.
|
|
32
|
+
*/
|
|
33
|
+
then<U>(f: (result: T) => Parser<U>): Parser<U>;
|
|
34
|
+
/**
|
|
35
|
+
* A parser that always fails.
|
|
36
|
+
*/
|
|
37
|
+
static zero: Parser<never>;
|
|
38
|
+
/**
|
|
39
|
+
* Combines this parser with another parser, trying this parser first and then the other parser.
|
|
40
|
+
*/
|
|
41
|
+
or(other: Parser<T>): Parser<T>;
|
|
42
|
+
/**
|
|
43
|
+
* Combines this parser with another parser, trying this parser first and then the other parser only if the first parser fails. It only returns the first successful result.
|
|
44
|
+
*/
|
|
45
|
+
orFirst(other: Parser<T>): Parser<T>;
|
|
46
|
+
/**
|
|
47
|
+
* Combines this parser with another parser, trying this parser first and then the other parser only if the first parser fails. It only returns the first successful result.
|
|
48
|
+
*
|
|
49
|
+
* The suffix ‘W’ stands for ‘widening’, as this method allows you to combine parsers with different result types.
|
|
50
|
+
*/
|
|
51
|
+
orFirstW<U>(other: Parser<U>): Parser<T | U>;
|
|
52
|
+
/**
|
|
53
|
+
* Returns a parser that tries this parser and returns its result if it succeeds, but if this parser fails, it returns a parser that always succeeds with `undefined` without consuming any input.
|
|
54
|
+
*/
|
|
55
|
+
optional(): Parser<T | undefined>;
|
|
56
|
+
/**
|
|
57
|
+
* Returns a parser that parses a character that satisfies the given predicate function.
|
|
58
|
+
*/
|
|
59
|
+
static satisfy<C extends string>(predicate: (character: string) => character is C): Parser<C>;
|
|
60
|
+
static satisfy(predicate: (character: string) => boolean): Parser<string>;
|
|
61
|
+
/**
|
|
62
|
+
* Returns a parser that parses a specific string.
|
|
63
|
+
*/
|
|
64
|
+
static string<T extends string>(string: T): Parser<T>;
|
|
65
|
+
/**
|
|
66
|
+
* Returns a parser that parses zero or more occurrences of this parser, returning an array of the parsed results.
|
|
67
|
+
*/
|
|
68
|
+
many(): Parser<T[]>;
|
|
69
|
+
/**
|
|
70
|
+
* Returns a parser that parses one or more occurrences of this parser, returning an array of the parsed results.
|
|
71
|
+
*
|
|
72
|
+
* It fails if this parser does not succeed at least once.
|
|
73
|
+
*/
|
|
74
|
+
many1(): Parser<T[]>;
|
|
75
|
+
/**
|
|
76
|
+
* Returns a parser that parses zero or more occurrences of this parser, separated by another parser, returning an array of the parsed results.
|
|
77
|
+
*/
|
|
78
|
+
separatedBy(separator: Parser<unknown>): Parser<T[]>;
|
|
79
|
+
/**
|
|
80
|
+
* Returns a parser that parses one or more occurrences of this parser, separated by another parser, returning an array of the parsed results.
|
|
81
|
+
*
|
|
82
|
+
* It fails if this parser does not succeed at least once.
|
|
83
|
+
*/
|
|
84
|
+
separatedBy1(separator: Parser<unknown>): Parser<T[]>;
|
|
85
|
+
/**
|
|
86
|
+
* Returns a parser that parses a string that matches the given regular expression pattern.
|
|
87
|
+
*
|
|
88
|
+
* The pattern must match at the beginning of the string (patterns that are designed like this might perform better), and the parser will return the matched substring as the parsed result.
|
|
89
|
+
*/
|
|
90
|
+
static regex(pattern: RegExp): Parser<string>;
|
|
91
|
+
/**
|
|
92
|
+
* A parser that parses whitepace characters.
|
|
93
|
+
*/
|
|
94
|
+
static space: Parser<string>;
|
|
95
|
+
/**
|
|
96
|
+
* A parser that parses horizontal whitepace characters.
|
|
97
|
+
*
|
|
98
|
+
* This can be useful for parsing a language where newlines are significant.
|
|
99
|
+
*/
|
|
100
|
+
static hspace: Parser<string>;
|
|
101
|
+
/**
|
|
102
|
+
* Throws away trailing whitespace characters before applying the given parser.
|
|
103
|
+
*/
|
|
104
|
+
token(): Parser<T>;
|
|
105
|
+
/**
|
|
106
|
+
* Throws away trailing horizontal whitespace characters before applying the given parser.
|
|
107
|
+
*
|
|
108
|
+
* This can be useful for parsing a language where newlines are significant.
|
|
109
|
+
*/
|
|
110
|
+
htoken(): Parser<T>;
|
|
111
|
+
/**
|
|
112
|
+
* Returns a parser that parses a specific string, ignoring trailing whitespace characters.
|
|
113
|
+
*/
|
|
114
|
+
static symb<T extends string>(symbol: T): Parser<T>;
|
|
115
|
+
/**
|
|
116
|
+
* Returns a parser that parses a specific string, ignoring trailing horizontal whitespace characters.
|
|
117
|
+
*
|
|
118
|
+
* This can be useful for parsing a language where newlines are significant.
|
|
119
|
+
*/
|
|
120
|
+
static hsymb<T extends string>(symbol: T): Parser<T>;
|
|
121
|
+
/**
|
|
122
|
+
* Creates a parser that parses a value using the given parser, surrounded by the given left and right parsers, and returns the parsed value.
|
|
123
|
+
*/
|
|
124
|
+
between<L, R>(left: Parser<L>, right: Parser<R>): Parser<T>;
|
|
125
|
+
/**
|
|
126
|
+
* Returns a parser that applies the given parser to the input string without consuming any input, returning the result of the parser if it succeeds. If the parser fails, this lookahead parser also fails.
|
|
127
|
+
*/
|
|
128
|
+
static lookahead<T>(parser: Parser<T>): Parser<T>;
|
|
129
|
+
/**
|
|
130
|
+
* Returns a parser that applies the given parser to the input string without consuming any input, returning `undefined` if it fails. If the parser succeeds, this fails instead.
|
|
131
|
+
*/
|
|
132
|
+
static negativeLookahead(parser: Parser<unknown>): Parser<undefined>;
|
|
133
|
+
/**
|
|
134
|
+
* Runs the parser on the given syntax string, ignoring any leading whitespace.
|
|
135
|
+
*
|
|
136
|
+
* A complete parse is one where the remaining unparsed string is empty. However, this method does not enforce that, and it will return all possible parses, including those that do not consume the entire input.
|
|
137
|
+
*/
|
|
138
|
+
apply(syntax: string): ParserResult<T>;
|
|
139
|
+
/**
|
|
140
|
+
* Runs the parser on the given syntax string.
|
|
141
|
+
*
|
|
142
|
+
* A complete parse is one where the remaining unparsed string is empty. However, this method does not enforce that, and it will return all possible parses, including those that do not consume the entire input.
|
|
143
|
+
*/
|
|
144
|
+
parse(syntax: string): ParserResult<T>;
|
|
145
|
+
static debugLog<T>(parser: Parser<T>): Parser<T>;
|
|
146
|
+
}
|
package/dist/parser.js
ADDED
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A simple parser combinator.
|
|
3
|
+
* @module
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* A class that serves as a parser combinator, allowing you to build complex parsers by combining simpler ones. The parser takes a string input and produces an array of tuples, where each tuple contains a parsed element of type T and the remaining unparsed string. If the parser fails to parse the input according to the defined rules, it returns an empty array.
|
|
7
|
+
*/
|
|
8
|
+
export class Parser {
|
|
9
|
+
/**
|
|
10
|
+
* The function takes a syntax string and returns an array of tuples, where each tuple contains a parsed element of type T and the remaining unparsed string. An empty array is returned if the syntax string cannot be parsed according to the defined rules.
|
|
11
|
+
*/
|
|
12
|
+
#fn;
|
|
13
|
+
/**
|
|
14
|
+
* Returns a parser that applies the given function to the syntax string if it is not empty.
|
|
15
|
+
*/
|
|
16
|
+
constructor(fn) {
|
|
17
|
+
this.#fn = fn;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Parses a single character.
|
|
21
|
+
*/
|
|
22
|
+
static item = new Parser(syntax =>
|
|
23
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- we check for empty string before accessing the first character
|
|
24
|
+
syntax.length === 0 ? [] : [[syntax[0], syntax.slice(1)]]);
|
|
25
|
+
/**
|
|
26
|
+
* Returns a parser that always succeeds with the given element, without consuming any input.
|
|
27
|
+
*/
|
|
28
|
+
static of(element) {
|
|
29
|
+
return new Parser(syntax => [[element, syntax]]);
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Transforms the result of this parser using the given function, without consuming any additional input.
|
|
33
|
+
*/
|
|
34
|
+
map(f) {
|
|
35
|
+
return new Parser(syntax => this.#fn(syntax).map(([result, remaining]) => [f(result), remaining]));
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Chains this parser with another parser that depends on the result of this parser.
|
|
39
|
+
*/
|
|
40
|
+
then(f) {
|
|
41
|
+
return new Parser(syntax => this.#fn(syntax).flatMap(([result, remaining]) => f(result).#fn(remaining)));
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* A parser that always fails.
|
|
45
|
+
*/
|
|
46
|
+
static zero = new Parser(() => []);
|
|
47
|
+
/**
|
|
48
|
+
* Combines this parser with another parser, trying this parser first and then the other parser.
|
|
49
|
+
*/
|
|
50
|
+
or(other) {
|
|
51
|
+
return new Parser(syntax => [...this.#fn(syntax), ...other.#fn(syntax)]);
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Combines this parser with another parser, trying this parser first and then the other parser only if the first parser fails. It only returns the first successful result.
|
|
55
|
+
*/
|
|
56
|
+
orFirst(other) {
|
|
57
|
+
return new Parser(syntax => {
|
|
58
|
+
const result = this.#fn(syntax);
|
|
59
|
+
return result.length > 0 ? result.slice(0, 1) : other.#fn(syntax).slice(0, 1);
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Combines this parser with another parser, trying this parser first and then the other parser only if the first parser fails. It only returns the first successful result.
|
|
64
|
+
*
|
|
65
|
+
* The suffix ‘W’ stands for ‘widening’, as this method allows you to combine parsers with different result types.
|
|
66
|
+
*/
|
|
67
|
+
orFirstW(other) {
|
|
68
|
+
return new Parser((syntax) => {
|
|
69
|
+
const result = this.#fn(syntax);
|
|
70
|
+
return result.length > 0 ? result.slice(0, 1) : other.#fn(syntax).slice(0, 1);
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Returns a parser that tries this parser and returns its result if it succeeds, but if this parser fails, it returns a parser that always succeeds with `undefined` without consuming any input.
|
|
75
|
+
*/
|
|
76
|
+
optional() {
|
|
77
|
+
return this.orFirstW(Parser.of(undefined));
|
|
78
|
+
}
|
|
79
|
+
static satisfy(predicate) {
|
|
80
|
+
return Parser.item.then(char => (predicate(char) ? Parser.of(char) : Parser.zero));
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Returns a parser that parses a specific string.
|
|
84
|
+
*/
|
|
85
|
+
static string(string) {
|
|
86
|
+
return new Parser(syntax => syntax.startsWith(string)
|
|
87
|
+
? [[syntax.slice(0, string.length), syntax.slice(string.length)]]
|
|
88
|
+
: []);
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Returns a parser that parses zero or more occurrences of this parser, returning an array of the parsed results.
|
|
92
|
+
*/
|
|
93
|
+
many() {
|
|
94
|
+
return this.many1().orFirst(Parser.of([]));
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Returns a parser that parses one or more occurrences of this parser, returning an array of the parsed results.
|
|
98
|
+
*
|
|
99
|
+
* It fails if this parser does not succeed at least once.
|
|
100
|
+
*/
|
|
101
|
+
many1() {
|
|
102
|
+
return this.then(result => this.many().then(results => Parser.of([result, ...results])));
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Returns a parser that parses zero or more occurrences of this parser, separated by another parser, returning an array of the parsed results.
|
|
106
|
+
*/
|
|
107
|
+
separatedBy(separator) {
|
|
108
|
+
return this.separatedBy1(separator).orFirst(Parser.of([]));
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Returns a parser that parses one or more occurrences of this parser, separated by another parser, returning an array of the parsed results.
|
|
112
|
+
*
|
|
113
|
+
* It fails if this parser does not succeed at least once.
|
|
114
|
+
*/
|
|
115
|
+
separatedBy1(separator) {
|
|
116
|
+
return this.then(result => separator
|
|
117
|
+
.then(() => this)
|
|
118
|
+
.many()
|
|
119
|
+
.then(results => Parser.of([result, ...results])));
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Returns a parser that parses a string that matches the given regular expression pattern.
|
|
123
|
+
*
|
|
124
|
+
* The pattern must match at the beginning of the string (patterns that are designed like this might perform better), and the parser will return the matched substring as the parsed result.
|
|
125
|
+
*/
|
|
126
|
+
static regex(pattern) {
|
|
127
|
+
return new Parser(syntax => {
|
|
128
|
+
const result = pattern.exec(syntax);
|
|
129
|
+
// checks for no match and not a match at the beginning of the string at the same time
|
|
130
|
+
return result?.index !== 0 ? [] : [[result[0], syntax.slice(result[0].length)]];
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* A parser that parses whitepace characters.
|
|
135
|
+
*/
|
|
136
|
+
static space = Parser.regex(/^\s*/);
|
|
137
|
+
/**
|
|
138
|
+
* A parser that parses horizontal whitepace characters.
|
|
139
|
+
*
|
|
140
|
+
* This can be useful for parsing a language where newlines are significant.
|
|
141
|
+
*/
|
|
142
|
+
static hspace = Parser.regex(/^[^\S\r\n]*/);
|
|
143
|
+
/**
|
|
144
|
+
* Throws away trailing whitespace characters before applying the given parser.
|
|
145
|
+
*/
|
|
146
|
+
token() {
|
|
147
|
+
return this.then(result => Parser.space.then(() => Parser.of(result)));
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Throws away trailing horizontal whitespace characters before applying the given parser.
|
|
151
|
+
*
|
|
152
|
+
* This can be useful for parsing a language where newlines are significant.
|
|
153
|
+
*/
|
|
154
|
+
htoken() {
|
|
155
|
+
return this.then(result => Parser.hspace.then(() => Parser.of(result)));
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Returns a parser that parses a specific string, ignoring trailing whitespace characters.
|
|
159
|
+
*/
|
|
160
|
+
static symb(symbol) {
|
|
161
|
+
return Parser.string(symbol).token();
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Returns a parser that parses a specific string, ignoring trailing horizontal whitespace characters.
|
|
165
|
+
*
|
|
166
|
+
* This can be useful for parsing a language where newlines are significant.
|
|
167
|
+
*/
|
|
168
|
+
static hsymb(symbol) {
|
|
169
|
+
return Parser.string(symbol).htoken();
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Creates a parser that parses a value using the given parser, surrounded by the given left and right parsers, and returns the parsed value.
|
|
173
|
+
*/
|
|
174
|
+
between(left, right) {
|
|
175
|
+
return left.then(() => this).then(result => right.then(() => Parser.of(result)));
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Returns a parser that applies the given parser to the input string without consuming any input, returning the result of the parser if it succeeds. If the parser fails, this lookahead parser also fails.
|
|
179
|
+
*/
|
|
180
|
+
static lookahead(parser) {
|
|
181
|
+
return new Parser(syntax => {
|
|
182
|
+
const result = parser.parse(syntax)[0];
|
|
183
|
+
return result !== undefined ? [[result[0], syntax]] : [];
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Returns a parser that applies the given parser to the input string without consuming any input, returning `undefined` if it fails. If the parser succeeds, this fails instead.
|
|
188
|
+
*/
|
|
189
|
+
static negativeLookahead(parser) {
|
|
190
|
+
return new Parser(syntax => {
|
|
191
|
+
const result = parser.parse(syntax)[0];
|
|
192
|
+
return result === undefined ? [[undefined, syntax]] : [];
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Runs the parser on the given syntax string, ignoring any leading whitespace.
|
|
197
|
+
*
|
|
198
|
+
* A complete parse is one where the remaining unparsed string is empty. However, this method does not enforce that, and it will return all possible parses, including those that do not consume the entire input.
|
|
199
|
+
*/
|
|
200
|
+
apply(syntax) {
|
|
201
|
+
return Parser.space.then(() => this).parse(syntax);
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Runs the parser on the given syntax string.
|
|
205
|
+
*
|
|
206
|
+
* A complete parse is one where the remaining unparsed string is empty. However, this method does not enforce that, and it will return all possible parses, including those that do not consume the entire input.
|
|
207
|
+
*/
|
|
208
|
+
parse(syntax) {
|
|
209
|
+
return this.#fn(syntax);
|
|
210
|
+
}
|
|
211
|
+
static debugLog(parser) {
|
|
212
|
+
return new Parser(syntax => {
|
|
213
|
+
console.log("Parsing:", syntax);
|
|
214
|
+
const results = parser.parse(syntax);
|
|
215
|
+
console.log(results);
|
|
216
|
+
return results;
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
}
|
package/dist/reader.js
CHANGED
|
@@ -24,31 +24,31 @@ export class Reader {
|
|
|
24
24
|
* Retrieve the entire environment.
|
|
25
25
|
*/
|
|
26
26
|
static ask() {
|
|
27
|
-
return new Reader(
|
|
27
|
+
return new Reader(env => env);
|
|
28
28
|
}
|
|
29
29
|
/**
|
|
30
30
|
* Retrieve a transformed value of the environment.
|
|
31
31
|
*/
|
|
32
32
|
static asks(f) {
|
|
33
|
-
return new Reader(
|
|
33
|
+
return new Reader(env => f(env));
|
|
34
34
|
}
|
|
35
35
|
/**
|
|
36
36
|
* Applies the given function to the value produced by this Reader and returns a new Reader that produces the result.
|
|
37
37
|
*/
|
|
38
38
|
map(f) {
|
|
39
|
-
return new Reader(
|
|
39
|
+
return new Reader(env => f(this.#fn(env)));
|
|
40
40
|
}
|
|
41
41
|
/**
|
|
42
42
|
* Combines this Reader with another Reader by applying a function to both of their results and returning a new Reader that produces the result.
|
|
43
43
|
*/
|
|
44
44
|
map2(other, f) {
|
|
45
|
-
return new Reader(
|
|
45
|
+
return new Reader(env => f(this.#fn(env), other.#fn(env)));
|
|
46
46
|
}
|
|
47
47
|
/**
|
|
48
48
|
* Applies the given function to the value produced by this Reader and returns a new Reader that produces the result. The function must return a Reader, which allows you to chain computations that depend on the same environment.
|
|
49
49
|
*/
|
|
50
50
|
then(f) {
|
|
51
|
-
return new Reader(
|
|
51
|
+
return new Reader(env => f(this.#fn(env)).#fn(env));
|
|
52
52
|
}
|
|
53
53
|
/**
|
|
54
54
|
* Applies the given function to the value produced by this Reader and returns a new Reader that produces the result. The function must return a Reader, which allows you to chain computations that depend on a shared environment. The environments do not have to be the same, but will need to be combined.
|
|
@@ -56,7 +56,7 @@ export class Reader {
|
|
|
56
56
|
* The suffix ‘W’ stands for ‘widening’, as this method allows you to widen the environment that the Reader depends on.
|
|
57
57
|
*/
|
|
58
58
|
thenW(f) {
|
|
59
|
-
return new Reader(
|
|
59
|
+
return new Reader(env => f(this.#fn(env)).#fn(env));
|
|
60
60
|
}
|
|
61
61
|
/**
|
|
62
62
|
* Modifies the environment for this Reader by applying the given function to it before running the computation.
|
|
@@ -64,7 +64,7 @@ export class Reader {
|
|
|
64
64
|
* This allows you to adapt the environment for a specific computation without changing the original Reader.
|
|
65
65
|
*/
|
|
66
66
|
with(modifyEnv) {
|
|
67
|
-
return new Reader(
|
|
67
|
+
return new Reader(env => this.#fn(modifyEnv(env)));
|
|
68
68
|
}
|
|
69
69
|
/**
|
|
70
70
|
* Computes the result by providing the required environment.
|
|
@@ -76,7 +76,7 @@ export class Reader {
|
|
|
76
76
|
* Apply a function to each value in the array, and return a Reader that produces an array of the results.
|
|
77
77
|
*/
|
|
78
78
|
static traverse(values, fn) {
|
|
79
|
-
return new Reader(
|
|
79
|
+
return new Reader(env => values.map(value => fn(value).run(env)));
|
|
80
80
|
}
|
|
81
81
|
/**
|
|
82
82
|
* Evaluate each reader in the array, and collect the results in a single reader instance.
|
|
@@ -90,7 +90,7 @@ export class Reader {
|
|
|
90
90
|
* This makes functions producing Readers that depend on more arguments sometimes easier to work with.
|
|
91
91
|
*/
|
|
92
92
|
static defer(fn) {
|
|
93
|
-
return new Reader(
|
|
93
|
+
return new Reader(env => (...args) => fn(...args).run(env));
|
|
94
94
|
}
|
|
95
95
|
/**
|
|
96
96
|
* Transforms a Reader that produces a function into a function that returns a Reader.
|
|
@@ -98,7 +98,7 @@ export class Reader {
|
|
|
98
98
|
* This is the inverse of {@link defer}.
|
|
99
99
|
*/
|
|
100
100
|
static undefer(reader) {
|
|
101
|
-
return (...args) => new Reader(
|
|
101
|
+
return (...args) => new Reader(env => reader.run(env)(...args));
|
|
102
102
|
}
|
|
103
103
|
}
|
|
104
104
|
// type Readable<T> =
|
package/dist/result.js
CHANGED
|
@@ -28,15 +28,15 @@ export const reduce = (result, fok, ferror) => (isOk(result) ? fok(result.value)
|
|
|
28
28
|
/**
|
|
29
29
|
* Maps the value of a result to a new value.
|
|
30
30
|
*/
|
|
31
|
-
export const map = (result, f) =>
|
|
31
|
+
export const map = (result, f) => isOk(result) ? ok(f(result.value)) : result;
|
|
32
32
|
/**
|
|
33
33
|
* Maps an error to a new error.
|
|
34
34
|
*/
|
|
35
|
-
export const mapError = (result, f) =>
|
|
35
|
+
export const mapError = (result, f) => isError(result) ? error(f(result.error)) : result;
|
|
36
36
|
/**
|
|
37
37
|
* Chains a result to a new result.
|
|
38
38
|
*/
|
|
39
|
-
export const then = (result, f) =>
|
|
39
|
+
export const then = (result, f) => isOk(result) ? f(result.value) : result;
|
|
40
40
|
/**
|
|
41
41
|
* Combines two results into one.
|
|
42
42
|
*
|
package/dist/state.d.ts
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The {@link State} class representing a state transformation function and includes methods to chain functions effectively.
|
|
3
|
+
* @module
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* A class representing a state transformation function that takes an initial state and returns a tuple containing a value and a new state.
|
|
7
|
+
*/
|
|
8
|
+
export declare class State<S, T> {
|
|
9
|
+
#private;
|
|
10
|
+
private constructor();
|
|
11
|
+
/**
|
|
12
|
+
* Returns a new {@link State} instance that returns the state as the resulting value without modifying the state.
|
|
13
|
+
*/
|
|
14
|
+
static get<S>(): State<S, S>;
|
|
15
|
+
/**
|
|
16
|
+
* Applies the state transformation function to the given state and returns a tuple containing the resulting value and the new state.
|
|
17
|
+
*/
|
|
18
|
+
run(state: S): [T, S];
|
|
19
|
+
/**
|
|
20
|
+
* Applies the state transformation function to the given state and returns the resulting value, discarding the new state.
|
|
21
|
+
*/
|
|
22
|
+
eval(state: S): T;
|
|
23
|
+
/**
|
|
24
|
+
* Applies the state transformation function to the given state and returns the new state, discarding the resulting value.
|
|
25
|
+
*/
|
|
26
|
+
exec(state: S): S;
|
|
27
|
+
/**
|
|
28
|
+
* Returns a new {@link State} instance that returns the given value without modifying the state.
|
|
29
|
+
*/
|
|
30
|
+
static of<S, T>(value: T): State<S, T>;
|
|
31
|
+
/**
|
|
32
|
+
* Transforms the value produced by this state transformation function using the given function, while keeping the state unchanged.
|
|
33
|
+
*/
|
|
34
|
+
map<U>(f: (value: T) => U): State<S, U>;
|
|
35
|
+
/**
|
|
36
|
+
* Transforms the value and state produced by this state transformation function using the given function.
|
|
37
|
+
*/
|
|
38
|
+
mapBoth<U>(f: (result: [T, S]) => [U, S]): State<S, U>;
|
|
39
|
+
/**
|
|
40
|
+
* Chains this state transformation function with another function that takes the value produced by this function and returns a new {@link State} instance, allowing for sequential state transformations.
|
|
41
|
+
*/
|
|
42
|
+
then<U>(f: (value: T) => State<S, U>): State<S, U>;
|
|
43
|
+
/**
|
|
44
|
+
* Returns a new {@link State} instance that applies the given function to the state and returns the resulting value without modifying the state.
|
|
45
|
+
*/
|
|
46
|
+
static gets<S, T>(f: (state: S) => T): State<S, T>;
|
|
47
|
+
/**
|
|
48
|
+
* Modifies the state using the given function before applying this state transformation function.
|
|
49
|
+
*/
|
|
50
|
+
with(f: (state: S) => S): State<S, T>;
|
|
51
|
+
}
|
package/dist/state.js
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The {@link State} class representing a state transformation function and includes methods to chain functions effectively.
|
|
3
|
+
* @module
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* A class representing a state transformation function that takes an initial state and returns a tuple containing a value and a new state.
|
|
7
|
+
*/
|
|
8
|
+
export class State {
|
|
9
|
+
#fn;
|
|
10
|
+
constructor(fn) {
|
|
11
|
+
this.#fn = fn;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Returns a new {@link State} instance that returns the state as the resulting value without modifying the state.
|
|
15
|
+
*/
|
|
16
|
+
static get() {
|
|
17
|
+
return new State(state => [state, state]);
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Applies the state transformation function to the given state and returns a tuple containing the resulting value and the new state.
|
|
21
|
+
*/
|
|
22
|
+
run(state) {
|
|
23
|
+
return this.#fn(state);
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Applies the state transformation function to the given state and returns the resulting value, discarding the new state.
|
|
27
|
+
*/
|
|
28
|
+
eval(state) {
|
|
29
|
+
return this.run(state)[0];
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Applies the state transformation function to the given state and returns the new state, discarding the resulting value.
|
|
33
|
+
*/
|
|
34
|
+
exec(state) {
|
|
35
|
+
return this.run(state)[1];
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Returns a new {@link State} instance that returns the given value without modifying the state.
|
|
39
|
+
*/
|
|
40
|
+
static of(value) {
|
|
41
|
+
return new State(state => [value, state]);
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Transforms the value produced by this state transformation function using the given function, while keeping the state unchanged.
|
|
45
|
+
*/
|
|
46
|
+
map(f) {
|
|
47
|
+
return new State(state => {
|
|
48
|
+
const [value, newState] = this.run(state);
|
|
49
|
+
return [f(value), newState];
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Transforms the value and state produced by this state transformation function using the given function.
|
|
54
|
+
*/
|
|
55
|
+
mapBoth(f) {
|
|
56
|
+
return new State(state => f(this.run(state)));
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Chains this state transformation function with another function that takes the value produced by this function and returns a new {@link State} instance, allowing for sequential state transformations.
|
|
60
|
+
*/
|
|
61
|
+
then(f) {
|
|
62
|
+
return new State(state => {
|
|
63
|
+
const [value, newState] = this.run(state);
|
|
64
|
+
return f(value).run(newState);
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Returns a new {@link State} instance that applies the given function to the state and returns the resulting value without modifying the state.
|
|
69
|
+
*/
|
|
70
|
+
static gets(f) {
|
|
71
|
+
return new State(state => [f(state), state]);
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Modifies the state using the given function before applying this state transformation function.
|
|
75
|
+
*/
|
|
76
|
+
with(f) {
|
|
77
|
+
return new State(state => this.run(f(state)));
|
|
78
|
+
}
|
|
79
|
+
}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A simple stateful parser combinator.
|
|
3
|
+
* @module
|
|
4
|
+
*/
|
|
5
|
+
import { Parser } from "./parser.js";
|
|
6
|
+
/**
|
|
7
|
+
* A class that combines the functionality of a parser with a state transformation function, allowing for more complex parsing scenarios where the parser can also manipulate some state during the parsing process.
|
|
8
|
+
*/
|
|
9
|
+
export declare class StateTParser<S, T> {
|
|
10
|
+
#private;
|
|
11
|
+
private constructor();
|
|
12
|
+
/**
|
|
13
|
+
* Returns a new {@link StateTParser} instance that always succeeds with the given value while not modifying the state.
|
|
14
|
+
*/
|
|
15
|
+
static of<S, T>(value: T): StateTParser<S, T>;
|
|
16
|
+
/**
|
|
17
|
+
* Chains the state transformation function and the parser with a function that takes the produced value and reutns a new {@link StateTParser} instance, allowing for sequential state transformations and parsing operations.
|
|
18
|
+
*/
|
|
19
|
+
then<U>(f: (result: T) => StateTParser<S, U>): StateTParser<S, U>;
|
|
20
|
+
/**
|
|
21
|
+
* Wraps a parser into a {@link StateTParser}, allowing the parser to be used in the context of state transformations.
|
|
22
|
+
*/
|
|
23
|
+
static lift<S, T>(parser: Parser<T>): StateTParser<S, T>;
|
|
24
|
+
/**
|
|
25
|
+
* Applies the state transformation function to the given state and returns a tuple containing the resulting value and the new state.
|
|
26
|
+
*/
|
|
27
|
+
runT(state: S): Parser<[T, S]>;
|
|
28
|
+
/**
|
|
29
|
+
* Applies the state transformation function to the given state and returns the resulting value, discarding the new state.
|
|
30
|
+
*/
|
|
31
|
+
evalT(state: S): Parser<T>;
|
|
32
|
+
/**
|
|
33
|
+
* Applies the state transformation function to the given state and returns the new state, discarding the resulting value.
|
|
34
|
+
*/
|
|
35
|
+
execT(state: S): Parser<S>;
|
|
36
|
+
/**
|
|
37
|
+
* Transforms the produced value using the given function, while keeping the state unchanged and not consuming any additional input.
|
|
38
|
+
*/
|
|
39
|
+
map<U>(f: (value: T) => U): StateTParser<S, U>;
|
|
40
|
+
/**
|
|
41
|
+
* Transforms the value and state produced by this state transformation function using the given function.
|
|
42
|
+
*/
|
|
43
|
+
mapT<U>(f: (result: Parser<[T, S]>) => Parser<[U, S]>): StateTParser<S, U>;
|
|
44
|
+
/**
|
|
45
|
+
* Returns a new {@link StateTParser} instance that returns the state as the resulting value without modifying the state.
|
|
46
|
+
*/
|
|
47
|
+
static getT<S>(): StateTParser<S, S>;
|
|
48
|
+
/**
|
|
49
|
+
* Returns a new {@link StateTParser} instance that applies the given function to the state and returns the resulting value without modifying the state.
|
|
50
|
+
*/
|
|
51
|
+
static getsT<S, T>(f: (state: S) => T): StateTParser<S, T>;
|
|
52
|
+
/**
|
|
53
|
+
* Modifies the state using the given function before applying this state transformation function.
|
|
54
|
+
*/
|
|
55
|
+
withT(f: (state: S) => S): StateTParser<S, T>;
|
|
56
|
+
/**
|
|
57
|
+
* Combines this parser with another parser, trying this parser first and then the other parser only if the first parser fails. It only returns the first successful result.
|
|
58
|
+
*/
|
|
59
|
+
orFirst(other: StateTParser<S, T>): StateTParser<S, T>;
|
|
60
|
+
/**
|
|
61
|
+
* Combines this parser with another parser, trying this parser first and then the other parser only if the first parser fails. It only returns the first successful result.
|
|
62
|
+
*
|
|
63
|
+
* The suffix ‘W’ stands for ‘widening’, as this method allows you to combine parsers with different result types.
|
|
64
|
+
*/
|
|
65
|
+
orFirstW<U>(other: StateTParser<S, U>): StateTParser<S, T | U>;
|
|
66
|
+
/**
|
|
67
|
+
* Returns a parser that tries this parser and returns its result if it succeeds, but if this parser fails, it returns a parser that always succeeds with `undefined` without consuming any input.
|
|
68
|
+
*/
|
|
69
|
+
optional(): StateTParser<S, T | undefined>;
|
|
70
|
+
/**
|
|
71
|
+
* Returns a parser that parses a specific string.
|
|
72
|
+
*/
|
|
73
|
+
static string<S, T extends string = string>(string: T): StateTParser<S, T>;
|
|
74
|
+
/**
|
|
75
|
+
* Returns a parser that parses zero or more occurrences of this parser, returning an array of the parsed results.
|
|
76
|
+
*/
|
|
77
|
+
many(): StateTParser<S, T[]>;
|
|
78
|
+
/**
|
|
79
|
+
* Returns a parser that parses one or more occurrences of this parser, returning an array of the parsed results.
|
|
80
|
+
*
|
|
81
|
+
* It fails if this parser does not succeed at least once.
|
|
82
|
+
*/
|
|
83
|
+
many1(): StateTParser<S, T[]>;
|
|
84
|
+
/**
|
|
85
|
+
* Returns a parser that parses zero or more occurrences of this parser, separated by another parser, returning an array of the parsed results.
|
|
86
|
+
*/
|
|
87
|
+
separatedBy(separator: StateTParser<S, unknown>): StateTParser<S, T[]>;
|
|
88
|
+
/**
|
|
89
|
+
* Returns a parser that parses one or more occurrences of this parser, separated by another parser, returning an array of the parsed results.
|
|
90
|
+
*
|
|
91
|
+
* It fails if this parser does not succeed at least once.
|
|
92
|
+
*/
|
|
93
|
+
separatedBy1(separator: StateTParser<S, unknown>): StateTParser<S, T[]>;
|
|
94
|
+
/**
|
|
95
|
+
* Returns a parser that parses a string that matches the given regular expression pattern.
|
|
96
|
+
*
|
|
97
|
+
* The pattern must match at the beginning of the string (patterns that are designed like this might perform better), and the parser will return the matched substring as the parsed result.
|
|
98
|
+
*/
|
|
99
|
+
static regex<S>(pattern: RegExp): StateTParser<S, string>;
|
|
100
|
+
/**
|
|
101
|
+
* A parser that parses whitepace characters.
|
|
102
|
+
*/
|
|
103
|
+
static space<S>(): StateTParser<S, string>;
|
|
104
|
+
/**
|
|
105
|
+
* A parser that parses horizontal whitepace characters.
|
|
106
|
+
*
|
|
107
|
+
* This can be useful for parsing a language where newlines are significant.
|
|
108
|
+
*/
|
|
109
|
+
static hspace<S>(): StateTParser<S, string>;
|
|
110
|
+
/**
|
|
111
|
+
* Throws away trailing whitespace characters before applying the given parser.
|
|
112
|
+
*/
|
|
113
|
+
token(): StateTParser<S, T>;
|
|
114
|
+
/**
|
|
115
|
+
* Throws away trailing horizontal whitespace characters before applying the given parser.
|
|
116
|
+
*
|
|
117
|
+
* This can be useful for parsing a language where newlines are significant.
|
|
118
|
+
*/
|
|
119
|
+
htoken(): StateTParser<S, T>;
|
|
120
|
+
/**
|
|
121
|
+
* Returns a parser that parses a specific string, ignoring trailing whitespace characters.
|
|
122
|
+
*/
|
|
123
|
+
static symb<S, T extends string>(symbol: T): StateTParser<S, T>;
|
|
124
|
+
/**
|
|
125
|
+
* Returns a parser that parses a specific string, ignoring trailing horizontal whitespace characters.
|
|
126
|
+
*
|
|
127
|
+
* This can be useful for parsing a language where newlines are significant.
|
|
128
|
+
*/
|
|
129
|
+
static hsymb<S, T extends string>(symbol: T): StateTParser<S, T>;
|
|
130
|
+
/**
|
|
131
|
+
* Creates a parser that parses a value using the given parser, surrounded by the given left and right parsers, and returns the parsed value.
|
|
132
|
+
*/
|
|
133
|
+
between<L, R>(left: StateTParser<S, L>, right: StateTParser<S, R>): StateTParser<S, T>;
|
|
134
|
+
/**
|
|
135
|
+
* Returns a parser that applies the given parser to the input string without consuming any input, returning the result of the parser if it succeeds. If the parser fails, this lookahead parser also fails.
|
|
136
|
+
*/
|
|
137
|
+
static lookahead<S, T>(parser: StateTParser<S, T>): StateTParser<S, T>;
|
|
138
|
+
/**
|
|
139
|
+
* Returns a parser that applies the given parser to the input string without consuming any input, returning `undefined` if it fails. If the parser succeeds, this fails instead.
|
|
140
|
+
*/
|
|
141
|
+
static negativeLookahead<S>(parser: StateTParser<S, unknown>): StateTParser<S, undefined>;
|
|
142
|
+
static debugLog<S, T>(stateParser: StateTParser<S, T>): StateTParser<S, T>;
|
|
143
|
+
}
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A simple stateful parser combinator.
|
|
3
|
+
* @module
|
|
4
|
+
*/
|
|
5
|
+
import { Parser } from "./parser.js";
|
|
6
|
+
/**
|
|
7
|
+
* A class that combines the functionality of a parser with a state transformation function, allowing for more complex parsing scenarios where the parser can also manipulate some state during the parsing process.
|
|
8
|
+
*/
|
|
9
|
+
export class StateTParser {
|
|
10
|
+
#fn;
|
|
11
|
+
constructor(fn) {
|
|
12
|
+
this.#fn = fn;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Returns a new {@link StateTParser} instance that always succeeds with the given value while not modifying the state.
|
|
16
|
+
*/
|
|
17
|
+
static of(value) {
|
|
18
|
+
return new StateTParser(state => Parser.of([value, state]));
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Chains the state transformation function and the parser with a function that takes the produced value and reutns a new {@link StateTParser} instance, allowing for sequential state transformations and parsing operations.
|
|
22
|
+
*/
|
|
23
|
+
then(f) {
|
|
24
|
+
return new StateTParser(state => this.#fn(state).then(([result, newState]) => f(result).#fn(newState)));
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Wraps a parser into a {@link StateTParser}, allowing the parser to be used in the context of state transformations.
|
|
28
|
+
*/
|
|
29
|
+
static lift(parser) {
|
|
30
|
+
return new StateTParser(state => parser.map(result => [result, state]));
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Applies the state transformation function to the given state and returns a tuple containing the resulting value and the new state.
|
|
34
|
+
*/
|
|
35
|
+
runT(state) {
|
|
36
|
+
return this.#fn(state);
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Applies the state transformation function to the given state and returns the resulting value, discarding the new state.
|
|
40
|
+
*/
|
|
41
|
+
evalT(state) {
|
|
42
|
+
return this.runT(state).map(result => result[0]);
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Applies the state transformation function to the given state and returns the new state, discarding the resulting value.
|
|
46
|
+
*/
|
|
47
|
+
execT(state) {
|
|
48
|
+
return this.runT(state).map(result => result[1]);
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Transforms the produced value using the given function, while keeping the state unchanged and not consuming any additional input.
|
|
52
|
+
*/
|
|
53
|
+
map(f) {
|
|
54
|
+
return new StateTParser(state => this.runT(state).map(([value, newState]) => [f(value), newState]));
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Transforms the value and state produced by this state transformation function using the given function.
|
|
58
|
+
*/
|
|
59
|
+
mapT(f) {
|
|
60
|
+
return new StateTParser(state => f(this.runT(state)));
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Returns a new {@link StateTParser} instance that returns the state as the resulting value without modifying the state.
|
|
64
|
+
*/
|
|
65
|
+
static getT() {
|
|
66
|
+
return new StateTParser(state => Parser.of([state, state]));
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Returns a new {@link StateTParser} instance that applies the given function to the state and returns the resulting value without modifying the state.
|
|
70
|
+
*/
|
|
71
|
+
static getsT(f) {
|
|
72
|
+
return new StateTParser(state => Parser.of([f(state), state]));
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Modifies the state using the given function before applying this state transformation function.
|
|
76
|
+
*/
|
|
77
|
+
withT(f) {
|
|
78
|
+
return new StateTParser(state => this.runT(f(state)));
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Combines this parser with another parser, trying this parser first and then the other parser only if the first parser fails. It only returns the first successful result.
|
|
82
|
+
*/
|
|
83
|
+
orFirst(other) {
|
|
84
|
+
return new StateTParser(state => {
|
|
85
|
+
const parser = this.#fn(state);
|
|
86
|
+
const otherParser = other.#fn(state);
|
|
87
|
+
return parser.orFirst(otherParser);
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Combines this parser with another parser, trying this parser first and then the other parser only if the first parser fails. It only returns the first successful result.
|
|
92
|
+
*
|
|
93
|
+
* The suffix ‘W’ stands for ‘widening’, as this method allows you to combine parsers with different result types.
|
|
94
|
+
*/
|
|
95
|
+
orFirstW(other) {
|
|
96
|
+
return new StateTParser((state) => {
|
|
97
|
+
const parser = this.#fn(state);
|
|
98
|
+
const otherParser = other.#fn(state);
|
|
99
|
+
return parser.orFirstW(otherParser);
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Returns a parser that tries this parser and returns its result if it succeeds, but if this parser fails, it returns a parser that always succeeds with `undefined` without consuming any input.
|
|
104
|
+
*/
|
|
105
|
+
optional() {
|
|
106
|
+
return this.orFirstW(StateTParser.of(undefined));
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Returns a parser that parses a specific string.
|
|
110
|
+
*/
|
|
111
|
+
static string(string) {
|
|
112
|
+
return StateTParser.lift(Parser.string(string));
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Returns a parser that parses zero or more occurrences of this parser, returning an array of the parsed results.
|
|
116
|
+
*/
|
|
117
|
+
many() {
|
|
118
|
+
return this.many1().orFirst(StateTParser.of([]));
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Returns a parser that parses one or more occurrences of this parser, returning an array of the parsed results.
|
|
122
|
+
*
|
|
123
|
+
* It fails if this parser does not succeed at least once.
|
|
124
|
+
*/
|
|
125
|
+
many1() {
|
|
126
|
+
return this.then(result => this.many().then(results => StateTParser.of([result, ...results])));
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Returns a parser that parses zero or more occurrences of this parser, separated by another parser, returning an array of the parsed results.
|
|
130
|
+
*/
|
|
131
|
+
separatedBy(separator) {
|
|
132
|
+
return this.separatedBy1(separator).orFirst(StateTParser.of([]));
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Returns a parser that parses one or more occurrences of this parser, separated by another parser, returning an array of the parsed results.
|
|
136
|
+
*
|
|
137
|
+
* It fails if this parser does not succeed at least once.
|
|
138
|
+
*/
|
|
139
|
+
separatedBy1(separator) {
|
|
140
|
+
return this.then(result => separator
|
|
141
|
+
.then(() => this)
|
|
142
|
+
.many()
|
|
143
|
+
.then(results => StateTParser.of([result, ...results])));
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Returns a parser that parses a string that matches the given regular expression pattern.
|
|
147
|
+
*
|
|
148
|
+
* The pattern must match at the beginning of the string (patterns that are designed like this might perform better), and the parser will return the matched substring as the parsed result.
|
|
149
|
+
*/
|
|
150
|
+
static regex(pattern) {
|
|
151
|
+
return StateTParser.lift(Parser.regex(pattern));
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* A parser that parses whitepace characters.
|
|
155
|
+
*/
|
|
156
|
+
static space() {
|
|
157
|
+
return StateTParser.lift(Parser.space);
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* A parser that parses horizontal whitepace characters.
|
|
161
|
+
*
|
|
162
|
+
* This can be useful for parsing a language where newlines are significant.
|
|
163
|
+
*/
|
|
164
|
+
static hspace() {
|
|
165
|
+
return StateTParser.lift(Parser.hspace);
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Throws away trailing whitespace characters before applying the given parser.
|
|
169
|
+
*/
|
|
170
|
+
token() {
|
|
171
|
+
return this.then(result => StateTParser.space().then(() => StateTParser.of(result)));
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Throws away trailing horizontal whitespace characters before applying the given parser.
|
|
175
|
+
*
|
|
176
|
+
* This can be useful for parsing a language where newlines are significant.
|
|
177
|
+
*/
|
|
178
|
+
htoken() {
|
|
179
|
+
return this.then(result => StateTParser.hspace().then(() => StateTParser.of(result)));
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Returns a parser that parses a specific string, ignoring trailing whitespace characters.
|
|
183
|
+
*/
|
|
184
|
+
static symb(symbol) {
|
|
185
|
+
return StateTParser.string(symbol).token();
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Returns a parser that parses a specific string, ignoring trailing horizontal whitespace characters.
|
|
189
|
+
*
|
|
190
|
+
* This can be useful for parsing a language where newlines are significant.
|
|
191
|
+
*/
|
|
192
|
+
static hsymb(symbol) {
|
|
193
|
+
return StateTParser.string(symbol).htoken();
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Creates a parser that parses a value using the given parser, surrounded by the given left and right parsers, and returns the parsed value.
|
|
197
|
+
*/
|
|
198
|
+
between(left, right) {
|
|
199
|
+
return left.then(() => this).then(result => right.then(() => StateTParser.of(result)));
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Returns a parser that applies the given parser to the input string without consuming any input, returning the result of the parser if it succeeds. If the parser fails, this lookahead parser also fails.
|
|
203
|
+
*/
|
|
204
|
+
static lookahead(parser) {
|
|
205
|
+
return new StateTParser(state => Parser.lookahead(parser.runT(state)));
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* Returns a parser that applies the given parser to the input string without consuming any input, returning `undefined` if it fails. If the parser succeeds, this fails instead.
|
|
209
|
+
*/
|
|
210
|
+
static negativeLookahead(parser) {
|
|
211
|
+
return new StateTParser(state => Parser.negativeLookahead(parser.runT(state)).map(() => [undefined, state]));
|
|
212
|
+
}
|
|
213
|
+
static debugLog(stateParser) {
|
|
214
|
+
return new StateTParser(state => {
|
|
215
|
+
console.log("Parsing with state:", state);
|
|
216
|
+
return Parser.debugLog(stateParser.runT(state));
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
}
|
package/dist/string/number.js
CHANGED
|
@@ -14,24 +14,16 @@ export const plusMinus = "\xB1";
|
|
|
14
14
|
/**
|
|
15
15
|
* Forces signing on the given number, returning `undefined` on zero.
|
|
16
16
|
*/
|
|
17
|
-
export const signIgnoreZero = (x) => x > 0
|
|
18
|
-
? `+${x.toString()}`
|
|
19
|
-
: x < 0
|
|
20
|
-
? `${minus}\u2060${Math.abs(x).toString()}`
|
|
21
|
-
: undefined;
|
|
17
|
+
export const signIgnoreZero = (x) => x > 0 ? `+${x.toString()}` : x < 0 ? `${minus}\u2060${Math.abs(x).toString()}` : undefined;
|
|
22
18
|
/**
|
|
23
19
|
* Forces signing on the given number.
|
|
24
20
|
*/
|
|
25
|
-
export const sign = (x) => x > 0
|
|
26
|
-
? `+${x.toString()}`
|
|
27
|
-
: x < 0
|
|
28
|
-
? `${minus}\u2060${Math.abs(x).toString()}`
|
|
29
|
-
: "0";
|
|
21
|
+
export const sign = (x) => x > 0 ? `+${x.toString()}` : x < 0 ? `${minus}\u2060${Math.abs(x).toString()}` : "0";
|
|
30
22
|
/**
|
|
31
23
|
* Returns the sign of the given number. Returns `undefined` if the number is
|
|
32
24
|
* zero.
|
|
33
25
|
*/
|
|
34
|
-
export const signStr = (x) => x > 0 ? "+" : x < 0 ? minus : undefined;
|
|
26
|
+
export const signStr = (x) => (x > 0 ? "+" : x < 0 ? minus : undefined);
|
|
35
27
|
/**
|
|
36
28
|
* Converts a string to an integer. If the string is not a valid integer, it
|
|
37
29
|
* returns `undefined`.
|
package/dist/string.js
CHANGED
|
@@ -28,8 +28,7 @@ export const splitStringParts = (str) => [...new Intl.Segmenter().segment(str)].
|
|
|
28
28
|
const nextSegment = strArr[i + 1];
|
|
29
29
|
const nextChar = nextSegment?.segment;
|
|
30
30
|
if (lastCharOfLastPart === undefined ||
|
|
31
|
-
(uppercase.test(lastCharOfLastPart) &&
|
|
32
|
-
(nextChar === undefined || separator.test(nextChar)))) {
|
|
31
|
+
(uppercase.test(lastCharOfLastPart) && (nextChar === undefined || separator.test(nextChar)))) {
|
|
33
32
|
return [...acc.slice(0, -1), lastPart + char];
|
|
34
33
|
}
|
|
35
34
|
else {
|
|
@@ -50,9 +49,7 @@ export const splitStringParts = (str) => [...new Intl.Segmenter().segment(str)].
|
|
|
50
49
|
* Converts a string to PascalCase.
|
|
51
50
|
*/
|
|
52
51
|
export const toPascalCase = (str) => splitStringParts(isAllUppercase(str) ? str.toLowerCase() : str)
|
|
53
|
-
.map(
|
|
54
|
-
? part
|
|
55
|
-
: part.charAt(0).toUpperCase() + part.slice(1).toLowerCase())
|
|
52
|
+
.map(part => isAllUppercase(part) ? part : part.charAt(0).toUpperCase() + part.slice(1).toLowerCase())
|
|
56
53
|
.join("");
|
|
57
54
|
/**
|
|
58
55
|
* Converts a string to camelCase.
|
|
@@ -68,21 +65,19 @@ export const toCamelCase = (str) => splitStringParts(isAllUppercase(str) ? str.t
|
|
|
68
65
|
* Converts a string to kebab-case.
|
|
69
66
|
*/
|
|
70
67
|
export const toKebabCase = (str) => splitStringParts(str)
|
|
71
|
-
.map(
|
|
68
|
+
.map(part => part.toLowerCase())
|
|
72
69
|
.join("-");
|
|
73
70
|
/**
|
|
74
71
|
* Converts a string to snake_case.
|
|
75
72
|
*/
|
|
76
73
|
export const toSnakeCase = (str) => splitStringParts(str)
|
|
77
|
-
.map(
|
|
74
|
+
.map(part => part.toLowerCase())
|
|
78
75
|
.join("_");
|
|
79
76
|
/**
|
|
80
77
|
* Converts a string to Title Case.
|
|
81
78
|
*/
|
|
82
79
|
export const toTitleCase = (str) => splitStringParts(isAllUppercase(str) ? str.toLowerCase() : str)
|
|
83
|
-
.map(
|
|
84
|
-
? part
|
|
85
|
-
: part.charAt(0).toUpperCase() + part.slice(1).toLowerCase())
|
|
80
|
+
.map(part => isAllUppercase(part) ? part : part.charAt(0).toUpperCase() + part.slice(1).toLowerCase())
|
|
86
81
|
.join(" ");
|
|
87
82
|
/**
|
|
88
83
|
* Finds the longest common prefix among the provided strings.
|
|
@@ -93,8 +88,6 @@ export const commonPrefix = (...strs) => {
|
|
|
93
88
|
}
|
|
94
89
|
return strs.reduce((accPrefix, str) => {
|
|
95
90
|
const indexOfDifference = Array.from(accPrefix).findIndex((char, i) => str[i] !== char);
|
|
96
|
-
return indexOfDifference === -1
|
|
97
|
-
? accPrefix
|
|
98
|
-
: accPrefix.slice(0, indexOfDifference);
|
|
91
|
+
return indexOfDifference === -1 ? accPrefix : accPrefix.slice(0, indexOfDifference);
|
|
99
92
|
});
|
|
100
93
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@elyukai/utils",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.9",
|
|
4
4
|
"description": "A set of JavaScript helper functions.",
|
|
5
5
|
"files": [
|
|
6
6
|
"dist",
|
|
@@ -33,14 +33,14 @@
|
|
|
33
33
|
"homepage": "https://github.com/elyukai/ts-utils#readme",
|
|
34
34
|
"devDependencies": {
|
|
35
35
|
"@eslint/js": "^10.0.1",
|
|
36
|
-
"@types/node": "^25.3.
|
|
36
|
+
"@types/node": "^25.3.3",
|
|
37
37
|
"commit-and-tag-version": "^12.6.1",
|
|
38
|
-
"eslint": "^10.0.
|
|
39
|
-
"eslint-plugin-jsdoc": "^62.7.
|
|
38
|
+
"eslint": "^10.0.2",
|
|
39
|
+
"eslint-plugin-jsdoc": "^62.7.1",
|
|
40
40
|
"prettier": "^3.8.1",
|
|
41
41
|
"tsx": "^4.21.0",
|
|
42
42
|
"typescript": "^5.9.3",
|
|
43
|
-
"typescript-eslint": "^8.56.
|
|
43
|
+
"typescript-eslint": "^8.56.1"
|
|
44
44
|
},
|
|
45
45
|
"type": "module"
|
|
46
46
|
}
|