(node: NodeData)
| 200 | } |
| 201 | } |
| 202 | } |
| 203 | } |
| 204 | return result; |
| 205 | } |
| 206 | |
| 207 | /** |
| 208 | * Compute the effective outputs the node emits to variable scope: available outputs |
| 209 | * filtered to active emit bindings only (inactive bindings and active assign bindings |
| 210 | * contribute nothing — assign routes to an existing variable, inactive is discarded). |
| 211 | * Emit bindings carry a user-chosen name that overrides the output's default name (the id). |
| 212 | * |
| 213 | * Binding lookup: |
| 214 | * - Static outputs (incl. FunctionCall returns): `node.arguments[out.id]` |
| 215 | * - List outputs: each entry is already a declaration; emit entries contribute |
| 216 | * directly (no separate binding), assign entries contribute nothing |
| 217 | */ |
| 218 | export function getNodeOutput(node: NodeData): Record<string, NodeOutput> { |
| 219 | const result: Record<string, NodeOutput> = {}; |
| 220 | const args = node.arguments as Record<string, unknown>; |
| 221 | |
| 222 | const applyStaticBinding = (key: string, defaultName: string, dataType: NodeOutput["dataType"], binding: OutputBinding | undefined) => { |
| 223 | // No binding = treat as default emit (the seeded shape). Otherwise honor active+mode. |
| 224 | if (!binding) { |
| 225 | result[key] = { name: defaultName, dataType }; |
| 226 | return; |
| 227 | } |
| 228 | if (!binding.active) return; |
| 229 | if (binding.mode !== "emit") return; |
| 230 | result[key] = { name: binding.name, dataType }; |
| 231 | }; |
| 232 | |
| 233 | if (node.type === "FunctionCall") { |
| 234 | for (const ret of node.functionInfo.returns) { |
| 235 | applyStaticBinding(ret.uid, ret.name, ret.dataType, getStaticBinding(args, ret.uid)); |
| 236 | } |
| 237 | return result; |
| 238 | } |
| 239 | |
| 240 | const def = NodeRegistry.getByType(node.type); |
| 241 | if (!def?.outputs) return result; |
| 242 | |
| 243 | for (const out of def.outputs) { |
no test coverage detected