selaws 0.0.0-stage → 0.1.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/LICENSE +21 -0
- package/README.md +355 -2
- package/dist/evidence.d.ts +45 -0
- package/dist/evidence.d.ts.map +1 -0
- package/dist/evidence.js +22 -0
- package/dist/evidence.js.map +1 -0
- package/dist/identity.d.ts +52 -0
- package/dist/identity.d.ts.map +1 -0
- package/dist/identity.js +22 -0
- package/dist/identity.js.map +1 -0
- package/dist/index.d.ts +35 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +18 -0
- package/dist/index.js.map +1 -0
- package/dist/internal/callback.d.ts +13 -0
- package/dist/internal/callback.d.ts.map +1 -0
- package/dist/internal/callback.js +2 -0
- package/dist/internal/callback.js.map +1 -0
- package/dist/internal/promise-like.d.ts +8 -0
- package/dist/internal/promise-like.d.ts.map +1 -0
- package/dist/internal/promise-like.js +12 -0
- package/dist/internal/promise-like.js.map +1 -0
- package/dist/internal/scalar.d.ts +18 -0
- package/dist/internal/scalar.d.ts.map +1 -0
- package/dist/internal/scalar.js +6 -0
- package/dist/internal/scalar.js.map +1 -0
- package/dist/option.d.ts +90 -0
- package/dist/option.d.ts.map +1 -0
- package/dist/option.js +96 -0
- package/dist/option.js.map +1 -0
- package/dist/protocol.d.ts +42 -0
- package/dist/protocol.d.ts.map +1 -0
- package/dist/protocol.js +67 -0
- package/dist/protocol.js.map +1 -0
- package/dist/result/capture.d.ts +42 -0
- package/dist/result/capture.d.ts.map +1 -0
- package/dist/result/capture.js +41 -0
- package/dist/result/capture.js.map +1 -0
- package/dist/result/core.d.ts +98 -0
- package/dist/result/core.d.ts.map +1 -0
- package/dist/result/core.js +103 -0
- package/dist/result/core.js.map +1 -0
- package/dist/result/index.d.ts +4 -0
- package/dist/result/index.d.ts.map +1 -0
- package/dist/result/index.js +4 -0
- package/dist/result/index.js.map +1 -0
- package/dist/result/throw.d.ts +4 -0
- package/dist/result/throw.d.ts.map +1 -0
- package/dist/result/throw.js +8 -0
- package/dist/result/throw.js.map +1 -0
- package/dist/validation.d.ts +126 -0
- package/dist/validation.d.ts.map +1 -0
- package/dist/validation.js +240 -0
- package/dist/validation.js.map +1 -0
- package/dist/variant.d.ts +97 -0
- package/dist/variant.d.ts.map +1 -0
- package/dist/variant.js +102 -0
- package/dist/variant.js.map +1 -0
- package/docs/API.md +543 -0
- package/docs/GUIDE.md +739 -0
- package/docs/SEMANTICS.md +319 -0
- package/docs/laws/evidence.md +113 -0
- package/docs/laws/identity.md +126 -0
- package/docs/laws/match.md +163 -0
- package/docs/laws/option.md +100 -0
- package/docs/laws/protocol.md +152 -0
- package/docs/laws/result.md +124 -0
- package/docs/laws/validation.md +111 -0
- package/docs/laws/variant.md +251 -0
- package/package.json +87 -3
- package/src/evidence.ts +120 -0
- package/src/identity.ts +129 -0
- package/src/index.ts +54 -0
- package/src/internal/callback.ts +54 -0
- package/src/internal/promise-like.ts +32 -0
- package/src/internal/scalar.ts +43 -0
- package/src/option.ts +214 -0
- package/src/protocol.ts +174 -0
- package/src/result/capture.ts +209 -0
- package/src/result/core.ts +229 -0
- package/src/result/index.ts +3 -0
- package/src/result/throw.ts +13 -0
- package/src/validation.ts +491 -0
- package/src/variant.ts +363 -0
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
import type { CallbackResult } from "../internal/callback.js";
|
|
2
|
+
import { assertNotPromiseLike, type NotPromiseLike } from "../internal/promise-like.js";
|
|
3
|
+
import type { Option } from "../option.js";
|
|
4
|
+
import type { Validation, ValidationIssues } from "../validation.js";
|
|
5
|
+
|
|
6
|
+
/** A successful Result value. */
|
|
7
|
+
export type Ok<T> = Readonly<{
|
|
8
|
+
ok: true;
|
|
9
|
+
value: T;
|
|
10
|
+
}>;
|
|
11
|
+
|
|
12
|
+
/** A recoverable Result error value. */
|
|
13
|
+
export type Err<E> = Readonly<{
|
|
14
|
+
ok: false;
|
|
15
|
+
error: E;
|
|
16
|
+
}>;
|
|
17
|
+
|
|
18
|
+
/** Recoverable success or error with fail-fast composition. */
|
|
19
|
+
export type Result<T, E> = Ok<T> | Err<E>;
|
|
20
|
+
|
|
21
|
+
/** Native Promise composition around a Result value. */
|
|
22
|
+
export type AsyncResult<T, E> = Promise<Result<T, E>>;
|
|
23
|
+
|
|
24
|
+
/** Extracts the success value type from a Result union. */
|
|
25
|
+
export type ResultValue<R> = R extends Ok<infer T> ? T : never;
|
|
26
|
+
|
|
27
|
+
/** Extracts the error value type from a Result union. */
|
|
28
|
+
export type ResultError<R> = R extends Err<infer E> ? E : never;
|
|
29
|
+
|
|
30
|
+
type ResultValues<R extends readonly Result<unknown, unknown>[]> = {
|
|
31
|
+
[K in keyof R]: ResultValue<R[K]>;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
type ValidationResultError<E> = [E] extends [never] ? never : ValidationIssues<E>;
|
|
35
|
+
|
|
36
|
+
type SynchronousReturn<T> = [T] extends [NotPromiseLike<T>] ? unknown : never;
|
|
37
|
+
|
|
38
|
+
type IsMutableArray<Value> = Value extends unknown[] ? true : false;
|
|
39
|
+
|
|
40
|
+
type StableArrayInput<Value extends readonly unknown[]> =
|
|
41
|
+
true extends IsMutableArray<Value> ? never : unknown;
|
|
42
|
+
|
|
43
|
+
/** Constructs a successful Result and preserves the error axis as never. */
|
|
44
|
+
export const ok = <T>(value: T): Result<T, never> => ({
|
|
45
|
+
ok: true,
|
|
46
|
+
value,
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
/** Constructs an error Result and preserves the value axis as never. */
|
|
50
|
+
export const err = <E>(error: E): Result<never, E> => ({
|
|
51
|
+
error,
|
|
52
|
+
ok: false,
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
/** Narrows a Result to Ok. */
|
|
56
|
+
export const isOk = <T, E>(result: Result<T, E>): result is Ok<T> => result.ok;
|
|
57
|
+
|
|
58
|
+
/** Narrows a Result to Err. */
|
|
59
|
+
export const isErr = <T, E>(result: Result<T, E>): result is Err<E> => !result.ok;
|
|
60
|
+
|
|
61
|
+
/** Eliminates a Result under the shared Match law. */
|
|
62
|
+
export const match = <
|
|
63
|
+
T,
|
|
64
|
+
E,
|
|
65
|
+
OkHandler extends (this: void, value: NoInfer<T>) => unknown,
|
|
66
|
+
ErrHandler extends (this: void, error: NoInfer<E>) => unknown,
|
|
67
|
+
>(
|
|
68
|
+
result: Result<T, E>,
|
|
69
|
+
arms: Readonly<{
|
|
70
|
+
ok: OkHandler;
|
|
71
|
+
err: ErrHandler;
|
|
72
|
+
}>,
|
|
73
|
+
): CallbackResult<OkHandler> | CallbackResult<ErrHandler> => {
|
|
74
|
+
if (result.ok) {
|
|
75
|
+
const selected = arms.ok;
|
|
76
|
+
return selected(result.value) as CallbackResult<OkHandler>;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const selected = arms.err;
|
|
80
|
+
return selected(result.error) as CallbackResult<ErrHandler>;
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
/** Transforms Ok and preserves Err. */
|
|
84
|
+
export const map = <T, E, U>(
|
|
85
|
+
result: Result<T, E>,
|
|
86
|
+
transform: (value: T) => U,
|
|
87
|
+
): Result<U, E> => (result.ok ? ok(transform(result.value)) : result);
|
|
88
|
+
|
|
89
|
+
/** Transforms Err and preserves Ok. */
|
|
90
|
+
export const mapError = <T, E, F>(
|
|
91
|
+
result: Result<T, E>,
|
|
92
|
+
transform: (error: E) => F,
|
|
93
|
+
): Result<T, F> => (result.ok ? result : err(transform(result.error)));
|
|
94
|
+
|
|
95
|
+
/** Sequences a dependent Result-producing success step. */
|
|
96
|
+
export const andThen = <T, E, U, F>(
|
|
97
|
+
result: Result<T, E>,
|
|
98
|
+
next: (value: T) => Result<U, F>,
|
|
99
|
+
): Result<U, E | F> => (result.ok ? next(result.value) : result);
|
|
100
|
+
|
|
101
|
+
/** Recovers from Err with another Result. */
|
|
102
|
+
export const orElse = <T, E, U, F>(
|
|
103
|
+
result: Result<T, E>,
|
|
104
|
+
recover: (error: E) => Result<U, F>,
|
|
105
|
+
): Result<T | U, F> => (result.ok ? result : recover(result.error));
|
|
106
|
+
|
|
107
|
+
/** Removes one explicit nested Result layer. */
|
|
108
|
+
export const flatten = <T, E, F>(result: Result<Result<T, F>, E>): Result<T, E | F> =>
|
|
109
|
+
result.ok ? result.value : result;
|
|
110
|
+
|
|
111
|
+
/** Synchronously observes Ok and returns the original Result. */
|
|
112
|
+
export const inspect = <T, E, R>(
|
|
113
|
+
result: Result<T, E>,
|
|
114
|
+
observe: ((value: T) => R) & SynchronousReturn<R>,
|
|
115
|
+
): Result<T, E> => {
|
|
116
|
+
if (result.ok) {
|
|
117
|
+
const completion = observe(result.value);
|
|
118
|
+
assertNotPromiseLike(
|
|
119
|
+
completion,
|
|
120
|
+
"Result.inspect() expects a synchronous observer.",
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
return result;
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
/** Synchronously observes Err and returns the original Result. */
|
|
127
|
+
export const inspectError = <T, E, R>(
|
|
128
|
+
result: Result<T, E>,
|
|
129
|
+
observe: ((error: E) => R) & SynchronousReturn<R>,
|
|
130
|
+
): Result<T, E> => {
|
|
131
|
+
if (!result.ok) {
|
|
132
|
+
const completion = observe(result.error);
|
|
133
|
+
assertNotPromiseLike(
|
|
134
|
+
completion,
|
|
135
|
+
"Result.inspectError() expects a synchronous observer.",
|
|
136
|
+
);
|
|
137
|
+
}
|
|
138
|
+
return result;
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
/** Returns the Ok value or an eager fallback. */
|
|
142
|
+
export const unwrapOr = <T, E, U>(result: Result<T, E>, fallback: U): T | U =>
|
|
143
|
+
result.ok ? result.value : fallback;
|
|
144
|
+
|
|
145
|
+
/** Returns the Ok value or evaluates a lazy fallback from Err. */
|
|
146
|
+
export const unwrapOrElse = <T, E, U>(
|
|
147
|
+
result: Result<T, E>,
|
|
148
|
+
fallback: (error: E) => U,
|
|
149
|
+
): T | U => (result.ok ? result.value : fallback(result.error));
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Combines already-materialized Results in input order.
|
|
153
|
+
*
|
|
154
|
+
* The first Err is returned; complete success preserves tuple positions.
|
|
155
|
+
*/
|
|
156
|
+
export const all = <const R extends readonly Result<unknown, unknown>[]>(
|
|
157
|
+
results: R & StableArrayInput<R>,
|
|
158
|
+
): Result<ResultValues<R>, ResultError<R[number]>> => {
|
|
159
|
+
const values: unknown[] = [];
|
|
160
|
+
const length = results.length;
|
|
161
|
+
|
|
162
|
+
for (let index = 0; index < length; index += 1) {
|
|
163
|
+
const result = results[index] as Result<unknown, unknown>;
|
|
164
|
+
if (!result.ok) {
|
|
165
|
+
return result as Err<ResultError<R[number]>>;
|
|
166
|
+
}
|
|
167
|
+
values.push(result.value);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
return ok(values as ResultValues<R>);
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
/** Converts presence into Result, lazily creating an error for None. */
|
|
174
|
+
export const fromOption = <T, E>(option: Option<T>, onNone: () => E): Result<T, E> =>
|
|
175
|
+
option.some ? ok(option.value) : err(onNone());
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Converts Validation into Result.
|
|
179
|
+
*
|
|
180
|
+
* Invalid contributes its complete non-empty issue collection as one Result
|
|
181
|
+
* error value.
|
|
182
|
+
*/
|
|
183
|
+
export const fromValidation = <T, E>(
|
|
184
|
+
validation: Validation<T, E>,
|
|
185
|
+
): Result<T, ValidationResultError<E>> =>
|
|
186
|
+
validation.valid
|
|
187
|
+
? ok(validation.value)
|
|
188
|
+
: (err(validation.errors) as Result<T, ValidationResultError<E>>);
|
|
189
|
+
|
|
190
|
+
type ResultFacade = Readonly<{
|
|
191
|
+
all: typeof all;
|
|
192
|
+
andThen: typeof andThen;
|
|
193
|
+
err: typeof err;
|
|
194
|
+
flatten: typeof flatten;
|
|
195
|
+
fromOption: typeof fromOption;
|
|
196
|
+
fromValidation: typeof fromValidation;
|
|
197
|
+
inspect: typeof inspect;
|
|
198
|
+
inspectError: typeof inspectError;
|
|
199
|
+
isErr: typeof isErr;
|
|
200
|
+
isOk: typeof isOk;
|
|
201
|
+
map: typeof map;
|
|
202
|
+
mapError: typeof mapError;
|
|
203
|
+
match: typeof match;
|
|
204
|
+
ok: typeof ok;
|
|
205
|
+
orElse: typeof orElse;
|
|
206
|
+
unwrapOr: typeof unwrapOr;
|
|
207
|
+
unwrapOrElse: typeof unwrapOrElse;
|
|
208
|
+
}>;
|
|
209
|
+
|
|
210
|
+
/** Facade for Result construction, transformation, elimination, and collection. */
|
|
211
|
+
export const Result: ResultFacade = {
|
|
212
|
+
all,
|
|
213
|
+
andThen,
|
|
214
|
+
err,
|
|
215
|
+
flatten,
|
|
216
|
+
fromOption,
|
|
217
|
+
fromValidation,
|
|
218
|
+
inspect,
|
|
219
|
+
inspectError,
|
|
220
|
+
isErr,
|
|
221
|
+
isOk,
|
|
222
|
+
map,
|
|
223
|
+
mapError,
|
|
224
|
+
match,
|
|
225
|
+
ok,
|
|
226
|
+
orElse,
|
|
227
|
+
unwrapOr,
|
|
228
|
+
unwrapOrElse,
|
|
229
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { Result } from "./core.js";
|
|
2
|
+
|
|
3
|
+
/** Converts Err into an explicitly mapped thrown value and returns Ok unchanged. */
|
|
4
|
+
export const orThrow = <T, E>(
|
|
5
|
+
result: Result<T, E>,
|
|
6
|
+
mapErrorToThrowable: (error: E) => unknown,
|
|
7
|
+
): T => {
|
|
8
|
+
if (result.ok) {
|
|
9
|
+
return result.value;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
throw mapErrorToThrowable(result.error);
|
|
13
|
+
};
|