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/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.0.
|
|
4
|
+
"version": "0.0.2",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"types": "build/index.d.ts",
|
|
7
7
|
"main": "build/index.cjs",
|
|
@@ -31,13 +31,9 @@
|
|
|
31
31
|
"require": "./build/unsafe.cjs",
|
|
32
32
|
"import": "./build/unsafe.js"
|
|
33
33
|
},
|
|
34
|
-
"./
|
|
35
|
-
"require": "./build/
|
|
36
|
-
"import": "./build/
|
|
37
|
-
},
|
|
38
|
-
"./devtools": {
|
|
39
|
-
"require": "./build/devtools.cjs",
|
|
40
|
-
"import": "./build/devtools.js"
|
|
34
|
+
"./iter": {
|
|
35
|
+
"require": "./build/iter.cjs",
|
|
36
|
+
"import": "./build/iter.js"
|
|
41
37
|
},
|
|
42
38
|
"./package.json": "./package.json"
|
|
43
39
|
},
|
|
@@ -71,17 +67,18 @@
|
|
|
71
67
|
},
|
|
72
68
|
"homepage": "https://github.com/3axap4eHko/nalloc#readme",
|
|
73
69
|
"devDependencies": {
|
|
74
|
-
"@eslint/js": "^
|
|
75
|
-
"@vitest/coverage-v8": "^4.0.
|
|
76
|
-
"eslint": "^
|
|
77
|
-
"eslint-plugin-prettier": "^5.5.
|
|
78
|
-
"inop": "^0.
|
|
79
|
-
"
|
|
70
|
+
"@eslint/js": "^10.0.1",
|
|
71
|
+
"@vitest/coverage-v8": "^4.0.18",
|
|
72
|
+
"eslint": "^10.0.2",
|
|
73
|
+
"eslint-plugin-prettier": "^5.5.5",
|
|
74
|
+
"inop": "^0.9.0",
|
|
75
|
+
"overtake": "^1.4.0",
|
|
76
|
+
"prettier": "^3.8.1",
|
|
80
77
|
"tsafe": "^1.8.12",
|
|
81
78
|
"tslib": "^2.8.1",
|
|
82
79
|
"typescript": "^5.9.3",
|
|
83
|
-
"typescript-eslint": "^8.
|
|
84
|
-
"vitest": "^4.0.
|
|
80
|
+
"typescript-eslint": "^8.56.1",
|
|
81
|
+
"vitest": "^4.0.18"
|
|
85
82
|
},
|
|
86
83
|
"scripts": {
|
|
87
84
|
"check": "tsc src/__tests__/option.types.ts src/__tests__/result.types.ts --noEmit --lib esnext,dom --target esnext --module nodenext --moduleResolution nodenext",
|
package/src/__tests__/index.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { describe, it, expect } from 'vitest';
|
|
2
2
|
import * as index from '../index.js';
|
|
3
|
+
import { isThenable, isSync } from '../types.js';
|
|
3
4
|
|
|
4
5
|
describe('index.ts exports', () => {
|
|
5
6
|
it('exports exist', () => {
|
|
@@ -10,4 +11,45 @@ describe('index.ts exports', () => {
|
|
|
10
11
|
expect(index.Option).toBeDefined();
|
|
11
12
|
expect(index.Result).toBeDefined();
|
|
12
13
|
});
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
describe('MaybePromise guards', () => {
|
|
17
|
+
describe('isThenable', () => {
|
|
18
|
+
it('returns true for Promise', () => {
|
|
19
|
+
expect(isThenable(Promise.resolve(1))).toBe(true);
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it('returns true for PromiseLike', () => {
|
|
23
|
+
const thenable = { then: (cb: (v: number) => void) => cb(1) };
|
|
24
|
+
expect(isThenable(thenable)).toBe(true);
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it('returns false for plain value', () => {
|
|
28
|
+
expect(isThenable(42)).toBe(false);
|
|
29
|
+
expect(isThenable('string')).toBe(false);
|
|
30
|
+
expect(isThenable({ x: 1 })).toBe(false);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it('returns false for null/undefined', () => {
|
|
34
|
+
expect(isThenable(null)).toBe(false);
|
|
35
|
+
expect(isThenable(undefined)).toBe(false);
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
describe('isSync', () => {
|
|
40
|
+
it('returns false for Promise', () => {
|
|
41
|
+
expect(isSync(Promise.resolve(1))).toBe(false);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it('returns true for plain value', () => {
|
|
45
|
+
expect(isSync(42)).toBe(true);
|
|
46
|
+
expect(isSync('string')).toBe(true);
|
|
47
|
+
expect(isSync({ x: 1 })).toBe(true);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it('returns true for null/undefined', () => {
|
|
51
|
+
expect(isSync(null)).toBe(true);
|
|
52
|
+
expect(isSync(undefined)).toBe(true);
|
|
53
|
+
});
|
|
54
|
+
});
|
|
13
55
|
});
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import {
|
|
3
|
+
mapWhile,
|
|
4
|
+
safeIter,
|
|
5
|
+
tryCollect,
|
|
6
|
+
tryFold,
|
|
7
|
+
tryForEach,
|
|
8
|
+
} from '../iter.js';
|
|
9
|
+
import { ok, err, isOk, isErr, some, none } from '../types.js';
|
|
10
|
+
import type { Result } from '../types.js';
|
|
11
|
+
|
|
12
|
+
describe('Iter', () => {
|
|
13
|
+
describe('mapWhile', () => {
|
|
14
|
+
it('yields while Some, stops at first None', () => {
|
|
15
|
+
const result = [...mapWhile([1, 2, 3, 4, 5], n => n < 4 ? some(n * 10) : none)];
|
|
16
|
+
expect(result).toEqual([10, 20, 30]);
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it('yields nothing when first is None', () => {
|
|
20
|
+
const result = [...mapWhile([1, 2, 3], () => none)];
|
|
21
|
+
expect(result).toEqual([]);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it('yields all when all Some', () => {
|
|
25
|
+
const result = [...mapWhile([1, 2, 3], n => some(n))];
|
|
26
|
+
expect(result).toEqual([1, 2, 3]);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it('handles empty source', () => {
|
|
30
|
+
const result = [...mapWhile([], () => some(1))];
|
|
31
|
+
expect(result).toEqual([]);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it('does not call fn after first None', () => {
|
|
35
|
+
let calls = 0;
|
|
36
|
+
const result = [...mapWhile([1, 2, 3, 4], n => {
|
|
37
|
+
calls++;
|
|
38
|
+
return n <= 2 ? some(n) : none;
|
|
39
|
+
})];
|
|
40
|
+
expect(result).toEqual([1, 2]);
|
|
41
|
+
expect(calls).toBe(3);
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
describe('safeIter', () => {
|
|
46
|
+
it('wraps normal values as Ok', () => {
|
|
47
|
+
const results = [...safeIter([1, 2, 3])];
|
|
48
|
+
expect(results).toHaveLength(3);
|
|
49
|
+
expect(results.every(r => isOk(r))).toBe(true);
|
|
50
|
+
expect(results).toEqual([1, 2, 3]);
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it('catches per-item throws as Err', () => {
|
|
54
|
+
function* throwing() {
|
|
55
|
+
yield 1;
|
|
56
|
+
throw new Error('boom');
|
|
57
|
+
}
|
|
58
|
+
const results = [...safeIter(throwing())];
|
|
59
|
+
expect(results).toHaveLength(2);
|
|
60
|
+
expect(isOk(results[0])).toBe(true);
|
|
61
|
+
expect(results[0]).toBe(1);
|
|
62
|
+
expect(isErr(results[1])).toBe(true);
|
|
63
|
+
expect((results[1] as { error: Error }).error.message).toBe('boom');
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it('handles empty source', () => {
|
|
67
|
+
expect([...safeIter([])]).toEqual([]);
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it('stops after first throw from a persistently throwing iterator', () => {
|
|
71
|
+
const iter: Iterable<number> = {
|
|
72
|
+
[Symbol.iterator]: () => ({
|
|
73
|
+
next() { throw new Error('always'); },
|
|
74
|
+
}),
|
|
75
|
+
};
|
|
76
|
+
const results = [...safeIter(iter)];
|
|
77
|
+
expect(results).toHaveLength(1);
|
|
78
|
+
expect(isErr(results[0])).toBe(true);
|
|
79
|
+
expect((results[0] as { error: Error }).error.message).toBe('always');
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
it('calls iter.return() when consumer breaks early', () => {
|
|
83
|
+
let returned = false;
|
|
84
|
+
const iter: Iterable<number> = {
|
|
85
|
+
[Symbol.iterator]: () => {
|
|
86
|
+
let i = 0;
|
|
87
|
+
return {
|
|
88
|
+
next() { return { value: ++i, done: false }; },
|
|
89
|
+
return() { returned = true; return { value: undefined, done: true }; },
|
|
90
|
+
};
|
|
91
|
+
},
|
|
92
|
+
};
|
|
93
|
+
const gen = safeIter(iter);
|
|
94
|
+
gen.next(); // consume one value
|
|
95
|
+
gen.return(undefined as any); // consumer breaks
|
|
96
|
+
expect(returned).toBe(true);
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
it('yields values then stops on throw', () => {
|
|
100
|
+
function* twoThenThrow() {
|
|
101
|
+
yield 1;
|
|
102
|
+
yield 2;
|
|
103
|
+
throw new Error('third');
|
|
104
|
+
}
|
|
105
|
+
const results = [...safeIter(twoThenThrow())];
|
|
106
|
+
expect(results).toHaveLength(3);
|
|
107
|
+
expect(isOk(results[0])).toBe(true);
|
|
108
|
+
expect(results[0]).toBe(1);
|
|
109
|
+
expect(isOk(results[1])).toBe(true);
|
|
110
|
+
expect(results[1]).toBe(2);
|
|
111
|
+
expect(isErr(results[2])).toBe(true);
|
|
112
|
+
expect((results[2] as { error: Error }).error.message).toBe('third');
|
|
113
|
+
});
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
describe('tryCollect', () => {
|
|
117
|
+
it('collects all Ok values into Result<T[], E>', () => {
|
|
118
|
+
const results: Result<number, string>[] = [ok(1), ok(2), ok(3)];
|
|
119
|
+
const collected = tryCollect(results);
|
|
120
|
+
expect(isOk(collected)).toBe(true);
|
|
121
|
+
expect(collected).toEqual([1, 2, 3]);
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
it('short-circuits on first Err', () => {
|
|
125
|
+
let calls = 0;
|
|
126
|
+
function* source(): Generator<Result<number, string>> {
|
|
127
|
+
calls++; yield ok(1);
|
|
128
|
+
calls++; yield err('fail');
|
|
129
|
+
calls++; yield ok(3);
|
|
130
|
+
}
|
|
131
|
+
const collected = tryCollect(source());
|
|
132
|
+
expect(isErr(collected)).toBe(true);
|
|
133
|
+
expect((collected as { error: string }).error).toBe('fail');
|
|
134
|
+
expect(calls).toBe(2);
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
it('handles empty source', () => {
|
|
138
|
+
const collected = tryCollect([]);
|
|
139
|
+
expect(isOk(collected)).toBe(true);
|
|
140
|
+
expect(collected).toEqual([]);
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
it('works with lazy generators', () => {
|
|
144
|
+
function* source(): Generator<Result<number, string>> {
|
|
145
|
+
yield ok(2);
|
|
146
|
+
yield ok(4);
|
|
147
|
+
yield ok(6);
|
|
148
|
+
}
|
|
149
|
+
const collected = tryCollect(source());
|
|
150
|
+
expect(isOk(collected)).toBe(true);
|
|
151
|
+
expect(collected).toEqual([2, 4, 6]);
|
|
152
|
+
});
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
describe('tryFold', () => {
|
|
156
|
+
it('folds all values when no error', () => {
|
|
157
|
+
const result = tryFold([1, 2, 3], 0, (acc, n) => ok(acc + n));
|
|
158
|
+
expect(isOk(result)).toBe(true);
|
|
159
|
+
expect(result).toBe(6);
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
it('short-circuits on first Err', () => {
|
|
163
|
+
let calls = 0;
|
|
164
|
+
const result = tryFold([1, 2, 3, 4], 0, (acc, n) => {
|
|
165
|
+
calls++;
|
|
166
|
+
return n === 3 ? err('stopped') as Result<number, string> : ok(acc + n);
|
|
167
|
+
});
|
|
168
|
+
expect(isErr(result)).toBe(true);
|
|
169
|
+
expect((result as { error: string }).error).toBe('stopped');
|
|
170
|
+
expect(calls).toBe(3);
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
it('handles empty source', () => {
|
|
174
|
+
const result = tryFold([], 42, () => ok(0));
|
|
175
|
+
expect(isOk(result)).toBe(true);
|
|
176
|
+
expect(result).toBe(42);
|
|
177
|
+
});
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
describe('tryForEach', () => {
|
|
181
|
+
it('iterates all items when no error', () => {
|
|
182
|
+
const seen: number[] = [];
|
|
183
|
+
const result = tryForEach([1, 2, 3], n => {
|
|
184
|
+
seen.push(n);
|
|
185
|
+
return ok(undefined);
|
|
186
|
+
});
|
|
187
|
+
expect(isOk(result)).toBe(true);
|
|
188
|
+
expect(seen).toEqual([1, 2, 3]);
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
it('short-circuits on first Err', () => {
|
|
192
|
+
const seen: number[] = [];
|
|
193
|
+
const result = tryForEach([1, 2, 3, 4], n => {
|
|
194
|
+
seen.push(n);
|
|
195
|
+
return n === 2 ? err('stop') as Result<void, string> : ok(undefined);
|
|
196
|
+
});
|
|
197
|
+
expect(isErr(result)).toBe(true);
|
|
198
|
+
expect((result as { error: string }).error).toBe('stop');
|
|
199
|
+
expect(seen).toEqual([1, 2]);
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
it('handles empty source', () => {
|
|
203
|
+
const result = tryForEach([], () => ok(undefined));
|
|
204
|
+
expect(isOk(result)).toBe(true);
|
|
205
|
+
});
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
describe('composition', () => {
|
|
209
|
+
it('safeIter -> native filter(isOk) collects safe values', () => {
|
|
210
|
+
function* unstable() {
|
|
211
|
+
yield 1;
|
|
212
|
+
throw new Error('oops');
|
|
213
|
+
}
|
|
214
|
+
const safe = [...safeIter(unstable())].filter(isOk);
|
|
215
|
+
expect(safe).toEqual([1]);
|
|
216
|
+
});
|
|
217
|
+
});
|
|
218
|
+
});
|
package/src/__tests__/option.ts
CHANGED
|
@@ -36,9 +36,10 @@ import {
|
|
|
36
36
|
unwrapOrReturn,
|
|
37
37
|
assertSome,
|
|
38
38
|
satisfiesOption,
|
|
39
|
-
filterMap
|
|
39
|
+
filterMap,
|
|
40
|
+
isNoneOr,
|
|
41
|
+
findMap
|
|
40
42
|
} from '../option.js';
|
|
41
|
-
import { formatOption, inspectOption } from '../devtools.js';
|
|
42
43
|
import { ok, err, some, none } from '../types.js';
|
|
43
44
|
|
|
44
45
|
describe('Option', () => {
|
|
@@ -65,11 +66,9 @@ describe('Option', () => {
|
|
|
65
66
|
expect(opt).toBe(42);
|
|
66
67
|
});
|
|
67
68
|
|
|
68
|
-
it('some
|
|
69
|
-
expect(() => some(null as any)).
|
|
70
|
-
expect(() => some(undefined as any)).
|
|
71
|
-
expect(isNone(some(null as any))).toBe(true);
|
|
72
|
-
expect(isNone(some(undefined as any))).toBe(true);
|
|
69
|
+
it('some throws on null/undefined', () => {
|
|
70
|
+
expect(() => some(null as any)).toThrow('some() requires a non-nullable value');
|
|
71
|
+
expect(() => some(undefined as any)).toThrow('some() requires a non-nullable value');
|
|
73
72
|
});
|
|
74
73
|
|
|
75
74
|
it('none creates None', () => {
|
|
@@ -564,9 +563,19 @@ describe('Option', () => {
|
|
|
564
563
|
expect(isSome(opt)).toBe(true);
|
|
565
564
|
expect(unwrap(opt)).toBe(99);
|
|
566
565
|
});
|
|
566
|
+
|
|
567
|
+
it('fromPromise returns None on rejection without callback', async () => {
|
|
568
|
+
const opt = await fromPromise(Promise.reject(new Error('boom')));
|
|
569
|
+
expect(isNone(opt)).toBe(true);
|
|
570
|
+
});
|
|
567
571
|
});
|
|
568
572
|
|
|
569
573
|
describe('control helpers', () => {
|
|
574
|
+
it('unwrapOrReturn returns value for Some', () => {
|
|
575
|
+
const result = unwrapOrReturn(of(42), () => 77);
|
|
576
|
+
expect(result).toBe(42);
|
|
577
|
+
});
|
|
578
|
+
|
|
570
579
|
it('unwrapOrReturn returns fallback for None', () => {
|
|
571
580
|
const result = unwrapOrReturn(none, () => 77);
|
|
572
581
|
expect(result).toBe(77);
|
|
@@ -588,18 +597,6 @@ describe('Option', () => {
|
|
|
588
597
|
});
|
|
589
598
|
});
|
|
590
599
|
|
|
591
|
-
describe('introspection helpers', () => {
|
|
592
|
-
it('inspectOption exposes discriminated metadata', () => {
|
|
593
|
-
expect(inspectOption(of(4))).toEqual({ kind: 'some', value: 4 });
|
|
594
|
-
expect(inspectOption(none)).toEqual({ kind: 'none' });
|
|
595
|
-
});
|
|
596
|
-
|
|
597
|
-
it('formatOption prints human friendly value', () => {
|
|
598
|
-
expect(formatOption(of(1))).toBe('Some(1)');
|
|
599
|
-
expect(formatOption(none)).toBe('None');
|
|
600
|
-
});
|
|
601
|
-
});
|
|
602
|
-
|
|
603
600
|
describe('filterMap', () => {
|
|
604
601
|
it('collects Some values from iterable', () => {
|
|
605
602
|
const items = [of(1), none, of(3)];
|
|
@@ -607,4 +604,36 @@ describe('Option', () => {
|
|
|
607
604
|
expect(result).toEqual([1, 3]);
|
|
608
605
|
});
|
|
609
606
|
});
|
|
607
|
+
|
|
608
|
+
describe('isNoneOr', () => {
|
|
609
|
+
it('returns true for None', () => {
|
|
610
|
+
expect(isNoneOr(none, () => false)).toBe(true);
|
|
611
|
+
});
|
|
612
|
+
|
|
613
|
+
it('returns true for Some when predicate is true', () => {
|
|
614
|
+
expect(isNoneOr(some(5), x => x > 2)).toBe(true);
|
|
615
|
+
});
|
|
616
|
+
|
|
617
|
+
it('returns false for Some when predicate is false', () => {
|
|
618
|
+
expect(isNoneOr(some(1), x => x > 2)).toBe(false);
|
|
619
|
+
});
|
|
620
|
+
});
|
|
621
|
+
|
|
622
|
+
describe('findMap', () => {
|
|
623
|
+
it('returns first Some result', () => {
|
|
624
|
+
const result = findMap([1, 2, 3], n => n > 1 ? some(n * 2) : none);
|
|
625
|
+
expect(isSome(result)).toBe(true);
|
|
626
|
+
expect(result).toBe(4);
|
|
627
|
+
});
|
|
628
|
+
|
|
629
|
+
it('returns None when no match', () => {
|
|
630
|
+
const result = findMap([1, 2, 3], n => n > 5 ? some(n) : none);
|
|
631
|
+
expect(isNone(result)).toBe(true);
|
|
632
|
+
});
|
|
633
|
+
|
|
634
|
+
it('returns None for empty iterable', () => {
|
|
635
|
+
const result = findMap([], () => some(1));
|
|
636
|
+
expect(isNone(result)).toBe(true);
|
|
637
|
+
});
|
|
638
|
+
});
|
|
610
639
|
});
|