@barnum/barnum 0.0.0-main-ef6df91f → 0.0.0-main-e8b82cff
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/artifacts/linux-arm64/barnum +0 -0
- package/artifacts/linux-x64/barnum +0 -0
- package/artifacts/macos-arm64/barnum +0 -0
- package/artifacts/macos-x64/barnum +0 -0
- package/artifacts/win-x64/barnum.exe +0 -0
- package/package.json +2 -1
- package/src/all.ts +116 -26
- package/src/ast.ts +262 -454
- package/src/bind.ts +65 -30
- package/src/builtins.ts +222 -123
- package/src/chain.ts +11 -2
- package/src/effect-id.ts +21 -6
- package/src/handler.ts +75 -32
- package/src/index.ts +11 -3
- package/src/pipe.ts +124 -29
- package/src/race.ts +58 -52
- package/src/run.ts +64 -23
- package/src/schema.ts +118 -0
- package/src/try-catch.ts +29 -30
- package/src/worker.ts +10 -1
package/src/builtins.ts
CHANGED
|
@@ -1,4 +1,12 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
type Action,
|
|
3
|
+
type Option as OptionT,
|
|
4
|
+
type Pipeable,
|
|
5
|
+
type Result as ResultT,
|
|
6
|
+
type TaggedUnion,
|
|
7
|
+
type TypedAction,
|
|
8
|
+
typedAction,
|
|
9
|
+
} from "./ast.js";
|
|
2
10
|
import { chain } from "./chain.js";
|
|
3
11
|
|
|
4
12
|
/**
|
|
@@ -51,9 +59,7 @@ export const drop: TypedAction<any, never> = typedAction({
|
|
|
51
59
|
export function tag<
|
|
52
60
|
TDef extends Record<string, unknown>,
|
|
53
61
|
TKind extends keyof TDef & string,
|
|
54
|
-
>(
|
|
55
|
-
kind: TKind,
|
|
56
|
-
): TypedAction<TDef[TKind], TaggedUnion<TDef>> {
|
|
62
|
+
>(kind: TKind): TypedAction<TDef[TKind], TaggedUnion<TDef>> {
|
|
57
63
|
return typedAction({
|
|
58
64
|
kind: "Invoke",
|
|
59
65
|
handler: { kind: "Builtin", builtin: { kind: "Tag", value: kind } },
|
|
@@ -112,10 +118,9 @@ export function extractField<
|
|
|
112
118
|
// ExtractIndex — extract a single element from an array by index
|
|
113
119
|
// ---------------------------------------------------------------------------
|
|
114
120
|
|
|
115
|
-
export function extractIndex<
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
>(index: TIndex): TypedAction<TTuple, TTuple[TIndex]> {
|
|
121
|
+
export function extractIndex<TTuple extends unknown[], TIndex extends number>(
|
|
122
|
+
index: TIndex,
|
|
123
|
+
): TypedAction<TTuple, TTuple[TIndex]> {
|
|
119
124
|
return typedAction({
|
|
120
125
|
kind: "Invoke",
|
|
121
126
|
handler: {
|
|
@@ -151,7 +156,10 @@ export function dropResult<TInput, TOutput, TRefs extends string = never>(
|
|
|
151
156
|
return typedAction({
|
|
152
157
|
kind: "Chain",
|
|
153
158
|
first: action as Action,
|
|
154
|
-
rest: {
|
|
159
|
+
rest: {
|
|
160
|
+
kind: "Invoke",
|
|
161
|
+
handler: { kind: "Builtin", builtin: { kind: "Drop" } },
|
|
162
|
+
},
|
|
155
163
|
});
|
|
156
164
|
}
|
|
157
165
|
|
|
@@ -205,13 +213,19 @@ export function withResource<
|
|
|
205
213
|
|
|
206
214
|
// Step 2: all(action, identity) → [TOut, TResource & TIn]
|
|
207
215
|
// Keep merged object so dispose can access resource fields.
|
|
208
|
-
const actionAndKeepMerged = typedAction<
|
|
216
|
+
const actionAndKeepMerged = typedAction<
|
|
217
|
+
TResource & TIn,
|
|
218
|
+
[TOut, TResource & TIn]
|
|
219
|
+
>({
|
|
209
220
|
kind: "All",
|
|
210
221
|
actions: [action as Action, identity as Action],
|
|
211
222
|
});
|
|
212
223
|
|
|
213
224
|
// Step 3: all(extractIndex(0), chain(extractIndex(1), dispose)) → [TOut, unknown]
|
|
214
|
-
const disposeAndKeepResult = typedAction<
|
|
225
|
+
const disposeAndKeepResult = typedAction<
|
|
226
|
+
[TOut, TResource & TIn],
|
|
227
|
+
[TOut, unknown]
|
|
228
|
+
>({
|
|
215
229
|
kind: "All",
|
|
216
230
|
actions: [
|
|
217
231
|
extractIndex<[TOut, TResource & TIn], 0>(0) as Action,
|
|
@@ -257,7 +271,10 @@ export function augment<
|
|
|
257
271
|
kind: "All",
|
|
258
272
|
actions: [action as Action, identity as Action],
|
|
259
273
|
},
|
|
260
|
-
rest: {
|
|
274
|
+
rest: {
|
|
275
|
+
kind: "Invoke",
|
|
276
|
+
handler: { kind: "Builtin", builtin: { kind: "Merge" } },
|
|
277
|
+
},
|
|
261
278
|
});
|
|
262
279
|
}
|
|
263
280
|
|
|
@@ -277,9 +294,10 @@ export function augment<
|
|
|
277
294
|
* Example:
|
|
278
295
|
* pipe(tap(pipe(pick("worktreePath", "description"), implement)), createPR)
|
|
279
296
|
*/
|
|
280
|
-
export function tap<
|
|
281
|
-
|
|
282
|
-
|
|
297
|
+
export function tap<
|
|
298
|
+
TInput extends Record<string, unknown>,
|
|
299
|
+
TRefs extends string = never,
|
|
300
|
+
>(action: Pipeable<TInput, any, TRefs>): TypedAction<TInput, TInput, TRefs> {
|
|
283
301
|
// Build AST directly — internal plumbing (action → constant → augment)
|
|
284
302
|
// can't go through typed chain/augment with invariant phantom fields.
|
|
285
303
|
// tap: all(chain(action, constant({})), identity()) → merge
|
|
@@ -291,12 +309,24 @@ export function tap<TInput extends Record<string, unknown>, TRefs extends string
|
|
|
291
309
|
{
|
|
292
310
|
kind: "Chain",
|
|
293
311
|
first: action as Action,
|
|
294
|
-
rest: {
|
|
312
|
+
rest: {
|
|
313
|
+
kind: "Invoke",
|
|
314
|
+
handler: {
|
|
315
|
+
kind: "Builtin",
|
|
316
|
+
builtin: { kind: "Constant", value: {} },
|
|
317
|
+
},
|
|
318
|
+
},
|
|
319
|
+
},
|
|
320
|
+
{
|
|
321
|
+
kind: "Invoke",
|
|
322
|
+
handler: { kind: "Builtin", builtin: { kind: "Identity" } },
|
|
295
323
|
},
|
|
296
|
-
{ kind: "Invoke", handler: { kind: "Builtin", builtin: { kind: "Identity" } } },
|
|
297
324
|
],
|
|
298
325
|
},
|
|
299
|
-
rest: {
|
|
326
|
+
rest: {
|
|
327
|
+
kind: "Invoke",
|
|
328
|
+
handler: { kind: "Builtin", builtin: { kind: "Merge" } },
|
|
329
|
+
},
|
|
300
330
|
});
|
|
301
331
|
}
|
|
302
332
|
|
|
@@ -304,10 +334,7 @@ export function tap<TInput extends Record<string, unknown>, TRefs extends string
|
|
|
304
334
|
// Range — produce an integer array [start, start+1, ..., end-1]
|
|
305
335
|
// ---------------------------------------------------------------------------
|
|
306
336
|
|
|
307
|
-
export function range(
|
|
308
|
-
start: number,
|
|
309
|
-
end: number,
|
|
310
|
-
): TypedAction<any, number[]> {
|
|
337
|
+
export function range(start: number, end: number): TypedAction<any, number[]> {
|
|
311
338
|
const result: number[] = [];
|
|
312
339
|
for (let i = start; i < end; i++) {
|
|
313
340
|
result.push(i);
|
|
@@ -323,11 +350,29 @@ export function range(
|
|
|
323
350
|
// ---------------------------------------------------------------------------
|
|
324
351
|
|
|
325
352
|
// Shared AST fragments for Option desugaring
|
|
326
|
-
const TAG_SOME: Action = {
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
const
|
|
353
|
+
const TAG_SOME: Action = {
|
|
354
|
+
kind: "Invoke",
|
|
355
|
+
handler: { kind: "Builtin", builtin: { kind: "Tag", value: "Some" } },
|
|
356
|
+
};
|
|
357
|
+
const TAG_NONE: Action = {
|
|
358
|
+
kind: "Invoke",
|
|
359
|
+
handler: { kind: "Builtin", builtin: { kind: "Tag", value: "None" } },
|
|
360
|
+
};
|
|
361
|
+
const EXTRACT_VALUE: Action = {
|
|
362
|
+
kind: "Invoke",
|
|
363
|
+
handler: {
|
|
364
|
+
kind: "Builtin",
|
|
365
|
+
builtin: { kind: "ExtractField", value: "value" },
|
|
366
|
+
},
|
|
367
|
+
};
|
|
368
|
+
const DROP: Action = {
|
|
369
|
+
kind: "Invoke",
|
|
370
|
+
handler: { kind: "Builtin", builtin: { kind: "Drop" } },
|
|
371
|
+
};
|
|
372
|
+
const IDENTITY: Action = {
|
|
373
|
+
kind: "Invoke",
|
|
374
|
+
handler: { kind: "Builtin", builtin: { kind: "Identity" } },
|
|
375
|
+
};
|
|
331
376
|
|
|
332
377
|
/** Wrap branch cases with ExtractField("value") auto-unwrapping. */
|
|
333
378
|
function optionBranch(someCaseBody: Action, noneCaseBody: Action): Action {
|
|
@@ -370,10 +415,12 @@ export const Option = {
|
|
|
370
415
|
* Desugars to: `branch({ Some: pipe(action, tag("Some")), None: tag("None") })`
|
|
371
416
|
*/
|
|
372
417
|
map<T, U>(action: Pipeable<T, U>): TypedAction<OptionT<T>, OptionT<U>> {
|
|
373
|
-
return typedAction(
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
418
|
+
return typedAction(
|
|
419
|
+
optionBranch(
|
|
420
|
+
{ kind: "Chain", first: action as Action, rest: TAG_SOME },
|
|
421
|
+
TAG_NONE,
|
|
422
|
+
),
|
|
423
|
+
);
|
|
377
424
|
},
|
|
378
425
|
|
|
379
426
|
/**
|
|
@@ -385,11 +432,10 @@ export const Option = {
|
|
|
385
432
|
*
|
|
386
433
|
* Desugars to: `branch({ Some: action, None: tag("None") })`
|
|
387
434
|
*/
|
|
388
|
-
andThen<T, U>(
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
));
|
|
435
|
+
andThen<T, U>(
|
|
436
|
+
action: Pipeable<T, OptionT<U>>,
|
|
437
|
+
): TypedAction<OptionT<T>, OptionT<U>> {
|
|
438
|
+
return typedAction(optionBranch(action as Action, TAG_NONE));
|
|
393
439
|
},
|
|
394
440
|
|
|
395
441
|
/**
|
|
@@ -410,7 +456,11 @@ export const Option = {
|
|
|
410
456
|
kind: "Branch",
|
|
411
457
|
cases: {
|
|
412
458
|
Some: { kind: "Chain", first: EXTRACT_VALUE, rest: IDENTITY },
|
|
413
|
-
None: {
|
|
459
|
+
None: {
|
|
460
|
+
kind: "Chain",
|
|
461
|
+
first: EXTRACT_VALUE,
|
|
462
|
+
rest: { kind: "Chain", first: DROP, rest: defaultAction as Action },
|
|
463
|
+
},
|
|
414
464
|
},
|
|
415
465
|
});
|
|
416
466
|
},
|
|
@@ -421,10 +471,7 @@ export const Option = {
|
|
|
421
471
|
* Desugars to: `branch({ Some: identity(), None: tag("None") })`
|
|
422
472
|
*/
|
|
423
473
|
flatten<T>(): TypedAction<OptionT<OptionT<T>>, OptionT<T>> {
|
|
424
|
-
return typedAction(optionBranch(
|
|
425
|
-
IDENTITY,
|
|
426
|
-
TAG_NONE,
|
|
427
|
-
));
|
|
474
|
+
return typedAction(optionBranch(IDENTITY, TAG_NONE));
|
|
428
475
|
},
|
|
429
476
|
|
|
430
477
|
/**
|
|
@@ -437,11 +484,10 @@ export const Option = {
|
|
|
437
484
|
*
|
|
438
485
|
* Desugars to: `branch({ Some: predicate, None: tag("None") })`
|
|
439
486
|
*/
|
|
440
|
-
filter<T>(
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
));
|
|
487
|
+
filter<T>(
|
|
488
|
+
predicate: Pipeable<T, OptionT<T>>,
|
|
489
|
+
): TypedAction<OptionT<T>, OptionT<T>> {
|
|
490
|
+
return typedAction(optionBranch(predicate as Action, TAG_NONE));
|
|
445
491
|
},
|
|
446
492
|
|
|
447
493
|
/**
|
|
@@ -467,12 +513,20 @@ export const Option = {
|
|
|
467
513
|
* Desugars to: `branch({ Some: pipe(drop(), constant(true)), None: pipe(drop(), constant(false)) })`
|
|
468
514
|
*/
|
|
469
515
|
isSome<T>(): TypedAction<OptionT<T>, boolean> {
|
|
470
|
-
const constTrue: Action = {
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
516
|
+
const constTrue: Action = {
|
|
517
|
+
kind: "Invoke",
|
|
518
|
+
handler: { kind: "Builtin", builtin: { kind: "Constant", value: true } },
|
|
519
|
+
};
|
|
520
|
+
const constFalse: Action = {
|
|
521
|
+
kind: "Invoke",
|
|
522
|
+
handler: { kind: "Builtin", builtin: { kind: "Constant", value: false } },
|
|
523
|
+
};
|
|
524
|
+
return typedAction(
|
|
525
|
+
optionBranch(
|
|
526
|
+
{ kind: "Chain", first: DROP, rest: constTrue },
|
|
527
|
+
{ kind: "Chain", first: DROP, rest: constFalse },
|
|
528
|
+
),
|
|
529
|
+
);
|
|
476
530
|
},
|
|
477
531
|
|
|
478
532
|
/**
|
|
@@ -483,12 +537,20 @@ export const Option = {
|
|
|
483
537
|
* Desugars to: `branch({ Some: pipe(drop(), constant(false)), None: pipe(drop(), constant(true)) })`
|
|
484
538
|
*/
|
|
485
539
|
isNone<T>(): TypedAction<OptionT<T>, boolean> {
|
|
486
|
-
const constTrue: Action = {
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
540
|
+
const constTrue: Action = {
|
|
541
|
+
kind: "Invoke",
|
|
542
|
+
handler: { kind: "Builtin", builtin: { kind: "Constant", value: true } },
|
|
543
|
+
};
|
|
544
|
+
const constFalse: Action = {
|
|
545
|
+
kind: "Invoke",
|
|
546
|
+
handler: { kind: "Builtin", builtin: { kind: "Constant", value: false } },
|
|
547
|
+
};
|
|
548
|
+
return typedAction(
|
|
549
|
+
optionBranch(
|
|
550
|
+
{ kind: "Chain", first: DROP, rest: constFalse },
|
|
551
|
+
{ kind: "Chain", first: DROP, rest: constTrue },
|
|
552
|
+
),
|
|
553
|
+
);
|
|
492
554
|
},
|
|
493
555
|
} as const;
|
|
494
556
|
|
|
@@ -497,8 +559,14 @@ export const Option = {
|
|
|
497
559
|
// ---------------------------------------------------------------------------
|
|
498
560
|
|
|
499
561
|
// Shared AST fragments for Result desugaring
|
|
500
|
-
const TAG_OK: Action = {
|
|
501
|
-
|
|
562
|
+
const TAG_OK: Action = {
|
|
563
|
+
kind: "Invoke",
|
|
564
|
+
handler: { kind: "Builtin", builtin: { kind: "Tag", value: "Ok" } },
|
|
565
|
+
};
|
|
566
|
+
const TAG_ERR: Action = {
|
|
567
|
+
kind: "Invoke",
|
|
568
|
+
handler: { kind: "Builtin", builtin: { kind: "Tag", value: "Err" } },
|
|
569
|
+
};
|
|
502
570
|
|
|
503
571
|
/** Wrap branch cases with ExtractField("value") auto-unwrapping. */
|
|
504
572
|
function resultBranch(okCaseBody: Action, errCaseBody: Action): Action {
|
|
@@ -538,10 +606,12 @@ export const Result = {
|
|
|
538
606
|
map<TValue, TOut, TError>(
|
|
539
607
|
action: Pipeable<TValue, TOut>,
|
|
540
608
|
): TypedAction<ResultT<TValue, TError>, ResultT<TOut, TError>> {
|
|
541
|
-
return typedAction(
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
609
|
+
return typedAction(
|
|
610
|
+
resultBranch(
|
|
611
|
+
{ kind: "Chain", first: action as Action, rest: TAG_OK },
|
|
612
|
+
TAG_ERR,
|
|
613
|
+
),
|
|
614
|
+
);
|
|
545
615
|
},
|
|
546
616
|
|
|
547
617
|
/**
|
|
@@ -552,10 +622,13 @@ export const Result = {
|
|
|
552
622
|
mapErr<TValue, TError, TErrorOut>(
|
|
553
623
|
action: Pipeable<TError, TErrorOut>,
|
|
554
624
|
): TypedAction<ResultT<TValue, TError>, ResultT<TValue, TErrorOut>> {
|
|
555
|
-
return typedAction(
|
|
556
|
-
TAG_OK,
|
|
557
|
-
|
|
558
|
-
|
|
625
|
+
return typedAction(
|
|
626
|
+
resultBranch(TAG_OK, {
|
|
627
|
+
kind: "Chain",
|
|
628
|
+
first: action as Action,
|
|
629
|
+
rest: TAG_ERR,
|
|
630
|
+
}),
|
|
631
|
+
);
|
|
559
632
|
},
|
|
560
633
|
|
|
561
634
|
/**
|
|
@@ -567,10 +640,7 @@ export const Result = {
|
|
|
567
640
|
andThen<TValue, TOut, TError>(
|
|
568
641
|
action: Pipeable<TValue, ResultT<TOut, TError>>,
|
|
569
642
|
): TypedAction<ResultT<TValue, TError>, ResultT<TOut, TError>> {
|
|
570
|
-
return typedAction(resultBranch(
|
|
571
|
-
action as Action,
|
|
572
|
-
TAG_ERR,
|
|
573
|
-
));
|
|
643
|
+
return typedAction(resultBranch(action as Action, TAG_ERR));
|
|
574
644
|
},
|
|
575
645
|
|
|
576
646
|
/**
|
|
@@ -582,10 +652,7 @@ export const Result = {
|
|
|
582
652
|
or<TValue, TError, TErrorOut>(
|
|
583
653
|
fallback: Pipeable<TError, ResultT<TValue, TErrorOut>>,
|
|
584
654
|
): TypedAction<ResultT<TValue, TError>, ResultT<TValue, TErrorOut>> {
|
|
585
|
-
return typedAction(resultBranch(
|
|
586
|
-
TAG_OK,
|
|
587
|
-
fallback as Action,
|
|
588
|
-
));
|
|
655
|
+
return typedAction(resultBranch(TAG_OK, fallback as Action));
|
|
589
656
|
},
|
|
590
657
|
|
|
591
658
|
/**
|
|
@@ -597,10 +664,12 @@ export const Result = {
|
|
|
597
664
|
and<TValue, TOut, TError>(
|
|
598
665
|
other: Pipeable<never, ResultT<TOut, TError>>,
|
|
599
666
|
): TypedAction<ResultT<TValue, TError>, ResultT<TOut, TError>> {
|
|
600
|
-
return typedAction(
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
667
|
+
return typedAction(
|
|
668
|
+
resultBranch(
|
|
669
|
+
{ kind: "Chain", first: DROP, rest: other as Action },
|
|
670
|
+
TAG_ERR,
|
|
671
|
+
),
|
|
672
|
+
);
|
|
604
673
|
},
|
|
605
674
|
|
|
606
675
|
/**
|
|
@@ -621,10 +690,7 @@ export const Result = {
|
|
|
621
690
|
__phantom_out?: () => TValue;
|
|
622
691
|
},
|
|
623
692
|
): TypedAction<ResultT<TValue, TError>, TValue> {
|
|
624
|
-
return typedAction(resultBranch(
|
|
625
|
-
IDENTITY,
|
|
626
|
-
defaultAction as Action,
|
|
627
|
-
));
|
|
693
|
+
return typedAction(resultBranch(IDENTITY, defaultAction as Action));
|
|
628
694
|
},
|
|
629
695
|
|
|
630
696
|
/**
|
|
@@ -632,11 +698,11 @@ export const Result = {
|
|
|
632
698
|
*
|
|
633
699
|
* Desugars to: `branch({ Ok: identity(), Err: tag("Err") })`
|
|
634
700
|
*/
|
|
635
|
-
flatten<TValue, TError>(): TypedAction<
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
));
|
|
701
|
+
flatten<TValue, TError>(): TypedAction<
|
|
702
|
+
ResultT<ResultT<TValue, TError>, TError>,
|
|
703
|
+
ResultT<TValue, TError>
|
|
704
|
+
> {
|
|
705
|
+
return typedAction(resultBranch(IDENTITY, TAG_ERR));
|
|
640
706
|
},
|
|
641
707
|
|
|
642
708
|
/**
|
|
@@ -644,11 +710,13 @@ export const Result = {
|
|
|
644
710
|
*
|
|
645
711
|
* Desugars to: `branch({ Ok: tag("Some"), Err: pipe(drop(), tag("None")) })`
|
|
646
712
|
*/
|
|
647
|
-
toOption<TValue, TError>(): TypedAction<
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
713
|
+
toOption<TValue, TError>(): TypedAction<
|
|
714
|
+
ResultT<TValue, TError>,
|
|
715
|
+
OptionT<TValue>
|
|
716
|
+
> {
|
|
717
|
+
return typedAction(
|
|
718
|
+
resultBranch(TAG_SOME, { kind: "Chain", first: DROP, rest: TAG_NONE }),
|
|
719
|
+
);
|
|
652
720
|
},
|
|
653
721
|
|
|
654
722
|
/**
|
|
@@ -656,53 +724,84 @@ export const Result = {
|
|
|
656
724
|
*
|
|
657
725
|
* Desugars to: `branch({ Ok: pipe(drop(), tag("None")), Err: tag("Some") })`
|
|
658
726
|
*/
|
|
659
|
-
toOptionErr<TValue, TError>(): TypedAction<
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
727
|
+
toOptionErr<TValue, TError>(): TypedAction<
|
|
728
|
+
ResultT<TValue, TError>,
|
|
729
|
+
OptionT<TError>
|
|
730
|
+
> {
|
|
731
|
+
return typedAction(
|
|
732
|
+
resultBranch({ kind: "Chain", first: DROP, rest: TAG_NONE }, TAG_SOME),
|
|
733
|
+
);
|
|
664
734
|
},
|
|
665
735
|
|
|
666
736
|
/**
|
|
667
737
|
* Swap Result/Option nesting.
|
|
668
738
|
* `Result<Option<TValue>, TError> → Option<Result<TValue, TError>>`
|
|
669
739
|
*/
|
|
670
|
-
transpose<TValue, TError>(): TypedAction<
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
740
|
+
transpose<TValue, TError>(): TypedAction<
|
|
741
|
+
ResultT<OptionT<TValue>, TError>,
|
|
742
|
+
OptionT<ResultT<TValue, TError>>
|
|
743
|
+
> {
|
|
744
|
+
return typedAction(
|
|
745
|
+
resultBranch(
|
|
746
|
+
// Ok case: receives Option<TValue>, branch on Some/None
|
|
747
|
+
{
|
|
748
|
+
kind: "Branch",
|
|
749
|
+
cases: {
|
|
750
|
+
Some: {
|
|
751
|
+
kind: "Chain",
|
|
752
|
+
first: EXTRACT_VALUE,
|
|
753
|
+
rest: { kind: "Chain", first: TAG_OK, rest: TAG_SOME },
|
|
754
|
+
},
|
|
755
|
+
None: {
|
|
756
|
+
kind: "Chain",
|
|
757
|
+
first: EXTRACT_VALUE,
|
|
758
|
+
rest: { kind: "Chain", first: DROP, rest: TAG_NONE },
|
|
759
|
+
},
|
|
760
|
+
},
|
|
678
761
|
},
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
)
|
|
762
|
+
// Err case: receives TError, wrap as Result.err then Option.some
|
|
763
|
+
{ kind: "Chain", first: TAG_ERR, rest: TAG_SOME },
|
|
764
|
+
),
|
|
765
|
+
);
|
|
683
766
|
},
|
|
684
767
|
|
|
685
768
|
/**
|
|
686
769
|
* Test if the value is Ok. `Result<TValue, TError> → boolean`
|
|
687
770
|
*/
|
|
688
771
|
isOk<TValue, TError>(): TypedAction<ResultT<TValue, TError>, boolean> {
|
|
689
|
-
const constTrue: Action = {
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
772
|
+
const constTrue: Action = {
|
|
773
|
+
kind: "Invoke",
|
|
774
|
+
handler: { kind: "Builtin", builtin: { kind: "Constant", value: true } },
|
|
775
|
+
};
|
|
776
|
+
const constFalse: Action = {
|
|
777
|
+
kind: "Invoke",
|
|
778
|
+
handler: { kind: "Builtin", builtin: { kind: "Constant", value: false } },
|
|
779
|
+
};
|
|
780
|
+
return typedAction(
|
|
781
|
+
resultBranch(
|
|
782
|
+
{ kind: "Chain", first: DROP, rest: constTrue },
|
|
783
|
+
{ kind: "Chain", first: DROP, rest: constFalse },
|
|
784
|
+
),
|
|
785
|
+
);
|
|
695
786
|
},
|
|
696
787
|
|
|
697
788
|
/**
|
|
698
789
|
* Test if the value is Err. `Result<TValue, TError> → boolean`
|
|
699
790
|
*/
|
|
700
791
|
isErr<TValue, TError>(): TypedAction<ResultT<TValue, TError>, boolean> {
|
|
701
|
-
const constTrue: Action = {
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
792
|
+
const constTrue: Action = {
|
|
793
|
+
kind: "Invoke",
|
|
794
|
+
handler: { kind: "Builtin", builtin: { kind: "Constant", value: true } },
|
|
795
|
+
};
|
|
796
|
+
const constFalse: Action = {
|
|
797
|
+
kind: "Invoke",
|
|
798
|
+
handler: { kind: "Builtin", builtin: { kind: "Constant", value: false } },
|
|
799
|
+
};
|
|
800
|
+
return typedAction(
|
|
801
|
+
resultBranch(
|
|
802
|
+
{ kind: "Chain", first: DROP, rest: constFalse },
|
|
803
|
+
{ kind: "Chain", first: DROP, rest: constTrue },
|
|
804
|
+
),
|
|
805
|
+
);
|
|
707
806
|
},
|
|
708
807
|
} as const;
|
package/src/chain.ts
CHANGED
|
@@ -1,8 +1,17 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
type Action,
|
|
3
|
+
type Pipeable,
|
|
4
|
+
type TypedAction,
|
|
5
|
+
typedAction,
|
|
6
|
+
} from "./ast.js";
|
|
2
7
|
|
|
3
8
|
export function chain<T1, T2, T3, R1 extends string, R2 extends string>(
|
|
4
9
|
first: Pipeable<T1, T2, R1>,
|
|
5
10
|
rest: Pipeable<T2, T3, R2>,
|
|
6
11
|
): TypedAction<T1, T3, R1 | R2> {
|
|
7
|
-
return typedAction({
|
|
12
|
+
return typedAction({
|
|
13
|
+
kind: "Chain",
|
|
14
|
+
first: first as Action,
|
|
15
|
+
rest: rest as Action,
|
|
16
|
+
});
|
|
8
17
|
}
|
package/src/effect-id.ts
CHANGED
|
@@ -2,14 +2,29 @@
|
|
|
2
2
|
// Shared effect ID counter for gensym'd effect identifiers
|
|
3
3
|
// ---------------------------------------------------------------------------
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
/** Branded ID for resume-style effect handlers. */
|
|
6
|
+
export type ResumeHandlerId = number & {
|
|
7
|
+
readonly __resumeHandlerBrand: unique symbol;
|
|
8
|
+
};
|
|
6
9
|
|
|
7
|
-
/**
|
|
8
|
-
export
|
|
9
|
-
|
|
10
|
+
/** Branded ID for restart-style effect handlers. */
|
|
11
|
+
export type RestartHandlerId = number & {
|
|
12
|
+
readonly __restartHandlerBrand: unique symbol;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
let nextId = 0;
|
|
16
|
+
|
|
17
|
+
/** Allocate a fresh, unique resume handler ID. */
|
|
18
|
+
export function allocateResumeHandlerId(): ResumeHandlerId {
|
|
19
|
+
return nextId++ as ResumeHandlerId;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/** Allocate a fresh, unique restart handler ID. */
|
|
23
|
+
export function allocateRestartHandlerId(): RestartHandlerId {
|
|
24
|
+
return nextId++ as RestartHandlerId;
|
|
10
25
|
}
|
|
11
26
|
|
|
12
|
-
/** Reset the
|
|
27
|
+
/** Reset the ID counter. For test isolation only. */
|
|
13
28
|
export function resetEffectIdCounter(): void {
|
|
14
|
-
|
|
29
|
+
nextId = 0;
|
|
15
30
|
}
|