@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 CHANGED
@@ -7,75 +7,157 @@
7
7
  [![Donation](https://img.shields.io/badge/donate-liberapay-green)](https://liberapay.com/daiyam/donate)
8
8
  [![Donation](https://img.shields.io/badge/donate-paypal-green)](https://paypal.me/daiyam99)
9
9
 
10
- Simple `try/catch` wrapper returning Result
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
- Getting Started
13
- ---------------
12
+ Why xtry?
13
+ ---------
14
14
 
15
- With [node](http://nodejs.org) previously installed:
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
- npm install @zokugun/xtry
19
+ Installation
20
+ ------------
18
21
 
19
- Basic Example
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 { fails, value, error } = xatry(somePromise);
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, ok, type Result, xatry, xtry } from '@zokugun/xtry'
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 { fails, value, error } = xatry(somePromise);
50
+ async function foobar(): Result<number, FoobarError> {
51
+ const result = await xatry(fetchUserFromApi());
38
52
 
39
- if (fails) {
53
+ if(fails) {
40
54
  return err({ type: 'FOOBAR', message: 'The promise has failed...' });
41
55
  }
42
56
 
43
- return ok(value);
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 (result.fails) {
63
+ if(result.fails) {
50
64
  console.error(result.error.message);
51
- exit(1);
65
+
66
+ return;
52
67
  }
53
68
 
54
- console.log(value);
69
+ console.log(result.value);
55
70
  }
56
71
  ```
57
72
 
58
- API
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 Success<T> = {
63
- fails: false;
64
- value: T;
65
- error: null;
66
- };
67
- type Failure<E> = {
68
- fails: true;
69
- value: null;
70
- error: E;
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
- export function xtry<T, E>(func: () => Exclude<T, Promise<unknown>>, handler?: ((error: E) => void)): Result<T, E>;
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
- type Success<T> = {
2
- fails: false;
3
- value: T;
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 function xtry(func, handler) {
2
- try {
3
- const value = func();
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';
@@ -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
@@ -0,0 +1,17 @@
1
+ export function yok(value) {
2
+ return {
3
+ fails: false,
4
+ success: true,
5
+ value,
6
+ error: null,
7
+ };
8
+ }
9
+ export function yerr(type) {
10
+ return {
11
+ fails: false,
12
+ success: false,
13
+ type,
14
+ value: null,
15
+ error: null,
16
+ };
17
+ }
@@ -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
@@ -0,0 +1,14 @@
1
+ export function ok(value) {
2
+ return {
3
+ fails: false,
4
+ value,
5
+ error: null,
6
+ };
7
+ }
8
+ export function err(error) {
9
+ return {
10
+ fails: true,
11
+ value: null,
12
+ error,
13
+ };
14
+ }
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
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@zokugun/xtry",
3
3
  "description": "simple try/catch wrapper returning Result",
4
- "version": "0.1.0",
4
+ "version": "0.2.0",
5
5
  "author": {
6
6
  "name": "Baptiste Augrain",
7
7
  "email": "daiyam@zokugun.org"
package/lib/test.d.ts DELETED
@@ -1,4 +0,0 @@
1
- export type FoobarError = {
2
- type: 'FOOBAR';
3
- message: string;
4
- };
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();