nalloc 0.0.1 → 0.0.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 (64) hide show
  1. package/README.md +124 -38
  2. package/build/index.cjs +12 -68
  3. package/build/index.cjs.map +1 -1
  4. package/build/index.d.ts +1 -4
  5. package/build/index.js +1 -3
  6. package/build/index.js.map +1 -1
  7. package/build/iter.cjs +105 -0
  8. package/build/iter.cjs.map +1 -0
  9. package/build/iter.d.ts +61 -0
  10. package/build/iter.js +78 -0
  11. package/build/iter.js.map +1 -0
  12. package/build/option.cjs +19 -5
  13. package/build/option.cjs.map +1 -1
  14. package/build/option.d.ts +22 -1
  15. package/build/option.js +14 -6
  16. package/build/option.js.map +1 -1
  17. package/build/result.cjs +125 -54
  18. package/build/result.cjs.map +1 -1
  19. package/build/result.d.ts +83 -53
  20. package/build/result.js +100 -38
  21. package/build/result.js.map +1 -1
  22. package/build/safe.cjs +34 -15
  23. package/build/safe.cjs.map +1 -1
  24. package/build/safe.d.ts +4 -27
  25. package/build/safe.js +3 -14
  26. package/build/safe.js.map +1 -1
  27. package/build/types.cjs +38 -7
  28. package/build/types.cjs.map +1 -1
  29. package/build/types.d.ts +26 -4
  30. package/build/types.js +23 -7
  31. package/build/types.js.map +1 -1
  32. package/build/unsafe.cjs +14 -61
  33. package/build/unsafe.cjs.map +1 -1
  34. package/build/unsafe.d.ts +2 -27
  35. package/build/unsafe.js +2 -9
  36. package/build/unsafe.js.map +1 -1
  37. package/package.json +13 -16
  38. package/src/__tests__/index.ts +42 -0
  39. package/src/__tests__/iter.ts +218 -0
  40. package/src/__tests__/option.ts +48 -19
  41. package/src/__tests__/result.ts +286 -91
  42. package/src/__tests__/result.types.ts +3 -22
  43. package/src/__tests__/safe.ts +9 -15
  44. package/src/__tests__/unsafe.ts +11 -12
  45. package/src/index.ts +1 -18
  46. package/src/iter.ts +129 -0
  47. package/src/option.ts +36 -7
  48. package/src/result.ts +216 -113
  49. package/src/safe.ts +5 -42
  50. package/src/types.ts +52 -14
  51. package/src/unsafe.ts +2 -47
  52. package/build/devtools.cjs +0 -79
  53. package/build/devtools.cjs.map +0 -1
  54. package/build/devtools.d.ts +0 -82
  55. package/build/devtools.js +0 -43
  56. package/build/devtools.js.map +0 -1
  57. package/build/testing.cjs +0 -111
  58. package/build/testing.cjs.map +0 -1
  59. package/build/testing.d.ts +0 -85
  60. package/build/testing.js +0 -81
  61. package/build/testing.js.map +0 -1
  62. package/src/__tests__/tooling.ts +0 -86
  63. package/src/devtools.ts +0 -97
  64. package/src/testing.ts +0 -159
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 } from 'nalloc';
47
+ import { Option, Result, ok, err, none, safeTry, unwrap } from 'nalloc';
48
48
 
49
49
  // Option: the value IS the Option
50
50
  const port = Option.fromNullable(process.env.PORT);
@@ -57,6 +57,13 @@ const data = Result.match(
57
57
  cfg => cfg,
58
58
  error => ({ fallback: true })
59
59
  );
60
+
61
+ // safeTry: Rust-like ? operator
62
+ const result = safeTry(() => {
63
+ const a = unwrap(parseNumber('10'));
64
+ const b = unwrap(parseNumber('5'));
65
+ return a + b;
66
+ }); // Ok(15) or Err(...)
60
67
  ```
61
68
 
62
69
  ## How it works
@@ -105,7 +112,7 @@ Option.map(42, x => x * 2); // value IS the Option
105
112
  The API mirrors Rust's `Option` and `Result`:
106
113
 
107
114
  ```ts
108
- import { Option, Result, ok, err, none } from 'nalloc';
115
+ import { Option, Result, ok, err, none, safeTry, unwrap } from 'nalloc';
109
116
 
110
117
  // Rust: Some(42).map(|x| x * 2)
111
118
  Option.map(42, x => x * 2);
@@ -115,6 +122,12 @@ Result.andThen(ok(42), x => x > 0 ? ok(x) : err('negative'));
115
122
 
116
123
  // Rust: result.unwrap_or(0)
117
124
  Result.unwrapOr(result, 0);
125
+
126
+ // Rust: let value = try!(get_value()) / let value = get_value()?
127
+ const value = safeTry(() => {
128
+ const a = unwrap(getValue());
129
+ return a + 1;
130
+ });
118
131
  ```
119
132
 
120
133
  ## Option
@@ -158,7 +171,7 @@ const maybeUser = await Option.fromPromise(fetchUserById(id));
158
171
  A `Result<T, E>` is either `Ok<T>` (the value itself) or `Err<E>` (a wrapper).
159
172
 
160
173
  ```ts
161
- import { Result, ok, err } from 'nalloc';
174
+ import { Result, ok, err, safeTry, safeTryAsync, unwrap } from 'nalloc';
162
175
 
163
176
  // Wrap throwing functions
164
177
  const parsed = Result.tryCatch(
@@ -166,11 +179,18 @@ const parsed = Result.tryCatch(
166
179
  e => 'invalid json'
167
180
  );
168
181
 
169
- // Async operations
170
- const data = await Result.fromPromise(fetch('/api'));
171
- const processed = await Result.tryAsync(async () => {
172
- const res = await fetch('/api');
173
- return res.json();
182
+ // safeTry: Rust-like ? operator for imperative error handling
183
+ const result = safeTry(() => {
184
+ const config = unwrap(parseConfig(raw));
185
+ const db = unwrap(connectDb(config.url));
186
+ return db.query('SELECT 1');
187
+ });
188
+
189
+ // Async safeTry
190
+ const data = await safeTryAsync(async () => {
191
+ const res = unwrap(await fetchUser(id));
192
+ const posts = unwrap(await fetchPosts(res.id));
193
+ return { user: res, posts };
174
194
  });
175
195
 
176
196
  // Transform
@@ -195,6 +215,34 @@ const first = Result.any([err('a'), ok(42), err('b')]); // Ok(42)
195
215
  const [oks, errs] = Result.partition(results);
196
216
  ```
197
217
 
218
+ ## Iter
219
+
220
+ Iterator utilities for working with fallible iteration and Result streams.
221
+
222
+ ```ts
223
+ import { Iter } from 'nalloc';
224
+
225
+ // Safe iteration: wraps throws as Err, values as Ok
226
+ for (const result of Iter.safeIter(riskyIterator)) {
227
+ if (isOk(result)) handleValue(result);
228
+ else handleError(result.error);
229
+ }
230
+
231
+ // mapWhile: yields mapped values while fn returns Some
232
+ const taken = [...Iter.mapWhile([1, 2, 3, 4, 5], n =>
233
+ n < 4 ? n * 10 : null
234
+ )]; // [10, 20, 30]
235
+
236
+ // tryCollect: collect Results into Result<T[], E>
237
+ const collected = Iter.tryCollect(results); // Ok([1, 2, 3]) or first Err
238
+
239
+ // tryFold: fold with early exit on Err
240
+ const sum = Iter.tryFold([1, 2, 3], 0, (acc, n) => ok(acc + n));
241
+
242
+ // tryForEach: iterate with early exit on Err
243
+ Iter.tryForEach(items, item => processItem(item));
244
+ ```
245
+
198
246
  ## API Reference
199
247
 
200
248
  ### Option
@@ -205,62 +253,100 @@ const [oks, errs] = Result.partition(results);
205
253
  | `fromPromise(promise)` | Promise to Option (rejection = None) |
206
254
  | `map(opt, fn)` | Transform Some value |
207
255
  | `flatMap(opt, fn)` | Chain Option-returning functions |
256
+ | `andThen(opt, fn)` | Alias for flatMap |
257
+ | `tap(opt, fn)` | Side effect on Some, return original |
208
258
  | `filter(opt, predicate)` | Keep Some if predicate passes |
209
259
  | `match(opt, onSome, onNone)` | Pattern match |
210
260
  | `unwrap(opt)` | Extract or throw |
211
261
  | `unwrapOr(opt, default)` | Extract or default |
212
262
  | `unwrapOrElse(opt, fn)` | Extract or compute default |
263
+ | `unwrapOrReturn(opt, fn)` | Extract or return computed value |
264
+ | `expect(opt, msg)` | Extract or throw with message |
213
265
  | `assertSome(opt, msg?)` | Assert and narrow to Some |
214
266
  | `isSome(opt)` / `isNone(opt)` | Type guards |
267
+ | `isSomeAnd(opt, pred)` | Some and predicate passes |
268
+ | `isNoneOr(opt, pred)` | None or predicate passes |
269
+ | `or(opt, other)` | Return first Some |
270
+ | `orElse(opt, fn)` | Return Some or compute fallback |
271
+ | `and(opt, other)` | Return second if first is Some |
272
+ | `xor(opt, other)` | Some if exactly one is Some |
273
+ | `zip(opt, other)` | Combine two Options into tuple |
274
+ | `unzip(opt)` | Split tuple Option into two |
275
+ | `flatten(opt)` | Flatten nested Option |
276
+ | `contains(opt, value)` | Check if Some contains value |
277
+ | `mapOr(opt, default, fn)` | Map or return default |
278
+ | `mapOrElse(opt, defaultFn, fn)` | Map or compute default |
279
+ | `toArray(opt)` | Some to [value], None to [] |
280
+ | `toNullable(opt)` | Some to value, None to null |
281
+ | `toUndefined(opt)` | Some to value, None to undefined |
282
+ | `okOr(opt, error)` | Option to Result |
283
+ | `okOrElse(opt, fn)` | Option to Result with computed error |
284
+ | `ofOk(result)` | Ok to Some, Err to None |
285
+ | `ofErr(result)` | Err to Some, Ok to None |
215
286
  | `filterMap(items, fn)` | Map and filter in one pass |
287
+ | `findMap(items, fn)` | Find first Some from mapping |
216
288
 
217
289
  ### Result
218
290
 
219
291
  | Function | Description |
220
292
  |----------|-------------|
221
293
  | `tryCatch(fn, onError?)` | Wrap throwing function |
222
- | `tryAsync(fn, onError?)` | Wrap async function |
223
- | `fromPromise(promise)` | Promise to Result |
294
+ | `tryCatchMaybePromise(fn, onError?)` | Wrap sync-or-async, preserving sync |
295
+ | `of(fn)` | Alias for tryCatch (no error mapper) |
296
+ | `safeTry(fn)` | Imperative error handling with unwrap |
297
+ | `safeTryAsync(fn)` | Async version of safeTry |
298
+ | `unwrap(result)` | Extract Ok or throw error value |
299
+ | `unwrapErr(result)` | Extract Err or throw |
300
+ | `unwrapOr(result, default)` | Extract Ok or default |
301
+ | `unwrapOrElse(result, fn)` | Extract Ok or compute from error |
302
+ | `unwrapOrReturn(result, fn)` | Extract Ok or return computed value |
303
+ | `expect(result, msg)` | Extract Ok or throw with message |
304
+ | `expectErr(result, msg)` | Extract Err or throw with message |
224
305
  | `map(result, fn)` | Transform Ok value |
225
306
  | `mapErr(result, fn)` | Transform Err value |
307
+ | `bimap(result, okFn, errFn)` | Transform both Ok and Err |
226
308
  | `flatMap(result, fn)` | Chain Result-returning functions |
309
+ | `andThen(result, fn)` | Alias for flatMap |
310
+ | `tap(result, fn)` | Side effect on Ok, return original |
311
+ | `tapErr(result, fn)` | Side effect on Err, return original |
227
312
  | `match(result, onOk, onErr)` | Pattern match |
228
- | `unwrap(result)` | Extract Ok or throw |
229
- | `unwrapOr(result, default)` | Extract Ok or default |
230
313
  | `assertOk(result, msg?)` | Assert and narrow to Ok |
314
+ | `assertErr(result, msg?)` | Assert and narrow to Err |
231
315
  | `isOk(result)` / `isErr(result)` | Type guards |
316
+ | `isOkAnd(result, pred)` | Ok and predicate passes |
317
+ | `isErrAnd(result, pred)` | Err and predicate passes |
318
+ | `isSomeErr(result)` | Err with non-null error |
319
+ | `and(result, other)` | Return second if first is Ok |
320
+ | `or(result, other)` | Return first Ok |
321
+ | `orElse(result, fn)` | Ok or compute fallback from error |
322
+ | `zip(a, b)` | Combine two Ok into tuple |
323
+ | `zipWith(a, b, fn)` | Combine two Ok with function |
324
+ | `flatten(result)` | Flatten nested Result |
325
+ | `transpose(result)` | Result<Option> to Option<Result> |
326
+ | `toOption(result)` | Ok to Some, Err to None |
327
+ | `toErrorOption(result)` | Err to Some, Ok to None |
328
+ | `mapOr(result, default, fn)` | Map Ok or return default |
329
+ | `mapOrElse(result, defaultFn, fn)` | Map Ok or compute default |
232
330
  | `all(results)` | Collect all Ok or first Err |
233
331
  | `any(results)` | First Ok or all Errs |
332
+ | `collect(results)` | Collect Ok values or first Err |
333
+ | `collectAll(results)` | All Ok or all Errs |
234
334
  | `partition(results)` | Split into [oks, errs] |
235
335
  | `partitionAsync(promises)` | Async partition |
336
+ | `filterOk(results)` | Extract all Ok values |
337
+ | `filterErr(results)` | Extract all Err values |
338
+ | `settleMaybePromise(values)` | Settle sync/async values to Results |
339
+ | `partitionMaybePromise(values)` | Partition sync/async Results |
236
340
 
237
- ## Testing
238
-
239
- ```ts
240
- import { expectOk, expectErr, expectSome, expectNone, extendExpect } from 'nalloc/testing';
241
- import { expect } from 'vitest';
242
-
243
- extendExpect(expect);
244
-
245
- expect(result).toBeOk();
246
- expect(result).toBeErr();
247
- expect(option).toBeSome();
248
- expect(option).toBeNone();
249
-
250
- const value = expectOk(result); // returns value or throws
251
- ```
341
+ ### Iter
252
342
 
253
- ## Devtools
254
-
255
- ```ts
256
- import { formatResult, formatOption, inspectResult, inspectOption } from 'nalloc/devtools';
257
-
258
- formatResult(ok(42)); // "Ok(42)"
259
- formatOption(null); // "None"
260
-
261
- inspectResult(ok(42)); // { status: 'ok', value: 42 }
262
- inspectOption(42); // { kind: 'some', value: 42 }
263
- ```
343
+ | Function | Description |
344
+ |----------|-------------|
345
+ | `safeIter(source)` | Wrap iterable: values as Ok, throws as Err |
346
+ | `mapWhile(source, fn)` | Yield mapped values while fn returns Some |
347
+ | `tryCollect(source)` | Collect Results into Result<T[], E> |
348
+ | `tryFold(source, init, fn)` | Fold with early exit on Err |
349
+ | `tryForEach(source, fn)` | Iterate with early exit on Err |
264
350
 
265
351
  ## Comparison
266
352
 
package/build/index.cjs CHANGED
@@ -2,75 +2,19 @@
2
2
  Object.defineProperty(exports, "__esModule", {
3
3
  value: true
4
4
  });
5
- function _export(target, all) {
6
- for(var name in all)Object.defineProperty(target, name, {
7
- enumerable: true,
8
- get: Object.getOwnPropertyDescriptor(all, name).get
9
- });
10
- }
11
- _export(exports, {
12
- get Option () {
13
- return _optioncjs;
14
- },
15
- get Result () {
16
- return _resultcjs;
17
- },
18
- get err () {
19
- return _typescjs.err;
20
- },
21
- get none () {
22
- return _typescjs.none;
23
- },
24
- get ok () {
25
- return _typescjs.ok;
26
- },
27
- get some () {
28
- return _typescjs.some;
29
- }
30
- });
31
- const _typescjs = require("./types.cjs");
32
- const _optioncjs = /*#__PURE__*/ _interop_require_wildcard(require("./option.cjs"));
33
- const _resultcjs = /*#__PURE__*/ _interop_require_wildcard(require("./result.cjs"));
34
- function _getRequireWildcardCache(nodeInterop) {
35
- if (typeof WeakMap !== "function") return null;
36
- var cacheBabelInterop = new WeakMap();
37
- var cacheNodeInterop = new WeakMap();
38
- return (_getRequireWildcardCache = function(nodeInterop) {
39
- return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
40
- })(nodeInterop);
41
- }
42
- function _interop_require_wildcard(obj, nodeInterop) {
43
- if (!nodeInterop && obj && obj.__esModule) {
44
- return obj;
45
- }
46
- if (obj === null || typeof obj !== "object" && typeof obj !== "function") {
47
- return {
48
- default: obj
49
- };
50
- }
51
- var cache = _getRequireWildcardCache(nodeInterop);
52
- if (cache && cache.has(obj)) {
53
- return cache.get(obj);
54
- }
55
- var newObj = {
56
- __proto__: null
57
- };
58
- var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor;
59
- for(var key in obj){
60
- if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) {
61
- var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null;
62
- if (desc && (desc.get || desc.set)) {
63
- Object.defineProperty(newObj, key, desc);
64
- } else {
65
- newObj[key] = obj[key];
66
- }
5
+ _export_star(require("./safe.cjs"), exports);
6
+ function _export_star(from, to) {
7
+ Object.keys(from).forEach(function(k) {
8
+ if (k !== "default" && !Object.prototype.hasOwnProperty.call(to, k)) {
9
+ Object.defineProperty(to, k, {
10
+ enumerable: true,
11
+ get: function() {
12
+ return from[k];
13
+ }
14
+ });
67
15
  }
68
- }
69
- newObj.default = obj;
70
- if (cache) {
71
- cache.set(obj, newObj);
72
- }
73
- return newObj;
16
+ });
17
+ return from;
74
18
  }
75
19
 
76
20
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["export { some, none, ok, err } from './types.js';\nexport type {\n Some,\n None,\n Ok,\n Err,\n Option as OptionType,\n OptionValue,\n IsOption,\n InferSome,\n Result as ResultType,\n ResultValue,\n ResultErrorType,\n IsResult,\n InferErr,\n} from './types.js';\nexport * as Option from './option.js';\nexport * as Result from './result.js';\n"],"names":["Option","Result","err","none","ok","some"],"mappings":";;;;;;;;;;;QAgBYA;;;QACAC;;;QAjBaC;eAAAA,aAAG;;QAAbC;eAAAA,cAAI;;QAAEC;eAAAA,YAAE;;QAAdC;eAAAA,cAAI;;;0BAAuB;mEAgBZ;mEACA"}
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["export * from './safe.js';\n"],"names":[],"mappings":";;;;qBAAc"}
package/build/index.d.ts CHANGED
@@ -1,4 +1 @@
1
- export { some, none, ok, err } from './types.js';
2
- export type { Some, None, Ok, Err, Option as OptionType, OptionValue, IsOption, InferSome, Result as ResultType, ResultValue, ResultErrorType, IsResult, InferErr, } from './types.js';
3
- export * as Option from './option.js';
4
- export * as Result from './result.js';
1
+ export * from './safe.js';
package/build/index.js CHANGED
@@ -1,5 +1,3 @@
1
- export { some, none, ok, err } from "./types.js";
2
- export * as Option from "./option.js";
3
- export * as Result from "./result.js";
1
+ export * from "./safe.js";
4
2
 
5
3
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["export { some, none, ok, err } from './types.js';\nexport type {\n Some,\n None,\n Ok,\n Err,\n Option as OptionType,\n OptionValue,\n IsOption,\n InferSome,\n Result as ResultType,\n ResultValue,\n ResultErrorType,\n IsResult,\n InferErr,\n} from './types.js';\nexport * as Option from './option.js';\nexport * as Result from './result.js';\n"],"names":["some","none","ok","err","Option","Result"],"mappings":"AAAA,SAASA,IAAI,EAAEC,IAAI,EAAEC,EAAE,EAAEC,GAAG,QAAQ,aAAa;AAgBjD,OAAO,KAAKC,MAAM,MAAM,cAAc;AACtC,OAAO,KAAKC,MAAM,MAAM,cAAc"}
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["export * from './safe.js';\n"],"names":[],"mappings":"AAAA,cAAc,YAAY"}
package/build/iter.cjs ADDED
@@ -0,0 +1,105 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ function _export(target, all) {
6
+ for(var name in all)Object.defineProperty(target, name, {
7
+ enumerable: true,
8
+ get: Object.getOwnPropertyDescriptor(all, name).get
9
+ });
10
+ }
11
+ _export(exports, {
12
+ get mapWhile () {
13
+ return mapWhile;
14
+ },
15
+ get safeIter () {
16
+ return safeIter;
17
+ },
18
+ get tryCollect () {
19
+ return tryCollect;
20
+ },
21
+ get tryFold () {
22
+ return tryFold;
23
+ },
24
+ get tryForEach () {
25
+ return tryForEach;
26
+ }
27
+ });
28
+ const _typescjs = require("./types.cjs");
29
+ function* mapWhile(source, fn) {
30
+ for (const item of source){
31
+ const mapped = fn(item);
32
+ if (!(0, _typescjs.isSome)(mapped)) return;
33
+ yield mapped;
34
+ }
35
+ }
36
+ function safeIter(source) {
37
+ const iter = source[Symbol.iterator]();
38
+ let done = false;
39
+ return {
40
+ [Symbol.iterator] () {
41
+ return this;
42
+ },
43
+ next () {
44
+ if (done) return {
45
+ value: undefined,
46
+ done: true
47
+ };
48
+ try {
49
+ const next = iter.next();
50
+ if (next.done) {
51
+ done = true;
52
+ return next;
53
+ }
54
+ return {
55
+ value: next.value,
56
+ done: false
57
+ };
58
+ } catch (e) {
59
+ done = true;
60
+ return {
61
+ value: (0, _typescjs.err)(e),
62
+ done: false
63
+ };
64
+ }
65
+ },
66
+ return () {
67
+ if (!done) {
68
+ done = true;
69
+ try {
70
+ iter.return?.();
71
+ } catch {}
72
+ }
73
+ return {
74
+ value: undefined,
75
+ done: true
76
+ };
77
+ }
78
+ };
79
+ }
80
+ function tryCollect(source) {
81
+ const collected = [];
82
+ for (const result of source){
83
+ if ((0, _typescjs.isErr)(result)) return result;
84
+ collected.push(result);
85
+ }
86
+ return collected;
87
+ }
88
+ function tryFold(source, init, fn) {
89
+ let acc = init;
90
+ for (const item of source){
91
+ const result = fn(acc, item);
92
+ if ((0, _typescjs.isErr)(result)) return result;
93
+ acc = result;
94
+ }
95
+ return acc;
96
+ }
97
+ function tryForEach(source, fn) {
98
+ for (const item of source){
99
+ const result = fn(item);
100
+ if ((0, _typescjs.isErr)(result)) return result;
101
+ }
102
+ return undefined;
103
+ }
104
+
105
+ //# sourceMappingURL=iter.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/iter.ts"],"sourcesContent":["import { isSome, isErr, err as ERR } from './types.js';\nimport type { Option, Result, Ok } from './types.js';\n\n/**\n * Yields mapped values while the mapping function returns Some, stops at the first None.\n * @param source - The iterable to map over\n * @param fn - Mapping function returning Some(value) to continue or None to stop\n * @returns Generator of mapped values\n * @example\n * [...mapWhile([1, 2, 3, 4], n => n < 3 ? some(n * 10) : none)] // [10, 20]\n */\nexport function* mapWhile<T, U>(source: Iterable<T>, fn: (value: T) => Option<U>): Generator<U> {\n for (const item of source) {\n const mapped = fn(item);\n if (!isSome(mapped)) return;\n yield mapped as U;\n }\n}\n\n/**\n * Wraps an iterable so that each yielded value becomes Ok and any throw becomes a single Err.\n * Stops after the first error - the source's internal state is unknown after an exception.\n *\n * Uses a manual iterator instead of a generator to avoid coroutine suspend/resume overhead.\n *\n * Follows the for-of IteratorClose spec:\n * - iter.return() is never called on natural exhaustion or after a caught error\n * - iter.return() is only called on early consumer exit (break/return)\n * - Cleanup errors from iter.return() are suppressed\n *\n * @param source - The iterable to wrap\n * @returns Iterable iterator of Result values\n * @example\n * [...safeIter([1, 2, 3])] // [Ok(1), Ok(2), Ok(3)]\n * [...safeIter(throwingIter())] // [Ok(1), Err(error)]\n */\nexport function safeIter<T>(source: Iterable<T>): IterableIterator<Result<T, unknown>> {\n const iter = source[Symbol.iterator]();\n let done = false;\n return {\n [Symbol.iterator]() {\n return this;\n },\n next(): IteratorResult<Result<T, unknown>> {\n if (done) return { value: undefined, done: true };\n try {\n const next = iter.next();\n if (next.done) {\n done = true;\n return next;\n }\n return { value: next.value as Ok<T>, done: false };\n } catch (e) {\n done = true;\n return { value: ERR(e), done: false };\n }\n },\n return(): IteratorResult<Result<T, unknown>> {\n if (!done) {\n done = true;\n try {\n iter.return?.();\n } catch {\n // suppressed\n }\n }\n return { value: undefined, done: true };\n },\n };\n}\n\n// -- Result-oriented terminal operations --\n\n/**\n * Collects an iterable of Results into a single Result containing an array.\n * Short-circuits on the first Err.\n * @param source - Iterable of Result values\n * @returns Ok(values[]) if all Ok, or the first Err encountered\n * @example\n * tryCollect([ok(1), ok(2), ok(3)]) // Ok([1, 2, 3])\n * tryCollect([ok(1), err('x')]) // Err('x')\n */\nexport function tryCollect<T, E>(source: Iterable<Result<T, E>>): Result<T[], E> {\n const collected: T[] = [];\n for (const result of source) {\n if (isErr(result)) return result;\n collected.push(result as T);\n }\n return collected as Ok<T[]>;\n}\n\n/**\n * Folds an iterable with a fallible accumulator function.\n * Short-circuits on the first Err returned by fn.\n * @param source - The iterable to fold over\n * @param init - Initial accumulator value\n * @param fn - Folding function returning Ok(newAcc) or Err\n * @returns Ok(finalAcc) if all steps succeed, or the first Err\n * @example\n * tryFold([1, 2, 3], 0, (acc, n) => ok(acc + n)) // Ok(6)\n * tryFold([1, 2, 3], 0, (acc, n) => n === 2 ? err('stop') : ok(acc + n)) // Err('stop')\n */\nexport function tryFold<T, Acc, E>(source: Iterable<T>, init: Acc, fn: (acc: Acc, item: T) => Result<Acc, E>): Result<Acc, E> {\n let acc = init;\n for (const item of source) {\n const result = fn(acc, item);\n if (isErr(result)) return result;\n acc = result as Acc;\n }\n return acc as Ok<Acc>;\n}\n\n/**\n * Iterates over a source, calling a fallible function for each item.\n * Short-circuits on the first Err returned by fn.\n * @param source - The iterable to iterate over\n * @param fn - Function to call for each item, returning Ok(void) or Err\n * @returns Ok(void) if all calls succeed, or the first Err\n * @example\n * tryForEach([1, 2, 3], n => ok(console.log(n))) // Ok(void), logs 1, 2, 3\n * tryForEach([1, 2, 3], n => n === 2 ? err('stop') : ok(undefined)) // Err('stop')\n */\nexport function tryForEach<T, E>(source: Iterable<T>, fn: (item: T) => Result<void, E>): Result<void, E> {\n for (const item of source) {\n const result = fn(item);\n if (isErr(result)) return result;\n }\n return undefined as Ok<void>;\n}\n"],"names":["mapWhile","safeIter","tryCollect","tryFold","tryForEach","source","fn","item","mapped","isSome","iter","Symbol","iterator","done","next","value","undefined","e","ERR","return","collected","result","isErr","push","init","acc"],"mappings":";;;;;;;;;;;QAWiBA;eAAAA;;QAyBDC;eAAAA;;QA8CAC;eAAAA;;QAoBAC;eAAAA;;QAoBAC;eAAAA;;;0BA1H0B;AAWnC,UAAUJ,SAAeK,MAAmB,EAAEC,EAA2B;IAC9E,KAAK,MAAMC,QAAQF,OAAQ;QACzB,MAAMG,SAASF,GAAGC;QAClB,IAAI,CAACE,IAAAA,gBAAM,EAACD,SAAS;QACrB,MAAMA;IACR;AACF;AAmBO,SAASP,SAAYI,MAAmB;IAC7C,MAAMK,OAAOL,MAAM,CAACM,OAAOC,QAAQ,CAAC;IACpC,IAAIC,OAAO;IACX,OAAO;QACL,CAACF,OAAOC,QAAQ,CAAC;YACf,OAAO,IAAI;QACb;QACAE;YACE,IAAID,MAAM,OAAO;gBAAEE,OAAOC;gBAAWH,MAAM;YAAK;YAChD,IAAI;gBACF,MAAMC,OAAOJ,KAAKI,IAAI;gBACtB,IAAIA,KAAKD,IAAI,EAAE;oBACbA,OAAO;oBACP,OAAOC;gBACT;gBACA,OAAO;oBAAEC,OAAOD,KAAKC,KAAK;oBAAWF,MAAM;gBAAM;YACnD,EAAE,OAAOI,GAAG;gBACVJ,OAAO;gBACP,OAAO;oBAAEE,OAAOG,IAAAA,aAAG,EAACD;oBAAIJ,MAAM;gBAAM;YACtC;QACF;QACAM;YACE,IAAI,CAACN,MAAM;gBACTA,OAAO;gBACP,IAAI;oBACFH,KAAKS,MAAM;gBACb,EAAE,OAAM,CAER;YACF;YACA,OAAO;gBAAEJ,OAAOC;gBAAWH,MAAM;YAAK;QACxC;IACF;AACF;AAaO,SAASX,WAAiBG,MAA8B;IAC7D,MAAMe,YAAiB,EAAE;IACzB,KAAK,MAAMC,UAAUhB,OAAQ;QAC3B,IAAIiB,IAAAA,eAAK,EAACD,SAAS,OAAOA;QAC1BD,UAAUG,IAAI,CAACF;IACjB;IACA,OAAOD;AACT;AAaO,SAASjB,QAAmBE,MAAmB,EAAEmB,IAAS,EAAElB,EAAyC;IAC1G,IAAImB,MAAMD;IACV,KAAK,MAAMjB,QAAQF,OAAQ;QACzB,MAAMgB,SAASf,GAAGmB,KAAKlB;QACvB,IAAIe,IAAAA,eAAK,EAACD,SAAS,OAAOA;QAC1BI,MAAMJ;IACR;IACA,OAAOI;AACT;AAYO,SAASrB,WAAiBC,MAAmB,EAAEC,EAAgC;IACpF,KAAK,MAAMC,QAAQF,OAAQ;QACzB,MAAMgB,SAASf,GAAGC;QAClB,IAAIe,IAAAA,eAAK,EAACD,SAAS,OAAOA;IAC5B;IACA,OAAOL;AACT"}
@@ -0,0 +1,61 @@
1
+ import type { Option, Result } from './types.js';
2
+ /**
3
+ * Yields mapped values while the mapping function returns Some, stops at the first None.
4
+ * @param source - The iterable to map over
5
+ * @param fn - Mapping function returning Some(value) to continue or None to stop
6
+ * @returns Generator of mapped values
7
+ * @example
8
+ * [...mapWhile([1, 2, 3, 4], n => n < 3 ? some(n * 10) : none)] // [10, 20]
9
+ */
10
+ export declare function mapWhile<T, U>(source: Iterable<T>, fn: (value: T) => Option<U>): Generator<U>;
11
+ /**
12
+ * Wraps an iterable so that each yielded value becomes Ok and any throw becomes a single Err.
13
+ * Stops after the first error - the source's internal state is unknown after an exception.
14
+ *
15
+ * Uses a manual iterator instead of a generator to avoid coroutine suspend/resume overhead.
16
+ *
17
+ * Follows the for-of IteratorClose spec:
18
+ * - iter.return() is never called on natural exhaustion or after a caught error
19
+ * - iter.return() is only called on early consumer exit (break/return)
20
+ * - Cleanup errors from iter.return() are suppressed
21
+ *
22
+ * @param source - The iterable to wrap
23
+ * @returns Iterable iterator of Result values
24
+ * @example
25
+ * [...safeIter([1, 2, 3])] // [Ok(1), Ok(2), Ok(3)]
26
+ * [...safeIter(throwingIter())] // [Ok(1), Err(error)]
27
+ */
28
+ export declare function safeIter<T>(source: Iterable<T>): IterableIterator<Result<T, unknown>>;
29
+ /**
30
+ * Collects an iterable of Results into a single Result containing an array.
31
+ * Short-circuits on the first Err.
32
+ * @param source - Iterable of Result values
33
+ * @returns Ok(values[]) if all Ok, or the first Err encountered
34
+ * @example
35
+ * tryCollect([ok(1), ok(2), ok(3)]) // Ok([1, 2, 3])
36
+ * tryCollect([ok(1), err('x')]) // Err('x')
37
+ */
38
+ export declare function tryCollect<T, E>(source: Iterable<Result<T, E>>): Result<T[], E>;
39
+ /**
40
+ * Folds an iterable with a fallible accumulator function.
41
+ * Short-circuits on the first Err returned by fn.
42
+ * @param source - The iterable to fold over
43
+ * @param init - Initial accumulator value
44
+ * @param fn - Folding function returning Ok(newAcc) or Err
45
+ * @returns Ok(finalAcc) if all steps succeed, or the first Err
46
+ * @example
47
+ * tryFold([1, 2, 3], 0, (acc, n) => ok(acc + n)) // Ok(6)
48
+ * tryFold([1, 2, 3], 0, (acc, n) => n === 2 ? err('stop') : ok(acc + n)) // Err('stop')
49
+ */
50
+ export declare function tryFold<T, Acc, E>(source: Iterable<T>, init: Acc, fn: (acc: Acc, item: T) => Result<Acc, E>): Result<Acc, E>;
51
+ /**
52
+ * Iterates over a source, calling a fallible function for each item.
53
+ * Short-circuits on the first Err returned by fn.
54
+ * @param source - The iterable to iterate over
55
+ * @param fn - Function to call for each item, returning Ok(void) or Err
56
+ * @returns Ok(void) if all calls succeed, or the first Err
57
+ * @example
58
+ * tryForEach([1, 2, 3], n => ok(console.log(n))) // Ok(void), logs 1, 2, 3
59
+ * tryForEach([1, 2, 3], n => n === 2 ? err('stop') : ok(undefined)) // Err('stop')
60
+ */
61
+ export declare function tryForEach<T, E>(source: Iterable<T>, fn: (item: T) => Result<void, E>): Result<void, E>;
package/build/iter.js ADDED
@@ -0,0 +1,78 @@
1
+ import { isSome, isErr, err as ERR } from "./types.js";
2
+ export function* mapWhile(source, fn) {
3
+ for (const item of source){
4
+ const mapped = fn(item);
5
+ if (!isSome(mapped)) return;
6
+ yield mapped;
7
+ }
8
+ }
9
+ export function safeIter(source) {
10
+ const iter = source[Symbol.iterator]();
11
+ let done = false;
12
+ return {
13
+ [Symbol.iterator] () {
14
+ return this;
15
+ },
16
+ next () {
17
+ if (done) return {
18
+ value: undefined,
19
+ done: true
20
+ };
21
+ try {
22
+ const next = iter.next();
23
+ if (next.done) {
24
+ done = true;
25
+ return next;
26
+ }
27
+ return {
28
+ value: next.value,
29
+ done: false
30
+ };
31
+ } catch (e) {
32
+ done = true;
33
+ return {
34
+ value: ERR(e),
35
+ done: false
36
+ };
37
+ }
38
+ },
39
+ return () {
40
+ if (!done) {
41
+ done = true;
42
+ try {
43
+ iter.return?.();
44
+ } catch {}
45
+ }
46
+ return {
47
+ value: undefined,
48
+ done: true
49
+ };
50
+ }
51
+ };
52
+ }
53
+ export function tryCollect(source) {
54
+ const collected = [];
55
+ for (const result of source){
56
+ if (isErr(result)) return result;
57
+ collected.push(result);
58
+ }
59
+ return collected;
60
+ }
61
+ export function tryFold(source, init, fn) {
62
+ let acc = init;
63
+ for (const item of source){
64
+ const result = fn(acc, item);
65
+ if (isErr(result)) return result;
66
+ acc = result;
67
+ }
68
+ return acc;
69
+ }
70
+ export function tryForEach(source, fn) {
71
+ for (const item of source){
72
+ const result = fn(item);
73
+ if (isErr(result)) return result;
74
+ }
75
+ return undefined;
76
+ }
77
+
78
+ //# sourceMappingURL=iter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/iter.ts"],"sourcesContent":["import { isSome, isErr, err as ERR } from './types.js';\nimport type { Option, Result, Ok } from './types.js';\n\n/**\n * Yields mapped values while the mapping function returns Some, stops at the first None.\n * @param source - The iterable to map over\n * @param fn - Mapping function returning Some(value) to continue or None to stop\n * @returns Generator of mapped values\n * @example\n * [...mapWhile([1, 2, 3, 4], n => n < 3 ? some(n * 10) : none)] // [10, 20]\n */\nexport function* mapWhile<T, U>(source: Iterable<T>, fn: (value: T) => Option<U>): Generator<U> {\n for (const item of source) {\n const mapped = fn(item);\n if (!isSome(mapped)) return;\n yield mapped as U;\n }\n}\n\n/**\n * Wraps an iterable so that each yielded value becomes Ok and any throw becomes a single Err.\n * Stops after the first error - the source's internal state is unknown after an exception.\n *\n * Uses a manual iterator instead of a generator to avoid coroutine suspend/resume overhead.\n *\n * Follows the for-of IteratorClose spec:\n * - iter.return() is never called on natural exhaustion or after a caught error\n * - iter.return() is only called on early consumer exit (break/return)\n * - Cleanup errors from iter.return() are suppressed\n *\n * @param source - The iterable to wrap\n * @returns Iterable iterator of Result values\n * @example\n * [...safeIter([1, 2, 3])] // [Ok(1), Ok(2), Ok(3)]\n * [...safeIter(throwingIter())] // [Ok(1), Err(error)]\n */\nexport function safeIter<T>(source: Iterable<T>): IterableIterator<Result<T, unknown>> {\n const iter = source[Symbol.iterator]();\n let done = false;\n return {\n [Symbol.iterator]() {\n return this;\n },\n next(): IteratorResult<Result<T, unknown>> {\n if (done) return { value: undefined, done: true };\n try {\n const next = iter.next();\n if (next.done) {\n done = true;\n return next;\n }\n return { value: next.value as Ok<T>, done: false };\n } catch (e) {\n done = true;\n return { value: ERR(e), done: false };\n }\n },\n return(): IteratorResult<Result<T, unknown>> {\n if (!done) {\n done = true;\n try {\n iter.return?.();\n } catch {\n // suppressed\n }\n }\n return { value: undefined, done: true };\n },\n };\n}\n\n// -- Result-oriented terminal operations --\n\n/**\n * Collects an iterable of Results into a single Result containing an array.\n * Short-circuits on the first Err.\n * @param source - Iterable of Result values\n * @returns Ok(values[]) if all Ok, or the first Err encountered\n * @example\n * tryCollect([ok(1), ok(2), ok(3)]) // Ok([1, 2, 3])\n * tryCollect([ok(1), err('x')]) // Err('x')\n */\nexport function tryCollect<T, E>(source: Iterable<Result<T, E>>): Result<T[], E> {\n const collected: T[] = [];\n for (const result of source) {\n if (isErr(result)) return result;\n collected.push(result as T);\n }\n return collected as Ok<T[]>;\n}\n\n/**\n * Folds an iterable with a fallible accumulator function.\n * Short-circuits on the first Err returned by fn.\n * @param source - The iterable to fold over\n * @param init - Initial accumulator value\n * @param fn - Folding function returning Ok(newAcc) or Err\n * @returns Ok(finalAcc) if all steps succeed, or the first Err\n * @example\n * tryFold([1, 2, 3], 0, (acc, n) => ok(acc + n)) // Ok(6)\n * tryFold([1, 2, 3], 0, (acc, n) => n === 2 ? err('stop') : ok(acc + n)) // Err('stop')\n */\nexport function tryFold<T, Acc, E>(source: Iterable<T>, init: Acc, fn: (acc: Acc, item: T) => Result<Acc, E>): Result<Acc, E> {\n let acc = init;\n for (const item of source) {\n const result = fn(acc, item);\n if (isErr(result)) return result;\n acc = result as Acc;\n }\n return acc as Ok<Acc>;\n}\n\n/**\n * Iterates over a source, calling a fallible function for each item.\n * Short-circuits on the first Err returned by fn.\n * @param source - The iterable to iterate over\n * @param fn - Function to call for each item, returning Ok(void) or Err\n * @returns Ok(void) if all calls succeed, or the first Err\n * @example\n * tryForEach([1, 2, 3], n => ok(console.log(n))) // Ok(void), logs 1, 2, 3\n * tryForEach([1, 2, 3], n => n === 2 ? err('stop') : ok(undefined)) // Err('stop')\n */\nexport function tryForEach<T, E>(source: Iterable<T>, fn: (item: T) => Result<void, E>): Result<void, E> {\n for (const item of source) {\n const result = fn(item);\n if (isErr(result)) return result;\n }\n return undefined as Ok<void>;\n}\n"],"names":["isSome","isErr","err","ERR","mapWhile","source","fn","item","mapped","safeIter","iter","Symbol","iterator","done","next","value","undefined","e","return","tryCollect","collected","result","push","tryFold","init","acc","tryForEach"],"mappings":"AAAA,SAASA,MAAM,EAAEC,KAAK,EAAEC,OAAOC,GAAG,QAAQ,aAAa;AAWvD,OAAO,UAAUC,SAAeC,MAAmB,EAAEC,EAA2B;IAC9E,KAAK,MAAMC,QAAQF,OAAQ;QACzB,MAAMG,SAASF,GAAGC;QAClB,IAAI,CAACP,OAAOQ,SAAS;QACrB,MAAMA;IACR;AACF;AAmBA,OAAO,SAASC,SAAYJ,MAAmB;IAC7C,MAAMK,OAAOL,MAAM,CAACM,OAAOC,QAAQ,CAAC;IACpC,IAAIC,OAAO;IACX,OAAO;QACL,CAACF,OAAOC,QAAQ,CAAC;YACf,OAAO,IAAI;QACb;QACAE;YACE,IAAID,MAAM,OAAO;gBAAEE,OAAOC;gBAAWH,MAAM;YAAK;YAChD,IAAI;gBACF,MAAMC,OAAOJ,KAAKI,IAAI;gBACtB,IAAIA,KAAKD,IAAI,EAAE;oBACbA,OAAO;oBACP,OAAOC;gBACT;gBACA,OAAO;oBAAEC,OAAOD,KAAKC,KAAK;oBAAWF,MAAM;gBAAM;YACnD,EAAE,OAAOI,GAAG;gBACVJ,OAAO;gBACP,OAAO;oBAAEE,OAAOZ,IAAIc;oBAAIJ,MAAM;gBAAM;YACtC;QACF;QACAK;YACE,IAAI,CAACL,MAAM;gBACTA,OAAO;gBACP,IAAI;oBACFH,KAAKQ,MAAM;gBACb,EAAE,OAAM,CAER;YACF;YACA,OAAO;gBAAEH,OAAOC;gBAAWH,MAAM;YAAK;QACxC;IACF;AACF;AAaA,OAAO,SAASM,WAAiBd,MAA8B;IAC7D,MAAMe,YAAiB,EAAE;IACzB,KAAK,MAAMC,UAAUhB,OAAQ;QAC3B,IAAIJ,MAAMoB,SAAS,OAAOA;QAC1BD,UAAUE,IAAI,CAACD;IACjB;IACA,OAAOD;AACT;AAaA,OAAO,SAASG,QAAmBlB,MAAmB,EAAEmB,IAAS,EAAElB,EAAyC;IAC1G,IAAImB,MAAMD;IACV,KAAK,MAAMjB,QAAQF,OAAQ;QACzB,MAAMgB,SAASf,GAAGmB,KAAKlB;QACvB,IAAIN,MAAMoB,SAAS,OAAOA;QAC1BI,MAAMJ;IACR;IACA,OAAOI;AACT;AAYA,OAAO,SAASC,WAAiBrB,MAAmB,EAAEC,EAAgC;IACpF,KAAK,MAAMC,QAAQF,OAAQ;QACzB,MAAMgB,SAASf,GAAGC;QAClB,IAAIN,MAAMoB,SAAS,OAAOA;IAC5B;IACA,OAAOL;AACT"}