go-go-try 7.2.1 → 7.4.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/AGENTS.md CHANGED
@@ -5,25 +5,35 @@
5
5
  **go-go-try** is a TypeScript utility library for error handling inspired by Go's error handling pattern. It provides a functional approach to try/catch operations by returning a tuple `[error, value]` instead of throwing exceptions.
6
6
 
7
7
  - **Name**: go-go-try
8
- - **Version**: 6.2.0
8
+ - **Version**: 7.2.1
9
9
  - **License**: MIT
10
10
  - **Repository**: thelinuxlich/go-go-try
11
11
  - **Node.js Requirements**: >= 16
12
12
 
13
+ ### Key Features
14
+
15
+ - Zero runtime dependencies
16
+ - Dual package support (CommonJS and ESM)
17
+ - Full TypeScript support with precise type inference
18
+ - Support for sync/async functions, promises, and direct values
19
+ - Parallel execution utilities with optional concurrency control
20
+ - Tagged errors for discriminated union pattern matching
21
+
13
22
  ## Technology Stack
14
23
 
15
- - **Language**: TypeScript 5.8.3
24
+ - **Language**: TypeScript 5.9.3
16
25
  - **Build Tool**: [pkgroll](https://github.com/privatenumber/pkgroll) - A zero-config TypeScript package bundler
17
26
  - **Linter**: [Biome](https://biomejs.dev/) - Fast linter and formatter
18
27
  - **Test Framework**: [Vitest](https://vitest.dev/) - Vite-native unit test framework
19
28
  - **Type Testing**: [@ark/attest](https://github.com/arktypeio/arktype) - Runtime type assertions for TypeScript
29
+ - **Git Hooks**: [Husky](https://typicode.github.io/husky/) + [lint-staged](https://github.com/lint-staged/lint-staged)
20
30
 
21
31
  ## Project Structure
22
32
 
23
33
  ```
24
34
  .
25
35
  ├── src/
26
- │ ├── index.ts # Main source file - exports goTry, goTryRaw, and utility types
36
+ │ ├── index.ts # Main source file - exports all functions and types
27
37
  │ └── index.test.ts # Comprehensive test suite with runtime and type tests
28
38
  ├── dist/ # Build output (generated by pkgroll)
29
39
  │ ├── index.cjs # CommonJS build
@@ -32,10 +42,12 @@
32
42
  │ └── index.d.mts # ES Module type definitions
33
43
  ├── .github/workflows/
34
44
  │ └── main.yml # CI configuration for GitHub Actions
45
+ ├── .husky/
46
+ │ └── pre-commit # Git pre-commit hook (runs lint-staged)
35
47
  ├── .attest/ # Ark attest cache directory
36
48
  ├── package.json # Package configuration with dual CJS/ESM exports
37
49
  ├── tsconfig.json # TypeScript strict configuration
38
- ├── vitest.config.ts # Vitest configuration with type checking enabled
50
+ ├── vitest.config.ts # Vitest configuration with type checking and coverage
39
51
  ├── setupVitest.ts # Vitest global setup for @ark/attest
40
52
  └── README.md # User-facing documentation
41
53
  ```
@@ -51,17 +63,20 @@ npm run lint
51
63
 
52
64
  # Run the full test suite (build + lint + vitest)
53
65
  npm test
66
+
67
+ # Run tests with coverage report
68
+ npm run test:coverage
54
69
  ```
55
70
 
56
- The test script is a composite that:
71
+ The `npm test` script is a composite that:
57
72
  1. Builds the project
58
73
  2. Runs the linter
59
- 3. Executes Vitest tests
74
+ 3. Executes Vitest tests with type checking
60
75
 
61
76
  ## Code Style Guidelines
62
77
 
63
- - **Linter**: Biome is used for linting and formatting
64
- - **Configuration**: Uses Biome's default configuration (no biome.json present)
78
+ - **Linter**: Biome is used for linting and formatting with default configuration (no biome.json present)
79
+ - **Pre-commit**: Husky runs `lint-staged` which lints all staged `.ts` files via Biome
65
80
  - **Strict TypeScript**: The `tsconfig.json` enforces strict mode with additional checks:
66
81
  - `noUnusedLocals`: true
67
82
  - `noUnusedParameters`: true
@@ -78,8 +93,8 @@ Tests are co-located with source code in `src/index.test.ts` using Vitest.
78
93
 
79
94
  ### Test Types
80
95
 
81
- 1. **Runtime Tests**: Standard unit tests verifying behavior
82
- 2. **Type Tests**: Using `@ark/attest` to verify TypeScript type inference at runtime
96
+ 1. **Runtime Tests**: Standard unit tests verifying behavior using Vitest's `assert` and `test`
97
+ 2. **Type Tests**: Using `@ark/attest` to verify TypeScript type inference at runtime with `attest<T>(value)`
83
98
 
84
99
  ### Key Testing Patterns
85
100
 
@@ -107,33 +122,60 @@ npx vitest run
107
122
 
108
123
  # Run tests in watch mode (during development)
109
124
  npx vitest
125
+
126
+ # Run with coverage
127
+ npx vitest run --coverage
110
128
  ```
111
129
 
112
- ### Global Setup
130
+ ### Coverage Configuration
113
131
 
114
- The `setupVitest.ts` file configures `@ark/attest` for type assertions in tests.
132
+ Coverage is provided by `@vitest/coverage-v8` with reporters: text, json, html, and lcov. Excluded paths:
133
+ - `node_modules/`
134
+ - `dist/`
135
+ - `**/*.test.ts`
136
+ - `setupVitest.ts`
115
137
 
116
138
  ## API Design
117
139
 
118
140
  ### Core Functions
119
141
 
120
- - **`goTry<T>(value)`**: Returns `[string | undefined, T | undefined]` - error is the message string
121
- - **`goTryRaw<T, E>(value)`**: Returns `[E | undefined, T | undefined]` - error is the raw Error object
142
+ | Function | Description | Error Type |
143
+ |----------|-------------|------------|
144
+ | `goTry<T>(value)` | Returns `[string \| undefined, T \| undefined]` | Error message string |
145
+ | `goTryRaw<T, E>(value, ErrorClass?)` | Returns `[E \| undefined, T \| undefined]` | Raw Error object or tagged error |
146
+ | `goTryOr<T>(value, defaultValue)` | Returns `[string \| undefined, T]` | Error message with fallback default |
147
+ | `goTryAll<T>(items, options?)` | Parallel execution, returns `[errors[], results[]]` | Error message strings |
148
+ | `goTryAllRaw<T>(items, options?)` | Parallel execution, returns `[Error[], results[]]` | Raw Error objects |
149
+
150
+ ### Input Handling
151
+
152
+ All `goTry*` functions accept:
153
+ - Direct values
154
+ - Functions (sync or async)
155
+ - Promises
122
156
 
123
157
  ### Type Helpers
124
158
 
125
- - **`Result<E, T>`**: The tuple type `[E | undefined, T | undefined]`
159
+ - **`Result<E, T>`**: The tuple type `[E \| undefined, T \| undefined]`
126
160
  - **`Success<T>`**: `[undefined, T]`
127
161
  - **`Failure<E>`**: `[E, undefined]`
162
+ - **`TaggedError<T>`**: Interface for discriminated errors with `_tag` property
163
+ - **`TaggedUnion<T>`**: Creates union type from multiple tagged error classes
128
164
  - **`isSuccess(result)`**: Type guard to check if result is success
129
165
  - **`isFailure(result)`**: Type guard to check if result is failure
166
+ - **`success(value)`**: Helper to create Success tuple
167
+ - **`failure(error)`**: Helper to create Failure tuple
130
168
 
131
- ### Input Handling
169
+ ### Tagged Errors
132
170
 
133
- Both functions accept:
134
- - Direct values
135
- - Functions (sync or async)
136
- - Promises
171
+ The `taggedError(tag)` function creates error classes with a `_tag` property for discriminated union pattern matching:
172
+
173
+ ```typescript
174
+ const DatabaseError = taggedError('DatabaseError')
175
+ const err = new DatabaseError('connection failed')
176
+ // err._tag === 'DatabaseError'
177
+ // err instanceof Error === true
178
+ ```
137
179
 
138
180
  ## Dual Package Support
139
181
 
@@ -141,6 +183,7 @@ The package supports both CommonJS and ESM consumers:
141
183
 
142
184
  ```json
143
185
  {
186
+ "type": "module",
144
187
  "main": "./dist/index.cjs",
145
188
  "module": "./dist/index.mjs",
146
189
  "types": "./dist/index.d.mts",
@@ -153,17 +196,28 @@ The package supports both CommonJS and ESM consumers:
153
196
 
154
197
  ## CI/CD
155
198
 
156
- GitHub Actions workflow (`.github/workflows/main.yml`) runs on every push and PR:
199
+ GitHub Actions workflow (`.github/workflows/main.yml`):
157
200
 
158
- - Tests against Node.js versions: 12, 14, 16, 18
159
- - Uses `yarn install` and `yarn test`
201
+ ### Test Job
202
+ - Runs on every push and PR to `main`/`master`
203
+ - Tests against Node.js versions: 18, 20, 22
204
+ - Steps: checkout → setup Node → install → build → test with coverage
160
205
  - `fail-fast: false` to see results for all Node versions
206
+ - Coverage uploaded to Codecov (Node 22 only)
207
+
208
+ ### Publish Job
209
+ - Runs only on tag pushes (refs/tags/v*)
210
+ - Depends on successful test job
211
+ - Publishes to npm with provenance
212
+ - Requires `NPM_TOKEN` secret
161
213
 
162
214
  ## Security Considerations
163
215
 
164
216
  - Zero runtime dependencies - reduces supply chain attack surface
165
217
  - Dev dependencies are locked via `package-lock.json`
166
218
  - Uses `type: "module"` for native ESM support
219
+ - npm publishing uses provenance for supply chain security
220
+ - CI has minimal permissions (`contents: read`, `id-token: write`)
167
221
 
168
222
  ## Development Workflow
169
223
 
@@ -171,6 +225,7 @@ GitHub Actions workflow (`.github/workflows/main.yml`) runs on every push and PR
171
225
  2. Add/update tests in `src/index.test.ts`
172
226
  3. Run `npm test` to verify build, lint, and tests pass
173
227
  4. The CI will test against multiple Node.js versions on push
228
+ 5. To release: push a version tag (e.g., `v7.2.1`) to trigger npm publish
174
229
 
175
230
  ## Notes for AI Agents
176
231
 
@@ -180,3 +235,6 @@ GitHub Actions workflow (`.github/workflows/main.yml`) runs on every push and PR
180
235
  - Maintain dual CJS/ESM compatibility when making changes
181
236
  - Follow the existing function overload patterns for type inference
182
237
  - Error handling should preserve the Go-style tuple return pattern
238
+ - Use `taggedError()` for creating discriminated error types
239
+ - The `goTryAll` function supports both promise arrays and factory function arrays for lazy execution
240
+ - When adding new functions, include both runtime tests and type tests with `attest()`
package/README.md CHANGED
@@ -46,10 +46,10 @@ const [err, todos = []] = await goTry(fetchTodos()) // err is string | undefined
46
46
  if (err) sendToErrorTrackingService(err)
47
47
 
48
48
  // goTry extracts the error message from the error object, if you want the raw error object, use goTryRaw
49
- const [err, value] = goTryRaw(() => JSON.parse('{/}')) // err is Error | undefined, value is T | undefined
49
+ const [err, value] = goTryRaw(() => JSON.parse('{/}')) // err is UnknownError | undefined, value is T | undefined
50
50
 
51
51
  // fetch todos, fallback to empty array, send error to your error tracking service
52
- const [err, todos = []] = await goTryRaw(fetchTodos()) // err is Error | undefined
52
+ const [err, todos = []] = await goTryRaw(fetchTodos()) // err is UnknownError | undefined
53
53
  if (err) sendToErrorTrackingService(err)
54
54
  ```
55
55
 
@@ -233,10 +233,10 @@ type AppErrorVerbose =
233
233
 
234
234
  // Use in functions with typed error returns
235
235
  async function fetchUser(id: string): Promise<Result<AppError, User>> {
236
- const [dbErr, user] = await goTryRaw(queryDatabase(id), DatabaseError)
236
+ const [dbErr, user] = await goTryRaw(queryDatabase(id), { errorClass: DatabaseError })
237
237
  if (dbErr) return failure(dbErr)
238
238
 
239
- const [netErr, enriched] = await goTryRaw(enrichUserData(user!), NetworkError)
239
+ const [netErr, enriched] = await goTryRaw(enrichUserData(user!), { errorClass: NetworkError })
240
240
  if (netErr) return failure(netErr)
241
241
 
242
242
  return [undefined, enriched] as const
@@ -318,32 +318,51 @@ Executes a function, promise, or value and returns a Result type with error mess
318
318
  function goTry<T>(value: T | Promise<T> | (() => T | Promise<T>)): Result<string, T> | Promise<Result<string, T>>
319
319
  ```
320
320
 
321
- ### `goTryRaw<T, E>(value, ErrorClass?)`
321
+ ### `goTryRaw<T, E>(value, options?)`
322
322
 
323
323
  Like `goTry` but returns the raw Error object instead of just the message.
324
324
 
325
- Optionally accepts an error constructor to wrap caught errors - useful with `taggedError` for discriminated unions.
325
+ By default, errors are wrapped in `UnknownError` (a tagged error class). You can customize this behavior with the options object:
326
326
 
327
327
  ```ts
328
- // Without ErrorClass - err is Error | undefined
329
- function goTryRaw<T, E = Error>(value: T | Promise<T> | (() => T | Promise<T>)): Result<E, T> | Promise<Result<E, T>>
328
+ type GoTryRawOptions<E> =
329
+ | { errorClass: ErrorConstructor<E> } // Wrap ALL errors in this class
330
+ | { systemErrorClass: ErrorConstructor<E> } // Only wrap non-tagged errors
331
+ | {} // Use defaults
332
+ ```
333
+
334
+ > **Note:** `errorClass` and `systemErrorClass` are **mutually exclusive**. TypeScript will show an error if you try to pass both.
335
+ > - Use `errorClass` when you want all errors wrapped in a specific type
336
+ > - Use `systemErrorClass` when you want tagged errors to pass through and only wrap untagged errors
337
+
338
+ ```ts
339
+ // Without options - err is UnknownError | undefined
340
+ function goTryRaw<T>(value: T | Promise<T> | (() => T | Promise<T>)): Result<UnknownError, T> | Promise<Result<UnknownError, T>>
330
341
 
331
- // With ErrorClass - err is E | undefined (e.g., DatabaseError | undefined)
332
- function goTryRaw<T, E>(value: T | Promise<T> | (() => T | Promise<T>), ErrorClass: ErrorConstructor<E>): Result<E, T> | Promise<Result<E, T>>
342
+ // With options object - err is E | undefined
343
+ function goTryRaw<T, E>(value: T | Promise<T> | (() => T | Promise<T>), options: GoTryRawOptions<E>): Result<E, T> | Promise<Result<E, T>>
333
344
  ```
334
345
 
335
- **Example:**
346
+ **Examples:**
347
+
336
348
  ```ts
337
349
  const DatabaseError = taggedError('DatabaseError')
350
+ const NetworkError = taggedError('NetworkError')
338
351
 
339
- // Raw error (default)
352
+ // Default - errors wrapped in UnknownError
340
353
  const [err1, data1] = await goTryRaw(fetchData())
341
- // err1 is Error | undefined
354
+ // err1 is UnknownError | undefined
355
+ // err1?._tag === 'UnknownError'
342
356
 
343
- // Tagged error
344
- const [err2, data2] = await goTryRaw(fetchData(), DatabaseError)
357
+ // Options object - wrap all errors
358
+ const [err2, data2] = await goTryRaw(fetchData(), { errorClass: DatabaseError })
345
359
  // err2 is DatabaseError | undefined
346
- // err2._tag is 'DatabaseError' - enables discriminated unions
360
+ // err2?._tag === 'DatabaseError'
361
+
362
+ // Options object - systemErrorClass only wraps non-tagged errors
363
+ const [err3, data3] = await goTryRaw(fetchData(), { systemErrorClass: NetworkError })
364
+ // If fetchData throws a tagged error (e.g., DatabaseError), it passes through
365
+ // If fetchData throws a plain Error, it gets wrapped in NetworkError
347
366
  ```
348
367
 
349
368
  ### `goTryAll<T>(items, options?)`
@@ -453,6 +472,47 @@ console.log(err.name) // 'DatabaseError'
453
472
  console.log(err.cause) // originalError
454
473
  ```
455
474
 
475
+ ### `UnknownError`
476
+
477
+ A default tagged error class used by `goTryRaw` when no options are provided, or when `systemErrorClass` is not specified in the options object.
478
+
479
+ ```ts
480
+ import { UnknownError, goTryRaw } from 'go-go-try'
481
+
482
+ // Errors are automatically wrapped in UnknownError
483
+ const [err, data] = goTryRaw(() => {
484
+ throw new Error('something went wrong')
485
+ })
486
+
487
+ if (err) {
488
+ console.log(err._tag) // 'UnknownError'
489
+ console.log(err.message) // 'something went wrong'
490
+ console.log(err.cause) // original Error
491
+ }
492
+ ```
493
+
494
+ Since `UnknownError` is the default for `systemErrorClass`, you can distinguish between known tagged errors and unexpected system errors without specifying any options:
495
+
496
+ ```ts
497
+ const DatabaseError = taggedError('DatabaseError')
498
+
499
+ function fetchData() {
500
+ // Operations that might throw DatabaseError should use errorClass to wrap them
501
+ const [err1, data1] = goTryRaw(() => queryDatabase(), { errorClass: DatabaseError })
502
+
503
+ // Other operations use the default behavior - non-tagged errors become UnknownError
504
+ const [err2, data2] = goTryRaw(() => parseData(data1))
505
+ // err2 is UnknownError | undefined
506
+
507
+ // Now you can distinguish between known and unknown error types
508
+ if (err1) {
509
+ console.log('Known DB error:', err1.message)
510
+ } else if (err2) {
511
+ console.log('Unexpected error:', err2.message)
512
+ }
513
+ }
514
+ ```
515
+
456
516
  ### `TaggedUnion<T>`
457
517
 
458
518
  Creates a union type from multiple tagged error classes.
@@ -487,11 +547,11 @@ When using `goTryRaw` with different error classes in the same function, TypeScr
487
547
  // No explicit return type needed!
488
548
  async function fetchUserData(id: string) {
489
549
  // First operation might fail with DatabaseError
490
- const [dbErr, user] = await goTryRaw(queryDb(id), DatabaseError)
550
+ const [dbErr, user] = await goTryRaw(queryDb(id), { errorClass: DatabaseError })
491
551
  if (dbErr) return failure(dbErr) // returns Failure<DatabaseError>
492
552
 
493
553
  // Second operation might fail with NetworkError
494
- const [netErr, enriched] = await goTryRaw(enrichUser(user!), NetworkError)
554
+ const [netErr, enriched] = await goTryRaw(enrichUser(user!), { errorClass: NetworkError })
495
555
  if (netErr) return failure(netErr) // returns Failure<NetworkError>
496
556
 
497
557
  return success(enriched) // returns Success<User>
@@ -525,6 +585,12 @@ type Result<E, T> = Success<T> | Failure<E>
525
585
  type TaggedInstance<T> = T extends ErrorConstructor<infer E> ? E : never
526
586
  type TaggedUnion<T extends readonly ErrorConstructor<unknown>[]> =
527
587
  { [K in keyof T]: T[K] extends ErrorConstructor<infer E> ? E : never }[number]
588
+
589
+ // Options for goTryRaw (errorClass and systemErrorClass are mutually exclusive)
590
+ type GoTryRawOptions<E> =
591
+ | { errorClass: ErrorConstructor<E>; systemErrorClass?: never }
592
+ | { errorClass?: never; systemErrorClass: ErrorConstructor<E> }
593
+ | { errorClass?: never; systemErrorClass?: never }
528
594
  ```
529
595
 
530
596
  ## License
package/dist/index.cjs CHANGED
@@ -1,15 +1,5 @@
1
1
  'use strict';
2
2
 
3
- function taggedError(tag) {
4
- return class TaggedErrorClass extends Error {
5
- constructor(message, options) {
6
- super(message);
7
- this._tag = tag;
8
- this.name = tag;
9
- this.cause = options?.cause;
10
- }
11
- };
12
- }
13
3
  function isSuccess(result) {
14
4
  return result[0] === void 0;
15
5
  }
@@ -22,9 +12,101 @@ function success(value) {
22
12
  function failure(error) {
23
13
  return [error, void 0];
24
14
  }
15
+ function assertNever(value) {
16
+ throw new Error(`Unhandled case: ${String(value)}`);
17
+ }
18
+
19
+ function getErrorMessage(error) {
20
+ if (error === void 0) return "undefined";
21
+ if (typeof error === "string") return error;
22
+ if (typeof error === "object" && error !== null && "message" in error && typeof error.message === "string") {
23
+ return error.message;
24
+ }
25
+ try {
26
+ return JSON.stringify(error);
27
+ } catch {
28
+ return String(error);
29
+ }
30
+ }
31
+ function isPromise(value) {
32
+ return typeof value === "object" && value !== null && "then" in value && typeof value.then === "function";
33
+ }
34
+ function isError(value) {
35
+ return value instanceof Error;
36
+ }
25
37
  function resolveDefault(defaultValue) {
26
38
  return typeof defaultValue === "function" ? defaultValue() : defaultValue;
27
39
  }
40
+
41
+ function goTry(value) {
42
+ try {
43
+ const result = typeof value === "function" ? value() : value;
44
+ if (isPromise(result)) {
45
+ return result.then((resolvedValue) => success(resolvedValue)).catch((err) => failure(getErrorMessage(err)));
46
+ }
47
+ return success(result);
48
+ } catch (err) {
49
+ return failure(getErrorMessage(err));
50
+ }
51
+ }
52
+
53
+ function taggedError(tag) {
54
+ return class TaggedErrorClass extends Error {
55
+ constructor(message, options) {
56
+ super(message);
57
+ this._tag = tag;
58
+ this.name = tag;
59
+ this.cause = options?.cause;
60
+ }
61
+ };
62
+ }
63
+
64
+ const UnknownError = taggedError("UnknownError");
65
+
66
+ function isTaggedError(err) {
67
+ return isError(err) && "_tag" in err && typeof err._tag === "string";
68
+ }
69
+ function goTryRaw(value, options) {
70
+ const { errorClass, systemErrorClass } = options || {};
71
+ const actualSystemErrorClass = systemErrorClass ?? UnknownError;
72
+ const wrapError = (err) => {
73
+ if (errorClass) {
74
+ if (err === void 0) {
75
+ return new errorClass("undefined");
76
+ }
77
+ if (isError(err)) {
78
+ return new errorClass(err.message, { cause: err });
79
+ }
80
+ return new errorClass(String(err));
81
+ }
82
+ if (actualSystemErrorClass) {
83
+ if (isTaggedError(err)) {
84
+ return err;
85
+ }
86
+ if (err === void 0) {
87
+ return new actualSystemErrorClass("undefined");
88
+ }
89
+ if (isError(err)) {
90
+ return new actualSystemErrorClass(err.message, { cause: err });
91
+ }
92
+ return new actualSystemErrorClass(String(err));
93
+ }
94
+ if (err === void 0) {
95
+ return new Error("undefined");
96
+ }
97
+ return isError(err) ? err : new Error(String(err));
98
+ };
99
+ try {
100
+ const result = typeof value === "function" ? value() : value;
101
+ if (isPromise(result)) {
102
+ return result.then((resolvedValue) => success(resolvedValue)).catch((err) => failure(wrapError(err)));
103
+ }
104
+ return success(result);
105
+ } catch (err) {
106
+ return failure(wrapError(err));
107
+ }
108
+ }
109
+
28
110
  function goTryOr(value, defaultValue) {
29
111
  try {
30
112
  const result = typeof value === "function" ? value() : value;
@@ -36,6 +118,7 @@ function goTryOr(value, defaultValue) {
36
118
  return [getErrorMessage(err), resolveDefault(defaultValue)];
37
119
  }
38
120
  }
121
+
39
122
  async function runWithConcurrency(items, concurrency) {
40
123
  if (items.length === 0) {
41
124
  return [];
@@ -99,62 +182,22 @@ async function goTryAllRaw(items, options) {
99
182
  }
100
183
  return [errors, results];
101
184
  }
102
- function getErrorMessage(error) {
103
- if (error === void 0) return "undefined";
104
- if (typeof error === "string") return error;
105
- if (typeof error === "object" && error !== null && "message" in error && typeof error.message === "string") {
106
- return error.message;
107
- }
108
- try {
109
- return JSON.stringify(error);
110
- } catch {
111
- return String(error);
112
- }
113
- }
114
- function isPromise(value) {
115
- return typeof value === "object" && value !== null && "then" in value && typeof value.then === "function";
116
- }
117
- function isError(value) {
118
- return value instanceof Error;
119
- }
120
- function goTry(value) {
121
- try {
122
- const result = typeof value === "function" ? value() : value;
123
- if (isPromise(result)) {
124
- return result.then((resolvedValue) => success(resolvedValue)).catch((err) => failure(getErrorMessage(err)));
125
- }
126
- return success(result);
127
- } catch (err) {
128
- return failure(getErrorMessage(err));
129
- }
130
- }
131
- function goTryRaw(value, ErrorClass) {
132
- const wrapError = (err) => {
133
- if (ErrorClass) {
134
- if (err === void 0) {
135
- return new ErrorClass("undefined");
136
- }
137
- if (isError(err)) {
138
- return new ErrorClass(err.message, { cause: err });
139
- }
140
- return new ErrorClass(String(err));
141
- }
142
- if (err === void 0) {
143
- return new Error("undefined");
185
+
186
+ function assert(condition, errorOrClass, message) {
187
+ if (!condition) {
188
+ if (typeof errorOrClass === "string") {
189
+ throw new Error(errorOrClass);
144
190
  }
145
- return isError(err) ? err : new Error(String(err));
146
- };
147
- try {
148
- const result = typeof value === "function" ? value() : value;
149
- if (isPromise(result)) {
150
- return result.then((resolvedValue) => success(resolvedValue)).catch((err) => failure(wrapError(err)));
191
+ if (typeof errorOrClass === "function" && message !== void 0) {
192
+ throw new errorOrClass(message);
151
193
  }
152
- return success(result);
153
- } catch (err) {
154
- return failure(wrapError(err));
194
+ throw errorOrClass;
155
195
  }
156
196
  }
157
197
 
198
+ exports.UnknownError = UnknownError;
199
+ exports.assert = assert;
200
+ exports.assertNever = assertNever;
158
201
  exports.failure = failure;
159
202
  exports.goTry = goTry;
160
203
  exports.goTryAll = goTryAll;