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.
- package/README.md +124 -38
- package/build/index.cjs +12 -68
- package/build/index.cjs.map +1 -1
- package/build/index.d.ts +1 -4
- package/build/index.js +1 -3
- package/build/index.js.map +1 -1
- package/build/iter.cjs +105 -0
- package/build/iter.cjs.map +1 -0
- package/build/iter.d.ts +61 -0
- package/build/iter.js +78 -0
- package/build/iter.js.map +1 -0
- package/build/option.cjs +19 -5
- package/build/option.cjs.map +1 -1
- package/build/option.d.ts +22 -1
- package/build/option.js +14 -6
- package/build/option.js.map +1 -1
- package/build/result.cjs +125 -54
- package/build/result.cjs.map +1 -1
- package/build/result.d.ts +83 -53
- package/build/result.js +100 -38
- package/build/result.js.map +1 -1
- package/build/safe.cjs +34 -15
- package/build/safe.cjs.map +1 -1
- package/build/safe.d.ts +4 -27
- package/build/safe.js +3 -14
- package/build/safe.js.map +1 -1
- package/build/types.cjs +38 -7
- package/build/types.cjs.map +1 -1
- package/build/types.d.ts +26 -4
- package/build/types.js +23 -7
- package/build/types.js.map +1 -1
- package/build/unsafe.cjs +14 -61
- package/build/unsafe.cjs.map +1 -1
- package/build/unsafe.d.ts +2 -27
- package/build/unsafe.js +2 -9
- package/build/unsafe.js.map +1 -1
- package/package.json +13 -16
- package/src/__tests__/index.ts +42 -0
- package/src/__tests__/iter.ts +218 -0
- package/src/__tests__/option.ts +48 -19
- package/src/__tests__/result.ts +286 -91
- package/src/__tests__/result.types.ts +3 -22
- package/src/__tests__/safe.ts +9 -15
- package/src/__tests__/unsafe.ts +11 -12
- package/src/index.ts +1 -18
- package/src/iter.ts +129 -0
- package/src/option.ts +36 -7
- package/src/result.ts +216 -113
- package/src/safe.ts +5 -42
- package/src/types.ts +52 -14
- package/src/unsafe.ts +2 -47
- package/build/devtools.cjs +0 -79
- package/build/devtools.cjs.map +0 -1
- package/build/devtools.d.ts +0 -82
- package/build/devtools.js +0 -43
- package/build/devtools.js.map +0 -1
- package/build/testing.cjs +0 -111
- package/build/testing.cjs.map +0 -1
- package/build/testing.d.ts +0 -85
- package/build/testing.js +0 -81
- package/build/testing.js.map +0 -1
- package/src/__tests__/tooling.ts +0 -86
- package/src/devtools.ts +0 -97
- package/src/testing.ts +0 -159
package/src/iter.ts
ADDED
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { isSome, isErr, err as ERR } from './types.js';
|
|
2
|
+
import type { Option, Result, Ok } from './types.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Yields mapped values while the mapping function returns Some, stops at the first None.
|
|
6
|
+
* @param source - The iterable to map over
|
|
7
|
+
* @param fn - Mapping function returning Some(value) to continue or None to stop
|
|
8
|
+
* @returns Generator of mapped values
|
|
9
|
+
* @example
|
|
10
|
+
* [...mapWhile([1, 2, 3, 4], n => n < 3 ? some(n * 10) : none)] // [10, 20]
|
|
11
|
+
*/
|
|
12
|
+
export function* mapWhile<T, U>(source: Iterable<T>, fn: (value: T) => Option<U>): Generator<U> {
|
|
13
|
+
for (const item of source) {
|
|
14
|
+
const mapped = fn(item);
|
|
15
|
+
if (!isSome(mapped)) return;
|
|
16
|
+
yield mapped as U;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Wraps an iterable so that each yielded value becomes Ok and any throw becomes a single Err.
|
|
22
|
+
* Stops after the first error - the source's internal state is unknown after an exception.
|
|
23
|
+
*
|
|
24
|
+
* Uses a manual iterator instead of a generator to avoid coroutine suspend/resume overhead.
|
|
25
|
+
*
|
|
26
|
+
* Follows the for-of IteratorClose spec:
|
|
27
|
+
* - iter.return() is never called on natural exhaustion or after a caught error
|
|
28
|
+
* - iter.return() is only called on early consumer exit (break/return)
|
|
29
|
+
* - Cleanup errors from iter.return() are suppressed
|
|
30
|
+
*
|
|
31
|
+
* @param source - The iterable to wrap
|
|
32
|
+
* @returns Iterable iterator of Result values
|
|
33
|
+
* @example
|
|
34
|
+
* [...safeIter([1, 2, 3])] // [Ok(1), Ok(2), Ok(3)]
|
|
35
|
+
* [...safeIter(throwingIter())] // [Ok(1), Err(error)]
|
|
36
|
+
*/
|
|
37
|
+
export function safeIter<T>(source: Iterable<T>): IterableIterator<Result<T, unknown>> {
|
|
38
|
+
const iter = source[Symbol.iterator]();
|
|
39
|
+
let done = false;
|
|
40
|
+
return {
|
|
41
|
+
[Symbol.iterator]() {
|
|
42
|
+
return this;
|
|
43
|
+
},
|
|
44
|
+
next(): IteratorResult<Result<T, unknown>> {
|
|
45
|
+
if (done) return { value: undefined, done: true };
|
|
46
|
+
try {
|
|
47
|
+
const next = iter.next();
|
|
48
|
+
if (next.done) {
|
|
49
|
+
done = true;
|
|
50
|
+
return next;
|
|
51
|
+
}
|
|
52
|
+
return { value: next.value as Ok<T>, done: false };
|
|
53
|
+
} catch (e) {
|
|
54
|
+
done = true;
|
|
55
|
+
return { value: ERR(e), done: false };
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
return(): IteratorResult<Result<T, unknown>> {
|
|
59
|
+
if (!done) {
|
|
60
|
+
done = true;
|
|
61
|
+
try {
|
|
62
|
+
iter.return?.();
|
|
63
|
+
} catch {
|
|
64
|
+
// suppressed
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return { value: undefined, done: true };
|
|
68
|
+
},
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// -- Result-oriented terminal operations --
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Collects an iterable of Results into a single Result containing an array.
|
|
76
|
+
* Short-circuits on the first Err.
|
|
77
|
+
* @param source - Iterable of Result values
|
|
78
|
+
* @returns Ok(values[]) if all Ok, or the first Err encountered
|
|
79
|
+
* @example
|
|
80
|
+
* tryCollect([ok(1), ok(2), ok(3)]) // Ok([1, 2, 3])
|
|
81
|
+
* tryCollect([ok(1), err('x')]) // Err('x')
|
|
82
|
+
*/
|
|
83
|
+
export function tryCollect<T, E>(source: Iterable<Result<T, E>>): Result<T[], E> {
|
|
84
|
+
const collected: T[] = [];
|
|
85
|
+
for (const result of source) {
|
|
86
|
+
if (isErr(result)) return result;
|
|
87
|
+
collected.push(result as T);
|
|
88
|
+
}
|
|
89
|
+
return collected as Ok<T[]>;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Folds an iterable with a fallible accumulator function.
|
|
94
|
+
* Short-circuits on the first Err returned by fn.
|
|
95
|
+
* @param source - The iterable to fold over
|
|
96
|
+
* @param init - Initial accumulator value
|
|
97
|
+
* @param fn - Folding function returning Ok(newAcc) or Err
|
|
98
|
+
* @returns Ok(finalAcc) if all steps succeed, or the first Err
|
|
99
|
+
* @example
|
|
100
|
+
* tryFold([1, 2, 3], 0, (acc, n) => ok(acc + n)) // Ok(6)
|
|
101
|
+
* tryFold([1, 2, 3], 0, (acc, n) => n === 2 ? err('stop') : ok(acc + n)) // Err('stop')
|
|
102
|
+
*/
|
|
103
|
+
export function tryFold<T, Acc, E>(source: Iterable<T>, init: Acc, fn: (acc: Acc, item: T) => Result<Acc, E>): Result<Acc, E> {
|
|
104
|
+
let acc = init;
|
|
105
|
+
for (const item of source) {
|
|
106
|
+
const result = fn(acc, item);
|
|
107
|
+
if (isErr(result)) return result;
|
|
108
|
+
acc = result as Acc;
|
|
109
|
+
}
|
|
110
|
+
return acc as Ok<Acc>;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Iterates over a source, calling a fallible function for each item.
|
|
115
|
+
* Short-circuits on the first Err returned by fn.
|
|
116
|
+
* @param source - The iterable to iterate over
|
|
117
|
+
* @param fn - Function to call for each item, returning Ok(void) or Err
|
|
118
|
+
* @returns Ok(void) if all calls succeed, or the first Err
|
|
119
|
+
* @example
|
|
120
|
+
* tryForEach([1, 2, 3], n => ok(console.log(n))) // Ok(void), logs 1, 2, 3
|
|
121
|
+
* tryForEach([1, 2, 3], n => n === 2 ? err('stop') : ok(undefined)) // Err('stop')
|
|
122
|
+
*/
|
|
123
|
+
export function tryForEach<T, E>(source: Iterable<T>, fn: (item: T) => Result<void, E>): Result<void, E> {
|
|
124
|
+
for (const item of source) {
|
|
125
|
+
const result = fn(item);
|
|
126
|
+
if (isErr(result)) return result;
|
|
127
|
+
}
|
|
128
|
+
return undefined as Ok<void>;
|
|
129
|
+
}
|
package/src/option.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { NONE, isSome, isNone, optionOf as of, err, isOk, isErr } from './types.js';
|
|
1
|
+
import { NONE, EMPTY, isSome, isNone, optionOf as of, err, isOk, isErr } from './types.js';
|
|
2
2
|
import type { Some, None, Option, NoneValueType, ValueType, Result, Ok, Widen } from './types.js';
|
|
3
3
|
|
|
4
4
|
export type { Some, None, Option };
|
|
@@ -97,13 +97,28 @@ export function filterMap<T, U>(values: Iterable<T>, fn: (value: T) => Option<U>
|
|
|
97
97
|
const collected: U[] = [];
|
|
98
98
|
for (const value of values) {
|
|
99
99
|
const mapped = fn(value);
|
|
100
|
-
if (isSome(mapped))
|
|
101
|
-
collected.push(mapped);
|
|
102
|
-
}
|
|
100
|
+
if (isSome(mapped)) collected.push(mapped);
|
|
103
101
|
}
|
|
104
102
|
return collected;
|
|
105
103
|
}
|
|
106
104
|
|
|
105
|
+
/**
|
|
106
|
+
* Finds the first element that maps to Some, returning that value.
|
|
107
|
+
* @param values - Iterable to search
|
|
108
|
+
* @param fn - Function that returns Some for matches
|
|
109
|
+
* @returns The first Some value, or None if no match
|
|
110
|
+
* @example
|
|
111
|
+
* findMap([1, 2, 3], n => n > 1 ? some(n * 2) : none) // Some(4)
|
|
112
|
+
* findMap([1], n => n > 5 ? some(n) : none) // None
|
|
113
|
+
*/
|
|
114
|
+
export function findMap<T, U>(values: Iterable<T>, fn: (value: T) => Option<U>): Option<U> {
|
|
115
|
+
for (const value of values) {
|
|
116
|
+
const mapped = fn(value);
|
|
117
|
+
if (isSome(mapped)) return mapped;
|
|
118
|
+
}
|
|
119
|
+
return NONE;
|
|
120
|
+
}
|
|
121
|
+
|
|
107
122
|
/**
|
|
108
123
|
* Transforms the value inside a Some, or returns None.
|
|
109
124
|
* @param opt - The Option to map
|
|
@@ -146,7 +161,7 @@ export function flatMap<T, U>(opt: Option<T>, fn: (value: T) => Option<U>): Opti
|
|
|
146
161
|
export function andThen<T, U>(opt: None, fn: (value: T) => Option<U>): None;
|
|
147
162
|
export function andThen<T, U>(opt: Option<T>, fn: (value: T) => Option<U>): Option<U>;
|
|
148
163
|
export function andThen<T, U>(opt: Option<T>, fn: (value: T) => Option<U>): Option<U> {
|
|
149
|
-
return
|
|
164
|
+
return isNone(opt) ? NONE : fn(opt);
|
|
150
165
|
}
|
|
151
166
|
|
|
152
167
|
/**
|
|
@@ -167,6 +182,20 @@ export function tap<T>(opt: Option<T>, fn: (value: T) => void): Option<T> {
|
|
|
167
182
|
return opt;
|
|
168
183
|
}
|
|
169
184
|
|
|
185
|
+
/**
|
|
186
|
+
* Returns true if None, or if Some and predicate returns true.
|
|
187
|
+
* @param opt - The Option to check
|
|
188
|
+
* @param predicate - Test function
|
|
189
|
+
* @returns true if None or predicate(value) is true
|
|
190
|
+
* @example
|
|
191
|
+
* isNoneOr(none, x => x > 2) // true
|
|
192
|
+
* isNoneOr(some(4), x => x > 2) // true
|
|
193
|
+
* isNoneOr(some(1), x => x > 2) // false
|
|
194
|
+
*/
|
|
195
|
+
export function isNoneOr<T>(opt: Option<T>, predicate: (value: T) => boolean): boolean {
|
|
196
|
+
return isNone(opt) || predicate(opt);
|
|
197
|
+
}
|
|
198
|
+
|
|
170
199
|
/**
|
|
171
200
|
* Returns Some if the value passes the predicate, None otherwise.
|
|
172
201
|
* @param opt - The Option to filter
|
|
@@ -407,8 +436,8 @@ export function isSomeAnd<T>(opt: Option<T>, predicate: (value: T) => boolean):
|
|
|
407
436
|
* toArray(some(42)) // [42]
|
|
408
437
|
* toArray(none) // []
|
|
409
438
|
*/
|
|
410
|
-
export function toArray<T>(opt: Option<T>): T[] {
|
|
411
|
-
return isSome(opt) ? [opt] : [];
|
|
439
|
+
export function toArray<T>(opt: Option<T>): readonly T[] {
|
|
440
|
+
return isSome(opt) ? [opt] : (EMPTY as readonly T[]);
|
|
412
441
|
}
|
|
413
442
|
|
|
414
443
|
/**
|