nalloc 0.2.2 → 0.5.0
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 +326 -178
- package/build/codemod-cli.cjs +153 -0
- package/build/codemod-cli.cjs.map +1 -0
- package/build/codemod-cli.d.ts +2 -0
- package/build/codemod-cli.js +103 -0
- package/build/codemod-cli.js.map +1 -0
- package/build/codemod.cjs +652 -0
- package/build/codemod.cjs.map +1 -0
- package/build/codemod.d.ts +29 -0
- package/build/codemod.js +634 -0
- package/build/codemod.js.map +1 -0
- package/build/eslint.cjs +221 -0
- package/build/eslint.cjs.map +1 -0
- package/build/eslint.d.ts +36 -0
- package/build/eslint.js +198 -0
- package/build/eslint.js.map +1 -0
- package/build/http.cjs +31 -0
- package/build/http.cjs.map +1 -0
- package/build/http.d.ts +31 -0
- package/build/http.js +13 -0
- package/build/http.js.map +1 -0
- package/build/nonempty.cjs +35 -0
- package/build/nonempty.cjs.map +1 -0
- package/build/nonempty.d.ts +34 -0
- package/build/nonempty.js +14 -0
- package/build/nonempty.js.map +1 -0
- package/build/option.cjs +1 -1
- package/build/option.cjs.map +1 -1
- package/build/option.d.ts +2 -2
- package/build/option.js +1 -1
- package/build/option.js.map +1 -1
- package/build/result.cjs +10 -18
- package/build/result.cjs.map +1 -1
- package/build/result.d.ts +3 -34
- package/build/result.js +10 -15
- package/build/result.js.map +1 -1
- package/build/safe.cjs +8 -0
- package/build/safe.cjs.map +1 -1
- package/build/safe.d.ts +3 -0
- package/build/safe.js +2 -0
- package/build/safe.js.map +1 -1
- package/build/schema.cjs +32 -0
- package/build/schema.cjs.map +1 -0
- package/build/schema.d.ts +44 -0
- package/build/schema.js +14 -0
- package/build/schema.js.map +1 -0
- package/package.json +63 -10
- package/src/__tests__/codemod.ts +211 -0
- package/src/__tests__/eslint.ts +99 -0
- package/src/__tests__/fixtures/tsconfig.json +10 -0
- package/src/__tests__/http.ts +64 -0
- package/src/__tests__/iter.ts +18 -0
- package/src/__tests__/nonempty.ts +46 -0
- package/src/__tests__/nonempty.types.ts +38 -0
- package/src/__tests__/option.ts +4 -0
- package/src/__tests__/result.ts +104 -129
- package/src/__tests__/result.types.ts +2 -2
- package/src/__tests__/schema.ts +58 -0
- package/src/codemod-cli.ts +108 -0
- package/src/codemod.ts +623 -0
- package/src/eslint.ts +145 -0
- package/src/http.ts +42 -0
- package/src/nonempty.ts +48 -0
- package/src/option.ts +3 -4
- package/src/result.ts +18 -49
- package/src/safe.ts +3 -0
- package/src/schema.ts +52 -0
package/src/__tests__/result.ts
CHANGED
|
@@ -49,11 +49,9 @@ import {
|
|
|
49
49
|
safeTry,
|
|
50
50
|
safeTryAsync,
|
|
51
51
|
fromPromise,
|
|
52
|
-
fromSchema,
|
|
53
52
|
gen,
|
|
54
|
-
genAsync
|
|
53
|
+
genAsync,
|
|
55
54
|
} from '../result.js';
|
|
56
|
-
import type { StandardSchema } from '../result.js';
|
|
57
55
|
import { ok, err, isOk, isErr, optionOf as optOf, none } from '../types.js';
|
|
58
56
|
|
|
59
57
|
describe('Result', () => {
|
|
@@ -86,7 +84,6 @@ describe('Result', () => {
|
|
|
86
84
|
expect(isErr(failure)).toBe(true);
|
|
87
85
|
expect((failure as any).error.message).toBe('failed');
|
|
88
86
|
});
|
|
89
|
-
|
|
90
87
|
});
|
|
91
88
|
|
|
92
89
|
describe('type guards', () => {
|
|
@@ -127,7 +124,7 @@ describe('Result', () => {
|
|
|
127
124
|
|
|
128
125
|
describe('map', () => {
|
|
129
126
|
it('maps Ok value', () => {
|
|
130
|
-
const result = map(ok(2), x => x * 3);
|
|
127
|
+
const result = map(ok(2), (x) => x * 3);
|
|
131
128
|
expect(unwrap(result)).toBe(6);
|
|
132
129
|
});
|
|
133
130
|
|
|
@@ -140,7 +137,7 @@ describe('Result', () => {
|
|
|
140
137
|
|
|
141
138
|
describe('mapErr', () => {
|
|
142
139
|
it('maps Err value', () => {
|
|
143
|
-
const result = mapErr(err('error'), e => e.toUpperCase());
|
|
140
|
+
const result = mapErr(err('error'), (e) => e.toUpperCase());
|
|
144
141
|
expect(isErr(result)).toBe(true);
|
|
145
142
|
expect((result as any).error).toBe('ERROR');
|
|
146
143
|
});
|
|
@@ -154,12 +151,12 @@ describe('Result', () => {
|
|
|
154
151
|
|
|
155
152
|
describe('flatMap', () => {
|
|
156
153
|
it('flatMaps Ok value', () => {
|
|
157
|
-
const result = flatMap(ok(2), x => ok(x * 3));
|
|
154
|
+
const result = flatMap(ok(2), (x) => ok(x * 3));
|
|
158
155
|
expect(unwrap(result)).toBe(6);
|
|
159
156
|
});
|
|
160
157
|
|
|
161
158
|
it('can return Err from mapper', () => {
|
|
162
|
-
const result = flatMap(ok(2), x => err(`error: ${x}`));
|
|
159
|
+
const result = flatMap(ok(2), (x) => err(`error: ${x}`));
|
|
163
160
|
expect(isErr(result)).toBe(true);
|
|
164
161
|
expect((result as any).error).toBe('error: 2');
|
|
165
162
|
});
|
|
@@ -173,7 +170,7 @@ describe('Result', () => {
|
|
|
173
170
|
|
|
174
171
|
describe('andThen', () => {
|
|
175
172
|
it('aliases flatMap for Ok', () => {
|
|
176
|
-
const result = andThen(ok(2), x => ok(x * 4));
|
|
173
|
+
const result = andThen(ok(2), (x) => ok(x * 4));
|
|
177
174
|
expect(unwrap(result)).toBe(8);
|
|
178
175
|
});
|
|
179
176
|
|
|
@@ -188,7 +185,7 @@ describe('Result', () => {
|
|
|
188
185
|
it('runs for Ok and returns original', () => {
|
|
189
186
|
let seen = 0;
|
|
190
187
|
const res = ok(7);
|
|
191
|
-
const out = tap(res, value => {
|
|
188
|
+
const out = tap(res, (value) => {
|
|
192
189
|
seen = value;
|
|
193
190
|
});
|
|
194
191
|
expect(out).toBe(res);
|
|
@@ -209,7 +206,7 @@ describe('Result', () => {
|
|
|
209
206
|
it('runs for Err and returns original', () => {
|
|
210
207
|
let seen = '';
|
|
211
208
|
const res = err('nope');
|
|
212
|
-
const out = tapErr(res, error => {
|
|
209
|
+
const out = tapErr(res, (error) => {
|
|
213
210
|
seen = error;
|
|
214
211
|
});
|
|
215
212
|
expect(out).toBe(res);
|
|
@@ -228,12 +225,20 @@ describe('Result', () => {
|
|
|
228
225
|
|
|
229
226
|
describe('bimap', () => {
|
|
230
227
|
it('maps Ok value', () => {
|
|
231
|
-
const result = bimap(
|
|
228
|
+
const result = bimap(
|
|
229
|
+
ok(2),
|
|
230
|
+
(x) => x * 3,
|
|
231
|
+
(e) => e,
|
|
232
|
+
);
|
|
232
233
|
expect(unwrap(result)).toBe(6);
|
|
233
234
|
});
|
|
234
235
|
|
|
235
236
|
it('maps Err value', () => {
|
|
236
|
-
const result = bimap(
|
|
237
|
+
const result = bimap(
|
|
238
|
+
err('error'),
|
|
239
|
+
(x: number) => x * 3,
|
|
240
|
+
(e) => e.toUpperCase(),
|
|
241
|
+
);
|
|
237
242
|
expect(isErr(result)).toBe(true);
|
|
238
243
|
expect((result as any).error).toBe('ERROR');
|
|
239
244
|
});
|
|
@@ -247,7 +252,11 @@ describe('Result', () => {
|
|
|
247
252
|
it('throws error value for Err', () => {
|
|
248
253
|
const e = err('error');
|
|
249
254
|
let caught: unknown;
|
|
250
|
-
try {
|
|
255
|
+
try {
|
|
256
|
+
unwrap(e);
|
|
257
|
+
} catch (x) {
|
|
258
|
+
caught = x;
|
|
259
|
+
}
|
|
251
260
|
expect(caught).toBe('error');
|
|
252
261
|
});
|
|
253
262
|
});
|
|
@@ -279,7 +288,7 @@ describe('Result', () => {
|
|
|
279
288
|
|
|
280
289
|
it('calls function for Err', () => {
|
|
281
290
|
let called = false;
|
|
282
|
-
const result = unwrapOrElse(err('error'), e => {
|
|
291
|
+
const result = unwrapOrElse(err('error'), (e) => {
|
|
283
292
|
called = true;
|
|
284
293
|
expect(e).toBe('error');
|
|
285
294
|
return 99;
|
|
@@ -291,7 +300,7 @@ describe('Result', () => {
|
|
|
291
300
|
|
|
292
301
|
describe('mapOr', () => {
|
|
293
302
|
it('maps Ok value', () => {
|
|
294
|
-
const result = mapOr(ok(2), 10, x => x * 3);
|
|
303
|
+
const result = mapOr(ok(2), 10, (x) => x * 3);
|
|
295
304
|
expect(result).toBe(6);
|
|
296
305
|
});
|
|
297
306
|
|
|
@@ -303,16 +312,24 @@ describe('Result', () => {
|
|
|
303
312
|
|
|
304
313
|
describe('mapOrElse', () => {
|
|
305
314
|
it('maps Ok value', () => {
|
|
306
|
-
const result = mapOrElse(
|
|
315
|
+
const result = mapOrElse(
|
|
316
|
+
ok(2),
|
|
317
|
+
() => 10,
|
|
318
|
+
(x) => x * 3,
|
|
319
|
+
);
|
|
307
320
|
expect(result).toBe(6);
|
|
308
321
|
});
|
|
309
322
|
|
|
310
323
|
it('returns default for Err', () => {
|
|
311
324
|
let called = false;
|
|
312
|
-
const result = mapOrElse(
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
325
|
+
const result = mapOrElse(
|
|
326
|
+
err('error'),
|
|
327
|
+
() => {
|
|
328
|
+
called = true;
|
|
329
|
+
return 10;
|
|
330
|
+
},
|
|
331
|
+
(x: number) => x * 3,
|
|
332
|
+
);
|
|
316
333
|
expect(result).toBe(10);
|
|
317
334
|
expect(called).toBe(true);
|
|
318
335
|
});
|
|
@@ -383,7 +400,7 @@ describe('Result', () => {
|
|
|
383
400
|
|
|
384
401
|
it('calls function if Err', () => {
|
|
385
402
|
let called = false;
|
|
386
|
-
const result = orElse(err('error'), e => {
|
|
403
|
+
const result = orElse(err('error'), (e) => {
|
|
387
404
|
called = true;
|
|
388
405
|
expect(e).toBe('error');
|
|
389
406
|
return ok(2);
|
|
@@ -462,7 +479,6 @@ describe('Result', () => {
|
|
|
462
479
|
expect(unwrap(result)).toBe(42);
|
|
463
480
|
});
|
|
464
481
|
|
|
465
|
-
|
|
466
482
|
it('returns outer Err', () => {
|
|
467
483
|
const result = flatten(err('outer error'));
|
|
468
484
|
expect(isErr(result)).toBe(true);
|
|
@@ -474,8 +490,8 @@ describe('Result', () => {
|
|
|
474
490
|
it('calls ok branch for Ok', () => {
|
|
475
491
|
const result = match(
|
|
476
492
|
ok(42),
|
|
477
|
-
x => `value: ${x}`,
|
|
478
|
-
e => `error: ${e}`,
|
|
493
|
+
(x) => `value: ${x}`,
|
|
494
|
+
(e) => `error: ${e}`,
|
|
479
495
|
);
|
|
480
496
|
expect(result).toBe('value: 42');
|
|
481
497
|
});
|
|
@@ -484,7 +500,7 @@ describe('Result', () => {
|
|
|
484
500
|
const result = match(
|
|
485
501
|
err('failed'),
|
|
486
502
|
(x: number) => `value: ${x}`,
|
|
487
|
-
e => `error: ${e}`,
|
|
503
|
+
(e) => `error: ${e}`,
|
|
488
504
|
);
|
|
489
505
|
expect(result).toBe('error: failed');
|
|
490
506
|
});
|
|
@@ -566,11 +582,11 @@ describe('Result', () => {
|
|
|
566
582
|
|
|
567
583
|
describe('isOkAnd', () => {
|
|
568
584
|
it('returns true if Ok and predicate true', () => {
|
|
569
|
-
expect(isOkAnd(ok(5), x => x > 3)).toBe(true);
|
|
585
|
+
expect(isOkAnd(ok(5), (x) => x > 3)).toBe(true);
|
|
570
586
|
});
|
|
571
587
|
|
|
572
588
|
it('returns false if Ok and predicate false', () => {
|
|
573
|
-
expect(isOkAnd(ok(2), x => x > 3)).toBe(false);
|
|
589
|
+
expect(isOkAnd(ok(2), (x) => x > 3)).toBe(false);
|
|
574
590
|
});
|
|
575
591
|
|
|
576
592
|
it('returns false for Err', () => {
|
|
@@ -580,11 +596,11 @@ describe('Result', () => {
|
|
|
580
596
|
|
|
581
597
|
describe('isErrAnd', () => {
|
|
582
598
|
it('returns true if Err and predicate true', () => {
|
|
583
|
-
expect(isErrAnd(err('error'), e => e.length > 3)).toBe(true);
|
|
599
|
+
expect(isErrAnd(err('error'), (e) => e.length > 3)).toBe(true);
|
|
584
600
|
});
|
|
585
601
|
|
|
586
602
|
it('returns false if Err and predicate false', () => {
|
|
587
|
-
expect(isErrAnd(err('no'), e => e.length > 3)).toBe(false);
|
|
603
|
+
expect(isErrAnd(err('no'), (e) => e.length > 3)).toBe(false);
|
|
588
604
|
});
|
|
589
605
|
|
|
590
606
|
it('returns false for Ok', () => {
|
|
@@ -598,12 +614,11 @@ describe('Result', () => {
|
|
|
598
614
|
() => {
|
|
599
615
|
throw new Error('boom');
|
|
600
616
|
},
|
|
601
|
-
error => (error as Error).message,
|
|
617
|
+
(error) => (error as Error).message,
|
|
602
618
|
);
|
|
603
619
|
expect(isErr(result)).toBe(true);
|
|
604
620
|
expect((result as any).error).toBe('boom');
|
|
605
621
|
});
|
|
606
|
-
|
|
607
622
|
});
|
|
608
623
|
|
|
609
624
|
describe('wrap', () => {
|
|
@@ -643,7 +658,7 @@ describe('Result', () => {
|
|
|
643
658
|
});
|
|
644
659
|
|
|
645
660
|
it('throws Err error for failed Result', () => {
|
|
646
|
-
const fn = (x: number) => x > 0 ? ok(x) : err('negative');
|
|
661
|
+
const fn = (x: number) => (x > 0 ? ok(x) : err('negative'));
|
|
647
662
|
const throwing = toThrowable(fn);
|
|
648
663
|
expect(() => throwing(-1)).toThrow('negative');
|
|
649
664
|
});
|
|
@@ -715,22 +730,14 @@ describe('Result', () => {
|
|
|
715
730
|
});
|
|
716
731
|
|
|
717
732
|
it('partitionAsync separates async results', async () => {
|
|
718
|
-
const promises = [
|
|
719
|
-
Promise.resolve(ok(1)),
|
|
720
|
-
Promise.resolve(err('a')),
|
|
721
|
-
Promise.resolve(ok(2)),
|
|
722
|
-
];
|
|
733
|
+
const promises = [Promise.resolve(ok(1)), Promise.resolve(err('a')), Promise.resolve(ok(2))];
|
|
723
734
|
const [oks, errs] = await partitionAsync(promises);
|
|
724
735
|
expect(oks).toEqual([1, 2]);
|
|
725
736
|
expect(errs).toEqual(['a']);
|
|
726
737
|
});
|
|
727
738
|
|
|
728
739
|
it('partitionAsync handles rejected promises as errors', async () => {
|
|
729
|
-
const promises = [
|
|
730
|
-
Promise.resolve(ok(1)),
|
|
731
|
-
Promise.reject(new Error('rejected')),
|
|
732
|
-
Promise.resolve(ok(2)),
|
|
733
|
-
];
|
|
740
|
+
const promises = [Promise.resolve(ok(1)), Promise.reject(new Error('rejected')), Promise.resolve(ok(2))];
|
|
734
741
|
const [oks, errs] = await partitionAsync(promises);
|
|
735
742
|
expect(oks).toEqual([1, 2]);
|
|
736
743
|
expect(errs).toHaveLength(1);
|
|
@@ -748,12 +755,6 @@ describe('Result', () => {
|
|
|
748
755
|
expect(isOk(outcome)).toBe(true);
|
|
749
756
|
expect(unwrap(outcome)).toBe(3);
|
|
750
757
|
});
|
|
751
|
-
|
|
752
|
-
it('any returns empty errors for empty array', () => {
|
|
753
|
-
const outcome = any([]);
|
|
754
|
-
expect(isErr(outcome)).toBe(true);
|
|
755
|
-
expect((outcome as any).error).toEqual([]);
|
|
756
|
-
});
|
|
757
758
|
});
|
|
758
759
|
|
|
759
760
|
describe('tryCatchMaybePromise', () => {
|
|
@@ -785,8 +786,10 @@ describe('Result', () => {
|
|
|
785
786
|
|
|
786
787
|
it('uses onError mapper for sync throw', () => {
|
|
787
788
|
const result = tryCatchMaybePromise(
|
|
788
|
-
() => {
|
|
789
|
-
|
|
789
|
+
() => {
|
|
790
|
+
throw new Error('fail');
|
|
791
|
+
},
|
|
792
|
+
(e) => `mapped: ${(e as Error).message}`,
|
|
790
793
|
);
|
|
791
794
|
expect(isErr(result)).toBe(true);
|
|
792
795
|
expect((result as any).error).toBe('mapped: fail');
|
|
@@ -795,7 +798,7 @@ describe('Result', () => {
|
|
|
795
798
|
it('uses onError mapper for async rejection', async () => {
|
|
796
799
|
const result = await tryCatchMaybePromise(
|
|
797
800
|
() => Promise.reject(new Error('fail')),
|
|
798
|
-
(e) => `mapped: ${(e as Error).message}
|
|
801
|
+
(e) => `mapped: ${(e as Error).message}`,
|
|
799
802
|
);
|
|
800
803
|
expect(isErr(result)).toBe(true);
|
|
801
804
|
expect((result as any).error).toBe('mapped: fail');
|
|
@@ -824,10 +827,7 @@ describe('Result', () => {
|
|
|
824
827
|
});
|
|
825
828
|
|
|
826
829
|
it('handles all async values', async () => {
|
|
827
|
-
const result = await settleMaybePromise([
|
|
828
|
-
Promise.resolve(1),
|
|
829
|
-
Promise.resolve(2)
|
|
830
|
-
]);
|
|
830
|
+
const result = await settleMaybePromise([Promise.resolve(1), Promise.resolve(2)]);
|
|
831
831
|
expect(result).toEqual([1, 2]);
|
|
832
832
|
});
|
|
833
833
|
|
|
@@ -852,28 +852,20 @@ describe('Result', () => {
|
|
|
852
852
|
});
|
|
853
853
|
|
|
854
854
|
it('preserves input order with interleaved sync/async', async () => {
|
|
855
|
-
const result = await partitionMaybePromise([
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
err('b'),
|
|
855
|
+
const result = await partitionMaybePromise([Promise.resolve(ok(1)), ok(2), Promise.resolve(err('a')), err('b')]);
|
|
856
|
+
expect(result).toEqual([
|
|
857
|
+
[1, 2],
|
|
858
|
+
['a', 'b'],
|
|
860
859
|
]);
|
|
861
|
-
expect(result).toEqual([[1, 2], ['a', 'b']]);
|
|
862
860
|
});
|
|
863
861
|
|
|
864
862
|
it('handles all async values', async () => {
|
|
865
|
-
const result = await partitionMaybePromise([
|
|
866
|
-
Promise.resolve(ok(1)),
|
|
867
|
-
Promise.resolve(err('a'))
|
|
868
|
-
]);
|
|
863
|
+
const result = await partitionMaybePromise([Promise.resolve(ok(1)), Promise.resolve(err('a'))]);
|
|
869
864
|
expect(result).toEqual([[1], ['a']]);
|
|
870
865
|
});
|
|
871
866
|
|
|
872
867
|
it('handles rejected promises as errors', async () => {
|
|
873
|
-
const result = await partitionMaybePromise([
|
|
874
|
-
ok(1),
|
|
875
|
-
Promise.reject(new Error('rejected'))
|
|
876
|
-
]);
|
|
868
|
+
const result = await partitionMaybePromise([ok(1), Promise.reject(new Error('rejected'))]);
|
|
877
869
|
expect(result[0]).toEqual([1]);
|
|
878
870
|
expect(result[1]).toHaveLength(1);
|
|
879
871
|
expect((result[1][0] as Error).message).toBe('rejected');
|
|
@@ -944,7 +936,7 @@ describe('Result', () => {
|
|
|
944
936
|
});
|
|
945
937
|
|
|
946
938
|
it('propagates Err through chain', () => {
|
|
947
|
-
const parse = (s: string) => s === 'bad' ? err('parse error') : ok(Number(s));
|
|
939
|
+
const parse = (s: string) => (s === 'bad' ? err('parse error') : ok(Number(s)));
|
|
948
940
|
const result = safeTry(() => {
|
|
949
941
|
const a = unwrap(parse('10'));
|
|
950
942
|
const b = unwrap(parse('bad'));
|
|
@@ -1001,10 +993,7 @@ describe('Result', () => {
|
|
|
1001
993
|
});
|
|
1002
994
|
|
|
1003
995
|
it('uses onError mapper for rejected promise', async () => {
|
|
1004
|
-
const result = await fromPromise(
|
|
1005
|
-
Promise.reject(new Error('boom')),
|
|
1006
|
-
(e) => `mapped: ${(e as Error).message}`,
|
|
1007
|
-
);
|
|
996
|
+
const result = await fromPromise(Promise.reject(new Error('boom')), (e) => `mapped: ${(e as Error).message}`);
|
|
1008
997
|
expect(isErr(result)).toBe(true);
|
|
1009
998
|
expect((result as { error: string }).error).toBe('mapped: boom');
|
|
1010
999
|
});
|
|
@@ -1022,53 +1011,9 @@ describe('Result', () => {
|
|
|
1022
1011
|
});
|
|
1023
1012
|
});
|
|
1024
1013
|
|
|
1025
|
-
describe('fromSchema', () => {
|
|
1026
|
-
const validSchema: StandardSchema<string> = {
|
|
1027
|
-
'~standard': {
|
|
1028
|
-
validate: (value) => typeof value === 'string'
|
|
1029
|
-
? { value }
|
|
1030
|
-
: { issues: [{ message: 'Expected string' }] },
|
|
1031
|
-
},
|
|
1032
|
-
};
|
|
1033
|
-
|
|
1034
|
-
const asyncSchema: StandardSchema<number> = {
|
|
1035
|
-
'~standard': {
|
|
1036
|
-
validate: (value) => Promise.resolve(
|
|
1037
|
-
typeof value === 'number'
|
|
1038
|
-
? { value }
|
|
1039
|
-
: { issues: [{ message: 'Expected number' }] },
|
|
1040
|
-
),
|
|
1041
|
-
},
|
|
1042
|
-
};
|
|
1043
|
-
|
|
1044
|
-
it('returns Ok for valid sync schema', () => {
|
|
1045
|
-
const result = fromSchema(validSchema, 'hello');
|
|
1046
|
-
expect(isOk(result)).toBe(true);
|
|
1047
|
-
expect(result).toBe('hello');
|
|
1048
|
-
});
|
|
1049
|
-
|
|
1050
|
-
it('returns Err with issues for invalid sync schema', () => {
|
|
1051
|
-
const result = fromSchema(validSchema, 42);
|
|
1052
|
-
expect(isErr(result)).toBe(true);
|
|
1053
|
-
expect((result as any).error).toEqual([{ message: 'Expected string' }]);
|
|
1054
|
-
});
|
|
1055
|
-
|
|
1056
|
-
it('returns Ok for valid async schema', async () => {
|
|
1057
|
-
const result = await fromSchema(asyncSchema, 42);
|
|
1058
|
-
expect(isOk(result)).toBe(true);
|
|
1059
|
-
expect(result).toBe(42);
|
|
1060
|
-
});
|
|
1061
|
-
|
|
1062
|
-
it('returns Err for invalid async schema', async () => {
|
|
1063
|
-
const result = await fromSchema(asyncSchema, 'hello');
|
|
1064
|
-
expect(isErr(result)).toBe(true);
|
|
1065
|
-
expect((result as any).error).toEqual([{ message: 'Expected number' }]);
|
|
1066
|
-
});
|
|
1067
|
-
});
|
|
1068
|
-
|
|
1069
1014
|
describe('gen', () => {
|
|
1070
1015
|
it('returns Ok for successful execution', () => {
|
|
1071
|
-
const result = gen(function*($) {
|
|
1016
|
+
const result = gen(function* ($) {
|
|
1072
1017
|
const a = yield* $(ok(10));
|
|
1073
1018
|
const b = yield* $(ok(5));
|
|
1074
1019
|
return a + b;
|
|
@@ -1078,7 +1023,7 @@ describe('Result', () => {
|
|
|
1078
1023
|
});
|
|
1079
1024
|
|
|
1080
1025
|
it('short-circuits on first Err', () => {
|
|
1081
|
-
const result = gen(function*($) {
|
|
1026
|
+
const result = gen(function* ($) {
|
|
1082
1027
|
const a = yield* $(ok(10));
|
|
1083
1028
|
const b = yield* $(err('fail') as Result<number, string>);
|
|
1084
1029
|
const c = yield* $(ok(5));
|
|
@@ -1089,8 +1034,8 @@ describe('Result', () => {
|
|
|
1089
1034
|
});
|
|
1090
1035
|
|
|
1091
1036
|
it('propagates Err through chain', () => {
|
|
1092
|
-
const parse = (s: string) => s === 'bad' ? err('parse error') : ok(Number(s));
|
|
1093
|
-
const result = gen(function*($) {
|
|
1037
|
+
const parse = (s: string) => (s === 'bad' ? err('parse error') : ok(Number(s)));
|
|
1038
|
+
const result = gen(function* ($) {
|
|
1094
1039
|
const a = yield* $(parse('10'));
|
|
1095
1040
|
const b = yield* $(parse('bad'));
|
|
1096
1041
|
const c = yield* $(parse('5'));
|
|
@@ -1101,17 +1046,33 @@ describe('Result', () => {
|
|
|
1101
1046
|
});
|
|
1102
1047
|
|
|
1103
1048
|
it('returns Ok for empty generator', () => {
|
|
1104
|
-
const result = gen(function*() {
|
|
1049
|
+
const result = gen(function* () {
|
|
1105
1050
|
return 42;
|
|
1106
1051
|
});
|
|
1107
1052
|
expect(isOk(result)).toBe(true);
|
|
1108
1053
|
expect(result).toBe(42);
|
|
1109
1054
|
});
|
|
1055
|
+
|
|
1056
|
+
it('runs try/finally cleanup when short-circuiting on Err', () => {
|
|
1057
|
+
let cleanedUp = false;
|
|
1058
|
+
const result = gen(function* ($) {
|
|
1059
|
+
try {
|
|
1060
|
+
const a = yield* $(ok(10));
|
|
1061
|
+
const b = yield* $(err('fail') as Result<number, string>);
|
|
1062
|
+
return a + b;
|
|
1063
|
+
} finally {
|
|
1064
|
+
cleanedUp = true;
|
|
1065
|
+
}
|
|
1066
|
+
});
|
|
1067
|
+
expect(isErr(result)).toBe(true);
|
|
1068
|
+
expect((result as any).error).toBe('fail');
|
|
1069
|
+
expect(cleanedUp).toBe(true);
|
|
1070
|
+
});
|
|
1110
1071
|
});
|
|
1111
1072
|
|
|
1112
1073
|
describe('genAsync', () => {
|
|
1113
1074
|
it('returns Ok for successful async execution', async () => {
|
|
1114
|
-
const result = await genAsync(async function*($) {
|
|
1075
|
+
const result = await genAsync(async function* ($) {
|
|
1115
1076
|
const a = yield* $(ok(10));
|
|
1116
1077
|
const b = yield* $(await fromPromise(Promise.resolve(5)));
|
|
1117
1078
|
return a + b;
|
|
@@ -1121,7 +1082,7 @@ describe('Result', () => {
|
|
|
1121
1082
|
});
|
|
1122
1083
|
|
|
1123
1084
|
it('short-circuits on first Err', async () => {
|
|
1124
|
-
const result = await genAsync(async function*($) {
|
|
1085
|
+
const result = await genAsync(async function* ($) {
|
|
1125
1086
|
const a = yield* $(ok(10));
|
|
1126
1087
|
const b = yield* $(err('async fail') as Result<number, string>);
|
|
1127
1088
|
return a + b;
|
|
@@ -1131,7 +1092,7 @@ describe('Result', () => {
|
|
|
1131
1092
|
});
|
|
1132
1093
|
|
|
1133
1094
|
it('handles rejected promises via fromPromise', async () => {
|
|
1134
|
-
const result = await genAsync(async function*($) {
|
|
1095
|
+
const result = await genAsync(async function* ($) {
|
|
1135
1096
|
const a = yield* $(await fromPromise(Promise.resolve(10)));
|
|
1136
1097
|
const b = yield* $(await fromPromise(Promise.reject('boom')));
|
|
1137
1098
|
return a + b;
|
|
@@ -1139,7 +1100,21 @@ describe('Result', () => {
|
|
|
1139
1100
|
expect(isErr(result)).toBe(true);
|
|
1140
1101
|
expect((result as any).error).toBe('boom');
|
|
1141
1102
|
});
|
|
1142
|
-
});
|
|
1143
1103
|
|
|
1104
|
+
it('runs try/finally cleanup when short-circuiting on Err', async () => {
|
|
1105
|
+
let cleanedUp = false;
|
|
1106
|
+
const result = await genAsync(async function* ($) {
|
|
1107
|
+
try {
|
|
1108
|
+
const a = yield* $(ok(10));
|
|
1109
|
+
const b = yield* $(err('async fail') as Result<number, string>);
|
|
1110
|
+
return a + b;
|
|
1111
|
+
} finally {
|
|
1112
|
+
cleanedUp = true;
|
|
1113
|
+
}
|
|
1114
|
+
});
|
|
1115
|
+
expect(isErr(result)).toBe(true);
|
|
1116
|
+
expect((result as any).error).toBe('async fail');
|
|
1117
|
+
expect(cleanedUp).toBe(true);
|
|
1118
|
+
});
|
|
1119
|
+
});
|
|
1144
1120
|
});
|
|
1145
|
-
|
|
@@ -138,7 +138,7 @@ const collected = collect(results);
|
|
|
138
138
|
assert<Equals<typeof collected, Result<number[], string>>>;
|
|
139
139
|
|
|
140
140
|
const collectedAll = collectAll(results);
|
|
141
|
-
assert<Equals<typeof collectedAll, Result<number[], string[]>>>;
|
|
141
|
+
assert<Equals<typeof collectedAll, Result<number[], [string, ...string[]]>>>;
|
|
142
142
|
|
|
143
143
|
const transposed = transpose(ok(42 as Option<number>) as Result<Option<number>, string>);
|
|
144
144
|
assert<Equals<typeof transposed, Option<Result<number, string>>>>;
|
|
@@ -234,7 +234,7 @@ const allResult = all([ok(1), ok(2)]);
|
|
|
234
234
|
assert<Equals<typeof allResult, Result<readonly number[], unknown>>>;
|
|
235
235
|
|
|
236
236
|
const anyResult = any([err('a'), ok(3)]);
|
|
237
|
-
assert<Equals<typeof anyResult, Result<number, string[]>>>;
|
|
237
|
+
assert<Equals<typeof anyResult, Result<number, [string, ...string[]]>>>;
|
|
238
238
|
|
|
239
239
|
const partitionAsyncResult = partitionAsync([Promise.resolve(ok(1)), Promise.resolve(err('a'))]);
|
|
240
240
|
assert<Equals<typeof partitionAsyncResult, Promise<[number[], string[]]>>>;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { fromSchema, wrapSchema } from '../schema.js';
|
|
3
|
+
import type { StandardSchema } from '../schema.js';
|
|
4
|
+
import { isOk, isErr } from '../types.js';
|
|
5
|
+
|
|
6
|
+
describe('Schema', () => {
|
|
7
|
+
const validSchema: StandardSchema<string> = {
|
|
8
|
+
'~standard': {
|
|
9
|
+
validate: (value) => (typeof value === 'string' ? { value } : { issues: [{ message: 'Expected string' }] }),
|
|
10
|
+
},
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
const asyncSchema: StandardSchema<number> = {
|
|
14
|
+
'~standard': {
|
|
15
|
+
validate: (value) => Promise.resolve(typeof value === 'number' ? { value } : { issues: [{ message: 'Expected number' }] }),
|
|
16
|
+
},
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
describe('fromSchema', () => {
|
|
20
|
+
it('returns Ok for valid sync schema', () => {
|
|
21
|
+
const result = fromSchema(validSchema, 'hello');
|
|
22
|
+
expect(isOk(result)).toBe(true);
|
|
23
|
+
expect(result).toBe('hello');
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it('returns Err with issues for invalid sync schema', () => {
|
|
27
|
+
const result = fromSchema(validSchema, 42);
|
|
28
|
+
expect(isErr(result)).toBe(true);
|
|
29
|
+
expect((result as any).error).toEqual([{ message: 'Expected string' }]);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it('returns Ok for valid async schema', async () => {
|
|
33
|
+
const result = await fromSchema(asyncSchema, 42);
|
|
34
|
+
expect(isOk(result)).toBe(true);
|
|
35
|
+
expect(result).toBe(42);
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it('returns Err for invalid async schema', async () => {
|
|
39
|
+
const result = await fromSchema(asyncSchema, 'hello');
|
|
40
|
+
expect(isErr(result)).toBe(true);
|
|
41
|
+
expect((result as any).error).toEqual([{ message: 'Expected number' }]);
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
describe('wrapSchema', () => {
|
|
46
|
+
it('creates a reusable sync validator', () => {
|
|
47
|
+
const parse = wrapSchema(validSchema);
|
|
48
|
+
expect(parse('hello')).toBe('hello');
|
|
49
|
+
expect(isErr(parse(42))).toBe(true);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it('creates a reusable async validator', async () => {
|
|
53
|
+
const parse = wrapSchema(asyncSchema);
|
|
54
|
+
expect(await parse(42)).toBe(42);
|
|
55
|
+
expect(isErr(await parse('hello'))).toBe(true);
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
});
|