@ntangled/kit 0.0.0-alpha.6 → 0.0.1

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
@@ -1,59 +1,209 @@
1
1
  # @ntangled/kit
2
2
 
3
- A TypeScript utililty package.
3
+ A lightweight, zero-dependency utility for TypeScript. Works seamlessly in **Node.js**, **Bun** and the **Browser**.
4
4
 
5
- ## Safe
5
+ > Disclaimer: This is my first "serious" npm lib. There will be typos, bad formulated paragraphs and more - and you are more than welcome to notify me.
6
6
 
7
- The `safe.ts` module provides utility functions for safely executing synchronous and asynchronous code, ensuring that errors are handled gracefully and never thrown. Instead, each function returns a tuple of `[error, result]`, making error handling explicit and consistent.
7
+ ## Features
8
8
 
9
- > [!IMPORTANT]
10
- > Throwing `null` will result in a NullError in the error entry. Use `instance of NullError` if you expect `null` to be thrown.
9
+ - **Universal**: Works in any environment (Node, Bun, Deno, Browsers).
11
10
 
12
- ### Utilities
11
+ - **Dual-Build**: Ships with ESM and CommonJS support.
13
12
 
14
- - **NullError**: Custom error thrown when a `null` value is encountered where not expected.
15
- - **px**: Safely executes an async callback, returns `[error, result]`.
16
- - **rx**: Safely executes a sync callback, returns `[error, result]`.
17
- - **pw**: Wraps an async function, returns a new function that always returns `[error, result]`.
18
- - **rw**: Wraps a sync function, returns a new function that always returns `[error, result]`.
13
+ - **Type-Safe**: Full TypeScript support with inference for both sync and async functions.
19
14
 
20
- ### Usage
15
+ - **Tiny**: Zero dependencies and minimal footprint.
21
16
 
22
- #### px (Promise Executor)
17
+ ## Installation
18
+
19
+ ```bash
20
+ npm install @ntangled/kit
21
+ ```
22
+
23
+ ```bash
24
+ yarn add @ntangled/kit
25
+ ```
26
+
27
+ ```bash
28
+ bun add @ntangled/kit
29
+ ```
30
+
31
+ ```bash
32
+ pnpm install @ntangled/kit
33
+ ```
34
+
35
+ ## Documentation
36
+
37
+ ### `s` (Safe)
38
+
39
+ A lightweight utility for **Go-style error handling** in TypeScript.
40
+
41
+ Stop nesting your code in `try/catch` blocks. Use `w` (wrap) and `x` (execute) to handle errors as values.
42
+
43
+ #### Usage
44
+
45
+ You can import the core utilities from the main entry point or directly from the `safe` subpath. Combine this with `Guard clauses` (_fast exist_) and your error handling becomes much easier.
46
+
47
+ > Guard clauses are awesome and makes the code more readable and easier to extend. It is not a library but a design pattern you can learn in less than a minute.
23
48
 
24
49
  ```ts
25
- const [err, data] = await px(async () => await fetchData());
26
- if (err) {
27
- // handle error
50
+ import { x, w } from '@ntangled/kit/safe';
51
+ // or
52
+ import { s } from '@ntangled/kit';
53
+ ```
54
+
55
+ #### Simple Example
56
+
57
+ ```ts
58
+ import { x } from '@ntangled/kit/safe';
59
+
60
+ const foo = () => {
61
+ const [error, value] = x(() => 'Hello safe' as const);
62
+
63
+ /*
64
+ type error is : {} | null
65
+ {} meaning everything sinde an error can be every thing
66
+
67
+ type value is : null | 'Hello safe'
68
+ */
69
+
70
+ if (error !== null) return console.error(error);
71
+
72
+ /*
73
+ type error is : null
74
+ type value is : 'Hello safe'
75
+ */
76
+
77
+ console.log(result.foo); // 'bar'
78
+ };
79
+
80
+ foo();
81
+ ```
82
+
83
+ > Note on conditions: The `error` must explicitly be match to not `null` because of the type system.
84
+
85
+ > Note on return: The early return `Guard clause` is what make the type system work.
86
+
87
+ If the function you call doesn't return anything you can simply just omit the second entry (`value`). The error will still be return so you can handle it.
88
+
89
+ #### `x` (Execute)
90
+
91
+ Executes a function immediately and returns a `[error, result]` tuple.
92
+
93
+ **Synchronous**
94
+
95
+ ```ts
96
+ const [error, result] = x(() => JSON.parse('{"foo": "bar"}'));
97
+
98
+ if (error !== null) return console.error(error);
99
+ console.log(result.foo); // 'bar'
100
+ ```
101
+
102
+ **Asynchronous**
103
+
104
+ ```ts
105
+ const [fetchErr, response] = await x(() => fetch('https://api.example.com'));
106
+ if (fetchErr) {
107
+ // Handle network error
28
108
  }
29
109
  ```
30
110
 
31
- #### rx (Result Executor)
111
+ #### `w` (Wrap)
112
+
113
+ Wraps a function and returns a new version of that function that always returns a `[error, result]` tuple. This is perfect for defining "safe" versions of existing functions.
114
+
115
+ Wrapping is useful for functions that already are defined like core JavaScript functions like `JSON.parse`, third-party libraries or your own functions if they already are used and rewriting them is hard do to the other implementations.
32
116
 
33
117
  ```ts
34
- const [err, value] = rx(() => computeValue());
35
- if (err) {
36
- // handle error
118
+ const safeJsonParse = w(JSON.parse);
119
+
120
+ const [err, data] = safeJsonParse('invalid json');
121
+ // err is now a SyntaxError instead of throwing
122
+ ```
123
+
124
+ #### Handling Errors
125
+
126
+ If you have a function that can trow multiple different errors and you want to handle them accordingly you can use the `instanceof` operator. By using this operator TypeScript knows the type within the scope so you can work with its properties.
127
+
128
+ ```ts
129
+ import { x, NullError } from '@ntangled/kit/safe';
130
+
131
+ const foo () => {
132
+ const [error] = x(bar); // bar is just a random function name
133
+
134
+ if (error !== null) {
135
+ // in this scope we know error exits
136
+
137
+ if (error instanceof NullError) return console.error('A null was thrown');
138
+ if (error instanceof TypeError) return console.error('A TypeError was thrown');
139
+ // ...
140
+
141
+ return console.error('A unknown error was thrown');
142
+ }
143
+
144
+ // if there is no error you can safely continue your code here...
145
+ }
146
+ ```
147
+
148
+ **Making a custom error**
149
+
150
+ Making custom errors can be useful. With this you can add properties to the error and then access them after using the `instanceof` operator.
151
+
152
+ ```ts
153
+ export class ValueError extends Error {
154
+ constructor(message: string, value: string) {
155
+ super(message);
156
+ this.name = 'ValueError';
157
+
158
+ // this is a custom value added when the error is thrown
159
+ this.value = value;
160
+
161
+ // this makes the instanceof work
162
+ Object.setPrototypeOf(this, ValueError.prototype);
163
+ }
37
164
  }
165
+
166
+ // usage
167
+ throw new ValueError('message arg', 'value arg');
38
168
  ```
39
169
 
40
- #### pw (Promise Wrapper)
170
+ #### Handling `null` Errors
171
+
172
+ If your code throws `null` (which is technically possible in JS), this library catches it and returns a specific `NullError` class to ensure your error variable is always an actual object.
41
173
 
42
174
  ```ts
43
- const safeFetch = pw(fetchData);
44
- const [err, data] = await safeFetch(arg1, arg2);
175
+ import { NullError } from '@ntangled/kit/safe';
176
+
177
+ const [error] = x(() => {
178
+ throw null;
179
+ });
180
+
181
+ console.log(error instanceof NullError); // true
45
182
  ```
46
183
 
47
- #### rw (Result Wrapper)
184
+ #### Why use this?
185
+
186
+ Standard `try/catch` blocks create extra indentation and scope-lock your variables:
187
+
188
+ **The old way:**
48
189
 
49
190
  ```ts
50
- const safeCompute = rw(computeValue);
51
- const [err, value] = safeCompute(arg1, arg2);
191
+ let data;
192
+
193
+ try {
194
+ data = JSON.parse(str);
195
+ } catch (error) {
196
+ // handle error
197
+ }
198
+
199
+ console.log(data); // data is available here, but the code is messy
52
200
  ```
53
201
 
54
- ### Why use Safe utilities?
202
+ **The `safe` way:**
203
+
204
+ ```ts
205
+ const [error, data] = x(() => JSON.parse(str));
206
+ if (error) return handle(error);
55
207
 
56
- - Avoids try/catch boilerplate.
57
- - Makes error handling explicit and consistent.
58
- - Works for both sync and async functions.
59
- - Prevents uncaught exceptions and null errors.
208
+ console.log(data); // Clean, flat, and type-safe
209
+ ```
package/dist/safe.d.mts CHANGED
@@ -8,8 +8,54 @@ import { NonNull } from './types.mjs';
8
8
  declare class NullError extends Error {
9
9
  constructor();
10
10
  }
11
+ /**
12
+ * Wraps a callback function (sync or async) and returns a function that executes the callback,
13
+ * capturing errors and returning them in a tuple. For async callbacks, errors are caught and returned
14
+ * as the first element of the tuple, and the resolved value as the second. For sync callbacks, errors
15
+ * are caught and returned similarly.
16
+ *
17
+ * @template Callback - The type of the callback function.
18
+ * @param callback - The callback function to wrap.
19
+ * @returns A function that, when called, returns a tuple: [error, result]. If no error occurs, error is null.
20
+ * For async callbacks, returns a Promise resolving to the tuple.
21
+ *
22
+ * @example
23
+ * // Synchronous usage
24
+ * const safeAdd = w((a: number, b: number) => a + b);
25
+ * const [err, sum] = safeAdd(1, 2);
26
+ *
27
+ * // Asynchronous usage
28
+ * const safeFetch = w(async (url: string) => fetch(url));
29
+ * const [err, response] = await safeFetch('https://example.com');
30
+ */
11
31
  declare function w<Callback extends (...params: any[]) => Promise<any>>(callback: Callback): (...params: Parameters<Callback>) => Promise<[NonNull, null] | [null, Awaited<ReturnType<Callback>>]>;
12
32
  declare function w<Callback extends (...params: any[]) => any>(callback: Callback): (...params: Parameters<Callback>) => [NonNull, null] | [null, ReturnType<Callback>];
33
+ /**
34
+ * Executes a callback function (sync or async) immediately, capturing errors and returning them in a tuple.
35
+ * You can pass an already defined function (e.g. x(foo())) or an anonymous function (e.g. x(() => 'hello world')).
36
+ * Both can be async.
37
+ *
38
+ * @template Callback - The type of the callback function.
39
+ * @param callback - The callback function to execute.
40
+ * @param params - Parameters to pass to the callback function.
41
+ * @returns A tuple: [error, result]. If no error occurs, error is null.
42
+ * For async callbacks, returns a Promise resolving to the tuple.
43
+ *
44
+ * @example
45
+ * // Synchronous usage with anonymous function
46
+ * const [err, result] = x(() => 'hello world');
47
+ *
48
+ * // Synchronous usage with defined function
49
+ * function foo() { return 42; }
50
+ * const [err, result] = x(foo);
51
+ *
52
+ * // Asynchronous usage with anonymous function
53
+ * const [err, result] = await x(async () => await fetch('https://example.com'));
54
+ *
55
+ * // Asynchronous usage with defined function
56
+ * async function fetchData() { return await fetch('https://example.com'); }
57
+ * const [err, result] = await x(fetchData);
58
+ */
13
59
  declare function x<Callback extends (...params: any[]) => Promise<any>>(callback: Callback, ...params: Parameters<Callback>): Promise<[NonNull, null] | [null, Awaited<ReturnType<Callback>>]>;
14
60
  declare function x<Callback extends (...params: any[]) => any>(callback: Callback, ...params: Parameters<Callback>): [NonNull, null] | [null, ReturnType<Callback>];
15
61
 
package/dist/safe.d.ts CHANGED
@@ -8,8 +8,54 @@ import { NonNull } from './types.js';
8
8
  declare class NullError extends Error {
9
9
  constructor();
10
10
  }
11
+ /**
12
+ * Wraps a callback function (sync or async) and returns a function that executes the callback,
13
+ * capturing errors and returning them in a tuple. For async callbacks, errors are caught and returned
14
+ * as the first element of the tuple, and the resolved value as the second. For sync callbacks, errors
15
+ * are caught and returned similarly.
16
+ *
17
+ * @template Callback - The type of the callback function.
18
+ * @param callback - The callback function to wrap.
19
+ * @returns A function that, when called, returns a tuple: [error, result]. If no error occurs, error is null.
20
+ * For async callbacks, returns a Promise resolving to the tuple.
21
+ *
22
+ * @example
23
+ * // Synchronous usage
24
+ * const safeAdd = w((a: number, b: number) => a + b);
25
+ * const [err, sum] = safeAdd(1, 2);
26
+ *
27
+ * // Asynchronous usage
28
+ * const safeFetch = w(async (url: string) => fetch(url));
29
+ * const [err, response] = await safeFetch('https://example.com');
30
+ */
11
31
  declare function w<Callback extends (...params: any[]) => Promise<any>>(callback: Callback): (...params: Parameters<Callback>) => Promise<[NonNull, null] | [null, Awaited<ReturnType<Callback>>]>;
12
32
  declare function w<Callback extends (...params: any[]) => any>(callback: Callback): (...params: Parameters<Callback>) => [NonNull, null] | [null, ReturnType<Callback>];
33
+ /**
34
+ * Executes a callback function (sync or async) immediately, capturing errors and returning them in a tuple.
35
+ * You can pass an already defined function (e.g. x(foo())) or an anonymous function (e.g. x(() => 'hello world')).
36
+ * Both can be async.
37
+ *
38
+ * @template Callback - The type of the callback function.
39
+ * @param callback - The callback function to execute.
40
+ * @param params - Parameters to pass to the callback function.
41
+ * @returns A tuple: [error, result]. If no error occurs, error is null.
42
+ * For async callbacks, returns a Promise resolving to the tuple.
43
+ *
44
+ * @example
45
+ * // Synchronous usage with anonymous function
46
+ * const [err, result] = x(() => 'hello world');
47
+ *
48
+ * // Synchronous usage with defined function
49
+ * function foo() { return 42; }
50
+ * const [err, result] = x(foo);
51
+ *
52
+ * // Asynchronous usage with anonymous function
53
+ * const [err, result] = await x(async () => await fetch('https://example.com'));
54
+ *
55
+ * // Asynchronous usage with defined function
56
+ * async function fetchData() { return await fetch('https://example.com'); }
57
+ * const [err, result] = await x(fetchData);
58
+ */
13
59
  declare function x<Callback extends (...params: any[]) => Promise<any>>(callback: Callback, ...params: Parameters<Callback>): Promise<[NonNull, null] | [null, Awaited<ReturnType<Callback>>]>;
14
60
  declare function x<Callback extends (...params: any[]) => any>(callback: Callback, ...params: Parameters<Callback>): [NonNull, null] | [null, ReturnType<Callback>];
15
61
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ntangled/kit",
3
- "version": "0.0.0-alpha.6",
3
+ "version": "0.0.1",
4
4
  "description": "A TypeScript utility package for safe function execution and other helpers.",
5
5
  "author": "Stephan D. <stephan.mdd@gmail.com>",
6
6
  "homepage": "https://github.com/ntangled/kit#readme",