@clipboard-health/util-ts 3.8.1 → 3.9.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 CHANGED
@@ -8,6 +8,9 @@ TypeScript utilities.
8
8
  - [Usage](#usage)
9
9
  - [ServiceError](#serviceerror)
10
10
  - [ServiceResult](#serviceresult)
11
+ - [`tryCatchAsync`](#trycatchasync)
12
+ - [`tryCatch`](#trycatch)
13
+ - [`fromSafeParseReturnType`](#fromsafeparsereturntype)
11
14
  - [Functional](#functional)
12
15
  - [`pipe`](#pipe)
13
16
  - [`option`](#option)
@@ -29,28 +32,28 @@ See `./src/lib` for each utility.
29
32
  <embedex source="packages/util-ts/examples/serviceError.ts">
30
33
 
31
34
  ```ts
32
- import { deepEqual, equal } from "node:assert/strict";
35
+ import { deepEqual, strictEqual } from "node:assert/strict";
33
36
 
34
37
  import { ERROR_CODES, ServiceError } from "@clipboard-health/util-ts";
35
38
  import { z } from "zod";
36
39
 
37
40
  {
38
41
  const error = new ServiceError("boom");
39
- equal(error.toString(), `ServiceError[${error.id}]: [internal]: boom`);
42
+ strictEqual(error.toString(), `ServiceError[${error.id}]: [internal]: boom`);
40
43
  }
41
44
 
42
45
  try {
43
46
  throw new Error("boom");
44
47
  } catch (error) {
45
48
  const serviceError = ServiceError.fromUnknown(error);
46
- equal(serviceError.toString(), `ServiceError[${serviceError.id}]: [internal]: boom`);
49
+ strictEqual(serviceError.toString(), `ServiceError[${serviceError.id}]: [internal]: boom`);
47
50
  }
48
51
 
49
52
  {
50
53
  const serviceError = ServiceError.fromZodError(
51
54
  new z.ZodError([{ code: "custom", path: ["foo"], message: "boom" }]),
52
55
  );
53
- equal(serviceError.toString(), `ServiceError[${serviceError.id}]: [unprocessableEntity]: boom`);
56
+ strictEqual(serviceError.toString(), `ServiceError[${serviceError.id}]: [badRequest]: boom`);
54
57
  }
55
58
 
56
59
  {
@@ -58,7 +61,7 @@ try {
58
61
  issues: [{ message: "boom" }],
59
62
  cause: new Error("Original error"),
60
63
  });
61
- equal(errorWithCause.toString(), `ServiceError[${errorWithCause.id}]: [internal]: boom`);
64
+ strictEqual(errorWithCause.toString(), `ServiceError[${errorWithCause.id}]: [internal]: boom`);
62
65
  }
63
66
 
64
67
  {
@@ -78,7 +81,7 @@ try {
78
81
  cause: new Error("Original error"),
79
82
  });
80
83
 
81
- equal(
84
+ strictEqual(
82
85
  multipleIssues.toString(),
83
86
  `ServiceError[${multipleIssues.id}]: [badRequest]: Invalid email format; [unprocessableEntity]: Phone number too short`,
84
87
  );
@@ -120,9 +123,10 @@ try {
120
123
  import { ok } from "node:assert/strict";
121
124
 
122
125
  import {
123
- either as E,
124
126
  ERROR_CODES,
125
127
  failure,
128
+ isFailure,
129
+ isSuccess,
126
130
  type ServiceResult,
127
131
  success,
128
132
  } from "@clipboard-health/util-ts";
@@ -142,8 +146,99 @@ function validateUser(params: { email: string; phone: string }): ServiceResult<{
142
146
  return success({ id: "user-123" });
143
147
  }
144
148
 
145
- ok(E.isLeft(validateUser({ email: "invalidEmail", phone: "invalidPhoneNumber" })));
146
- ok(E.isRight(validateUser({ email: "user@example.com", phone: "555-555-5555" })));
149
+ ok(isFailure(validateUser({ email: "invalidEmail", phone: "invalidPhoneNumber" })));
150
+ ok(isSuccess(validateUser({ email: "user@example.com", phone: "555-555-5555" })));
151
+ ```
152
+
153
+ </embedex>
154
+
155
+ #### `tryCatchAsync`
156
+
157
+ <embedex source="packages/util-ts/examples/tryCatchAsync.ts">
158
+
159
+ ```ts
160
+ import { ok, strictEqual } from "node:assert/strict";
161
+
162
+ import { isFailure, isSuccess, ServiceError, tryCatchAsync } from "@clipboard-health/util-ts";
163
+
164
+ async function example() {
165
+ const successResult = await tryCatchAsync(
166
+ async () => {
167
+ const response = await fetch("https://jsonplaceholder.typicode.com/posts/1");
168
+ return (await response.json()) as { id: number };
169
+ },
170
+ (error) => new ServiceError(`Failed to fetch: ${String(error)}`),
171
+ );
172
+
173
+ ok(isSuccess(successResult));
174
+ strictEqual(successResult.value.id, 1);
175
+
176
+ const failureResult = await tryCatchAsync(
177
+ async () => await Promise.reject(new Error("Network error")),
178
+ (error) => new ServiceError(`Failed to fetch: ${String(error)}`),
179
+ );
180
+
181
+ ok(isFailure(failureResult));
182
+ strictEqual(failureResult.error.issues[0]?.message, "Failed to fetch: Error: Network error");
183
+ }
184
+
185
+ // eslint-disable-next-line unicorn/prefer-top-level-await
186
+ void example();
187
+ ```
188
+
189
+ </embedex>
190
+
191
+ #### `tryCatch`
192
+
193
+ <embedex source="packages/util-ts/examples/tryCatch.ts">
194
+
195
+ ```ts
196
+ import { ok, strictEqual } from "node:assert/strict";
197
+
198
+ import { isFailure, isSuccess, parseJson, ServiceError, tryCatch } from "@clipboard-health/util-ts";
199
+
200
+ const successResult = tryCatch(
201
+ () => parseJson<{ name: string }>('{"name": "John"}'),
202
+ (error) => new ServiceError(`Parse error: ${String(error)}`),
203
+ );
204
+
205
+ ok(isSuccess(successResult));
206
+ strictEqual(successResult.value.name, "John");
207
+
208
+ const failureResult = tryCatch(
209
+ () => parseJson("invalid json"),
210
+ (error) => new ServiceError(`Parse error: ${String(error)}`),
211
+ );
212
+
213
+ ok(isFailure(failureResult));
214
+ ok(failureResult.error.issues[0]?.message?.includes("Parse error"));
215
+ ```
216
+
217
+ </embedex>
218
+
219
+ #### `fromSafeParseReturnType`
220
+
221
+ <embedex source="packages/util-ts/examples/fromSafeParseReturnType.ts">
222
+
223
+ ```ts
224
+ import { ok, strictEqual } from "node:assert/strict";
225
+
226
+ import { fromSafeParseReturnType, isFailure, isSuccess } from "@clipboard-health/util-ts";
227
+ import { z } from "zod";
228
+
229
+ const schema = z.object({ name: z.string(), age: z.number() });
230
+
231
+ const validData = { name: "John", age: 30 };
232
+ const successResult = fromSafeParseReturnType(schema.safeParse(validData));
233
+
234
+ ok(isSuccess(successResult));
235
+ strictEqual(successResult.value.name, "John");
236
+
237
+ const invalidData = { name: "John", age: "thirty" };
238
+ const failureResult = fromSafeParseReturnType(schema.safeParse(invalidData));
239
+
240
+ ok(isFailure(failureResult));
241
+ ok(failureResult.error.issues.length > 0);
147
242
  ```
148
243
 
149
244
  </embedex>
@@ -155,7 +250,7 @@ ok(E.isRight(validateUser({ email: "user@example.com", phone: "555-555-5555" }))
155
250
  <embedex source="packages/util-ts/examples/pipe.ts">
156
251
 
157
252
  ```ts
158
- import { equal } from "node:assert/strict";
253
+ import { strictEqual } from "node:assert/strict";
159
254
 
160
255
  import { pipe } from "@clipboard-health/util-ts";
161
256
 
@@ -167,7 +262,7 @@ const result = pipe(
167
262
  (array) => array.join(" "),
168
263
  );
169
264
 
170
- equal(result, "Hello World");
265
+ strictEqual(result, "Hello World");
171
266
  ```
172
267
 
173
268
  </embedex>
@@ -177,7 +272,7 @@ equal(result, "Hello World");
177
272
  <embedex source="packages/util-ts/examples/option.ts">
178
273
 
179
274
  ```ts
180
- import { equal } from "node:assert/strict";
275
+ import { strictEqual } from "node:assert/strict";
181
276
 
182
277
  import { option as O, pipe } from "@clipboard-health/util-ts";
183
278
 
@@ -199,7 +294,7 @@ const result = pipe(
199
294
  ),
200
295
  );
201
296
 
202
- equal(result, "Result is 0.1");
297
+ strictEqual(result, "Result is 0.1");
203
298
  ```
204
299
 
205
300
  </embedex>
@@ -209,7 +304,7 @@ equal(result, "Result is 0.1");
209
304
  <embedex source="packages/util-ts/examples/either.ts">
210
305
 
211
306
  ```ts
212
- import { equal } from "node:assert/strict";
307
+ import { strictEqual } from "node:assert/strict";
213
308
 
214
309
  import { either as E, pipe } from "@clipboard-health/util-ts";
215
310
 
@@ -231,7 +326,7 @@ const result = pipe(
231
326
  ),
232
327
  );
233
328
 
234
- equal(result, "Result is 0.1");
329
+ strictEqual(result, "Result is 0.1");
235
330
  ```
236
331
 
237
332
  </embedex>
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@clipboard-health/util-ts",
3
3
  "description": "TypeScript utilities.",
4
- "version": "3.8.1",
4
+ "version": "3.9.0",
5
5
  "bugs": "https://github.com/ClipboardHealth/core-utils/issues",
6
6
  "dependencies": {
7
7
  "tslib": "2.8.1"
package/src/index.d.ts CHANGED
@@ -6,4 +6,5 @@ export * from "./lib/functional";
6
6
  export * from "./lib/logger";
7
7
  export * from "./lib/nullish";
8
8
  export * from "./lib/strings";
9
+ export * from "./lib/strings/parseJson";
9
10
  export * from "./lib/types";
package/src/index.js CHANGED
@@ -9,5 +9,6 @@ tslib_1.__exportStar(require("./lib/functional"), exports);
9
9
  tslib_1.__exportStar(require("./lib/logger"), exports);
10
10
  tslib_1.__exportStar(require("./lib/nullish"), exports);
11
11
  tslib_1.__exportStar(require("./lib/strings"), exports);
12
+ tslib_1.__exportStar(require("./lib/strings/parseJson"), exports);
12
13
  tslib_1.__exportStar(require("./lib/types"), exports);
13
14
  //# sourceMappingURL=index.js.map
package/src/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../packages/util-ts/src/index.ts"],"names":[],"mappings":";;;AAAA,uDAA6B;AAC7B,2DAAiC;AACjC,uDAA6B;AAC7B,0DAAgC;AAChC,2DAAiC;AACjC,uDAA6B;AAC7B,wDAA8B;AAC9B,wDAA8B;AAC9B,sDAA4B"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../packages/util-ts/src/index.ts"],"names":[],"mappings":";;;AAAA,uDAA6B;AAC7B,2DAAiC;AACjC,uDAA6B;AAC7B,0DAAgC;AAChC,2DAAiC;AACjC,uDAA6B;AAC7B,wDAA8B;AAC9B,wDAA8B;AAC9B,kEAAwC;AACxC,sDAA4B"}
@@ -107,6 +107,16 @@ export declare class ServiceError extends Error {
107
107
  static fromZodError(error: ZodError, options?: {
108
108
  source?: ErrorSource;
109
109
  }): ServiceError;
110
+ /**
111
+ * Merges multiple ServiceErrors into a single ServiceError.
112
+ * Combines all issues from the input errors and uses the highest status code.
113
+ *
114
+ * @param error - The primary error
115
+ * @param errors - Additional ServiceErrors
116
+ * @returns New ServiceError containing all issues from input errors
117
+ */
118
+ static merge(error: unknown, ...errors: readonly unknown[]): ServiceError;
119
+ static merge(error: ServiceError, ...errors: readonly ServiceError[]): ServiceError;
110
120
  /**
111
121
  * Creates a ServiceError from a JSON:API error object
112
122
  * @see {@link https://jsonapi.org/format/#error-objects}
@@ -86,6 +86,17 @@ class ServiceError extends Error {
86
86
  source: options?.source,
87
87
  });
88
88
  }
89
+ static merge(error, ...errors) {
90
+ const firstError = error instanceof ServiceError ? error : ServiceError.fromUnknown(error);
91
+ if (errors.length === 0) {
92
+ return firstError;
93
+ }
94
+ const additionalErrors = errors.map((error) => error instanceof ServiceError ? error : ServiceError.fromUnknown(error));
95
+ return new ServiceError({
96
+ cause: firstError.cause ?? firstError,
97
+ issues: [...firstError.issues, ...additionalErrors.flatMap((error) => error.issues)],
98
+ });
99
+ }
89
100
  /**
90
101
  * Creates a ServiceError from a JSON:API error object
91
102
  * @see {@link https://jsonapi.org/format/#error-objects}
@@ -1 +1 @@
1
- {"version":3,"file":"serviceError.js","sourceRoot":"","sources":["../../../../../../packages/util-ts/src/lib/errors/serviceError.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"serviceError.js","sourceRoot":"","sources":["../../../../../../packages/util-ts/src/lib/errors/serviceError.ts"],"names":[],"mappings":"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"}
@@ -17,7 +17,7 @@ export type Right<A> = Readonly<{
17
17
  * <embedex source="packages/util-ts/examples/either.ts">
18
18
  *
19
19
  * ```ts
20
- * import { equal } from "node:assert/strict";
20
+ * import { strictEqual } from "node:assert/strict";
21
21
  *
22
22
  * import { either as E, pipe } from "@clipboard-health/util-ts";
23
23
  *
@@ -39,7 +39,7 @@ export type Right<A> = Readonly<{
39
39
  * ),
40
40
  * );
41
41
  *
42
- * equal(result, "Result is 0.1");
42
+ * strictEqual(result, "Result is 0.1");
43
43
  * ```
44
44
  *
45
45
  * </embedex>
@@ -12,7 +12,7 @@ export type Some<A> = Readonly<{
12
12
  * <embedex source="packages/util-ts/examples/option.ts">
13
13
  *
14
14
  * ```ts
15
- * import { equal } from "node:assert/strict";
15
+ * import { strictEqual } from "node:assert/strict";
16
16
  *
17
17
  * import { option as O, pipe } from "@clipboard-health/util-ts";
18
18
  *
@@ -34,7 +34,7 @@ export type Some<A> = Readonly<{
34
34
  * ),
35
35
  * );
36
36
  *
37
- * equal(result, "Result is 0.1");
37
+ * strictEqual(result, "Result is 0.1");
38
38
  * ```
39
39
  *
40
40
  * </embedex>
@@ -12,7 +12,7 @@ exports.pipe = pipe;
12
12
  * <embedex source="packages/util-ts/examples/pipe.ts">
13
13
  *
14
14
  * ```ts
15
- * import { equal } from "node:assert/strict";
15
+ * import { strictEqual } from "node:assert/strict";
16
16
  *
17
17
  * import { pipe } from "@clipboard-health/util-ts";
18
18
  *
@@ -24,7 +24,7 @@ exports.pipe = pipe;
24
24
  * (array) => array.join(" "),
25
25
  * );
26
26
  *
27
- * equal(result, "Hello World");
27
+ * strictEqual(result, "Hello World");
28
28
  * ```
29
29
  *
30
30
  * </embedex>
@@ -1,25 +1,158 @@
1
- import { either as E } from "@clipboard-health/util-ts";
2
1
  import { type SafeParseReturnType } from "zod";
3
2
  import { ServiceError, type ServiceErrorParams } from "../errors/serviceError";
3
+ import { type Either, type Left, type Right } from "./either";
4
+ export interface Success<A> {
5
+ readonly isSuccess: true;
6
+ readonly value: A;
7
+ }
8
+ export interface Failure<E> {
9
+ readonly isSuccess: false;
10
+ readonly error: E;
11
+ }
4
12
  /**
5
13
  * Represents the result of a service operation that may fail.
6
14
  * @template A The type of the successful result value
7
15
  */
8
- export type ServiceResult<A> = E.Either<ServiceError, A>;
16
+ export type ServiceResult<A> = Either<ServiceError, A> & (Success<A> | Failure<ServiceError>);
9
17
  /**
10
- * Creates a successful `ServiceResult` containing the provided value.
11
- *
12
- * @template A The type of the success value
13
- * @param value The value to wrap in a successful result
14
- * @returns A `ServiceResult` containing the success value
18
+ * Alias for {@link right} that duplicates the `right` property to `value` and `isRight` to
19
+ * `isSuccess`.
15
20
  */
16
21
  export declare function success<A>(value: A): ServiceResult<A>;
17
22
  /**
18
- * Creates a failed `ServiceResult` containing a `ServiceError`.
19
- *
20
- * @template A The type of the success value
21
- * @param params The parameters to create the `ServiceError`
22
- * @returns A `ServiceResult` containing the error
23
+ * Alias for {@link left} that duplicates the `left` property to `error` and `isLeft` to
24
+ * `isSuccess`.
23
25
  */
24
26
  export declare function failure<A = never>(params: ServiceErrorParams | ServiceError): ServiceResult<A>;
27
+ /**
28
+ * Alias for {@link isLeft}.
29
+ */
30
+ export declare function isFailure<A>(result: ServiceResult<A>): result is Left<ServiceError> & Failure<ServiceError>;
31
+ /**
32
+ * Alias for {@link isRight}.
33
+ */
34
+ export declare function isSuccess<A>(result: ServiceResult<A>): result is Right<A> & Success<A>;
35
+ /**
36
+ * Alias for {@link mapLeft}
37
+ */
38
+ export declare function mapFailure<G>(f: (left: ServiceError) => G): <A>(result: ServiceResult<A>) => Either<G, A>;
39
+ /**
40
+ * Converts a promise returning function into a ServiceResult by handling potential rejections.
41
+ * If the promise returning function resolves successfully, returns a success ServiceResult.
42
+ * If the promise rejects, calls the onError function to convert the error into a ServiceError.
43
+ *
44
+ * @template A The type of the value the promise resolves to
45
+ * @param f Function returning a Promise to execute. Passing a function allows catching synchronous throws
46
+ * @param onError Maps unknown errors to a ServiceError
47
+ * @returns A promise that resolves to a ServiceResult<A>
48
+ *
49
+ * @example
50
+ * <embedex source="packages/util-ts/examples/tryCatchAsync.ts">
51
+ *
52
+ * ```ts
53
+ * import { ok, strictEqual } from "node:assert/strict";
54
+ *
55
+ * import { isFailure, isSuccess, ServiceError, tryCatchAsync } from "@clipboard-health/util-ts";
56
+ *
57
+ * async function example() {
58
+ * const successResult = await tryCatchAsync(
59
+ * async () => {
60
+ * const response = await fetch("https://jsonplaceholder.typicode.com/posts/1");
61
+ * return (await response.json()) as { id: number };
62
+ * },
63
+ * (error) => new ServiceError(`Failed to fetch: ${String(error)}`),
64
+ * );
65
+ *
66
+ * ok(isSuccess(successResult));
67
+ * strictEqual(successResult.value.id, 1);
68
+ *
69
+ * const failureResult = await tryCatchAsync(
70
+ * async () => await Promise.reject(new Error("Network error")),
71
+ * (error) => new ServiceError(`Failed to fetch: ${String(error)}`),
72
+ * );
73
+ *
74
+ * ok(isFailure(failureResult));
75
+ * strictEqual(failureResult.error.issues[0]?.message, "Failed to fetch: Error: Network error");
76
+ * }
77
+ *
78
+ * // eslint-disable-next-line unicorn/prefer-top-level-await
79
+ * void example();
80
+ * ```
81
+ *
82
+ * </embedex>
83
+ */
84
+ export declare function tryCatchAsync<A>(f: () => Promise<A>, onError: (error: unknown) => ServiceError): Promise<ServiceResult<A>>;
85
+ /**
86
+ * Wraps a synchronous function that might throw into a ServiceResult.
87
+ * If the function executes successfully, returns a success ServiceResult.
88
+ * If the function throws, calls the onError function to convert the error into a ServiceError.
89
+ *
90
+ * @template A The return type of the function
91
+ * @param f The function to execute safely
92
+ * @param onError Function to convert unknown errors into ServiceError
93
+ * @returns A ServiceResult<A>
94
+ *
95
+ * @example
96
+ * <embedex source="packages/util-ts/examples/tryCatch.ts">
97
+ *
98
+ * ```ts
99
+ * import { ok, strictEqual } from "node:assert/strict";
100
+ *
101
+ * import { isFailure, isSuccess, parseJson, ServiceError, tryCatch } from "@clipboard-health/util-ts";
102
+ *
103
+ * const successResult = tryCatch(
104
+ * () => parseJson<{ name: string }>('{"name": "John"}'),
105
+ * (error) => new ServiceError(`Parse error: ${String(error)}`),
106
+ * );
107
+ *
108
+ * ok(isSuccess(successResult));
109
+ * strictEqual(successResult.value.name, "John");
110
+ *
111
+ * const failureResult = tryCatch(
112
+ * () => parseJson("invalid json"),
113
+ * (error) => new ServiceError(`Parse error: ${String(error)}`),
114
+ * );
115
+ *
116
+ * ok(isFailure(failureResult));
117
+ * ok(failureResult.error.issues[0]?.message?.includes("Parse error"));
118
+ * ```
119
+ *
120
+ * </embedex>
121
+ */
122
+ export declare function tryCatch<A>(f: () => A, onError: (error: unknown) => ServiceError): ServiceResult<A>;
123
+ /**
124
+ * Converts a Zod SafeParseReturnType into a ServiceResult.
125
+ * If the parse was successful, returns a success ServiceResult with the parsed data.
126
+ * If the parse failed, returns a failure ServiceResult with the validation errors.
127
+ *
128
+ * @template A The type of the successfully parsed value
129
+ * @param value The SafeParseReturnType from a Zod schema parse
130
+ * @returns A ServiceResult<A>
131
+ *
132
+ * @example
133
+ * <embedex source="packages/util-ts/examples/fromSafeParseReturnType.ts">
134
+ *
135
+ * ```ts
136
+ * import { ok, strictEqual } from "node:assert/strict";
137
+ *
138
+ * import { fromSafeParseReturnType, isFailure, isSuccess } from "@clipboard-health/util-ts";
139
+ * import { z } from "zod";
140
+ *
141
+ * const schema = z.object({ name: z.string(), age: z.number() });
142
+ *
143
+ * const validData = { name: "John", age: 30 };
144
+ * const successResult = fromSafeParseReturnType(schema.safeParse(validData));
145
+ *
146
+ * ok(isSuccess(successResult));
147
+ * strictEqual(successResult.value.name, "John");
148
+ *
149
+ * const invalidData = { name: "John", age: "thirty" };
150
+ * const failureResult = fromSafeParseReturnType(schema.safeParse(invalidData));
151
+ *
152
+ * ok(isFailure(failureResult));
153
+ * ok(failureResult.error.issues.length > 0);
154
+ * ```
155
+ *
156
+ * </embedex>
157
+ */
25
158
  export declare function fromSafeParseReturnType<A>(value: SafeParseReturnType<unknown, A>): ServiceResult<A>;
@@ -2,32 +2,202 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.success = success;
4
4
  exports.failure = failure;
5
+ exports.isFailure = isFailure;
6
+ exports.isSuccess = isSuccess;
7
+ exports.mapFailure = mapFailure;
8
+ exports.tryCatchAsync = tryCatchAsync;
9
+ exports.tryCatch = tryCatch;
5
10
  exports.fromSafeParseReturnType = fromSafeParseReturnType;
6
- const util_ts_1 = require("@clipboard-health/util-ts");
7
11
  const serviceError_1 = require("../errors/serviceError");
12
+ const either_1 = require("./either");
8
13
  /**
9
- * Creates a successful `ServiceResult` containing the provided value.
10
- *
11
- * @template A The type of the success value
12
- * @param value The value to wrap in a successful result
13
- * @returns A `ServiceResult` containing the success value
14
+ * Alias for {@link right} that duplicates the `right` property to `value` and `isRight` to
15
+ * `isSuccess`.
14
16
  */
15
17
  function success(value) {
16
- return util_ts_1.either.right(value);
18
+ const base = (0, either_1.right)(value);
19
+ Object.defineProperties(base, {
20
+ isSuccess: { get: () => true, enumerable: true },
21
+ value: { get: () => base.right, enumerable: true },
22
+ });
23
+ return Object.freeze(base);
17
24
  }
18
25
  /**
19
- * Creates a failed `ServiceResult` containing a `ServiceError`.
20
- *
21
- * @template A The type of the success value
22
- * @param params The parameters to create the `ServiceError`
23
- * @returns A `ServiceResult` containing the error
26
+ * Alias for {@link left} that duplicates the `left` property to `error` and `isLeft` to
27
+ * `isSuccess`.
24
28
  */
25
29
  function failure(params) {
26
- return util_ts_1.either.left(params instanceof serviceError_1.ServiceError ? params : new serviceError_1.ServiceError(params));
30
+ const error = params instanceof serviceError_1.ServiceError ? params : new serviceError_1.ServiceError(params);
31
+ const base = (0, either_1.left)(error);
32
+ Object.defineProperties(base, {
33
+ isSuccess: { get: () => false, enumerable: true },
34
+ error: { get: () => base.left, enumerable: true },
35
+ });
36
+ return Object.freeze(base);
37
+ }
38
+ /**
39
+ * Alias for {@link isLeft}.
40
+ */
41
+ function isFailure(result) {
42
+ return !result.isSuccess;
43
+ }
44
+ /**
45
+ * Alias for {@link isRight}.
46
+ */
47
+ function isSuccess(result) {
48
+ return result.isSuccess;
49
+ }
50
+ /**
51
+ * Alias for {@link mapLeft}
52
+ */
53
+ function mapFailure(f) {
54
+ return (0, either_1.mapLeft)(f);
55
+ }
56
+ /**
57
+ * Converts a promise returning function into a ServiceResult by handling potential rejections.
58
+ * If the promise returning function resolves successfully, returns a success ServiceResult.
59
+ * If the promise rejects, calls the onError function to convert the error into a ServiceError.
60
+ *
61
+ * @template A The type of the value the promise resolves to
62
+ * @param f Function returning a Promise to execute. Passing a function allows catching synchronous throws
63
+ * @param onError Maps unknown errors to a ServiceError
64
+ * @returns A promise that resolves to a ServiceResult<A>
65
+ *
66
+ * @example
67
+ * <embedex source="packages/util-ts/examples/tryCatchAsync.ts">
68
+ *
69
+ * ```ts
70
+ * import { ok, strictEqual } from "node:assert/strict";
71
+ *
72
+ * import { isFailure, isSuccess, ServiceError, tryCatchAsync } from "@clipboard-health/util-ts";
73
+ *
74
+ * async function example() {
75
+ * const successResult = await tryCatchAsync(
76
+ * async () => {
77
+ * const response = await fetch("https://jsonplaceholder.typicode.com/posts/1");
78
+ * return (await response.json()) as { id: number };
79
+ * },
80
+ * (error) => new ServiceError(`Failed to fetch: ${String(error)}`),
81
+ * );
82
+ *
83
+ * ok(isSuccess(successResult));
84
+ * strictEqual(successResult.value.id, 1);
85
+ *
86
+ * const failureResult = await tryCatchAsync(
87
+ * async () => await Promise.reject(new Error("Network error")),
88
+ * (error) => new ServiceError(`Failed to fetch: ${String(error)}`),
89
+ * );
90
+ *
91
+ * ok(isFailure(failureResult));
92
+ * strictEqual(failureResult.error.issues[0]?.message, "Failed to fetch: Error: Network error");
93
+ * }
94
+ *
95
+ * // eslint-disable-next-line unicorn/prefer-top-level-await
96
+ * void example();
97
+ * ```
98
+ *
99
+ * </embedex>
100
+ */
101
+ async function tryCatchAsync(f, onError) {
102
+ try {
103
+ return success(await f());
104
+ }
105
+ catch (error) {
106
+ return handleError(error, onError);
107
+ }
27
108
  }
109
+ /**
110
+ * Wraps a synchronous function that might throw into a ServiceResult.
111
+ * If the function executes successfully, returns a success ServiceResult.
112
+ * If the function throws, calls the onError function to convert the error into a ServiceError.
113
+ *
114
+ * @template A The return type of the function
115
+ * @param f The function to execute safely
116
+ * @param onError Function to convert unknown errors into ServiceError
117
+ * @returns A ServiceResult<A>
118
+ *
119
+ * @example
120
+ * <embedex source="packages/util-ts/examples/tryCatch.ts">
121
+ *
122
+ * ```ts
123
+ * import { ok, strictEqual } from "node:assert/strict";
124
+ *
125
+ * import { isFailure, isSuccess, parseJson, ServiceError, tryCatch } from "@clipboard-health/util-ts";
126
+ *
127
+ * const successResult = tryCatch(
128
+ * () => parseJson<{ name: string }>('{"name": "John"}'),
129
+ * (error) => new ServiceError(`Parse error: ${String(error)}`),
130
+ * );
131
+ *
132
+ * ok(isSuccess(successResult));
133
+ * strictEqual(successResult.value.name, "John");
134
+ *
135
+ * const failureResult = tryCatch(
136
+ * () => parseJson("invalid json"),
137
+ * (error) => new ServiceError(`Parse error: ${String(error)}`),
138
+ * );
139
+ *
140
+ * ok(isFailure(failureResult));
141
+ * ok(failureResult.error.issues[0]?.message?.includes("Parse error"));
142
+ * ```
143
+ *
144
+ * </embedex>
145
+ */
146
+ function tryCatch(f, onError) {
147
+ try {
148
+ return success(f());
149
+ }
150
+ catch (error) {
151
+ return handleError(error, onError);
152
+ }
153
+ }
154
+ /**
155
+ * Converts a Zod SafeParseReturnType into a ServiceResult.
156
+ * If the parse was successful, returns a success ServiceResult with the parsed data.
157
+ * If the parse failed, returns a failure ServiceResult with the validation errors.
158
+ *
159
+ * @template A The type of the successfully parsed value
160
+ * @param value The SafeParseReturnType from a Zod schema parse
161
+ * @returns A ServiceResult<A>
162
+ *
163
+ * @example
164
+ * <embedex source="packages/util-ts/examples/fromSafeParseReturnType.ts">
165
+ *
166
+ * ```ts
167
+ * import { ok, strictEqual } from "node:assert/strict";
168
+ *
169
+ * import { fromSafeParseReturnType, isFailure, isSuccess } from "@clipboard-health/util-ts";
170
+ * import { z } from "zod";
171
+ *
172
+ * const schema = z.object({ name: z.string(), age: z.number() });
173
+ *
174
+ * const validData = { name: "John", age: 30 };
175
+ * const successResult = fromSafeParseReturnType(schema.safeParse(validData));
176
+ *
177
+ * ok(isSuccess(successResult));
178
+ * strictEqual(successResult.value.name, "John");
179
+ *
180
+ * const invalidData = { name: "John", age: "thirty" };
181
+ * const failureResult = fromSafeParseReturnType(schema.safeParse(invalidData));
182
+ *
183
+ * ok(isFailure(failureResult));
184
+ * ok(failureResult.error.issues.length > 0);
185
+ * ```
186
+ *
187
+ * </embedex>
188
+ */
28
189
  function fromSafeParseReturnType(value) {
29
- return value.success
30
- ? success(value.data)
31
- : failure({ issues: value.error.issues.map(serviceError_1.toZodIssue) });
190
+ return value.success ? success(value.data) : failure(serviceError_1.ServiceError.fromZodError(value.error));
191
+ }
192
+ /**
193
+ * Handles possible throws in onError functions.
194
+ */
195
+ function handleError(error, onError) {
196
+ try {
197
+ return failure(onError(error));
198
+ }
199
+ catch (mappingError) {
200
+ return failure(serviceError_1.ServiceError.merge(error, mappingError));
201
+ }
32
202
  }
33
203
  //# sourceMappingURL=serviceResult.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"serviceResult.js","sourceRoot":"","sources":["../../../../../../packages/util-ts/src/lib/functional/serviceResult.ts"],"names":[],"mappings":";;AAkBA,0BAEC;AASD,0BAEC;AAED,0DAMC;AAvCD,uDAAwD;AAGxD,yDAA2F;AAQ3F;;;;;;GAMG;AACH,SAAgB,OAAO,CAAI,KAAQ;IACjC,OAAO,gBAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;AACxB,CAAC;AAED;;;;;;GAMG;AACH,SAAgB,OAAO,CAAY,MAAyC;IAC1E,OAAO,gBAAC,CAAC,IAAI,CAAC,MAAM,YAAY,2BAAY,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,2BAAY,CAAC,MAAM,CAAC,CAAC,CAAC;AACpF,CAAC;AAED,SAAgB,uBAAuB,CACrC,KAAsC;IAEtC,OAAO,KAAK,CAAC,OAAO;QAClB,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC;QACrB,CAAC,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,yBAAU,CAAC,EAAE,CAAC,CAAC;AAC9D,CAAC"}
1
+ {"version":3,"file":"serviceResult.js","sourceRoot":"","sources":["../../../../../../packages/util-ts/src/lib/functional/serviceResult.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Parses a JSON string and returns the parsed value with optional (unsafe) type assertion.
3
+ *
4
+ * @template T - The expected type of the parsed JSON value
5
+ * @param value - The JSON string to parse
6
+ * @param reviver - A function that transforms the result before returning it
7
+ * @returns The parsed JSON value cast to type T
8
+ * @throws {SyntaxError} When the JSON string is malformed
9
+ *
10
+ * @example
11
+ * ```typescript
12
+ * const data = parseJson<{ name: string }>('{"name": "John"}');
13
+ * console.log(data.name); // "John"
14
+ * ```
15
+ */
16
+ export declare function parseJson<T = unknown>(value: string, reviver?: (this: unknown, key: string, value: unknown) => unknown): T;
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parseJson = parseJson;
4
+ /**
5
+ * Parses a JSON string and returns the parsed value with optional (unsafe) type assertion.
6
+ *
7
+ * @template T - The expected type of the parsed JSON value
8
+ * @param value - The JSON string to parse
9
+ * @param reviver - A function that transforms the result before returning it
10
+ * @returns The parsed JSON value cast to type T
11
+ * @throws {SyntaxError} When the JSON string is malformed
12
+ *
13
+ * @example
14
+ * ```typescript
15
+ * const data = parseJson<{ name: string }>('{"name": "John"}');
16
+ * console.log(data.name); // "John"
17
+ * ```
18
+ */
19
+ function parseJson(value, reviver) {
20
+ return JSON.parse(value, reviver);
21
+ }
22
+ //# sourceMappingURL=parseJson.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parseJson.js","sourceRoot":"","sources":["../../../../../../packages/util-ts/src/lib/strings/parseJson.ts"],"names":[],"mappings":";;AAeA,8BAKC;AApBD;;;;;;;;;;;;;;GAcG;AACH,SAAgB,SAAS,CACvB,KAAa,EACb,OAAiE;IAEjE,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,OAAO,CAAM,CAAC;AACzC,CAAC"}
@@ -5,4 +5,4 @@
5
5
  * @returns A JSON string representation of the value
6
6
  * @throws {TypeError} When the value contains circular references
7
7
  */
8
- export declare function stringify(value: unknown): string;
8
+ export declare function stringify(value: unknown, replacer?: (this: unknown, key: string, value: unknown) => unknown, space?: string | number): string;
@@ -8,7 +8,10 @@ exports.stringify = stringify;
8
8
  * @returns A JSON string representation of the value
9
9
  * @throws {TypeError} When the value contains circular references
10
10
  */
11
- function stringify(value) {
12
- return JSON.stringify(value, (_, value) => typeof value === "bigint" ? String(value) : value);
11
+ function stringify(value, replacer, space) {
12
+ return JSON.stringify(value, replacer ?? defaultReplacer, space);
13
+ }
14
+ function defaultReplacer(_key, value) {
15
+ return typeof value === "bigint" ? String(value) : value;
13
16
  }
14
17
  //# sourceMappingURL=stringify.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"stringify.js","sourceRoot":"","sources":["../../../../../../packages/util-ts/src/lib/strings/stringify.ts"],"names":[],"mappings":";;AAOA,8BAIC;AAXD;;;;;;GAMG;AACH,SAAgB,SAAS,CAAC,KAAc;IACtC,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,CAAC,CAAC,EAAE,KAAc,EAAE,EAAE,CACjD,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAClD,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"stringify.js","sourceRoot":"","sources":["../../../../../../packages/util-ts/src/lib/strings/stringify.ts"],"names":[],"mappings":";;AAOA,8BAMC;AAbD;;;;;;GAMG;AACH,SAAgB,SAAS,CACvB,KAAc,EACd,QAAkE,EAClE,KAAuB;IAEvB,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,QAAQ,IAAI,eAAe,EAAE,KAAK,CAAC,CAAC;AACnE,CAAC;AAED,SAAS,eAAe,CAAgB,IAAY,EAAE,KAAc;IAClE,OAAO,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;AAC3D,CAAC"}