@nicolastoulemont/std 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/README.md +1 -0
- package/dist/adt/index.d.mts +2 -0
- package/dist/adt/index.mjs +3 -0
- package/dist/adt-DraJkmij.mjs +318 -0
- package/dist/adt-DraJkmij.mjs.map +1 -0
- package/dist/apply-fn.types-CXDoeA7D.d.mts +8 -0
- package/dist/apply-fn.types-CXDoeA7D.d.mts.map +1 -0
- package/dist/brand/index.d.mts +2 -0
- package/dist/brand/index.mjs +3 -0
- package/dist/brand-CTaxGuU9.mjs +165 -0
- package/dist/brand-CTaxGuU9.mjs.map +1 -0
- package/dist/data/index.d.mts +2 -0
- package/dist/data/index.mjs +3 -0
- package/dist/data-DgzWI4R_.mjs +244 -0
- package/dist/data-DgzWI4R_.mjs.map +1 -0
- package/dist/discriminator.types-DCkkrCj4.d.mts +7 -0
- package/dist/discriminator.types-DCkkrCj4.d.mts.map +1 -0
- package/dist/either/index.d.mts +2 -0
- package/dist/either/index.mjs +3 -0
- package/dist/either-CnOBUH7a.mjs +598 -0
- package/dist/either-CnOBUH7a.mjs.map +1 -0
- package/dist/equality/index.d.mts +86 -0
- package/dist/equality/index.d.mts.map +1 -0
- package/dist/equality/index.mjs +3 -0
- package/dist/equality-YMebYwm1.mjs +201 -0
- package/dist/equality-YMebYwm1.mjs.map +1 -0
- package/dist/err/index.d.mts +2 -0
- package/dist/err/index.mjs +3 -0
- package/dist/err-BqQApH9r.mjs +169 -0
- package/dist/err-BqQApH9r.mjs.map +1 -0
- package/dist/flow/index.d.mts +2 -0
- package/dist/flow/index.mjs +3 -0
- package/dist/flow-pRdnqmMY.mjs +21 -0
- package/dist/flow-pRdnqmMY.mjs.map +1 -0
- package/dist/gen/index.d.mts +3 -0
- package/dist/gen/index.mjs +3 -0
- package/dist/gen-YfMC9sDT.mjs +42 -0
- package/dist/gen-YfMC9sDT.mjs.map +1 -0
- package/dist/index-BCrD3pEs.d.mts +222 -0
- package/dist/index-BCrD3pEs.d.mts.map +1 -0
- package/dist/index-BR7takNf.d.mts +186 -0
- package/dist/index-BR7takNf.d.mts.map +1 -0
- package/dist/index-CcPnhWje.d.mts +72 -0
- package/dist/index-CcPnhWje.d.mts.map +1 -0
- package/dist/index-CtJ8Ks9X.d.mts +105 -0
- package/dist/index-CtJ8Ks9X.d.mts.map +1 -0
- package/dist/index-CvGTIg9L.d.mts +211 -0
- package/dist/index-CvGTIg9L.d.mts.map +1 -0
- package/dist/index-DPVT0yK4.d.mts +50 -0
- package/dist/index-DPVT0yK4.d.mts.map +1 -0
- package/dist/index-DgOAEEpu.d.mts +79 -0
- package/dist/index-DgOAEEpu.d.mts.map +1 -0
- package/dist/index-Dtq3kmln.d.mts +394 -0
- package/dist/index-Dtq3kmln.d.mts.map +1 -0
- package/dist/index-bLRqTe5I.d.mts +80 -0
- package/dist/index-bLRqTe5I.d.mts.map +1 -0
- package/dist/index-tkgTLCoq.d.mts +80 -0
- package/dist/index-tkgTLCoq.d.mts.map +1 -0
- package/dist/index-wTrnFgYg.d.mts +57 -0
- package/dist/index-wTrnFgYg.d.mts.map +1 -0
- package/dist/index-yyBTq8Ys.d.mts +79 -0
- package/dist/index-yyBTq8Ys.d.mts.map +1 -0
- package/dist/index.d.mts +135 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +41 -0
- package/dist/index.mjs.map +1 -0
- package/dist/is-promise-BEl3eGZg.mjs +11 -0
- package/dist/is-promise-BEl3eGZg.mjs.map +1 -0
- package/dist/option/index.d.mts +3 -0
- package/dist/option/index.mjs +3 -0
- package/dist/option-CKHDOVea.mjs +410 -0
- package/dist/option-CKHDOVea.mjs.map +1 -0
- package/dist/option.types-D6TYG_i3.d.mts +89 -0
- package/dist/option.types-D6TYG_i3.d.mts.map +1 -0
- package/dist/pipe/index.d.mts +2 -0
- package/dist/pipe/index.mjs +3 -0
- package/dist/pipe-GYxZNkPB.mjs +10 -0
- package/dist/pipe-GYxZNkPB.mjs.map +1 -0
- package/dist/predicate/index.d.mts +2 -0
- package/dist/predicate/index.mjs +3 -0
- package/dist/predicate-B6-EdVgW.mjs +293 -0
- package/dist/predicate-B6-EdVgW.mjs.map +1 -0
- package/dist/result/index.d.mts +3 -0
- package/dist/result/index.mjs +3 -0
- package/dist/result-C5tPWR60.mjs +422 -0
- package/dist/result-C5tPWR60.mjs.map +1 -0
- package/dist/result-D7XJ96pv.mjs +1 -0
- package/dist/result.types-Ce7AEOzj.d.mts +156 -0
- package/dist/result.types-Ce7AEOzj.d.mts.map +1 -0
- package/dist/run/index.d.mts +2 -0
- package/dist/run/index.mjs +3 -0
- package/dist/run-DpXkImo9.mjs +10 -0
- package/dist/run-DpXkImo9.mjs.map +1 -0
- package/package.json +89 -0
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { t as Discriminator } from "../discriminator.types-DCkkrCj4.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/equality/equality.d.ts
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Compute a 32-bit hash code for any value using an FNV-1a inspired algorithm.
|
|
7
|
+
*
|
|
8
|
+
* Handles: primitives, null, undefined, Date, arrays, and plain objects.
|
|
9
|
+
* Object keys are sorted for deterministic hashing regardless of insertion order.
|
|
10
|
+
*
|
|
11
|
+
* @param value - The value to hash (any type)
|
|
12
|
+
* @returns A 32-bit unsigned integer hash code
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```ts
|
|
16
|
+
* deepHash({ a: 1, b: 2 }) // deterministic number
|
|
17
|
+
* deepHash({ b: 2, a: 1 }) // same number (keys sorted)
|
|
18
|
+
* deepHash([1, 2, 3]) === deepHash([1, 2, 3]) // true
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
declare function deepHash(value: unknown): number;
|
|
22
|
+
/**
|
|
23
|
+
* Deep structural equality comparison for two values.
|
|
24
|
+
*
|
|
25
|
+
* Compares by value rather than reference. Handles:
|
|
26
|
+
* - Primitives (===)
|
|
27
|
+
* - null and undefined
|
|
28
|
+
* - Date objects (by timestamp)
|
|
29
|
+
* - Arrays (element-wise, same length required)
|
|
30
|
+
* - Plain objects (key-value pairs, same keys required)
|
|
31
|
+
*
|
|
32
|
+
* @param a - First value to compare
|
|
33
|
+
* @param b - Second value to compare
|
|
34
|
+
* @returns true if values are structurally equal
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* ```ts
|
|
38
|
+
* deepEquals({ x: 1 }, { x: 1 }) // true
|
|
39
|
+
* deepEquals([1, 2], [1, 2]) // true
|
|
40
|
+
* deepEquals(new Date(0), new Date(0)) // true
|
|
41
|
+
* deepEquals({ a: 1 }, { a: 1, b: 2 }) // false (different keys)
|
|
42
|
+
* ```
|
|
43
|
+
*/
|
|
44
|
+
declare function deepEquals(a: unknown, b: unknown): boolean;
|
|
45
|
+
/**
|
|
46
|
+
* Create an equals method for a specific record type.
|
|
47
|
+
*
|
|
48
|
+
* Returns a function that compares two values of the same record type.
|
|
49
|
+
* Returns false if either value doesn't have the expected __typename.
|
|
50
|
+
*
|
|
51
|
+
* @template Typename - The discriminator string literal type
|
|
52
|
+
* @template T - The record's data type (excluding __typename)
|
|
53
|
+
* @param __typename - The expected __typename discriminator value
|
|
54
|
+
* @returns A binary equality function for the record type
|
|
55
|
+
*
|
|
56
|
+
* @example
|
|
57
|
+
* ```ts
|
|
58
|
+
* const equalsPoint = createEqualsMethod<'Point', { x: number; y: number }>('Point')
|
|
59
|
+
* equalsPoint(
|
|
60
|
+
* { __typename: 'Point', x: 1, y: 2 },
|
|
61
|
+
* { __typename: 'Point', x: 1, y: 2 }
|
|
62
|
+
* ) // true
|
|
63
|
+
* ```
|
|
64
|
+
*/
|
|
65
|
+
declare function createEqualsMethod<Typename extends string, T>(__typename: Typename): (a: T & Discriminator<Typename>, b: T & Discriminator<Typename>) => boolean;
|
|
66
|
+
/**
|
|
67
|
+
* Create a hash method for a specific record type.
|
|
68
|
+
*
|
|
69
|
+
* Returns a function that computes a hash code for values of the record type.
|
|
70
|
+
* Returns 0 if the value doesn't have the expected __typename.
|
|
71
|
+
*
|
|
72
|
+
* @template Typename - The discriminator string literal type
|
|
73
|
+
* @template T - The record's data type (excluding __typename)
|
|
74
|
+
* @param __typename - The expected __typename discriminator value
|
|
75
|
+
* @returns A unary hash function for the record type
|
|
76
|
+
*
|
|
77
|
+
* @example
|
|
78
|
+
* ```ts
|
|
79
|
+
* const hashPoint = createHashMethod<'Point', { x: number; y: number }>('Point')
|
|
80
|
+
* hashPoint({ __typename: 'Point', x: 1, y: 2 }) // number
|
|
81
|
+
* ```
|
|
82
|
+
*/
|
|
83
|
+
declare function createHashMethod<Typename extends string, T>(__typename: Typename): (value: T & Discriminator<Typename>) => number;
|
|
84
|
+
//#endregion
|
|
85
|
+
export { createEqualsMethod, createHashMethod, deepEquals, deepHash };
|
|
86
|
+
//# sourceMappingURL=index.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../../src/equality/equality.ts"],"sourcesContent":[],"mappings":";;;;;;AAyBA;AA4FA;AAgEA;;;;;;;;;AA2BA;;;AAE6B,iBAzLb,QAAA,CAyLa,KAAA,EAAA,OAAA,CAAA,EAAA,MAAA;;;;;;;;;;;;;;;;;;;;;;;iBA7Fb,UAAA;;;;;;;;;;;;;;;;;;;;;iBAgEA,2DACF,eACP,IAAI,cAAc,cAAc,IAAI,cAAc;;;;;;;;;;;;;;;;;;iBAyBzC,yDACF,mBACH,IAAI,cAAc"}
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
//#region src/equality/equality.ts
|
|
2
|
+
const FNV_OFFSET = 2166136261;
|
|
3
|
+
const FNV_PRIME = 16777619;
|
|
4
|
+
/**
|
|
5
|
+
* Compute a 32-bit hash code for any value using an FNV-1a inspired algorithm.
|
|
6
|
+
*
|
|
7
|
+
* Handles: primitives, null, undefined, Date, arrays, and plain objects.
|
|
8
|
+
* Object keys are sorted for deterministic hashing regardless of insertion order.
|
|
9
|
+
*
|
|
10
|
+
* @param value - The value to hash (any type)
|
|
11
|
+
* @returns A 32-bit unsigned integer hash code
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```ts
|
|
15
|
+
* deepHash({ a: 1, b: 2 }) // deterministic number
|
|
16
|
+
* deepHash({ b: 2, a: 1 }) // same number (keys sorted)
|
|
17
|
+
* deepHash([1, 2, 3]) === deepHash([1, 2, 3]) // true
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
function deepHash(value) {
|
|
21
|
+
let hash = FNV_OFFSET;
|
|
22
|
+
if (value === null) return hash ^ 1853189228;
|
|
23
|
+
if (value === void 0) return hash ^ 1970168933;
|
|
24
|
+
switch (typeof value) {
|
|
25
|
+
case "boolean": return hash ^ (value ? 1 : 0);
|
|
26
|
+
case "number":
|
|
27
|
+
if (Number.isNaN(value)) return hash ^ 5136718;
|
|
28
|
+
if (!Number.isFinite(value)) return hash ^ (value > 0 ? 4812390 : 759787110);
|
|
29
|
+
return hash ^ (value | 0) ^ (value * 1e6 | 0);
|
|
30
|
+
case "string":
|
|
31
|
+
for (let i = 0; i < value.length; i++) {
|
|
32
|
+
hash ^= value.codePointAt(i);
|
|
33
|
+
hash = Math.imul(hash, FNV_PRIME);
|
|
34
|
+
}
|
|
35
|
+
return hash >>> 0;
|
|
36
|
+
case "object": {
|
|
37
|
+
if (value instanceof Date) return hash ^ deepHash(value.getTime());
|
|
38
|
+
if (Array.isArray(value)) {
|
|
39
|
+
hash ^= 23389;
|
|
40
|
+
for (let i = 0; i < value.length; i++) {
|
|
41
|
+
hash ^= deepHash(value[i]);
|
|
42
|
+
hash = Math.imul(hash, FNV_PRIME);
|
|
43
|
+
}
|
|
44
|
+
return hash >>> 0;
|
|
45
|
+
}
|
|
46
|
+
hash ^= 31613;
|
|
47
|
+
const obj = value;
|
|
48
|
+
const keys = Object.keys(obj).toSorted();
|
|
49
|
+
for (const key of keys) {
|
|
50
|
+
hash ^= deepHash(key);
|
|
51
|
+
hash = Math.imul(hash, FNV_PRIME);
|
|
52
|
+
hash ^= deepHash(obj[key]);
|
|
53
|
+
hash = Math.imul(hash, FNV_PRIME);
|
|
54
|
+
}
|
|
55
|
+
return hash >>> 0;
|
|
56
|
+
}
|
|
57
|
+
default: return hash;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Deep structural equality comparison for two values.
|
|
62
|
+
*
|
|
63
|
+
* Compares by value rather than reference. Handles:
|
|
64
|
+
* - Primitives (===)
|
|
65
|
+
* - null and undefined
|
|
66
|
+
* - Date objects (by timestamp)
|
|
67
|
+
* - Arrays (element-wise, same length required)
|
|
68
|
+
* - Plain objects (key-value pairs, same keys required)
|
|
69
|
+
*
|
|
70
|
+
* @param a - First value to compare
|
|
71
|
+
* @param b - Second value to compare
|
|
72
|
+
* @returns true if values are structurally equal
|
|
73
|
+
*
|
|
74
|
+
* @example
|
|
75
|
+
* ```ts
|
|
76
|
+
* deepEquals({ x: 1 }, { x: 1 }) // true
|
|
77
|
+
* deepEquals([1, 2], [1, 2]) // true
|
|
78
|
+
* deepEquals(new Date(0), new Date(0)) // true
|
|
79
|
+
* deepEquals({ a: 1 }, { a: 1, b: 2 }) // false (different keys)
|
|
80
|
+
* ```
|
|
81
|
+
*/
|
|
82
|
+
function deepEquals(a, b) {
|
|
83
|
+
if (a === b) return true;
|
|
84
|
+
if (typeof a !== typeof b) return false;
|
|
85
|
+
if (a === null || b === null) return false;
|
|
86
|
+
if (typeof a !== "object") return false;
|
|
87
|
+
if (a instanceof Date && b instanceof Date) return a.getTime() === b.getTime();
|
|
88
|
+
if (Array.isArray(a) && Array.isArray(b)) {
|
|
89
|
+
if (a.length !== b.length) return false;
|
|
90
|
+
return a.every((item, index) => deepEquals(item, b[index]));
|
|
91
|
+
}
|
|
92
|
+
if (Array.isArray(a) !== Array.isArray(b)) return false;
|
|
93
|
+
const aObj = a;
|
|
94
|
+
const bObj = b;
|
|
95
|
+
const aKeys = Object.keys(aObj);
|
|
96
|
+
const bKeys = Object.keys(bObj);
|
|
97
|
+
if (aKeys.length !== bKeys.length) return false;
|
|
98
|
+
return aKeys.every((key) => deepEquals(aObj[key], bObj[key]));
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Create an equals method for a specific record type.
|
|
102
|
+
*
|
|
103
|
+
* Returns a function that compares two values of the same record type.
|
|
104
|
+
* Returns false if either value doesn't have the expected __typename.
|
|
105
|
+
*
|
|
106
|
+
* @template Typename - The discriminator string literal type
|
|
107
|
+
* @template T - The record's data type (excluding __typename)
|
|
108
|
+
* @param __typename - The expected __typename discriminator value
|
|
109
|
+
* @returns A binary equality function for the record type
|
|
110
|
+
*
|
|
111
|
+
* @example
|
|
112
|
+
* ```ts
|
|
113
|
+
* const equalsPoint = createEqualsMethod<'Point', { x: number; y: number }>('Point')
|
|
114
|
+
* equalsPoint(
|
|
115
|
+
* { __typename: 'Point', x: 1, y: 2 },
|
|
116
|
+
* { __typename: 'Point', x: 1, y: 2 }
|
|
117
|
+
* ) // true
|
|
118
|
+
* ```
|
|
119
|
+
*/
|
|
120
|
+
function createEqualsMethod(__typename) {
|
|
121
|
+
return (a, b) => {
|
|
122
|
+
if (a === b) return true;
|
|
123
|
+
if (a.__typename !== __typename || b.__typename !== __typename) return false;
|
|
124
|
+
return deepEquals(a, b);
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Create a hash method for a specific record type.
|
|
129
|
+
*
|
|
130
|
+
* Returns a function that computes a hash code for values of the record type.
|
|
131
|
+
* Returns 0 if the value doesn't have the expected __typename.
|
|
132
|
+
*
|
|
133
|
+
* @template Typename - The discriminator string literal type
|
|
134
|
+
* @template T - The record's data type (excluding __typename)
|
|
135
|
+
* @param __typename - The expected __typename discriminator value
|
|
136
|
+
* @returns A unary hash function for the record type
|
|
137
|
+
*
|
|
138
|
+
* @example
|
|
139
|
+
* ```ts
|
|
140
|
+
* const hashPoint = createHashMethod<'Point', { x: number; y: number }>('Point')
|
|
141
|
+
* hashPoint({ __typename: 'Point', x: 1, y: 2 }) // number
|
|
142
|
+
* ```
|
|
143
|
+
*/
|
|
144
|
+
function createHashMethod(__typename) {
|
|
145
|
+
return (value) => {
|
|
146
|
+
if (value.__typename !== __typename) return 0;
|
|
147
|
+
return deepHash(value);
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Create an equals method for an ADT (any variant).
|
|
152
|
+
*
|
|
153
|
+
* Returns a function that compares two ADT values for structural equality.
|
|
154
|
+
* Values must have the same __typename and be a known variant.
|
|
155
|
+
*
|
|
156
|
+
* @template T - The ADT type (union of all variants with __typename)
|
|
157
|
+
* @param typenames - Array of valid __typename values for this ADT
|
|
158
|
+
* @returns A binary equality function for any variant of the ADT
|
|
159
|
+
*
|
|
160
|
+
* @example
|
|
161
|
+
* ```ts
|
|
162
|
+
* const equalsShape = createADTEqualsMethod<Circle | Square>(['Circle', 'Square'])
|
|
163
|
+
* equalsShape(circle1, circle2) // true if structurally equal
|
|
164
|
+
* equalsShape(circle, square) // false (different __typename)
|
|
165
|
+
* ```
|
|
166
|
+
*/
|
|
167
|
+
function createADTEqualsMethod(typenames) {
|
|
168
|
+
return (a, b) => {
|
|
169
|
+
if (a === b) return true;
|
|
170
|
+
if (a.__typename !== b.__typename) return false;
|
|
171
|
+
if (!typenames.includes(a.__typename)) return false;
|
|
172
|
+
return deepEquals(a, b);
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Create a hash method for an ADT (any variant).
|
|
177
|
+
*
|
|
178
|
+
* Returns a function that computes a hash code for any variant of the ADT.
|
|
179
|
+
* Returns 0 if the value's __typename is not a known variant.
|
|
180
|
+
*
|
|
181
|
+
* @template T - The ADT type (union of all variants with __typename)
|
|
182
|
+
* @param typenames - Array of valid __typename values for this ADT
|
|
183
|
+
* @returns A unary hash function for any variant of the ADT
|
|
184
|
+
*
|
|
185
|
+
* @example
|
|
186
|
+
* ```ts
|
|
187
|
+
* const hashShape = createADTHashMethod<Circle | Square>(['Circle', 'Square'])
|
|
188
|
+
* hashShape(circle) // number
|
|
189
|
+
* hashShape(square) // number
|
|
190
|
+
* ```
|
|
191
|
+
*/
|
|
192
|
+
function createADTHashMethod(typenames) {
|
|
193
|
+
return (value) => {
|
|
194
|
+
if (!typenames.includes(value.__typename)) return 0;
|
|
195
|
+
return deepHash(value);
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
//#endregion
|
|
200
|
+
export { deepEquals as a, createHashMethod as i, createADTHashMethod as n, deepHash as o, createEqualsMethod as r, createADTEqualsMethod as t };
|
|
201
|
+
//# sourceMappingURL=equality-YMebYwm1.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"equality-YMebYwm1.mjs","names":[],"sources":["../src/equality/equality.ts"],"sourcesContent":["import type { Discriminator } from \"../shared/discriminator.types\"\n\n// ============================================================================\n// Hashing (FNV-1a inspired algorithm)\n// ============================================================================\n\nconst FNV_OFFSET = 2166136261\nconst FNV_PRIME = 16777619\n\n/**\n * Compute a 32-bit hash code for any value using an FNV-1a inspired algorithm.\n *\n * Handles: primitives, null, undefined, Date, arrays, and plain objects.\n * Object keys are sorted for deterministic hashing regardless of insertion order.\n *\n * @param value - The value to hash (any type)\n * @returns A 32-bit unsigned integer hash code\n *\n * @example\n * ```ts\n * deepHash({ a: 1, b: 2 }) // deterministic number\n * deepHash({ b: 2, a: 1 }) // same number (keys sorted)\n * deepHash([1, 2, 3]) === deepHash([1, 2, 3]) // true\n * ```\n */\nexport function deepHash(value: unknown): number {\n let hash = FNV_OFFSET\n\n // \"null\" as hex\n if (value === null) return hash ^ 0x6e756c6c\n // \"unde\" as hex\n if (value === undefined) return hash ^ 0x756e6465\n\n /* oxlint-disable unicorn/prefer-math-trunc, no-case-declarations, switch-exhaustiveness-check -- Bitwise ops are intentional for FNV-1a hash: | 0 truncates to signed 32-bit, >>> 0 converts to unsigned 32-bit (Math.trunc cannot do this). Default case handles function, symbol, bigint. */\n switch (typeof value) {\n case \"boolean\":\n return hash ^ (value ? 1 : 0)\n\n case \"number\": {\n // Handle special cases: \"NaN\" as hex\n if (Number.isNaN(value)) return hash ^ 0x4e614e\n if (!Number.isFinite(value)) return hash ^ (value > 0 ? 0x496e66 : 0x2d496e66)\n // Mix the number bits into hash\n return hash ^ (value | 0) ^ ((value * 1000000) | 0)\n }\n\n case \"string\":\n for (let i = 0; i < value.length; i++) {\n hash ^= value.codePointAt(i)!\n hash = Math.imul(hash, FNV_PRIME)\n }\n // Convert to unsigned 32-bit\n return hash >>> 0\n\n case \"object\": {\n if (value instanceof Date) {\n return hash ^ deepHash(value.getTime())\n }\n\n if (Array.isArray(value)) {\n // \"[]\" as hex\n hash ^= 0x5b5d\n for (let i = 0; i < value.length; i++) {\n hash ^= deepHash(value[i])\n hash = Math.imul(hash, FNV_PRIME)\n }\n return hash >>> 0\n }\n\n // Plain object: \"{}\" as hex\n hash ^= 0x7b7d\n // oxlint-disable-next-line no-unsafe-type-assertion -- Required for object iteration\n const obj = value as Record<string, unknown>\n // Sort keys for consistency\n const keys = Object.keys(obj).toSorted()\n for (const key of keys) {\n hash ^= deepHash(key)\n hash = Math.imul(hash, FNV_PRIME)\n hash ^= deepHash(obj[key])\n hash = Math.imul(hash, FNV_PRIME)\n }\n return hash >>> 0\n }\n\n default:\n // Handles: function, symbol, bigint\n return hash\n }\n /* oxlint-enable unicorn/prefer-math-trunc, no-case-declarations */\n}\n\n// ============================================================================\n// Equality\n// ============================================================================\n\n/**\n * Deep structural equality comparison for two values.\n *\n * Compares by value rather than reference. Handles:\n * - Primitives (===)\n * - null and undefined\n * - Date objects (by timestamp)\n * - Arrays (element-wise, same length required)\n * - Plain objects (key-value pairs, same keys required)\n *\n * @param a - First value to compare\n * @param b - Second value to compare\n * @returns true if values are structurally equal\n *\n * @example\n * ```ts\n * deepEquals({ x: 1 }, { x: 1 }) // true\n * deepEquals([1, 2], [1, 2]) // true\n * deepEquals(new Date(0), new Date(0)) // true\n * deepEquals({ a: 1 }, { a: 1, b: 2 }) // false (different keys)\n * ```\n */\nexport function deepEquals(a: unknown, b: unknown): boolean {\n // Same reference or both null/undefined\n if (a === b) return true\n\n // Different types\n if (typeof a !== typeof b) return false\n\n // Handle null\n if (a === null || b === null) return false\n\n // Primitives (already checked === above)\n if (typeof a !== \"object\") return false\n\n // Date comparison\n if (a instanceof Date && b instanceof Date) {\n return a.getTime() === b.getTime()\n }\n\n // Array comparison\n if (Array.isArray(a) && Array.isArray(b)) {\n if (a.length !== b.length) return false\n return a.every((item, index) => deepEquals(item, b[index]))\n }\n\n // Plain object comparison\n if (Array.isArray(a) !== Array.isArray(b)) return false\n\n // oxlint-disable-next-line no-unsafe-type-assertion -- Required for object comparison\n const aObj = a as Record<string, unknown>\n // oxlint-disable-next-line no-unsafe-type-assertion -- Required for object comparison\n const bObj = b as Record<string, unknown>\n\n const aKeys = Object.keys(aObj)\n const bKeys = Object.keys(bObj)\n\n if (aKeys.length !== bKeys.length) return false\n\n return aKeys.every((key) => deepEquals(aObj[key], bObj[key]))\n}\n\n// ============================================================================\n// Factory Functions\n// ============================================================================\n\n/**\n * Create an equals method for a specific record type.\n *\n * Returns a function that compares two values of the same record type.\n * Returns false if either value doesn't have the expected __typename.\n *\n * @template Typename - The discriminator string literal type\n * @template T - The record's data type (excluding __typename)\n * @param __typename - The expected __typename discriminator value\n * @returns A binary equality function for the record type\n *\n * @example\n * ```ts\n * const equalsPoint = createEqualsMethod<'Point', { x: number; y: number }>('Point')\n * equalsPoint(\n * { __typename: 'Point', x: 1, y: 2 },\n * { __typename: 'Point', x: 1, y: 2 }\n * ) // true\n * ```\n */\nexport function createEqualsMethod<Typename extends string, T>(\n __typename: Typename,\n): (a: T & Discriminator<Typename>, b: T & Discriminator<Typename>) => boolean {\n return (a, b) => {\n if (a === b) return true\n if (a.__typename !== __typename || b.__typename !== __typename) return false\n return deepEquals(a, b)\n }\n}\n\n/**\n * Create a hash method for a specific record type.\n *\n * Returns a function that computes a hash code for values of the record type.\n * Returns 0 if the value doesn't have the expected __typename.\n *\n * @template Typename - The discriminator string literal type\n * @template T - The record's data type (excluding __typename)\n * @param __typename - The expected __typename discriminator value\n * @returns A unary hash function for the record type\n *\n * @example\n * ```ts\n * const hashPoint = createHashMethod<'Point', { x: number; y: number }>('Point')\n * hashPoint({ __typename: 'Point', x: 1, y: 2 }) // number\n * ```\n */\nexport function createHashMethod<Typename extends string, T>(\n __typename: Typename,\n): (value: T & Discriminator<Typename>) => number {\n return (value) => {\n if (value.__typename !== __typename) return 0\n return deepHash(value)\n }\n}\n\n/**\n * Create an equals method for an ADT (any variant).\n *\n * Returns a function that compares two ADT values for structural equality.\n * Values must have the same __typename and be a known variant.\n *\n * @template T - The ADT type (union of all variants with __typename)\n * @param typenames - Array of valid __typename values for this ADT\n * @returns A binary equality function for any variant of the ADT\n *\n * @example\n * ```ts\n * const equalsShape = createADTEqualsMethod<Circle | Square>(['Circle', 'Square'])\n * equalsShape(circle1, circle2) // true if structurally equal\n * equalsShape(circle, square) // false (different __typename)\n * ```\n */\nexport function createADTEqualsMethod<T extends { readonly __typename: string }>(\n typenames: string[],\n): (a: T, b: T) => boolean {\n return (a, b) => {\n if (a === b) return true\n if (a.__typename !== b.__typename) return false\n if (!typenames.includes(a.__typename)) return false\n return deepEquals(a, b)\n }\n}\n\n/**\n * Create a hash method for an ADT (any variant).\n *\n * Returns a function that computes a hash code for any variant of the ADT.\n * Returns 0 if the value's __typename is not a known variant.\n *\n * @template T - The ADT type (union of all variants with __typename)\n * @param typenames - Array of valid __typename values for this ADT\n * @returns A unary hash function for any variant of the ADT\n *\n * @example\n * ```ts\n * const hashShape = createADTHashMethod<Circle | Square>(['Circle', 'Square'])\n * hashShape(circle) // number\n * hashShape(square) // number\n * ```\n */\nexport function createADTHashMethod<T extends { readonly __typename: string }>(\n typenames: string[],\n): (value: T) => number {\n return (value) => {\n if (!typenames.includes(value.__typename)) return 0\n return deepHash(value)\n }\n}\n"],"mappings":";AAMA,MAAM,aAAa;AACnB,MAAM,YAAY;;;;;;;;;;;;;;;;;AAkBlB,SAAgB,SAAS,OAAwB;CAC/C,IAAI,OAAO;AAGX,KAAI,UAAU,KAAM,QAAO,OAAO;AAElC,KAAI,UAAU,OAAW,QAAO,OAAO;AAGvC,SAAQ,OAAO,OAAf;EACE,KAAK,UACH,QAAO,QAAQ,QAAQ,IAAI;EAE7B,KAAK;AAEH,OAAI,OAAO,MAAM,MAAM,CAAE,QAAO,OAAO;AACvC,OAAI,CAAC,OAAO,SAAS,MAAM,CAAE,QAAO,QAAQ,QAAQ,IAAI,UAAW;AAEnE,UAAO,QAAQ,QAAQ,MAAO,QAAQ,MAAW;EAGnD,KAAK;AACH,QAAK,IAAI,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;AACrC,YAAQ,MAAM,YAAY,EAAE;AAC5B,WAAO,KAAK,KAAK,MAAM,UAAU;;AAGnC,UAAO,SAAS;EAElB,KAAK,UAAU;AACb,OAAI,iBAAiB,KACnB,QAAO,OAAO,SAAS,MAAM,SAAS,CAAC;AAGzC,OAAI,MAAM,QAAQ,MAAM,EAAE;AAExB,YAAQ;AACR,SAAK,IAAI,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;AACrC,aAAQ,SAAS,MAAM,GAAG;AAC1B,YAAO,KAAK,KAAK,MAAM,UAAU;;AAEnC,WAAO,SAAS;;AAIlB,WAAQ;GAER,MAAM,MAAM;GAEZ,MAAM,OAAO,OAAO,KAAK,IAAI,CAAC,UAAU;AACxC,QAAK,MAAM,OAAO,MAAM;AACtB,YAAQ,SAAS,IAAI;AACrB,WAAO,KAAK,KAAK,MAAM,UAAU;AACjC,YAAQ,SAAS,IAAI,KAAK;AAC1B,WAAO,KAAK,KAAK,MAAM,UAAU;;AAEnC,UAAO,SAAS;;EAGlB,QAEE,QAAO;;;;;;;;;;;;;;;;;;;;;;;;;AA+Bb,SAAgB,WAAW,GAAY,GAAqB;AAE1D,KAAI,MAAM,EAAG,QAAO;AAGpB,KAAI,OAAO,MAAM,OAAO,EAAG,QAAO;AAGlC,KAAI,MAAM,QAAQ,MAAM,KAAM,QAAO;AAGrC,KAAI,OAAO,MAAM,SAAU,QAAO;AAGlC,KAAI,aAAa,QAAQ,aAAa,KACpC,QAAO,EAAE,SAAS,KAAK,EAAE,SAAS;AAIpC,KAAI,MAAM,QAAQ,EAAE,IAAI,MAAM,QAAQ,EAAE,EAAE;AACxC,MAAI,EAAE,WAAW,EAAE,OAAQ,QAAO;AAClC,SAAO,EAAE,OAAO,MAAM,UAAU,WAAW,MAAM,EAAE,OAAO,CAAC;;AAI7D,KAAI,MAAM,QAAQ,EAAE,KAAK,MAAM,QAAQ,EAAE,CAAE,QAAO;CAGlD,MAAM,OAAO;CAEb,MAAM,OAAO;CAEb,MAAM,QAAQ,OAAO,KAAK,KAAK;CAC/B,MAAM,QAAQ,OAAO,KAAK,KAAK;AAE/B,KAAI,MAAM,WAAW,MAAM,OAAQ,QAAO;AAE1C,QAAO,MAAM,OAAO,QAAQ,WAAW,KAAK,MAAM,KAAK,KAAK,CAAC;;;;;;;;;;;;;;;;;;;;;;AA2B/D,SAAgB,mBACd,YAC6E;AAC7E,SAAQ,GAAG,MAAM;AACf,MAAI,MAAM,EAAG,QAAO;AACpB,MAAI,EAAE,eAAe,cAAc,EAAE,eAAe,WAAY,QAAO;AACvE,SAAO,WAAW,GAAG,EAAE;;;;;;;;;;;;;;;;;;;;AAqB3B,SAAgB,iBACd,YACgD;AAChD,SAAQ,UAAU;AAChB,MAAI,MAAM,eAAe,WAAY,QAAO;AAC5C,SAAO,SAAS,MAAM;;;;;;;;;;;;;;;;;;;;AAqB1B,SAAgB,sBACd,WACyB;AACzB,SAAQ,GAAG,MAAM;AACf,MAAI,MAAM,EAAG,QAAO;AACpB,MAAI,EAAE,eAAe,EAAE,WAAY,QAAO;AAC1C,MAAI,CAAC,UAAU,SAAS,EAAE,WAAW,CAAE,QAAO;AAC9C,SAAO,WAAW,GAAG,EAAE;;;;;;;;;;;;;;;;;;;;AAqB3B,SAAgB,oBACd,WACsB;AACtB,SAAQ,UAAU;AAChB,MAAI,CAAC,UAAU,SAAS,MAAM,WAAW,CAAE,QAAO;AAClD,SAAO,SAAS,MAAM"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { a as TaggedError$1, i as ErrorTag, n as TaggedError, o as TaggedErrorFactory, r as ErrorData, s as TaggedErrorInstance, t as Err } from "../index-BR7takNf.mjs";
|
|
2
|
+
export { Err, ErrorData, ErrorTag, TaggedError, TaggedErrorFactory, TaggedErrorInstance, TaggedError$1 as TaggedErrorType };
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
//#region src/err/err.ts
|
|
2
|
+
/**
|
|
3
|
+
* Create a constructor function for a tagged error type.
|
|
4
|
+
* If the error has no additional data, returns a function that takes no arguments.
|
|
5
|
+
* If the error has data, returns a function that requires the data object.
|
|
6
|
+
*
|
|
7
|
+
* @template E - The tagged error type
|
|
8
|
+
* @param tag - The error tag (must match E's __typename)
|
|
9
|
+
* @returns A constructor function for the error type
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```ts
|
|
13
|
+
* // Error with data
|
|
14
|
+
* type NotFoundError = TaggedError<"NotFoundError", { resourceId: string }>
|
|
15
|
+
* const NotFound = Err.tagged<NotFoundError>("NotFoundError")
|
|
16
|
+
* const err = NotFound({ resourceId: "user-123" })
|
|
17
|
+
* // { __typename: "NotFoundError", resourceId: "user-123" }
|
|
18
|
+
*
|
|
19
|
+
* // Error without data
|
|
20
|
+
* type UnauthorizedError = TaggedError<"UnauthorizedError">
|
|
21
|
+
* const Unauthorized = Err.tagged<UnauthorizedError>("UnauthorizedError")
|
|
22
|
+
* const err = Unauthorized()
|
|
23
|
+
* // { __typename: "UnauthorizedError" }
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
const tagged = (tag) => {
|
|
27
|
+
return ((data) => ({
|
|
28
|
+
__typename: tag,
|
|
29
|
+
...data
|
|
30
|
+
}));
|
|
31
|
+
};
|
|
32
|
+
/**
|
|
33
|
+
* Create a class-based tagged error type (Effect-style syntax).
|
|
34
|
+
* Returns a class that can be extended to create custom error types.
|
|
35
|
+
* Errors are native Error objects with proper stack traces and instanceof support.
|
|
36
|
+
* Implements Yieldable protocol so errors can be directly yielded in Do computations.
|
|
37
|
+
*
|
|
38
|
+
* @template Tag - The error tag (discriminator string)
|
|
39
|
+
* @param tag - The error tag
|
|
40
|
+
* @returns A class that can be extended with custom data
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* ```ts
|
|
44
|
+
* // Error with data
|
|
45
|
+
* class NotFoundError extends TaggedError("NotFoundError")<{ id: string }> {}
|
|
46
|
+
* const err = new NotFoundError({ id: "123" })
|
|
47
|
+
* err.id // "123"
|
|
48
|
+
* err.__typename // "NotFoundError"
|
|
49
|
+
* err.stack // Error stack trace
|
|
50
|
+
*
|
|
51
|
+
* // Error without data
|
|
52
|
+
* class UnauthorizedError extends TaggedError("UnauthorizedError") {}
|
|
53
|
+
* const err2 = new UnauthorizedError()
|
|
54
|
+
*
|
|
55
|
+
* // Direct yielding in Do computation
|
|
56
|
+
* const program = gen(function* () {
|
|
57
|
+
* yield* new NotFoundError({ id: "123" }) // Short-circuits with error
|
|
58
|
+
* })
|
|
59
|
+
*
|
|
60
|
+
* // instanceof checks work
|
|
61
|
+
* if (err instanceof NotFoundError) {
|
|
62
|
+
* console.log(err.id)
|
|
63
|
+
* }
|
|
64
|
+
* ```
|
|
65
|
+
*/
|
|
66
|
+
function TaggedError(tag) {
|
|
67
|
+
return class TaggedErrorImpl extends Error {
|
|
68
|
+
static __typename = tag;
|
|
69
|
+
__typename = tag;
|
|
70
|
+
constructor(...args) {
|
|
71
|
+
super(tag);
|
|
72
|
+
this.name = tag;
|
|
73
|
+
const data = args[0];
|
|
74
|
+
if (data) Object.assign(this, data);
|
|
75
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
76
|
+
}
|
|
77
|
+
*[Symbol.iterator]() {
|
|
78
|
+
yield this;
|
|
79
|
+
throw new Error("Unreachable: Do should short-circuit on error");
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Create a type guard for a tagged error type.
|
|
85
|
+
* Returns a curried function that checks if a value is the specified error type.
|
|
86
|
+
*
|
|
87
|
+
* @template E - The tagged error type to check for
|
|
88
|
+
* @param tag - The error tag to match
|
|
89
|
+
* @returns A type guard function
|
|
90
|
+
*
|
|
91
|
+
* @example
|
|
92
|
+
* ```ts
|
|
93
|
+
* type NotFoundError = TaggedError<"NotFoundError", { id: string }>
|
|
94
|
+
*
|
|
95
|
+
* const error: unknown = getError()
|
|
96
|
+
*
|
|
97
|
+
* if (Err.is<NotFoundError>("NotFoundError")(error)) {
|
|
98
|
+
* console.log(error.id) // TypeScript knows error is NotFoundError
|
|
99
|
+
* }
|
|
100
|
+
*
|
|
101
|
+
* // Works with union error types
|
|
102
|
+
* type AppError = NotFoundError | ValidationError | DbError
|
|
103
|
+
*
|
|
104
|
+
* function handleError(error: AppError) {
|
|
105
|
+
* if (Err.is<NotFoundError>("NotFoundError")(error)) {
|
|
106
|
+
* // Handle not found
|
|
107
|
+
* } else if (Err.is<ValidationError>("ValidationError")(error)) {
|
|
108
|
+
* // Handle validation error
|
|
109
|
+
* }
|
|
110
|
+
* }
|
|
111
|
+
* ```
|
|
112
|
+
*/
|
|
113
|
+
const is = (tag) => {
|
|
114
|
+
return (error) => typeof error === "object" && error !== null && "__typename" in error && error.__typename === tag;
|
|
115
|
+
};
|
|
116
|
+
/**
|
|
117
|
+
* Err namespace containing utilities for creating and checking tagged errors.
|
|
118
|
+
*
|
|
119
|
+
* Tagged errors are plain objects with a `__typename` discriminator field,
|
|
120
|
+
* making them serializable and easy to pattern match.
|
|
121
|
+
*
|
|
122
|
+
* @example
|
|
123
|
+
* ```ts
|
|
124
|
+
* import { Err, Result, Do } from "@repo/std"
|
|
125
|
+
* import type { TaggedError } from "@repo/std"
|
|
126
|
+
*
|
|
127
|
+
* // Define error types
|
|
128
|
+
* type NotFoundError = TaggedError<"NotFoundError", { resourceId: string }>
|
|
129
|
+
* type ValidationError = TaggedError<"ValidationError", { field: string; message: string }>
|
|
130
|
+
*
|
|
131
|
+
* // Create constructors
|
|
132
|
+
* const NotFound = Err.tagged<NotFoundError>("NotFoundError")
|
|
133
|
+
* const Validation = Err.tagged<ValidationError>("ValidationError")
|
|
134
|
+
*
|
|
135
|
+
* // Use with Result
|
|
136
|
+
* function findUser(id: string): Result<User, NotFoundError> {
|
|
137
|
+
* const user = db.find(id)
|
|
138
|
+
* if (!user) return Result.err(NotFound({ resourceId: id }))
|
|
139
|
+
* return Result.ok(user)
|
|
140
|
+
* }
|
|
141
|
+
*
|
|
142
|
+
* // Use with Do computation
|
|
143
|
+
* const program = gen(function* () {
|
|
144
|
+
* const user = yield* findUser("123")
|
|
145
|
+
* return user
|
|
146
|
+
* })
|
|
147
|
+
*
|
|
148
|
+
* // Pattern match on error types
|
|
149
|
+
* pipe(
|
|
150
|
+
* program.run(),
|
|
151
|
+
* Result.match({
|
|
152
|
+
* ok: (user) => console.log(user),
|
|
153
|
+
* err: (error) => {
|
|
154
|
+
* if (Err.is<NotFoundError>("NotFoundError")(error)) {
|
|
155
|
+
* console.log(`Not found: ${error.resourceId}`)
|
|
156
|
+
* }
|
|
157
|
+
* }
|
|
158
|
+
* })
|
|
159
|
+
* )
|
|
160
|
+
* ```
|
|
161
|
+
*/
|
|
162
|
+
const Err = {
|
|
163
|
+
tagged,
|
|
164
|
+
is
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
//#endregion
|
|
168
|
+
export { TaggedError as n, Err as t };
|
|
169
|
+
//# sourceMappingURL=err-BqQApH9r.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"err-BqQApH9r.mjs","names":[],"sources":["../src/err/err.ts"],"sourcesContent":["import type { TaggedError, TaggedErrorFactory } from \"./err.types\"\n\n/**\n * Helper type to extract data fields from a TaggedError (excluding __typename)\n */\ntype DataOf<E extends TaggedError<string>> = Omit<E, \"__typename\">\n\n/**\n * Helper type to check if data is empty (only has __typename)\n */\ntype IsEmptyData<Data> = keyof Data extends never ? true : false\n\n/**\n * Create a constructor function for a tagged error type.\n * If the error has no additional data, returns a function that takes no arguments.\n * If the error has data, returns a function that requires the data object.\n *\n * @template E - The tagged error type\n * @param tag - The error tag (must match E's __typename)\n * @returns A constructor function for the error type\n *\n * @example\n * ```ts\n * // Error with data\n * type NotFoundError = TaggedError<\"NotFoundError\", { resourceId: string }>\n * const NotFound = Err.tagged<NotFoundError>(\"NotFoundError\")\n * const err = NotFound({ resourceId: \"user-123\" })\n * // { __typename: \"NotFoundError\", resourceId: \"user-123\" }\n *\n * // Error without data\n * type UnauthorizedError = TaggedError<\"UnauthorizedError\">\n * const Unauthorized = Err.tagged<UnauthorizedError>(\"UnauthorizedError\")\n * const err = Unauthorized()\n * // { __typename: \"UnauthorizedError\" }\n * ```\n */\nexport const tagged: <E extends TaggedError<string>>(\n tag: E[\"__typename\"],\n) => IsEmptyData<DataOf<E>> extends true ? () => E : (data: DataOf<E>) => E = (tag) => {\n return ((data?: object) => ({ __typename: tag, ...data })) as never\n}\n\n/**\n * Create a class-based tagged error type (Effect-style syntax).\n * Returns a class that can be extended to create custom error types.\n * Errors are native Error objects with proper stack traces and instanceof support.\n * Implements Yieldable protocol so errors can be directly yielded in Do computations.\n *\n * @template Tag - The error tag (discriminator string)\n * @param tag - The error tag\n * @returns A class that can be extended with custom data\n *\n * @example\n * ```ts\n * // Error with data\n * class NotFoundError extends TaggedError(\"NotFoundError\")<{ id: string }> {}\n * const err = new NotFoundError({ id: \"123\" })\n * err.id // \"123\"\n * err.__typename // \"NotFoundError\"\n * err.stack // Error stack trace\n *\n * // Error without data\n * class UnauthorizedError extends TaggedError(\"UnauthorizedError\") {}\n * const err2 = new UnauthorizedError()\n *\n * // Direct yielding in Do computation\n * const program = gen(function* () {\n * yield* new NotFoundError({ id: \"123\" }) // Short-circuits with error\n * })\n *\n * // instanceof checks work\n * if (err instanceof NotFoundError) {\n * console.log(err.id)\n * }\n * ```\n */\nexport function TaggedError<Tag extends string>(tag: Tag): TaggedErrorFactory<Tag> {\n return class TaggedErrorImpl<Data extends object = object> extends Error {\n static readonly __typename: Tag = tag\n readonly __typename: Tag = tag\n\n constructor(...args: keyof Data extends never ? [] : [data: Data]) {\n super(tag)\n this.name = tag\n const data = args[0]\n if (data) Object.assign(this, data)\n Object.setPrototypeOf(this, new.target.prototype)\n }\n\n *[Symbol.iterator](): Generator<this, never, unknown> {\n yield this\n throw new Error(\"Unreachable: Do should short-circuit on error\")\n }\n } as unknown as TaggedErrorFactory<Tag>\n}\n\n/**\n * Create a type guard for a tagged error type.\n * Returns a curried function that checks if a value is the specified error type.\n *\n * @template E - The tagged error type to check for\n * @param tag - The error tag to match\n * @returns A type guard function\n *\n * @example\n * ```ts\n * type NotFoundError = TaggedError<\"NotFoundError\", { id: string }>\n *\n * const error: unknown = getError()\n *\n * if (Err.is<NotFoundError>(\"NotFoundError\")(error)) {\n * console.log(error.id) // TypeScript knows error is NotFoundError\n * }\n *\n * // Works with union error types\n * type AppError = NotFoundError | ValidationError | DbError\n *\n * function handleError(error: AppError) {\n * if (Err.is<NotFoundError>(\"NotFoundError\")(error)) {\n * // Handle not found\n * } else if (Err.is<ValidationError>(\"ValidationError\")(error)) {\n * // Handle validation error\n * }\n * }\n * ```\n */\nexport const is = <E extends TaggedError<string>>(tag: E[\"__typename\"]): ((error: unknown) => error is E) => {\n return (error: unknown): error is E =>\n typeof error === \"object\" && error !== null && \"__typename\" in error && error.__typename === tag\n}\n\n/**\n * Err namespace containing utilities for creating and checking tagged errors.\n *\n * Tagged errors are plain objects with a `__typename` discriminator field,\n * making them serializable and easy to pattern match.\n *\n * @example\n * ```ts\n * import { Err, Result, Do } from \"@repo/std\"\n * import type { TaggedError } from \"@repo/std\"\n *\n * // Define error types\n * type NotFoundError = TaggedError<\"NotFoundError\", { resourceId: string }>\n * type ValidationError = TaggedError<\"ValidationError\", { field: string; message: string }>\n *\n * // Create constructors\n * const NotFound = Err.tagged<NotFoundError>(\"NotFoundError\")\n * const Validation = Err.tagged<ValidationError>(\"ValidationError\")\n *\n * // Use with Result\n * function findUser(id: string): Result<User, NotFoundError> {\n * const user = db.find(id)\n * if (!user) return Result.err(NotFound({ resourceId: id }))\n * return Result.ok(user)\n * }\n *\n * // Use with Do computation\n * const program = gen(function* () {\n * const user = yield* findUser(\"123\")\n * return user\n * })\n *\n * // Pattern match on error types\n * pipe(\n * program.run(),\n * Result.match({\n * ok: (user) => console.log(user),\n * err: (error) => {\n * if (Err.is<NotFoundError>(\"NotFoundError\")(error)) {\n * console.log(`Not found: ${error.resourceId}`)\n * }\n * }\n * })\n * )\n * ```\n */\nexport const Err = {\n tagged,\n is,\n} as const\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;AAoCA,MAAa,UAEkE,QAAQ;AACrF,UAAS,UAAmB;EAAE,YAAY;EAAK,GAAG;EAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAqC1D,SAAgB,YAAgC,KAAmC;AACjF,QAAO,MAAM,wBAAsD,MAAM;EACvE,OAAgB,aAAkB;EAClC,AAAS,aAAkB;EAE3B,YAAY,GAAG,MAAoD;AACjE,SAAM,IAAI;AACV,QAAK,OAAO;GACZ,MAAM,OAAO,KAAK;AAClB,OAAI,KAAM,QAAO,OAAO,MAAM,KAAK;AACnC,UAAO,eAAe,MAAM,IAAI,OAAO,UAAU;;EAGnD,EAAE,OAAO,YAA6C;AACpD,SAAM;AACN,SAAM,IAAI,MAAM,gDAAgD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAmCtE,MAAa,MAAqC,QAA2D;AAC3G,SAAQ,UACN,OAAO,UAAU,YAAY,UAAU,QAAQ,gBAAgB,SAAS,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAiDjG,MAAa,MAAM;CACjB;CACA;CACD"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { t as isPromise } from "./is-promise-BEl3eGZg.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/flow/flow.ts
|
|
4
|
+
function flow(...fns) {
|
|
5
|
+
return ((...args) => {
|
|
6
|
+
let nextArgs = args;
|
|
7
|
+
for (let i = 0; i < fns.length; i++) {
|
|
8
|
+
const [result] = nextArgs = [fns[i]?.(...nextArgs)];
|
|
9
|
+
if (isPromise(result)) return resolveAsync(result, fns.slice(i + 1));
|
|
10
|
+
}
|
|
11
|
+
return nextArgs[0];
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
const resolveAsync = async (result, funs) => {
|
|
15
|
+
for (const fun of funs) result = fun(await result);
|
|
16
|
+
return await result;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
//#endregion
|
|
20
|
+
export { flow as t };
|
|
21
|
+
//# sourceMappingURL=flow-pRdnqmMY.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"flow-pRdnqmMY.mjs","names":[],"sources":["../src/flow/flow.ts"],"sourcesContent":["import { isPromise } from \"../shared/is-promise\"\nimport type { λ } from \"../shared/lambda.types\"\nimport type { FlowdFun } from \"./flow.types\"\n\n/**\n * Given a list of functions returns a function that will execute the given\n * functions one after another, always passing the result of the previous\n * function as an argument to the next function.\n *\n * If one of the given functions returns a promise, the promise will be resolved\n * before being passed to the next function.\n *\n * Type inference: This function provides automatic type inference for chains of\n * 1-15 functions. Each function's parameter type is automatically inferred from\n * the previous function's return type. For chains longer than 15 functions,\n * types must be explicitly specified.\n *\n * Async support: Functions can return Promises. The runtime automatically awaits\n * Promises before passing values to subsequent functions, and parameter types\n * use `Awaited<T>` to reflect this behavior. The final return type will be\n * Promise<T> if any function returns a Promise.\n *\n * @see {@link pipe} for immediate execution with an initial value\n *\n * @example\n * ```typescript\n * const join = (...chars: string[]) => chars.join('')\n * flow(join, parseInt)('1', '2', '3') // -> 123\n *\n * const square = (n: number) => n ** 2\n *\n * // this is equivalent to: square(square(square(2)))\n * flow(square, square, square)(2) // -> 256\n *\n * // Type inference in action\n * const fn = flow(\n * (n: number) => n * 2, // First function must be typed\n * (n) => n + 1, // n: number (inferred!)\n * (n) => n.toString() // n: number (inferred!)\n * )\n *\n * // also works with promises:\n * // fetchNumber :: async () => Promise<number>\n * flow(fetchNumber, n => n.toString()) // async () => Promise<string>\n * ```\n */\n// 1 function\nexport function flow<A extends unknown[], B>(f1: (...args: A) => B): FlowdFun<[typeof f1]>\n// 2 functions\nexport function flow<A extends unknown[], B, C>(\n f1: (...args: A) => B,\n f2: (arg: Awaited<B>) => C,\n): FlowdFun<[typeof f1, typeof f2]>\n// 3 functions\nexport function flow<A extends unknown[], B, C, D>(\n f1: (...args: A) => B,\n f2: (arg: Awaited<B>) => C,\n f3: (arg: Awaited<C>) => D,\n): FlowdFun<[typeof f1, typeof f2, typeof f3]>\n// 4 functions\nexport function flow<A extends unknown[], B, C, D, E>(\n f1: (...args: A) => B,\n f2: (arg: Awaited<B>) => C,\n f3: (arg: Awaited<C>) => D,\n f4: (arg: Awaited<D>) => E,\n): FlowdFun<[typeof f1, typeof f2, typeof f3, typeof f4]>\n// 5 functions\nexport function flow<A extends unknown[], B, C, D, E, F>(\n f1: (...args: A) => B,\n f2: (arg: Awaited<B>) => C,\n f3: (arg: Awaited<C>) => D,\n f4: (arg: Awaited<D>) => E,\n f5: (arg: Awaited<E>) => F,\n): FlowdFun<[typeof f1, typeof f2, typeof f3, typeof f4, typeof f5]>\n// 6 functions\nexport function flow<A extends unknown[], B, C, D, E, F, G>(\n f1: (...args: A) => B,\n f2: (arg: Awaited<B>) => C,\n f3: (arg: Awaited<C>) => D,\n f4: (arg: Awaited<D>) => E,\n f5: (arg: Awaited<E>) => F,\n f6: (arg: Awaited<F>) => G,\n): FlowdFun<[typeof f1, typeof f2, typeof f3, typeof f4, typeof f5, typeof f6]>\n// 7 functions\nexport function flow<A extends unknown[], B, C, D, E, F, G, H>(\n f1: (...args: A) => B,\n f2: (arg: Awaited<B>) => C,\n f3: (arg: Awaited<C>) => D,\n f4: (arg: Awaited<D>) => E,\n f5: (arg: Awaited<E>) => F,\n f6: (arg: Awaited<F>) => G,\n f7: (arg: Awaited<G>) => H,\n): FlowdFun<[typeof f1, typeof f2, typeof f3, typeof f4, typeof f5, typeof f6, typeof f7]>\n// 8 functions\nexport function flow<A extends unknown[], B, C, D, E, F, G, H, I>(\n f1: (...args: A) => B,\n f2: (arg: Awaited<B>) => C,\n f3: (arg: Awaited<C>) => D,\n f4: (arg: Awaited<D>) => E,\n f5: (arg: Awaited<E>) => F,\n f6: (arg: Awaited<F>) => G,\n f7: (arg: Awaited<G>) => H,\n f8: (arg: Awaited<H>) => I,\n): FlowdFun<[typeof f1, typeof f2, typeof f3, typeof f4, typeof f5, typeof f6, typeof f7, typeof f8]>\n// 9 functions\nexport function flow<A extends unknown[], B, C, D, E, F, G, H, I, J>(\n f1: (...args: A) => B,\n f2: (arg: Awaited<B>) => C,\n f3: (arg: Awaited<C>) => D,\n f4: (arg: Awaited<D>) => E,\n f5: (arg: Awaited<E>) => F,\n f6: (arg: Awaited<F>) => G,\n f7: (arg: Awaited<G>) => H,\n f8: (arg: Awaited<H>) => I,\n f9: (arg: Awaited<I>) => J,\n): FlowdFun<[typeof f1, typeof f2, typeof f3, typeof f4, typeof f5, typeof f6, typeof f7, typeof f8, typeof f9]>\n// 10 functions\nexport function flow<A extends unknown[], B, C, D, E, F, G, H, I, J, K>(\n f1: (...args: A) => B,\n f2: (arg: Awaited<B>) => C,\n f3: (arg: Awaited<C>) => D,\n f4: (arg: Awaited<D>) => E,\n f5: (arg: Awaited<E>) => F,\n f6: (arg: Awaited<F>) => G,\n f7: (arg: Awaited<G>) => H,\n f8: (arg: Awaited<H>) => I,\n f9: (arg: Awaited<I>) => J,\n f10: (arg: Awaited<J>) => K,\n): FlowdFun<\n [typeof f1, typeof f2, typeof f3, typeof f4, typeof f5, typeof f6, typeof f7, typeof f8, typeof f9, typeof f10]\n>\n// 11 functions\nexport function flow<A extends unknown[], B, C, D, E, F, G, H, I, J, K, L>(\n f1: (...args: A) => B,\n f2: (arg: Awaited<B>) => C,\n f3: (arg: Awaited<C>) => D,\n f4: (arg: Awaited<D>) => E,\n f5: (arg: Awaited<E>) => F,\n f6: (arg: Awaited<F>) => G,\n f7: (arg: Awaited<G>) => H,\n f8: (arg: Awaited<H>) => I,\n f9: (arg: Awaited<I>) => J,\n f10: (arg: Awaited<J>) => K,\n f11: (arg: Awaited<K>) => L,\n): FlowdFun<\n [\n typeof f1,\n typeof f2,\n typeof f3,\n typeof f4,\n typeof f5,\n typeof f6,\n typeof f7,\n typeof f8,\n typeof f9,\n typeof f10,\n typeof f11,\n ]\n>\n// 12 functions\nexport function flow<A extends unknown[], B, C, D, E, F, G, H, I, J, K, L, M>(\n f1: (...args: A) => B,\n f2: (arg: Awaited<B>) => C,\n f3: (arg: Awaited<C>) => D,\n f4: (arg: Awaited<D>) => E,\n f5: (arg: Awaited<E>) => F,\n f6: (arg: Awaited<F>) => G,\n f7: (arg: Awaited<G>) => H,\n f8: (arg: Awaited<H>) => I,\n f9: (arg: Awaited<I>) => J,\n f10: (arg: Awaited<J>) => K,\n f11: (arg: Awaited<K>) => L,\n f12: (arg: Awaited<L>) => M,\n): FlowdFun<\n [\n typeof f1,\n typeof f2,\n typeof f3,\n typeof f4,\n typeof f5,\n typeof f6,\n typeof f7,\n typeof f8,\n typeof f9,\n typeof f10,\n typeof f11,\n typeof f12,\n ]\n>\n// 13 functions\nexport function flow<A extends unknown[], B, C, D, E, F, G, H, I, J, K, L, M, N>(\n f1: (...args: A) => B,\n f2: (arg: Awaited<B>) => C,\n f3: (arg: Awaited<C>) => D,\n f4: (arg: Awaited<D>) => E,\n f5: (arg: Awaited<E>) => F,\n f6: (arg: Awaited<F>) => G,\n f7: (arg: Awaited<G>) => H,\n f8: (arg: Awaited<H>) => I,\n f9: (arg: Awaited<I>) => J,\n f10: (arg: Awaited<J>) => K,\n f11: (arg: Awaited<K>) => L,\n f12: (arg: Awaited<L>) => M,\n f13: (arg: Awaited<M>) => N,\n): FlowdFun<\n [\n typeof f1,\n typeof f2,\n typeof f3,\n typeof f4,\n typeof f5,\n typeof f6,\n typeof f7,\n typeof f8,\n typeof f9,\n typeof f10,\n typeof f11,\n typeof f12,\n typeof f13,\n ]\n>\n// 14 functions\nexport function flow<A extends unknown[], B, C, D, E, F, G, H, I, J, K, L, M, N, O>(\n f1: (...args: A) => B,\n f2: (arg: Awaited<B>) => C,\n f3: (arg: Awaited<C>) => D,\n f4: (arg: Awaited<D>) => E,\n f5: (arg: Awaited<E>) => F,\n f6: (arg: Awaited<F>) => G,\n f7: (arg: Awaited<G>) => H,\n f8: (arg: Awaited<H>) => I,\n f9: (arg: Awaited<I>) => J,\n f10: (arg: Awaited<J>) => K,\n f11: (arg: Awaited<K>) => L,\n f12: (arg: Awaited<L>) => M,\n f13: (arg: Awaited<M>) => N,\n f14: (arg: Awaited<N>) => O,\n): FlowdFun<\n [\n typeof f1,\n typeof f2,\n typeof f3,\n typeof f4,\n typeof f5,\n typeof f6,\n typeof f7,\n typeof f8,\n typeof f9,\n typeof f10,\n typeof f11,\n typeof f12,\n typeof f13,\n typeof f14,\n ]\n>\n// 15 functions\nexport function flow<A extends unknown[], B, C, D, E, F, G, H, I, J, K, L, M, N, O, P>(\n f1: (...args: A) => B,\n f2: (arg: Awaited<B>) => C,\n f3: (arg: Awaited<C>) => D,\n f4: (arg: Awaited<D>) => E,\n f5: (arg: Awaited<E>) => F,\n f6: (arg: Awaited<F>) => G,\n f7: (arg: Awaited<G>) => H,\n f8: (arg: Awaited<H>) => I,\n f9: (arg: Awaited<I>) => J,\n f10: (arg: Awaited<J>) => K,\n f11: (arg: Awaited<K>) => L,\n f12: (arg: Awaited<L>) => M,\n f13: (arg: Awaited<M>) => N,\n f14: (arg: Awaited<N>) => O,\n f15: (arg: Awaited<O>) => P,\n): FlowdFun<\n [\n typeof f1,\n typeof f2,\n typeof f3,\n typeof f4,\n typeof f5,\n typeof f6,\n typeof f7,\n typeof f8,\n typeof f9,\n typeof f10,\n typeof f11,\n typeof f12,\n typeof f13,\n typeof f14,\n typeof f15,\n ]\n>\n// Implementation signature (fallback for 16+ functions)\nexport function flow<Fns extends [λ, ...λ[]]>(...fns: Fns): FlowdFun<Fns> {\n // oxlint-disable-next-line\n return ((...args) => {\n // oxlint-disable-next-line\n let nextArgs: unknown[] = args\n\n for (let i = 0; i < fns.length; i++) {\n // oxlint-disable-next-line\n const [result] = (nextArgs = [fns[i]?.(...nextArgs)])\n if (isPromise(result)) return resolveAsync(result, fns.slice(i + 1))\n }\n\n return nextArgs[0]\n }) as FlowdFun<Fns>\n}\n\nconst resolveAsync = async (result: unknown, funs: λ[]) => {\n // oxlint-disable-next-line\n for (const fun of funs) result = fun(await result)\n return await result\n}\n"],"mappings":";;;AAoSA,SAAgB,KAA8B,GAAG,KAAyB;AAExE,UAAS,GAAG,SAAS;EAEnB,IAAI,WAAsB;AAE1B,OAAK,IAAI,IAAI,GAAG,IAAI,IAAI,QAAQ,KAAK;GAEnC,MAAM,CAAC,UAAW,WAAW,CAAC,IAAI,KAAK,GAAG,SAAS,CAAC;AACpD,OAAI,UAAU,OAAO,CAAE,QAAO,aAAa,QAAQ,IAAI,MAAM,IAAI,EAAE,CAAC;;AAGtE,SAAO,SAAS;;;AAIpB,MAAM,eAAe,OAAO,QAAiB,SAAc;AAEzD,MAAK,MAAM,OAAO,KAAM,UAAS,IAAI,MAAM,OAAO;AAClD,QAAO,MAAM"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { _ as YieldableError, d as AsyncComputation, f as AsyncGenGenerator, g as Yieldable, h as SyncComputation, m as GenGenerator, p as Computation, v as YieldableValue } from "../result.types-Ce7AEOzj.mjs";
|
|
2
|
+
import { t as gen } from "../index-DPVT0yK4.mjs";
|
|
3
|
+
export { AsyncComputation, AsyncGenGenerator, Computation, GenGenerator, SyncComputation, Yieldable, YieldableError, YieldableValue, gen };
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { n as err, r as ok } from "./result-C5tPWR60.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/gen/gen.ts
|
|
4
|
+
/**
|
|
5
|
+
* Implementation of unified gen function.
|
|
6
|
+
* Detects sync vs async generator and returns appropriate computation type.
|
|
7
|
+
*/
|
|
8
|
+
function gen(generatorFn) {
|
|
9
|
+
const runSync = () => {
|
|
10
|
+
const gen$1 = generatorFn();
|
|
11
|
+
if (Symbol.asyncIterator in gen$1) throw new Error("Cannot run sync on async generator. This should not happen if types are correct.");
|
|
12
|
+
const next = gen$1.next();
|
|
13
|
+
if (next.done !== true) return err(next.value);
|
|
14
|
+
return ok(next.value);
|
|
15
|
+
};
|
|
16
|
+
const runAsync = async () => {
|
|
17
|
+
const gen$1 = generatorFn();
|
|
18
|
+
if (Symbol.asyncIterator in gen$1) {
|
|
19
|
+
const next = await gen$1.next();
|
|
20
|
+
if (next.done !== true) return err(next.value);
|
|
21
|
+
return ok(next.value);
|
|
22
|
+
}
|
|
23
|
+
return runSync();
|
|
24
|
+
};
|
|
25
|
+
const testGen = generatorFn();
|
|
26
|
+
if (Symbol.asyncIterator in testGen) return { run: runAsync };
|
|
27
|
+
return {
|
|
28
|
+
run: runSync,
|
|
29
|
+
*[Symbol.iterator]() {
|
|
30
|
+
const result = runSync();
|
|
31
|
+
if (!result.ok) {
|
|
32
|
+
yield result.error;
|
|
33
|
+
throw new Error("Unreachable: Do should short-circuit on error");
|
|
34
|
+
}
|
|
35
|
+
return result.value;
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
//#endregion
|
|
41
|
+
export { gen as t };
|
|
42
|
+
//# sourceMappingURL=gen-YfMC9sDT.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gen-YfMC9sDT.mjs","names":["gen"],"sources":["../src/gen/gen.ts"],"sourcesContent":["import { ok, err } from \"../result/result\"\nimport type { Result } from \"../result/result.types\"\nimport type { SyncComputation, AsyncComputation, GenGenerator, AsyncGenGenerator } from \"./gen.types\"\n\n/**\n * Create a computation from a sync generator function.\n * Returns a SyncComputation where run() returns Result directly (no Promise).\n *\n * @template A - The success value type\n * @template E - The error type\n * @param generatorFn - A function that returns a sync generator\n * @returns SyncComputation<A, E>\n *\n * @see {@link run} for immediate execution without storing the computation\n *\n * @example\n * ```ts\n * const result = gen(function* () {\n * const a = yield* Result.yield(divide(10, 2))\n * const b = yield* Result.yield(divide(a, 2))\n * return b\n * }).run()\n * // Type: Result<number, \"DivisionByZero\">\n * ```\n */\nexport function gen<A, E>(generatorFn: () => GenGenerator<A, E>): SyncComputation<A, E>\n\n/**\n * Create a computation from an async generator function.\n * Returns an AsyncComputation where run() returns Promise<Result>.\n *\n * @template A - The success value type\n * @template E - The error type\n * @param generatorFn - A function that returns an async generator\n * @returns AsyncComputation<A, E>\n *\n * @see {@link run} for immediate execution without storing the computation\n *\n * @example\n * ```ts\n * const result = await gen(async function* () {\n * const data = yield* Result.yield(await fetchData(1))\n * return data\n * }).run()\n * // Type: Promise<Result<string, \"NetworkError\">>\n * ```\n */\nexport function gen<A, E>(generatorFn: () => AsyncGenGenerator<A, E>): AsyncComputation<A, E>\n\n/**\n * Implementation of unified gen function.\n * Detects sync vs async generator and returns appropriate computation type.\n */\nexport function gen<A, E>(\n generatorFn: () => GenGenerator<A, E> | AsyncGenGenerator<A, E>,\n): SyncComputation<A, E> | AsyncComputation<A, E> {\n // Helper to run sync generator\n const runSync = (): Result<A, E> => {\n const gen = generatorFn()\n\n // Detect async generator at runtime (safety check)\n if (Symbol.asyncIterator in gen) {\n throw new Error(\"Cannot run sync on async generator. This should not happen if types are correct.\")\n }\n\n const syncGen = gen\n const next = syncGen.next()\n\n // If not done, an error was yielded (short-circuit)\n if (next.done !== true) {\n return err(next.value)\n }\n\n return ok(next.value)\n }\n\n // Helper to run async generator\n const runAsync = async (): Promise<Result<A, E>> => {\n const gen = generatorFn()\n\n if (Symbol.asyncIterator in gen) {\n // Async generator path\n const asyncGen = gen\n const next = await asyncGen.next()\n\n if (next.done !== true) {\n return err(next.value)\n }\n return ok(next.value)\n }\n // Sync generator can also use run() - just runs synchronously\n return runSync()\n }\n\n // Check if we're dealing with async generator\n // We need to call it once to check the type\n const testGen = generatorFn()\n const isAsync = Symbol.asyncIterator in testGen\n\n if (isAsync) {\n // Return AsyncComputation (no Symbol.iterator - can't be yielded in sync context)\n return {\n run: runAsync,\n } as AsyncComputation<A, E>\n }\n // Return SyncComputation (with Symbol.iterator for nesting)\n return {\n run: runSync,\n *[Symbol.iterator](): Generator<E, A, unknown> {\n const result = runSync()\n if (!result.ok) {\n yield result.error\n // This line is never reached because outer Do stops iteration on first yield\n // But TypeScript needs a return statement for the A type\n throw new Error(\"Unreachable: Do should short-circuit on error\")\n }\n return result.value\n },\n } as SyncComputation<A, E>\n}\n"],"mappings":";;;;;;;AAqDA,SAAgB,IACd,aACgD;CAEhD,MAAM,gBAA8B;EAClC,MAAMA,QAAM,aAAa;AAGzB,MAAI,OAAO,iBAAiBA,MAC1B,OAAM,IAAI,MAAM,mFAAmF;EAIrG,MAAM,OADUA,MACK,MAAM;AAG3B,MAAI,KAAK,SAAS,KAChB,QAAO,IAAI,KAAK,MAAM;AAGxB,SAAO,GAAG,KAAK,MAAM;;CAIvB,MAAM,WAAW,YAAmC;EAClD,MAAMA,QAAM,aAAa;AAEzB,MAAI,OAAO,iBAAiBA,OAAK;GAG/B,MAAM,OAAO,MADIA,MACW,MAAM;AAElC,OAAI,KAAK,SAAS,KAChB,QAAO,IAAI,KAAK,MAAM;AAExB,UAAO,GAAG,KAAK,MAAM;;AAGvB,SAAO,SAAS;;CAKlB,MAAM,UAAU,aAAa;AAG7B,KAFgB,OAAO,iBAAiB,QAItC,QAAO,EACL,KAAK,UACN;AAGH,QAAO;EACL,KAAK;EACL,EAAE,OAAO,YAAsC;GAC7C,MAAM,SAAS,SAAS;AACxB,OAAI,CAAC,OAAO,IAAI;AACd,UAAM,OAAO;AAGb,UAAM,IAAI,MAAM,gDAAgD;;AAElE,UAAO,OAAO;;EAEjB"}
|