nalloc 0.2.0 → 0.2.2

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.
Files changed (2) hide show
  1. package/README.md +61 -28
  2. package/package.json +17 -9
package/README.md CHANGED
@@ -44,7 +44,7 @@ npm install nalloc
44
44
  ## Quick start
45
45
 
46
46
  ```ts
47
- import { Option, Result, ok, err, none, safeTry, unwrap } from 'nalloc';
47
+ import { Option, Result, ok, err, none, pipe, gen } from 'nalloc';
48
48
 
49
49
  // Option: the value IS the Option
50
50
  const port = Option.fromNullable(process.env.PORT);
@@ -58,12 +58,19 @@ const data = Result.match(
58
58
  error => ({ fallback: true })
59
59
  );
60
60
 
61
- // safeTry: Rust-like ? operator
62
- const result = safeTry(() => {
63
- const a = unwrap(parseNumber('10'));
64
- const b = unwrap(parseNumber('5'));
61
+ // gen: Rust-like ? operator with type-safe errors
62
+ const result = gen(function*($) {
63
+ const a = yield* $(parseNumber('10'));
64
+ const b = yield* $(parseNumber('5'));
65
65
  return a + b;
66
- }); // Ok(15) or Err(...)
66
+ }); // Result<number, ParseError>
67
+
68
+ // pipe: left-to-right composition
69
+ const userId = pipe(
70
+ Result.tryCatch(() => JSON.parse(raw)),
71
+ r => Result.map(r, data => data.userId),
72
+ r => Result.unwrapOr(r, 0),
73
+ );
67
74
  ```
68
75
 
69
76
  ## How it works
@@ -103,8 +110,8 @@ import * as O from 'fp-ts/Option';
103
110
  pipe(O.some(42), O.map(x => x * 2));
104
111
 
105
112
  // nalloc - simpler, faster
106
- import { Option } from 'nalloc';
107
- Option.map(42, x => x * 2); // value IS the Option
113
+ import { Option, pipe } from 'nalloc';
114
+ pipe(42, v => Option.map(v, x => x * 2)); // built-in pipe, value IS the Option
108
115
  ```
109
116
 
110
117
  ### From oxide.ts
@@ -146,7 +153,7 @@ Option.unwrapOr(42, 0); // value IS the Option
146
153
  The API mirrors Rust's `Option` and `Result`:
147
154
 
148
155
  ```ts
149
- import { Option, Result, ok, err, none, safeTry, unwrap } from 'nalloc';
156
+ import { Option, Result, ok, err, none, gen } from 'nalloc';
150
157
 
151
158
  // Rust: Some(42).map(|x| x * 2)
152
159
  Option.map(42, x => x * 2);
@@ -157,9 +164,9 @@ Result.andThen(ok(42), x => x > 0 ? ok(x) : err('negative'));
157
164
  // Rust: result.unwrap_or(0)
158
165
  Result.unwrapOr(result, 0);
159
166
 
160
- // Rust: let value = try!(get_value()) / let value = get_value()?
161
- const value = safeTry(() => {
162
- const a = unwrap(getValue());
167
+ // Rust: let value = get_value()?
168
+ const value = gen(function*($) {
169
+ const a = yield* $(getValue());
163
170
  return a + 1;
164
171
  });
165
172
  ```
@@ -205,7 +212,7 @@ const maybeUser = await Option.fromPromise(fetchUserById(id));
205
212
  A `Result<T, E>` is either `Ok<T>` (the value itself) or `Err<E>` (a wrapper).
206
213
 
207
214
  ```ts
208
- import { Result, ok, err, safeTry, safeTryAsync, unwrap } from 'nalloc';
215
+ import { Result, ok, err, gen, genAsync, pipe } from 'nalloc';
209
216
 
210
217
  // Wrap throwing functions
211
218
  const parsed = Result.tryCatch(
@@ -213,24 +220,35 @@ const parsed = Result.tryCatch(
213
220
  e => 'invalid json'
214
221
  );
215
222
 
216
- // safeTry: Rust-like ? operator for imperative error handling
217
- const result = safeTry(() => {
218
- const config = unwrap(parseConfig(raw));
219
- const db = unwrap(connectDb(config.url));
223
+ // gen: Rust-like ? operator with preserved error types
224
+ const result = gen(function*($) {
225
+ const config = yield* $(parseConfig(raw));
226
+ const db = yield* $(connectDb(config.url));
220
227
  return db.query('SELECT 1');
221
- });
228
+ }); // Result<QueryResult, ConfigError | DbError>
222
229
 
223
- // Async safeTry
224
- const data = await safeTryAsync(async () => {
225
- const res = unwrap(await fetchUser(id));
226
- const posts = unwrap(await fetchPosts(res.id));
230
+ // Async gen
231
+ const data = await genAsync(async function*($) {
232
+ const res = yield* $(await Result.fromPromise(fetchUser(id)));
233
+ const posts = yield* $(await Result.fromPromise(fetchPosts(res.id)));
227
234
  return { user: res, posts };
228
- });
235
+ }); // Promise<Result<{user, posts}, unknown>>
229
236
 
230
- // Transform
231
- const userId = Result.map(parsed, data => data.userId);
232
- const validated = Result.flatMap(userId, id =>
233
- id > 0 ? ok(id) : err('invalid id')
237
+ // wrap / toThrowable: ecosystem boundaries
238
+ const safeParse = Result.wrap(JSON.parse); // throwing -> Result
239
+ safeParse('{"a":1}'); // Ok({a: 1})
240
+ const throwingFind = Result.toThrowable(findUser); // Result -> throwing
241
+ throwingFind('123'); // returns User or throws
242
+
243
+ // Standard Schema validation (Zod, Valibot, ArkType, etc.)
244
+ const validated = Result.fromSchema(userSchema, input);
245
+ // Result<User, readonly SchemaIssue[]>
246
+
247
+ // Transform with pipe
248
+ const userId = pipe(
249
+ parsed,
250
+ r => Result.map(r, data => data.userId),
251
+ r => Result.flatMap(r, id => id > 0 ? ok(id) : err('invalid id')),
234
252
  );
235
253
 
236
254
  // Pattern match
@@ -289,6 +307,7 @@ Iter.tryForEach(items, item => processItem(item));
289
307
  | `flatMap(opt, fn)` | Chain Option-returning functions |
290
308
  | `andThen(opt, fn)` | Alias for flatMap |
291
309
  | `tap(opt, fn)` | Side effect on Some, return original |
310
+ | `tapNone(opt, fn)` | Side effect on None, return original |
292
311
  | `filter(opt, predicate)` | Keep Some if predicate passes |
293
312
  | `match(opt, onSome, onNone)` | Pattern match |
294
313
  | `unwrap(opt)` | Extract or throw |
@@ -327,6 +346,11 @@ Iter.tryForEach(items, item => processItem(item));
327
346
  | `tryCatch(fn, onError?)` | Wrap throwing function |
328
347
  | `tryCatchMaybePromise(fn, onError?)` | Wrap sync-or-async, preserving sync |
329
348
  | `of(fn)` | Alias for tryCatch (no error mapper) |
349
+ | `wrap(fn, onError?)` | Wrap throwing function once, reuse |
350
+ | `toThrowable(fn)` | Inverse of wrap: Result-returning to throwing |
351
+ | `fromSchema(schema, value)` | Validate via Standard Schema v1 |
352
+ | `gen(fn)` | Generator do-notation with typed errors |
353
+ | `genAsync(fn)` | Async generator do-notation |
330
354
  | `safeTry(fn)` | Imperative error handling with unwrap |
331
355
  | `safeTryAsync(fn)` | Async version of safeTry |
332
356
  | `unwrap(result)` | Extract Ok or throw error value |
@@ -382,6 +406,12 @@ Iter.tryForEach(items, item => processItem(item));
382
406
  | `tryFold(source, init, fn)` | Fold with early exit on Err |
383
407
  | `tryForEach(source, fn)` | Iterate with early exit on Err |
384
408
 
409
+ ### Utilities
410
+
411
+ | Function | Description |
412
+ |----------|-------------|
413
+ | `pipe(value, ...fns)` | Thread value through functions left-to-right |
414
+
385
415
  ## Comparison
386
416
 
387
417
  | Feature | nalloc | neverthrow | fp-ts | oxide.ts | ts-results |
@@ -393,7 +423,10 @@ Iter.tryForEach(items, item => processItem(item));
393
423
  | Async support | Yes | Yes | Yes | Limited | No |
394
424
  | Tree-shakeable | Yes | Yes | Yes | Yes | Yes |
395
425
  | Iterator utilities | Yes | No | Yes | No | No |
396
- | safeTry (? operator) | Yes | Yes | No | No | No |
426
+ | gen (? operator) | Yes | Yes | No | No | No |
427
+ | pipe | Yes | No | Yes | No | No |
428
+ | Schema validation | Yes | No | No | No | No |
429
+ | Ecosystem interop | Yes | No | No | No | No |
397
430
 
398
431
  ## Alternatives
399
432
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "nalloc",
3
3
  "description": "Rust-like Option and Result for TypeScript with near-zero allocations for extreme performance",
4
- "version": "0.2.0",
4
+ "version": "0.2.2",
5
5
  "type": "module",
6
6
  "types": "build/index.d.ts",
7
7
  "main": "build/index.cjs",
@@ -60,22 +60,30 @@
60
60
  "type-safe",
61
61
  "monad",
62
62
  "functional",
63
- "fp",
64
- "adt",
65
63
  "algebraic-data-types",
66
64
  "discriminated-union",
65
+ "sum-type",
67
66
  "error-handling",
68
- "try-catch",
69
- "safe",
70
- "nullable",
71
67
  "null-safety",
72
68
  "pattern-matching",
69
+ "do-notation",
70
+ "generator",
71
+ "pipe",
72
+ "iterator",
73
+ "railway-oriented-programming",
74
+ "schema-validation",
73
75
  "zero-allocation",
74
- "no-allocation",
76
+ "zero-cost",
75
77
  "gc-friendly",
76
78
  "performance",
79
+ "lightweight",
80
+ "tree-shakeable",
77
81
  "neverthrow-alternative",
78
- "fp-ts-alternative"
82
+ "fp-ts-alternative",
83
+ "effect-alternative",
84
+ "oxide-ts-alternative",
85
+ "ts-results-alternative",
86
+ "true-myth-alternative"
79
87
  ],
80
88
  "author": "Ivan Zakharchanka",
81
89
  "license": "MIT",
@@ -86,7 +94,7 @@
86
94
  "devDependencies": {
87
95
  "@eslint/js": "^10.0.1",
88
96
  "@vitest/coverage-v8": "^4.1.2",
89
- "eslint": "^10.1.0",
97
+ "eslint": "^10.2.0",
90
98
  "eslint-plugin-prettier": "^5.5.5",
91
99
  "inop": "^0.9.0",
92
100
  "overtake": "^2.1.1",