@nlozgachev/pipekit 0.1.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +182 -0
- package/esm/mod.js +3 -0
- package/esm/package.json +3 -0
- package/esm/src/Composition/compose.js +3 -0
- package/esm/src/Composition/curry.js +42 -0
- package/esm/src/Composition/flip.js +20 -0
- package/esm/src/Composition/flow.js +8 -0
- package/esm/src/Composition/fn.js +85 -0
- package/esm/src/Composition/index.js +10 -0
- package/esm/src/Composition/memoize.js +66 -0
- package/esm/src/Composition/not.js +25 -0
- package/esm/src/Composition/pipe.js +3 -0
- package/esm/src/Composition/tap.js +33 -0
- package/esm/src/Composition/uncurry.js +32 -0
- package/esm/src/Core/Arr.js +461 -0
- package/esm/src/Core/InternalTypes.js +1 -0
- package/esm/src/Core/Option.js +195 -0
- package/esm/src/Core/Rec.js +167 -0
- package/esm/src/Core/RemoteData.js +210 -0
- package/esm/src/Core/Result.js +173 -0
- package/esm/src/Core/Task.js +108 -0
- package/esm/src/Core/TaskResult.js +63 -0
- package/esm/src/Core/Validation.js +215 -0
- package/esm/src/Core/index.js +8 -0
- package/esm/src/Types/NonEmptyList.js +14 -0
- package/esm/src/Types/index.js +1 -0
- package/package.json +60 -0
- package/script/mod.js +19 -0
- package/script/package.json +3 -0
- package/script/src/Composition/compose.js +6 -0
- package/script/src/Composition/curry.js +48 -0
- package/script/src/Composition/flip.js +24 -0
- package/script/src/Composition/flow.js +11 -0
- package/script/src/Composition/fn.js +98 -0
- package/script/src/Composition/index.js +26 -0
- package/script/src/Composition/memoize.js +71 -0
- package/script/src/Composition/not.js +29 -0
- package/script/src/Composition/pipe.js +6 -0
- package/script/src/Composition/tap.js +37 -0
- package/script/src/Composition/uncurry.js +38 -0
- package/script/src/Core/Arr.js +464 -0
- package/script/src/Core/InternalTypes.js +2 -0
- package/script/src/Core/Option.js +198 -0
- package/script/src/Core/Rec.js +170 -0
- package/script/src/Core/RemoteData.js +213 -0
- package/script/src/Core/Result.js +176 -0
- package/script/src/Core/Task.js +111 -0
- package/script/src/Core/TaskResult.js +66 -0
- package/script/src/Core/Validation.js +218 -0
- package/script/src/Core/index.js +24 -0
- package/script/src/Types/NonEmptyList.js +18 -0
- package/script/src/Types/index.js +17 -0
- package/types/mod.d.ts +4 -0
- package/types/mod.d.ts.map +1 -0
- package/types/src/Composition/compose.d.ts +33 -0
- package/types/src/Composition/compose.d.ts.map +1 -0
- package/types/src/Composition/curry.d.ts +43 -0
- package/types/src/Composition/curry.d.ts.map +1 -0
- package/types/src/Composition/flip.d.ts +21 -0
- package/types/src/Composition/flip.d.ts.map +1 -0
- package/types/src/Composition/flow.d.ts +56 -0
- package/types/src/Composition/flow.d.ts.map +1 -0
- package/types/src/Composition/fn.d.ts +76 -0
- package/types/src/Composition/fn.d.ts.map +1 -0
- package/types/src/Composition/index.d.ts +11 -0
- package/types/src/Composition/index.d.ts.map +1 -0
- package/types/src/Composition/memoize.d.ts +46 -0
- package/types/src/Composition/memoize.d.ts.map +1 -0
- package/types/src/Composition/not.d.ts +26 -0
- package/types/src/Composition/not.d.ts.map +1 -0
- package/types/src/Composition/pipe.d.ts +56 -0
- package/types/src/Composition/pipe.d.ts.map +1 -0
- package/types/src/Composition/tap.d.ts +31 -0
- package/types/src/Composition/tap.d.ts.map +1 -0
- package/types/src/Composition/uncurry.d.ts +54 -0
- package/types/src/Composition/uncurry.d.ts.map +1 -0
- package/types/src/Core/Arr.d.ts +355 -0
- package/types/src/Core/Arr.d.ts.map +1 -0
- package/types/src/Core/InternalTypes.d.ts +14 -0
- package/types/src/Core/InternalTypes.d.ts.map +1 -0
- package/types/src/Core/Option.d.ts +214 -0
- package/types/src/Core/Option.d.ts.map +1 -0
- package/types/src/Core/Rec.d.ts +121 -0
- package/types/src/Core/Rec.d.ts.map +1 -0
- package/types/src/Core/RemoteData.d.ts +196 -0
- package/types/src/Core/RemoteData.d.ts.map +1 -0
- package/types/src/Core/Result.d.ts +185 -0
- package/types/src/Core/Result.d.ts.map +1 -0
- package/types/src/Core/Task.d.ts +125 -0
- package/types/src/Core/Task.d.ts.map +1 -0
- package/types/src/Core/TaskResult.d.ts +78 -0
- package/types/src/Core/TaskResult.d.ts.map +1 -0
- package/types/src/Core/Validation.d.ts +217 -0
- package/types/src/Core/Validation.d.ts.map +1 -0
- package/types/src/Core/index.d.ts +9 -0
- package/types/src/Core/index.d.ts.map +1 -0
- package/types/src/Types/NonEmptyList.d.ts +29 -0
- package/types/src/Types/NonEmptyList.d.ts.map +1 -0
- package/types/src/Types/index.d.ts +2 -0
- package/types/src/Types/index.d.ts.map +1 -0
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { Result } from "./Result.js";
|
|
2
|
+
import { Task } from "./Task.js";
|
|
3
|
+
export var TaskResult;
|
|
4
|
+
(function (TaskResult) {
|
|
5
|
+
/**
|
|
6
|
+
* Wraps a value in a successful TaskResult.
|
|
7
|
+
*/
|
|
8
|
+
TaskResult.of = (value) => Task.of(Result.toOk(value));
|
|
9
|
+
/**
|
|
10
|
+
* Creates a failed TaskResult with the given error.
|
|
11
|
+
*/
|
|
12
|
+
TaskResult.fail = (error) => Task.of(Result.toErr(error));
|
|
13
|
+
/**
|
|
14
|
+
* Creates a TaskResult from a function that may throw.
|
|
15
|
+
* Catches any errors and transforms them using the onError function.
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```ts
|
|
19
|
+
* const parseJson = (s: string): TaskResult<string, unknown> =>
|
|
20
|
+
* TaskResult.tryCatch(
|
|
21
|
+
* async () => JSON.parse(s),
|
|
22
|
+
* (e) => `Parse error: ${e}`
|
|
23
|
+
* );
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
TaskResult.tryCatch = (f, onError) => () => f()
|
|
27
|
+
.then(Result.toOk)
|
|
28
|
+
.catch((e) => Result.toErr(onError(e)));
|
|
29
|
+
/**
|
|
30
|
+
* Transforms the success value inside a TaskResult.
|
|
31
|
+
*/
|
|
32
|
+
TaskResult.map = (f) => (data) => Task.map(Result.map(f))(data);
|
|
33
|
+
/**
|
|
34
|
+
* Transforms the error value inside a TaskResult.
|
|
35
|
+
*/
|
|
36
|
+
TaskResult.mapError = (f) => (data) => Task.map(Result.mapError(f))(data);
|
|
37
|
+
/**
|
|
38
|
+
* Chains TaskResult computations. If the first succeeds, passes the value to f.
|
|
39
|
+
* If the first fails, propagates the error.
|
|
40
|
+
*/
|
|
41
|
+
TaskResult.chain = (f) => (data) => Task.chain((result) => Result.isOk(result) ? f(result.value) : Task.of(Result.toErr(result.error)))(data);
|
|
42
|
+
/**
|
|
43
|
+
* Extracts the value from a TaskResult by providing handlers for both cases.
|
|
44
|
+
*/
|
|
45
|
+
TaskResult.fold = (onErr, onOk) => (data) => Task.map(Result.fold(onErr, onOk))(data);
|
|
46
|
+
/**
|
|
47
|
+
* Pattern matches on a TaskResult, returning a Task of the result.
|
|
48
|
+
*/
|
|
49
|
+
TaskResult.match = (cases) => (data) => Task.map(Result.match(cases))(data);
|
|
50
|
+
/**
|
|
51
|
+
* Recovers from an error by providing a fallback TaskResult.
|
|
52
|
+
*/
|
|
53
|
+
TaskResult.recover = (fallback) => (data) => Task.chain((result) => Result.isErr(result) ? fallback(result.error) : Task.of(result))(data);
|
|
54
|
+
/**
|
|
55
|
+
* Returns the success value or a default value if the TaskResult is an error.
|
|
56
|
+
*/
|
|
57
|
+
TaskResult.getOrElse = (defaultValue) => (data) => Task.map(Result.getOrElse(defaultValue))(data);
|
|
58
|
+
/**
|
|
59
|
+
* Executes a side effect on the success value without changing the TaskResult.
|
|
60
|
+
* Useful for logging or debugging.
|
|
61
|
+
*/
|
|
62
|
+
TaskResult.tap = (f) => (data) => Task.map(Result.tap(f))(data);
|
|
63
|
+
})(TaskResult || (TaskResult = {}));
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
import { isNonEmptyList } from "../Types/NonEmptyList.js";
|
|
2
|
+
export var Validation;
|
|
3
|
+
(function (Validation) {
|
|
4
|
+
/**
|
|
5
|
+
* Wraps a value in a valid Validation.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```ts
|
|
9
|
+
* Validation.of(42); // Valid(42)
|
|
10
|
+
* ```
|
|
11
|
+
*/
|
|
12
|
+
Validation.of = (value) => ({
|
|
13
|
+
kind: "Valid",
|
|
14
|
+
value,
|
|
15
|
+
});
|
|
16
|
+
/**
|
|
17
|
+
* Creates a valid Validation with the given value.
|
|
18
|
+
*/
|
|
19
|
+
Validation.toValid = (value) => ({ kind: "Valid", value });
|
|
20
|
+
/**
|
|
21
|
+
* Type guard that checks if a Validation is valid.
|
|
22
|
+
*/
|
|
23
|
+
Validation.isValid = (data) => data.kind === "Valid";
|
|
24
|
+
/**
|
|
25
|
+
* Creates an invalid Validation with the given errors.
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* ```ts
|
|
29
|
+
* Validation.toInvalid(["Email is invalid", "Password too short"]);
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
Validation.toInvalid = (errors) => ({
|
|
33
|
+
kind: "Invalid",
|
|
34
|
+
errors,
|
|
35
|
+
});
|
|
36
|
+
/**
|
|
37
|
+
* Type guard that checks if a Validation is invalid.
|
|
38
|
+
*/
|
|
39
|
+
Validation.isInvalid = (data) => data.kind === "Invalid";
|
|
40
|
+
/**
|
|
41
|
+
* Creates an invalid Validation from a single error.
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* ```ts
|
|
45
|
+
* Validation.fail("Invalid input");
|
|
46
|
+
* ```
|
|
47
|
+
*/
|
|
48
|
+
Validation.fail = (error) => Validation.toInvalid([error]);
|
|
49
|
+
/**
|
|
50
|
+
* Transforms the success value inside a Validation.
|
|
51
|
+
*
|
|
52
|
+
* @example
|
|
53
|
+
* ```ts
|
|
54
|
+
* pipe(Validation.of(5), Validation.map(n => n * 2)); // Valid(10)
|
|
55
|
+
* pipe(Validation.fail("oops"), Validation.map(n => n * 2)); // Invalid(["oops"])
|
|
56
|
+
* ```
|
|
57
|
+
*/
|
|
58
|
+
Validation.map = (f) => (data) => Validation.isValid(data) ? Validation.of(f(data.value)) : data;
|
|
59
|
+
/**
|
|
60
|
+
* Chains Validation computations. If the first is Valid, passes the value to f.
|
|
61
|
+
* If the first is Invalid, propagates the errors.
|
|
62
|
+
*
|
|
63
|
+
* Note: chain short-circuits on first error. Use `ap` to accumulate errors.
|
|
64
|
+
*
|
|
65
|
+
* @example
|
|
66
|
+
* ```ts
|
|
67
|
+
* const validatePositive = (n: number): Validation<string, number> =>
|
|
68
|
+
* n > 0 ? Validation.of(n) : Validation.fail("Must be positive");
|
|
69
|
+
*
|
|
70
|
+
* pipe(Validation.of(5), Validation.chain(validatePositive)); // Valid(5)
|
|
71
|
+
* pipe(Validation.of(-1), Validation.chain(validatePositive)); // Invalid(["Must be positive"])
|
|
72
|
+
* ```
|
|
73
|
+
*/
|
|
74
|
+
Validation.chain = (f) => (data) => Validation.isValid(data) ? f(data.value) : data;
|
|
75
|
+
/**
|
|
76
|
+
* Applies a function wrapped in a Validation to a value wrapped in a Validation.
|
|
77
|
+
* Accumulates errors from both sides.
|
|
78
|
+
*
|
|
79
|
+
* @example
|
|
80
|
+
* ```ts
|
|
81
|
+
* const add = (a: number) => (b: number) => a + b;
|
|
82
|
+
* pipe(
|
|
83
|
+
* Validation.of(add),
|
|
84
|
+
* Validation.ap(Validation.of(5)),
|
|
85
|
+
* Validation.ap(Validation.of(3))
|
|
86
|
+
* ); // Valid(8)
|
|
87
|
+
*
|
|
88
|
+
* pipe(
|
|
89
|
+
* Validation.of(add),
|
|
90
|
+
* Validation.ap(Validation.fail<string, number>("bad a")),
|
|
91
|
+
* Validation.ap(Validation.fail<string, number>("bad b"))
|
|
92
|
+
* ); // Invalid(["bad a", "bad b"])
|
|
93
|
+
* ```
|
|
94
|
+
*/
|
|
95
|
+
Validation.ap = (arg) => (data) => {
|
|
96
|
+
if (Validation.isValid(data) && Validation.isValid(arg))
|
|
97
|
+
return Validation.of(data.value(arg.value));
|
|
98
|
+
const errors = [
|
|
99
|
+
...(Validation.isInvalid(data) ? data.errors : []),
|
|
100
|
+
...(Validation.isInvalid(arg) ? arg.errors : []),
|
|
101
|
+
];
|
|
102
|
+
return isNonEmptyList(errors) ? Validation.toInvalid(errors) : Validation.of(data);
|
|
103
|
+
};
|
|
104
|
+
/**
|
|
105
|
+
* Extracts the value from a Validation by providing handlers for both cases.
|
|
106
|
+
*
|
|
107
|
+
* @example
|
|
108
|
+
* ```ts
|
|
109
|
+
* pipe(
|
|
110
|
+
* Validation.of(42),
|
|
111
|
+
* Validation.fold(
|
|
112
|
+
* errors => `Errors: ${errors.join(", ")}`,
|
|
113
|
+
* value => `Value: ${value}`
|
|
114
|
+
* )
|
|
115
|
+
* );
|
|
116
|
+
* ```
|
|
117
|
+
*/
|
|
118
|
+
Validation.fold = (onInvalid, onValid) => (data) => Validation.isValid(data) ? onValid(data.value) : onInvalid(data.errors);
|
|
119
|
+
/**
|
|
120
|
+
* Pattern matches on a Validation, returning the result of the matching case.
|
|
121
|
+
*
|
|
122
|
+
* @example
|
|
123
|
+
* ```ts
|
|
124
|
+
* pipe(
|
|
125
|
+
* validation,
|
|
126
|
+
* Validation.match({
|
|
127
|
+
* valid: value => `Got ${value}`,
|
|
128
|
+
* invalid: errors => `Failed: ${errors.join(", ")}`
|
|
129
|
+
* })
|
|
130
|
+
* );
|
|
131
|
+
* ```
|
|
132
|
+
*/
|
|
133
|
+
Validation.match = (cases) => (data) => Validation.isValid(data) ? cases.valid(data.value) : cases.invalid(data.errors);
|
|
134
|
+
/**
|
|
135
|
+
* Returns the success value or a default value if the Validation is invalid.
|
|
136
|
+
*
|
|
137
|
+
* @example
|
|
138
|
+
* ```ts
|
|
139
|
+
* pipe(Validation.of(5), Validation.getOrElse(0)); // 5
|
|
140
|
+
* pipe(Validation.fail("oops"), Validation.getOrElse(0)); // 0
|
|
141
|
+
* ```
|
|
142
|
+
*/
|
|
143
|
+
Validation.getOrElse = (defaultValue) => (data) => Validation.isValid(data) ? data.value : defaultValue;
|
|
144
|
+
/**
|
|
145
|
+
* Executes a side effect on the success value without changing the Validation.
|
|
146
|
+
*
|
|
147
|
+
* @example
|
|
148
|
+
* ```ts
|
|
149
|
+
* pipe(
|
|
150
|
+
* Validation.of(5),
|
|
151
|
+
* Validation.tap(n => console.log("Value:", n)),
|
|
152
|
+
* Validation.map(n => n * 2)
|
|
153
|
+
* );
|
|
154
|
+
* ```
|
|
155
|
+
*/
|
|
156
|
+
Validation.tap = (f) => (data) => {
|
|
157
|
+
if (Validation.isValid(data))
|
|
158
|
+
f(data.value);
|
|
159
|
+
return data;
|
|
160
|
+
};
|
|
161
|
+
/**
|
|
162
|
+
* Recovers from an Invalid state by providing a fallback Validation.
|
|
163
|
+
*/
|
|
164
|
+
Validation.recover = (fallback) => (data) => Validation.isValid(data) ? data : fallback();
|
|
165
|
+
/**
|
|
166
|
+
* Recovers from an Invalid state unless the errors contain any of the blocked errors.
|
|
167
|
+
*/
|
|
168
|
+
Validation.recoverUnless = (blockedErrors, fallback) => (data) => Validation.isInvalid(data) &&
|
|
169
|
+
!data.errors.some((err) => blockedErrors.includes(err))
|
|
170
|
+
? fallback()
|
|
171
|
+
: data;
|
|
172
|
+
/**
|
|
173
|
+
* Combines two Validation instances, accumulating errors from both.
|
|
174
|
+
* If both are Valid, returns the second valid value.
|
|
175
|
+
* If either is Invalid, combines their errors into a single Invalid.
|
|
176
|
+
*
|
|
177
|
+
* @example
|
|
178
|
+
* ```ts
|
|
179
|
+
* Validation.combine(
|
|
180
|
+
* Validation.fail("Error 1"),
|
|
181
|
+
* Validation.fail("Error 2")
|
|
182
|
+
* ); // Invalid(["Error 1", "Error 2"])
|
|
183
|
+
*
|
|
184
|
+
* Validation.combine(
|
|
185
|
+
* Validation.of("a"),
|
|
186
|
+
* Validation.of("b")
|
|
187
|
+
* ); // Valid("b")
|
|
188
|
+
* ```
|
|
189
|
+
*/
|
|
190
|
+
Validation.combine = (first, second) => {
|
|
191
|
+
if (Validation.isValid(first) && Validation.isValid(second)) {
|
|
192
|
+
return second;
|
|
193
|
+
}
|
|
194
|
+
const errors = [
|
|
195
|
+
...(Validation.isInvalid(first) ? first.errors : []),
|
|
196
|
+
...(Validation.isInvalid(second) ? second.errors : []),
|
|
197
|
+
];
|
|
198
|
+
return isNonEmptyList(errors) ? Validation.toInvalid(errors) : second;
|
|
199
|
+
};
|
|
200
|
+
/**
|
|
201
|
+
* Combines multiple Validation instances, accumulating all errors.
|
|
202
|
+
* If all are Valid, returns the last valid value.
|
|
203
|
+
* Returns undefined for an empty array.
|
|
204
|
+
*
|
|
205
|
+
* @example
|
|
206
|
+
* ```ts
|
|
207
|
+
* Validation.combineAll([
|
|
208
|
+
* validateName(name),
|
|
209
|
+
* validateEmail(email),
|
|
210
|
+
* validateAge(age)
|
|
211
|
+
* ]);
|
|
212
|
+
* ```
|
|
213
|
+
*/
|
|
214
|
+
Validation.combineAll = (data) => data.length === 0 ? undefined : data.reduce((acc, v) => Validation.combine(acc, v));
|
|
215
|
+
})(Validation || (Validation = {}));
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type guard that checks if an array is non-empty.
|
|
3
|
+
*
|
|
4
|
+
* @example
|
|
5
|
+
* ```ts
|
|
6
|
+
* const items: string[] = getItems();
|
|
7
|
+
*
|
|
8
|
+
* if (isNonEmptyList(items)) {
|
|
9
|
+
* // TypeScript knows items has at least one element
|
|
10
|
+
* const first = items[0]; // string, not string | undefined
|
|
11
|
+
* }
|
|
12
|
+
* ```
|
|
13
|
+
*/
|
|
14
|
+
export const isNonEmptyList = (list) => list.length > 0;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./NonEmptyList.js";
|
package/package.json
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@nlozgachev/pipekit",
|
|
3
|
+
"version": "0.1.6",
|
|
4
|
+
"description": "Simple functional programming toolkit for TypeScript",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"functional",
|
|
7
|
+
"fp",
|
|
8
|
+
"typescript",
|
|
9
|
+
"composition",
|
|
10
|
+
"pipe"
|
|
11
|
+
],
|
|
12
|
+
"repository": {
|
|
13
|
+
"type": "git",
|
|
14
|
+
"url": "https://github.com/nlozgachev/pipekit"
|
|
15
|
+
},
|
|
16
|
+
"license": "MIT",
|
|
17
|
+
"types": "./types/mod.d.ts",
|
|
18
|
+
"exports": {
|
|
19
|
+
"./Composition": {
|
|
20
|
+
"import": {
|
|
21
|
+
"types": "./types/src/Composition/index.d.ts",
|
|
22
|
+
"default": "./esm/src/Composition/index.js"
|
|
23
|
+
},
|
|
24
|
+
"require": {
|
|
25
|
+
"types": "./types/src/Composition/index.d.ts",
|
|
26
|
+
"default": "./script/src/Composition/index.js"
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
"./Core": {
|
|
30
|
+
"import": {
|
|
31
|
+
"types": "./types/src/Core/index.d.ts",
|
|
32
|
+
"default": "./esm/src/Core/index.js"
|
|
33
|
+
},
|
|
34
|
+
"require": {
|
|
35
|
+
"types": "./types/src/Core/index.d.ts",
|
|
36
|
+
"default": "./script/src/Core/index.js"
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
"./Types": {
|
|
40
|
+
"import": {
|
|
41
|
+
"types": "./types/src/Types/index.d.ts",
|
|
42
|
+
"default": "./esm/src/Types/index.js"
|
|
43
|
+
},
|
|
44
|
+
"require": {
|
|
45
|
+
"types": "./types/src/Types/index.d.ts",
|
|
46
|
+
"default": "./script/src/Types/index.js"
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
"scripts": {},
|
|
51
|
+
"sideEffects": false,
|
|
52
|
+
"engines": {
|
|
53
|
+
"node": ">=22"
|
|
54
|
+
},
|
|
55
|
+
"files": [
|
|
56
|
+
"esm",
|
|
57
|
+
"script",
|
|
58
|
+
"types"
|
|
59
|
+
]
|
|
60
|
+
}
|
package/script/mod.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
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("./src/Composition/index.js"), exports);
|
|
18
|
+
__exportStar(require("./src/Core/index.js"), exports);
|
|
19
|
+
__exportStar(require("./src/Composition/index.js"), exports);
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.curry4 = exports.curry3 = exports.curry = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Converts a multi-argument function into a curried function.
|
|
6
|
+
* The inverse of `uncurry`.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```ts
|
|
10
|
+
* const add = (a: number, b: number) => a + b;
|
|
11
|
+
* const curriedAdd = curry(add);
|
|
12
|
+
* curriedAdd(1)(2); // 3
|
|
13
|
+
*
|
|
14
|
+
* // Partial application
|
|
15
|
+
* const addTen = curriedAdd(10);
|
|
16
|
+
* addTen(5); // 15
|
|
17
|
+
* ```
|
|
18
|
+
*
|
|
19
|
+
* @see {@link uncurry} for the inverse operation
|
|
20
|
+
* @see {@link curry3} for 3-argument functions
|
|
21
|
+
* @see {@link curry4} for 4-argument functions
|
|
22
|
+
*/
|
|
23
|
+
const curry = (f) => (a) => (b) => f(a, b);
|
|
24
|
+
exports.curry = curry;
|
|
25
|
+
/**
|
|
26
|
+
* Converts a 3-argument function into a curried function.
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* ```ts
|
|
30
|
+
* const add3 = (a: number, b: number, c: number) => a + b + c;
|
|
31
|
+
* const curriedAdd3 = curry3(add3);
|
|
32
|
+
* curriedAdd3(1)(2)(3); // 6
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
const curry3 = (f) => (a) => (b) => (c) => f(a, b, c);
|
|
36
|
+
exports.curry3 = curry3;
|
|
37
|
+
/**
|
|
38
|
+
* Converts a 4-argument function into a curried function.
|
|
39
|
+
*
|
|
40
|
+
* @example
|
|
41
|
+
* ```ts
|
|
42
|
+
* const add4 = (a: number, b: number, c: number, d: number) => a + b + c + d;
|
|
43
|
+
* const curriedAdd4 = curry4(add4);
|
|
44
|
+
* curriedAdd4(1)(2)(3)(4); // 10
|
|
45
|
+
* ```
|
|
46
|
+
*/
|
|
47
|
+
const curry4 = (f) => (a) => (b) => (c) => (d) => f(a, b, c, d);
|
|
48
|
+
exports.curry4 = curry4;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.flip = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Flips the order of arguments for a curried binary function.
|
|
6
|
+
* Converts a data-last function to data-first.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```ts
|
|
10
|
+
* // Original data-last (for pipe)
|
|
11
|
+
* pipe(
|
|
12
|
+
* Option.of(5),
|
|
13
|
+
* Option.map(n => n * 2)
|
|
14
|
+
* ); // Some(10)
|
|
15
|
+
*
|
|
16
|
+
* // Flipped to data-first
|
|
17
|
+
* const mapFirst = flip(Option.map);
|
|
18
|
+
* mapFirst(Option.of(5))(n => n * 2); // Some(10)
|
|
19
|
+
* ```
|
|
20
|
+
*
|
|
21
|
+
* @see {@link uncurry} for converting curried functions to multi-argument functions
|
|
22
|
+
*/
|
|
23
|
+
const flip = (f) => (b) => (a) => f(a)(b);
|
|
24
|
+
exports.flip = flip;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.flow = flow;
|
|
4
|
+
function flow(...fns) {
|
|
5
|
+
return (...args) => {
|
|
6
|
+
if (fns.length === 0)
|
|
7
|
+
return args[0];
|
|
8
|
+
const [first, ...rest] = fns;
|
|
9
|
+
return rest.reduce((acc, fn) => fn(acc), first(...args));
|
|
10
|
+
};
|
|
11
|
+
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.once = exports.or = exports.and = exports.constVoid = exports.constUndefined = exports.constNull = exports.constFalse = exports.constTrue = exports.constant = exports.identity = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Returns the value unchanged. The identity function.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```ts
|
|
9
|
+
* identity(42); // 42
|
|
10
|
+
* pipe(Option.of(5), Option.fold(() => 0, identity)); // 5
|
|
11
|
+
* ```
|
|
12
|
+
*/
|
|
13
|
+
const identity = (a) => a;
|
|
14
|
+
exports.identity = identity;
|
|
15
|
+
/**
|
|
16
|
+
* Creates a function that always returns the given value, ignoring its argument.
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```ts
|
|
20
|
+
* const always42 = constant(42);
|
|
21
|
+
* always42(); // 42
|
|
22
|
+
* [1, 2, 3].map(constant("x")); // ["x", "x", "x"]
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
const constant = (a) => () => a;
|
|
26
|
+
exports.constant = constant;
|
|
27
|
+
/** Always returns `true`. */
|
|
28
|
+
const constTrue = () => true;
|
|
29
|
+
exports.constTrue = constTrue;
|
|
30
|
+
/** Always returns `false`. */
|
|
31
|
+
const constFalse = () => false;
|
|
32
|
+
exports.constFalse = constFalse;
|
|
33
|
+
/** Always returns `null`. */
|
|
34
|
+
const constNull = () => null;
|
|
35
|
+
exports.constNull = constNull;
|
|
36
|
+
/** Always returns `undefined`. */
|
|
37
|
+
const constUndefined = () => undefined;
|
|
38
|
+
exports.constUndefined = constUndefined;
|
|
39
|
+
/** Always returns `void`. */
|
|
40
|
+
const constVoid = () => { };
|
|
41
|
+
exports.constVoid = constVoid;
|
|
42
|
+
/**
|
|
43
|
+
* Combines two predicates with logical AND.
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* ```ts
|
|
47
|
+
* const isPositive = (n: number) => n > 0;
|
|
48
|
+
* const isEven = (n: number) => n % 2 === 0;
|
|
49
|
+
* const isPositiveEven = and(isPositive, isEven);
|
|
50
|
+
*
|
|
51
|
+
* isPositiveEven(4); // true
|
|
52
|
+
* isPositiveEven(-2); // false
|
|
53
|
+
* isPositiveEven(3); // false
|
|
54
|
+
* ```
|
|
55
|
+
*/
|
|
56
|
+
const and = (p1, p2) => (...args) => p1(...args) && p2(...args);
|
|
57
|
+
exports.and = and;
|
|
58
|
+
/**
|
|
59
|
+
* Combines two predicates with logical OR.
|
|
60
|
+
*
|
|
61
|
+
* @example
|
|
62
|
+
* ```ts
|
|
63
|
+
* const isNegative = (n: number) => n < 0;
|
|
64
|
+
* const isZero = (n: number) => n === 0;
|
|
65
|
+
* const isNonPositive = or(isNegative, isZero);
|
|
66
|
+
*
|
|
67
|
+
* isNonPositive(-1); // true
|
|
68
|
+
* isNonPositive(0); // true
|
|
69
|
+
* isNonPositive(1); // false
|
|
70
|
+
* ```
|
|
71
|
+
*/
|
|
72
|
+
const or = (p1, p2) => (...args) => p1(...args) || p2(...args);
|
|
73
|
+
exports.or = or;
|
|
74
|
+
/**
|
|
75
|
+
* Creates a function that executes at most once.
|
|
76
|
+
* Subsequent calls return the cached result from the first execution.
|
|
77
|
+
*
|
|
78
|
+
* @example
|
|
79
|
+
* ```ts
|
|
80
|
+
* let count = 0;
|
|
81
|
+
* const initOnce = once(() => { count++; return "initialized"; });
|
|
82
|
+
*
|
|
83
|
+
* initOnce(); // "initialized", count === 1
|
|
84
|
+
* initOnce(); // "initialized", count === 1 (not called again)
|
|
85
|
+
* ```
|
|
86
|
+
*/
|
|
87
|
+
const once = (f) => {
|
|
88
|
+
let called = false;
|
|
89
|
+
let result;
|
|
90
|
+
return () => {
|
|
91
|
+
if (!called) {
|
|
92
|
+
result = f();
|
|
93
|
+
called = true;
|
|
94
|
+
}
|
|
95
|
+
return result;
|
|
96
|
+
};
|
|
97
|
+
};
|
|
98
|
+
exports.once = once;
|
|
@@ -0,0 +1,26 @@
|
|
|
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("./compose.js"), exports);
|
|
18
|
+
__exportStar(require("./curry.js"), exports);
|
|
19
|
+
__exportStar(require("./flip.js"), exports);
|
|
20
|
+
__exportStar(require("./fn.js"), exports);
|
|
21
|
+
__exportStar(require("./flow.js"), exports);
|
|
22
|
+
__exportStar(require("./memoize.js"), exports);
|
|
23
|
+
__exportStar(require("./not.js"), exports);
|
|
24
|
+
__exportStar(require("./pipe.js"), exports);
|
|
25
|
+
__exportStar(require("./tap.js"), exports);
|
|
26
|
+
__exportStar(require("./uncurry.js"), exports);
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.memoizeWeak = exports.memoize = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Creates a memoized version of a function that caches results.
|
|
6
|
+
* Subsequent calls with the same argument return the cached result.
|
|
7
|
+
*
|
|
8
|
+
* By default, uses the argument directly as the cache key.
|
|
9
|
+
* For complex arguments, provide a custom `keyFn` to generate cache keys.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```ts
|
|
13
|
+
* // Basic usage
|
|
14
|
+
* const expensive = memoize((n: number) => {
|
|
15
|
+
* console.log("Computing...");
|
|
16
|
+
* return n * 2;
|
|
17
|
+
* });
|
|
18
|
+
*
|
|
19
|
+
* expensive(5); // logs "Computing...", returns 10
|
|
20
|
+
* expensive(5); // returns 10 (cached, no log)
|
|
21
|
+
* expensive(3); // logs "Computing...", returns 6
|
|
22
|
+
*
|
|
23
|
+
* // With custom key function for objects
|
|
24
|
+
* const fetchUser = memoize(
|
|
25
|
+
* (opts: { id: string }) => fetch(`/users/${opts.id}`),
|
|
26
|
+
* opts => opts.id
|
|
27
|
+
* );
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
const memoize = (f, keyFn = (a) => a) => {
|
|
31
|
+
const cache = new Map();
|
|
32
|
+
return (a) => {
|
|
33
|
+
const key = keyFn(a);
|
|
34
|
+
if (cache.has(key)) {
|
|
35
|
+
return cache.get(key);
|
|
36
|
+
}
|
|
37
|
+
const result = f(a);
|
|
38
|
+
cache.set(key, result);
|
|
39
|
+
return result;
|
|
40
|
+
};
|
|
41
|
+
};
|
|
42
|
+
exports.memoize = memoize;
|
|
43
|
+
/**
|
|
44
|
+
* Creates a memoized version of a function using WeakMap.
|
|
45
|
+
* Only works with object arguments, but allows garbage collection
|
|
46
|
+
* of cached values when keys are no longer referenced.
|
|
47
|
+
*
|
|
48
|
+
* @example
|
|
49
|
+
* ```ts
|
|
50
|
+
* const processUser = memoizeWeak((user: User) => {
|
|
51
|
+
* return expensiveOperation(user);
|
|
52
|
+
* });
|
|
53
|
+
*
|
|
54
|
+
* const user = { id: 1, name: "Alice" };
|
|
55
|
+
* processUser(user); // computed
|
|
56
|
+
* processUser(user); // cached
|
|
57
|
+
* // When `user` is garbage collected, cached result is too
|
|
58
|
+
* ```
|
|
59
|
+
*/
|
|
60
|
+
const memoizeWeak = (f) => {
|
|
61
|
+
const cache = new WeakMap();
|
|
62
|
+
return (a) => {
|
|
63
|
+
if (cache.has(a)) {
|
|
64
|
+
return cache.get(a);
|
|
65
|
+
}
|
|
66
|
+
const result = f(a);
|
|
67
|
+
cache.set(a, result);
|
|
68
|
+
return result;
|
|
69
|
+
};
|
|
70
|
+
};
|
|
71
|
+
exports.memoizeWeak = memoizeWeak;
|