@barnum/barnum 0.2.3 → 0.3.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 (56) 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/cli.cjs +33 -0
  7. package/dist/all.d.ts +12 -0
  8. package/dist/all.js +8 -0
  9. package/dist/ast.d.ts +375 -0
  10. package/dist/ast.js +381 -0
  11. package/dist/bind.d.ts +62 -0
  12. package/dist/bind.js +106 -0
  13. package/dist/builtins.d.ts +257 -0
  14. package/dist/builtins.js +600 -0
  15. package/dist/chain.d.ts +2 -0
  16. package/dist/chain.js +8 -0
  17. package/dist/effect-id.d.ts +14 -0
  18. package/dist/effect-id.js +16 -0
  19. package/dist/handler.d.ts +50 -0
  20. package/dist/handler.js +146 -0
  21. package/dist/index.d.ts +8 -0
  22. package/dist/index.js +5 -0
  23. package/dist/pipe.d.ts +11 -0
  24. package/dist/pipe.js +11 -0
  25. package/dist/race.d.ts +53 -0
  26. package/dist/race.js +141 -0
  27. package/dist/recursive.d.ts +34 -0
  28. package/dist/recursive.js +53 -0
  29. package/dist/run.d.ts +7 -0
  30. package/dist/run.js +143 -0
  31. package/dist/schema.d.ts +8 -0
  32. package/dist/schema.js +95 -0
  33. package/dist/try-catch.d.ts +23 -0
  34. package/dist/try-catch.js +36 -0
  35. package/dist/worker.d.ts +11 -0
  36. package/dist/worker.js +46 -0
  37. package/package.json +40 -16
  38. package/src/all.ts +89 -0
  39. package/src/ast.ts +878 -0
  40. package/src/bind.ts +192 -0
  41. package/src/builtins.ts +804 -0
  42. package/src/chain.ts +17 -0
  43. package/src/effect-id.ts +30 -0
  44. package/src/handler.ts +279 -0
  45. package/src/index.ts +30 -0
  46. package/src/pipe.ts +93 -0
  47. package/src/race.ts +183 -0
  48. package/src/recursive.ts +112 -0
  49. package/src/run.ts +181 -0
  50. package/src/schema.ts +118 -0
  51. package/src/try-catch.ts +53 -0
  52. package/src/worker.ts +56 -0
  53. package/README.md +0 -19
  54. package/barnum-config-schema.json +0 -408
  55. package/cli.js +0 -20
  56. package/index.js +0 -23
package/src/bind.ts ADDED
@@ -0,0 +1,192 @@
1
+ import {
2
+ type Action,
3
+ type ExtractInput,
4
+ type ExtractOutput,
5
+ type TypedAction,
6
+ typedAction,
7
+ } from "./ast.js";
8
+ import { identity, drop } from "./builtins.js";
9
+ import { allocateResumeHandlerId, type ResumeHandlerId } from "./effect-id.js";
10
+ import { pipe } from "./pipe.js";
11
+
12
+ // ---------------------------------------------------------------------------
13
+ // VarRef — typed reference to a bound value
14
+ // ---------------------------------------------------------------------------
15
+
16
+ /**
17
+ * A typed reference to a bound value. Output is `TValue`.
18
+ *
19
+ * Use `.then()` (not `pipe()`) when chaining a VarRef into a generic
20
+ * action like `pick` or `extractField` — pipe overloads can't infer
21
+ * the generic's type parameter from the VarRef's output.
22
+ */
23
+ export type VarRef<TValue> = TypedAction<never, TValue>;
24
+
25
+ function createVarRef<TValue>(
26
+ resumeHandlerId: ResumeHandlerId,
27
+ ): VarRef<TValue> {
28
+ return typedAction({
29
+ kind: "ResumePerform",
30
+ resume_handler_id: resumeHandlerId,
31
+ });
32
+ }
33
+
34
+ // ---------------------------------------------------------------------------
35
+ // InferVarRefs — map bindings to VarRef types
36
+ // ---------------------------------------------------------------------------
37
+
38
+ /**
39
+ * Maps each binding's output type to a VarRef. TypeScript resolves
40
+ * ExtractOutput from each binding expression.
41
+ *
42
+ * Constraint is `Action[]` (not `Pipeable<any, any>[]`) because
43
+ * `TypedAction<never, X>` (e.g. from `constant()`) fails the invariant
44
+ * `__in` check against `Pipeable<any, any>` on the 9-variant
45
+ * Action union. Using raw `Action[]` avoids the phantom field
46
+ * assignability issue while `ExtractOutput` still extracts the correct
47
+ * output type from the phantom fields on the concrete types.
48
+ */
49
+ export type InferVarRefs<TBindings extends Action[]> = {
50
+ [K in keyof TBindings]: VarRef<ExtractOutput<TBindings[K]>>;
51
+ };
52
+
53
+ // ---------------------------------------------------------------------------
54
+ // readVar — handler DAG for the nth binding
55
+ // ---------------------------------------------------------------------------
56
+
57
+ /**
58
+ * Returns an action that extracts the nth value from the ResumeHandle's
59
+ * state tuple and passes state through unchanged. When a ResumePerform
60
+ * fires, the engine calls the handler with `[payload, state]`. For bind,
61
+ * `state` (index 1) is the full All output tuple. The handler produces
62
+ * `[state[n], state]` — value is state[n], new_state is state (unchanged).
63
+ *
64
+ * Expanded AST: All(Chain(ExtractIndex(1), ExtractIndex(n)), ExtractIndex(1))
65
+ */
66
+ function readVar(n: number): Action {
67
+ return {
68
+ kind: "All",
69
+ actions: [
70
+ {
71
+ kind: "Chain",
72
+ first: {
73
+ kind: "Invoke",
74
+ handler: {
75
+ kind: "Builtin",
76
+ builtin: { kind: "ExtractIndex", value: 1 },
77
+ },
78
+ },
79
+ rest: {
80
+ kind: "Invoke",
81
+ handler: {
82
+ kind: "Builtin",
83
+ builtin: { kind: "ExtractIndex", value: n },
84
+ },
85
+ },
86
+ },
87
+ {
88
+ kind: "Invoke",
89
+ handler: {
90
+ kind: "Builtin",
91
+ builtin: { kind: "ExtractIndex", value: 1 },
92
+ },
93
+ },
94
+ ],
95
+ };
96
+ }
97
+
98
+ // ---------------------------------------------------------------------------
99
+ // bind — the user-facing function
100
+ // ---------------------------------------------------------------------------
101
+
102
+ /**
103
+ * Bind concurrent values as VarRefs available throughout the body.
104
+ *
105
+ * All bindings are actions (Pipeable) evaluated concurrently with the
106
+ * pipeline input. The body callback receives an array of VarRefs,
107
+ * one per binding.
108
+ *
109
+ * Compiles to:
110
+ * Chain(
111
+ * All(...bindings, Identity),
112
+ * ResumeHandle(r0, readVar(0),
113
+ * ResumeHandle(r1, readVar(1),
114
+ * Chain(ExtractIndex(N), body)
115
+ * )
116
+ * )
117
+ * )
118
+ */
119
+ /**
120
+ * Constraint for the body callback return type. Only requires the output
121
+ * phantom fields — omits `__in` and `__in_co` so that body actions with
122
+ * `In = never` (e.g. pipelines starting from a VarRef) are assignable.
123
+ */
124
+ type BodyResult<TOut> = Action & {
125
+ __out?: () => TOut;
126
+ __out_contra?: (output: TOut) => void;
127
+ };
128
+
129
+ export function bind<TBindings extends Action[], TOut>(
130
+ bindings: [...TBindings],
131
+ body: (vars: InferVarRefs<TBindings>) => BodyResult<TOut>,
132
+ ): TypedAction<ExtractInput<TBindings[number]>, TOut> {
133
+ // 1. Gensym one resumeHandlerId per binding.
134
+ const resumeHandlerIds = bindings.map(() => allocateResumeHandlerId());
135
+
136
+ // 2. Create VarRefs (ResumePerform nodes) for each binding.
137
+ const varRefs = resumeHandlerIds.map((id) => createVarRef(id));
138
+
139
+ // 3. Invoke the body callback with the VarRefs.
140
+ const bodyAction = body(varRefs as InferVarRefs<TBindings>) as Action;
141
+
142
+ // 4. Build nested Handles from inside out.
143
+ // Innermost: extract pipeline_input (last All element) → user body
144
+ const pipelineInputIndex = bindings.length;
145
+ let inner: Action = {
146
+ kind: "Chain",
147
+ first: {
148
+ kind: "Invoke",
149
+ handler: {
150
+ kind: "Builtin",
151
+ builtin: { kind: "ExtractIndex", value: pipelineInputIndex },
152
+ },
153
+ },
154
+ rest: bodyAction,
155
+ };
156
+ for (let i = resumeHandlerIds.length - 1; i >= 0; i--) {
157
+ inner = {
158
+ kind: "ResumeHandle",
159
+ resume_handler_id: resumeHandlerIds[i],
160
+ handler: readVar(i),
161
+ body: inner,
162
+ };
163
+ }
164
+
165
+ // 5. All(...bindings, identity()) → nested Handles
166
+ const allActions = [...bindings.map((b) => b as Action), identity as Action];
167
+ return typedAction({
168
+ kind: "Chain",
169
+ first: { kind: "All", actions: allActions },
170
+ rest: inner,
171
+ });
172
+ }
173
+
174
+ // ---------------------------------------------------------------------------
175
+ // bindInput — bind the pipeline input
176
+ // ---------------------------------------------------------------------------
177
+
178
+ /**
179
+ * Convenience wrapper for the common pattern of capturing the pipeline
180
+ * input as a VarRef. The body's pipeline input is `never` — the input
181
+ * is dropped, so the body must access it through the VarRef.
182
+ *
183
+ * Sugar for: `bind([identity()], ([input]) => pipe(drop, body(input)))`
184
+ *
185
+ * TOut defaults to `any` so callers can specify just TIn:
186
+ * bindInput<FileEntry>((entry) => ...)
187
+ */
188
+ export function bindInput<TIn, TOut = any>(
189
+ body: (input: VarRef<TIn>) => BodyResult<TOut>,
190
+ ): TypedAction<TIn, TOut> {
191
+ return bind([identity], ([input]) => pipe(drop, body(input)));
192
+ }