wellcrafted 0.29.1 → 0.31.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 +26 -2
- package/dist/brand.d.ts +64 -5
- package/dist/brand.d.ts.map +1 -1
- package/dist/error/index.d.ts +72 -241
- package/dist/error/index.d.ts.map +1 -1
- package/dist/error/index.js +38 -91
- package/dist/error/index.js.map +1 -1
- package/dist/query/index.js +2 -2
- package/dist/result/index.js +2 -2
- package/dist/{result-DfuKgZo9.js → result-0QjbC3Hw.js} +2 -2
- package/dist/{result-DfuKgZo9.js.map → result-0QjbC3Hw.js.map} +1 -1
- package/dist/{result-B1iWFqM9.js → result-DnOm5ds5.js} +1 -3
- package/dist/result-DnOm5ds5.js.map +1 -0
- package/dist/result-DolxQXIZ.d.ts.map +1 -1
- package/dist/standard-schema/index.d.ts +371 -0
- package/dist/standard-schema/index.d.ts.map +1 -0
- package/dist/standard-schema/index.js +344 -0
- package/dist/standard-schema/index.js.map +1 -0
- package/package.json +13 -5
- package/dist/result-B1iWFqM9.js.map +0 -1
package/dist/error/index.js
CHANGED
|
@@ -1,40 +1,11 @@
|
|
|
1
|
-
import { Err } from "../result-
|
|
1
|
+
import { Err } from "../result-DnOm5ds5.js";
|
|
2
2
|
|
|
3
3
|
//#region src/error/utils.ts
|
|
4
4
|
/**
|
|
5
5
|
* Extracts a readable error message from an unknown error value
|
|
6
6
|
*
|
|
7
|
-
* This utility is commonly used in mapErr functions when converting
|
|
8
|
-
* unknown errors to typed error objects in the Result system.
|
|
9
|
-
*
|
|
10
7
|
* @param error - The unknown error to extract a message from
|
|
11
8
|
* @returns A string representation of the error
|
|
12
|
-
*
|
|
13
|
-
* @example
|
|
14
|
-
* ```ts
|
|
15
|
-
* // With native Error
|
|
16
|
-
* const error = new Error("Something went wrong");
|
|
17
|
-
* const message = extractErrorMessage(error); // "Something went wrong"
|
|
18
|
-
*
|
|
19
|
-
* // With string error
|
|
20
|
-
* const stringError = "String error";
|
|
21
|
-
* const message2 = extractErrorMessage(stringError); // "String error"
|
|
22
|
-
*
|
|
23
|
-
* // With object error
|
|
24
|
-
* const unknownError = { code: 500, details: "Server error" };
|
|
25
|
-
* const message3 = extractErrorMessage(unknownError); // '{"code":500,"details":"Server error"}'
|
|
26
|
-
*
|
|
27
|
-
* // Used in mapErr function
|
|
28
|
-
* const result = await tryAsync({
|
|
29
|
-
* try: () => riskyOperation(),
|
|
30
|
-
* mapErr: (error) => Err({
|
|
31
|
-
* name: "NetworkError",
|
|
32
|
-
* message: extractErrorMessage(error),
|
|
33
|
-
* context: { operation: "riskyOperation" },
|
|
34
|
-
* cause: error,
|
|
35
|
-
* }),
|
|
36
|
-
* });
|
|
37
|
-
* ```
|
|
38
9
|
*/
|
|
39
10
|
function extractErrorMessage(error) {
|
|
40
11
|
if (error instanceof Error) return error.message;
|
|
@@ -66,85 +37,61 @@ function extractErrorMessage(error) {
|
|
|
66
37
|
/**
|
|
67
38
|
* Creates a new tagged error type with a fluent builder API.
|
|
68
39
|
*
|
|
69
|
-
*
|
|
70
|
-
*
|
|
71
|
-
* - `{Name}Err`: Factory function that creates Err-wrapped TaggedError objects
|
|
72
|
-
* - `withContext<T>()`: Chain method to add context type
|
|
73
|
-
* - `withCause<T>()`: Chain method to add cause type
|
|
74
|
-
*
|
|
75
|
-
* **Explicit Opt-In (Rust-inspired):**
|
|
76
|
-
* By default, errors only have `{ name, message }`. Context and cause must be
|
|
77
|
-
* explicitly added via `.withContext<T>()` and `.withCause<T>()`. This follows
|
|
78
|
-
* Rust's thiserror pattern where error properties are intentional decisions.
|
|
79
|
-
*
|
|
80
|
-
* **Optionality via type unions:**
|
|
81
|
-
* Both `withContext` and `withCause` determine optionality based on whether
|
|
82
|
-
* the type includes `undefined`:
|
|
83
|
-
* - `T` without undefined → property is required
|
|
84
|
-
* - `T | undefined` → property is optional but typed when provided
|
|
40
|
+
* The builder provides `.withContext<T>()`, `.withCause<T>()`, and `.withMessage(fn)`.
|
|
41
|
+
* `.withMessage(fn)` is **required** and **terminal** — it returns the factory functions.
|
|
85
42
|
*
|
|
86
|
-
* @
|
|
87
|
-
* @param name - The name of the error type
|
|
88
|
-
*
|
|
89
|
-
* @example Minimal error (no context, no cause)
|
|
43
|
+
* @example Simple error
|
|
90
44
|
* ```ts
|
|
91
|
-
* const {
|
|
92
|
-
*
|
|
93
|
-
* NetworkError({ message: 'Connection failed' })
|
|
94
|
-
* // Error only has { name: 'NetworkError', message: 'Connection failed' }
|
|
45
|
+
* const { RecorderBusyError, RecorderBusyErr } = createTaggedError('RecorderBusyError')
|
|
46
|
+
* .withMessage(() => 'A recording is already in progress');
|
|
95
47
|
* ```
|
|
96
48
|
*
|
|
97
|
-
* @example
|
|
49
|
+
* @example Error with context
|
|
98
50
|
* ```ts
|
|
99
|
-
* const {
|
|
100
|
-
* .withContext<{
|
|
101
|
-
*
|
|
102
|
-
* ApiError({ message: 'Failed', context: { endpoint: '/users', status: 500 } })
|
|
103
|
-
* // ApiError({ message: 'Failed' }) // Type error: context required
|
|
104
|
-
* ```
|
|
105
|
-
*
|
|
106
|
-
* @example Optional typed cause
|
|
107
|
-
* ```ts
|
|
108
|
-
* const { ServiceError } = createTaggedError('ServiceError')
|
|
109
|
-
* .withCause<DbError | CacheError | undefined>()
|
|
110
|
-
*
|
|
111
|
-
* ServiceError({ message: 'Failed' }) // OK
|
|
112
|
-
* ServiceError({ message: 'Failed', cause: dbError }) // OK, typed
|
|
51
|
+
* const { DbNotFoundError, DbNotFoundErr } = createTaggedError('DbNotFoundError')
|
|
52
|
+
* .withContext<{ table: string; id: string }>()
|
|
53
|
+
* .withMessage(({ context }) => `${context.table} '${context.id}' not found`);
|
|
113
54
|
* ```
|
|
114
55
|
*
|
|
115
|
-
* @example
|
|
56
|
+
* @example Error with context and cause
|
|
116
57
|
* ```ts
|
|
117
|
-
* const {
|
|
118
|
-
* .withContext<{
|
|
119
|
-
* .withCause<
|
|
120
|
-
*
|
|
121
|
-
*
|
|
122
|
-
*
|
|
123
|
-
* ```
|
|
124
|
-
*
|
|
125
|
-
* @example Permissive mode (if you want the old behavior)
|
|
126
|
-
* ```ts
|
|
127
|
-
* const { FlexibleError } = createTaggedError('FlexibleError')
|
|
128
|
-
* .withContext<Record<string, unknown> | undefined>()
|
|
129
|
-
* .withCause<AnyTaggedError | undefined>()
|
|
58
|
+
* const { ServiceError, ServiceErr } = createTaggedError('ServiceError')
|
|
59
|
+
* .withContext<{ operation: string }>()
|
|
60
|
+
* .withCause<DbServiceError>()
|
|
61
|
+
* .withMessage(({ context, cause }) =>
|
|
62
|
+
* `Operation '${context.operation}' failed: ${cause.message}`
|
|
63
|
+
* );
|
|
130
64
|
* ```
|
|
131
65
|
*/
|
|
132
66
|
function createTaggedError(name) {
|
|
133
67
|
const createBuilder = () => {
|
|
134
|
-
const errorConstructor = (input) => ({
|
|
135
|
-
name,
|
|
136
|
-
...input
|
|
137
|
-
});
|
|
138
|
-
const errName = name.replace(/Error$/, "Err");
|
|
139
|
-
const errConstructor = (input) => Err(errorConstructor(input));
|
|
140
68
|
return {
|
|
141
|
-
[name]: errorConstructor,
|
|
142
|
-
[errName]: errConstructor,
|
|
143
69
|
withContext() {
|
|
144
70
|
return createBuilder();
|
|
145
71
|
},
|
|
146
72
|
withCause() {
|
|
147
73
|
return createBuilder();
|
|
74
|
+
},
|
|
75
|
+
withMessage(fn) {
|
|
76
|
+
const errorConstructor = (input) => {
|
|
77
|
+
const messageInput = {
|
|
78
|
+
name,
|
|
79
|
+
..."context" in input ? { context: input.context } : {},
|
|
80
|
+
..."cause" in input ? { cause: input.cause } : {}
|
|
81
|
+
};
|
|
82
|
+
return {
|
|
83
|
+
name,
|
|
84
|
+
message: input.message ?? fn(messageInput),
|
|
85
|
+
..."context" in input ? { context: input.context } : {},
|
|
86
|
+
..."cause" in input ? { cause: input.cause } : {}
|
|
87
|
+
};
|
|
88
|
+
};
|
|
89
|
+
const errName = name.replace(/Error$/, "Err");
|
|
90
|
+
const errConstructor = (input) => Err(errorConstructor(input));
|
|
91
|
+
return {
|
|
92
|
+
[name]: errorConstructor,
|
|
93
|
+
[errName]: errConstructor
|
|
94
|
+
};
|
|
148
95
|
}
|
|
149
96
|
};
|
|
150
97
|
};
|
package/dist/error/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["error: unknown","name: TName","input: ErrorInput<TContext, TCause>"],"sources":["../../src/error/utils.ts"],"sourcesContent":["import type { TaggedError, AnyTaggedError } from \"./types.js\";\nimport { Err } from \"../result/result.js\";\n\n/**\n * Extracts a readable error message from an unknown error value\n *\n * This utility is commonly used in mapErr functions when converting\n * unknown errors to typed error objects in the Result system.\n *\n * @param error - The unknown error to extract a message from\n * @returns A string representation of the error\n *\n * @example\n * ```ts\n * // With native Error\n * const error = new Error(\"Something went wrong\");\n * const message = extractErrorMessage(error); // \"Something went wrong\"\n *\n * // With string error\n * const stringError = \"String error\";\n * const message2 = extractErrorMessage(stringError); // \"String error\"\n *\n * // With object error\n * const unknownError = { code: 500, details: \"Server error\" };\n * const message3 = extractErrorMessage(unknownError); // '{\"code\":500,\"details\":\"Server error\"}'\n *\n * // Used in mapErr function\n * const result = await tryAsync({\n * try: () => riskyOperation(),\n * mapErr: (error) => Err({\n * name: \"NetworkError\",\n * message: extractErrorMessage(error),\n * context: { operation: \"riskyOperation\" },\n * cause: error,\n * }),\n * });\n * ```\n */\nexport function extractErrorMessage(error: unknown): string {\n\t// Handle Error instances\n\tif (error instanceof Error) {\n\t\treturn error.message;\n\t}\n\n\t// Handle primitives\n\tif (typeof error === \"string\") return error;\n\tif (\n\t\ttypeof error === \"number\" ||\n\t\ttypeof error === \"boolean\" ||\n\t\ttypeof error === \"bigint\"\n\t)\n\t\treturn String(error);\n\tif (typeof error === \"symbol\") return error.toString();\n\tif (error === null) return \"null\";\n\tif (error === undefined) return \"undefined\";\n\n\t// Handle arrays\n\tif (Array.isArray(error)) return JSON.stringify(error);\n\n\t// Handle plain objects\n\tif (typeof error === \"object\") {\n\t\tconst errorObj = error as Record<string, unknown>;\n\n\t\t// Check common error properties\n\t\tconst messageProps = [\n\t\t\t\"message\",\n\t\t\t\"error\",\n\t\t\t\"description\",\n\t\t\t\"title\",\n\t\t\t\"reason\",\n\t\t\t\"details\",\n\t\t] as const;\n\t\tfor (const prop of messageProps) {\n\t\t\tif (prop in errorObj && typeof errorObj[prop] === \"string\") {\n\t\t\t\treturn errorObj[prop];\n\t\t\t}\n\t\t}\n\n\t\t// Fallback to JSON stringification\n\t\ttry {\n\t\t\treturn JSON.stringify(error);\n\t\t} catch {\n\t\t\treturn String(error);\n\t\t}\n\t}\n\n\t// Final fallback\n\treturn String(error);\n}\n\n/**\n * Replaces the \"Error\" suffix with \"Err\" suffix in error type names.\n *\n * @template T - An error type name that must end with \"Error\"\n * @returns The type name with \"Error\" replaced by \"Err\"\n *\n * @example\n * ```ts\n * type NetworkErr = ReplaceErrorWithErr<\"NetworkError\">; // \"NetworkErr\"\n * type ValidationErr = ReplaceErrorWithErr<\"ValidationError\">; // \"ValidationErr\"\n * ```\n */\ntype ReplaceErrorWithErr<T extends `${string}Error`> =\n\tT extends `${infer TBase}Error` ? `${TBase}Err` : never;\n\n// =============================================================================\n// Fluent API Types\n// =============================================================================\n\n/**\n * Helper type that determines optionality based on whether T includes undefined.\n * - If T includes undefined → property is optional\n * - If T does not include undefined → property is required\n */\ntype OptionalIfUndefined<T, TKey extends string> = undefined extends T\n\t? { [K in TKey]?: Exclude<T, undefined> }\n\t: { [K in TKey]: T };\n\n/**\n * Input type for error constructors with fluent API context/cause handling.\n *\n * Follows explicit opt-in philosophy:\n * - When TContext/TCause is undefined: property doesn't exist\n * - When TContext/TCause includes undefined: property is optional but typed\n * - When TContext/TCause is a specific type: property is required\n */\ntype ErrorInput<\n\tTContext extends Record<string, unknown> | undefined,\n\tTCause extends AnyTaggedError | undefined,\n> = { message: string } & (TContext extends undefined\n\t? {}\n\t: OptionalIfUndefined<TContext, \"context\">) &\n\t(TCause extends undefined\n\t\t? {}\n\t\t: OptionalIfUndefined<TCause, \"cause\">);\n\n/**\n * The factories object returned by createTaggedError and its builder methods.\n */\ntype ErrorFactories<\n\tTName extends `${string}Error`,\n\tTContext extends Record<string, unknown> | undefined,\n\tTCause extends AnyTaggedError | undefined,\n> = {\n\t[K in TName]: (\n\t\tinput: ErrorInput<TContext, TCause>,\n\t) => TaggedError<TName, TContext, TCause>;\n} & {\n\t[K in ReplaceErrorWithErr<TName>]: (\n\t\tinput: ErrorInput<TContext, TCause>,\n\t) => Err<TaggedError<TName, TContext, TCause>>;\n};\n\n/**\n * Builder interface for the fluent createTaggedError API.\n * Provides chaining methods and the error factories.\n */\ntype ErrorBuilder<\n\tTName extends `${string}Error`,\n\tTContext extends Record<string, unknown> | undefined = undefined,\n\tTCause extends AnyTaggedError | undefined = undefined,\n> = ErrorFactories<TName, TContext, TCause> & {\n\t/**\n\t * Constrains the context type for this error.\n\t *\n\t * Optionality is determined by whether the type includes `undefined`:\n\t * - `withContext<T>()` where T doesn't include undefined → context is **required**\n\t * - `withContext<T | undefined>()` → context is **optional** but typed when provided\n\t *\n\t * @typeParam T - The shape of the context object. Include `| undefined` to make optional.\n\t *\n\t * @example Required context\n\t * ```ts\n\t * const { FileError } = createTaggedError('FileError')\n\t * .withContext<{ path: string }>()\n\t *\n\t * FileError({ message: 'Not found', context: { path: '/etc/config' } }) // OK\n\t * FileError({ message: 'Not found' }) // Type error: context required\n\t * ```\n\t *\n\t * @example Optional but typed context\n\t * ```ts\n\t * const { LogError } = createTaggedError('LogError')\n\t * .withContext<{ file: string; line: number } | undefined>()\n\t *\n\t * LogError({ message: 'Parse error' }) // OK\n\t * LogError({ message: 'Parse error', context: { file: 'app.ts', line: 42 } }) // OK\n\t * ```\n\t *\n\t * @example Default (no generic): permissive optional context\n\t * ```ts\n\t * const { FlexError } = createTaggedError('FlexError')\n\t * .withContext() // Defaults to Record<string, unknown> | undefined\n\t *\n\t * FlexError({ message: 'Error' }) // OK - context is optional\n\t * FlexError({ message: 'Error', context: { anything: 'works' } }) // OK\n\t * ```\n\t */\n\twithContext<\n\t\tT extends Record<string, unknown> | undefined = Record<string, unknown> | undefined,\n\t>(): ErrorBuilder<TName, T, TCause>;\n\n\t/**\n\t * Constrains the cause type for this error.\n\t *\n\t * Optionality is determined by whether the type includes `undefined`:\n\t * - `withCause<T>()` where T doesn't include undefined → cause is **required**\n\t * - `withCause<T | undefined>()` → cause is **optional** but typed when provided\n\t *\n\t * Since cause is typically optional, include `| undefined` in most cases.\n\t *\n\t * @typeParam T - The allowed cause type(s). Include `| undefined` to make optional.\n\t *\n\t * @example Optional typed cause (common)\n\t * ```ts\n\t * const { ServiceError } = createTaggedError('ServiceError')\n\t * .withCause<DbError | CacheError | undefined>()\n\t *\n\t * ServiceError({ message: 'Failed' }) // OK\n\t * ServiceError({ message: 'Failed', cause: dbError }) // OK\n\t * ```\n\t *\n\t * @example Required cause (for wrapper errors)\n\t * ```ts\n\t * const { UnhandledError } = createTaggedError('UnhandledError')\n\t * .withCause<AnyTaggedError>()\n\t *\n\t * UnhandledError({ message: 'Unexpected', cause: originalError }) // OK\n\t * UnhandledError({ message: 'Unexpected' }) // Type error: cause required\n\t * ```\n\t *\n\t * @example Default (no generic): permissive optional cause\n\t * ```ts\n\t * const { FlexError } = createTaggedError('FlexError')\n\t * .withCause() // Defaults to AnyTaggedError | undefined\n\t *\n\t * FlexError({ message: 'Error' }) // OK - cause is optional\n\t * FlexError({ message: 'Error', cause: anyTaggedError }) // OK\n\t * ```\n\t */\n\twithCause<\n\t\tT extends AnyTaggedError | undefined = AnyTaggedError | undefined,\n\t>(): ErrorBuilder<TName, TContext, T>;\n};\n\n// =============================================================================\n// Fluent API Implementation\n// =============================================================================\n\n/**\n * Creates a new tagged error type with a fluent builder API.\n *\n * Returns an object containing:\n * - `{Name}Error`: Factory function that creates plain TaggedError objects\n * - `{Name}Err`: Factory function that creates Err-wrapped TaggedError objects\n * - `withContext<T>()`: Chain method to add context type\n * - `withCause<T>()`: Chain method to add cause type\n *\n * **Explicit Opt-In (Rust-inspired):**\n * By default, errors only have `{ name, message }`. Context and cause must be\n * explicitly added via `.withContext<T>()` and `.withCause<T>()`. This follows\n * Rust's thiserror pattern where error properties are intentional decisions.\n *\n * **Optionality via type unions:**\n * Both `withContext` and `withCause` determine optionality based on whether\n * the type includes `undefined`:\n * - `T` without undefined → property is required\n * - `T | undefined` → property is optional but typed when provided\n *\n * @template TName - The name of the error type (must end with \"Error\")\n * @param name - The name of the error type\n *\n * @example Minimal error (no context, no cause)\n * ```ts\n * const { NetworkError, NetworkErr } = createTaggedError('NetworkError')\n *\n * NetworkError({ message: 'Connection failed' })\n * // Error only has { name: 'NetworkError', message: 'Connection failed' }\n * ```\n *\n * @example Required context\n * ```ts\n * const { ApiError, ApiErr } = createTaggedError('ApiError')\n * .withContext<{ endpoint: string; status: number }>()\n *\n * ApiError({ message: 'Failed', context: { endpoint: '/users', status: 500 } })\n * // ApiError({ message: 'Failed' }) // Type error: context required\n * ```\n *\n * @example Optional typed cause\n * ```ts\n * const { ServiceError } = createTaggedError('ServiceError')\n * .withCause<DbError | CacheError | undefined>()\n *\n * ServiceError({ message: 'Failed' }) // OK\n * ServiceError({ message: 'Failed', cause: dbError }) // OK, typed\n * ```\n *\n * @example Full example with both\n * ```ts\n * const { UserServiceError } = createTaggedError('UserServiceError')\n * .withContext<{ userId: string }>()\n * .withCause<RepoError | undefined>()\n *\n * // Type extraction works\n * type UserServiceError = ReturnType<typeof UserServiceError>\n * ```\n *\n * @example Permissive mode (if you want the old behavior)\n * ```ts\n * const { FlexibleError } = createTaggedError('FlexibleError')\n * .withContext<Record<string, unknown> | undefined>()\n * .withCause<AnyTaggedError | undefined>()\n * ```\n */\nexport function createTaggedError<TName extends `${string}Error`>(\n\tname: TName,\n): ErrorBuilder<TName> {\n\tconst createBuilder = <\n\t\tTContext extends Record<string, unknown> | undefined = undefined,\n\t\tTCause extends AnyTaggedError | undefined = undefined,\n\t>(): ErrorBuilder<TName, TContext, TCause> => {\n\t\tconst errorConstructor = (input: ErrorInput<TContext, TCause>) =>\n\t\t\t({ name, ...input }) as unknown as TaggedError<TName, TContext, TCause>;\n\n\t\tconst errName = name.replace(\n\t\t\t/Error$/,\n\t\t\t\"Err\",\n\t\t) as ReplaceErrorWithErr<TName>;\n\t\tconst errConstructor = (input: ErrorInput<TContext, TCause>) =>\n\t\t\tErr(errorConstructor(input));\n\n\t\treturn {\n\t\t\t[name]: errorConstructor,\n\t\t\t[errName]: errConstructor,\n\t\t\twithContext<\n\t\t\t\tT extends Record<string, unknown> | undefined = Record<string, unknown> | undefined,\n\t\t\t>() {\n\t\t\t\treturn createBuilder<T, TCause>();\n\t\t\t},\n\t\t\twithCause<\n\t\t\t\tT extends AnyTaggedError | undefined = AnyTaggedError | undefined,\n\t\t\t>() {\n\t\t\t\treturn createBuilder<TContext, T>();\n\t\t\t},\n\t\t} as ErrorBuilder<TName, TContext, TCause>;\n\t};\n\n\treturn createBuilder();\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAsCA,SAAgB,oBAAoBA,OAAwB;AAE3D,KAAI,iBAAiB,MACpB,QAAO,MAAM;AAId,YAAW,UAAU,SAAU,QAAO;AACtC,YACQ,UAAU,mBACV,UAAU,oBACV,UAAU,SAEjB,QAAO,OAAO,MAAM;AACrB,YAAW,UAAU,SAAU,QAAO,MAAM,UAAU;AACtD,KAAI,UAAU,KAAM,QAAO;AAC3B,KAAI,iBAAqB,QAAO;AAGhC,KAAI,MAAM,QAAQ,MAAM,CAAE,QAAO,KAAK,UAAU,MAAM;AAGtD,YAAW,UAAU,UAAU;EAC9B,MAAM,WAAW;EAGjB,MAAM,eAAe;GACpB;GACA;GACA;GACA;GACA;GACA;EACA;AACD,OAAK,MAAM,QAAQ,aAClB,KAAI,QAAQ,mBAAmB,SAAS,UAAU,SACjD,QAAO,SAAS;AAKlB,MAAI;AACH,UAAO,KAAK,UAAU,MAAM;EAC5B,QAAO;AACP,UAAO,OAAO,MAAM;EACpB;CACD;AAGD,QAAO,OAAO,MAAM;AACpB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAmOD,SAAgB,kBACfC,MACsB;CACtB,MAAM,gBAAgB,MAGwB;EAC7C,MAAM,mBAAmB,CAACC,WACxB;GAAE;GAAM,GAAG;EAAO;EAEpB,MAAM,UAAU,KAAK,QACpB,UACA,MACA;EACD,MAAM,iBAAiB,CAACA,UACvB,IAAI,iBAAiB,MAAM,CAAC;AAE7B,SAAO;IACL,OAAO;IACP,UAAU;GACX,cAEI;AACH,WAAO,eAA0B;GACjC;GACD,YAEI;AACH,WAAO,eAA4B;GACnC;EACD;CACD;AAED,QAAO,eAAe;AACtB"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["error: unknown","name: TName","fn: MessageFn<TName, TContext, TCause>","input: ErrorCallInput<TContext, TCause>"],"sources":["../../src/error/utils.ts"],"sourcesContent":["import type {\n\tTaggedError,\n\tAnyTaggedError,\n\tJsonObject,\n} from \"./types.js\";\nimport { Err } from \"../result/result.js\";\n\n/**\n * Extracts a readable error message from an unknown error value\n *\n * @param error - The unknown error to extract a message from\n * @returns A string representation of the error\n */\nexport function extractErrorMessage(error: unknown): string {\n\t// Handle Error instances\n\tif (error instanceof Error) {\n\t\treturn error.message;\n\t}\n\n\t// Handle primitives\n\tif (typeof error === \"string\") return error;\n\tif (\n\t\ttypeof error === \"number\" ||\n\t\ttypeof error === \"boolean\" ||\n\t\ttypeof error === \"bigint\"\n\t)\n\t\treturn String(error);\n\tif (typeof error === \"symbol\") return error.toString();\n\tif (error === null) return \"null\";\n\tif (error === undefined) return \"undefined\";\n\n\t// Handle arrays\n\tif (Array.isArray(error)) return JSON.stringify(error);\n\n\t// Handle plain objects\n\tif (typeof error === \"object\") {\n\t\tconst errorObj = error as Record<string, unknown>;\n\n\t\t// Check common error properties\n\t\tconst messageProps = [\n\t\t\t\"message\",\n\t\t\t\"error\",\n\t\t\t\"description\",\n\t\t\t\"title\",\n\t\t\t\"reason\",\n\t\t\t\"details\",\n\t\t] as const;\n\t\tfor (const prop of messageProps) {\n\t\t\tif (prop in errorObj && typeof errorObj[prop] === \"string\") {\n\t\t\t\treturn errorObj[prop];\n\t\t\t}\n\t\t}\n\n\t\t// Fallback to JSON stringification\n\t\ttry {\n\t\t\treturn JSON.stringify(error);\n\t\t} catch {\n\t\t\treturn String(error);\n\t\t}\n\t}\n\n\t// Final fallback\n\treturn String(error);\n}\n\n/**\n * Replaces the \"Error\" suffix with \"Err\" suffix in error type names.\n */\ntype ReplaceErrorWithErr<T extends `${string}Error`> =\n\tT extends `${infer TBase}Error` ? `${TBase}Err` : never;\n\n// =============================================================================\n// Message Function Types\n// =============================================================================\n\n/**\n * Input provided to the message template function.\n * Contains everything the error will have except `message` (since that's what it computes).\n */\ntype MessageInput<\n\tTName extends string,\n\tTContext extends JsonObject | undefined,\n\tTCause extends AnyTaggedError | undefined,\n> = { name: TName } & ([TContext] extends [undefined]\n\t? Record<never, never>\n\t: { context: Exclude<TContext, undefined> }) &\n\t([TCause] extends [undefined]\n\t\t? Record<never, never>\n\t\t: { cause: Exclude<TCause, undefined> });\n\n/**\n * Message template function type.\n */\ntype MessageFn<\n\tTName extends string,\n\tTContext extends JsonObject | undefined,\n\tTCause extends AnyTaggedError | undefined,\n> = (input: MessageInput<TName, TContext, TCause>) => string;\n\n// =============================================================================\n// Factory Input Types\n// =============================================================================\n\n/**\n * Helper type that determines optionality based on whether T includes undefined.\n */\ntype OptionalIfUndefined<T, TKey extends string> = undefined extends T\n\t? { [K in TKey]?: Exclude<T, undefined> }\n\t: { [K in TKey]: T };\n\n/**\n * Input type for error factory functions.\n * `message` is optional (computed from template when omitted).\n * `context` and `cause` follow the same optionality rules as before.\n */\ntype ErrorCallInput<\n\tTContext extends JsonObject | undefined,\n\tTCause extends AnyTaggedError | undefined,\n> = { message?: string } & (TContext extends undefined\n\t? Record<never, never>\n\t: OptionalIfUndefined<TContext, \"context\">) &\n\t(TCause extends undefined\n\t\t? Record<never, never>\n\t\t: OptionalIfUndefined<TCause, \"cause\">);\n\n// =============================================================================\n// Builder & Factory Types\n// =============================================================================\n\n/**\n * The final factories object returned by `.withMessage()`.\n * Has factory functions, NO chain methods.\n */\ntype FinalFactories<\n\tTName extends `${string}Error`,\n\tTContext extends JsonObject | undefined,\n\tTCause extends AnyTaggedError | undefined,\n> = {\n\t[K in TName]: (\n\t\tinput: ErrorCallInput<TContext, TCause>,\n\t) => TaggedError<TName, TContext, TCause>;\n} & {\n\t[K in ReplaceErrorWithErr<TName>]: (\n\t\tinput: ErrorCallInput<TContext, TCause>,\n\t) => Err<TaggedError<TName, TContext, TCause>>;\n};\n\n/**\n * Builder interface for the fluent createTaggedError API.\n * Has chain methods only, NO factory functions.\n * Must call `.withMessage(fn)` to get factories.\n */\ntype ErrorBuilder<\n\tTName extends `${string}Error`,\n\tTContext extends JsonObject | undefined = undefined,\n\tTCause extends AnyTaggedError | undefined = undefined,\n> = {\n\t/**\n\t * Constrains the context type for this error.\n\t * `.withContext<T>()` where T doesn't include undefined → context is **required**\n\t * `.withContext<T | undefined>()` → context is **optional** but typed when provided\n\t */\n\twithContext<\n\t\tT extends JsonObject | undefined = JsonObject | undefined,\n\t>(): ErrorBuilder<TName, T, TCause>;\n\n\t/**\n\t * Constrains the cause type for this error.\n\t * `.withCause<T>()` where T doesn't include undefined → cause is **required**\n\t * `.withCause<T | undefined>()` → cause is **optional** but typed when provided\n\t */\n\twithCause<\n\t\tT extends AnyTaggedError | undefined = AnyTaggedError | undefined,\n\t>(): ErrorBuilder<TName, TContext, T>;\n\n\t/**\n\t * Terminal method that defines how the error message is computed from its data.\n\t * Returns the factory functions — this is the only way to get them.\n\t *\n\t * @param fn - Template function that receives `{ name, context?, cause? }` and returns a message string\n\t */\n\twithMessage(\n\t\tfn: MessageFn<TName, TContext, TCause>,\n\t): FinalFactories<TName, TContext, TCause>;\n};\n\n// =============================================================================\n// Implementation\n// =============================================================================\n\n/**\n * Creates a new tagged error type with a fluent builder API.\n *\n * The builder provides `.withContext<T>()`, `.withCause<T>()`, and `.withMessage(fn)`.\n * `.withMessage(fn)` is **required** and **terminal** — it returns the factory functions.\n *\n * @example Simple error\n * ```ts\n * const { RecorderBusyError, RecorderBusyErr } = createTaggedError('RecorderBusyError')\n * .withMessage(() => 'A recording is already in progress');\n * ```\n *\n * @example Error with context\n * ```ts\n * const { DbNotFoundError, DbNotFoundErr } = createTaggedError('DbNotFoundError')\n * .withContext<{ table: string; id: string }>()\n * .withMessage(({ context }) => `${context.table} '${context.id}' not found`);\n * ```\n *\n * @example Error with context and cause\n * ```ts\n * const { ServiceError, ServiceErr } = createTaggedError('ServiceError')\n * .withContext<{ operation: string }>()\n * .withCause<DbServiceError>()\n * .withMessage(({ context, cause }) =>\n * `Operation '${context.operation}' failed: ${cause.message}`\n * );\n * ```\n */\nexport function createTaggedError<TName extends `${string}Error`>(\n\tname: TName,\n): ErrorBuilder<TName> {\n\tconst createBuilder = <\n\t\tTContext extends JsonObject | undefined = undefined,\n\t\tTCause extends AnyTaggedError | undefined = undefined,\n\t>(): ErrorBuilder<TName, TContext, TCause> => {\n\t\treturn {\n\t\t\twithContext<\n\t\t\t\tT extends JsonObject | undefined = JsonObject | undefined,\n\t\t\t>() {\n\t\t\t\treturn createBuilder<T, TCause>();\n\t\t\t},\n\t\t\twithCause<\n\t\t\t\tT extends AnyTaggedError | undefined = AnyTaggedError | undefined,\n\t\t\t>() {\n\t\t\t\treturn createBuilder<TContext, T>();\n\t\t\t},\n\t\t\twithMessage(\n\t\t\t\tfn: MessageFn<TName, TContext, TCause>,\n\t\t\t): FinalFactories<TName, TContext, TCause> {\n\t\t\t\tconst errorConstructor = (\n\t\t\t\t\tinput: ErrorCallInput<TContext, TCause>,\n\t\t\t\t) => {\n\t\t\t\t\tconst messageInput = {\n\t\t\t\t\t\tname,\n\t\t\t\t\t\t...(\"context\" in input ? { context: input.context } : {}),\n\t\t\t\t\t\t...(\"cause\" in input ? { cause: input.cause } : {}),\n\t\t\t\t\t} as MessageInput<TName, TContext, TCause>;\n\n\t\t\t\t\treturn {\n\t\t\t\t\t\tname,\n\t\t\t\t\t\tmessage:\n\t\t\t\t\t\t\tinput.message ?? fn(messageInput),\n\t\t\t\t\t\t...(\"context\" in input ? { context: input.context } : {}),\n\t\t\t\t\t\t...(\"cause\" in input ? { cause: input.cause } : {}),\n\t\t\t\t\t} as unknown as TaggedError<TName, TContext, TCause>;\n\t\t\t\t};\n\n\t\t\t\tconst errName = name.replace(\n\t\t\t\t\t/Error$/,\n\t\t\t\t\t\"Err\",\n\t\t\t\t) as ReplaceErrorWithErr<TName>;\n\t\t\t\tconst errConstructor = (\n\t\t\t\t\tinput: ErrorCallInput<TContext, TCause>,\n\t\t\t\t) => Err(errorConstructor(input));\n\n\t\t\t\treturn {\n\t\t\t\t\t[name]: errorConstructor,\n\t\t\t\t\t[errName]: errConstructor,\n\t\t\t\t} as FinalFactories<TName, TContext, TCause>;\n\t\t\t},\n\t\t} as ErrorBuilder<TName, TContext, TCause>;\n\t};\n\n\treturn createBuilder();\n}\n"],"mappings":";;;;;;;;;AAaA,SAAgB,oBAAoBA,OAAwB;AAE3D,KAAI,iBAAiB,MACpB,QAAO,MAAM;AAId,YAAW,UAAU,SAAU,QAAO;AACtC,YACQ,UAAU,mBACV,UAAU,oBACV,UAAU,SAEjB,QAAO,OAAO,MAAM;AACrB,YAAW,UAAU,SAAU,QAAO,MAAM,UAAU;AACtD,KAAI,UAAU,KAAM,QAAO;AAC3B,KAAI,iBAAqB,QAAO;AAGhC,KAAI,MAAM,QAAQ,MAAM,CAAE,QAAO,KAAK,UAAU,MAAM;AAGtD,YAAW,UAAU,UAAU;EAC9B,MAAM,WAAW;EAGjB,MAAM,eAAe;GACpB;GACA;GACA;GACA;GACA;GACA;EACA;AACD,OAAK,MAAM,QAAQ,aAClB,KAAI,QAAQ,mBAAmB,SAAS,UAAU,SACjD,QAAO,SAAS;AAKlB,MAAI;AACH,UAAO,KAAK,UAAU,MAAM;EAC5B,QAAO;AACP,UAAO,OAAO,MAAM;EACpB;CACD;AAGD,QAAO,OAAO,MAAM;AACpB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4JD,SAAgB,kBACfC,MACsB;CACtB,MAAM,gBAAgB,MAGwB;AAC7C,SAAO;GACN,cAEI;AACH,WAAO,eAA0B;GACjC;GACD,YAEI;AACH,WAAO,eAA4B;GACnC;GACD,YACCC,IAC0C;IAC1C,MAAM,mBAAmB,CACxBC,UACI;KACJ,MAAM,eAAe;MACpB;MACA,GAAI,aAAa,QAAQ,EAAE,SAAS,MAAM,QAAS,IAAG,CAAE;MACxD,GAAI,WAAW,QAAQ,EAAE,OAAO,MAAM,MAAO,IAAG,CAAE;KAClD;AAED,YAAO;MACN;MACA,SACC,MAAM,WAAW,GAAG,aAAa;MAClC,GAAI,aAAa,QAAQ,EAAE,SAAS,MAAM,QAAS,IAAG,CAAE;MACxD,GAAI,WAAW,QAAQ,EAAE,OAAO,MAAM,MAAO,IAAG,CAAE;KAClD;IACD;IAED,MAAM,UAAU,KAAK,QACpB,UACA,MACA;IACD,MAAM,iBAAiB,CACtBA,UACI,IAAI,iBAAiB,MAAM,CAAC;AAEjC,WAAO;MACL,OAAO;MACP,UAAU;IACX;GACD;EACD;CACD;AAED,QAAO,eAAe;AACtB"}
|
package/dist/query/index.js
CHANGED
package/dist/result/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Err, Ok, isErr, isOk, isResult, resolve, tryAsync, trySync, unwrap } from "../result-
|
|
2
|
-
import { partitionResults } from "../result-
|
|
1
|
+
import { Err, Ok, isErr, isOk, isResult, resolve, tryAsync, trySync, unwrap } from "../result-DnOm5ds5.js";
|
|
2
|
+
import { partitionResults } from "../result-0QjbC3Hw.js";
|
|
3
3
|
|
|
4
4
|
export { Err, Ok, isErr, isOk, isResult, partitionResults, resolve, tryAsync, trySync, unwrap };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { isOk } from "./result-
|
|
1
|
+
import { isOk } from "./result-DnOm5ds5.js";
|
|
2
2
|
|
|
3
3
|
//#region src/result/utils.ts
|
|
4
4
|
/**
|
|
@@ -27,4 +27,4 @@ function partitionResults(results) {
|
|
|
27
27
|
|
|
28
28
|
//#endregion
|
|
29
29
|
export { partitionResults };
|
|
30
|
-
//# sourceMappingURL=result-
|
|
30
|
+
//# sourceMappingURL=result-0QjbC3Hw.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"result-
|
|
1
|
+
{"version":3,"file":"result-0QjbC3Hw.js","names":["results: Result<T, E>[]"],"sources":["../src/result/utils.ts"],"sourcesContent":["import type { Err, Ok, Result } from \"./result.js\";\nimport { isOk } from \"./result.js\";\n\n/**\n * Partitions an array of Result objects into two separate arrays based on their status.\n *\n * @template T - The success type\n * @template E - The error type\n * @param results - An array of Result objects to partition\n * @returns An object containing two arrays:\n * - `oks`: Array of successful Result objects (Ok<T>[])\n * - `errs`: Array of error Result objects (Err<E>[])\n *\n * @example\n * const results = [Ok(1), Err(\"error\"), Ok(2)];\n * const { oks, errs } = partitionResults(results);\n * // oks = [Ok(1), Ok(2)]\n * // errs = [Err(\"error\")]\n */\nexport function partitionResults<T, E>(results: Result<T, E>[]) {\n\treturn {\n\t\toks: [],\n\t\terrs: [],\n\t\t...Object.groupBy(results, (result) => (isOk(result) ? \"oks\" : \"errs\")),\n\t} as { oks: Ok<T>[]; errs: Err<E>[] };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAmBA,SAAgB,iBAAuBA,SAAyB;AAC/D,QAAO;EACN,KAAK,CAAE;EACP,MAAM,CAAE;EACR,GAAG,OAAO,QAAQ,SAAS,CAAC,WAAY,KAAK,OAAO,GAAG,QAAQ,OAAQ;CACvE;AACD"}
|
|
@@ -72,8 +72,6 @@ function isResult(value) {
|
|
|
72
72
|
const hasDataProperty = "data" in value;
|
|
73
73
|
const hasErrorProperty = "error" in value;
|
|
74
74
|
if (!hasDataProperty || !hasErrorProperty) return false;
|
|
75
|
-
const isNeitherNull = value.data !== null && value.error !== null;
|
|
76
|
-
if (isNeitherNull) return false;
|
|
77
75
|
return true;
|
|
78
76
|
}
|
|
79
77
|
/**
|
|
@@ -248,4 +246,4 @@ function resolve(value) {
|
|
|
248
246
|
|
|
249
247
|
//#endregion
|
|
250
248
|
export { Err, Ok, isErr, isOk, isResult, resolve, tryAsync, trySync, unwrap };
|
|
251
|
-
//# sourceMappingURL=result-
|
|
249
|
+
//# sourceMappingURL=result-DnOm5ds5.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"result-DnOm5ds5.js","names":["data: T","error: E","value: unknown","result: Result<T, E>","value: T | Result<T, E>"],"sources":["../src/result/result.ts"],"sourcesContent":["/**\n * Represents the successful outcome of an operation, encapsulating the success value.\n *\n * This is the 'Ok' variant of the `Result` type. It holds a `data` property\n * of type `T` (the success value) and an `error` property explicitly set to `null`,\n * signifying no error occurred.\n *\n * Use this type in conjunction with `Err<E>` and `Result<T, E>`.\n *\n * @template T - The type of the success value contained within.\n */\nexport type Ok<T> = { data: T; error: null };\n\n/**\n * Represents the failure outcome of an operation, encapsulating the error value.\n *\n * This is the 'Err' variant of the `Result` type. It holds an `error` property\n * of type `E` (the error value) and a `data` property explicitly set to `null`,\n * signifying that no success value is present due to the failure.\n *\n * Use this type in conjunction with `Ok<T>` and `Result<T, E>`.\n *\n * @template E - The type of the error value contained within.\n */\nexport type Err<E> = { error: E; data: null };\n\n/**\n * A type that represents the outcome of an operation that can either succeed or fail.\n *\n * `Result<T, E>` is a discriminated union type with two possible variants:\n * - `Ok<T>`: Represents a successful outcome, containing a `data` field with the success value of type `T`.\n * In this case, the `error` field is `null`.\n * - `Err<E>`: Represents a failure outcome, containing an `error` field with the error value of type `E`.\n * In this case, the `data` field is `null`.\n *\n * This type promotes explicit error handling by requiring developers to check\n * the variant of the `Result` before accessing its potential value or error.\n * It helps avoid runtime errors often associated with implicit error handling (e.g., relying on `try-catch` for all errors).\n *\n * @template T - The type of the success value if the operation is successful (held in `Ok<T>`).\n * @template E - The type of the error value if the operation fails (held in `Err<E>`).\n * @example\n * ```ts\n * function divide(numerator: number, denominator: number): Result<number, string> {\n * if (denominator === 0) {\n * return Err(\"Cannot divide by zero\");\n * }\n * return Ok(numerator / denominator);\n * }\n *\n * const result1 = divide(10, 2);\n * if (isOk(result1)) {\n * console.log(\"Success:\", result1.data); // Output: Success: 5\n * }\n *\n * const result2 = divide(10, 0);\n * if (isErr(result2)) {\n * console.error(\"Failure:\", result2.error); // Output: Failure: Cannot divide by zero\n * }\n * ```\n */\nexport type Result<T, E> = Ok<T> | Err<E>;\n\n/**\n * Constructs an `Ok<T>` variant, representing a successful outcome.\n *\n * This factory function creates the success variant of a `Result`.\n * It wraps the provided `data` (the success value) and ensures the `error` property is `null`.\n *\n * @template T - The type of the success value.\n * @param data - The success value to be wrapped in the `Ok` variant.\n * @returns An `Ok<T>` object with the provided data and `error` set to `null`.\n * @example\n * ```ts\n * const successfulResult = Ok(\"Operation completed successfully\");\n * // successfulResult is { data: \"Operation completed successfully\", error: null }\n * ```\n */\nexport const Ok = <T>(data: T): Ok<T> => ({ data, error: null });\n\n/**\n * Constructs an `Err<E>` variant, representing a failure outcome.\n *\n * This factory function creates the error variant of a `Result`.\n * It wraps the provided `error` (the error value) and ensures the `data` property is `null`.\n *\n * @template E - The type of the error value.\n * @param error - The error value to be wrapped in the `Err` variant. This value represents the specific error that occurred.\n * @returns An `Err<E>` object with the provided error and `data` set to `null`.\n * @example\n * ```ts\n * const failedResult = Err(new TypeError(\"Invalid input\"));\n * // failedResult is { error: TypeError(\"Invalid input\"), data: null }\n * ```\n */\nexport const Err = <E>(error: E): Err<E> => ({ error, data: null });\n\n/**\n * Utility type to extract the `Ok<T>` variant from a `Result<T, E>` union type.\n *\n * If `R` is a `Result` type (e.g., `Result<string, Error>`), this type will resolve\n * to `Ok<string>`. This can be useful in generic contexts or for type narrowing.\n *\n * @template R - The `Result<T, E>` union type from which to extract the `Ok<T>` variant.\n * Must extend `Result<unknown, unknown>`.\n */\nexport type ExtractOkFromResult<R extends Result<unknown, unknown>> = Extract<\n\tR,\n\t{ error: null }\n>;\n\n/**\n * Utility type to extract the `Err<E>` variant from a `Result<T, E>` union type.\n *\n * If `R` is a `Result` type (e.g., `Result<string, Error>`), this type will resolve\n * to `Err<Error>`. This can be useful in generic contexts or for type narrowing.\n *\n * @template R - The `Result<T, E>` union type from which to extract the `Err<E>` variant.\n * Must extend `Result<unknown, unknown>`.\n */\nexport type ExtractErrFromResult<R extends Result<unknown, unknown>> = Extract<\n\tR,\n\t{ data: null }\n>;\n\n/**\n * Utility type to extract the success value's type `T` from a `Result<T, E>` type.\n *\n * If `R` is an `Ok<T>` variant (or a `Result<T, E>` that could be an `Ok<T>`),\n * this type resolves to `T`. If `R` can only be an `Err<E>` variant, it resolves to `never`.\n * This is useful for obtaining the type of the `data` field when you know you have a success.\n *\n * @template R - The `Result<T, E>` type from which to extract the success value's type.\n * Must extend `Result<unknown, unknown>`.\n * @example\n * ```ts\n * type MyResult = Result<number, string>;\n * type SuccessValueType = UnwrapOk<MyResult>; // SuccessValueType is number\n *\n * type MyErrorResult = Err<string>;\n * type ErrorValueType = UnwrapOk<MyErrorResult>; // ErrorValueType is never\n * ```\n */\nexport type UnwrapOk<R extends Result<unknown, unknown>> = R extends Ok<infer U>\n\t? U\n\t: never;\n\n/**\n * Utility type to extract the error value's type `E` from a `Result<T, E>` type.\n *\n * If `R` is an `Err<E>` variant (or a `Result<T, E>` that could be an `Err<E>`),\n * this type resolves to `E`. If `R` can only be an `Ok<T>` variant, it resolves to `never`.\n * This is useful for obtaining the type of the `error` field when you know you have a failure.\n *\n * @template R - The `Result<T, E>` type from which to extract the error value's type.\n * Must extend `Result<unknown, unknown>`.\n * @example\n * ```ts\n * type MyResult = Result<number, string>;\n * type ErrorValueType = UnwrapErr<MyResult>; // ErrorValueType is string\n *\n * type MySuccessResult = Ok<number>;\n * type SuccessValueType = UnwrapErr<MySuccessResult>; // SuccessValueType is never\n * ```\n */\nexport type UnwrapErr<R extends Result<unknown, unknown>> = R extends Err<\n\tinfer E\n>\n\t? E\n\t: never;\n\n/**\n * Type guard to runtime check if an unknown value is a valid `Result<T, E>`.\n *\n * A value is considered a valid `Result` if:\n * 1. It is a non-null object.\n * 2. It has both `data` and `error` properties.\n * 3. At least one of the `data` or `error` channels is `null`. Both being `null` represents `Ok(null)`.\n *\n * This function does not validate the types of `data` or `error` beyond `null` checks.\n *\n * @template T - The expected type of the success value if the value is an `Ok` variant (defaults to `unknown`).\n * @template E - The expected type of the error value if the value is an `Err` variant (defaults to `unknown`).\n * @param value - The value to check.\n * @returns `true` if the value conforms to the `Result` structure, `false` otherwise.\n * If `true`, TypeScript's type system will narrow `value` to `Result<T, E>`.\n * @example\n * ```ts\n * declare const someValue: unknown;\n *\n * if (isResult<string, Error>(someValue)) {\n * // someValue is now typed as Result<string, Error>\n * if (isOk(someValue)) {\n * console.log(someValue.data); // string\n * } else {\n * console.error(someValue.error); // Error\n * }\n * }\n * ```\n */\nexport function isResult<T = unknown, E = unknown>(\n\tvalue: unknown,\n): value is Result<T, E> {\n\tconst isNonNullObject = typeof value === \"object\" && value !== null;\n\tif (!isNonNullObject) return false;\n\n\tconst hasDataProperty = \"data\" in value;\n\tconst hasErrorProperty = \"error\" in value;\n\tif (!hasDataProperty || !hasErrorProperty) return false;\n\n\treturn true;\n}\n\n/**\n * Type guard to runtime check if a `Result<T, E>` is an `Ok<T>` variant.\n *\n * This function narrows the type of a `Result` to `Ok<T>` if it represents a successful outcome.\n * An `Ok<T>` variant is identified by its `error` property being `null`.\n *\n * @template T - The success value type.\n * @template E - The error value type.\n * @param result - The `Result<T, E>` to check.\n * @returns `true` if the `result` is an `Ok<T>` variant, `false` otherwise.\n * If `true`, TypeScript's type system will narrow `result` to `Ok<T>`.\n * @example\n * ```ts\n * declare const myResult: Result<number, string>;\n *\n * if (isOk(myResult)) {\n * // myResult is now typed as Ok<number>\n * console.log(\"Success value:\", myResult.data); // myResult.data is number\n * }\n * ```\n */\nexport function isOk<T, E>(result: Result<T, E>): result is Ok<T> {\n\treturn result.error === null;\n}\n\n/**\n * Type guard to runtime check if a `Result<T, E>` is an `Err<E>` variant.\n *\n * This function narrows the type of a `Result` to `Err<E>` if it represents a failure outcome.\n * An `Err<E>` variant is identified by its `error` property being non-`null` (and thus `data` being `null`).\n *\n * @template T - The success value type.\n * @template E - The error value type.\n * @param result - The `Result<T, E>` to check.\n * @returns `true` if the `result` is an `Err<E>` variant, `false` otherwise.\n * If `true`, TypeScript's type system will narrow `result` to `Err<E>`.\n * @example\n * ```ts\n * declare const myResult: Result<number, string>;\n *\n * if (isErr(myResult)) {\n * // myResult is now typed as Err<string>\n * console.error(\"Error value:\", myResult.error); // myResult.error is string\n * }\n * ```\n */\nexport function isErr<T, E>(result: Result<T, E>): result is Err<E> {\n\treturn result.error !== null; // Equivalent to result.data === null\n}\n\n/**\n * Executes a synchronous operation and wraps its outcome in a Result type.\n *\n * This function attempts to execute the `try` operation:\n * - If the `try` operation completes successfully, its return value is wrapped in an `Ok<T>` variant.\n * - If the `try` operation throws an exception, the caught exception (of type `unknown`) is passed to\n * the `catch` function, which transforms it into either an `Ok<T>` (recovery) or `Err<E>` (propagation).\n *\n * The return type is automatically narrowed based on what your catch function returns:\n * - If catch always returns `Ok<T>`, the function returns `Ok<T>` (guaranteed success)\n * - If catch always returns `Err<E>`, the function returns `Result<T, E>` (may succeed or fail)\n * - If catch can return either `Ok<T>` or `Err<E>`, the function returns `Result<T, E>` (conditional recovery)\n *\n * @template T - The success value type\n * @template E - The error value type (when catch can return errors)\n * @param options - Configuration object\n * @param options.try - The operation to execute\n * @param options.catch - Error handler that transforms caught exceptions into either `Ok<T>` (recovery) or `Err<E>` (propagation)\n * @returns `Ok<T>` if catch always returns Ok (recovery), otherwise `Result<T, E>` (propagation or conditional recovery)\n *\n * @example\n * ```ts\n * // Returns Ok<string> - guaranteed success since catch always returns Ok\n * const alwaysOk = trySync({\n * try: () => JSON.parse(input),\n * catch: () => Ok(\"fallback\") // Always Ok<T>\n * });\n *\n * // Returns Result<object, string> - may fail since catch always returns Err\n * const mayFail = trySync({\n * try: () => JSON.parse(input),\n * catch: (err) => Err(\"Parse failed\") // Returns Err<E>\n * });\n *\n * // Returns Result<void, MyError> - conditional recovery based on error type\n * const conditional = trySync({\n * try: () => riskyOperation(),\n * catch: (err) => {\n * if (isRecoverable(err)) return Ok(undefined);\n * return MyErr({ message: \"Unrecoverable\" });\n * }\n * });\n * ```\n */\nexport function trySync<T>(options: {\n\ttry: () => T;\n\tcatch: (error: unknown) => Ok<T>;\n}): Ok<T>;\n\nexport function trySync<T, E>(options: {\n\ttry: () => T;\n\tcatch: (error: unknown) => Err<E>;\n}): Result<T, E>;\n\nexport function trySync<T, E>(options: {\n\ttry: () => T;\n\tcatch: (error: unknown) => Ok<T> | Err<E>;\n}): Result<T, E>;\n\nexport function trySync<T, E>({\n\ttry: operation,\n\tcatch: catchFn,\n}: {\n\ttry: () => T;\n\tcatch: (error: unknown) => Ok<T> | Err<E>;\n}): Ok<T> | Result<T, E> {\n\ttry {\n\t\tconst data = operation();\n\t\treturn Ok(data);\n\t} catch (error) {\n\t\treturn catchFn(error);\n\t}\n}\n\n/**\n * Executes an asynchronous operation and wraps its outcome in a Promise<Result>.\n *\n * This function attempts to execute the `try` operation:\n * - If the `try` operation resolves successfully, its resolved value is wrapped in an `Ok<T>` variant.\n * - If the `try` operation rejects or throws an exception, the caught error (of type `unknown`) is passed to\n * the `catch` function, which transforms it into either an `Ok<T>` (recovery) or `Err<E>` (propagation).\n *\n * The return type is automatically narrowed based on what your catch function returns:\n * - If catch always returns `Ok<T>`, the function returns `Promise<Ok<T>>` (guaranteed success)\n * - If catch always returns `Err<E>`, the function returns `Promise<Result<T, E>>` (may succeed or fail)\n * - If catch can return either `Ok<T>` or `Err<E>`, the function returns `Promise<Result<T, E>>` (conditional recovery)\n *\n * @template T - The success value type\n * @template E - The error value type (when catch can return errors)\n * @param options - Configuration object\n * @param options.try - The async operation to execute\n * @param options.catch - Error handler that transforms caught exceptions/rejections into either `Ok<T>` (recovery) or `Err<E>` (propagation)\n * @returns `Promise<Ok<T>>` if catch always returns Ok (recovery), otherwise `Promise<Result<T, E>>` (propagation or conditional recovery)\n *\n * @example\n * ```ts\n * // Returns Promise<Ok<Response>> - guaranteed success since catch always returns Ok\n * const alwaysOk = tryAsync({\n * try: async () => fetch(url),\n * catch: () => Ok(new Response()) // Always Ok<T>\n * });\n *\n * // Returns Promise<Result<Response, Error>> - may fail since catch always returns Err\n * const mayFail = tryAsync({\n * try: async () => fetch(url),\n * catch: (err) => Err(new Error(\"Fetch failed\")) // Returns Err<E>\n * });\n *\n * // Returns Promise<Result<void, BlobError>> - conditional recovery based on error type\n * const conditional = await tryAsync({\n * try: async () => {\n * await deleteFile(filename);\n * },\n * catch: (err) => {\n * if ((err as { name?: string }).name === 'NotFoundError') {\n * return Ok(undefined); // Already deleted, that's fine\n * }\n * return BlobErr({ message: \"Delete failed\" });\n * }\n * });\n * ```\n */\nexport async function tryAsync<T>(options: {\n\ttry: () => Promise<T>;\n\tcatch: (error: unknown) => Ok<T>;\n}): Promise<Ok<T>>;\n\nexport async function tryAsync<T, E>(options: {\n\ttry: () => Promise<T>;\n\tcatch: (error: unknown) => Err<E>;\n}): Promise<Result<T, E>>;\n\nexport async function tryAsync<T, E>(options: {\n\ttry: () => Promise<T>;\n\tcatch: (error: unknown) => Ok<T> | Err<E>;\n}): Promise<Result<T, E>>;\n\nexport async function tryAsync<T, E>({\n\ttry: operation,\n\tcatch: catchFn,\n}: {\n\ttry: () => Promise<T>;\n\tcatch: (error: unknown) => Ok<T> | Err<E>;\n}): Promise<Ok<T> | Result<T, E>> {\n\ttry {\n\t\tconst data = await operation();\n\t\treturn Ok(data);\n\t} catch (error) {\n\t\treturn catchFn(error);\n\t}\n}\n\n/**\n * Resolves a value that may or may not be wrapped in a `Result`, returning the final value.\n *\n * This function handles the common pattern where a value might be a `Result<T, E>` or a plain `T`:\n * - If `value` is an `Ok<T>` variant, returns the contained success value.\n * - If `value` is an `Err<E>` variant, throws the contained error value.\n * - If `value` is not a `Result` (i.e., it's already a plain value of type `T`),\n * returns it as-is.\n *\n * This is useful when working with APIs that might return either direct values or Results,\n * allowing you to normalize them to the actual value or propagate errors via throwing.\n *\n * Use `resolve` when the input might or might not be a Result.\n * Use `unwrap` when you know the input is definitely a Result.\n *\n * @template T - The type of the success value (if `value` is `Ok<T>`) or the type of the plain value.\n * @template E - The type of the error value (if `value` is `Err<E>`).\n * @param value - The value to resolve. Can be a `Result<T, E>` or a plain value of type `T`.\n * @returns The final value of type `T` if `value` is `Ok<T>` or if `value` is already a plain `T`.\n * @throws The error value `E` if `value` is an `Err<E>` variant.\n *\n * @example\n * ```ts\n * // Example with an Ok variant\n * const okResult = Ok(\"success data\");\n * const resolved = resolve(okResult); // \"success data\"\n *\n * // Example with an Err variant\n * const errResult = Err(new Error(\"failure\"));\n * try {\n * resolve(errResult);\n * } catch (e) {\n * console.error(e.message); // \"failure\"\n * }\n *\n * // Example with a plain value\n * const plainValue = \"plain data\";\n * const resolved = resolve(plainValue); // \"plain data\"\n *\n * // Example with a function that might return Result or plain value\n * declare function mightReturnResult(): string | Result<string, Error>;\n * const outcome = mightReturnResult();\n * try {\n * const finalValue = resolve(outcome); // handles both cases\n * console.log(\"Final value:\", finalValue);\n * } catch (e) {\n * console.error(\"Operation failed:\", e);\n * }\n * ```\n */\n/**\n * Unwraps a `Result<T, E>`, returning the success value or throwing the error.\n *\n * This function extracts the data from a `Result`:\n * - If the `Result` is an `Ok<T>` variant, returns the contained success value of type `T`.\n * - If the `Result` is an `Err<E>` variant, throws the contained error value of type `E`.\n *\n * Unlike `resolve`, this function expects the input to always be a `Result` type,\n * making it more direct for cases where you know you're working with a `Result`.\n *\n * @template T - The type of the success value contained in the `Ok<T>` variant.\n * @template E - The type of the error value contained in the `Err<E>` variant.\n * @param result - The `Result<T, E>` to unwrap.\n * @returns The success value of type `T` if the `Result` is `Ok<T>`.\n * @throws The error value of type `E` if the `Result` is `Err<E>`.\n *\n * @example\n * ```ts\n * // Example with an Ok variant\n * const okResult = Ok(\"success data\");\n * const value = unwrap(okResult); // \"success data\"\n *\n * // Example with an Err variant\n * const errResult = Err(new Error(\"something went wrong\"));\n * try {\n * unwrap(errResult);\n * } catch (error) {\n * console.error(error.message); // \"something went wrong\"\n * }\n *\n * // Usage in a function that returns Result\n * function divide(a: number, b: number): Result<number, string> {\n * if (b === 0) return Err(\"Division by zero\");\n * return Ok(a / b);\n * }\n *\n * try {\n * const result = unwrap(divide(10, 2)); // 5\n * console.log(\"Result:\", result);\n * } catch (error) {\n * console.error(\"Division failed:\", error);\n * }\n * ```\n */\nexport function unwrap<T, E>(result: Result<T, E>): T {\n\tif (isOk(result)) {\n\t\treturn result.data;\n\t}\n\tthrow result.error;\n}\n\nexport function resolve<T, E>(value: T | Result<T, E>): T {\n\tif (isResult<T, E>(value)) {\n\t\tif (isOk(value)) {\n\t\t\treturn value.data;\n\t\t}\n\t\t// If it's a Result and not Ok, it must be Err.\n\t\t// The type guard isResult<T,E>(value) and isOk(value) already refine the type.\n\t\t// So, 'value' here is known to be Err<E>.\n\t\tthrow value.error;\n\t}\n\n\t// If it's not a Result type, return the value as-is.\n\t// 'value' here is known to be of type T.\n\treturn value;\n}\n"],"mappings":";;;;;;;;;;;;;;;;AA8EA,MAAa,KAAK,CAAIA,UAAoB;CAAE;CAAM,OAAO;AAAM;;;;;;;;;;;;;;;;AAiB/D,MAAa,MAAM,CAAIC,WAAsB;CAAE;CAAO,MAAM;AAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAyGlE,SAAgB,SACfC,OACwB;CACxB,MAAM,yBAAyB,UAAU,YAAY,UAAU;AAC/D,MAAK,gBAAiB,QAAO;CAE7B,MAAM,kBAAkB,UAAU;CAClC,MAAM,mBAAmB,WAAW;AACpC,MAAK,oBAAoB,iBAAkB,QAAO;AAElD,QAAO;AACP;;;;;;;;;;;;;;;;;;;;;;AAuBD,SAAgB,KAAWC,QAAuC;AACjE,QAAO,OAAO,UAAU;AACxB;;;;;;;;;;;;;;;;;;;;;;AAuBD,SAAgB,MAAYA,QAAwC;AACnE,QAAO,OAAO,UAAU;AACxB;AA6DD,SAAgB,QAAc,EAC7B,KAAK,WACL,OAAO,SAIP,EAAwB;AACxB,KAAI;EACH,MAAM,OAAO,WAAW;AACxB,SAAO,GAAG,KAAK;CACf,SAAQ,OAAO;AACf,SAAO,QAAQ,MAAM;CACrB;AACD;AAiED,eAAsB,SAAe,EACpC,KAAK,WACL,OAAO,SAIP,EAAiC;AACjC,KAAI;EACH,MAAM,OAAO,MAAM,WAAW;AAC9B,SAAO,GAAG,KAAK;CACf,SAAQ,OAAO;AACf,SAAO,QAAQ,MAAM;CACrB;AACD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgGD,SAAgB,OAAaA,QAAyB;AACrD,KAAI,KAAK,OAAO,CACf,QAAO,OAAO;AAEf,OAAM,OAAO;AACb;AAED,SAAgB,QAAcC,OAA4B;AACzD,KAAI,SAAe,MAAM,EAAE;AAC1B,MAAI,KAAK,MAAM,CACd,QAAO,MAAM;AAKd,QAAM,MAAM;CACZ;AAID,QAAO;AACP"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"result-DolxQXIZ.d.ts","names":[],"sources":["../src/result/result.ts"],"sourcesContent":[],"mappings":";;AAWA;AAaA;AAqCA;;;;;;AAAsC;AAiBtC;AAAgE,KAnEpD,EAmEoD,CAAA,CAAA,CAAA,GAAA;EAAA,IAApC,EAnEA,CAmEA;EAAC,KAAM,EAAA,IAAA;CAAC;AAAF;AAiBlC;;;;;AAAqC;AAWrC;;;;AAAsE,KAlF1D,GAkF0D,CAAA,CAAA,CAAA,GAAA;EAAO,KAAA,EAlF/C,CAkF+C;EAcjE,IAAA,EAAA,IAAA;CAAoB;;;;AAA8C;AAuB9E;;;;;;AACI;AAqBJ;;;;;;AAGI;AAgCJ;;;;;AAEkB;
|
|
1
|
+
{"version":3,"file":"result-DolxQXIZ.d.ts","names":[],"sources":["../src/result/result.ts"],"sourcesContent":[],"mappings":";;AAWA;AAaA;AAqCA;;;;;;AAAsC;AAiBtC;AAAgE,KAnEpD,EAmEoD,CAAA,CAAA,CAAA,GAAA;EAAA,IAApC,EAnEA,CAmEA;EAAC,KAAM,EAAA,IAAA;CAAC;AAAF;AAiBlC;;;;;AAAqC;AAWrC;;;;AAAsE,KAlF1D,GAkF0D,CAAA,CAAA,CAAA,GAAA;EAAO,KAAA,EAlF/C,CAkF+C;EAcjE,IAAA,EAAA,IAAA;CAAoB;;;;AAA8C;AAuB9E;;;;;;AACI;AAqBJ;;;;;;AAGI;AAgCJ;;;;;AAEkB;AAgClB;;;;;;;AAA8D;AAyB9D;;;AAA8C,KAtMlC,MAsMkC,CAAA,CAAA,EAAA,CAAA,CAAA,GAtMnB,EAsMmB,CAtMhB,CAsMgB,CAAA,GAtMX,GAsMW,CAtMP,CAsMO,CAAA;;;;AAAkB;AAgDhE;;;;;;;AAGM;AAEN;;;AAEgC,cA5OnB,EA4OmB,EAAA,CAAA,CAAA,CAAA,CAAA,IAAA,EA5OJ,CA4OI,EAAA,GA5OA,EA4OA,CA5OG,CA4OH,CAAA;;;;;AACtB;AAEV;;;;;;;;;;AAGU,cAjOG,GAiOH,EAAA,CAAA,CAAA,CAAA,CAAA,KAAA,EAjOoB,CAiOpB,EAAA,GAjOwB,GAiOxB,CAjO4B,CAiO5B,CAAA;AAiEV;;;;;;;;;AAGW,KA1RC,mBA0RD,CAAA,UA1R+B,MA0R/B,CAAA,OAAA,EAAA,OAAA,CAAA,CAAA,GA1R2D,OA0R3D,CAzRV,CAyRU,EAAA;EAEW,KAAA,EAAA,IAAQ;CAAA,CAAA;;;;;;;;;AAGnB;AAEW,KAnRV,oBAmRkB,CAAA,UAnRa,MAmRb,CAAA,OAAA,EAAA,OAAA,CAAA,CAAA,GAnRyC,OAmRzC,CAlR7B,CAkR6B,EAAA;EAAA,IAAA,EAAA,IAAA;CAAA,CAAA;;;;;;;;;;AAGnB;AA+GX;;;;;;AAAqD;AAOrD;AAAuB,KArXX,QAqXW,CAAA,UArXQ,MAqXR,CAAA,OAAA,EAAA,OAAA,CAAA,CAAA,GArXoC,CAqXpC,SArX8C,EAqX9C,CAAA,KAAA,EAAA,CAAA,GApXpB,CAoXoB,GAAA,KAAA;;;;;;AAAkC;;;;;;;;;;;;;KA/V7C,oBAAoB,4BAA4B,UAAU,eAGnE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAgCa,6DAEJ,OAAO,GAAG;;;;;;;;;;;;;;;;;;;;;;iBAgCN,mBAAmB,OAAO,GAAG,eAAe,GAAG;;;;;;;;;;;;;;;;;;;;;;iBAyB/C,oBAAoB,OAAO,GAAG,eAAe,IAAI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAgDjD;aACJ;6BACgB,GAAG;IAC3B,GAAG;iBAES;aACJ;6BACgB,IAAI;IAC5B,OAAO,GAAG;iBAEE;aACJ;6BACgB,GAAG,KAAK,IAAI;IACpC,OAAO,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAiEQ;aACV,QAAQ;6BACQ,GAAG;IAC3B,QAAQ,GAAG;iBAEO;aACV,QAAQ;6BACQ,IAAI;IAC5B,QAAQ,OAAO,GAAG;iBAEA;aACV,QAAQ;6BACQ,GAAG,KAAK,IAAI;IACpC,QAAQ,OAAO,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA+GN,qBAAqB,OAAO,GAAG,KAAK;iBAOpC,qBAAqB,IAAI,OAAO,GAAG,KAAK"}
|