@foresthubai/workflow-core 0.4.3 → 0.4.5

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 (298) hide show
  1. package/LICENSE +202 -202
  2. package/NOTICE +14 -14
  3. package/README.md +63 -63
  4. package/dist/api/deployment.d.ts +74 -0
  5. package/dist/api/deployment.d.ts.map +1 -0
  6. package/dist/api/deployment.js +6 -0
  7. package/dist/api/deployment.js.map +1 -0
  8. package/dist/api/engine.d.ts +744 -0
  9. package/dist/api/engine.d.ts.map +1 -0
  10. package/dist/api/engine.js +6 -0
  11. package/dist/api/engine.js.map +1 -0
  12. package/dist/api/index.d.ts +4 -0
  13. package/dist/api/index.d.ts.map +1 -1
  14. package/dist/api/index.js +2 -0
  15. package/dist/api/index.js.map +1 -1
  16. package/dist/api/workflow.d.ts +25 -9
  17. package/dist/api/workflow.d.ts.map +1 -1
  18. package/dist/channel/Channel.d.ts +1 -1
  19. package/dist/channel/Channel.d.ts.map +1 -1
  20. package/dist/channel/Channel.js +3 -1
  21. package/dist/channel/Channel.js.map +1 -1
  22. package/dist/channel/ChannelDefinition.d.ts.map +1 -1
  23. package/dist/channel/ChannelDefinition.js +24 -0
  24. package/dist/channel/ChannelDefinition.js.map +1 -1
  25. package/dist/channel/index.d.ts.map +1 -1
  26. package/dist/channel/index.js +2 -0
  27. package/dist/channel/index.js.map +1 -1
  28. package/dist/channel/serialization.d.ts.map +1 -1
  29. package/dist/channel/serialization.js +8 -0
  30. package/dist/channel/serialization.js.map +1 -1
  31. package/dist/deploy/index.d.ts +5 -1
  32. package/dist/deploy/index.d.ts.map +1 -1
  33. package/dist/deploy/index.js +4 -1
  34. package/dist/deploy/index.js.map +1 -1
  35. package/dist/deploy/inputs.d.ts +26 -0
  36. package/dist/deploy/inputs.d.ts.map +1 -0
  37. package/dist/deploy/inputs.js +4 -0
  38. package/dist/deploy/inputs.js.map +1 -0
  39. package/dist/deploy/requirements.d.ts +24 -0
  40. package/dist/deploy/requirements.d.ts.map +1 -1
  41. package/dist/deploy/requirements.js +63 -0
  42. package/dist/deploy/requirements.js.map +1 -1
  43. package/dist/deploy/spec.d.ts +27 -0
  44. package/dist/deploy/spec.d.ts.map +1 -0
  45. package/dist/deploy/spec.js +352 -0
  46. package/dist/deploy/spec.js.map +1 -0
  47. package/dist/diagnostics/__fixtures__/diagnosticFixtures.d.ts.map +1 -1
  48. package/dist/diagnostics/__fixtures__/diagnosticFixtures.js +2 -0
  49. package/dist/diagnostics/__fixtures__/diagnosticFixtures.js.map +1 -1
  50. package/dist/diagnostics/diagnostics.d.ts.map +1 -1
  51. package/dist/diagnostics/diagnostics.js +2 -0
  52. package/dist/diagnostics/diagnostics.js.map +1 -1
  53. package/dist/diagnostics/index.d.ts.map +1 -1
  54. package/dist/diagnostics/index.js +2 -0
  55. package/dist/diagnostics/index.js.map +1 -1
  56. package/dist/edge/Edge.d.ts.map +1 -1
  57. package/dist/edge/Edge.js +2 -0
  58. package/dist/edge/Edge.js.map +1 -1
  59. package/dist/edge/EdgeDefinition.d.ts.map +1 -1
  60. package/dist/edge/EdgeDefinition.js +2 -0
  61. package/dist/edge/EdgeDefinition.js.map +1 -1
  62. package/dist/edge/EdgeType.d.ts.map +1 -1
  63. package/dist/edge/EdgeType.js +2 -0
  64. package/dist/edge/EdgeType.js.map +1 -1
  65. package/dist/edge/index.d.ts.map +1 -1
  66. package/dist/edge/index.js +2 -2
  67. package/dist/edge/index.js.map +1 -1
  68. package/dist/edge/serialization.d.ts.map +1 -1
  69. package/dist/edge/serialization.js +2 -0
  70. package/dist/edge/serialization.js.map +1 -1
  71. package/dist/expression/index.d.ts.map +1 -1
  72. package/dist/expression/index.js +2 -0
  73. package/dist/expression/index.js.map +1 -1
  74. package/dist/expression/parser.d.ts.map +1 -1
  75. package/dist/expression/parser.js +2 -0
  76. package/dist/expression/parser.js.map +1 -1
  77. package/dist/expression/types.d.ts.map +1 -1
  78. package/dist/expression/types.js +2 -0
  79. package/dist/expression/types.js.map +1 -1
  80. package/dist/function/FunctionDeclaration.d.ts.map +1 -1
  81. package/dist/function/FunctionDeclaration.js +2 -0
  82. package/dist/function/FunctionDeclaration.js.map +1 -1
  83. package/dist/function/index.d.ts.map +1 -1
  84. package/dist/function/index.js +2 -0
  85. package/dist/function/index.js.map +1 -1
  86. package/dist/function/serialization.d.ts.map +1 -1
  87. package/dist/function/serialization.js +2 -0
  88. package/dist/function/serialization.js.map +1 -1
  89. package/dist/id/index.d.ts.map +1 -1
  90. package/dist/id/index.js +2 -0
  91. package/dist/id/index.js.map +1 -1
  92. package/dist/index.d.ts.map +1 -1
  93. package/dist/index.js +2 -0
  94. package/dist/index.js.map +1 -1
  95. package/dist/memory/Memory.d.ts.map +1 -1
  96. package/dist/memory/Memory.js +2 -0
  97. package/dist/memory/Memory.js.map +1 -1
  98. package/dist/memory/MemoryDefinition.d.ts.map +1 -1
  99. package/dist/memory/MemoryDefinition.js +2 -0
  100. package/dist/memory/MemoryDefinition.js.map +1 -1
  101. package/dist/memory/MemoryFileDefinition.d.ts.map +1 -1
  102. package/dist/memory/MemoryFileDefinition.js +2 -0
  103. package/dist/memory/MemoryFileDefinition.js.map +1 -1
  104. package/dist/memory/MemoryRegistry.d.ts.map +1 -1
  105. package/dist/memory/MemoryRegistry.js +2 -0
  106. package/dist/memory/MemoryRegistry.js.map +1 -1
  107. package/dist/memory/VectorDatabaseDefinition.d.ts.map +1 -1
  108. package/dist/memory/VectorDatabaseDefinition.js +2 -0
  109. package/dist/memory/VectorDatabaseDefinition.js.map +1 -1
  110. package/dist/memory/index.d.ts.map +1 -1
  111. package/dist/memory/index.js +2 -0
  112. package/dist/memory/index.js.map +1 -1
  113. package/dist/memory/serialization.d.ts.map +1 -1
  114. package/dist/memory/serialization.js +2 -0
  115. package/dist/memory/serialization.js.map +1 -1
  116. package/dist/migration/index.d.ts.map +1 -1
  117. package/dist/migration/index.js +2 -0
  118. package/dist/migration/index.js.map +1 -1
  119. package/dist/migration/migrate.d.ts.map +1 -1
  120. package/dist/migration/migrate.js +2 -0
  121. package/dist/migration/migrate.js.map +1 -1
  122. package/dist/migration/migrations.d.ts.map +1 -1
  123. package/dist/migration/migrations.js +2 -0
  124. package/dist/migration/migrations.js.map +1 -1
  125. package/dist/migration/version.d.ts.map +1 -1
  126. package/dist/migration/version.js +2 -0
  127. package/dist/migration/version.js.map +1 -1
  128. package/dist/model/LLMModelDefinition.d.ts.map +1 -1
  129. package/dist/model/LLMModelDefinition.js +2 -0
  130. package/dist/model/LLMModelDefinition.js.map +1 -1
  131. package/dist/model/Model.d.ts.map +1 -1
  132. package/dist/model/Model.js +2 -13
  133. package/dist/model/Model.js.map +1 -1
  134. package/dist/model/ModelDefinition.d.ts.map +1 -1
  135. package/dist/model/ModelDefinition.js +2 -0
  136. package/dist/model/ModelDefinition.js.map +1 -1
  137. package/dist/model/ModelRegistry.d.ts.map +1 -1
  138. package/dist/model/ModelRegistry.js +2 -0
  139. package/dist/model/ModelRegistry.js.map +1 -1
  140. package/dist/model/index.d.ts.map +1 -1
  141. package/dist/model/index.js +2 -0
  142. package/dist/model/index.js.map +1 -1
  143. package/dist/model/serialization.d.ts.map +1 -1
  144. package/dist/model/serialization.js +2 -0
  145. package/dist/model/serialization.js.map +1 -1
  146. package/dist/node/AgentNode.d.ts.map +1 -1
  147. package/dist/node/AgentNode.js +2 -0
  148. package/dist/node/AgentNode.js.map +1 -1
  149. package/dist/node/DataNode.d.ts.map +1 -1
  150. package/dist/node/DataNode.js +2 -0
  151. package/dist/node/DataNode.js.map +1 -1
  152. package/dist/node/FunctionNode.d.ts.map +1 -1
  153. package/dist/node/FunctionNode.js +2 -0
  154. package/dist/node/FunctionNode.js.map +1 -1
  155. package/dist/node/InputNode.d.ts.map +1 -1
  156. package/dist/node/InputNode.js +2 -0
  157. package/dist/node/InputNode.js.map +1 -1
  158. package/dist/node/LogicNode.d.ts.map +1 -1
  159. package/dist/node/LogicNode.js +2 -0
  160. package/dist/node/LogicNode.js.map +1 -1
  161. package/dist/node/MqttNode.d.ts.map +1 -1
  162. package/dist/node/MqttNode.js +2 -0
  163. package/dist/node/MqttNode.js.map +1 -1
  164. package/dist/node/Node.d.ts.map +1 -1
  165. package/dist/node/Node.js +2 -7
  166. package/dist/node/Node.js.map +1 -1
  167. package/dist/node/NodeDefinition.d.ts.map +1 -1
  168. package/dist/node/NodeDefinition.js +2 -0
  169. package/dist/node/NodeDefinition.js.map +1 -1
  170. package/dist/node/NodeRegistry.d.ts.map +1 -1
  171. package/dist/node/NodeRegistry.js +2 -0
  172. package/dist/node/NodeRegistry.js.map +1 -1
  173. package/dist/node/OutputNode.d.ts.map +1 -1
  174. package/dist/node/OutputNode.js +4 -2
  175. package/dist/node/OutputNode.js.map +1 -1
  176. package/dist/node/ToolNode.d.ts.map +1 -1
  177. package/dist/node/ToolNode.js +2 -0
  178. package/dist/node/ToolNode.js.map +1 -1
  179. package/dist/node/TriggerNode.d.ts.map +1 -1
  180. package/dist/node/TriggerNode.js +2 -0
  181. package/dist/node/TriggerNode.js.map +1 -1
  182. package/dist/node/constants.d.ts.map +1 -1
  183. package/dist/node/constants.js +2 -0
  184. package/dist/node/constants.js.map +1 -1
  185. package/dist/node/index.d.ts.map +1 -1
  186. package/dist/node/index.js +2 -0
  187. package/dist/node/index.js.map +1 -1
  188. package/dist/node/methods.d.ts.map +1 -1
  189. package/dist/node/methods.js +2 -0
  190. package/dist/node/methods.js.map +1 -1
  191. package/dist/node/serialization.d.ts.map +1 -1
  192. package/dist/node/serialization.js +33 -13
  193. package/dist/node/serialization.js.map +1 -1
  194. package/dist/parameter/OutputParameter.d.ts.map +1 -1
  195. package/dist/parameter/OutputParameter.js +2 -0
  196. package/dist/parameter/OutputParameter.js.map +1 -1
  197. package/dist/parameter/Parameter.d.ts.map +1 -1
  198. package/dist/parameter/Parameter.js +2 -0
  199. package/dist/parameter/Parameter.js.map +1 -1
  200. package/dist/parameter/index.d.ts.map +1 -1
  201. package/dist/parameter/index.js +2 -0
  202. package/dist/parameter/index.js.map +1 -1
  203. package/dist/variable/Variable.d.ts.map +1 -1
  204. package/dist/variable/Variable.js +2 -0
  205. package/dist/variable/Variable.js.map +1 -1
  206. package/dist/variable/index.d.ts.map +1 -1
  207. package/dist/variable/index.js +2 -3
  208. package/dist/variable/index.js.map +1 -1
  209. package/dist/variable/operations.d.ts.map +1 -1
  210. package/dist/variable/operations.js +2 -0
  211. package/dist/variable/operations.js.map +1 -1
  212. package/dist/workflow/Workflow.d.ts.map +1 -1
  213. package/dist/workflow/Workflow.js +2 -0
  214. package/dist/workflow/Workflow.js.map +1 -1
  215. package/dist/workflow/index.d.ts.map +1 -1
  216. package/dist/workflow/index.js +2 -0
  217. package/dist/workflow/index.js.map +1 -1
  218. package/dist/workflow/serialization.d.ts.map +1 -1
  219. package/dist/workflow/serialization.js +2 -4
  220. package/dist/workflow/serialization.js.map +1 -1
  221. package/package.json +2 -2
  222. package/src/api/deployment.ts +74 -0
  223. package/src/api/engine.ts +744 -0
  224. package/src/api/index.ts +29 -11
  225. package/src/api/workflow.ts +25 -9
  226. package/src/channel/Channel.ts +14 -11
  227. package/src/channel/ChannelDefinition.ts +101 -76
  228. package/src/channel/index.ts +9 -6
  229. package/src/channel/serialization.ts +77 -68
  230. package/src/deploy/index.ts +17 -1
  231. package/src/deploy/inputs.ts +44 -0
  232. package/src/deploy/requirements.test.ts +64 -61
  233. package/src/deploy/requirements.ts +159 -41
  234. package/src/deploy/spec.test.ts +227 -0
  235. package/src/deploy/spec.ts +397 -0
  236. package/src/diagnostics/__fixtures__/diagnosticFixtures.ts +161 -158
  237. package/src/diagnostics/diagnostics.test.ts +881 -878
  238. package/src/diagnostics/diagnostics.ts +939 -936
  239. package/src/diagnostics/index.ts +14 -11
  240. package/src/edge/Edge.ts +26 -23
  241. package/src/edge/EdgeDefinition.ts +48 -45
  242. package/src/edge/EdgeType.ts +22 -19
  243. package/src/edge/index.ts +11 -8
  244. package/src/edge/serialization.ts +86 -83
  245. package/src/expression/index.ts +7 -4
  246. package/src/expression/parser.ts +365 -362
  247. package/src/expression/types.ts +33 -30
  248. package/src/function/FunctionDeclaration.ts +57 -54
  249. package/src/function/index.ts +6 -3
  250. package/src/function/serialization.ts +43 -40
  251. package/src/globals.d.ts +12 -9
  252. package/src/id/index.ts +11 -8
  253. package/src/index.ts +25 -22
  254. package/src/memory/Memory.ts +18 -15
  255. package/src/memory/MemoryDefinition.ts +19 -16
  256. package/src/memory/MemoryFileDefinition.ts +40 -37
  257. package/src/memory/MemoryRegistry.ts +38 -35
  258. package/src/memory/VectorDatabaseDefinition.ts +24 -21
  259. package/src/memory/index.ts +11 -8
  260. package/src/memory/serialization.ts +50 -47
  261. package/src/migration/index.ts +7 -4
  262. package/src/migration/migrate.test.ts +47 -44
  263. package/src/migration/migrate.ts +61 -58
  264. package/src/migration/migrations.ts +27 -24
  265. package/src/migration/version.ts +12 -9
  266. package/src/model/LLMModelDefinition.ts +15 -12
  267. package/src/model/Model.ts +42 -39
  268. package/src/model/ModelDefinition.ts +18 -15
  269. package/src/model/ModelRegistry.ts +36 -33
  270. package/src/model/index.ts +10 -7
  271. package/src/model/serialization.ts +33 -30
  272. package/src/node/AgentNode.ts +85 -82
  273. package/src/node/DataNode.ts +44 -41
  274. package/src/node/FunctionNode.ts +79 -76
  275. package/src/node/InputNode.ts +188 -185
  276. package/src/node/LogicNode.ts +36 -33
  277. package/src/node/MqttNode.ts +130 -127
  278. package/src/node/Node.ts +64 -61
  279. package/src/node/NodeDefinition.ts +40 -37
  280. package/src/node/NodeRegistry.ts +88 -85
  281. package/src/node/OutputNode.ts +90 -87
  282. package/src/node/ToolNode.ts +35 -32
  283. package/src/node/TriggerNode.ts +275 -272
  284. package/src/node/constants.ts +19 -16
  285. package/src/node/index.ts +29 -26
  286. package/src/node/methods.ts +281 -278
  287. package/src/node/serialization.test.ts +51 -0
  288. package/src/node/serialization.ts +565 -544
  289. package/src/parameter/OutputParameter.ts +71 -68
  290. package/src/parameter/Parameter.ts +246 -243
  291. package/src/parameter/index.ts +36 -33
  292. package/src/variable/Variable.ts +13 -10
  293. package/src/variable/index.ts +19 -16
  294. package/src/variable/operations.ts +109 -106
  295. package/src/workflow/Workflow.ts +44 -41
  296. package/src/workflow/index.ts +6 -3
  297. package/src/workflow/serialization.test.ts +243 -240
  298. package/src/workflow/serialization.ts +245 -242
@@ -1,158 +1,161 @@
1
- import type { Edge } from "../../edge";
2
- import type { NodeDefinition, NodeData } from "../../node";
3
- import type { DataType, Expression, Reference } from "../../api";
4
- import type { Channel } from "../../channel";
5
- import type { Memory } from "../../memory";
6
- import { NodeCategory } from "../../node";
7
- import type { Variable, DeclaredVariable, NodeOutputVariable } from "../../variable";
8
- import type { Diagnostic, DiagnosticCategory } from "../diagnostics";
9
-
10
- // ============================================================================
11
- // Variable builders
12
- // ============================================================================
13
-
14
- export function makeDeclaredVar(overrides: Partial<DeclaredVariable> = {}): Variable {
15
- return {
16
- kind: "declared",
17
- uid: "v1",
18
- name: "count",
19
- dataType: "int" as DataType,
20
- ...overrides,
21
- };
22
- }
23
-
24
- export function makeNodeOutputVar(overrides: Partial<NodeOutputVariable> = {}): Variable {
25
- return {
26
- kind: "node",
27
- nodeId: "n1",
28
- outputId: "output",
29
- name: "result",
30
- dataType: "int" as DataType,
31
- ...overrides,
32
- };
33
- }
34
-
35
- /** Build an `availableVariables` map from a list of `AvailableVariable` entries. */
36
- export function makeAvailableVars(vars: Variable[]): Record<string, Variable> {
37
- const map: Record<string, Variable> = {};
38
- for (const v of vars) {
39
- const key = v.kind === "declared" ? `declared:${v.uid}` : v.kind === "fnarg" ? `fnarg:${v.uid}` : `${v.nodeId}:${v.outputId}`;
40
- map[key] = v;
41
- }
42
- return map;
43
- }
44
-
45
- // ============================================================================
46
- // Expression / Reference builders
47
- // ============================================================================
48
-
49
- export function makeExpression(expression: string, dataType: DataType = "int", references: Reference[] = []): Expression {
50
- return { expression, references, dataType };
51
- }
52
-
53
- export function makeDeclaredRef(uid: string): Reference {
54
- return { srcId: "declared", varId: uid };
55
- }
56
-
57
- // ============================================================================
58
- // Edge builder
59
- // ============================================================================
60
-
61
- export function makeEdge(
62
- id: string,
63
- source: string,
64
- sourceHandle: string,
65
- target: string,
66
- targetHandle: string,
67
- overrides: Partial<Edge> = {},
68
- ): Edge {
69
- return {
70
- id,
71
- source,
72
- sourceHandle,
73
- target,
74
- targetHandle,
75
- type: "control",
76
- ...overrides,
77
- };
78
- }
79
-
80
- // ============================================================================
81
- // Channel builders
82
- // ============================================================================
83
-
84
- export function makeChannel(overrides: Partial<Channel> = {}): Channel {
85
- return {
86
- id: "ch1",
87
- label: "GPIO 4",
88
- type: "GPIOIN",
89
- arguments: {},
90
- ...overrides,
91
- };
92
- }
93
-
94
- export function makeChannels(channels: Channel[]): Record<string, Channel> {
95
- const map: Record<string, Channel> = {};
96
- for (const v of channels) map[v.id] = v;
97
- return map;
98
- }
99
-
100
- // ============================================================================
101
- // Memory builders
102
- // ============================================================================
103
-
104
- export function makeMemory(overrides: Partial<Memory> = {}): Memory {
105
- return {
106
- id: "mem1",
107
- label: "memory1",
108
- type: "MemoryFile",
109
- arguments: {},
110
- ...overrides,
111
- };
112
- }
113
-
114
- export function makeMemories(memories: Memory[]): Record<string, Memory> {
115
- const map: Record<string, Memory> = {};
116
- for (const m of memories) map[m.id] = m;
117
- return map;
118
- }
119
-
120
- // ============================================================================
121
- // Node instance builder — untyped escape hatch
122
- // ============================================================================
123
-
124
- /**
125
- * Build a minimal NodeData. Tests assert against the shape `computeNodeDiagnostics`
126
- * sees (arguments record + type discriminator), not against the strict per-type shapes,
127
- * so we widen to `NodeData` via unknown at the boundary.
128
- */
129
- export function makeNode(type: string, args: Record<string, unknown>, overrides: Record<string, unknown> = {}): NodeData {
130
- return { id: "n1", type, arguments: args, ...overrides } as unknown as NodeData;
131
- }
132
-
133
- // ============================================================================
134
- // Synthetic NodeDefinition builder
135
- // ============================================================================
136
-
137
- export function makeNodeDef(overrides: Partial<NodeDefinition> = {}): NodeDefinition {
138
- return {
139
- type: "Synthetic" as NodeDefinition["type"],
140
- label: "Synthetic Node",
141
- category: NodeCategory.Input,
142
- description: "Synthetic node used only in tests",
143
- parameters: [],
144
- ...overrides,
145
- };
146
- }
147
-
148
- // ============================================================================
149
- // Diagnostic assertion helpers
150
- // ============================================================================
151
-
152
- export function diagsOfCategory(diags: Diagnostic[], category: DiagnosticCategory): Diagnostic[] {
153
- return diags.filter((d) => d.category === category);
154
- }
155
-
156
- export function hasDiag(diags: Diagnostic[], predicate: (d: Diagnostic) => boolean): boolean {
157
- return diags.some(predicate);
158
- }
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright (c) 2026 ForestHub.
3
+
4
+ import type { Edge } from "../../edge";
5
+ import type { NodeDefinition, NodeData } from "../../node";
6
+ import type { DataType, Expression, Reference } from "../../api";
7
+ import type { Channel } from "../../channel";
8
+ import type { Memory } from "../../memory";
9
+ import { NodeCategory } from "../../node";
10
+ import type { Variable, DeclaredVariable, NodeOutputVariable } from "../../variable";
11
+ import type { Diagnostic, DiagnosticCategory } from "../diagnostics";
12
+
13
+ // ============================================================================
14
+ // Variable builders
15
+ // ============================================================================
16
+
17
+ export function makeDeclaredVar(overrides: Partial<DeclaredVariable> = {}): Variable {
18
+ return {
19
+ kind: "declared",
20
+ uid: "v1",
21
+ name: "count",
22
+ dataType: "int" as DataType,
23
+ ...overrides,
24
+ };
25
+ }
26
+
27
+ export function makeNodeOutputVar(overrides: Partial<NodeOutputVariable> = {}): Variable {
28
+ return {
29
+ kind: "node",
30
+ nodeId: "n1",
31
+ outputId: "output",
32
+ name: "result",
33
+ dataType: "int" as DataType,
34
+ ...overrides,
35
+ };
36
+ }
37
+
38
+ /** Build an `availableVariables` map from a list of `AvailableVariable` entries. */
39
+ export function makeAvailableVars(vars: Variable[]): Record<string, Variable> {
40
+ const map: Record<string, Variable> = {};
41
+ for (const v of vars) {
42
+ const key = v.kind === "declared" ? `declared:${v.uid}` : v.kind === "fnarg" ? `fnarg:${v.uid}` : `${v.nodeId}:${v.outputId}`;
43
+ map[key] = v;
44
+ }
45
+ return map;
46
+ }
47
+
48
+ // ============================================================================
49
+ // Expression / Reference builders
50
+ // ============================================================================
51
+
52
+ export function makeExpression(expression: string, dataType: DataType = "int", references: Reference[] = []): Expression {
53
+ return { expression, references, dataType };
54
+ }
55
+
56
+ export function makeDeclaredRef(uid: string): Reference {
57
+ return { srcId: "declared", varId: uid };
58
+ }
59
+
60
+ // ============================================================================
61
+ // Edge builder
62
+ // ============================================================================
63
+
64
+ export function makeEdge(
65
+ id: string,
66
+ source: string,
67
+ sourceHandle: string,
68
+ target: string,
69
+ targetHandle: string,
70
+ overrides: Partial<Edge> = {},
71
+ ): Edge {
72
+ return {
73
+ id,
74
+ source,
75
+ sourceHandle,
76
+ target,
77
+ targetHandle,
78
+ type: "control",
79
+ ...overrides,
80
+ };
81
+ }
82
+
83
+ // ============================================================================
84
+ // Channel builders
85
+ // ============================================================================
86
+
87
+ export function makeChannel(overrides: Partial<Channel> = {}): Channel {
88
+ return {
89
+ id: "ch1",
90
+ label: "GPIO 4",
91
+ type: "GPIOIN",
92
+ arguments: {},
93
+ ...overrides,
94
+ };
95
+ }
96
+
97
+ export function makeChannels(channels: Channel[]): Record<string, Channel> {
98
+ const map: Record<string, Channel> = {};
99
+ for (const v of channels) map[v.id] = v;
100
+ return map;
101
+ }
102
+
103
+ // ============================================================================
104
+ // Memory builders
105
+ // ============================================================================
106
+
107
+ export function makeMemory(overrides: Partial<Memory> = {}): Memory {
108
+ return {
109
+ id: "mem1",
110
+ label: "memory1",
111
+ type: "MemoryFile",
112
+ arguments: {},
113
+ ...overrides,
114
+ };
115
+ }
116
+
117
+ export function makeMemories(memories: Memory[]): Record<string, Memory> {
118
+ const map: Record<string, Memory> = {};
119
+ for (const m of memories) map[m.id] = m;
120
+ return map;
121
+ }
122
+
123
+ // ============================================================================
124
+ // Node instance builder — untyped escape hatch
125
+ // ============================================================================
126
+
127
+ /**
128
+ * Build a minimal NodeData. Tests assert against the shape `computeNodeDiagnostics`
129
+ * sees (arguments record + type discriminator), not against the strict per-type shapes,
130
+ * so we widen to `NodeData` via unknown at the boundary.
131
+ */
132
+ export function makeNode(type: string, args: Record<string, unknown>, overrides: Record<string, unknown> = {}): NodeData {
133
+ return { id: "n1", type, arguments: args, ...overrides } as unknown as NodeData;
134
+ }
135
+
136
+ // ============================================================================
137
+ // Synthetic NodeDefinition builder
138
+ // ============================================================================
139
+
140
+ export function makeNodeDef(overrides: Partial<NodeDefinition> = {}): NodeDefinition {
141
+ return {
142
+ type: "Synthetic" as NodeDefinition["type"],
143
+ label: "Synthetic Node",
144
+ category: NodeCategory.Input,
145
+ description: "Synthetic node used only in tests",
146
+ parameters: [],
147
+ ...overrides,
148
+ };
149
+ }
150
+
151
+ // ============================================================================
152
+ // Diagnostic assertion helpers
153
+ // ============================================================================
154
+
155
+ export function diagsOfCategory(diags: Diagnostic[], category: DiagnosticCategory): Diagnostic[] {
156
+ return diags.filter((d) => d.category === category);
157
+ }
158
+
159
+ export function hasDiag(diags: Diagnostic[], predicate: (d: Diagnostic) => boolean): boolean {
160
+ return diags.some(predicate);
161
+ }