@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/ast.js CHANGED
@@ -1,182 +1,227 @@
1
+ import { chain } from "./chain.js";
2
+ import { constant, drop, extractPrefix, flatten as flattenBuiltin, getField, getIndex, identity, panic, pick, splitFirst, splitLast, tag, wrapInField, asOption as asOptionStandalone, } from "./builtins/index.js";
3
+ import { Option } from "./option.js";
4
+ import { Result } from "./result.js";
5
+ // Lazy import — iterator.ts imports from ast.ts, but these are only called inside
6
+ // methods (after all modules load), so the circular reference is safe at runtime.
7
+ import { Iterator as IteratorNs } from "./iterator.js";
8
+ // Lazy import — bind.ts imports from ast.ts, but these are only called inside
9
+ // methods (after all modules load), so the circular reference is safe at runtime.
10
+ import { bind as bindStandalone, bindInput as bindInputStandalone, } from "./bind.js";
11
+ /**
12
+ * Strip phantom types from a Pipeable, returning a plain Action.
13
+ *
14
+ * Replaces `x as Action` casts throughout the codebase. The constraint
15
+ * ensures the argument is structurally a Pipeable — unlike a bare cast,
16
+ * `toAction(123)` is a type error.
17
+ */
18
+ export function toAction(pipeable) {
19
+ return pipeable;
20
+ }
1
21
  // ---------------------------------------------------------------------------
2
22
  // typedAction — attach .then() and .forEach() as non-enumerable methods
3
23
  // ---------------------------------------------------------------------------
4
24
  // Shared implementations (one closure, not per-instance)
5
25
  function thenMethod(next) {
6
- return typedAction({ kind: "Chain", first: this, rest: next });
7
- }
8
- function forEachMethod(action) {
9
- return typedAction({
10
- kind: "Chain",
11
- first: this,
12
- rest: { kind: "ForEach", action },
13
- });
26
+ return chain(this, next);
14
27
  }
15
28
  function branchMethod(cases) {
16
- return typedAction({
17
- kind: "Chain",
18
- first: this,
19
- rest: { kind: "Branch", cases: unwrapBranchCases(cases) },
20
- });
29
+ return chain(toAction(this), toAction(branch(cases)));
21
30
  }
22
31
  function flattenMethod() {
23
- return typedAction({
24
- kind: "Chain",
25
- first: this,
26
- rest: {
27
- kind: "Invoke",
28
- handler: { kind: "Builtin", builtin: { kind: "Flatten" } },
29
- },
30
- });
32
+ return chain(toAction(this), toAction(flattenBuiltin()));
31
33
  }
32
34
  function dropMethod() {
33
- return typedAction({
34
- kind: "Chain",
35
- first: this,
36
- rest: {
37
- kind: "Invoke",
38
- handler: { kind: "Builtin", builtin: { kind: "Drop" } },
39
- },
40
- });
35
+ return chain(toAction(this), toAction(drop));
41
36
  }
42
- function tagMethod(kind) {
43
- return typedAction({
44
- kind: "Chain",
45
- first: this,
46
- rest: {
47
- kind: "Invoke",
48
- handler: { kind: "Builtin", builtin: { kind: "Tag", value: kind } },
49
- },
50
- });
37
+ function tagMethod(kind, enumName) {
38
+ return chain(toAction(this), toAction(tag(kind, enumName)));
51
39
  }
52
- function getMethod(field) {
53
- return typedAction({
54
- kind: "Chain",
55
- first: this,
56
- rest: {
57
- kind: "Invoke",
58
- handler: {
59
- kind: "Builtin",
60
- builtin: { kind: "ExtractField", value: field },
61
- },
62
- },
63
- });
40
+ function someMethod() {
41
+ return chain(toAction(this), toAction(Option.some()));
64
42
  }
65
- function augmentMethod() {
66
- // Construct: All(this, identity) → Merge
67
- // "this" is the sub-pipeline. augment() wraps it so the original input
68
- // flows through identity alongside the sub-pipeline, then merges the results.
69
- return typedAction({
70
- kind: "Chain",
71
- first: {
72
- kind: "All",
73
- actions: [
74
- this,
75
- {
76
- kind: "Invoke",
77
- handler: { kind: "Builtin", builtin: { kind: "Identity" } },
78
- },
79
- ],
80
- },
81
- rest: {
82
- kind: "Invoke",
83
- handler: { kind: "Builtin", builtin: { kind: "Merge" } },
84
- },
85
- });
43
+ function okMethod() {
44
+ return chain(toAction(this), toAction(Result.ok()));
86
45
  }
87
- function mergeMethod() {
88
- return typedAction({
89
- kind: "Chain",
90
- first: this,
91
- rest: {
92
- kind: "Invoke",
93
- handler: { kind: "Builtin", builtin: { kind: "Merge" } },
94
- },
95
- });
46
+ function errMethod() {
47
+ return chain(toAction(this), toAction(Result.err()));
48
+ }
49
+ function getFieldMethod(field) {
50
+ return chain(toAction(this), toAction(getField(field)));
51
+ }
52
+ function getIndexMethod(index) {
53
+ return chain(toAction(this), toAction(getIndex(index)));
54
+ }
55
+ function wrapInFieldMethod(field) {
56
+ return chain(toAction(this), toAction(wrapInField(field)));
96
57
  }
97
58
  function pickMethod(...keys) {
98
- return typedAction({
99
- kind: "Chain",
100
- first: this,
101
- rest: {
102
- kind: "Invoke",
103
- handler: { kind: "Builtin", builtin: { kind: "Pick", value: keys } },
104
- },
105
- });
59
+ return chain(toAction(this), toAction(pick(...keys)));
106
60
  }
107
- function mapOptionMethod(action) {
108
- // Desugars to: self.then(branch({ Some: pipe(action, tag("Some")), None: tag("None") }))
109
- // But branch auto-unwraps value, so:
110
- // Some case: receives T, runs action, wraps as Some
111
- // None case: receives void, wraps as None
112
- return typedAction({
113
- kind: "Chain",
114
- first: this,
115
- rest: {
116
- kind: "Branch",
117
- cases: unwrapBranchCases({
118
- Some: {
119
- kind: "Chain",
120
- first: action,
121
- rest: {
122
- kind: "Invoke",
123
- handler: {
124
- kind: "Builtin",
125
- builtin: { kind: "Tag", value: "Some" },
126
- },
127
- },
128
- },
129
- None: {
130
- kind: "Invoke",
131
- handler: { kind: "Builtin", builtin: { kind: "Tag", value: "None" } },
132
- },
133
- }),
134
- },
135
- });
61
+ function splitFirstMethod() {
62
+ return chain(toAction(this), toAction(branchFamily({
63
+ Iterator: IteratorNs.splitFirst(),
64
+ Array: splitFirst(),
65
+ })));
136
66
  }
137
- function mapErrMethod(action) {
138
- // Desugars to: self.then(branch({ Ok: tag("Ok"), Err: pipe(action, tag("Err")) }))
139
- return typedAction({
140
- kind: "Chain",
141
- first: this,
142
- rest: {
143
- kind: "Branch",
144
- cases: unwrapBranchCases({
145
- Ok: {
146
- kind: "Invoke",
147
- handler: { kind: "Builtin", builtin: { kind: "Tag", value: "Ok" } },
148
- },
149
- Err: {
150
- kind: "Chain",
151
- first: action,
152
- rest: {
153
- kind: "Invoke",
154
- handler: {
155
- kind: "Builtin",
156
- builtin: { kind: "Tag", value: "Err" },
157
- },
158
- },
159
- },
160
- }),
161
- },
162
- });
67
+ function splitLastMethod() {
68
+ return chain(toAction(this), toAction(branchFamily({
69
+ Iterator: IteratorNs.splitLast(),
70
+ Array: splitLast(),
71
+ })));
72
+ }
73
+ // --- Shared postfix methods (Option + Result) — dispatch via branchFamily ---
74
+ function mapMethod(action) {
75
+ return chain(toAction(this), toAction(branchFamily({
76
+ Result: branch({
77
+ Ok: chain(toAction(action), toAction(Result.ok())),
78
+ Err: Result.err(),
79
+ }),
80
+ Option: branch({
81
+ Some: chain(toAction(action), toAction(Option.some())),
82
+ None: Option.none(),
83
+ }),
84
+ Iterator: IteratorNs.map(action),
85
+ })));
86
+ }
87
+ function unwrapMethod() {
88
+ return chain(toAction(this), toAction(branchFamily({
89
+ Result: branch({ Ok: identity(), Err: panic("called unwrap on Err") }),
90
+ Option: branch({
91
+ Some: identity(),
92
+ None: panic("called unwrap on None"),
93
+ }),
94
+ })));
163
95
  }
164
96
  function unwrapOrMethod(defaultAction) {
165
- // Desugars to: self.then(branch({ Ok: identity(), Err: defaultAction }))
166
- return typedAction({
167
- kind: "Chain",
168
- first: this,
169
- rest: {
170
- kind: "Branch",
171
- cases: unwrapBranchCases({
172
- Ok: {
173
- kind: "Invoke",
174
- handler: { kind: "Builtin", builtin: { kind: "Identity" } },
175
- },
176
- Err: defaultAction,
97
+ return chain(toAction(this), toAction(branchFamily({
98
+ Result: branch({ Ok: identity(), Err: defaultAction }),
99
+ Option: branch({ Some: identity(), None: defaultAction }),
100
+ })));
101
+ }
102
+ function andThenMethod(action) {
103
+ return chain(toAction(this), toAction(branchFamily({
104
+ Result: branch({ Ok: action, Err: Result.err() }),
105
+ Option: branch({ Some: action, None: Option.none() }),
106
+ })));
107
+ }
108
+ function transposeMethod() {
109
+ return chain(toAction(this), toAction(branchFamily({
110
+ Option: branch({
111
+ Some: branch({
112
+ Ok: chain(toAction(Option.some()), toAction(Result.ok())),
113
+ Err: Result.err(),
177
114
  }),
178
- },
179
- });
115
+ None: chain(toAction(chain(toAction(drop), toAction(Option.none()))), toAction(Result.ok())),
116
+ }),
117
+ Result: branch({
118
+ Ok: branch({
119
+ Some: chain(toAction(Result.ok()), toAction(Option.some())),
120
+ None: chain(toAction(drop), toAction(Option.none())),
121
+ }),
122
+ Err: chain(toAction(Result.err()), toAction(Option.some())),
123
+ }),
124
+ })));
125
+ }
126
+ // --- Result-only postfix methods ---
127
+ function mapErrMethod(action) {
128
+ return chain(toAction(this), toAction(branch({
129
+ Ok: Result.ok(),
130
+ Err: chain(toAction(action), toAction(Result.err())),
131
+ })));
132
+ }
133
+ function orMethod(fallback) {
134
+ return chain(toAction(this), toAction(branch({
135
+ Ok: Result.ok(),
136
+ Err: fallback,
137
+ })));
138
+ }
139
+ function asOkOptionMethod() {
140
+ return chain(toAction(this), toAction(branch({
141
+ Ok: Option.some(),
142
+ Err: chain(toAction(drop), toAction(Option.none())),
143
+ })));
144
+ }
145
+ function asErrOptionMethod() {
146
+ return chain(toAction(this), toAction(branch({
147
+ Ok: chain(toAction(drop), toAction(Option.none())),
148
+ Err: Option.some(),
149
+ })));
150
+ }
151
+ function isOkMethod() {
152
+ return chain(toAction(this), toAction(branch({
153
+ Ok: constant(true),
154
+ Err: constant(false),
155
+ })));
156
+ }
157
+ function isErrMethod() {
158
+ return chain(toAction(this), toAction(branch({
159
+ Ok: constant(false),
160
+ Err: constant(true),
161
+ })));
162
+ }
163
+ // --- Option-only postfix methods ---
164
+ function filterMethod(predicate) {
165
+ return chain(toAction(this), toAction(branchFamily({
166
+ Option: branch({
167
+ Some: predicate,
168
+ None: Option.none(),
169
+ }),
170
+ Iterator: IteratorNs.filter(predicate),
171
+ })));
172
+ }
173
+ function isSomeMethod() {
174
+ return chain(toAction(this), toAction(branch({
175
+ Some: constant(true),
176
+ None: constant(false),
177
+ })));
178
+ }
179
+ function isNoneMethod() {
180
+ return chain(toAction(this), toAction(branch({
181
+ Some: constant(false),
182
+ None: constant(true),
183
+ })));
184
+ }
185
+ function asOptionMethod() {
186
+ return chain(toAction(this), toAction(asOptionStandalone()));
187
+ }
188
+ // --- Iterator postfix methods ---
189
+ function iterateMethod() {
190
+ return chain(toAction(this), toAction(branchFamily({
191
+ Option: IteratorNs.fromOption(),
192
+ Result: IteratorNs.fromResult(),
193
+ Array: IteratorNs.fromArray(),
194
+ })));
195
+ }
196
+ function flatMapMethod(action) {
197
+ return chain(toAction(this), toAction(IteratorNs.flatMap(action)));
198
+ }
199
+ function collectMethod() {
200
+ return chain(toAction(this), toAction(branchFamily({
201
+ Array: Option.collect(),
202
+ Iterator: IteratorNs.collect(),
203
+ })));
204
+ }
205
+ function foldMethod(init, body) {
206
+ return chain(toAction(this), toAction(IteratorNs.fold(init, body)));
207
+ }
208
+ function isEmptyMethod() {
209
+ return chain(toAction(this), toAction(IteratorNs.isEmpty()));
210
+ }
211
+ function sliceMethod(start, end) {
212
+ return chain(toAction(this), toAction(IteratorNs.slice(start, end)));
213
+ }
214
+ function takeMethod(n) {
215
+ return chain(toAction(this), toAction(IteratorNs.take(n)));
216
+ }
217
+ function skipMethod(n) {
218
+ return chain(toAction(this), toAction(IteratorNs.skip(n)));
219
+ }
220
+ function bindMethod(bindings, body) {
221
+ return chain(toAction(this), toAction(bindStandalone(bindings, body)));
222
+ }
223
+ function bindInputMethod(body) {
224
+ return chain(toAction(this), toAction(bindInputStandalone(body)));
180
225
  }
181
226
  /**
182
227
  * Attach `.then()` and `.forEach()` methods to a plain Action object.
@@ -186,18 +231,44 @@ export function typedAction(action) {
186
231
  if (!("then" in action)) {
187
232
  Object.defineProperties(action, {
188
233
  then: { value: thenMethod, configurable: true },
189
- forEach: { value: forEachMethod, configurable: true },
190
234
  branch: { value: branchMethod, configurable: true },
191
235
  flatten: { value: flattenMethod, configurable: true },
192
236
  drop: { value: dropMethod, configurable: true },
193
237
  tag: { value: tagMethod, configurable: true },
194
- get: { value: getMethod, configurable: true },
195
- augment: { value: augmentMethod, configurable: true },
196
- merge: { value: mergeMethod, configurable: true },
238
+ some: { value: someMethod, configurable: true },
239
+ ok: { value: okMethod, configurable: true },
240
+ err: { value: errMethod, configurable: true },
241
+ getField: { value: getFieldMethod, configurable: true },
242
+ getIndex: { value: getIndexMethod, configurable: true },
243
+ wrapInField: { value: wrapInFieldMethod, configurable: true },
197
244
  pick: { value: pickMethod, configurable: true },
198
- mapOption: { value: mapOptionMethod, configurable: true },
245
+ splitFirst: { value: splitFirstMethod, configurable: true },
246
+ splitLast: { value: splitLastMethod, configurable: true },
247
+ map: { value: mapMethod, configurable: true },
199
248
  mapErr: { value: mapErrMethod, configurable: true },
249
+ unwrap: { value: unwrapMethod, configurable: true },
200
250
  unwrapOr: { value: unwrapOrMethod, configurable: true },
251
+ andThen: { value: andThenMethod, configurable: true },
252
+ filter: { value: filterMethod, configurable: true },
253
+ isSome: { value: isSomeMethod, configurable: true },
254
+ isNone: { value: isNoneMethod, configurable: true },
255
+ asOption: { value: asOptionMethod, configurable: true },
256
+ collect: { value: collectMethod, configurable: true },
257
+ fold: { value: foldMethod, configurable: true },
258
+ isEmpty: { value: isEmptyMethod, configurable: true },
259
+ slice: { value: sliceMethod, configurable: true },
260
+ take: { value: takeMethod, configurable: true },
261
+ skip: { value: skipMethod, configurable: true },
262
+ or: { value: orMethod, configurable: true },
263
+ iterate: { value: iterateMethod, configurable: true },
264
+ flatMap: { value: flatMapMethod, configurable: true },
265
+ asOkOption: { value: asOkOptionMethod, configurable: true },
266
+ asErrOption: { value: asErrOptionMethod, configurable: true },
267
+ isOk: { value: isOkMethod, configurable: true },
268
+ isErr: { value: isErrMethod, configurable: true },
269
+ transpose: { value: transposeMethod, configurable: true },
270
+ bind: { value: bindMethod, configurable: true },
271
+ bindInput: { value: bindInputMethod, configurable: true },
201
272
  });
202
273
  }
203
274
  return action;
@@ -215,10 +286,10 @@ import { allocateRestartHandlerId, } from "./effect-id.js";
215
286
  export { tryCatch } from "./try-catch.js";
216
287
  export { race, sleep, withTimeout } from "./race.js";
217
288
  export function forEach(action) {
218
- return typedAction({ kind: "ForEach", action: action });
289
+ return typedAction({ kind: "ForEach", action: toAction(action) });
219
290
  }
220
291
  /**
221
- * Insert ExtractField("value") before each case handler in a branch.
292
+ * Insert GetField("value") before each case handler in a branch.
222
293
  * This implements auto-unwrapping: the engine dispatches on `kind`, then
223
294
  * extracts `value` before passing to the handler. Case handlers receive
224
295
  * the payload directly, not the full `{ kind, value }` variant.
@@ -226,17 +297,7 @@ export function forEach(action) {
226
297
  function unwrapBranchCases(cases) {
227
298
  const unwrapped = {};
228
299
  for (const key of Object.keys(cases)) {
229
- unwrapped[key] = {
230
- kind: "Chain",
231
- first: {
232
- kind: "Invoke",
233
- handler: {
234
- kind: "Builtin",
235
- builtin: { kind: "ExtractField", value: "value" },
236
- },
237
- },
238
- rest: cases[key],
239
- };
300
+ unwrapped[key] = toAction(chain(toAction(getField("value")), toAction(cases[key])));
240
301
  }
241
302
  return unwrapped;
242
303
  }
@@ -244,25 +305,21 @@ function unwrapBranchCases(cases) {
244
305
  export function branch(cases) {
245
306
  return typedAction({ kind: "Branch", cases: unwrapBranchCases(cases) });
246
307
  }
247
- // ---------------------------------------------------------------------------
248
- // Shared AST constants for control flow compilation
249
- // ---------------------------------------------------------------------------
250
- const EXTRACT_PAYLOAD = {
251
- kind: "Invoke",
252
- handler: { kind: "Builtin", builtin: { kind: "ExtractIndex", value: 0 } },
253
- };
254
- const TAG_CONTINUE = {
255
- kind: "Invoke",
256
- handler: { kind: "Builtin", builtin: { kind: "Tag", value: "Continue" } },
257
- };
258
- export const TAG_BREAK = {
259
- kind: "Invoke",
260
- handler: { kind: "Builtin", builtin: { kind: "Tag", value: "Break" } },
261
- };
262
- export const IDENTITY = {
263
- kind: "Invoke",
264
- handler: { kind: "Builtin", builtin: { kind: "Identity" } },
265
- };
308
+ /**
309
+ * Two-level dispatch: extract the enum prefix from a tagged value's `kind`,
310
+ * then branch on that prefix. Used by postfix methods (`.map()`, `.unwrapOr()`,
311
+ * etc.) to dispatch across union families (Option, Result) without runtime
312
+ * metadata.
313
+ *
314
+ * `branchFamily({ Result: ..., Option: ... })` ≡ `chain(extractPrefix(), branch(cases))`
315
+ */
316
+ export function branchFamily(cases) {
317
+ return typedAction({
318
+ kind: "Chain",
319
+ first: toAction(extractPrefix()),
320
+ rest: toAction(branch(cases)),
321
+ });
322
+ }
266
323
  // ---------------------------------------------------------------------------
267
324
  // recur — restart body primitive
268
325
  // ---------------------------------------------------------------------------
@@ -273,7 +330,7 @@ export const IDENTITY = {
273
330
  * If the body completes normally → output is TOut.
274
331
  * If restart fires → body re-executes with the restarted value.
275
332
  *
276
- * Compiled form: `RestartHandle(id, ExtractIndex(0), body)`
333
+ * Compiled form: `RestartHandle(id, GetIndex(0), body)`
277
334
  */
278
335
  export function recur(bodyFn) {
279
336
  const restartHandlerId = allocateRestartHandlerId();
@@ -281,12 +338,12 @@ export function recur(bodyFn) {
281
338
  kind: "RestartPerform",
282
339
  restart_handler_id: restartHandlerId,
283
340
  });
284
- const body = bodyFn(restartAction);
341
+ const body = toAction(bodyFn(restartAction));
285
342
  return typedAction({
286
343
  kind: "RestartHandle",
287
344
  restart_handler_id: restartHandlerId,
288
345
  body,
289
- handler: EXTRACT_PAYLOAD,
346
+ handler: toAction(getIndex(0).unwrap()),
290
347
  });
291
348
  }
292
349
  // ---------------------------------------------------------------------------
@@ -306,20 +363,19 @@ export function recur(bodyFn) {
306
363
  */
307
364
  export function earlyReturn(bodyFn) {
308
365
  const restartHandlerId = allocateRestartHandlerId();
309
- const earlyReturnAction = typedAction({
310
- kind: "Chain",
311
- first: TAG_BREAK,
312
- rest: { kind: "RestartPerform", restart_handler_id: restartHandlerId },
313
- });
314
- const body = bodyFn(earlyReturnAction);
315
- return typedAction(buildRestartBranchAction(restartHandlerId, body, IDENTITY));
366
+ const earlyReturnAction = typedAction(toAction(chain(toAction(tag("Break", "LoopResult")), {
367
+ kind: "RestartPerform",
368
+ restart_handler_id: restartHandlerId,
369
+ })));
370
+ const body = toAction(bodyFn(earlyReturnAction));
371
+ return typedAction(buildRestartBranchAction(restartHandlerId, body, toAction(identity())));
316
372
  }
317
373
  // ---------------------------------------------------------------------------
318
374
  // loop — iterative restart with break
319
375
  // ---------------------------------------------------------------------------
320
376
  /**
321
377
  * Build the restart+branch compiled form:
322
- * `Chain(Tag("Continue"), RestartHandle(id, ExtractIndex(0), Branch({ Continue: continueArm, Break: breakArm })))`
378
+ * `Chain(Tag("Continue"), RestartHandle(id, GetIndex(0), Branch({ Continue: continueArm, Break: breakArm })))`
323
379
  *
324
380
  * Input is tagged Continue so the Branch enters the continueArm on first execution.
325
381
  * Continue tag → restart → re-enters continueArm. Break tag → restart → runs breakArm, exits `RestartHandle`.
@@ -327,22 +383,12 @@ export function earlyReturn(bodyFn) {
327
383
  * Used by earlyReturn, loop, tryCatch, and race.
328
384
  */
329
385
  export function buildRestartBranchAction(restartHandlerId, continueArm, breakArm) {
330
- return {
331
- kind: "Chain",
332
- first: TAG_CONTINUE,
333
- rest: {
334
- kind: "RestartHandle",
335
- restart_handler_id: restartHandlerId,
336
- body: {
337
- kind: "Branch",
338
- cases: unwrapBranchCases({
339
- Continue: continueArm,
340
- Break: breakArm,
341
- }),
342
- },
343
- handler: EXTRACT_PAYLOAD,
344
- },
345
- };
386
+ return toAction(chain(toAction(tag("Continue", "LoopResult")), {
387
+ kind: "RestartHandle",
388
+ restart_handler_id: restartHandlerId,
389
+ body: toAction(branch({ Continue: continueArm, Break: breakArm })),
390
+ handler: toAction(getIndex(0).unwrap()),
391
+ }));
346
392
  }
347
393
  /**
348
394
  * Iterative loop. The body callback receives `recur` and `done`:
@@ -359,18 +405,10 @@ export function loop(bodyFn) {
359
405
  kind: "RestartPerform",
360
406
  restart_handler_id: restartHandlerId,
361
407
  };
362
- const recurAction = typedAction({
363
- kind: "Chain",
364
- first: TAG_CONTINUE,
365
- rest: perform,
366
- });
367
- const doneAction = typedAction({
368
- kind: "Chain",
369
- first: TAG_BREAK,
370
- rest: perform,
371
- });
372
- const body = bodyFn(recurAction, doneAction);
373
- return typedAction(buildRestartBranchAction(restartHandlerId, body, IDENTITY));
408
+ const recurAction = typedAction(toAction(chain(toAction(tag("Continue", "LoopResult")), toAction(perform))));
409
+ const doneAction = typedAction(toAction(chain(toAction(tag("Break", "LoopResult")), toAction(perform))));
410
+ const body = toAction(bodyFn(recurAction, doneAction));
411
+ return typedAction(buildRestartBranchAction(restartHandlerId, body, toAction(identity())));
374
412
  }
375
413
  // ---------------------------------------------------------------------------
376
414
  // Config builders
package/dist/bind.d.ts CHANGED
@@ -3,20 +3,17 @@ import { type Action, type ExtractInput, type ExtractOutput, type TypedAction }
3
3
  * A typed reference to a bound value. Output is `TValue`.
4
4
  *
5
5
  * Use `.then()` (not `pipe()`) when chaining a VarRef into a generic
6
- * action like `pick` or `extractField` — pipe overloads can't infer
6
+ * action like `pick` or `getField` — pipe overloads can't infer
7
7
  * the generic's type parameter from the VarRef's output.
8
8
  */
9
- export type VarRef<TValue> = TypedAction<never, TValue>;
9
+ export type VarRef<TValue> = TypedAction<any, TValue>;
10
10
  /**
11
11
  * Maps each binding's output type to a VarRef. TypeScript resolves
12
12
  * ExtractOutput from each binding expression.
13
13
  *
14
- * Constraint is `Action[]` (not `Pipeable<any, any>[]`) because
15
- * `TypedAction<never, X>` (e.g. from `constant()`) fails the invariant
16
- * `__in` check against `Pipeable<any, any>` on the 9-variant
17
- * Action union. Using raw `Action[]` avoids the phantom field
18
- * assignability issue while `ExtractOutput` still extracts the correct
19
- * output type from the phantom fields on the concrete types.
14
+ * Constraint is `Action[]` (not `Pipeable<any, any>[]`) so that
15
+ * `ExtractOutput` extracts the correct output type from the phantom
16
+ * fields on the concrete types without fighting invariant `__in` checks.
20
17
  */
21
18
  export type InferVarRefs<TBindings extends Action[]> = {
22
19
  [K in keyof TBindings]: VarRef<ExtractOutput<TBindings[K]>>;
@@ -33,19 +30,18 @@ export type InferVarRefs<TBindings extends Action[]> = {
33
30
  * All(...bindings, Identity),
34
31
  * ResumeHandle(r0, readVar(0),
35
32
  * ResumeHandle(r1, readVar(1),
36
- * Chain(ExtractIndex(N), body)
33
+ * Chain(GetIndex(N), body)
37
34
  * )
38
35
  * )
39
36
  * )
40
37
  */
41
38
  /**
42
39
  * Constraint for the body callback return type. Only requires the output
43
- * phantom fields — omits `__in` and `__in_co` so that body actions with
44
- * `In = never` (e.g. pipelines starting from a VarRef) are assignable.
40
+ * phantom field — omits `__in` and `__in_co` so that body actions with
41
+ * any input type (e.g. pipelines starting from a VarRef) are assignable.
45
42
  */
46
43
  type BodyResult<TOut> = Action & {
47
44
  __out?: () => TOut;
48
- __out_contra?: (output: TOut) => void;
49
45
  };
50
46
  export declare function bind<TBindings extends Action[], TOut>(bindings: [...TBindings], body: (vars: InferVarRefs<TBindings>) => BodyResult<TOut>): TypedAction<ExtractInput<TBindings[number]>, TOut>;
51
47
  /**
@@ -60,3 +56,4 @@ export declare function bind<TBindings extends Action[], TOut>(bindings: [...TBi
60
56
  */
61
57
  export declare function bindInput<TIn, TOut = any>(body: (input: VarRef<TIn>) => BodyResult<TOut>): TypedAction<TIn, TOut>;
62
58
  export {};
59
+ //# sourceMappingURL=bind.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bind.d.ts","sourceRoot":"","sources":["../src/bind.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,MAAM,EACX,KAAK,YAAY,EACjB,KAAK,aAAa,EAClB,KAAK,WAAW,EAGjB,MAAM,UAAU,CAAC;AAWlB;;;;;;GAMG;AACH,MAAM,MAAM,MAAM,CAAC,MAAM,IAAI,WAAW,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;AAetD;;;;;;;GAOG;AACH,MAAM,MAAM,YAAY,CAAC,SAAS,SAAS,MAAM,EAAE,IAAI;KACpD,CAAC,IAAI,MAAM,SAAS,GAAG,MAAM,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;CAC5D,CAAC;AA4BF;;;;;;;;;;;;;;;;GAgBG;AACH;;;;GAIG;AACH,KAAK,UAAU,CAAC,IAAI,IAAI,MAAM,GAAG;IAC/B,KAAK,CAAC,EAAE,MAAM,IAAI,CAAC;CACpB,CAAC;AAEF,wBAAgB,IAAI,CAAC,SAAS,SAAS,MAAM,EAAE,EAAE,IAAI,EACnD,QAAQ,EAAE,CAAC,GAAG,SAAS,CAAC,EACxB,IAAI,EAAE,CAAC,IAAI,EAAE,YAAY,CAAC,SAAS,CAAC,KAAK,UAAU,CAAC,IAAI,CAAC,GACxD,WAAW,CAAC,YAAY,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,EAAE,IAAI,CAAC,CAkCpD;AAMD;;;;;;;;;GASG;AACH,wBAAgB,SAAS,CAAC,GAAG,EAAE,IAAI,GAAG,GAAG,EACvC,IAAI,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC,GAAG,CAAC,KAAK,UAAU,CAAC,IAAI,CAAC,GAC7C,WAAW,CAAC,GAAG,EAAE,IAAI,CAAC,CAExB"}