@ambarltd/core 0.1.17

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/README.md +10 -0
  2. package/dist/callable.d.ts +1 -0
  3. package/dist/callable.js +6 -0
  4. package/dist/future.d.ts +102 -0
  5. package/dist/future.js +164 -0
  6. package/dist/helpers/object.d.ts +9 -0
  7. package/dist/helpers/object.js +31 -0
  8. package/dist/json/decoder.d.ts +99 -0
  9. package/dist/json/decoder.js +213 -0
  10. package/dist/json/encoder.d.ts +50 -0
  11. package/dist/json/encoder.js +115 -0
  12. package/dist/json/schema.d.ts +78 -0
  13. package/dist/json/schema.js +168 -0
  14. package/dist/json/types.d.ts +6 -0
  15. package/dist/json/types.js +1 -0
  16. package/dist/list.d.ts +35 -0
  17. package/dist/list.js +130 -0
  18. package/dist/maybe.d.ts +104 -0
  19. package/dist/maybe.js +106 -0
  20. package/dist/remote-data.d.ts +117 -0
  21. package/dist/remote-data.js +148 -0
  22. package/dist/result.d.ts +75 -0
  23. package/dist/result.js +126 -0
  24. package/dist/router.d.ts +117 -0
  25. package/dist/router.js +106 -0
  26. package/dist/test.d.ts +63 -0
  27. package/dist/test.js +470 -0
  28. package/dist/time.d.ts +118 -0
  29. package/dist/time.js +387 -0
  30. package/dist/tracing/opentelemetry.d.ts +27 -0
  31. package/dist/tracing/opentelemetry.js +215 -0
  32. package/dist/tracing/proxy.d.ts +20 -0
  33. package/dist/tracing/proxy.js +103 -0
  34. package/dist/tracing/simple.d.ts +10 -0
  35. package/dist/tracing/simple.js +224 -0
  36. package/dist/tracing.d.ts +29 -0
  37. package/dist/tracing.js +55 -0
  38. package/dist/trampoline.d.ts +24 -0
  39. package/dist/trampoline.js +46 -0
  40. package/dist/tree-map.d.ts +73 -0
  41. package/dist/tree-map.js +169 -0
  42. package/dist/tree-set.d.ts +63 -0
  43. package/dist/tree-set.js +114 -0
  44. package/dist/types.d.ts +21 -0
  45. package/dist/types.js +1 -0
  46. package/package.json +49 -0
@@ -0,0 +1,104 @@
1
+ /**
2
+ * A type which represents the existence or absence of a value in a
3
+ * robust and unambiguous manner.
4
+ *
5
+ * Values can be extracted using `instanceof` tests.
6
+ *
7
+ * ```ts
8
+ * switch (true) {
9
+ * case x instanceof Just:
10
+ * // use x.value here
11
+ * break;
12
+ * case x instanceof Nothing:
13
+ * break;
14
+ * default:
15
+ * x satisfies never;
16
+ * }
17
+ * ```
18
+ */
19
+ type Maybe<T> = Just<T> | Nothing<T>;
20
+ type Nullable<T> = T | null;
21
+ /** Infer the type from a Maybe definition. */
22
+ type Infer<A extends Maybe<unknown>> = A extends Maybe<infer B> ? B : never;
23
+ export interface IMaybe<T> {
24
+ isJust(): boolean;
25
+ isNothing(): boolean;
26
+ map<W>(f: (t: T) => W): Maybe<W>;
27
+ withDefault(def: T): T;
28
+ expect(msg: string): T;
29
+ maybe<W>(def: W, f: (t: T) => W): W;
30
+ unwrap<W>(f: () => W, g: (t: T) => W): W;
31
+ chain<W>(f: (t: T) => Maybe<W>): Maybe<W>;
32
+ alt(other: Maybe<T>): Maybe<T>;
33
+ asNullable(): Nullable<T>;
34
+ }
35
+ /** Wrap a present value. Use at system boundaries or to lift a value into a `Maybe<T>`. */
36
+ declare class Just<T> implements IMaybe<T> {
37
+ static new<W>(v: W): Just<W>;
38
+ readonly value: T;
39
+ constructor(v: T);
40
+ toString(): string;
41
+ /** Returns true if this is a `Just`. Prefer `instanceof Just` — booleans don't narrow the type. */
42
+ isJust(): boolean;
43
+ /** Returns true if this is a `Nothing`. Prefer `instanceof Nothing` — booleans don't narrow the type. */
44
+ isNothing(): boolean;
45
+ /** Transform the contained value if present; `Nothing` passes through unchanged. */
46
+ map<W>(f: (t: T) => W): Maybe<W>;
47
+ /** Unwrap the value, returning `def` if this is a `Nothing`. */
48
+ withDefault(_: T): T;
49
+ /**
50
+ * Unwrap the value or throw `new Error(msg)`. Only use for catastrophic
51
+ * programmer bugs — use `withDefault` or `maybe` for recoverable absence.
52
+ */
53
+ expect(_: string): T;
54
+ /** Fold into a `W`: return `def` for `Nothing`, else apply `f` to the value. */
55
+ maybe<W>(_: W, f: (t: T) => W): W;
56
+ /** Exhaustive two-branch fold: `f()` on `Nothing`, `g(value)` on `Just`. */
57
+ unwrap<W>(_: () => W, g: (t: T) => W): W;
58
+ /** Monadic bind. Use when `f` returns `Maybe<W>` — avoids `Maybe<Maybe<W>>`. */
59
+ chain<W>(f: (t: T) => Maybe<W>): Maybe<W>;
60
+ /** Fallback to `other` if this is a `Nothing`. Chainable: `primary.alt(secondary).alt(fallback)`. */
61
+ alt(_: Maybe<T>): Maybe<T>;
62
+ /** Convert to `T | null` at a system boundary. */
63
+ asNullable(): T;
64
+ }
65
+ /** Represent absence. Use instead of returning `null`/`undefined` from domain code. */
66
+ declare class Nothing<T> implements IMaybe<T> {
67
+ static new<T>(): Nothing<T>;
68
+ constructor();
69
+ toString(): string;
70
+ /** Returns true if this is a `Just`. Prefer `instanceof Just` — booleans don't narrow the type. */
71
+ isJust(): boolean;
72
+ /** Returns true if this is a `Nothing`. Prefer `instanceof Nothing` — booleans don't narrow the type. */
73
+ isNothing(): boolean;
74
+ /** Transform the contained value if present; `Nothing` passes through unchanged. */
75
+ map<W>(_: (t: T) => W): Maybe<W>;
76
+ /** Unwrap the value, returning `def` if this is a `Nothing`. */
77
+ withDefault(d: T): T;
78
+ /**
79
+ * Unwrap the value or throw `new Error(msg)`. Only use for catastrophic
80
+ * programmer bugs — use `withDefault` or `maybe` for recoverable absence.
81
+ */
82
+ expect(msg: string): T;
83
+ /** Fold into a `W`: return `def` for `Nothing`, else apply `f` to the value. */
84
+ maybe<W>(def: W, _: (t: T) => W): W;
85
+ /** Exhaustive two-branch fold: `f()` on `Nothing`, `g(value)` on `Just`. */
86
+ unwrap<W>(f: () => W, _: (t: T) => W): W;
87
+ /** Monadic bind. Use when `f` returns `Maybe<W>` — avoids `Maybe<Maybe<W>>`. */
88
+ chain<W>(_: (t: T) => Maybe<W>): Maybe<W>;
89
+ /** Fallback to `other` if this is a `Nothing`. Chainable: `primary.alt(secondary).alt(fallback)`. */
90
+ alt(other: Maybe<T>): Maybe<T>;
91
+ /** Convert to `T | null` at a system boundary. */
92
+ asNullable(): Nullable<T>;
93
+ }
94
+ /** Boundary helper: `undefined` becomes `Nothing`, any other value becomes `Just`. Don't mix with `fromNullable`. */
95
+ declare function fromOptional<T>(v: undefined | T): Maybe<T>;
96
+ /** Boundary helper: `null` becomes `Nothing`, any other value becomes `Just`. Don't mix with `fromOptional`. */
97
+ declare function fromNullable<T>(v: NonNullable<T> | null): Maybe<T>;
98
+ /** Remove Nothings from an array. */
99
+ declare function catMaybes<T>(xs: Array<Maybe<T>>): Array<T>;
100
+ /** Map and filter using maybes. */
101
+ declare function mapMaybe<T, W>(xs: Array<T>, f: (v: T) => Maybe<W>): Array<W>;
102
+ declare var CallableJust: typeof Just & typeof Just.new;
103
+ declare var CallableNothing: typeof Nothing & typeof Nothing.new;
104
+ export { type Maybe, type Nullable, type Infer, CallableJust as Just, CallableNothing as Nothing, fromOptional, fromNullable, catMaybes, mapMaybe, };
package/dist/maybe.js ADDED
@@ -0,0 +1,106 @@
1
+ import Callable from "./callable";
2
+ /** Wrap a present value. Use at system boundaries or to lift a value into a `Maybe<T>`. */
3
+ // prettier-ignore
4
+ class Just {
5
+ static new(v) { return new Just(v); }
6
+ value;
7
+ constructor(v) { this.value = v; }
8
+ toString() {
9
+ return `Just(${this.value})`;
10
+ }
11
+ /** Returns true if this is a `Just`. Prefer `instanceof Just` — booleans don't narrow the type. */
12
+ isJust() { return true; }
13
+ /** Returns true if this is a `Nothing`. Prefer `instanceof Nothing` — booleans don't narrow the type. */
14
+ isNothing() { return false; }
15
+ /** Transform the contained value if present; `Nothing` passes through unchanged. */
16
+ map(f) { return new Just(f(this.value)); }
17
+ /** Unwrap the value, returning `def` if this is a `Nothing`. */
18
+ withDefault(_) { return this.value; }
19
+ /**
20
+ * Unwrap the value or throw `new Error(msg)`. Only use for catastrophic
21
+ * programmer bugs — use `withDefault` or `maybe` for recoverable absence.
22
+ */
23
+ expect(_) { return this.value; }
24
+ /** Fold into a `W`: return `def` for `Nothing`, else apply `f` to the value. */
25
+ maybe(_, f) { return f(this.value); }
26
+ /** Exhaustive two-branch fold: `f()` on `Nothing`, `g(value)` on `Just`. */
27
+ unwrap(_, g) { return g(this.value); }
28
+ /** Monadic bind. Use when `f` returns `Maybe<W>` — avoids `Maybe<Maybe<W>>`. */
29
+ chain(f) { return f(this.value); }
30
+ /** Fallback to `other` if this is a `Nothing`. Chainable: `primary.alt(secondary).alt(fallback)`. */
31
+ alt(_) { return this; }
32
+ /** Convert to `T | null` at a system boundary. */
33
+ asNullable() { return this.value; }
34
+ }
35
+ /** Represent absence. Use instead of returning `null`/`undefined` from domain code. */
36
+ // prettier-ignore
37
+ class Nothing {
38
+ static new() { return new Nothing(); }
39
+ constructor() { }
40
+ toString() {
41
+ return "Nothing()";
42
+ }
43
+ /** Returns true if this is a `Just`. Prefer `instanceof Just` — booleans don't narrow the type. */
44
+ isJust() { return false; }
45
+ /** Returns true if this is a `Nothing`. Prefer `instanceof Nothing` — booleans don't narrow the type. */
46
+ isNothing() { return true; }
47
+ /** Transform the contained value if present; `Nothing` passes through unchanged. */
48
+ map(_) { return new Nothing(); }
49
+ /** Unwrap the value, returning `def` if this is a `Nothing`. */
50
+ withDefault(d) { return d; }
51
+ /**
52
+ * Unwrap the value or throw `new Error(msg)`. Only use for catastrophic
53
+ * programmer bugs — use `withDefault` or `maybe` for recoverable absence.
54
+ */
55
+ expect(msg) { throw new Error(msg); }
56
+ /** Fold into a `W`: return `def` for `Nothing`, else apply `f` to the value. */
57
+ maybe(def, _) { return def; }
58
+ /** Exhaustive two-branch fold: `f()` on `Nothing`, `g(value)` on `Just`. */
59
+ unwrap(f, _) { return f(); }
60
+ /** Monadic bind. Use when `f` returns `Maybe<W>` — avoids `Maybe<Maybe<W>>`. */
61
+ chain(_) {
62
+ return new Nothing();
63
+ }
64
+ /** Fallback to `other` if this is a `Nothing`. Chainable: `primary.alt(secondary).alt(fallback)`. */
65
+ alt(other) { return other; }
66
+ /** Convert to `T | null` at a system boundary. */
67
+ asNullable() { return null; }
68
+ }
69
+ /** Boundary helper: `undefined` becomes `Nothing`, any other value becomes `Just`. Don't mix with `fromNullable`. */
70
+ function fromOptional(v) {
71
+ if (typeof v === "undefined") {
72
+ return new Nothing();
73
+ }
74
+ else {
75
+ return new Just(v);
76
+ }
77
+ }
78
+ /** Boundary helper: `null` becomes `Nothing`, any other value becomes `Just`. Don't mix with `fromOptional`. */
79
+ function fromNullable(v) {
80
+ if (v === null) {
81
+ return new Nothing();
82
+ }
83
+ else {
84
+ return new Just(v);
85
+ }
86
+ }
87
+ /** Remove Nothings from an array. */
88
+ function catMaybes(xs) {
89
+ const r = [];
90
+ for (const x of xs) {
91
+ x.map(v => r.push(v));
92
+ }
93
+ return r;
94
+ }
95
+ /** Map and filter using maybes. */
96
+ function mapMaybe(xs, f) {
97
+ const r = [];
98
+ for (const x of xs) {
99
+ f(x).map(v => r.push(v));
100
+ }
101
+ return r;
102
+ }
103
+ /* eslint-disable no-var */
104
+ var CallableJust = Callable(Just);
105
+ var CallableNothing = Callable(Nothing);
106
+ export { CallableJust as Just, CallableNothing as Nothing, fromOptional, fromNullable, catMaybes, mapMaybe, };
@@ -0,0 +1,117 @@
1
+ import { Nullable, Maybe } from "./maybe";
2
+ /**
3
+ * Represents the state of data that is fetched from a remote source.
4
+ *
5
+ * A value is either not yet requested, loading, failed with an error, or
6
+ * successfully loaded (`Ready`).
7
+ */
8
+ type RemoteData<E, T> = NotAsked<E, T> | Loading<E, T> | Failed<E, T> | Ready<E, T>;
9
+ interface IRemoteData<E, T> {
10
+ map<W>(f: (t: T) => W): RemoteData<E, W>;
11
+ chain<W>(f: (t: T) => RemoteData<E, W>): RemoteData<E, W>;
12
+ unwrapFailure<W>(def: W, f: (e: E) => W): W;
13
+ toMaybe(): Maybe<T>;
14
+ readonly isLoading: boolean;
15
+ readonly isReady: boolean;
16
+ readonly isFailed: boolean;
17
+ }
18
+ /**
19
+ * Initial state: the request hasn't been made yet. For "asked but empty",
20
+ * use `Ready([])` instead — `NotAsked` is not a generic "no data" state.
21
+ */
22
+ declare class NotAsked<E, T> implements IRemoteData<E, T> {
23
+ private readonly _tag;
24
+ static new<E, T>(): NotAsked<E, T>;
25
+ /** Transform only if `Ready`; `Loading`/`Failed`/`NotAsked` pass through unchanged. */
26
+ map<W>(_: (t: T) => W): RemoteData<E, W>;
27
+ /** Chain a `RemoteData`-returning fn without double-wrapping. */
28
+ chain<W>(_: (t: T) => RemoteData<E, W>): NotAsked<E, W>;
29
+ /** Return `f(error)` on `Failed`, otherwise return `def`. */
30
+ unwrapFailure<W>(def: W, _: (e: E) => W): W;
31
+ /** Collapse to `Just(value)` on `Ready`, otherwise `Nothing`. */
32
+ toMaybe(): Maybe<T>;
33
+ /** `true` only in `Loading`. Prefer `instanceof Loading` + `satisfies never` for exhaustive narrowing. */
34
+ readonly isLoading = false;
35
+ /** `true` only in `Ready`. Prefer `instanceof Ready` + `satisfies never` for exhaustive narrowing. */
36
+ readonly isReady = false;
37
+ /** `true` only in `Failed`. Prefer `instanceof Failed` + `satisfies never` for exhaustive narrowing. */
38
+ readonly isFailed = false;
39
+ }
40
+ type Bytes = number;
41
+ type LoadingDetails = {
42
+ uploaded: Bytes;
43
+ uploadSize: Nullable<Bytes>;
44
+ downloaded: Bytes;
45
+ downloadSize: Nullable<Bytes>;
46
+ };
47
+ /** In-flight state. Optionally carries upload/download progress via `details`. */
48
+ declare class Loading<E, T> implements IRemoteData<E, T> {
49
+ private readonly _tag;
50
+ readonly uploaded: Bytes;
51
+ readonly uploadSize: Nullable<Bytes>;
52
+ readonly downloaded: Bytes;
53
+ readonly downloadSize: Nullable<Bytes>;
54
+ constructor(details?: Nullable<LoadingDetails>);
55
+ static new<E, T>(details?: Nullable<LoadingDetails>): Loading<E, T>;
56
+ /** Transform only if `Ready`; `Loading`/`Failed`/`NotAsked` pass through unchanged. */
57
+ map<W>(_: (t: T) => W): RemoteData<E, W>;
58
+ /** Chain a `RemoteData`-returning fn without double-wrapping. */
59
+ chain<W>(_: (t: T) => RemoteData<E, W>): Loading<E, W>;
60
+ /** Return `f(error)` on `Failed`, otherwise return `def`. */
61
+ unwrapFailure<W>(def: W, _: (e: E) => W): W;
62
+ /** Collapse to `Just(value)` on `Ready`, otherwise `Nothing`. */
63
+ toMaybe(): Maybe<T>;
64
+ /** `true` only in `Loading`. Prefer `instanceof Loading` + `satisfies never` for exhaustive narrowing. */
65
+ readonly isLoading = true;
66
+ /** `true` only in `Ready`. Prefer `instanceof Ready` + `satisfies never` for exhaustive narrowing. */
67
+ readonly isReady = false;
68
+ /** `true` only in `Failed`. Prefer `instanceof Failed` + `satisfies never` for exhaustive narrowing. */
69
+ readonly isFailed = false;
70
+ }
71
+ /** Terminal failure state carrying the error payload. */
72
+ declare class Failed<E, T> implements IRemoteData<E, T> {
73
+ private readonly _tag;
74
+ readonly error: E;
75
+ static new<E, T>(e: E): Failed<E, T>;
76
+ constructor(e: E);
77
+ /** Transform only if `Ready`; `Loading`/`Failed`/`NotAsked` pass through unchanged. */
78
+ map<W>(_: (t: T) => W): RemoteData<E, W>;
79
+ /** Chain a `RemoteData`-returning fn without double-wrapping. */
80
+ chain<W>(_: (t: T) => RemoteData<E, W>): Failed<E, W>;
81
+ /** Return `f(error)` on `Failed`, otherwise return `def`. */
82
+ unwrapFailure<W>(_: W, f: (e: E) => W): W;
83
+ /** Collapse to `Just(value)` on `Ready`, otherwise `Nothing`. */
84
+ toMaybe(): Maybe<T>;
85
+ /** `true` only in `Loading`. Prefer `instanceof Loading` + `satisfies never` for exhaustive narrowing. */
86
+ readonly isLoading = false;
87
+ /** `true` only in `Ready`. Prefer `instanceof Ready` + `satisfies never` for exhaustive narrowing. */
88
+ readonly isReady = false;
89
+ /** `true` only in `Failed`. Prefer `instanceof Failed` + `satisfies never` for exhaustive narrowing. */
90
+ readonly isFailed = true;
91
+ }
92
+ /** Terminal success state carrying the loaded value. */
93
+ declare class Ready<E, T> implements IRemoteData<E, T> {
94
+ private readonly _tag;
95
+ static new<E, T>(v: T): Ready<E, T>;
96
+ readonly value: T;
97
+ constructor(v: T);
98
+ /** Transform only if `Ready`; `Loading`/`Failed`/`NotAsked` pass through unchanged. */
99
+ map<W>(f: (t: T) => W): RemoteData<E, W>;
100
+ /** Chain a `RemoteData`-returning fn without double-wrapping. */
101
+ chain<W>(f: (t: T) => RemoteData<E, W>): RemoteData<E, W>;
102
+ /** Return `f(error)` on `Failed`, otherwise return `def`. */
103
+ unwrapFailure<W>(def: W, _: (e: E) => W): W;
104
+ /** Collapse to `Just(value)` on `Ready`, otherwise `Nothing`. */
105
+ toMaybe(): Maybe<T>;
106
+ /** `true` only in `Loading`. Prefer `instanceof Loading` + `satisfies never` for exhaustive narrowing. */
107
+ readonly isLoading = false;
108
+ /** `true` only in `Ready`. Prefer `instanceof Ready` + `satisfies never` for exhaustive narrowing. */
109
+ readonly isReady = true;
110
+ /** `true` only in `Failed`. Prefer `instanceof Failed` + `satisfies never` for exhaustive narrowing. */
111
+ readonly isFailed = false;
112
+ }
113
+ declare var CallableNotAsked: typeof NotAsked & typeof NotAsked.new;
114
+ declare var CallableLoading: typeof Loading & typeof Loading.new;
115
+ declare var CallableFailure: typeof Failed & typeof Failed.new;
116
+ declare var CallableSuccess: typeof Ready & typeof Ready.new;
117
+ export { type RemoteData, CallableSuccess as Ready, CallableFailure as Failed, CallableNotAsked as NotAsked, CallableLoading as Loading, };
@@ -0,0 +1,148 @@
1
+ import { Nothing, Just } from "./maybe";
2
+ import Callable from "./callable";
3
+ /**
4
+ * Initial state: the request hasn't been made yet. For "asked but empty",
5
+ * use `Ready([])` instead — `NotAsked` is not a generic "no data" state.
6
+ */
7
+ class NotAsked {
8
+ // @ts-expect-error Unused _tag's existence prevents structural comparison
9
+ _tag = null;
10
+ static new() {
11
+ return new NotAsked();
12
+ }
13
+ /** Transform only if `Ready`; `Loading`/`Failed`/`NotAsked` pass through unchanged. */
14
+ map(_) {
15
+ return new NotAsked();
16
+ }
17
+ /** Chain a `RemoteData`-returning fn without double-wrapping. */
18
+ chain(_) {
19
+ return new NotAsked();
20
+ }
21
+ /** Return `f(error)` on `Failed`, otherwise return `def`. */
22
+ unwrapFailure(def, _) {
23
+ return def;
24
+ }
25
+ /** Collapse to `Just(value)` on `Ready`, otherwise `Nothing`. */
26
+ toMaybe() {
27
+ return Nothing();
28
+ }
29
+ /** `true` only in `Loading`. Prefer `instanceof Loading` + `satisfies never` for exhaustive narrowing. */
30
+ isLoading = false;
31
+ /** `true` only in `Ready`. Prefer `instanceof Ready` + `satisfies never` for exhaustive narrowing. */
32
+ isReady = false;
33
+ /** `true` only in `Failed`. Prefer `instanceof Failed` + `satisfies never` for exhaustive narrowing. */
34
+ isFailed = false;
35
+ }
36
+ /** In-flight state. Optionally carries upload/download progress via `details`. */
37
+ class Loading {
38
+ // @ts-expect-errorUnused_tag's existence prevents structural comparison
39
+ _tag = null;
40
+ uploaded;
41
+ uploadSize;
42
+ downloaded;
43
+ downloadSize;
44
+ constructor(details = null) {
45
+ this.uploaded = details?.uploaded ?? 0;
46
+ this.uploadSize = details?.uploadSize ?? null;
47
+ this.downloaded = details?.downloaded ?? 0;
48
+ this.downloadSize = details?.downloadSize ?? null;
49
+ }
50
+ static new(details = null) {
51
+ return new Loading(details);
52
+ }
53
+ /** Transform only if `Ready`; `Loading`/`Failed`/`NotAsked` pass through unchanged. */
54
+ map(_) {
55
+ return new Loading();
56
+ }
57
+ /** Chain a `RemoteData`-returning fn without double-wrapping. */
58
+ chain(_) {
59
+ return new Loading();
60
+ }
61
+ /** Return `f(error)` on `Failed`, otherwise return `def`. */
62
+ unwrapFailure(def, _) {
63
+ return def;
64
+ }
65
+ /** Collapse to `Just(value)` on `Ready`, otherwise `Nothing`. */
66
+ toMaybe() {
67
+ return Nothing();
68
+ }
69
+ /** `true` only in `Loading`. Prefer `instanceof Loading` + `satisfies never` for exhaustive narrowing. */
70
+ isLoading = true;
71
+ /** `true` only in `Ready`. Prefer `instanceof Ready` + `satisfies never` for exhaustive narrowing. */
72
+ isReady = false;
73
+ /** `true` only in `Failed`. Prefer `instanceof Failed` + `satisfies never` for exhaustive narrowing. */
74
+ isFailed = false;
75
+ }
76
+ /** Terminal failure state carrying the error payload. */
77
+ class Failed {
78
+ // @ts-expect-error Unused _tag's existence prevents structural comparison
79
+ _tag = null;
80
+ error;
81
+ static new(e) {
82
+ return new Failed(e);
83
+ }
84
+ constructor(e) {
85
+ this.error = e;
86
+ }
87
+ /** Transform only if `Ready`; `Loading`/`Failed`/`NotAsked` pass through unchanged. */
88
+ map(_) {
89
+ return new Failed(this.error);
90
+ }
91
+ /** Chain a `RemoteData`-returning fn without double-wrapping. */
92
+ chain(_) {
93
+ return new Failed(this.error);
94
+ }
95
+ /** Return `f(error)` on `Failed`, otherwise return `def`. */
96
+ unwrapFailure(_, f) {
97
+ return f(this.error);
98
+ }
99
+ /** Collapse to `Just(value)` on `Ready`, otherwise `Nothing`. */
100
+ toMaybe() {
101
+ return Nothing();
102
+ }
103
+ /** `true` only in `Loading`. Prefer `instanceof Loading` + `satisfies never` for exhaustive narrowing. */
104
+ isLoading = false;
105
+ /** `true` only in `Ready`. Prefer `instanceof Ready` + `satisfies never` for exhaustive narrowing. */
106
+ isReady = false;
107
+ /** `true` only in `Failed`. Prefer `instanceof Failed` + `satisfies never` for exhaustive narrowing. */
108
+ isFailed = true;
109
+ }
110
+ /** Terminal success state carrying the loaded value. */
111
+ class Ready {
112
+ // @ts-expect-error Unused _tag's existence prevents structural comparison
113
+ _tag = null;
114
+ static new(v) {
115
+ return new Ready(v);
116
+ }
117
+ value;
118
+ constructor(v) {
119
+ this.value = v;
120
+ }
121
+ /** Transform only if `Ready`; `Loading`/`Failed`/`NotAsked` pass through unchanged. */
122
+ map(f) {
123
+ return new Ready(f(this.value));
124
+ }
125
+ /** Chain a `RemoteData`-returning fn without double-wrapping. */
126
+ chain(f) {
127
+ return f(this.value);
128
+ }
129
+ /** Return `f(error)` on `Failed`, otherwise return `def`. */
130
+ unwrapFailure(def, _) {
131
+ return def;
132
+ }
133
+ /** Collapse to `Just(value)` on `Ready`, otherwise `Nothing`. */
134
+ toMaybe() {
135
+ return Just(this.value);
136
+ }
137
+ /** `true` only in `Loading`. Prefer `instanceof Loading` + `satisfies never` for exhaustive narrowing. */
138
+ isLoading = false;
139
+ /** `true` only in `Ready`. Prefer `instanceof Ready` + `satisfies never` for exhaustive narrowing. */
140
+ isReady = true;
141
+ /** `true` only in `Failed`. Prefer `instanceof Failed` + `satisfies never` for exhaustive narrowing. */
142
+ isFailed = false;
143
+ }
144
+ var CallableNotAsked = Callable(NotAsked);
145
+ var CallableLoading = Callable(Loading);
146
+ var CallableFailure = Callable(Failed);
147
+ var CallableSuccess = Callable(Ready);
148
+ export { CallableSuccess as Ready, CallableFailure as Failed, CallableNotAsked as NotAsked, CallableLoading as Loading, };
@@ -0,0 +1,75 @@
1
+ import { List } from "./list";
2
+ /**
3
+ * Represents the result of a computation that may fail.
4
+ *
5
+ * Either `Success<E, T>` wrapping a successful value, or `Failure<E, T>`
6
+ * wrapping an error value.
7
+ */
8
+ type Result<E, T> = Success<E, T> | Failure<E, T>;
9
+ export interface IResult<E, T> {
10
+ isSuccess(): boolean;
11
+ isFailure(): boolean;
12
+ map<W>(f: (t: T) => W): Result<E, W>;
13
+ mapFailure<W>(f: (t: E) => W): Result<W, T>;
14
+ either<W>(f: (e: E) => W, g: (s: T) => W): W;
15
+ chain<W>(f: (t: T) => Result<E, W>): Result<E, W>;
16
+ unwrap(f: (e: E) => string): T;
17
+ withDefault(f: (e: E) => T): T;
18
+ }
19
+ /** Wrap a computed value. Use to return from a fallible operation that succeeded. */
20
+ declare class Success<E, T> implements IResult<E, T> {
21
+ readonly value: T;
22
+ static new<E, T>(v: T): Success<E, T>;
23
+ constructor(v: T);
24
+ /** Returns true if this is a `Success`. Prefer `instanceof Success` for narrowing. */
25
+ isSuccess(): boolean;
26
+ /** Returns true if this is a `Failure`. Prefer `instanceof Failure` for narrowing. */
27
+ isFailure(): boolean;
28
+ /** Transform the success value; `Failure` passes through unchanged. */
29
+ map<W>(f: (t: T) => W): Result<E, W>;
30
+ /** Transform the error value; `Success` passes through unchanged. */
31
+ mapFailure<W>(_: (t: E) => W): Result<W, T>;
32
+ /** Exhaustive fold: `f(error)` on `Failure`, `g(value)` on `Success`. */
33
+ either<W>(_: (e: E) => W, g: (s: T) => W): W;
34
+ /** Monadic sequencing. Short-circuits on the first `Failure`. */
35
+ chain<W>(f: (t: T) => Result<E, W>): Result<E, W>;
36
+ /**
37
+ * Unwrap the value or throw an `Error` built from `f(error)`. Boundary-only —
38
+ * don't mix with try/catch; use `either` or `withDefault` in business logic.
39
+ */
40
+ unwrap(_: (e: E) => string): T;
41
+ /** Recover from `Failure` by mapping the error to a default value. */
42
+ withDefault(_: (e: E) => T): T;
43
+ }
44
+ /** Wrap an error value. Return from a fallible operation instead of throwing — reserve `throw` for catastrophic bugs. */
45
+ declare class Failure<E, T> implements IResult<E, T> {
46
+ readonly error: E;
47
+ static new<E, T>(v: E): Failure<E, T>;
48
+ constructor(v: E);
49
+ /** Returns true if this is a `Success`. Prefer `instanceof Success` for narrowing. */
50
+ isSuccess(): boolean;
51
+ /** Returns true if this is a `Failure`. Prefer `instanceof Failure` for narrowing. */
52
+ isFailure(): boolean;
53
+ /** Transform the success value; `Failure` passes through unchanged. */
54
+ map<W>(_: (t: T) => W): Result<E, W>;
55
+ /** Transform the error value; `Success` passes through unchanged. */
56
+ mapFailure<W>(f: (t: E) => W): Result<W, T>;
57
+ /** Exhaustive fold: `f(error)` on `Failure`, `g(value)` on `Success`. */
58
+ either<W>(f: (e: E) => W, _: (s: T) => W): W;
59
+ /** Monadic sequencing. Short-circuits on the first `Failure`. */
60
+ chain<W>(_: (t: T) => Result<E, W>): Result<E, W>;
61
+ /**
62
+ * Unwrap the value or throw an `Error` built from `f(error)`. Boundary-only —
63
+ * don't mix with try/catch; use `either` or `withDefault` in business logic.
64
+ */
65
+ unwrap(f: (error: E) => string): T;
66
+ /** Recover from `Failure` by mapping the error to a default value. */
67
+ withDefault(f: (e: E) => T): T;
68
+ }
69
+ /** Traverse a `List<A>` with a fallible fn. Short-circuits on the first `Failure`. */
70
+ declare function traverse<T, A, E>(xs: List<A>, f: (v: A) => Result<E, T>): Result<E, List<T>>;
71
+ /** Array version of `traverse`. Short-circuits on the first `Failure`. */
72
+ declare function traverse_<T, A, E>(xs: Array<A>, f: (v: A) => Result<E, T>): Result<E, Array<T>>;
73
+ declare var CallableSuccess: typeof Success & typeof Success.new;
74
+ declare var CallableFailure: typeof Failure & typeof Failure.new;
75
+ export { type Result, CallableSuccess as Success, CallableFailure as Failure, traverse, traverse_ };
package/dist/result.js ADDED
@@ -0,0 +1,126 @@
1
+ import { end, tailRecursive } from "./trampoline";
2
+ import { List } from "./list";
3
+ import Callable from "./callable";
4
+ /** Wrap a computed value. Use to return from a fallible operation that succeeded. */
5
+ class Success {
6
+ value;
7
+ static new(v) {
8
+ return new Success(v);
9
+ }
10
+ constructor(v) {
11
+ this.value = v;
12
+ }
13
+ /** Returns true if this is a `Success`. Prefer `instanceof Success` for narrowing. */
14
+ isSuccess() {
15
+ return true;
16
+ }
17
+ /** Returns true if this is a `Failure`. Prefer `instanceof Failure` for narrowing. */
18
+ isFailure() {
19
+ return false;
20
+ }
21
+ /** Transform the success value; `Failure` passes through unchanged. */
22
+ map(f) {
23
+ return new Success(f(this.value));
24
+ }
25
+ /** Transform the error value; `Success` passes through unchanged. */
26
+ mapFailure(_) {
27
+ return new Success(this.value);
28
+ }
29
+ /** Exhaustive fold: `f(error)` on `Failure`, `g(value)` on `Success`. */
30
+ either(_, g) {
31
+ return g(this.value);
32
+ }
33
+ /** Monadic sequencing. Short-circuits on the first `Failure`. */
34
+ chain(f) {
35
+ return f(this.value);
36
+ }
37
+ /**
38
+ * Unwrap the value or throw an `Error` built from `f(error)`. Boundary-only —
39
+ * don't mix with try/catch; use `either` or `withDefault` in business logic.
40
+ */
41
+ unwrap(_) {
42
+ return this.value;
43
+ }
44
+ /** Recover from `Failure` by mapping the error to a default value. */
45
+ withDefault(_) {
46
+ return this.value;
47
+ }
48
+ }
49
+ /** Wrap an error value. Return from a fallible operation instead of throwing — reserve `throw` for catastrophic bugs. */
50
+ class Failure {
51
+ error;
52
+ static new(v) {
53
+ return new Failure(v);
54
+ }
55
+ constructor(v) {
56
+ this.error = v;
57
+ }
58
+ /** Returns true if this is a `Success`. Prefer `instanceof Success` for narrowing. */
59
+ isSuccess() {
60
+ return false;
61
+ }
62
+ /** Returns true if this is a `Failure`. Prefer `instanceof Failure` for narrowing. */
63
+ isFailure() {
64
+ return true;
65
+ }
66
+ /** Transform the success value; `Failure` passes through unchanged. */
67
+ map(_) {
68
+ return new Failure(this.error);
69
+ }
70
+ /** Transform the error value; `Success` passes through unchanged. */
71
+ mapFailure(f) {
72
+ return new Failure(f(this.error));
73
+ }
74
+ /** Exhaustive fold: `f(error)` on `Failure`, `g(value)` on `Success`. */
75
+ either(f, _) {
76
+ return f(this.error);
77
+ }
78
+ /** Monadic sequencing. Short-circuits on the first `Failure`. */
79
+ chain(_) {
80
+ return new Failure(this.error);
81
+ }
82
+ /**
83
+ * Unwrap the value or throw an `Error` built from `f(error)`. Boundary-only —
84
+ * don't mix with try/catch; use `either` or `withDefault` in business logic.
85
+ */
86
+ unwrap(f) {
87
+ throw new Error(f(this.error));
88
+ }
89
+ /** Recover from `Failure` by mapping the error to a default value. */
90
+ withDefault(f) {
91
+ return f(this.error);
92
+ }
93
+ }
94
+ /** Traverse a `List<A>` with a fallible fn. Short-circuits on the first `Failure`. */
95
+ function traverse(xs, f) {
96
+ const go = tailRecursive((done, todo) => {
97
+ switch (true) {
98
+ case "head" in todo.value: {
99
+ const { head, tail } = todo.value;
100
+ const r = f(head);
101
+ switch (true) {
102
+ case r instanceof Success: {
103
+ const value = r.value;
104
+ return go(List.cons(value, done), tail);
105
+ }
106
+ case r instanceof Failure:
107
+ return end(new Failure(r.error));
108
+ default:
109
+ return r;
110
+ }
111
+ }
112
+ case "empty" in todo.value:
113
+ return end(new Success(done.reverse()));
114
+ default:
115
+ return todo.value;
116
+ }
117
+ });
118
+ return go(List.empty(), xs).run();
119
+ }
120
+ /** Array version of `traverse`. Short-circuits on the first `Failure`. */
121
+ function traverse_(xs, f) {
122
+ return traverse(List.from(xs), f).map(r => r.toArray());
123
+ }
124
+ var CallableSuccess = Callable(Success);
125
+ var CallableFailure = Callable(Failure);
126
+ export { CallableSuccess as Success, CallableFailure as Failure, traverse, traverse_ };