@barnum/barnum 0.3.0 → 0.4.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.
Files changed (109) hide show
  1. package/artifacts/linux-arm64/barnum +0 -0
  2. package/artifacts/linux-x64/barnum +0 -0
  3. package/artifacts/macos-arm64/barnum +0 -0
  4. package/artifacts/macos-x64/barnum +0 -0
  5. package/artifacts/win-x64/barnum.exe +0 -0
  6. package/dist/all.d.ts +41 -10
  7. package/dist/all.d.ts.map +1 -0
  8. package/dist/all.js +1 -1
  9. package/dist/ast.d.ts +199 -98
  10. package/dist/ast.d.ts.map +1 -0
  11. package/dist/ast.js +271 -233
  12. package/dist/bind.d.ts +9 -12
  13. package/dist/bind.d.ts.map +1 -0
  14. package/dist/bind.js +14 -51
  15. package/dist/builtins/array.d.ts +36 -0
  16. package/dist/builtins/array.d.ts.map +1 -0
  17. package/dist/builtins/array.js +93 -0
  18. package/dist/builtins/index.d.ts +6 -0
  19. package/dist/builtins/index.d.ts.map +1 -0
  20. package/dist/builtins/index.js +5 -0
  21. package/dist/builtins/scalar.d.ts +12 -0
  22. package/dist/builtins/scalar.d.ts.map +1 -0
  23. package/dist/builtins/scalar.js +41 -0
  24. package/dist/builtins/struct.d.ts +25 -0
  25. package/dist/builtins/struct.d.ts.map +1 -0
  26. package/dist/builtins/struct.js +67 -0
  27. package/dist/builtins/tagged-union.d.ts +54 -0
  28. package/dist/builtins/tagged-union.d.ts.map +1 -0
  29. package/dist/builtins/tagged-union.js +81 -0
  30. package/dist/builtins/with-resource.d.ts +23 -0
  31. package/dist/builtins/with-resource.d.ts.map +1 -0
  32. package/dist/builtins/with-resource.js +35 -0
  33. package/dist/chain.d.ts +1 -0
  34. package/dist/chain.d.ts.map +1 -0
  35. package/dist/chain.js +3 -3
  36. package/dist/effect-id.d.ts +1 -0
  37. package/dist/effect-id.d.ts.map +1 -0
  38. package/dist/handler.d.ts +7 -6
  39. package/dist/handler.d.ts.map +1 -0
  40. package/dist/handler.js +5 -21
  41. package/dist/index.d.ts +10 -6
  42. package/dist/index.d.ts.map +1 -0
  43. package/dist/index.js +4 -2
  44. package/dist/iterator.d.ts +32 -0
  45. package/dist/iterator.d.ts.map +1 -0
  46. package/dist/iterator.js +123 -0
  47. package/dist/option.d.ts +74 -0
  48. package/dist/option.d.ts.map +1 -0
  49. package/dist/option.js +141 -0
  50. package/dist/pipe.d.ts +11 -10
  51. package/dist/pipe.d.ts.map +1 -0
  52. package/dist/pipe.js +5 -4
  53. package/dist/race.d.ts +5 -4
  54. package/dist/race.d.ts.map +1 -0
  55. package/dist/race.js +17 -42
  56. package/dist/recursive.d.ts +9 -3
  57. package/dist/recursive.d.ts.map +1 -0
  58. package/dist/recursive.js +18 -13
  59. package/dist/result.d.ts +50 -0
  60. package/dist/result.d.ts.map +1 -0
  61. package/dist/result.js +117 -0
  62. package/dist/run.d.ts +9 -2
  63. package/dist/run.d.ts.map +1 -0
  64. package/dist/run.js +37 -20
  65. package/dist/runtime.d.ts +6 -0
  66. package/dist/runtime.d.ts.map +1 -0
  67. package/dist/runtime.js +7 -0
  68. package/dist/schema.d.ts +1 -0
  69. package/dist/schema.d.ts.map +1 -0
  70. package/dist/schemas.d.ts +5 -0
  71. package/dist/schemas.d.ts.map +1 -0
  72. package/dist/schemas.js +13 -0
  73. package/dist/try-catch.d.ts +2 -1
  74. package/dist/try-catch.d.ts.map +1 -0
  75. package/dist/try-catch.js +10 -9
  76. package/dist/values.d.ts +6 -0
  77. package/dist/values.d.ts.map +1 -0
  78. package/dist/values.js +12 -0
  79. package/dist/worker.d.ts +5 -1
  80. package/dist/worker.d.ts.map +1 -0
  81. package/dist/worker.js +15 -3
  82. package/package.json +8 -6
  83. package/src/all.ts +118 -74
  84. package/src/ast.ts +773 -350
  85. package/src/bind.ts +32 -62
  86. package/src/builtins/array.ts +121 -0
  87. package/src/builtins/index.ts +17 -0
  88. package/src/builtins/scalar.ts +49 -0
  89. package/src/builtins/struct.ts +111 -0
  90. package/src/builtins/tagged-union.ts +142 -0
  91. package/src/builtins/with-resource.ts +69 -0
  92. package/src/chain.ts +4 -4
  93. package/src/handler.ts +12 -28
  94. package/src/index.ts +24 -17
  95. package/src/iterator.ts +243 -0
  96. package/src/option.ts +199 -0
  97. package/src/pipe.ts +123 -78
  98. package/src/race.ts +41 -51
  99. package/src/recursive.ts +44 -27
  100. package/src/result.ts +168 -0
  101. package/src/run.ts +53 -25
  102. package/src/runtime.ts +16 -0
  103. package/src/schemas.ts +21 -0
  104. package/src/try-catch.ts +14 -10
  105. package/src/values.ts +21 -0
  106. package/src/worker.ts +17 -2
  107. package/dist/builtins.d.ts +0 -257
  108. package/dist/builtins.js +0 -600
  109. package/src/builtins.ts +0 -804
package/dist/builtins.js DELETED
@@ -1,600 +0,0 @@
1
- import { typedAction, } from "./ast.js";
2
- import { chain } from "./chain.js";
3
- /**
4
- * Typed combinators for structural data transformations.
5
- *
6
- * All builtins emit `{ kind: "Builtin", builtin: { kind: ... } }` handler
7
- * kinds. The Rust scheduler executes them inline (no subprocess).
8
- */
9
- // ---------------------------------------------------------------------------
10
- // Constant — produce a fixed value (takes no pipeline input)
11
- // ---------------------------------------------------------------------------
12
- export function constant(value) {
13
- return typedAction({
14
- kind: "Invoke",
15
- handler: { kind: "Builtin", builtin: { kind: "Constant", value } },
16
- });
17
- }
18
- // ---------------------------------------------------------------------------
19
- // Identity — pass input through unchanged
20
- // ---------------------------------------------------------------------------
21
- export const identity = typedAction({
22
- kind: "Invoke",
23
- handler: { kind: "Builtin", builtin: { kind: "Identity" } },
24
- });
25
- // ---------------------------------------------------------------------------
26
- // Drop — discard pipeline value
27
- // ---------------------------------------------------------------------------
28
- export const drop = typedAction({
29
- kind: "Invoke",
30
- handler: { kind: "Builtin", builtin: { kind: "Drop" } },
31
- });
32
- // ---------------------------------------------------------------------------
33
- // Tag — wrap input as a tagged union variant
34
- // ---------------------------------------------------------------------------
35
- /**
36
- * Wrap input as a tagged union member. Requires the full variant map TDef
37
- * so the output type carries __def for branch decomposition.
38
- *
39
- * Usage: tag<{ Ok: string; Err: number }, "Ok">("Ok")
40
- * input: string → output: TaggedUnion<{ Ok: string; Err: number }>
41
- */
42
- export function tag(kind) {
43
- return typedAction({
44
- kind: "Invoke",
45
- handler: { kind: "Builtin", builtin: { kind: "Tag", value: kind } },
46
- });
47
- }
48
- export function merge() {
49
- return typedAction({
50
- kind: "Invoke",
51
- handler: { kind: "Builtin", builtin: { kind: "Merge" } },
52
- });
53
- }
54
- // ---------------------------------------------------------------------------
55
- // Flatten — flatten a nested array one level
56
- // ---------------------------------------------------------------------------
57
- export function flatten() {
58
- return typedAction({
59
- kind: "Invoke",
60
- handler: { kind: "Builtin", builtin: { kind: "Flatten" } },
61
- });
62
- }
63
- // ---------------------------------------------------------------------------
64
- // ExtractField — extract a single field from an object
65
- // ---------------------------------------------------------------------------
66
- export function extractField(field) {
67
- return typedAction({
68
- kind: "Invoke",
69
- handler: {
70
- kind: "Builtin",
71
- builtin: { kind: "ExtractField", value: field },
72
- },
73
- });
74
- }
75
- // ---------------------------------------------------------------------------
76
- // ExtractIndex — extract a single element from an array by index
77
- // ---------------------------------------------------------------------------
78
- export function extractIndex(index) {
79
- return typedAction({
80
- kind: "Invoke",
81
- handler: {
82
- kind: "Builtin",
83
- builtin: { kind: "ExtractIndex", value: index },
84
- },
85
- });
86
- }
87
- // ---------------------------------------------------------------------------
88
- // Pick — select named fields from an object
89
- // ---------------------------------------------------------------------------
90
- export function pick(...keys) {
91
- return typedAction({
92
- kind: "Invoke",
93
- handler: { kind: "Builtin", builtin: { kind: "Pick", value: keys } },
94
- });
95
- }
96
- // ---------------------------------------------------------------------------
97
- // DropResult — run an action for side effects, discard its output
98
- // ---------------------------------------------------------------------------
99
- export function dropResult(action) {
100
- // Build AST directly — chain inference fails when drop's TValue
101
- // isn't constrained by context (resolves to unknown ≠ TOutput).
102
- return typedAction({
103
- kind: "Chain",
104
- first: action,
105
- rest: {
106
- kind: "Invoke",
107
- handler: { kind: "Builtin", builtin: { kind: "Drop" } },
108
- },
109
- });
110
- }
111
- // ---------------------------------------------------------------------------
112
- // WithResource — RAII-style create/action/dispose
113
- // ---------------------------------------------------------------------------
114
- /**
115
- * RAII-style resource management combinator.
116
- *
117
- * Runs `create` to acquire a resource, then merges the resource with the
118
- * original input into a flat object (`TResource & TIn`) for the action.
119
- * After the action completes, `dispose` receives the resource for cleanup.
120
- * The overall combinator returns the action's output.
121
- *
122
- * ```
123
- * TIn → create → TResource
124
- * → merge(TResource, TIn) → TResource & TIn
125
- * → action(TResource & TIn) → TOut
126
- * → dispose(TResource) → (discarded)
127
- * → TOut
128
- * ```
129
- */
130
- export function withResource({ create, action, dispose, }) {
131
- const mergeBuiltin = {
132
- kind: "Invoke",
133
- handler: { kind: "Builtin", builtin: { kind: "Merge" } },
134
- };
135
- // Step 1: all(create, identity) → [TResource, TIn] → merge → TResource & TIn
136
- const acquireAndMerge = chain(typedAction({
137
- kind: "All",
138
- actions: [create, identity],
139
- }), typedAction(mergeBuiltin));
140
- // Step 2: all(action, identity) → [TOut, TResource & TIn]
141
- // Keep merged object so dispose can access resource fields.
142
- const actionAndKeepMerged = typedAction({
143
- kind: "All",
144
- actions: [action, identity],
145
- });
146
- // Step 3: all(extractIndex(0), chain(extractIndex(1), dispose)) → [TOut, unknown]
147
- const disposeAndKeepResult = typedAction({
148
- kind: "All",
149
- actions: [
150
- extractIndex(0),
151
- chain(extractIndex(1), dispose),
152
- ],
153
- });
154
- // Step 4: extractIndex(0) → TOut
155
- return chain(chain(chain(acquireAndMerge, actionAndKeepMerged), disposeAndKeepResult), extractIndex(0));
156
- }
157
- // ---------------------------------------------------------------------------
158
- // Augment — run a transform, merge its output back into the original input
159
- // ---------------------------------------------------------------------------
160
- /**
161
- * Run `action` on the input, then merge the action's output fields back
162
- * into the original input object. The action must accept exactly `TInput`.
163
- * Use `pick` inside the action's pipe if the inner handler needs a subset.
164
- *
165
- * Example:
166
- * augment(pipe(pick("file"), migrate))
167
- * // { file, outputPath } → { file, outputPath, content, migrated }
168
- */
169
- export function augment(action) {
170
- // Build AST directly — chain inference fails because [TOutput, TInput]
171
- // doesn't match merge()'s Record<string, unknown>[] with invariance.
172
- return typedAction({
173
- kind: "Chain",
174
- first: {
175
- kind: "All",
176
- actions: [action, identity],
177
- },
178
- rest: {
179
- kind: "Invoke",
180
- handler: { kind: "Builtin", builtin: { kind: "Merge" } },
181
- },
182
- });
183
- }
184
- // ---------------------------------------------------------------------------
185
- // Tap — run an action for side effects, preserve original input
186
- // ---------------------------------------------------------------------------
187
- /**
188
- * Run `action` on the input for its side effects, then discard the action's
189
- * output and return the original input unchanged. The action must accept
190
- * exactly `TInput`. Use `pick` inside the action's pipe if the inner
191
- * handler needs a subset.
192
- *
193
- * Constraint: input must be an object (uses augment internally, which
194
- * relies on all + merge).
195
- *
196
- * Example:
197
- * pipe(tap(pipe(pick("worktreePath", "description"), implement)), createPR)
198
- */
199
- export function tap(action) {
200
- // Build AST directly — internal plumbing (action → constant → augment)
201
- // can't go through typed chain/augment with invariant phantom fields.
202
- // tap: all(chain(action, constant({})), identity()) → merge
203
- return typedAction({
204
- kind: "Chain",
205
- first: {
206
- kind: "All",
207
- actions: [
208
- {
209
- kind: "Chain",
210
- first: action,
211
- rest: {
212
- kind: "Invoke",
213
- handler: {
214
- kind: "Builtin",
215
- builtin: { kind: "Constant", value: {} },
216
- },
217
- },
218
- },
219
- {
220
- kind: "Invoke",
221
- handler: { kind: "Builtin", builtin: { kind: "Identity" } },
222
- },
223
- ],
224
- },
225
- rest: {
226
- kind: "Invoke",
227
- handler: { kind: "Builtin", builtin: { kind: "Merge" } },
228
- },
229
- });
230
- }
231
- // ---------------------------------------------------------------------------
232
- // Range — produce an integer array [start, start+1, ..., end-1]
233
- // ---------------------------------------------------------------------------
234
- export function range(start, end) {
235
- const result = [];
236
- for (let i = start; i < end; i++) {
237
- result.push(i);
238
- }
239
- return typedAction({
240
- kind: "Invoke",
241
- handler: { kind: "Builtin", builtin: { kind: "Constant", value: result } },
242
- });
243
- }
244
- // ---------------------------------------------------------------------------
245
- // Option namespace — combinators for Option<T> tagged unions
246
- // ---------------------------------------------------------------------------
247
- // Shared AST fragments for Option desugaring
248
- const TAG_SOME = {
249
- kind: "Invoke",
250
- handler: { kind: "Builtin", builtin: { kind: "Tag", value: "Some" } },
251
- };
252
- const TAG_NONE = {
253
- kind: "Invoke",
254
- handler: { kind: "Builtin", builtin: { kind: "Tag", value: "None" } },
255
- };
256
- const EXTRACT_VALUE = {
257
- kind: "Invoke",
258
- handler: {
259
- kind: "Builtin",
260
- builtin: { kind: "ExtractField", value: "value" },
261
- },
262
- };
263
- const DROP = {
264
- kind: "Invoke",
265
- handler: { kind: "Builtin", builtin: { kind: "Drop" } },
266
- };
267
- const IDENTITY = {
268
- kind: "Invoke",
269
- handler: { kind: "Builtin", builtin: { kind: "Identity" } },
270
- };
271
- /** Wrap branch cases with ExtractField("value") auto-unwrapping. */
272
- function optionBranch(someCaseBody, noneCaseBody) {
273
- return {
274
- kind: "Branch",
275
- cases: {
276
- Some: { kind: "Chain", first: EXTRACT_VALUE, rest: someCaseBody },
277
- None: { kind: "Chain", first: EXTRACT_VALUE, rest: noneCaseBody },
278
- },
279
- };
280
- }
281
- /**
282
- * Option namespace. All combinators produce TypedAction AST nodes that
283
- * desugar to branch + existing builtins, except collect which uses the
284
- * CollectSome builtin.
285
- */
286
- export const Option = {
287
- /**
288
- * Wrap a value as Some. `T → Option<T>`
289
- *
290
- * Equivalent to `tag<OptionDef<T>, "Some">("Some")`.
291
- */
292
- some() {
293
- return typedAction(TAG_SOME);
294
- },
295
- /**
296
- * Produce a None. `never → Option<T>`
297
- *
298
- * Chain after `.drop()` to discard the current value first.
299
- * Equivalent to `tag<OptionDef<T>, "None">("None")`.
300
- */
301
- none() {
302
- return typedAction(TAG_NONE);
303
- },
304
- /**
305
- * Transform the Some value. `Option<T> → Option<U>`
306
- *
307
- * Desugars to: `branch({ Some: pipe(action, tag("Some")), None: tag("None") })`
308
- */
309
- map(action) {
310
- return typedAction(optionBranch({ kind: "Chain", first: action, rest: TAG_SOME }, TAG_NONE));
311
- },
312
- /**
313
- * Monadic bind (flatMap). If Some, pass the value to action which
314
- * returns Option<U>. If None, stay None. `Option<T> → Option<U>`
315
- *
316
- * This is the most fundamental combinator — map, flatten, and filter
317
- * are all derivable from andThen + constructors.
318
- *
319
- * Desugars to: `branch({ Some: action, None: tag("None") })`
320
- */
321
- andThen(action) {
322
- return typedAction(optionBranch(action, TAG_NONE));
323
- },
324
- /**
325
- * Extract the Some value or produce a default from an action.
326
- * `Option<T> → T`
327
- *
328
- * The defaultAction takes no meaningful input (never) and must produce T.
329
- * Use `Option.unwrapOr(constant("fallback"))`.
330
- *
331
- * The None branch drops its void payload before calling defaultAction,
332
- * matching Rust's `unwrap_or_else(|| default)` where the closure takes
333
- * no arguments.
334
- *
335
- * Desugars to: `branch({ Some: identity(), None: pipe(drop(), defaultAction) })`
336
- */
337
- unwrapOr(defaultAction) {
338
- return typedAction({
339
- kind: "Branch",
340
- cases: {
341
- Some: { kind: "Chain", first: EXTRACT_VALUE, rest: IDENTITY },
342
- None: {
343
- kind: "Chain",
344
- first: EXTRACT_VALUE,
345
- rest: { kind: "Chain", first: DROP, rest: defaultAction },
346
- },
347
- },
348
- });
349
- },
350
- /**
351
- * Unwrap a nested Option. `Option<Option<T>> → Option<T>`
352
- *
353
- * Desugars to: `branch({ Some: identity(), None: tag("None") })`
354
- */
355
- flatten() {
356
- return typedAction(optionBranch(IDENTITY, TAG_NONE));
357
- },
358
- /**
359
- * Conditional keep. If Some, pass value to predicate which returns
360
- * Option<T> (some() to keep, none() to discard). If None, stay None.
361
- * `Option<T> → Option<T>`
362
- *
363
- * This has the same signature and desugaring as andThen with T=U.
364
- * Named "filter" for readability when the intent is filtering.
365
- *
366
- * Desugars to: `branch({ Some: predicate, None: tag("None") })`
367
- */
368
- filter(predicate) {
369
- return typedAction(optionBranch(predicate, TAG_NONE));
370
- },
371
- /**
372
- * Collect Some values from an array, discarding Nones.
373
- * `Option<T>[] → T[]`
374
- *
375
- * This is a builtin handler (CollectSome) — it can't be expressed
376
- * as a composition of existing AST nodes because it requires
377
- * array-level filtering logic.
378
- */
379
- collect() {
380
- return typedAction({
381
- kind: "Invoke",
382
- handler: { kind: "Builtin", builtin: { kind: "CollectSome" } },
383
- });
384
- },
385
- /**
386
- * Test if the value is Some. `Option<T> → boolean`
387
- *
388
- * Rarely useful — branch on Some/None directly instead.
389
- *
390
- * Desugars to: `branch({ Some: pipe(drop(), constant(true)), None: pipe(drop(), constant(false)) })`
391
- */
392
- isSome() {
393
- const constTrue = {
394
- kind: "Invoke",
395
- handler: { kind: "Builtin", builtin: { kind: "Constant", value: true } },
396
- };
397
- const constFalse = {
398
- kind: "Invoke",
399
- handler: { kind: "Builtin", builtin: { kind: "Constant", value: false } },
400
- };
401
- return typedAction(optionBranch({ kind: "Chain", first: DROP, rest: constTrue }, { kind: "Chain", first: DROP, rest: constFalse }));
402
- },
403
- /**
404
- * Test if the value is None. `Option<T> → boolean`
405
- *
406
- * Rarely useful — branch on Some/None directly instead.
407
- *
408
- * Desugars to: `branch({ Some: pipe(drop(), constant(false)), None: pipe(drop(), constant(true)) })`
409
- */
410
- isNone() {
411
- const constTrue = {
412
- kind: "Invoke",
413
- handler: { kind: "Builtin", builtin: { kind: "Constant", value: true } },
414
- };
415
- const constFalse = {
416
- kind: "Invoke",
417
- handler: { kind: "Builtin", builtin: { kind: "Constant", value: false } },
418
- };
419
- return typedAction(optionBranch({ kind: "Chain", first: DROP, rest: constFalse }, { kind: "Chain", first: DROP, rest: constTrue }));
420
- },
421
- };
422
- // ---------------------------------------------------------------------------
423
- // Result namespace — combinators for Result<TValue, TError> tagged unions
424
- // ---------------------------------------------------------------------------
425
- // Shared AST fragments for Result desugaring
426
- const TAG_OK = {
427
- kind: "Invoke",
428
- handler: { kind: "Builtin", builtin: { kind: "Tag", value: "Ok" } },
429
- };
430
- const TAG_ERR = {
431
- kind: "Invoke",
432
- handler: { kind: "Builtin", builtin: { kind: "Tag", value: "Err" } },
433
- };
434
- /** Wrap branch cases with ExtractField("value") auto-unwrapping. */
435
- function resultBranch(okCaseBody, errCaseBody) {
436
- return {
437
- kind: "Branch",
438
- cases: {
439
- Ok: { kind: "Chain", first: EXTRACT_VALUE, rest: okCaseBody },
440
- Err: { kind: "Chain", first: EXTRACT_VALUE, rest: errCaseBody },
441
- },
442
- };
443
- }
444
- /**
445
- * Result namespace. All combinators produce TypedAction AST nodes that
446
- * desugar to branch + existing builtins.
447
- */
448
- export const Result = {
449
- /**
450
- * Wrap a value as Ok. `TValue → Result<TValue, TError>`
451
- */
452
- ok() {
453
- return typedAction(TAG_OK);
454
- },
455
- /**
456
- * Wrap a value as Err. `TError → Result<TValue, TError>`
457
- */
458
- err() {
459
- return typedAction(TAG_ERR);
460
- },
461
- /**
462
- * Transform the Ok value. `Result<TValue, TError> → Result<TOut, TError>`
463
- *
464
- * Desugars to: `branch({ Ok: pipe(action, tag("Ok")), Err: tag("Err") })`
465
- */
466
- map(action) {
467
- return typedAction(resultBranch({ kind: "Chain", first: action, rest: TAG_OK }, TAG_ERR));
468
- },
469
- /**
470
- * Transform the Err value. `Result<TValue, TError> → Result<TValue, TErrorOut>`
471
- *
472
- * Desugars to: `branch({ Ok: tag("Ok"), Err: pipe(action, tag("Err")) })`
473
- */
474
- mapErr(action) {
475
- return typedAction(resultBranch(TAG_OK, {
476
- kind: "Chain",
477
- first: action,
478
- rest: TAG_ERR,
479
- }));
480
- },
481
- /**
482
- * Monadic bind (flatMap) for Ok. If Ok, pass value to action which
483
- * returns Result<TOut, TError>. If Err, propagate.
484
- *
485
- * Desugars to: `branch({ Ok: action, Err: tag("Err") })`
486
- */
487
- andThen(action) {
488
- return typedAction(resultBranch(action, TAG_ERR));
489
- },
490
- /**
491
- * Fallback on Err. If Ok, keep it. If Err, pass error to fallback
492
- * which returns a new Result.
493
- *
494
- * Desugars to: `branch({ Ok: tag("Ok"), Err: fallback })`
495
- */
496
- or(fallback) {
497
- return typedAction(resultBranch(TAG_OK, fallback));
498
- },
499
- /**
500
- * Replace Ok value with another Result. If Ok, discard value and
501
- * return other. If Err, propagate.
502
- *
503
- * Desugars to: `branch({ Ok: pipe(drop(), other), Err: tag("Err") })`
504
- */
505
- and(other) {
506
- return typedAction(resultBranch({ kind: "Chain", first: DROP, rest: other }, TAG_ERR));
507
- },
508
- /**
509
- * Extract Ok or compute default from Err. `Result<TValue, TError> → TValue`
510
- *
511
- * Takes an action that receives the Err payload and produces a fallback.
512
- * Uses covariant output checking so throw tokens (Out=never) are assignable
513
- * when TValue is provided explicitly: `Result.unwrapOr<string, string>(throwError)`.
514
- *
515
- * For inference-free usage with throw tokens, prefer the postfix method:
516
- * `handler.unwrapOr(throwError)` — the `this` constraint provides TValue.
517
- *
518
- * Desugars to: `branch({ Ok: identity(), Err: defaultAction })`
519
- */
520
- unwrapOr(defaultAction) {
521
- return typedAction(resultBranch(IDENTITY, defaultAction));
522
- },
523
- /**
524
- * Unwrap nested Result. `Result<Result<TValue, TError>, TError> → Result<TValue, TError>`
525
- *
526
- * Desugars to: `branch({ Ok: identity(), Err: tag("Err") })`
527
- */
528
- flatten() {
529
- return typedAction(resultBranch(IDENTITY, TAG_ERR));
530
- },
531
- /**
532
- * Convert Ok to Some, Err to None. `Result<TValue, TError> → Option<TValue>`
533
- *
534
- * Desugars to: `branch({ Ok: tag("Some"), Err: pipe(drop(), tag("None")) })`
535
- */
536
- toOption() {
537
- return typedAction(resultBranch(TAG_SOME, { kind: "Chain", first: DROP, rest: TAG_NONE }));
538
- },
539
- /**
540
- * Convert Err to Some, Ok to None. `Result<TValue, TError> → Option<TError>`
541
- *
542
- * Desugars to: `branch({ Ok: pipe(drop(), tag("None")), Err: tag("Some") })`
543
- */
544
- toOptionErr() {
545
- return typedAction(resultBranch({ kind: "Chain", first: DROP, rest: TAG_NONE }, TAG_SOME));
546
- },
547
- /**
548
- * Swap Result/Option nesting.
549
- * `Result<Option<TValue>, TError> → Option<Result<TValue, TError>>`
550
- */
551
- transpose() {
552
- return typedAction(resultBranch(
553
- // Ok case: receives Option<TValue>, branch on Some/None
554
- {
555
- kind: "Branch",
556
- cases: {
557
- Some: {
558
- kind: "Chain",
559
- first: EXTRACT_VALUE,
560
- rest: { kind: "Chain", first: TAG_OK, rest: TAG_SOME },
561
- },
562
- None: {
563
- kind: "Chain",
564
- first: EXTRACT_VALUE,
565
- rest: { kind: "Chain", first: DROP, rest: TAG_NONE },
566
- },
567
- },
568
- },
569
- // Err case: receives TError, wrap as Result.err then Option.some
570
- { kind: "Chain", first: TAG_ERR, rest: TAG_SOME }));
571
- },
572
- /**
573
- * Test if the value is Ok. `Result<TValue, TError> → boolean`
574
- */
575
- isOk() {
576
- const constTrue = {
577
- kind: "Invoke",
578
- handler: { kind: "Builtin", builtin: { kind: "Constant", value: true } },
579
- };
580
- const constFalse = {
581
- kind: "Invoke",
582
- handler: { kind: "Builtin", builtin: { kind: "Constant", value: false } },
583
- };
584
- return typedAction(resultBranch({ kind: "Chain", first: DROP, rest: constTrue }, { kind: "Chain", first: DROP, rest: constFalse }));
585
- },
586
- /**
587
- * Test if the value is Err. `Result<TValue, TError> → boolean`
588
- */
589
- isErr() {
590
- const constTrue = {
591
- kind: "Invoke",
592
- handler: { kind: "Builtin", builtin: { kind: "Constant", value: true } },
593
- };
594
- const constFalse = {
595
- kind: "Invoke",
596
- handler: { kind: "Builtin", builtin: { kind: "Constant", value: false } },
597
- };
598
- return typedAction(resultBranch({ kind: "Chain", first: DROP, rest: constFalse }, { kind: "Chain", first: DROP, rest: constTrue }));
599
- },
600
- };