@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
package/README.md
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# @nicolastoulemont/std
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { _ as VariantNames, a as record, c as CodecDef, d as Infer, f as InferInput, g as ValidationError, h as RecordObject, i as data, l as CodecError, m as RecordDef, n as MatchHandlers, o as ADT, p as InferOutput, r as match, s as CodecConstraint, t as createCodecError, u as ExtractSchema, v as VariantOf } from "../index-Dtq3kmln.mjs";
|
|
2
|
+
export { ADT, CodecConstraint, CodecDef, CodecError, ExtractSchema, Infer, InferInput, InferOutput, MatchHandlers, RecordDef, RecordObject, ValidationError, VariantNames, VariantOf, createCodecError, data, match, record };
|
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
import { i as createHashMethod, n as createADTHashMethod, r as createEqualsMethod, t as createADTEqualsMethod } from "./equality-YMebYwm1.mjs";
|
|
2
|
+
import { t as isPromise } from "./is-promise-BEl3eGZg.mjs";
|
|
3
|
+
import { n as err, r as ok } from "./result-C5tPWR60.mjs";
|
|
4
|
+
|
|
5
|
+
//#region src/shared/is-plain-object.ts
|
|
6
|
+
/**
|
|
7
|
+
* Check if a value is a plain object.
|
|
8
|
+
* A plain object is an object created with `{}`, `Object.create(null)`, or `new Object()`.
|
|
9
|
+
* Arrays, functions, dates, maps, etc. are not considered plain objects.
|
|
10
|
+
*/
|
|
11
|
+
function isPlainObject(value) {
|
|
12
|
+
if (value === null || typeof value !== "object") return false;
|
|
13
|
+
const proto = Object.getPrototypeOf(value);
|
|
14
|
+
return proto === null || proto === Object.prototype;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
//#endregion
|
|
18
|
+
//#region src/adt/adt.utils.ts
|
|
19
|
+
/**
|
|
20
|
+
* Check if a value is a RecordObject created by record().
|
|
21
|
+
* RecordObjects are callable functions with static properties.
|
|
22
|
+
*/
|
|
23
|
+
function isRecord(value) {
|
|
24
|
+
return typeof value === "function" && "_record" in value && value["_record"] === true;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Wrap Standard Schema validation result into our Result type.
|
|
28
|
+
*/
|
|
29
|
+
function wrapValidationResult(result) {
|
|
30
|
+
if (result.issues) return err({ issues: result.issues.map((issue) => ({
|
|
31
|
+
message: issue.message,
|
|
32
|
+
path: issue.path?.map((segment) => typeof segment === "object" && "key" in segment ? segment.key : segment)
|
|
33
|
+
})) });
|
|
34
|
+
return ok(result.value);
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Validate data using a Standard Schema, enforcing sync-only validation.
|
|
38
|
+
* Throws if the schema returns a Promise.
|
|
39
|
+
*/
|
|
40
|
+
function validateSync(schema, data$1, __typename) {
|
|
41
|
+
const result = schema["~standard"].validate(data$1);
|
|
42
|
+
if (isPromise(result)) throw new Error(`Async validation not supported. Schema for "${__typename}" returned a Promise. Use a synchronous schema or handle async validation separately.`);
|
|
43
|
+
return wrapValidationResult(result);
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Create a type guard function for a specific __typename.
|
|
47
|
+
*/
|
|
48
|
+
function createIsGuard(__typename) {
|
|
49
|
+
return (value) => {
|
|
50
|
+
return isPlainObject(value) && "__typename" in value && value["__typename"] === __typename;
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Create a type guard function for multiple __typenames (ADT root guard).
|
|
55
|
+
*/
|
|
56
|
+
function createIsAnyGuard(__typenames) {
|
|
57
|
+
const __typenameSet = new Set(__typenames);
|
|
58
|
+
return (value) => {
|
|
59
|
+
return isPlainObject(value) && "__typename" in value && typeof value["__typename"] === "string" && __typenameSet.has(value["__typename"]);
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
//#endregion
|
|
64
|
+
//#region src/adt/adt.codec.ts
|
|
65
|
+
/**
|
|
66
|
+
* Create a CodecError with consistent structure.
|
|
67
|
+
*/
|
|
68
|
+
function createCodecError(kind, message, cause, validationIssues) {
|
|
69
|
+
if (cause !== void 0 && validationIssues !== void 0) return {
|
|
70
|
+
kind,
|
|
71
|
+
message,
|
|
72
|
+
cause,
|
|
73
|
+
validationIssues
|
|
74
|
+
};
|
|
75
|
+
if (cause !== void 0) return {
|
|
76
|
+
kind,
|
|
77
|
+
message,
|
|
78
|
+
cause
|
|
79
|
+
};
|
|
80
|
+
if (validationIssues !== void 0) return {
|
|
81
|
+
kind,
|
|
82
|
+
message,
|
|
83
|
+
validationIssues
|
|
84
|
+
};
|
|
85
|
+
return {
|
|
86
|
+
kind,
|
|
87
|
+
message
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Built-in JSON codec that works with any schema.
|
|
92
|
+
* Encodes to JSON string and decodes with JSON.parse.
|
|
93
|
+
*/
|
|
94
|
+
function createJsonCodec(__typename) {
|
|
95
|
+
return {
|
|
96
|
+
to: (value) => {
|
|
97
|
+
return JSON.stringify(value);
|
|
98
|
+
},
|
|
99
|
+
from: (input) => {
|
|
100
|
+
try {
|
|
101
|
+
const parsed = JSON.parse(input);
|
|
102
|
+
if (typeof parsed === "object" && parsed !== null && "__typename" in parsed) {
|
|
103
|
+
const { __typename: _, ...rest } = parsed;
|
|
104
|
+
return rest;
|
|
105
|
+
}
|
|
106
|
+
return parsed;
|
|
107
|
+
} catch {
|
|
108
|
+
return null;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Create the "to" methods object with JSON codec and custom codecs.
|
|
115
|
+
* All methods return Result<T, CodecError> for consistent error handling.
|
|
116
|
+
*/
|
|
117
|
+
function createToMethods(__typename, schema, customCodecs) {
|
|
118
|
+
const jsonCodec = createJsonCodec(__typename);
|
|
119
|
+
const to = { json: (value) => {
|
|
120
|
+
const result = validateSync(schema, {
|
|
121
|
+
...value,
|
|
122
|
+
__typename
|
|
123
|
+
}, __typename);
|
|
124
|
+
if (!result.ok) return err(createCodecError("ValidationError", `Cannot encode invalid data: ${result.error.issues.map((i) => i.message).join(", ")}`, void 0, result.error.issues));
|
|
125
|
+
try {
|
|
126
|
+
return ok(jsonCodec.to(result.value));
|
|
127
|
+
} catch (e) {
|
|
128
|
+
return err(createCodecError("EncodingError", `JSON encoding failed: ${e instanceof Error ? e.message : String(e)}`, e));
|
|
129
|
+
}
|
|
130
|
+
} };
|
|
131
|
+
if (customCodecs) for (const [name, codec] of Object.entries(customCodecs)) to[name] = (value) => {
|
|
132
|
+
const result = validateSync(schema, {
|
|
133
|
+
...value,
|
|
134
|
+
__typename
|
|
135
|
+
}, __typename);
|
|
136
|
+
if (!result.ok) return err(createCodecError("ValidationError", `Cannot encode invalid data: ${result.error.issues.map((i) => i.message).join(", ")}`, void 0, result.error.issues));
|
|
137
|
+
try {
|
|
138
|
+
return ok(codec.to(result.value));
|
|
139
|
+
} catch (e) {
|
|
140
|
+
return err(createCodecError("EncodingError", `Encoding with codec '${name}' failed: ${e instanceof Error ? e.message : String(e)}`, e));
|
|
141
|
+
}
|
|
142
|
+
};
|
|
143
|
+
return to;
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Create the "from" methods object with JSON codec and custom codecs.
|
|
147
|
+
* All methods return Result<T, CodecError> for consistent error handling.
|
|
148
|
+
*/
|
|
149
|
+
function createFromMethods(__typename, schema, customCodecs) {
|
|
150
|
+
const jsonCodec = createJsonCodec(__typename);
|
|
151
|
+
const from = { json: (input) => {
|
|
152
|
+
const decoded = jsonCodec.from(input);
|
|
153
|
+
if (decoded === null) return err(createCodecError("DecodingError", "Invalid JSON format"));
|
|
154
|
+
const result = validateSync(schema, {
|
|
155
|
+
...decoded,
|
|
156
|
+
__typename
|
|
157
|
+
}, __typename);
|
|
158
|
+
if (!result.ok) return err(createCodecError("ValidationError", "Decoded data failed schema validation", void 0, result.error.issues));
|
|
159
|
+
return ok({
|
|
160
|
+
...result.value,
|
|
161
|
+
__typename
|
|
162
|
+
});
|
|
163
|
+
} };
|
|
164
|
+
if (customCodecs) for (const [name, codec] of Object.entries(customCodecs)) from[name] = (input) => {
|
|
165
|
+
let decoded;
|
|
166
|
+
try {
|
|
167
|
+
decoded = codec.from(input);
|
|
168
|
+
} catch (e) {
|
|
169
|
+
return err(createCodecError("DecodingError", `Decoding with codec '${name}' threw an error`, e));
|
|
170
|
+
}
|
|
171
|
+
if (decoded === null) return err(createCodecError("DecodingError", `Codec '${name}' failed to decode input`));
|
|
172
|
+
const result = validateSync(schema, {
|
|
173
|
+
...decoded,
|
|
174
|
+
__typename
|
|
175
|
+
}, __typename);
|
|
176
|
+
if (!result.ok) return err(createCodecError("ValidationError", "Decoded data failed schema validation", void 0, result.error.issues));
|
|
177
|
+
return ok({
|
|
178
|
+
...result.value,
|
|
179
|
+
__typename
|
|
180
|
+
});
|
|
181
|
+
};
|
|
182
|
+
return from;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
//#endregion
|
|
186
|
+
//#region src/adt/adt.record.ts
|
|
187
|
+
function record(__typename, schema, codecs) {
|
|
188
|
+
const isGuard = createIsGuard(__typename);
|
|
189
|
+
const to = createToMethods(__typename, schema, codecs);
|
|
190
|
+
const from = createFromMethods(__typename, schema, codecs);
|
|
191
|
+
const equals = createEqualsMethod(__typename);
|
|
192
|
+
const hash = createHashMethod(__typename);
|
|
193
|
+
const constructor = (input) => {
|
|
194
|
+
const result = validateSync(schema, {
|
|
195
|
+
...input,
|
|
196
|
+
__typename
|
|
197
|
+
}, __typename);
|
|
198
|
+
if (!result.ok) return err(result.error);
|
|
199
|
+
return ok({
|
|
200
|
+
...result.value,
|
|
201
|
+
__typename
|
|
202
|
+
});
|
|
203
|
+
};
|
|
204
|
+
constructor._record = true;
|
|
205
|
+
constructor.__typename = __typename;
|
|
206
|
+
constructor.schema = schema;
|
|
207
|
+
if (codecs) constructor.codecs = codecs;
|
|
208
|
+
constructor.is = isGuard;
|
|
209
|
+
constructor.to = to;
|
|
210
|
+
constructor.from = from;
|
|
211
|
+
constructor.equals = equals;
|
|
212
|
+
constructor.hash = hash;
|
|
213
|
+
return constructor;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
//#endregion
|
|
217
|
+
//#region src/adt/adt.data.ts
|
|
218
|
+
/**
|
|
219
|
+
* Compose records or schemas into a discriminated union (ADT).
|
|
220
|
+
*
|
|
221
|
+
* Accepts either:
|
|
222
|
+
* - Pre-built RecordObjects from record() (codecs are preserved)
|
|
223
|
+
* - Raw Standard Schema validators (will be wrapped internally)
|
|
224
|
+
*
|
|
225
|
+
* When using pre-built records, the object key overrides the original __typename.
|
|
226
|
+
*
|
|
227
|
+
* @template R - Record of variant names to RecordObjects or StandardSchema validators
|
|
228
|
+
* @param name - The name of this ADT (for identification)
|
|
229
|
+
* @param records - An object mapping __typename names to RecordObjects or schemas
|
|
230
|
+
* @returns An ADT object with accessors for each variant
|
|
231
|
+
*
|
|
232
|
+
* @see {@link record} for creating individual record types
|
|
233
|
+
* @see {@link match} for exhaustive pattern matching on ADT values
|
|
234
|
+
*
|
|
235
|
+
* @example
|
|
236
|
+
* ```ts
|
|
237
|
+
* // From pre-built records
|
|
238
|
+
* const Circle = record('Circle', CircleSchema)
|
|
239
|
+
* const Square = record('Square', SquareSchema)
|
|
240
|
+
* const Shape = data('Shape', { Circle, Square })
|
|
241
|
+
*
|
|
242
|
+
* // From raw schemas (JSON codec is automatically included)
|
|
243
|
+
* const Shape = data('Shape', {
|
|
244
|
+
* Circle: CircleSchema,
|
|
245
|
+
* Square: SquareSchema
|
|
246
|
+
* })
|
|
247
|
+
*
|
|
248
|
+
* // JSON codec works on all variants
|
|
249
|
+
* Shape.Circle.to.json({ radius: 10 })
|
|
250
|
+
* Shape.Circle.from.json(jsonString)
|
|
251
|
+
*
|
|
252
|
+
* // Mixed
|
|
253
|
+
* const Shape = data('Shape', {
|
|
254
|
+
* Circle, // Pre-built record
|
|
255
|
+
* Square: SquareSchema // Raw schema
|
|
256
|
+
* })
|
|
257
|
+
*
|
|
258
|
+
* // Usage
|
|
259
|
+
* Shape.Circle({ radius: 10 })
|
|
260
|
+
* Shape.is(someValue) // type guard for any variant
|
|
261
|
+
* Shape.Circle.is(someValue) // type guard for Circle
|
|
262
|
+
* ```
|
|
263
|
+
*/
|
|
264
|
+
function data(name, records) {
|
|
265
|
+
const typenames = Object.keys(records);
|
|
266
|
+
const variants = {};
|
|
267
|
+
for (const [__typename, def] of Object.entries(records)) if (isRecord(def)) if (def.__typename === __typename) variants[__typename] = def;
|
|
268
|
+
else if (def.codecs) variants[__typename] = record(__typename, def.schema, def.codecs);
|
|
269
|
+
else variants[__typename] = record(__typename, def.schema);
|
|
270
|
+
else variants[__typename] = record(__typename, def);
|
|
271
|
+
return {
|
|
272
|
+
_name: name,
|
|
273
|
+
is: createIsAnyGuard(typenames),
|
|
274
|
+
equals: createADTEqualsMethod(typenames),
|
|
275
|
+
hash: createADTHashMethod(typenames),
|
|
276
|
+
...variants
|
|
277
|
+
};
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
//#endregion
|
|
281
|
+
//#region src/adt/adt.match.ts
|
|
282
|
+
/**
|
|
283
|
+
* Exhaustive pattern matching for discriminated unions.
|
|
284
|
+
*
|
|
285
|
+
* TypeScript will error if any variant is missing from handlers,
|
|
286
|
+
* ensuring exhaustive handling of all cases.
|
|
287
|
+
*
|
|
288
|
+
* @template T - The discriminated union type (must have readonly __typename)
|
|
289
|
+
* @template TResult - The return type of all handlers
|
|
290
|
+
* @template Handlers - The handler object type (inferred)
|
|
291
|
+
* @param value - A discriminated union value with __typename
|
|
292
|
+
* @param handlers - An object with a handler function for each variant
|
|
293
|
+
* @returns The result of calling the matching handler
|
|
294
|
+
*
|
|
295
|
+
* @see {@link data} for creating discriminated unions
|
|
296
|
+
* @see {@link record} for creating individual record types
|
|
297
|
+
*
|
|
298
|
+
* @example
|
|
299
|
+
* ```ts
|
|
300
|
+
* const Shape = data('Shape', { Circle, Square })
|
|
301
|
+
* type Shape = Infer<typeof Shape>
|
|
302
|
+
*
|
|
303
|
+
* function describeShape(shape: Shape): string {
|
|
304
|
+
* return match(shape, {
|
|
305
|
+
* Circle: (c) => `Circle with radius ${c.radius}`,
|
|
306
|
+
* Square: (s) => `Square with size ${s.size}`,
|
|
307
|
+
* })
|
|
308
|
+
* }
|
|
309
|
+
* ```
|
|
310
|
+
*/
|
|
311
|
+
function match(value, handlers) {
|
|
312
|
+
const handler = handlers[value.__typename];
|
|
313
|
+
return handler(value);
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
//#endregion
|
|
317
|
+
export { createCodecError as i, data as n, record as r, match as t };
|
|
318
|
+
//# sourceMappingURL=adt-DraJkmij.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adt-DraJkmij.mjs","names":["data"],"sources":["../src/shared/is-plain-object.ts","../src/adt/adt.utils.ts","../src/adt/adt.codec.ts","../src/adt/adt.record.ts","../src/adt/adt.data.ts","../src/adt/adt.match.ts"],"sourcesContent":["/**\n * Check if a value is a plain object.\n * A plain object is an object created with `{}`, `Object.create(null)`, or `new Object()`.\n * Arrays, functions, dates, maps, etc. are not considered plain objects.\n */\nexport function isPlainObject(value: unknown): value is Record<PropertyKey, unknown> {\n if (value === null || typeof value !== \"object\") {\n return false\n }\n\n const proto = Object.getPrototypeOf(value)\n return proto === null || proto === Object.prototype\n}\n","import { ok, err } from \"../result/result\"\nimport type { Result } from \"../result/result.types\"\nimport { isPlainObject } from \"../shared/is-plain-object\"\nimport { isPromise } from \"../shared/is-promise\"\nimport type { RecordObject, ValidationError } from \"./adt.types\"\nimport type { StandardSchemaV1 } from \"@standard-schema/spec\"\n\n/**\n * Check if a value is a RecordObject created by record().\n * RecordObjects are callable functions with static properties.\n */\nexport function isRecord(value: unknown): value is RecordObject {\n return typeof value === \"function\" && \"_record\" in value && value[\"_record\"] === true\n}\n\n/**\n * Wrap Standard Schema validation result into our Result type.\n */\nfunction wrapValidationResult<T>(result: StandardSchemaV1.Result<T>): Result<T, ValidationError> {\n if (result.issues) {\n return err({\n issues: result.issues.map((issue) => ({\n message: issue.message,\n path: issue.path?.map((segment) => (typeof segment === \"object\" && \"key\" in segment ? segment.key : segment)),\n })),\n })\n }\n return ok(result.value)\n}\n\n/**\n * Validate data using a Standard Schema, enforcing sync-only validation.\n * Throws if the schema returns a Promise.\n */\nexport function validateSync<T>(\n schema: StandardSchemaV1<unknown, T>,\n data: unknown,\n __typename: string,\n): Result<T, ValidationError> {\n const result = schema[\"~standard\"].validate(data)\n\n if (isPromise(result)) {\n throw new Error(\n `Async validation not supported. Schema for \"${__typename}\" returned a Promise. ` +\n `Use a synchronous schema or handle async validation separately.`,\n )\n }\n\n return wrapValidationResult(result)\n}\n\n/**\n * Create a type guard function for a specific __typename.\n */\nexport function createIsGuard<Typename extends string, T>(\n __typename: Typename,\n): (value: unknown) => value is T & { readonly __typename: Typename } {\n return (value: unknown): value is T & { readonly __typename: Typename } => {\n return isPlainObject(value) && \"__typename\" in value && value[\"__typename\"] === __typename\n }\n}\n\n/**\n * Create a type guard function for multiple __typenames (ADT root guard).\n */\nexport function createIsAnyGuard<T>(__typenames: readonly string[]): (value: unknown) => value is T {\n const __typenameSet = new Set(__typenames)\n return (value: unknown): value is T => {\n return (\n isPlainObject(value) &&\n \"__typename\" in value &&\n typeof value[\"__typename\"] === \"string\" &&\n __typenameSet.has(value[\"__typename\"])\n )\n }\n}\n","import { ok, err } from \"../result/result\"\nimport type { Result } from \"../result/result.types\"\nimport type { Discriminator } from \"../shared/discriminator.types\"\nimport type {\n CodecConstraint,\n CodecDef,\n CodecError,\n InferInput,\n InferOutput,\n ValidationError,\n ToMethods,\n FromMethods,\n} from \"./adt.types\"\nimport { validateSync } from \"./adt.utils\"\nimport type { StandardSchemaV1 } from \"@standard-schema/spec\"\n\n/**\n * Create a CodecError with consistent structure.\n */\nexport function createCodecError(\n kind: CodecError[\"kind\"],\n message: string,\n cause?: unknown,\n validationIssues?: ValidationError[\"issues\"],\n): CodecError {\n if (cause !== undefined && validationIssues !== undefined) {\n return { kind, message, cause, validationIssues }\n }\n if (cause !== undefined) {\n return { kind, message, cause }\n }\n if (validationIssues !== undefined) {\n return { kind, message, validationIssues }\n }\n return { kind, message }\n}\n\n/**\n * Built-in JSON codec that works with any schema.\n * Encodes to JSON string and decodes with JSON.parse.\n */\nexport function createJsonCodec<Typename extends string, S extends StandardSchemaV1>(\n __typename: Typename,\n): CodecDef<InferOutput<S> & Discriminator<Typename>, string, InferInput<S>> {\n return {\n to: (value) => {\n // JSON.stringify can throw for circular references, BigInt, etc.\n // We let it throw and catch it in the wrapper\n return JSON.stringify(value)\n },\n /* oxlint-disable no-unsafe-assignment, no-unsafe-type-assertion, no-unsafe-return -- Required for JSON parsing which returns unknown types */\n from: (input: string) => {\n try {\n const parsed = JSON.parse(input)\n // Return parsed object without __typename - it will be added during validation\n if (typeof parsed === \"object\" && parsed !== null && \"__typename\" in parsed) {\n const { __typename: _, ...rest } = parsed\n return rest as InferInput<S>\n }\n return parsed\n } catch {\n return null\n }\n },\n /* oxlint-enable no-unsafe-assignment, no-unsafe-type-assertion, no-unsafe-return */\n }\n}\n\n/**\n * Create the \"to\" methods object with JSON codec and custom codecs.\n * All methods return Result<T, CodecError> for consistent error handling.\n */\nexport function createToMethods<\n Typename extends string,\n S extends StandardSchemaV1,\n Codecs extends CodecConstraint<Typename, S> | undefined = undefined,\n>(__typename: Typename, schema: S, customCodecs?: Codecs): ToMethods<S, Codecs> {\n type Output = InferOutput<S> & Discriminator<Typename>\n\n const jsonCodec = createJsonCodec<Typename, S>(__typename)\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const to: Record<string, (value: InferInput<S>) => Result<any, CodecError>> = {\n json: (value: InferInput<S>): Result<string, CodecError> => {\n // First, create a validated record to ensure we're encoding valid data\n // oxlint-disable-next-line no-unsafe-type-assertion -- Required for spreading generic input into object\n const taggedInput = { ...(value as object), __typename }\n const result = validateSync(schema, taggedInput, __typename)\n\n if (!result.ok) {\n return err(\n createCodecError(\n \"ValidationError\",\n `Cannot encode invalid data: ${result.error.issues.map((i) => i.message).join(\", \")}`,\n undefined,\n result.error.issues,\n ),\n )\n }\n\n try {\n // oxlint-disable-next-line no-unsafe-type-assertion -- Required for validated value cast\n return ok(jsonCodec.to(result.value as Output))\n } catch (e) {\n return err(\n createCodecError(\"EncodingError\", `JSON encoding failed: ${e instanceof Error ? e.message : String(e)}`, e),\n )\n }\n },\n }\n\n // Add custom codecs\n if (customCodecs) {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n for (const [name, codec] of Object.entries(customCodecs) as Array<[string, CodecDef<Output, any, any>]>) {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n to[name] = (value: InferInput<S>): Result<any, CodecError> => {\n // Validate input first\n // oxlint-disable-next-line no-unsafe-type-assertion -- Required for spreading generic input\n const taggedInput = { ...(value as object), __typename }\n const result = validateSync(schema, taggedInput, __typename)\n\n if (!result.ok) {\n return err(\n createCodecError(\n \"ValidationError\",\n `Cannot encode invalid data: ${result.error.issues.map((i) => i.message).join(\", \")}`,\n undefined,\n result.error.issues,\n ),\n )\n }\n\n try {\n // oxlint-disable-next-line no-unsafe-type-assertion -- Required for validated value cast\n return ok(codec.to(result.value as Output))\n } catch (e) {\n return err(\n createCodecError(\n \"EncodingError\",\n `Encoding with codec '${name}' failed: ${e instanceof Error ? e.message : String(e)}`,\n e,\n ),\n )\n }\n }\n }\n }\n\n // oxlint-disable-next-line no-unsafe-type-assertion -- Required for generic return type\n return to as ToMethods<S, Codecs>\n}\n\n/**\n * Create the \"from\" methods object with JSON codec and custom codecs.\n * All methods return Result<T, CodecError> for consistent error handling.\n */\nexport function createFromMethods<\n Typename extends string,\n S extends StandardSchemaV1,\n Codecs extends CodecConstraint<Typename, S> | undefined = undefined,\n>(__typename: Typename, schema: S, customCodecs?: Codecs): FromMethods<Typename, S, Codecs> {\n type Output = InferOutput<S> & Discriminator<Typename>\n\n const jsonCodec = createJsonCodec<Typename, S>(__typename)\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const from: Record<string, (input: any) => Result<Output, CodecError>> = {\n json: (input: string): Result<Output, CodecError> => {\n // Decode\n const decoded = jsonCodec.from(input)\n if (decoded === null) {\n return err(createCodecError(\"DecodingError\", \"Invalid JSON format\"))\n }\n\n // Validate through schema\n // oxlint-disable-next-line no-unsafe-type-assertion -- Required for spreading decoded value\n const taggedInput = { ...(decoded as object), __typename }\n const result = validateSync(schema, taggedInput, __typename)\n\n if (!result.ok) {\n return err(\n createCodecError(\"ValidationError\", \"Decoded data failed schema validation\", undefined, result.error.issues),\n )\n }\n\n // Ensure __typename in output\n // oxlint-disable-next-line no-unsafe-type-assertion -- Required for output construction\n const output = { ...(result.value as object), __typename } as Output\n return ok(output)\n },\n }\n\n // Add custom codecs\n if (customCodecs) {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n for (const [name, codec] of Object.entries(customCodecs) as Array<[string, CodecDef<Output, any, any>]>) {\n from[name] = (input: unknown): Result<Output, CodecError> => {\n // Decode\n let decoded: unknown\n try {\n decoded = codec.from(input)\n } catch (e) {\n return err(createCodecError(\"DecodingError\", `Decoding with codec '${name}' threw an error`, e))\n }\n\n if (decoded === null) {\n return err(createCodecError(\"DecodingError\", `Codec '${name}' failed to decode input`))\n }\n\n // Validate through schema\n // oxlint-disable-next-line no-unsafe-type-assertion -- Required for spreading decoded value\n const taggedInput = { ...(decoded as object), __typename }\n const result = validateSync(schema, taggedInput, __typename)\n\n if (!result.ok) {\n return err(\n createCodecError(\n \"ValidationError\",\n \"Decoded data failed schema validation\",\n undefined,\n result.error.issues,\n ),\n )\n }\n\n // Ensure __typename in output\n // oxlint-disable-next-line no-unsafe-type-assertion -- Required for output construction\n const output = { ...(result.value as object), __typename } as Output\n return ok(output)\n }\n }\n }\n\n // oxlint-disable-next-line no-unsafe-type-assertion -- Required for generic return type\n return from as FromMethods<Typename, S, Codecs>\n}\n","import { createEqualsMethod, createHashMethod } from \"../equality/equality\"\nimport { ok, err } from \"../result/result\"\nimport type { Result } from \"../result/result.types\"\nimport type { Discriminator } from \"../shared/discriminator.types\"\nimport { createToMethods, createFromMethods } from \"./adt.codec\"\nimport type { CodecConstraint, InferInput, InferOutput, RecordObject, ValidationError } from \"./adt.types\"\nimport { createIsGuard, validateSync } from \"./adt.utils\"\nimport type { StandardSchemaV1 } from \"@standard-schema/spec\"\n\n/**\n * Create a standalone tagged record from a Standard Schema with optional codecs.\n *\n * Records can be used independently or composed into an ADT via data().\n * All defaults should be defined at the schema level (e.g., Zod's .default()).\n *\n * @template Typename - The string literal type for the __typename discriminator\n * @template S - The Standard Schema type for validation\n * @template Codecs - Optional codec definitions for custom serialization formats\n * @param __typename - The __typename discriminator value\n * @param schema - A Standard Schema compliant validator\n * @param codecs - Optional codec definitions for custom serialization formats\n * @returns A callable RecordObject with is(), to, and from methods\n *\n * @see {@link data} for composing records into discriminated unions\n * @see {@link tagged} for unvalidated tagged value constructors\n *\n * @example\n * ```ts\n * const CircleSchema = z.object({\n * radius: z.number().positive(),\n * color: z.string().default('blue')\n * })\n *\n * // Basic record with JSON codec (always included)\n * const Circle = record('Circle', CircleSchema)\n *\n * const result = Circle({ radius: 10 })\n * // { ok: true, value: { __typename: 'Circle', radius: 10, color: 'blue' } }\n *\n * Circle.is(someValue) // type guard\n *\n * const json = Circle.to.json({ radius: 10 }) // JSON string\n * const result2 = Circle.from.json(json) // Result<Circle, CodecError>\n *\n * // Record with custom codec\n * const Circle2 = record('Circle', CircleSchema, {\n * graphic: {\n * to: (circle) => `(${circle.radius})`,\n * from: (input: string) => {\n * const match = input.match(/^\\((\\d+)\\)$/)\n * return match ? { radius: parseInt(match[1]!) } : null\n * }\n * }\n * })\n *\n * const graphic = Circle2.to.graphic({ radius: 10 }) // \"(10)\"\n * const result3 = Circle2.from.graphic(\"(10)\") // Result<Circle, CodecError>\n * ```\n */\n// Overload: with codecs\nexport function record<\n Typename extends string,\n S extends StandardSchemaV1,\n Codecs extends CodecConstraint<Typename, S>,\n>(__typename: Typename, schema: S, codecs: Codecs): RecordObject<Typename, S, Codecs>\n\n// Overload: without codecs\nexport function record<Typename extends string, S extends StandardSchemaV1>(\n __typename: Typename,\n schema: S,\n): RecordObject<Typename, S>\n\n// Implementation\nexport function record<\n Typename extends string,\n S extends StandardSchemaV1,\n Codecs extends CodecConstraint<Typename, S> | undefined,\n>(__typename: Typename, schema: S, codecs?: Codecs): RecordObject<Typename, S, Codecs> {\n type Output = InferOutput<S> & Discriminator<Typename>\n\n const isGuard = createIsGuard<Typename, Output>(__typename)\n const to = createToMethods(__typename, schema, codecs)\n const from = createFromMethods(__typename, schema, codecs)\n const equals = createEqualsMethod<Typename, InferOutput<S>>(__typename)\n const hash = createHashMethod<Typename, InferOutput<S>>(__typename)\n\n // Constructor function\n const constructor = (input: InferInput<S>): Result<Output, ValidationError> => {\n // Add __typename to the input before validation\n // oxlint-disable-next-line no-unsafe-type-assertion -- Required for spreading generic input\n const taggedInput = { ...(input as object), __typename }\n\n // Validate using the schema\n const result = validateSync(schema, taggedInput, __typename)\n\n if (!result.ok) {\n return err(result.error)\n }\n\n // Ensure __typename is in the output (schema might strip unknown keys)\n // oxlint-disable-next-line no-unsafe-type-assertion -- Required for output construction\n const output = { ...(result.value as object), __typename } as Output\n return ok(output)\n }\n\n // Attach static properties to constructor function\n constructor._record = true as const\n constructor.__typename = __typename\n constructor.schema = schema\n if (codecs) {\n // oxlint-disable-next-line no-unsafe-type-assertion -- Conditional assignment of codecs\n ;(constructor as { codecs?: Codecs }).codecs = codecs\n }\n constructor.is = isGuard\n constructor.to = to\n constructor.from = from\n constructor.equals = equals\n constructor.hash = hash\n\n return constructor as RecordObject<Typename, S, Codecs>\n}\n","import { createADTEqualsMethod, createADTHashMethod } from \"../equality/equality\"\nimport { record } from \"./adt.record\"\nimport type { ADT, RecordDef, RecordObject } from \"./adt.types\"\nimport { createIsAnyGuard, isRecord } from \"./adt.utils\"\nimport type { StandardSchemaV1 } from \"@standard-schema/spec\"\n\n/**\n * Compose records or schemas into a discriminated union (ADT).\n *\n * Accepts either:\n * - Pre-built RecordObjects from record() (codecs are preserved)\n * - Raw Standard Schema validators (will be wrapped internally)\n *\n * When using pre-built records, the object key overrides the original __typename.\n *\n * @template R - Record of variant names to RecordObjects or StandardSchema validators\n * @param name - The name of this ADT (for identification)\n * @param records - An object mapping __typename names to RecordObjects or schemas\n * @returns An ADT object with accessors for each variant\n *\n * @see {@link record} for creating individual record types\n * @see {@link match} for exhaustive pattern matching on ADT values\n *\n * @example\n * ```ts\n * // From pre-built records\n * const Circle = record('Circle', CircleSchema)\n * const Square = record('Square', SquareSchema)\n * const Shape = data('Shape', { Circle, Square })\n *\n * // From raw schemas (JSON codec is automatically included)\n * const Shape = data('Shape', {\n * Circle: CircleSchema,\n * Square: SquareSchema\n * })\n *\n * // JSON codec works on all variants\n * Shape.Circle.to.json({ radius: 10 })\n * Shape.Circle.from.json(jsonString)\n *\n * // Mixed\n * const Shape = data('Shape', {\n * Circle, // Pre-built record\n * Square: SquareSchema // Raw schema\n * })\n *\n * // Usage\n * Shape.Circle({ radius: 10 })\n * Shape.is(someValue) // type guard for any variant\n * Shape.Circle.is(someValue) // type guard for Circle\n * ```\n */\nexport function data<R extends Record<string, RecordDef>>(name: string, records: R): ADT<R> {\n const typenames = Object.keys(records)\n const variants: Record<string, RecordObject> = {}\n\n for (const [__typename, def] of Object.entries(records)) {\n if (isRecord(def)) {\n // Pre-built RecordObject - key overrides original __typename\n if (def.__typename === __typename) {\n // __typename matches key, use as-is (preserves codecs)\n variants[__typename] = def\n // oxlint-disable-next-line strict-boolean-expressions -- codecs can be undefined\n } else if (def.codecs) {\n // __typename differs from key - create new record with key as __typename\n // Preserve codecs\n variants[__typename] = record(__typename, def.schema, def.codecs)\n } else {\n // __typename differs from key and no codecs\n variants[__typename] = record(__typename, def.schema)\n }\n } else {\n // Raw schema - wrap in record\n // Note: Even without custom codecs, this still gets JSON codec!\n // oxlint-disable-next-line no-unsafe-type-assertion -- def is a StandardSchemaV1 in this branch\n variants[__typename] = record(__typename, def as StandardSchemaV1)\n }\n }\n\n // Create the root type guard for any variant\n const isAnyVariant = createIsAnyGuard(typenames)\n const equals = createADTEqualsMethod(typenames)\n const hash = createADTHashMethod(typenames)\n\n // oxlint-disable-next-line no-unsafe-type-assertion -- Required for generic ADT return type\n return {\n _name: name,\n is: isAnyVariant,\n equals,\n hash,\n ...variants,\n } as ADT<R>\n}\n","/**\n * Handler functions for each variant in a discriminated union.\n * Each key maps to a function that receives the variant value and returns TResult.\n *\n * @template T - The discriminated union type (must have readonly __typename)\n * @template TResult - The return type of all handlers\n */\nexport type MatchHandlers<T extends { readonly __typename: string }, TResult> = {\n [K in T[\"__typename\"]]: (value: Extract<T, { readonly __typename: K }>) => TResult\n}\n\n/**\n * Exhaustive pattern matching for discriminated unions.\n *\n * TypeScript will error if any variant is missing from handlers,\n * ensuring exhaustive handling of all cases.\n *\n * @template T - The discriminated union type (must have readonly __typename)\n * @template TResult - The return type of all handlers\n * @template Handlers - The handler object type (inferred)\n * @param value - A discriminated union value with __typename\n * @param handlers - An object with a handler function for each variant\n * @returns The result of calling the matching handler\n *\n * @see {@link data} for creating discriminated unions\n * @see {@link record} for creating individual record types\n *\n * @example\n * ```ts\n * const Shape = data('Shape', { Circle, Square })\n * type Shape = Infer<typeof Shape>\n *\n * function describeShape(shape: Shape): string {\n * return match(shape, {\n * Circle: (c) => `Circle with radius ${c.radius}`,\n * Square: (s) => `Square with size ${s.size}`,\n * })\n * }\n * ```\n */\nexport function match<\n T extends { readonly __typename: string },\n TResult,\n Handlers extends MatchHandlers<T, TResult> = MatchHandlers<T, TResult>,\n>(value: T, handlers: Handlers): TResult {\n const typename = value.__typename as keyof Handlers\n const handler = handlers[typename]\n // oxlint-disable-next-line no-explicit-any, no-unsafe-argument, no-unsafe-type-assertion -- Required for variant dispatch\n return handler(value as any)\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
//#region src/shared/lambda.types.d.ts
|
|
2
|
+
type λ<TA extends any[] = any[], TR = any> = (...args: TA) => TR;
|
|
3
|
+
//#endregion
|
|
4
|
+
//#region src/shared/apply-fn.types.d.ts
|
|
5
|
+
type ApplyFn<F extends λ, Arg> = F extends ((arg: Arg) => infer R) ? R : F extends ((arg: any) => infer R) ? R : never;
|
|
6
|
+
//#endregion
|
|
7
|
+
export { λ as n, ApplyFn as t };
|
|
8
|
+
//# sourceMappingURL=apply-fn.types-CXDoeA7D.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"apply-fn.types-CXDoeA7D.d.mts","names":[],"sources":["../src/shared/lambda.types.ts","../src/shared/apply-fn.types.ts"],"sourcesContent":[],"mappings":";KACY,kDAAkD,OAAO;;;ACMzD,KAAA,OAAO,CAAA,UAAW,CAAX,EAAA,GAAA,CAAA,GAAqB,CAArB,UAAA,CAAA,GAAA,EAAqC,GAArC,EAAA,GAAA,KAAA,EAAA,IAAA,CAAA,GAEf,CAFe,UAAA,CAAA,GAAA,EAAA,GAAA,EAAA,GAAA,KAAA,EAAA,IAAA,CAAA,GAAA,KAAA"}
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import { t as Result } from "./result-C5tPWR60.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/brand/brand.ts
|
|
4
|
+
/**
|
|
5
|
+
* Create a branded value without validation.
|
|
6
|
+
* This is a type-level cast with zero runtime cost.
|
|
7
|
+
*
|
|
8
|
+
* Use this when you trust the value source (e.g., from a database)
|
|
9
|
+
* or when validation happens elsewhere.
|
|
10
|
+
*
|
|
11
|
+
* @template B - The branded type
|
|
12
|
+
* @param value - The value to brand
|
|
13
|
+
* @returns The value as a branded type
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```ts
|
|
17
|
+
* type UserId = Branded<string, "UserId">
|
|
18
|
+
*
|
|
19
|
+
* // Trust the value from database
|
|
20
|
+
* const userId = Brand.make<UserId>(row.id)
|
|
21
|
+
*
|
|
22
|
+
* // Or use in a validated factory
|
|
23
|
+
* function createUserId(input: string): UserId {
|
|
24
|
+
* if (!input.startsWith("user_")) throw new Error("Invalid")
|
|
25
|
+
* return Brand.make<UserId>(input)
|
|
26
|
+
* }
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
const make = (value) => {
|
|
30
|
+
return value;
|
|
31
|
+
};
|
|
32
|
+
/**
|
|
33
|
+
* Alias for make() - explicitly indicates no validation occurs.
|
|
34
|
+
* Prefer this when readability about the lack of validation is important.
|
|
35
|
+
*
|
|
36
|
+
* @template B - The branded type
|
|
37
|
+
* @param value - The value to brand (unchecked)
|
|
38
|
+
* @returns The value as a branded type
|
|
39
|
+
*
|
|
40
|
+
* @example
|
|
41
|
+
* ```ts
|
|
42
|
+
* type PositiveNumber = Branded<number, "PositiveNumber">
|
|
43
|
+
*
|
|
44
|
+
* // Explicitly unsafe - reader knows no validation
|
|
45
|
+
* const n = Brand.unsafeMake<PositiveNumber>(-5) // No error, but logically wrong
|
|
46
|
+
* ```
|
|
47
|
+
*/
|
|
48
|
+
const unsafeMake = (value) => {
|
|
49
|
+
return value;
|
|
50
|
+
};
|
|
51
|
+
/**
|
|
52
|
+
* Create a type guard with validation for a branded type.
|
|
53
|
+
* Returns a refinement predicate that narrows to the branded type.
|
|
54
|
+
*
|
|
55
|
+
* @template T - The base type
|
|
56
|
+
* @template K - The brand key (string literal)
|
|
57
|
+
* @param validator - A function that validates the base value
|
|
58
|
+
* @returns A type guard that returns true if validation passes
|
|
59
|
+
*
|
|
60
|
+
* @example
|
|
61
|
+
* ```ts
|
|
62
|
+
* type PositiveNumber = Branded<number, "PositiveNumber">
|
|
63
|
+
*
|
|
64
|
+
* const isPositive = Brand.is<number, "PositiveNumber">(n => n > 0)
|
|
65
|
+
*
|
|
66
|
+
* const value: number = 42
|
|
67
|
+
* if (isPositive(value)) {
|
|
68
|
+
* // value is now PositiveNumber
|
|
69
|
+
* acceptPositive(value) // OK
|
|
70
|
+
* }
|
|
71
|
+
* ```
|
|
72
|
+
*/
|
|
73
|
+
const is = (validator) => {
|
|
74
|
+
return (value) => validator(value);
|
|
75
|
+
};
|
|
76
|
+
/**
|
|
77
|
+
* Create a validated branded value wrapped in a Result.
|
|
78
|
+
* Returns `Result.ok(brandedValue)` on success, `Result.err(BrandError)` on failure.
|
|
79
|
+
*
|
|
80
|
+
* The returned Result is yieldable in Do computations via `yield*`.
|
|
81
|
+
*
|
|
82
|
+
* @template B - The branded type
|
|
83
|
+
* @param validator - A function that validates the base value
|
|
84
|
+
* @param errorMessage - Optional custom error message (or function)
|
|
85
|
+
* @returns A function that takes a value and returns a Result
|
|
86
|
+
*
|
|
87
|
+
* @example
|
|
88
|
+
* ```ts
|
|
89
|
+
* type Email = Branded<string, "Email">
|
|
90
|
+
*
|
|
91
|
+
* const parseEmail = Brand.refine<Email>(
|
|
92
|
+
* s => s.includes("@"),
|
|
93
|
+
* (v) => `Invalid email: ${v}`
|
|
94
|
+
* )
|
|
95
|
+
*
|
|
96
|
+
* // Basic usage
|
|
97
|
+
* const result = parseEmail("user@example.com")
|
|
98
|
+
* // { ok: true, value: "user@example.com" }
|
|
99
|
+
*
|
|
100
|
+
* const bad = parseEmail("not-an-email")
|
|
101
|
+
* // { ok: false, error: { __typename: "BrandError", value: "not-an-email", message: "..." } }
|
|
102
|
+
*
|
|
103
|
+
* // With Do computation
|
|
104
|
+
* const computation = gen(function* () {
|
|
105
|
+
* const email = yield* parseEmail(input)
|
|
106
|
+
* return email
|
|
107
|
+
* })
|
|
108
|
+
*
|
|
109
|
+
* // With pipe
|
|
110
|
+
* pipe(
|
|
111
|
+
* userInput,
|
|
112
|
+
* parseEmail,
|
|
113
|
+
* Result.map(email => sendTo(email)),
|
|
114
|
+
* Result.unwrapOr(defaultEmail)
|
|
115
|
+
* )
|
|
116
|
+
* ```
|
|
117
|
+
*/
|
|
118
|
+
const refine = (validator, errorMessage) => {
|
|
119
|
+
return (value) => {
|
|
120
|
+
if (!validator(value)) {
|
|
121
|
+
const msg = typeof errorMessage === "function" ? errorMessage(value) : errorMessage ?? "Brand validation failed";
|
|
122
|
+
return Result.err({
|
|
123
|
+
__typename: "BrandError",
|
|
124
|
+
value,
|
|
125
|
+
message: msg
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
return Result.ok(value);
|
|
129
|
+
};
|
|
130
|
+
};
|
|
131
|
+
/**
|
|
132
|
+
* Brand namespace containing utilities for nominal typing in TypeScript.
|
|
133
|
+
*
|
|
134
|
+
* Brand types add type-level distinctiveness to primitive types without
|
|
135
|
+
* any runtime overhead. This prevents accidental mixing of semantically
|
|
136
|
+
* different values that share the same structural type.
|
|
137
|
+
*
|
|
138
|
+
* @example
|
|
139
|
+
* ```ts
|
|
140
|
+
* import { Brand } from "@repo/std"
|
|
141
|
+
* import type { Branded } from "@repo/std"
|
|
142
|
+
*
|
|
143
|
+
* // Define branded types
|
|
144
|
+
* type UserId = Branded<string, "UserId">
|
|
145
|
+
* type Email = Branded<string, "Email">
|
|
146
|
+
*
|
|
147
|
+
* // Create values
|
|
148
|
+
* const userId = Brand.make<UserId>("user-123")
|
|
149
|
+
* const isValidEmail = Brand.is<Email>(s => s.includes("@"))
|
|
150
|
+
*
|
|
151
|
+
* // Type safety
|
|
152
|
+
* function sendEmail(email: Email) { ... }
|
|
153
|
+
* sendEmail(userId) // Type error! UserId is not Email
|
|
154
|
+
* ```
|
|
155
|
+
*/
|
|
156
|
+
const Brand = {
|
|
157
|
+
make,
|
|
158
|
+
unsafeMake,
|
|
159
|
+
is,
|
|
160
|
+
refine
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
//#endregion
|
|
164
|
+
export { Brand as t };
|
|
165
|
+
//# sourceMappingURL=brand-CTaxGuU9.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"brand-CTaxGuU9.mjs","names":[],"sources":["../src/brand/brand.ts"],"sourcesContent":["import { Result } from \"../result\"\nimport type { Result as ResultType } from \"../result/result.types\"\nimport type { BrandError, Branded, Unbrand, Validator } from \"./brand.types\"\n\n/**\n * Create a branded value without validation.\n * This is a type-level cast with zero runtime cost.\n *\n * Use this when you trust the value source (e.g., from a database)\n * or when validation happens elsewhere.\n *\n * @template B - The branded type\n * @param value - The value to brand\n * @returns The value as a branded type\n *\n * @example\n * ```ts\n * type UserId = Branded<string, \"UserId\">\n *\n * // Trust the value from database\n * const userId = Brand.make<UserId>(row.id)\n *\n * // Or use in a validated factory\n * function createUserId(input: string): UserId {\n * if (!input.startsWith(\"user_\")) throw new Error(\"Invalid\")\n * return Brand.make<UserId>(input)\n * }\n * ```\n */\nexport const make = <B extends Branded<unknown, string>>(value: Unbrand<B>): B => {\n return value as B\n}\n\n/**\n * Alias for make() - explicitly indicates no validation occurs.\n * Prefer this when readability about the lack of validation is important.\n *\n * @template B - The branded type\n * @param value - The value to brand (unchecked)\n * @returns The value as a branded type\n *\n * @example\n * ```ts\n * type PositiveNumber = Branded<number, \"PositiveNumber\">\n *\n * // Explicitly unsafe - reader knows no validation\n * const n = Brand.unsafeMake<PositiveNumber>(-5) // No error, but logically wrong\n * ```\n */\nexport const unsafeMake = <B extends Branded<unknown, string>>(value: Unbrand<B>): B => {\n return value as B\n}\n\n/**\n * Create a type guard with validation for a branded type.\n * Returns a refinement predicate that narrows to the branded type.\n *\n * @template T - The base type\n * @template K - The brand key (string literal)\n * @param validator - A function that validates the base value\n * @returns A type guard that returns true if validation passes\n *\n * @example\n * ```ts\n * type PositiveNumber = Branded<number, \"PositiveNumber\">\n *\n * const isPositive = Brand.is<number, \"PositiveNumber\">(n => n > 0)\n *\n * const value: number = 42\n * if (isPositive(value)) {\n * // value is now PositiveNumber\n * acceptPositive(value) // OK\n * }\n * ```\n */\nexport const is = <T, K extends string>(validator: Validator<T>): ((value: T) => value is Branded<T, K>) => {\n return (value: T): value is Branded<T, K> => validator(value)\n}\n\n/**\n * Create a validated branded value wrapped in a Result.\n * Returns `Result.ok(brandedValue)` on success, `Result.err(BrandError)` on failure.\n *\n * The returned Result is yieldable in Do computations via `yield*`.\n *\n * @template B - The branded type\n * @param validator - A function that validates the base value\n * @param errorMessage - Optional custom error message (or function)\n * @returns A function that takes a value and returns a Result\n *\n * @example\n * ```ts\n * type Email = Branded<string, \"Email\">\n *\n * const parseEmail = Brand.refine<Email>(\n * s => s.includes(\"@\"),\n * (v) => `Invalid email: ${v}`\n * )\n *\n * // Basic usage\n * const result = parseEmail(\"user@example.com\")\n * // { ok: true, value: \"user@example.com\" }\n *\n * const bad = parseEmail(\"not-an-email\")\n * // { ok: false, error: { __typename: \"BrandError\", value: \"not-an-email\", message: \"...\" } }\n *\n * // With Do computation\n * const computation = gen(function* () {\n * const email = yield* parseEmail(input)\n * return email\n * })\n *\n * // With pipe\n * pipe(\n * userInput,\n * parseEmail,\n * Result.map(email => sendTo(email)),\n * Result.unwrapOr(defaultEmail)\n * )\n * ```\n */\nexport const refine = <B extends Branded<unknown, string>>(\n validator: Validator<Unbrand<B>>,\n errorMessage?: string | ((value: Unbrand<B>) => string),\n): ((value: Unbrand<B>) => ResultType<B, BrandError<Unbrand<B>>>) => {\n return (value: Unbrand<B>) => {\n if (!validator(value)) {\n const msg = typeof errorMessage === \"function\" ? errorMessage(value) : (errorMessage ?? \"Brand validation failed\")\n return Result.err({ __typename: \"BrandError\" as const, value, message: msg })\n }\n return Result.ok(value as B)\n }\n}\n\n/**\n * Brand namespace containing utilities for nominal typing in TypeScript.\n *\n * Brand types add type-level distinctiveness to primitive types without\n * any runtime overhead. This prevents accidental mixing of semantically\n * different values that share the same structural type.\n *\n * @example\n * ```ts\n * import { Brand } from \"@repo/std\"\n * import type { Branded } from \"@repo/std\"\n *\n * // Define branded types\n * type UserId = Branded<string, \"UserId\">\n * type Email = Branded<string, \"Email\">\n *\n * // Create values\n * const userId = Brand.make<UserId>(\"user-123\")\n * const isValidEmail = Brand.is<Email>(s => s.includes(\"@\"))\n *\n * // Type safety\n * function sendEmail(email: Email) { ... }\n * sendEmail(userId) // Type error! UserId is not Email\n * ```\n */\nexport const Brand = {\n make,\n unsafeMake,\n is,\n refine,\n} as const\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6BA,MAAa,QAA4C,UAAyB;AAChF,QAAO;;;;;;;;;;;;;;;;;;AAmBT,MAAa,cAAkD,UAAyB;AACtF,QAAO;;;;;;;;;;;;;;;;;;;;;;;;AAyBT,MAAa,MAA2B,cAAoE;AAC1G,SAAQ,UAAqC,UAAU,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6C/D,MAAa,UACX,WACA,iBACmE;AACnE,SAAQ,UAAsB;AAC5B,MAAI,CAAC,UAAU,MAAM,EAAE;GACrB,MAAM,MAAM,OAAO,iBAAiB,aAAa,aAAa,MAAM,GAAI,gBAAgB;AACxF,UAAO,OAAO,IAAI;IAAE,YAAY;IAAuB;IAAO,SAAS;IAAK,CAAC;;AAE/E,SAAO,OAAO,GAAG,MAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6BhC,MAAa,QAAQ;CACnB;CACA;CACA;CACA;CACD"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { a as ArrayValue, c as TaggedValue, i as tagged, l as TupleValue, n as tuple, o as StructValue, r as struct, s as TaggedConstructor, t as array } from "../index-BCrD3pEs.mjs";
|
|
2
|
+
export { ArrayValue, StructValue, TaggedConstructor, TaggedValue, TupleValue, array, struct, tagged, tuple };
|