@@ -14,6 +14,16 @@ import type { MaybePromise, TreeContext } from "./tree-types.ts";
1414import { isFatalError , isPromise , applyControlFlow , BridgeAbortError } from "./tree-types.ts" ;
1515import { coerceConstant , getSimplePullRef } from "./tree-utils.ts" ;
1616
17+ // ── Wire type helpers ────────────────────────────────────────────────────────
18+
19+ /**
20+ * A non-constant wire — any Wire variant that carries gate modifiers
21+ * (`falsyFallback`, `nullishFallbackRef`, `catchFallback`, etc.).
22+ * Excludes the `{ value: string; to: NodeRef }` constant wire which has no
23+ * modifier slots.
24+ */
25+ type WireWithGates = Exclude < Wire , { value : string } > ;
26+
1727// ── Public entry point ──────────────────────────────────────────────────────
1828
1929/**
@@ -66,8 +76,8 @@ async function resolveWiresAsync(
6676 ctx : TreeContext ,
6777 wires : Wire [ ] ,
6878 pullChain ?: Set < string > ,
69- ) : Promise < any > {
70- let lastError : any ;
79+ ) : Promise < unknown > {
80+ let lastError : unknown ;
7181
7282 for ( const w of wires ) {
7383 // Abort discipline — yield immediately if client disconnected
@@ -77,45 +87,24 @@ async function resolveWiresAsync(
7787 if ( "value" in w ) return coerceConstant ( w . value ) ;
7888
7989 try {
80- // --- Layer 1: Execution ---
81- let resolvedValue = await evaluateWireSource ( ctx , w , pullChain ) ;
82-
83- // --- Layer 2a: Falsy Gate (||) ---
84- if ( ! resolvedValue && w . falsyFallbackRefs ?. length ) {
85- for ( const ref of w . falsyFallbackRefs ) {
86- resolvedValue = await ctx . pullSingle ( ref , pullChain ) ;
87- if ( resolvedValue ) break ;
88- }
89- }
90+ // Layer 1: Execution
91+ let value = await evaluateWireSource ( ctx , w , pullChain ) ;
9092
91- if ( ! resolvedValue ) {
92- if ( w . falsyControl ) {
93- resolvedValue = applyControlFlow ( w . falsyControl ) ;
94- } else if ( w . falsyFallback != null ) {
95- resolvedValue = coerceConstant ( w . falsyFallback ) ;
96- }
97- }
93+ // Layer 2a: Falsy Gate (||)
94+ value = await applyFalsyGate ( ctx , w , value , pullChain ) ;
9895
99- // --- Layer 2b: Nullish Gate (??) ---
100- if ( resolvedValue == null ) {
101- if ( w . nullishControl ) {
102- resolvedValue = applyControlFlow ( w . nullishControl ) ;
103- } else if ( w . nullishFallbackRef ) {
104- resolvedValue = await ctx . pullSingle ( w . nullishFallbackRef , pullChain ) ;
105- } else if ( w . nullishFallback != null ) {
106- resolvedValue = coerceConstant ( w . nullishFallback ) ;
107- }
108- }
96+ // Layer 2b: Nullish Gate (??)
97+ value = await applyNullishGate ( ctx , w , value , pullChain ) ;
10998
110- // --- Overdefinition Boundary ---
111- if ( resolvedValue != null ) return resolvedValue ;
112- } catch ( err : any ) {
113- // --- Layer 3: Catch ---
99+ // Overdefinition Boundary
100+ if ( value != null ) return value ;
101+ } catch ( err : unknown ) {
102+ // Layer 3: Catch Gate
114103 if ( isFatalError ( err ) ) throw err ;
115- if ( w . catchControl ) return applyControlFlow ( w . catchControl ) ;
116- if ( w . catchFallbackRef )
117- return ctx . pullSingle ( w . catchFallbackRef , pullChain ) ;
118- if ( w . catchFallback != null ) return coerceConstant ( w . catchFallback ) ;
104+
105+ const recoveredValue = await applyCatchGate ( ctx , w , pullChain ) ;
106+ if ( recoveredValue != null ) return recoveredValue ;
107+
119108 lastError = err ;
120109 }
121110 }
@@ -124,6 +113,79 @@ async function resolveWiresAsync(
124113 return undefined ;
125114}
126115
116+ // ── Layer 2a: Falsy Gate (||) ────────────────────────────────────────────────
117+
118+ /**
119+ * Apply the Falsy Gate (Layer 2a) to a resolved value.
120+ *
121+ * If the value is already truthy the gate is a no-op. Otherwise the gate
122+ * walks `falsyFallbackRefs` (chained `||` refs) in order, returning the first
123+ * truthy result. If none yields a truthy value, `falsyControl` or
124+ * `falsyFallback` is tried as a last resort.
125+ */
126+ export async function applyFalsyGate (
127+ ctx : TreeContext ,
128+ w : WireWithGates ,
129+ value : unknown ,
130+ pullChain ?: Set < string > ,
131+ ) : Promise < unknown > {
132+ if ( value ) return value ; // already truthy — gate is closed
133+
134+ if ( w . falsyFallbackRefs ?. length ) {
135+ for ( const ref of w . falsyFallbackRefs ) {
136+ const fallback = await ctx . pullSingle ( ref , pullChain ) ;
137+ if ( fallback ) return fallback ;
138+ }
139+ }
140+
141+ if ( w . falsyControl ) return applyControlFlow ( w . falsyControl ) ;
142+ if ( w . falsyFallback != null ) return coerceConstant ( w . falsyFallback ) ;
143+ return value ;
144+ }
145+
146+ // ── Layer 2b: Nullish Gate (??) ──────────────────────────────────────────────
147+
148+ /**
149+ * Apply the Nullish Gate (Layer 2b) to a resolved value.
150+ *
151+ * If the value is non-nullish the gate is a no-op. Otherwise `nullishControl`,
152+ * `nullishFallbackRef`, or `nullishFallback` is applied (in priority order).
153+ */
154+ export async function applyNullishGate (
155+ ctx : TreeContext ,
156+ w : WireWithGates ,
157+ value : unknown ,
158+ pullChain ?: Set < string > ,
159+ ) : Promise < unknown > {
160+ if ( value != null ) return value ; // non-nullish — gate is closed
161+
162+ if ( w . nullishControl ) return applyControlFlow ( w . nullishControl ) ;
163+ if ( w . nullishFallbackRef ) return ctx . pullSingle ( w . nullishFallbackRef , pullChain ) ;
164+ if ( w . nullishFallback != null ) return coerceConstant ( w . nullishFallback ) ;
165+ return value ;
166+ }
167+
168+ // ── Layer 3: Catch Gate ──────────────────────────────────────────────────────
169+
170+ /**
171+ * Apply the Catch Gate (Layer 3) after an error has been thrown by the
172+ * execution layer.
173+ *
174+ * Returns the recovered value if the wire supplies a catch handler, or
175+ * `undefined` if the error should be stored as `lastError` so the loop can
176+ * continue to the next wire.
177+ */
178+ export async function applyCatchGate (
179+ ctx : TreeContext ,
180+ w : WireWithGates ,
181+ pullChain ?: Set < string > ,
182+ ) : Promise < unknown > {
183+ if ( w . catchControl ) return applyControlFlow ( w . catchControl ) ;
184+ if ( w . catchFallbackRef ) return ctx . pullSingle ( w . catchFallbackRef , pullChain ) ;
185+ if ( w . catchFallback != null ) return coerceConstant ( w . catchFallback ) ;
186+ return undefined ;
187+ }
188+
127189// ── Layer 1: Wire source evaluation ─────────────────────────────────────────
128190
129191/**
0 commit comments