@nlozgachev/pipelined 0.10.0 → 0.12.0
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/README.md +9 -3
- package/esm/src/Core/Option.js +2 -1
- package/esm/src/Core/RemoteData.js +5 -5
- package/esm/src/Core/TaskValidation.js +1 -3
- package/esm/src/Core/Tuple.js +112 -0
- package/esm/src/Core/index.js +4 -5
- package/esm/src/{Core → Utils}/Arr.js +95 -23
- package/esm/src/Utils/Dict.js +421 -0
- package/esm/src/Utils/Num.js +124 -0
- package/esm/src/{Core → Utils}/Rec.js +85 -11
- package/esm/src/Utils/Str.js +134 -0
- package/esm/src/Utils/Uniq.js +265 -0
- package/esm/src/Utils/index.js +6 -0
- package/package.json +11 -1
- package/script/src/Core/Option.js +2 -1
- package/script/src/Core/RemoteData.js +5 -5
- package/script/src/Core/TaskValidation.js +1 -3
- package/script/src/Core/Tuple.js +115 -0
- package/script/src/Core/index.js +4 -5
- package/script/src/{Core → Utils}/Arr.js +95 -23
- package/script/src/Utils/Dict.js +424 -0
- package/script/src/Utils/Num.js +127 -0
- package/script/src/{Core → Utils}/Rec.js +85 -11
- package/script/src/Utils/Str.js +137 -0
- package/script/src/Utils/Uniq.js +268 -0
- package/script/src/Utils/index.js +22 -0
- package/types/src/Composition/compose.d.ts.map +1 -1
- package/types/src/Composition/converge.d.ts.map +1 -1
- package/types/src/Composition/curry.d.ts.map +1 -1
- package/types/src/Composition/flow.d.ts.map +1 -1
- package/types/src/Composition/fn.d.ts.map +1 -1
- package/types/src/Composition/juxt.d.ts.map +1 -1
- package/types/src/Composition/memoize.d.ts.map +1 -1
- package/types/src/Composition/not.d.ts.map +1 -1
- package/types/src/Composition/on.d.ts.map +1 -1
- package/types/src/Composition/pipe.d.ts.map +1 -1
- package/types/src/Composition/uncurry.d.ts.map +1 -1
- package/types/src/Core/Deferred.d.ts.map +1 -1
- package/types/src/Core/Lens.d.ts.map +1 -1
- package/types/src/Core/Logged.d.ts.map +1 -1
- package/types/src/Core/Option.d.ts.map +1 -1
- package/types/src/Core/Optional.d.ts.map +1 -1
- package/types/src/Core/Predicate.d.ts.map +1 -1
- package/types/src/Core/Reader.d.ts.map +1 -1
- package/types/src/Core/Refinement.d.ts.map +1 -1
- package/types/src/Core/RemoteData.d.ts.map +1 -1
- package/types/src/Core/Result.d.ts.map +1 -1
- package/types/src/Core/State.d.ts.map +1 -1
- package/types/src/Core/Task.d.ts.map +1 -1
- package/types/src/Core/TaskOption.d.ts.map +1 -1
- package/types/src/Core/TaskResult.d.ts.map +1 -1
- package/types/src/Core/TaskValidation.d.ts.map +1 -1
- package/types/src/Core/These.d.ts.map +1 -1
- package/types/src/Core/Tuple.d.ts +129 -0
- package/types/src/Core/Tuple.d.ts.map +1 -0
- package/types/src/Core/Validation.d.ts.map +1 -1
- package/types/src/Core/index.d.ts +4 -5
- package/types/src/Core/index.d.ts.map +1 -1
- package/types/src/Types/Brand.d.ts.map +1 -1
- package/types/src/Types/NonEmptyList.d.ts.map +1 -1
- package/types/src/{Core → Utils}/Arr.d.ts +25 -3
- package/types/src/Utils/Arr.d.ts.map +1 -0
- package/types/src/Utils/Dict.d.ts +310 -0
- package/types/src/Utils/Dict.d.ts.map +1 -0
- package/types/src/Utils/Num.d.ts +110 -0
- package/types/src/Utils/Num.d.ts.map +1 -0
- package/types/src/{Core → Utils}/Rec.d.ts +39 -1
- package/types/src/Utils/Rec.d.ts.map +1 -0
- package/types/src/Utils/Str.d.ts +128 -0
- package/types/src/Utils/Str.d.ts.map +1 -0
- package/types/src/Utils/Uniq.d.ts +179 -0
- package/types/src/Utils/Uniq.d.ts.map +1 -0
- package/types/src/Utils/index.d.ts +7 -0
- package/types/src/Utils/index.d.ts.map +1 -0
- package/types/src/Core/Arr.d.ts.map +0 -1
- package/types/src/Core/Rec.d.ts.map +0 -1
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Num = void 0;
|
|
4
|
+
const Option_js_1 = require("../Core/Option.js");
|
|
5
|
+
/**
|
|
6
|
+
* Number utilities for common operations. All transformation functions are data-last
|
|
7
|
+
* and curried so they compose naturally with `pipe` and `Arr.map`.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```ts
|
|
11
|
+
* import { Num } from "@nlozgachev/pipelined/utils";
|
|
12
|
+
* import { pipe } from "@nlozgachev/pipelined/composition";
|
|
13
|
+
*
|
|
14
|
+
* pipe(
|
|
15
|
+
* Num.range(1, 6),
|
|
16
|
+
* Arr.map(Num.multiply(2)),
|
|
17
|
+
* Arr.filter(Num.between(4, 8))
|
|
18
|
+
* ); // [4, 6, 8]
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
var Num;
|
|
22
|
+
(function (Num) {
|
|
23
|
+
/**
|
|
24
|
+
* Generates an array of numbers from `from` to `to` (both inclusive),
|
|
25
|
+
* stepping by `step` (default `1`). If `step` is negative or zero, or `from > to`,
|
|
26
|
+
* returns an empty array. When `step` does not land exactly on `to`, the last value
|
|
27
|
+
* is the largest reachable value that does not exceed `to`.
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* ```ts
|
|
31
|
+
* Num.range(0, 5); // [0, 1, 2, 3, 4, 5]
|
|
32
|
+
* Num.range(0, 10, 2); // [0, 2, 4, 6, 8, 10]
|
|
33
|
+
* Num.range(0, 9, 2); // [0, 2, 4, 6, 8]
|
|
34
|
+
* Num.range(5, 0); // []
|
|
35
|
+
* Num.range(3, 3); // [3]
|
|
36
|
+
* ```
|
|
37
|
+
*/
|
|
38
|
+
Num.range = (from, to, step = 1) => {
|
|
39
|
+
if (step <= 0 || from > to)
|
|
40
|
+
return [];
|
|
41
|
+
const count = Math.floor((to - from) / step) + 1;
|
|
42
|
+
const result = new Array(count);
|
|
43
|
+
for (let i = 0; i < count; i++) {
|
|
44
|
+
result[i] = from + i * step;
|
|
45
|
+
}
|
|
46
|
+
return result;
|
|
47
|
+
};
|
|
48
|
+
/**
|
|
49
|
+
* Clamps a number between `min` and `max` (both inclusive).
|
|
50
|
+
*
|
|
51
|
+
* @example
|
|
52
|
+
* ```ts
|
|
53
|
+
* pipe(150, Num.clamp(0, 100)); // 100
|
|
54
|
+
* pipe(-5, Num.clamp(0, 100)); // 0
|
|
55
|
+
* pipe(42, Num.clamp(0, 100)); // 42
|
|
56
|
+
* ```
|
|
57
|
+
*/
|
|
58
|
+
Num.clamp = (min, max) => (n) => Math.min(Math.max(n, min), max);
|
|
59
|
+
/**
|
|
60
|
+
* Returns `true` when the number is between `min` and `max` (both inclusive).
|
|
61
|
+
*
|
|
62
|
+
* @example
|
|
63
|
+
* ```ts
|
|
64
|
+
* pipe(5, Num.between(1, 10)); // true
|
|
65
|
+
* pipe(0, Num.between(1, 10)); // false
|
|
66
|
+
* pipe(10, Num.between(1, 10)); // true
|
|
67
|
+
* ```
|
|
68
|
+
*/
|
|
69
|
+
Num.between = (min, max) => (n) => n >= min && n <= max;
|
|
70
|
+
/**
|
|
71
|
+
* Parses a string as a number. Returns `None` when the result is `NaN`.
|
|
72
|
+
*
|
|
73
|
+
* @example
|
|
74
|
+
* ```ts
|
|
75
|
+
* Num.parse("42"); // Some(42)
|
|
76
|
+
* Num.parse("3.14"); // Some(3.14)
|
|
77
|
+
* Num.parse("abc"); // None
|
|
78
|
+
* Num.parse(""); // None
|
|
79
|
+
* ```
|
|
80
|
+
*/
|
|
81
|
+
Num.parse = (s) => {
|
|
82
|
+
if (s.trim() === "")
|
|
83
|
+
return Option_js_1.Option.none();
|
|
84
|
+
const n = Number(s);
|
|
85
|
+
return isNaN(n) ? Option_js_1.Option.none() : Option_js_1.Option.some(n);
|
|
86
|
+
};
|
|
87
|
+
/**
|
|
88
|
+
* Adds `b` to a number. Data-last: use in `pipe` or `Arr.map`.
|
|
89
|
+
*
|
|
90
|
+
* @example
|
|
91
|
+
* ```ts
|
|
92
|
+
* pipe(5, Num.add(3)); // 8
|
|
93
|
+
* pipe([1, 2, 3], Arr.map(Num.add(10))); // [11, 12, 13]
|
|
94
|
+
* ```
|
|
95
|
+
*/
|
|
96
|
+
Num.add = (b) => (a) => a + b;
|
|
97
|
+
/**
|
|
98
|
+
* Subtracts `b` from a number. Data-last: `subtract(b)(a)` = `a - b`.
|
|
99
|
+
*
|
|
100
|
+
* @example
|
|
101
|
+
* ```ts
|
|
102
|
+
* pipe(10, Num.subtract(3)); // 7
|
|
103
|
+
* pipe([5, 10, 15], Arr.map(Num.subtract(2))); // [3, 8, 13]
|
|
104
|
+
* ```
|
|
105
|
+
*/
|
|
106
|
+
Num.subtract = (b) => (a) => a - b;
|
|
107
|
+
/**
|
|
108
|
+
* Multiplies a number by `b`. Data-last: use in `pipe` or `Arr.map`.
|
|
109
|
+
*
|
|
110
|
+
* @example
|
|
111
|
+
* ```ts
|
|
112
|
+
* pipe(6, Num.multiply(7)); // 42
|
|
113
|
+
* pipe([1, 2, 3], Arr.map(Num.multiply(100))); // [100, 200, 300]
|
|
114
|
+
* ```
|
|
115
|
+
*/
|
|
116
|
+
Num.multiply = (b) => (a) => a * b;
|
|
117
|
+
/**
|
|
118
|
+
* Divides a number by `b`. Data-last: `divide(b)(a)` = `a / b`.
|
|
119
|
+
*
|
|
120
|
+
* @example
|
|
121
|
+
* ```ts
|
|
122
|
+
* pipe(20, Num.divide(4)); // 5
|
|
123
|
+
* pipe([10, 20, 30], Arr.map(Num.divide(10))); // [1, 2, 3]
|
|
124
|
+
* ```
|
|
125
|
+
*/
|
|
126
|
+
Num.divide = (b) => (a) => a / b;
|
|
127
|
+
})(Num || (exports.Num = Num = {}));
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.Rec = void 0;
|
|
4
|
-
const Option_js_1 = require("
|
|
4
|
+
const Option_js_1 = require("../Core/Option.js");
|
|
5
5
|
/**
|
|
6
6
|
* Functional record/object utilities that compose well with pipe.
|
|
7
7
|
* All functions are data-last and curried where applicable.
|
|
@@ -26,9 +26,11 @@ var Rec;
|
|
|
26
26
|
* ```
|
|
27
27
|
*/
|
|
28
28
|
Rec.map = (f) => (data) => {
|
|
29
|
+
const keys = Object.keys(data);
|
|
30
|
+
const vals = Object.values(data);
|
|
29
31
|
const result = {};
|
|
30
|
-
for (
|
|
31
|
-
result[
|
|
32
|
+
for (let i = 0; i < keys.length; i++) {
|
|
33
|
+
result[keys[i]] = f(vals[i]);
|
|
32
34
|
}
|
|
33
35
|
return result;
|
|
34
36
|
};
|
|
@@ -42,9 +44,11 @@ var Rec;
|
|
|
42
44
|
* ```
|
|
43
45
|
*/
|
|
44
46
|
Rec.mapWithKey = (f) => (data) => {
|
|
47
|
+
const keys = Object.keys(data);
|
|
48
|
+
const vals = Object.values(data);
|
|
45
49
|
const result = {};
|
|
46
|
-
for (
|
|
47
|
-
result[
|
|
50
|
+
for (let i = 0; i < keys.length; i++) {
|
|
51
|
+
result[keys[i]] = f(keys[i], vals[i]);
|
|
48
52
|
}
|
|
49
53
|
return result;
|
|
50
54
|
};
|
|
@@ -57,10 +61,12 @@ var Rec;
|
|
|
57
61
|
* ```
|
|
58
62
|
*/
|
|
59
63
|
Rec.filter = (predicate) => (data) => {
|
|
64
|
+
const keys = Object.keys(data);
|
|
65
|
+
const vals = Object.values(data);
|
|
60
66
|
const result = {};
|
|
61
|
-
for (
|
|
62
|
-
if (predicate(
|
|
63
|
-
result[
|
|
67
|
+
for (let i = 0; i < keys.length; i++) {
|
|
68
|
+
if (predicate(vals[i]))
|
|
69
|
+
result[keys[i]] = vals[i];
|
|
64
70
|
}
|
|
65
71
|
return result;
|
|
66
72
|
};
|
|
@@ -74,10 +80,12 @@ var Rec;
|
|
|
74
80
|
* ```
|
|
75
81
|
*/
|
|
76
82
|
Rec.filterWithKey = (predicate) => (data) => {
|
|
83
|
+
const keys = Object.keys(data);
|
|
84
|
+
const vals = Object.values(data);
|
|
77
85
|
const result = {};
|
|
78
|
-
for (
|
|
79
|
-
if (predicate(
|
|
80
|
-
result[
|
|
86
|
+
for (let i = 0; i < keys.length; i++) {
|
|
87
|
+
if (predicate(keys[i], vals[i]))
|
|
88
|
+
result[keys[i]] = vals[i];
|
|
81
89
|
}
|
|
82
90
|
return result;
|
|
83
91
|
};
|
|
@@ -112,6 +120,32 @@ var Rec;
|
|
|
112
120
|
* ```
|
|
113
121
|
*/
|
|
114
122
|
Rec.fromEntries = (data) => Object.fromEntries(data);
|
|
123
|
+
/**
|
|
124
|
+
* Groups elements of an array into a record keyed by the result of `keyFn`. Each key maps to
|
|
125
|
+
* the array of elements that produced it, in insertion order.
|
|
126
|
+
*
|
|
127
|
+
* Unlike `Dict.groupBy`, keys are always strings. Use `Dict.groupBy` when you need non-string
|
|
128
|
+
* keys or want to avoid the plain-object prototype chain.
|
|
129
|
+
*
|
|
130
|
+
* @example
|
|
131
|
+
* ```ts
|
|
132
|
+
* pipe(
|
|
133
|
+
* ["apple", "avocado", "banana", "blueberry"],
|
|
134
|
+
* Rec.groupBy(s => s[0]),
|
|
135
|
+
* ); // { a: ["apple", "avocado"], b: ["banana", "blueberry"] }
|
|
136
|
+
* ```
|
|
137
|
+
*/
|
|
138
|
+
Rec.groupBy = (keyFn) => (items) => {
|
|
139
|
+
const result = {};
|
|
140
|
+
for (const item of items) {
|
|
141
|
+
const key = keyFn(item);
|
|
142
|
+
if (key in result)
|
|
143
|
+
result[key].push(item);
|
|
144
|
+
else
|
|
145
|
+
result[key] = [item];
|
|
146
|
+
}
|
|
147
|
+
return result;
|
|
148
|
+
};
|
|
115
149
|
/**
|
|
116
150
|
* Picks specific keys from a record.
|
|
117
151
|
*
|
|
@@ -167,4 +201,44 @@ var Rec;
|
|
|
167
201
|
* Returns the number of keys in a record.
|
|
168
202
|
*/
|
|
169
203
|
Rec.size = (data) => Object.keys(data).length;
|
|
204
|
+
/**
|
|
205
|
+
* Transforms each key while preserving values.
|
|
206
|
+
* If two keys map to the same new key, the last one wins.
|
|
207
|
+
*
|
|
208
|
+
* @example
|
|
209
|
+
* ```ts
|
|
210
|
+
* pipe({ firstName: "Alice", lastName: "Smith" }, Rec.mapKeys(k => k.toUpperCase()));
|
|
211
|
+
* // { FIRSTNAME: "Alice", LASTNAME: "Smith" }
|
|
212
|
+
* ```
|
|
213
|
+
*/
|
|
214
|
+
Rec.mapKeys = (f) => (data) => {
|
|
215
|
+
const keys = Object.keys(data);
|
|
216
|
+
const vals = Object.values(data);
|
|
217
|
+
const result = {};
|
|
218
|
+
for (let i = 0; i < keys.length; i++) {
|
|
219
|
+
result[f(keys[i])] = vals[i];
|
|
220
|
+
}
|
|
221
|
+
return result;
|
|
222
|
+
};
|
|
223
|
+
/**
|
|
224
|
+
* Removes all `None` values from a `Record<string, Option<A>>`, returning a plain `Record<string, A>`.
|
|
225
|
+
* Useful when building records from fallible lookups.
|
|
226
|
+
*
|
|
227
|
+
* @example
|
|
228
|
+
* ```ts
|
|
229
|
+
* Rec.compact({ a: Option.some(1), b: Option.none(), c: Option.some(3) });
|
|
230
|
+
* // { a: 1, c: 3 }
|
|
231
|
+
* ```
|
|
232
|
+
*/
|
|
233
|
+
Rec.compact = (data) => {
|
|
234
|
+
const keys = Object.keys(data);
|
|
235
|
+
const vals = Object.values(data);
|
|
236
|
+
const result = {};
|
|
237
|
+
for (let i = 0; i < keys.length; i++) {
|
|
238
|
+
const v = vals[i];
|
|
239
|
+
if (v.kind === "Some")
|
|
240
|
+
result[keys[i]] = v.value;
|
|
241
|
+
}
|
|
242
|
+
return result;
|
|
243
|
+
};
|
|
170
244
|
})(Rec || (exports.Rec = Rec = {}));
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Str = void 0;
|
|
4
|
+
const Option_js_1 = require("../Core/Option.js");
|
|
5
|
+
/**
|
|
6
|
+
* String utilities. All transformation functions are data-last and curried so they
|
|
7
|
+
* compose naturally with `pipe`. Safe parsers return `Option` instead of `NaN`.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```ts
|
|
11
|
+
* import { Str } from "@nlozgachev/pipelined/utils";
|
|
12
|
+
* import { pipe } from "@nlozgachev/pipelined/composition";
|
|
13
|
+
*
|
|
14
|
+
* pipe(" Hello, World! ", Str.trim, Str.toLowerCase); // "hello, world!"
|
|
15
|
+
* ```
|
|
16
|
+
*/
|
|
17
|
+
var Str;
|
|
18
|
+
(function (Str) {
|
|
19
|
+
/**
|
|
20
|
+
* Splits a string by a separator. Data-last: use in `pipe`.
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* ```ts
|
|
24
|
+
* pipe("a,b,c", Str.split(",")); // ["a", "b", "c"]
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
Str.split = (separator) => (s) => s.split(separator);
|
|
28
|
+
/**
|
|
29
|
+
* Removes leading and trailing whitespace from a string.
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* ```ts
|
|
33
|
+
* pipe(" hello ", Str.trim); // "hello"
|
|
34
|
+
* ```
|
|
35
|
+
*/
|
|
36
|
+
Str.trim = (s) => s.trim();
|
|
37
|
+
/**
|
|
38
|
+
* Returns `true` when the string contains the given substring.
|
|
39
|
+
*
|
|
40
|
+
* @example
|
|
41
|
+
* ```ts
|
|
42
|
+
* pipe("hello world", Str.includes("world")); // true
|
|
43
|
+
* pipe("hello world", Str.includes("xyz")); // false
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
Str.includes = (substring) => (s) => s.includes(substring);
|
|
47
|
+
/**
|
|
48
|
+
* Returns `true` when the string starts with the given prefix.
|
|
49
|
+
*
|
|
50
|
+
* @example
|
|
51
|
+
* ```ts
|
|
52
|
+
* pipe("hello world", Str.startsWith("hello")); // true
|
|
53
|
+
* pipe("hello world", Str.startsWith("world")); // false
|
|
54
|
+
* ```
|
|
55
|
+
*/
|
|
56
|
+
Str.startsWith = (prefix) => (s) => s.startsWith(prefix);
|
|
57
|
+
/**
|
|
58
|
+
* Returns `true` when the string ends with the given suffix.
|
|
59
|
+
*
|
|
60
|
+
* @example
|
|
61
|
+
* ```ts
|
|
62
|
+
* pipe("hello world", Str.endsWith("world")); // true
|
|
63
|
+
* pipe("hello world", Str.endsWith("hello")); // false
|
|
64
|
+
* ```
|
|
65
|
+
*/
|
|
66
|
+
Str.endsWith = (suffix) => (s) => s.endsWith(suffix);
|
|
67
|
+
/**
|
|
68
|
+
* Converts a string to uppercase.
|
|
69
|
+
*
|
|
70
|
+
* @example
|
|
71
|
+
* ```ts
|
|
72
|
+
* pipe("hello", Str.toUpperCase); // "HELLO"
|
|
73
|
+
* ```
|
|
74
|
+
*/
|
|
75
|
+
Str.toUpperCase = (s) => s.toUpperCase();
|
|
76
|
+
/**
|
|
77
|
+
* Converts a string to lowercase.
|
|
78
|
+
*
|
|
79
|
+
* @example
|
|
80
|
+
* ```ts
|
|
81
|
+
* pipe("HELLO", Str.toLowerCase); // "hello"
|
|
82
|
+
* ```
|
|
83
|
+
*/
|
|
84
|
+
Str.toLowerCase = (s) => s.toLowerCase();
|
|
85
|
+
/**
|
|
86
|
+
* Splits a string into lines, normalising `\r\n` and `\r` line endings.
|
|
87
|
+
*
|
|
88
|
+
* @example
|
|
89
|
+
* ```ts
|
|
90
|
+
* Str.lines("one\ntwo\nthree"); // ["one", "two", "three"]
|
|
91
|
+
* Str.lines("a\r\nb"); // ["a", "b"]
|
|
92
|
+
* ```
|
|
93
|
+
*/
|
|
94
|
+
Str.lines = (s) => s.split(/\r?\n|\r/);
|
|
95
|
+
/**
|
|
96
|
+
* Splits a string into words on any whitespace boundary, filtering out empty strings.
|
|
97
|
+
*
|
|
98
|
+
* @example
|
|
99
|
+
* ```ts
|
|
100
|
+
* Str.words(" hello world "); // ["hello", "world"]
|
|
101
|
+
* ```
|
|
102
|
+
*/
|
|
103
|
+
Str.words = (s) => s.trim().split(/\s+/).filter(Boolean);
|
|
104
|
+
/**
|
|
105
|
+
* Safe number parsers that return `Option` instead of `NaN`.
|
|
106
|
+
*/
|
|
107
|
+
Str.parse = {
|
|
108
|
+
/**
|
|
109
|
+
* Parses a string as an integer (base 10). Returns `None` if the result is `NaN`.
|
|
110
|
+
*
|
|
111
|
+
* @example
|
|
112
|
+
* ```ts
|
|
113
|
+
* Str.parse.int("42"); // Some(42)
|
|
114
|
+
* Str.parse.int("3.7"); // Some(3)
|
|
115
|
+
* Str.parse.int("abc"); // None
|
|
116
|
+
* ```
|
|
117
|
+
*/
|
|
118
|
+
int: (s) => {
|
|
119
|
+
const n = parseInt(s, 10);
|
|
120
|
+
return isNaN(n) ? Option_js_1.Option.none() : Option_js_1.Option.some(n);
|
|
121
|
+
},
|
|
122
|
+
/**
|
|
123
|
+
* Parses a string as a floating-point number. Returns `None` if the result is `NaN`.
|
|
124
|
+
*
|
|
125
|
+
* @example
|
|
126
|
+
* ```ts
|
|
127
|
+
* Str.parse.float("3.14"); // Some(3.14)
|
|
128
|
+
* Str.parse.float("42"); // Some(42)
|
|
129
|
+
* Str.parse.float("abc"); // None
|
|
130
|
+
* ```
|
|
131
|
+
*/
|
|
132
|
+
float: (s) => {
|
|
133
|
+
const n = parseFloat(s);
|
|
134
|
+
return isNaN(n) ? Option_js_1.Option.none() : Option_js_1.Option.some(n);
|
|
135
|
+
},
|
|
136
|
+
};
|
|
137
|
+
})(Str || (exports.Str = Str = {}));
|
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Uniq = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Functional utilities for unique-value collections (`ReadonlySet<A>`). All functions are pure
|
|
6
|
+
* and data-last — they compose naturally with `pipe`.
|
|
7
|
+
*
|
|
8
|
+
* Every "mutating" operation returns a new set; the original is never changed.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```ts
|
|
12
|
+
* import { Uniq } from "@nlozgachev/pipelined/utils";
|
|
13
|
+
* import { pipe } from "@nlozgachev/pipelined/composition";
|
|
14
|
+
*
|
|
15
|
+
* const active = pipe(
|
|
16
|
+
* Uniq.fromArray(["alice", "bob", "alice", "carol"]),
|
|
17
|
+
* Uniq.remove("bob"),
|
|
18
|
+
* Uniq.map(name => name.toUpperCase()),
|
|
19
|
+
* );
|
|
20
|
+
* // ReadonlySet { "ALICE", "CAROL" }
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
var Uniq;
|
|
24
|
+
(function (Uniq) {
|
|
25
|
+
// ---------------------------------------------------------------------------
|
|
26
|
+
// Constructors
|
|
27
|
+
// ---------------------------------------------------------------------------
|
|
28
|
+
/**
|
|
29
|
+
* Creates an empty unique collection.
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* ```ts
|
|
33
|
+
* Uniq.empty<number>(); // ReadonlySet {}
|
|
34
|
+
* ```
|
|
35
|
+
*/
|
|
36
|
+
Uniq.empty = () => new globalThis.Set();
|
|
37
|
+
/**
|
|
38
|
+
* Creates a unique collection containing a single item.
|
|
39
|
+
*
|
|
40
|
+
* @example
|
|
41
|
+
* ```ts
|
|
42
|
+
* Uniq.singleton(42); // ReadonlySet { 42 }
|
|
43
|
+
* ```
|
|
44
|
+
*/
|
|
45
|
+
Uniq.singleton = (item) => new globalThis.Set([item]);
|
|
46
|
+
/**
|
|
47
|
+
* Creates a unique collection from an array, automatically discarding duplicates.
|
|
48
|
+
*
|
|
49
|
+
* @example
|
|
50
|
+
* ```ts
|
|
51
|
+
* Uniq.fromArray([1, 2, 2, 3, 3, 3]); // ReadonlySet { 1, 2, 3 }
|
|
52
|
+
* Uniq.fromArray([]); // ReadonlySet {}
|
|
53
|
+
* ```
|
|
54
|
+
*/
|
|
55
|
+
Uniq.fromArray = (arr) => new globalThis.Set(arr);
|
|
56
|
+
// ---------------------------------------------------------------------------
|
|
57
|
+
// Query
|
|
58
|
+
// ---------------------------------------------------------------------------
|
|
59
|
+
/**
|
|
60
|
+
* Returns `true` if the collection contains the given item.
|
|
61
|
+
*
|
|
62
|
+
* @example
|
|
63
|
+
* ```ts
|
|
64
|
+
* pipe(Uniq.fromArray([1, 2, 3]), Uniq.has(2)); // true
|
|
65
|
+
* pipe(Uniq.fromArray([1, 2, 3]), Uniq.has(4)); // false
|
|
66
|
+
* ```
|
|
67
|
+
*/
|
|
68
|
+
Uniq.has = (item) => (s) => s.has(item);
|
|
69
|
+
/**
|
|
70
|
+
* Returns the number of items in the collection.
|
|
71
|
+
*
|
|
72
|
+
* @example
|
|
73
|
+
* ```ts
|
|
74
|
+
* Uniq.size(Uniq.fromArray([1, 2, 3])); // 3
|
|
75
|
+
* ```
|
|
76
|
+
*/
|
|
77
|
+
Uniq.size = (s) => s.size;
|
|
78
|
+
/**
|
|
79
|
+
* Returns `true` if the collection has no items.
|
|
80
|
+
*
|
|
81
|
+
* @example
|
|
82
|
+
* ```ts
|
|
83
|
+
* Uniq.isEmpty(Uniq.empty()); // true
|
|
84
|
+
* ```
|
|
85
|
+
*/
|
|
86
|
+
Uniq.isEmpty = (s) => s.size === 0;
|
|
87
|
+
/**
|
|
88
|
+
* Returns `true` if every item in `set` also exists in `other`.
|
|
89
|
+
*
|
|
90
|
+
* @example
|
|
91
|
+
* ```ts
|
|
92
|
+
* pipe(Uniq.fromArray([1, 2]), Uniq.isSubsetOf(Uniq.fromArray([1, 2, 3]))); // true
|
|
93
|
+
* pipe(Uniq.fromArray([1, 4]), Uniq.isSubsetOf(Uniq.fromArray([1, 2, 3]))); // false
|
|
94
|
+
* pipe(Uniq.empty<number>(), Uniq.isSubsetOf(Uniq.fromArray([1, 2, 3]))); // true
|
|
95
|
+
* ```
|
|
96
|
+
*/
|
|
97
|
+
Uniq.isSubsetOf = (other) => (s) => {
|
|
98
|
+
const set = s;
|
|
99
|
+
if (typeof set.isSubsetOf === "function")
|
|
100
|
+
return set.isSubsetOf(other);
|
|
101
|
+
for (const item of s)
|
|
102
|
+
if (!other.has(item))
|
|
103
|
+
return false;
|
|
104
|
+
return true;
|
|
105
|
+
};
|
|
106
|
+
// ---------------------------------------------------------------------------
|
|
107
|
+
// Modification
|
|
108
|
+
// ---------------------------------------------------------------------------
|
|
109
|
+
/**
|
|
110
|
+
* Returns a new collection with the item added. If the item is already present, returns the
|
|
111
|
+
* original collection unchanged.
|
|
112
|
+
*
|
|
113
|
+
* @example
|
|
114
|
+
* ```ts
|
|
115
|
+
* pipe(Uniq.fromArray([1, 2]), Uniq.insert(3)); // ReadonlySet { 1, 2, 3 }
|
|
116
|
+
* pipe(Uniq.fromArray([1, 2]), Uniq.insert(2)); // ReadonlySet { 1, 2 } — unchanged
|
|
117
|
+
* ```
|
|
118
|
+
*/
|
|
119
|
+
Uniq.insert = (item) => (s) => {
|
|
120
|
+
if (s.has(item))
|
|
121
|
+
return s;
|
|
122
|
+
const result = new globalThis.Set(s);
|
|
123
|
+
result.add(item);
|
|
124
|
+
return result;
|
|
125
|
+
};
|
|
126
|
+
/**
|
|
127
|
+
* Returns a new collection with the item removed. If the item is not present, returns the
|
|
128
|
+
* original collection unchanged.
|
|
129
|
+
*
|
|
130
|
+
* @example
|
|
131
|
+
* ```ts
|
|
132
|
+
* pipe(Uniq.fromArray([1, 2, 3]), Uniq.remove(2)); // ReadonlySet { 1, 3 }
|
|
133
|
+
* pipe(Uniq.fromArray([1, 2, 3]), Uniq.remove(4)); // ReadonlySet { 1, 2, 3 } — unchanged
|
|
134
|
+
* ```
|
|
135
|
+
*/
|
|
136
|
+
Uniq.remove = (item) => (s) => {
|
|
137
|
+
if (!s.has(item))
|
|
138
|
+
return s;
|
|
139
|
+
const result = new globalThis.Set(s);
|
|
140
|
+
result.delete(item);
|
|
141
|
+
return result;
|
|
142
|
+
};
|
|
143
|
+
// ---------------------------------------------------------------------------
|
|
144
|
+
// Transform
|
|
145
|
+
// ---------------------------------------------------------------------------
|
|
146
|
+
/**
|
|
147
|
+
* Applies `f` to each item, returning a new collection of the results. Duplicate results are
|
|
148
|
+
* automatically merged.
|
|
149
|
+
*
|
|
150
|
+
* @example
|
|
151
|
+
* ```ts
|
|
152
|
+
* pipe(Uniq.fromArray([1, 2, 3, 4]), Uniq.map(n => n % 3)); // ReadonlySet { 1, 2, 0 }
|
|
153
|
+
* ```
|
|
154
|
+
*/
|
|
155
|
+
Uniq.map = (f) => (s) => {
|
|
156
|
+
const result = new globalThis.Set();
|
|
157
|
+
for (const item of s) {
|
|
158
|
+
result.add(f(item));
|
|
159
|
+
}
|
|
160
|
+
return result;
|
|
161
|
+
};
|
|
162
|
+
/**
|
|
163
|
+
* Returns a new collection containing only the items for which the predicate returns `true`.
|
|
164
|
+
*
|
|
165
|
+
* @example
|
|
166
|
+
* ```ts
|
|
167
|
+
* pipe(Uniq.fromArray([1, 2, 3, 4, 5]), Uniq.filter(n => n % 2 === 0));
|
|
168
|
+
* // ReadonlySet { 2, 4 }
|
|
169
|
+
* ```
|
|
170
|
+
*/
|
|
171
|
+
Uniq.filter = (predicate) => (s) => {
|
|
172
|
+
const result = new globalThis.Set();
|
|
173
|
+
for (const item of s) {
|
|
174
|
+
if (predicate(item))
|
|
175
|
+
result.add(item);
|
|
176
|
+
}
|
|
177
|
+
return result;
|
|
178
|
+
};
|
|
179
|
+
// ---------------------------------------------------------------------------
|
|
180
|
+
// Set operations
|
|
181
|
+
// ---------------------------------------------------------------------------
|
|
182
|
+
/**
|
|
183
|
+
* Returns a new collection containing all items from both collections.
|
|
184
|
+
*
|
|
185
|
+
* @example
|
|
186
|
+
* ```ts
|
|
187
|
+
* pipe(Uniq.fromArray([1, 2, 3]), Uniq.union(Uniq.fromArray([2, 3, 4])));
|
|
188
|
+
* // ReadonlySet { 1, 2, 3, 4 }
|
|
189
|
+
* ```
|
|
190
|
+
*/
|
|
191
|
+
Uniq.union = (other) => (s) => {
|
|
192
|
+
const set = s;
|
|
193
|
+
if (typeof set.union === "function")
|
|
194
|
+
return set.union(other);
|
|
195
|
+
const result = new globalThis.Set(s);
|
|
196
|
+
for (const item of other)
|
|
197
|
+
result.add(item);
|
|
198
|
+
return result;
|
|
199
|
+
};
|
|
200
|
+
/**
|
|
201
|
+
* Returns a new collection containing only the items that appear in both collections.
|
|
202
|
+
*
|
|
203
|
+
* @example
|
|
204
|
+
* ```ts
|
|
205
|
+
* pipe(Uniq.fromArray([1, 2, 3]), Uniq.intersection(Uniq.fromArray([2, 3, 4])));
|
|
206
|
+
* // ReadonlySet { 2, 3 }
|
|
207
|
+
* ```
|
|
208
|
+
*/
|
|
209
|
+
Uniq.intersection = (other) => (s) => {
|
|
210
|
+
const set = s;
|
|
211
|
+
if (typeof set.intersection === "function")
|
|
212
|
+
return set.intersection(other);
|
|
213
|
+
const result = new globalThis.Set();
|
|
214
|
+
for (const item of s)
|
|
215
|
+
if (other.has(item))
|
|
216
|
+
result.add(item);
|
|
217
|
+
return result;
|
|
218
|
+
};
|
|
219
|
+
/**
|
|
220
|
+
* Returns a new collection containing only the items from `set` that do not appear in `other`.
|
|
221
|
+
*
|
|
222
|
+
* @example
|
|
223
|
+
* ```ts
|
|
224
|
+
* pipe(Uniq.fromArray([1, 2, 3, 4]), Uniq.difference(Uniq.fromArray([2, 4])));
|
|
225
|
+
* // ReadonlySet { 1, 3 }
|
|
226
|
+
* ```
|
|
227
|
+
*/
|
|
228
|
+
Uniq.difference = (other) => (s) => {
|
|
229
|
+
const set = s;
|
|
230
|
+
if (typeof set.difference === "function")
|
|
231
|
+
return set.difference(other);
|
|
232
|
+
const result = new globalThis.Set();
|
|
233
|
+
for (const item of s)
|
|
234
|
+
if (!other.has(item))
|
|
235
|
+
result.add(item);
|
|
236
|
+
return result;
|
|
237
|
+
};
|
|
238
|
+
// ---------------------------------------------------------------------------
|
|
239
|
+
// Fold
|
|
240
|
+
// ---------------------------------------------------------------------------
|
|
241
|
+
/**
|
|
242
|
+
* Folds the collection into a single value by applying `f` to each item in insertion order.
|
|
243
|
+
*
|
|
244
|
+
* @example
|
|
245
|
+
* ```ts
|
|
246
|
+
* Uniq.reduce(0, (acc, n) => acc + n)(Uniq.fromArray([1, 2, 3])); // 6
|
|
247
|
+
* ```
|
|
248
|
+
*/
|
|
249
|
+
Uniq.reduce = (init, f) => (s) => {
|
|
250
|
+
let acc = init;
|
|
251
|
+
for (const item of s) {
|
|
252
|
+
acc = f(acc, item);
|
|
253
|
+
}
|
|
254
|
+
return acc;
|
|
255
|
+
};
|
|
256
|
+
// ---------------------------------------------------------------------------
|
|
257
|
+
// Convert
|
|
258
|
+
// ---------------------------------------------------------------------------
|
|
259
|
+
/**
|
|
260
|
+
* Converts the collection to a readonly array in insertion order.
|
|
261
|
+
*
|
|
262
|
+
* @example
|
|
263
|
+
* ```ts
|
|
264
|
+
* Uniq.toArray(Uniq.fromArray([3, 1, 2])); // [3, 1, 2]
|
|
265
|
+
* ```
|
|
266
|
+
*/
|
|
267
|
+
Uniq.toArray = (s) => [...s];
|
|
268
|
+
})(Uniq || (exports.Uniq = Uniq = {}));
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./Arr.js"), exports);
|
|
18
|
+
__exportStar(require("./Rec.js"), exports);
|
|
19
|
+
__exportStar(require("./Num.js"), exports);
|
|
20
|
+
__exportStar(require("./Str.js"), exports);
|
|
21
|
+
__exportStar(require("./Dict.js"), exports);
|
|
22
|
+
__exportStar(require("./Uniq.js"), exports);
|