@zokugun/xtry 0.1.0 → 0.2.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 +114 -32
- package/lib/index.d.ts +3 -16
- package/lib/index.js +3 -38
- package/lib/partial.d.ts +14 -0
- package/lib/partial.js +17 -0
- package/lib/result.d.ts +13 -0
- package/lib/result.js +14 -0
- package/lib/try.d.ts +3 -0
- package/lib/try.js +25 -0
- package/package.json +1 -1
- package/lib/test.d.ts +0 -4
- package/lib/test.js +0 -21
package/README.md
CHANGED
|
@@ -7,75 +7,157 @@
|
|
|
7
7
|
[](https://liberapay.com/daiyam/donate)
|
|
8
8
|
[](https://paypal.me/daiyam99)
|
|
9
9
|
|
|
10
|
-
Simple `try/catch`
|
|
10
|
+
Simple `try/catch` wrappers that always return a `Result` discriminated union, plus ready-made helpers (`ok`, `err`) for predictable control flow.
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
Why xtry?
|
|
13
|
+
---------
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
- Turn any sync or async function into an explicit `Result` object with zero dependencies.
|
|
16
|
+
- Strong TypeScript types guide your control flow (`fails` and tagged errors).
|
|
17
|
+
- Optional failure handlers let you log, meter, or mutate state exactly where the error occurs.
|
|
16
18
|
|
|
17
|
-
|
|
19
|
+
Installation
|
|
20
|
+
------------
|
|
18
21
|
|
|
19
|
-
|
|
20
|
-
|
|
22
|
+
```bash
|
|
23
|
+
npm install @zokugun/xtry
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Quick Start
|
|
27
|
+
-----------
|
|
21
28
|
|
|
22
29
|
```typescript
|
|
23
30
|
import { xatry } from '@zokugun/xtry'
|
|
24
31
|
|
|
25
|
-
const
|
|
32
|
+
const userResult = await xatry(fetchUserFromApi());
|
|
33
|
+
|
|
34
|
+
if(userResult.fails) {
|
|
35
|
+
console.error(userResult.error);
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
console.log('User loaded:', userResult.value);
|
|
26
40
|
```
|
|
27
41
|
|
|
28
42
|
Advanced Example
|
|
29
43
|
----------------
|
|
30
44
|
|
|
31
45
|
```typescript
|
|
32
|
-
import { err,
|
|
46
|
+
import { err, type Result, xatry, xtry } from '@zokugun/xtry'
|
|
33
47
|
|
|
34
48
|
export type FoobarError = { type: 'FOOBAR'; message: string };
|
|
35
49
|
|
|
36
|
-
function foobar(): Result<number, FoobarError> {
|
|
37
|
-
const
|
|
50
|
+
async function foobar(): Result<number, FoobarError> {
|
|
51
|
+
const result = await xatry(fetchUserFromApi());
|
|
38
52
|
|
|
39
|
-
if
|
|
53
|
+
if(fails) {
|
|
40
54
|
return err({ type: 'FOOBAR', message: 'The promise has failed...' });
|
|
41
55
|
}
|
|
42
56
|
|
|
43
|
-
return
|
|
57
|
+
return try(() => calculateAge(result.value));
|
|
44
58
|
}
|
|
45
59
|
|
|
46
|
-
function main() {
|
|
47
|
-
const result = foobar();
|
|
60
|
+
async function main() {
|
|
61
|
+
const result = await foobar();
|
|
48
62
|
|
|
49
|
-
if
|
|
63
|
+
if(result.fails) {
|
|
50
64
|
console.error(result.error.message);
|
|
51
|
-
|
|
65
|
+
|
|
66
|
+
return;
|
|
52
67
|
}
|
|
53
68
|
|
|
54
|
-
console.log(value);
|
|
69
|
+
console.log(result.value);
|
|
55
70
|
}
|
|
56
71
|
```
|
|
57
72
|
|
|
58
|
-
|
|
59
|
-
|
|
73
|
+
Partial Example
|
|
74
|
+
---------------
|
|
75
|
+
|
|
76
|
+
`YResult` extends the base `Result` union with a `success` flag so you can distinguish "valid failure" states from true errors.
|
|
60
77
|
|
|
61
78
|
```typescript
|
|
62
|
-
type
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
79
|
+
import { err, ok, yerr, yok, type YResult } from '@zokugun/xtry'
|
|
80
|
+
|
|
81
|
+
function toNumber(input: string): YResult<number, MyError, 'empty-string'> {
|
|
82
|
+
if(input.length > 0) {
|
|
83
|
+
return yerr('empty-string');
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const floatValue = Number.parseFloat(input);
|
|
87
|
+
|
|
88
|
+
if(Number.isNaN(floatValue)) {
|
|
89
|
+
return err({ type: '#VALUE!' });
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return yok(floatValue);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function add(_x: string, _y: number): Result<number, MyError> {
|
|
96
|
+
const x = toNumber(_x);
|
|
97
|
+
if(x.fails) {
|
|
98
|
+
return x;
|
|
99
|
+
}
|
|
100
|
+
if(!x.success) {
|
|
101
|
+
return ok(0);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const y = toNumber(_y);
|
|
105
|
+
if(y.fails) {
|
|
106
|
+
return y;
|
|
107
|
+
}
|
|
108
|
+
if(!y.success) {
|
|
109
|
+
return ok(0);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return x.value + y.value;
|
|
113
|
+
}
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
API reference
|
|
117
|
+
-------------
|
|
118
|
+
|
|
119
|
+
### Result helpers
|
|
120
|
+
|
|
121
|
+
```typescript
|
|
122
|
+
export type Success<T> = { fails: false; value: T; error: null };
|
|
123
|
+
export type Failure<E> = { fails: true; value: null; error: E };
|
|
72
124
|
export type Result<T, E> = Success<T> | Failure<E>;
|
|
73
|
-
|
|
74
|
-
export async function xatry<T, E>(func: (() => Exclude<T, Promise<unknown>>) | Promise<Exclude<T, Promise<unknown>>>, handler?: ((error: E) => void)): Promise<Result<T, E>>;
|
|
125
|
+
|
|
75
126
|
export function ok<T>(value: T): Success<T>;
|
|
76
127
|
export function err<E>(error: E): Failure<E>;
|
|
77
128
|
```
|
|
78
129
|
|
|
130
|
+
### Try helpers
|
|
131
|
+
|
|
132
|
+
```typescript
|
|
133
|
+
export function xtry<T, E>(func: () => Exclude<T, Promise<unknown>>, handler?: (error: E) => void): Result<T, E>;
|
|
134
|
+
export function xatry<T, E>(func: (() => Exclude<T, Promise<unknown>>) | Promise<Exclude<T, Promise<unknown>>>, handler?: (error: E) => void): Promise<Result<T, E>>;
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
Both helpers:
|
|
138
|
+
|
|
139
|
+
- execute the supplied function and capture thrown values;
|
|
140
|
+
- call the optional `handler` before turning that value into `err(error)`;
|
|
141
|
+
- never throw, making the return signature a reliable discriminated union.
|
|
142
|
+
|
|
143
|
+
### Partial helpers
|
|
144
|
+
|
|
145
|
+
```typescript
|
|
146
|
+
export type YSuccess<T> = Success<T> & { success: true };
|
|
147
|
+
export type YFailure<S> = { fails: false; success: false; type: S; value: null; error: null };
|
|
148
|
+
export type YResult<T, E, S> = Failure<E> | YSuccess<T> | YFailure<S>;
|
|
149
|
+
|
|
150
|
+
export function yok<T>(value: T): YSuccess<T>;
|
|
151
|
+
export function yerr<S>(type: S): YFailure<S>;
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
These helpers are useful when you need to separate soft rejections (`success: false`) from hard failures (`fails: true`).
|
|
155
|
+
|
|
156
|
+
Tips
|
|
157
|
+
----
|
|
158
|
+
|
|
159
|
+
- Narrow on `fails` first, then use other flags (`success`, custom `type` or `value`) for the happy-path branching.
|
|
160
|
+
|
|
79
161
|
Donations
|
|
80
162
|
---------
|
|
81
163
|
|
package/lib/index.d.ts
CHANGED
|
@@ -1,16 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
error: null;
|
|
5
|
-
};
|
|
6
|
-
type Failure<E> = {
|
|
7
|
-
fails: true;
|
|
8
|
-
value: null;
|
|
9
|
-
error: E;
|
|
10
|
-
};
|
|
11
|
-
export type Result<T, E> = Success<T> | Failure<E>;
|
|
12
|
-
export declare function xtry<T, E>(func: () => Exclude<T, Promise<unknown>>, handler?: ((error: E) => void)): Result<T, E>;
|
|
13
|
-
export declare function xatry<T, E>(func: (() => Exclude<T, Promise<unknown>>) | Promise<Exclude<T, Promise<unknown>>>, handler?: ((error: E) => void)): Promise<Result<T, E>>;
|
|
14
|
-
export declare function ok<T>(value: T): Success<T>;
|
|
15
|
-
export declare function err<E>(error: E): Failure<E>;
|
|
16
|
-
export {};
|
|
1
|
+
export * from './partial.js';
|
|
2
|
+
export * from './result.js';
|
|
3
|
+
export * from './try.js';
|
package/lib/index.js
CHANGED
|
@@ -1,38 +1,3 @@
|
|
|
1
|
-
export
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
return ok(value);
|
|
5
|
-
}
|
|
6
|
-
catch (error) {
|
|
7
|
-
if (handler) {
|
|
8
|
-
handler(error);
|
|
9
|
-
}
|
|
10
|
-
return err(error);
|
|
11
|
-
}
|
|
12
|
-
}
|
|
13
|
-
export async function xatry(func, handler) {
|
|
14
|
-
try {
|
|
15
|
-
const value = await (func instanceof Promise ? func : Promise.resolve().then(func));
|
|
16
|
-
return ok(value);
|
|
17
|
-
}
|
|
18
|
-
catch (error) {
|
|
19
|
-
if (handler) {
|
|
20
|
-
handler(error);
|
|
21
|
-
}
|
|
22
|
-
return err(error);
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
export function ok(value) {
|
|
26
|
-
return {
|
|
27
|
-
fails: false,
|
|
28
|
-
value,
|
|
29
|
-
error: null,
|
|
30
|
-
};
|
|
31
|
-
}
|
|
32
|
-
export function err(error) {
|
|
33
|
-
return {
|
|
34
|
-
fails: true,
|
|
35
|
-
value: null,
|
|
36
|
-
error,
|
|
37
|
-
};
|
|
38
|
-
}
|
|
1
|
+
export * from './partial.js';
|
|
2
|
+
export * from './result.js';
|
|
3
|
+
export * from './try.js';
|
package/lib/partial.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { type Failure, type Success } from './result.js';
|
|
2
|
+
export type YResult<T, E, S> = Failure<E> | YSuccess<T> | YFailure<S>;
|
|
3
|
+
export type YSuccess<T> = Success<T> & {
|
|
4
|
+
success: true;
|
|
5
|
+
};
|
|
6
|
+
export type YFailure<S> = {
|
|
7
|
+
fails: false;
|
|
8
|
+
success: false;
|
|
9
|
+
type: S;
|
|
10
|
+
value: null;
|
|
11
|
+
error: null;
|
|
12
|
+
};
|
|
13
|
+
export declare function yok<T>(value: T): YSuccess<T>;
|
|
14
|
+
export declare function yerr<S>(type: S): YFailure<S>;
|
package/lib/partial.js
ADDED
package/lib/result.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export type Success<T> = {
|
|
2
|
+
fails: false;
|
|
3
|
+
value: T;
|
|
4
|
+
error: null;
|
|
5
|
+
};
|
|
6
|
+
export type Failure<E> = {
|
|
7
|
+
fails: true;
|
|
8
|
+
value: null;
|
|
9
|
+
error: E;
|
|
10
|
+
};
|
|
11
|
+
export type Result<T, E> = Success<T> | Failure<E>;
|
|
12
|
+
export declare function ok<T>(value: T): Success<T>;
|
|
13
|
+
export declare function err<E>(error: E): Failure<E>;
|
package/lib/result.js
ADDED
package/lib/try.d.ts
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { type Result } from './result.js';
|
|
2
|
+
export declare function xtry<T, E>(func: () => Exclude<T, Promise<unknown>>, handler?: ((error: E) => void)): Result<T, E>;
|
|
3
|
+
export declare function xatry<T, E>(func: (() => Exclude<T, Promise<unknown>>) | Promise<Exclude<T, Promise<unknown>>>, handler?: ((error: E) => void)): Promise<Result<T, E>>;
|
package/lib/try.js
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { err, ok } from './result.js';
|
|
2
|
+
export function xtry(func, handler) {
|
|
3
|
+
try {
|
|
4
|
+
const value = func();
|
|
5
|
+
return ok(value);
|
|
6
|
+
}
|
|
7
|
+
catch (error) {
|
|
8
|
+
if (handler) {
|
|
9
|
+
handler(error);
|
|
10
|
+
}
|
|
11
|
+
return err(error);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
export async function xatry(func, handler) {
|
|
15
|
+
try {
|
|
16
|
+
const value = await (func instanceof Promise ? func : Promise.resolve().then(func));
|
|
17
|
+
return ok(value);
|
|
18
|
+
}
|
|
19
|
+
catch (error) {
|
|
20
|
+
if (handler) {
|
|
21
|
+
handler(error);
|
|
22
|
+
}
|
|
23
|
+
return err(error);
|
|
24
|
+
}
|
|
25
|
+
}
|
package/package.json
CHANGED
package/lib/test.d.ts
DELETED
package/lib/test.js
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import { err, ok, xatry } from './index.js';
|
|
2
|
-
import { exit } from 'node:process';
|
|
3
|
-
import { readFile } from "fs/promises";
|
|
4
|
-
async function readConfigFile() {
|
|
5
|
-
return readFile("./config.json", "utf-8").then((data) => JSON.parse(data).PORT);
|
|
6
|
-
}
|
|
7
|
-
async function foobar() {
|
|
8
|
-
const { fails, value } = await xatry(readConfigFile());
|
|
9
|
-
if (fails) {
|
|
10
|
-
return err({ type: 'FOOBAR', message: 'The promise has failed...' });
|
|
11
|
-
}
|
|
12
|
-
return ok(value);
|
|
13
|
-
}
|
|
14
|
-
async function main() {
|
|
15
|
-
const { fails, value } = await xatry(foobar);
|
|
16
|
-
if (fails) {
|
|
17
|
-
exit(1);
|
|
18
|
-
}
|
|
19
|
-
console.log(value);
|
|
20
|
-
}
|
|
21
|
-
main();
|