@bian-womp/spark-graph 0.3.31 → 0.3.32
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.
- package/lib/cjs/index.cjs +194 -95
- package/lib/cjs/index.cjs.map +1 -1
- package/lib/cjs/src/builder/GraphBuilder.d.ts +0 -1
- package/lib/cjs/src/builder/GraphBuilder.d.ts.map +1 -1
- package/lib/cjs/src/builder/Registry.d.ts +6 -0
- package/lib/cjs/src/builder/Registry.d.ts.map +1 -1
- package/lib/cjs/src/core/type-utils.d.ts +11 -0
- package/lib/cjs/src/core/type-utils.d.ts.map +1 -1
- package/lib/cjs/src/index.d.ts +1 -1
- package/lib/cjs/src/index.d.ts.map +1 -1
- package/lib/cjs/src/misc/utils/merge.d.ts.map +1 -1
- package/lib/cjs/src/runtime/components/Graph.d.ts +1 -2
- package/lib/cjs/src/runtime/components/Graph.d.ts.map +1 -1
- package/lib/cjs/src/runtime/components/HandleResolver.d.ts.map +1 -1
- package/lib/cjs/src/runtime/components/graph-utils.d.ts +4 -4
- package/lib/cjs/src/runtime/components/graph-utils.d.ts.map +1 -1
- package/lib/cjs/src/runtime/components/types.d.ts +1 -2
- package/lib/cjs/src/runtime/components/types.d.ts.map +1 -1
- package/lib/esm/index.js +194 -96
- package/lib/esm/index.js.map +1 -1
- package/lib/esm/src/builder/GraphBuilder.d.ts +0 -1
- package/lib/esm/src/builder/GraphBuilder.d.ts.map +1 -1
- package/lib/esm/src/builder/Registry.d.ts +6 -0
- package/lib/esm/src/builder/Registry.d.ts.map +1 -1
- package/lib/esm/src/core/type-utils.d.ts +11 -0
- package/lib/esm/src/core/type-utils.d.ts.map +1 -1
- package/lib/esm/src/index.d.ts +1 -1
- package/lib/esm/src/index.d.ts.map +1 -1
- package/lib/esm/src/misc/utils/merge.d.ts.map +1 -1
- package/lib/esm/src/runtime/components/Graph.d.ts +1 -2
- package/lib/esm/src/runtime/components/Graph.d.ts.map +1 -1
- package/lib/esm/src/runtime/components/HandleResolver.d.ts.map +1 -1
- package/lib/esm/src/runtime/components/graph-utils.d.ts +4 -4
- package/lib/esm/src/runtime/components/graph-utils.d.ts.map +1 -1
- package/lib/esm/src/runtime/components/types.d.ts +1 -2
- package/lib/esm/src/runtime/components/types.d.ts.map +1 -1
- package/package.json +2 -2
package/lib/esm/index.js
CHANGED
|
@@ -16,19 +16,42 @@ function getTypedOutputValue(v) {
|
|
|
16
16
|
return v.__spark_value;
|
|
17
17
|
return v;
|
|
18
18
|
}
|
|
19
|
-
|
|
19
|
+
/**
|
|
20
|
+
* Get the full declared type(s) for an input handle (supports union types)
|
|
21
|
+
* Returns the typeId as-is: string for single type, string[] for union types
|
|
22
|
+
*/
|
|
23
|
+
function getInputDeclaredTypes(inputs, handle) {
|
|
20
24
|
const v = inputs ? inputs[handle] : undefined;
|
|
21
25
|
if (!v)
|
|
22
26
|
return undefined;
|
|
23
|
-
|
|
27
|
+
if (typeof v === "string")
|
|
28
|
+
return v;
|
|
29
|
+
if (Array.isArray(v))
|
|
30
|
+
return v;
|
|
31
|
+
return v.typeId;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Get the primary (first) type ID for an input handle.
|
|
35
|
+
* For union types, returns the first type in the array.
|
|
36
|
+
* This maintains backward compatibility for code that expects a single type.
|
|
37
|
+
*/
|
|
38
|
+
function getInputTypeId(inputs, handle) {
|
|
39
|
+
const decl = getInputDeclaredTypes(inputs, handle);
|
|
40
|
+
if (!decl)
|
|
41
|
+
return undefined;
|
|
42
|
+
return Array.isArray(decl) ? decl[0] : decl;
|
|
24
43
|
}
|
|
25
44
|
function isInputPrivate(inputs, handle) {
|
|
26
45
|
const v = inputs ? inputs[handle] : undefined;
|
|
27
|
-
|
|
46
|
+
if (!v || typeof v === "string" || Array.isArray(v))
|
|
47
|
+
return false;
|
|
48
|
+
// At this point, v must be an object with optional private/metadata fields
|
|
49
|
+
return !!(typeof v === "object" && v !== null && "private" in v && v.private);
|
|
28
50
|
}
|
|
29
51
|
/**
|
|
30
52
|
* Merge two InputHandleDescriptor values, with dynamic taking precedence.
|
|
31
53
|
* If both have metadata, merge the metadata objects (dynamic overrides static).
|
|
54
|
+
* Supports union types (arrays) in both static and dynamic descriptors.
|
|
32
55
|
*/
|
|
33
56
|
function mergeInputHandleDescriptors(staticDesc, dynamicDesc) {
|
|
34
57
|
// If only one exists, return it
|
|
@@ -36,12 +59,17 @@ function mergeInputHandleDescriptors(staticDesc, dynamicDesc) {
|
|
|
36
59
|
return dynamicDesc;
|
|
37
60
|
if (!dynamicDesc)
|
|
38
61
|
return staticDesc;
|
|
39
|
-
// If both are
|
|
40
|
-
if (typeof staticDesc === "string"
|
|
62
|
+
// If both are primitive (string or array), dynamic wins
|
|
63
|
+
if ((typeof staticDesc === "string" || Array.isArray(staticDesc)) &&
|
|
64
|
+
(typeof dynamicDesc === "string" || Array.isArray(dynamicDesc))) {
|
|
41
65
|
return dynamicDesc;
|
|
42
66
|
}
|
|
43
|
-
const staticObj = typeof staticDesc === "string"
|
|
44
|
-
|
|
67
|
+
const staticObj = typeof staticDesc === "string" || Array.isArray(staticDesc)
|
|
68
|
+
? { typeId: staticDesc }
|
|
69
|
+
: staticDesc;
|
|
70
|
+
const dynamicObj = typeof dynamicDesc === "string" || Array.isArray(dynamicDesc)
|
|
71
|
+
? { typeId: dynamicDesc }
|
|
72
|
+
: dynamicDesc;
|
|
45
73
|
// Merge: dynamic takes precedence, but merge metadata objects
|
|
46
74
|
const merged = {
|
|
47
75
|
typeId: dynamicObj.typeId ?? staticObj.typeId,
|
|
@@ -62,7 +90,7 @@ function mergeInputHandleDescriptors(staticDesc, dynamicDesc) {
|
|
|
62
90
|
*/
|
|
63
91
|
function getInputHandleMetadata(inputs, handle) {
|
|
64
92
|
const v = inputs ? inputs[handle] : undefined;
|
|
65
|
-
if (!v || typeof v === "string")
|
|
93
|
+
if (!v || typeof v === "string" || Array.isArray(v))
|
|
66
94
|
return undefined;
|
|
67
95
|
return v.metadata;
|
|
68
96
|
}
|
|
@@ -257,7 +285,11 @@ class Registry {
|
|
|
257
285
|
if (cached)
|
|
258
286
|
return cached;
|
|
259
287
|
if (fromTypeId === toTypeId) {
|
|
260
|
-
const res = {
|
|
288
|
+
const res = {
|
|
289
|
+
kind: "sync",
|
|
290
|
+
convert: (v) => v,
|
|
291
|
+
cost: { edges: 0, async: 0 },
|
|
292
|
+
};
|
|
261
293
|
this.resolvedCache.set(cacheKey, res);
|
|
262
294
|
return res;
|
|
263
295
|
}
|
|
@@ -267,6 +299,7 @@ class Registry {
|
|
|
267
299
|
const res = {
|
|
268
300
|
kind: "sync",
|
|
269
301
|
convert: directSync.convert,
|
|
302
|
+
cost: { edges: 1, async: 0 },
|
|
270
303
|
};
|
|
271
304
|
this.resolvedCache.set(cacheKey, res);
|
|
272
305
|
return res;
|
|
@@ -276,6 +309,7 @@ class Registry {
|
|
|
276
309
|
const res = {
|
|
277
310
|
kind: "async",
|
|
278
311
|
convertAsync: directAsync.convertAsync,
|
|
312
|
+
cost: { edges: 1, async: 1 },
|
|
279
313
|
};
|
|
280
314
|
this.resolvedCache.set(cacheKey, res);
|
|
281
315
|
return res;
|
|
@@ -332,6 +366,10 @@ class Registry {
|
|
|
332
366
|
const cur = queue.shift();
|
|
333
367
|
if (cur.node === toTypeId) {
|
|
334
368
|
// Compose
|
|
369
|
+
const cost = {
|
|
370
|
+
edges: cur.cost.edges,
|
|
371
|
+
async: cur.cost.async,
|
|
372
|
+
};
|
|
335
373
|
const hasAsync = cur.path.some((s) => s.kind === "async");
|
|
336
374
|
if (!hasAsync) {
|
|
337
375
|
const convert = (value) => {
|
|
@@ -342,7 +380,11 @@ class Registry {
|
|
|
342
380
|
}
|
|
343
381
|
return acc;
|
|
344
382
|
};
|
|
345
|
-
const res = {
|
|
383
|
+
const res = {
|
|
384
|
+
kind: "sync",
|
|
385
|
+
convert,
|
|
386
|
+
cost,
|
|
387
|
+
};
|
|
346
388
|
this.resolvedCache.set(cacheKey, res);
|
|
347
389
|
return res;
|
|
348
390
|
}
|
|
@@ -359,7 +401,11 @@ class Registry {
|
|
|
359
401
|
}
|
|
360
402
|
return acc;
|
|
361
403
|
};
|
|
362
|
-
const res = {
|
|
404
|
+
const res = {
|
|
405
|
+
kind: "async",
|
|
406
|
+
convertAsync,
|
|
407
|
+
cost,
|
|
408
|
+
};
|
|
363
409
|
this.resolvedCache.set(cacheKey, res);
|
|
364
410
|
return res;
|
|
365
411
|
}
|
|
@@ -816,9 +862,6 @@ class Graph {
|
|
|
816
862
|
const edge = this.edges.find((e) => e.id === edgeId);
|
|
817
863
|
if (!edge)
|
|
818
864
|
return;
|
|
819
|
-
if (updates.effectiveTypeId !== undefined) {
|
|
820
|
-
edge.effectiveTypeId = updates.effectiveTypeId;
|
|
821
|
-
}
|
|
822
865
|
if (updates.dstDeclared !== undefined) {
|
|
823
866
|
edge.dstDeclared = updates.dstDeclared;
|
|
824
867
|
}
|
|
@@ -1412,14 +1455,13 @@ function buildEdges(def, registry, resolvedByNode) {
|
|
|
1412
1455
|
return def.edges.map((e) => {
|
|
1413
1456
|
const srcNode = def.nodes.find((n) => n.nodeId === e.source.nodeId);
|
|
1414
1457
|
const dstNode = def.nodes.find((n) => n.nodeId === e.target.nodeId);
|
|
1415
|
-
const { srcDeclared, dstDeclared
|
|
1458
|
+
const { srcDeclared, dstDeclared } = extractEdgeTypes(e.source.nodeId, e.source.handle, e.target.nodeId, e.target.handle, resolvedByNode);
|
|
1416
1459
|
const { convert, convertAsync } = buildEdgeConverters(srcDeclared, dstDeclared, registry, `buildEdges: ${srcNode?.typeId || ""}.${e.source.nodeId}.${e.source.handle} -> ${dstNode?.typeId || ""}.${e.target.nodeId}.${e.target.handle}`);
|
|
1417
1460
|
return {
|
|
1418
1461
|
id: e.id,
|
|
1419
1462
|
source: { ...e.source },
|
|
1420
1463
|
target: { ...e.target },
|
|
1421
1464
|
typeId: e.typeId, // Preserve original (may be undefined)
|
|
1422
|
-
effectiveTypeId, // Always present
|
|
1423
1465
|
convert,
|
|
1424
1466
|
convertAsync,
|
|
1425
1467
|
srcUnionTypes: Array.isArray(srcDeclared) ? [...srcDeclared] : undefined,
|
|
@@ -1431,37 +1473,79 @@ function buildEdges(def, registry, resolvedByNode) {
|
|
|
1431
1473
|
/**
|
|
1432
1474
|
* Extract edge type information from resolved handles
|
|
1433
1475
|
* Used by both buildEdges and updateNodeHandles to avoid duplication
|
|
1476
|
+
* Now supports union types on both source (output) and destination (input) handles
|
|
1434
1477
|
*/
|
|
1435
|
-
function extractEdgeTypes(sourceNodeId, sourceHandle, targetNodeId, targetHandle, resolvedByNode
|
|
1478
|
+
function extractEdgeTypes(sourceNodeId, sourceHandle, targetNodeId, targetHandle, resolvedByNode) {
|
|
1436
1479
|
const srcResolved = resolvedByNode.get(sourceNodeId);
|
|
1437
1480
|
const dstResolved = resolvedByNode.get(targetNodeId);
|
|
1438
1481
|
const srcDeclared = srcResolved
|
|
1439
1482
|
? srcResolved.outputs[sourceHandle]
|
|
1440
1483
|
: undefined;
|
|
1441
1484
|
const dstDeclared = dstResolved
|
|
1442
|
-
?
|
|
1485
|
+
? getInputDeclaredTypes(dstResolved.inputs, targetHandle)
|
|
1443
1486
|
: undefined;
|
|
1444
|
-
let effectiveTypeId = explicitTypeId;
|
|
1445
|
-
if (!effectiveTypeId) {
|
|
1446
|
-
// Infer if not explicitly set
|
|
1447
|
-
effectiveTypeId = Array.isArray(srcDeclared) ? srcDeclared[0] : srcDeclared;
|
|
1448
|
-
}
|
|
1449
1487
|
return {
|
|
1450
1488
|
srcDeclared,
|
|
1451
1489
|
dstDeclared,
|
|
1452
|
-
effectiveTypeId: effectiveTypeId ?? "untyped",
|
|
1453
1490
|
};
|
|
1454
1491
|
}
|
|
1455
1492
|
// Static helper: build edge converters for type coercion
|
|
1493
|
+
// Now supports union types on both source (output) and destination (input) handles
|
|
1456
1494
|
function buildEdgeConverters(srcDeclared, dstDeclared, registry, edgeLabel) {
|
|
1457
1495
|
if (!dstDeclared || !srcDeclared) {
|
|
1458
1496
|
return {};
|
|
1459
1497
|
}
|
|
1460
|
-
const
|
|
1461
|
-
const srcTypes =
|
|
1462
|
-
|
|
1463
|
-
const
|
|
1464
|
-
|
|
1498
|
+
const isSrcUnion = Array.isArray(srcDeclared);
|
|
1499
|
+
const srcTypes = isSrcUnion ? srcDeclared : [srcDeclared];
|
|
1500
|
+
const isDstUnion = Array.isArray(dstDeclared);
|
|
1501
|
+
const dstTypes = isDstUnion ? dstDeclared : [dstDeclared];
|
|
1502
|
+
// Helper to compare coercion costs (sync preferred, then fewer steps)
|
|
1503
|
+
const compareCost = (a, b) => {
|
|
1504
|
+
// Prefer sync over async
|
|
1505
|
+
if (a.kind === "sync" && b.kind === "async")
|
|
1506
|
+
return -1;
|
|
1507
|
+
if (a.kind === "async" && b.kind === "sync")
|
|
1508
|
+
return 1;
|
|
1509
|
+
// If same kind, prefer fewer edges
|
|
1510
|
+
if (a.cost.edges !== b.cost.edges)
|
|
1511
|
+
return a.cost.edges - b.cost.edges;
|
|
1512
|
+
// If same edges, prefer fewer async steps
|
|
1513
|
+
return a.cost.async - b.cost.async;
|
|
1514
|
+
};
|
|
1515
|
+
// Helper to find the best coercion from a source type to any destination type
|
|
1516
|
+
const getCoercion = (srcTypeId) => {
|
|
1517
|
+
const candidates = [];
|
|
1518
|
+
// Try all destination types and collect valid coercions
|
|
1519
|
+
for (const dstTypeId of dstTypes) {
|
|
1520
|
+
const coercion = registry.resolveCoercion(srcTypeId, dstTypeId);
|
|
1521
|
+
if (coercion) {
|
|
1522
|
+
candidates.push({
|
|
1523
|
+
dstType: dstTypeId,
|
|
1524
|
+
coercion,
|
|
1525
|
+
});
|
|
1526
|
+
}
|
|
1527
|
+
}
|
|
1528
|
+
if (candidates.length === 0)
|
|
1529
|
+
return null;
|
|
1530
|
+
// Select best by cost: sync preferred, then fewer edges, then fewer async steps
|
|
1531
|
+
const best = candidates.reduce((best, cur) => {
|
|
1532
|
+
return compareCost(cur.coercion, best.coercion) < 0 ? cur : best;
|
|
1533
|
+
});
|
|
1534
|
+
if (best.coercion.kind === "sync") {
|
|
1535
|
+
return {
|
|
1536
|
+
kind: "sync",
|
|
1537
|
+
convert: best.coercion.convert,
|
|
1538
|
+
dstType: best.dstType,
|
|
1539
|
+
};
|
|
1540
|
+
}
|
|
1541
|
+
else {
|
|
1542
|
+
return {
|
|
1543
|
+
kind: "async",
|
|
1544
|
+
convert: (v) => v, // placeholder, not used for async
|
|
1545
|
+
convertAsync: best.coercion.convertAsync,
|
|
1546
|
+
dstType: best.dstType,
|
|
1547
|
+
};
|
|
1548
|
+
}
|
|
1465
1549
|
};
|
|
1466
1550
|
// Resolve coercions for all source types
|
|
1467
1551
|
const coercions = srcTypes.map(getCoercion);
|
|
@@ -1470,7 +1554,7 @@ function buildEdgeConverters(srcDeclared, dstDeclared, registry, edgeLabel) {
|
|
|
1470
1554
|
const extractPayload = (v) => {
|
|
1471
1555
|
const typeId = getTypedOutputTypeId(v);
|
|
1472
1556
|
const payload = getTypedOutputValue(v);
|
|
1473
|
-
if (
|
|
1557
|
+
if (isSrcUnion) {
|
|
1474
1558
|
if (!typeId) {
|
|
1475
1559
|
throw new Error(`Typed output required for union source (${edgeLabel}); allowed: ${srcTypes.join("|")}`);
|
|
1476
1560
|
}
|
|
@@ -1484,17 +1568,27 @@ function buildEdgeConverters(srcDeclared, dstDeclared, registry, edgeLabel) {
|
|
|
1484
1568
|
}
|
|
1485
1569
|
return { typeId: typeId || srcTypes[0], payload };
|
|
1486
1570
|
};
|
|
1571
|
+
const wrapIfDstUnion = (dstType, val) => {
|
|
1572
|
+
if (!isDstUnion || !dstType)
|
|
1573
|
+
return val;
|
|
1574
|
+
return typed(dstType, val);
|
|
1575
|
+
};
|
|
1487
1576
|
if (hasAsync) {
|
|
1488
1577
|
return {
|
|
1489
1578
|
convertAsync: async (v, signal) => {
|
|
1490
1579
|
const { typeId, payload } = extractPayload(v);
|
|
1491
1580
|
const res = getCoercion(typeId);
|
|
1492
|
-
if (!res)
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1581
|
+
if (!res) {
|
|
1582
|
+
const fallbackType = isDstUnion && typeId && dstTypes.includes(typeId)
|
|
1583
|
+
? typeId
|
|
1584
|
+
: undefined;
|
|
1585
|
+
return wrapIfDstUnion(fallbackType, payload);
|
|
1496
1586
|
}
|
|
1497
|
-
|
|
1587
|
+
if (res.kind === "async" && res.convertAsync) {
|
|
1588
|
+
const converted = await res.convertAsync(payload, signal);
|
|
1589
|
+
return wrapIfDstUnion(res.dstType, converted);
|
|
1590
|
+
}
|
|
1591
|
+
return wrapIfDstUnion(res.dstType, res.convert(payload));
|
|
1498
1592
|
},
|
|
1499
1593
|
};
|
|
1500
1594
|
}
|
|
@@ -1507,12 +1601,17 @@ function buildEdgeConverters(srcDeclared, dstDeclared, registry, edgeLabel) {
|
|
|
1507
1601
|
convert: (v) => {
|
|
1508
1602
|
const { typeId, payload } = extractPayload(v);
|
|
1509
1603
|
const res = getCoercion(typeId);
|
|
1510
|
-
if (!res)
|
|
1511
|
-
|
|
1604
|
+
if (!res) {
|
|
1605
|
+
const fallbackType = isDstUnion && typeId && dstTypes.includes(typeId)
|
|
1606
|
+
? typeId
|
|
1607
|
+
: undefined;
|
|
1608
|
+
return wrapIfDstUnion(fallbackType, payload);
|
|
1609
|
+
}
|
|
1512
1610
|
if (res.kind === "async") {
|
|
1513
1611
|
throw new Error(`Async coercion required but convert used (${edgeLabel})`);
|
|
1514
1612
|
}
|
|
1515
|
-
|
|
1613
|
+
const converted = res.convert(payload);
|
|
1614
|
+
return wrapIfDstUnion(res.dstType, converted);
|
|
1516
1615
|
},
|
|
1517
1616
|
};
|
|
1518
1617
|
}
|
|
@@ -1615,12 +1714,11 @@ class HandleResolver {
|
|
|
1615
1714
|
const dstNode = this.graph.getNode(e.target.nodeId);
|
|
1616
1715
|
const oldDstDeclared = e.dstDeclared;
|
|
1617
1716
|
// Extract edge types using shared helper (handles both source and target updates)
|
|
1618
|
-
const { srcDeclared, dstDeclared
|
|
1717
|
+
const { srcDeclared, dstDeclared } = extractEdgeTypes(e.source.nodeId, e.source.handle, e.target.nodeId, e.target.handle, resolvedByNode);
|
|
1619
1718
|
// Update converters
|
|
1620
1719
|
const conv = buildEdgeConverters(srcDeclared, dstDeclared, registry, `updateNodeHandles: ${srcNode?.typeId || ""}.${e.source.nodeId}.${e.source.handle} -> ${dstNode?.typeId || ""}.${e.target.nodeId}.${e.target.handle}`);
|
|
1621
1720
|
// Update edge properties via Graph
|
|
1622
1721
|
this.graph.updateEdgeProperties(e.id, {
|
|
1623
|
-
effectiveTypeId: !e.typeId ? effectiveTypeId : undefined,
|
|
1624
1722
|
dstDeclared,
|
|
1625
1723
|
srcUnionTypes: Array.isArray(srcDeclared)
|
|
1626
1724
|
? [...srcDeclared]
|
|
@@ -3466,20 +3564,12 @@ class GraphBuilder {
|
|
|
3466
3564
|
return { inputs, outputs };
|
|
3467
3565
|
};
|
|
3468
3566
|
const normOut = (decl) => Array.isArray(decl) ? decl : decl ? [decl] : [];
|
|
3469
|
-
const inferEdgeType = (srcDeclared, dstDeclared, explicit) => {
|
|
3470
|
-
if (explicit)
|
|
3471
|
-
return explicit;
|
|
3472
|
-
if (Array.isArray(srcDeclared) && dstDeclared)
|
|
3473
|
-
return dstDeclared;
|
|
3474
|
-
if (srcDeclared)
|
|
3475
|
-
return Array.isArray(srcDeclared) ? srcDeclared[0] : srcDeclared;
|
|
3476
|
-
return undefined;
|
|
3477
|
-
};
|
|
3478
3567
|
const canFlow = (from, to) => {
|
|
3479
3568
|
if (!to || !from)
|
|
3480
3569
|
return true;
|
|
3481
|
-
const
|
|
3482
|
-
|
|
3570
|
+
const srcTypes = Array.isArray(from) ? from : [from];
|
|
3571
|
+
const dstTypes = Array.isArray(to) ? to : [to];
|
|
3572
|
+
return srcTypes.some((s) => dstTypes.some((t) => s === t || !!this.registry.canCoerce(s, t)));
|
|
3483
3573
|
};
|
|
3484
3574
|
// Helper to validate enum value
|
|
3485
3575
|
const validateEnumValue = (typeId, value, nodeId, handle) => {
|
|
@@ -3590,37 +3680,29 @@ class GraphBuilder {
|
|
|
3590
3680
|
};
|
|
3591
3681
|
const dstEff = effByNodeId.get(e.target.nodeId) || {
|
|
3592
3682
|
inputs: {}};
|
|
3593
|
-
|
|
3594
|
-
|
|
3595
|
-
|
|
3596
|
-
|
|
3597
|
-
|
|
3598
|
-
|
|
3599
|
-
// Effective edge type
|
|
3600
|
-
const effectiveTypeId = inferEdgeType(_srcDeclared, _dstDeclared, e.typeId);
|
|
3601
|
-
const type = effectiveTypeId
|
|
3602
|
-
? this.registry.types.get(effectiveTypeId)
|
|
3603
|
-
: undefined;
|
|
3604
|
-
if (!type) {
|
|
3605
|
-
pushIssue("error", "TYPE_MISSING", `Edge ${e.id} type missing or unknown`, {
|
|
3606
|
-
edgeId: e.id,
|
|
3607
|
-
});
|
|
3683
|
+
// Validate explicit type if provided
|
|
3684
|
+
if (e.typeId) {
|
|
3685
|
+
const type = this.registry.types.get(e.typeId);
|
|
3686
|
+
if (!type) {
|
|
3687
|
+
pushIssue("error", "TYPE_MISSING", `Edge ${e.id} explicit type ${e.typeId} is missing or unknown`, { edgeId: e.id });
|
|
3688
|
+
}
|
|
3608
3689
|
}
|
|
3609
3690
|
if (srcNode) {
|
|
3610
3691
|
if (!(e.source.handle in srcEff.outputs)) {
|
|
3611
3692
|
pushIssue("error", "OUTPUT_MISSING", `Edge ${e.id} source output ${e.source.handle} missing on ${srcNode.typeId}`, { edgeId: e.id, nodeId: srcNode.nodeId, output: e.source.handle });
|
|
3612
3693
|
}
|
|
3613
3694
|
const declaredArr = normOut(srcEff.outputs[e.source.handle]);
|
|
3614
|
-
if (declaredArr.length > 0
|
|
3615
|
-
|
|
3616
|
-
!canFlow(declaredArr,
|
|
3617
|
-
|
|
3618
|
-
|
|
3619
|
-
|
|
3620
|
-
|
|
3621
|
-
|
|
3622
|
-
|
|
3623
|
-
|
|
3695
|
+
if (declaredArr.length > 0) {
|
|
3696
|
+
// Check if explicit type matches source output
|
|
3697
|
+
if (e.typeId && !canFlow(declaredArr, e.typeId)) {
|
|
3698
|
+
pushIssue("error", "TYPE_MISMATCH_OUTPUT", `Edge ${e.id} explicit type ${e.typeId} mismatches source output ${srcNode.typeId}.${e.source.handle} (${declaredArr.join("|")}) and no coercion exists`, {
|
|
3699
|
+
edgeId: e.id,
|
|
3700
|
+
nodeId: srcNode.nodeId,
|
|
3701
|
+
output: e.source.handle,
|
|
3702
|
+
declared: declaredArr.join("|"),
|
|
3703
|
+
typeId: e.typeId,
|
|
3704
|
+
});
|
|
3705
|
+
}
|
|
3624
3706
|
}
|
|
3625
3707
|
}
|
|
3626
3708
|
if (dstNode) {
|
|
@@ -3631,30 +3713,30 @@ class GraphBuilder {
|
|
|
3631
3713
|
if (isInputPrivate(dstEff.inputs, e.target.handle)) {
|
|
3632
3714
|
pushIssue("error", "INPUT_PRIVATE", `Edge ${e.id} targets private input ${dstNode.typeId}.${e.target.handle}`, { edgeId: e.id, nodeId: dstNode.nodeId, input: e.target.handle });
|
|
3633
3715
|
}
|
|
3634
|
-
const declaredIn =
|
|
3635
|
-
|
|
3716
|
+
const declaredIn = getInputDeclaredTypes(dstEff.inputs, e.target.handle);
|
|
3717
|
+
const declaredInArr = normOut(declaredIn);
|
|
3718
|
+
if (declaredInArr.length > 0) {
|
|
3636
3719
|
if (srcNode) {
|
|
3637
3720
|
const srcDeclared = srcEff.outputs[e.source.handle];
|
|
3638
|
-
const srcArr = normOut(srcDeclared)
|
|
3639
|
-
|
|
3640
|
-
|
|
3641
|
-
if (!canFlow(srcArr, declaredIn)) {
|
|
3642
|
-
pushIssue("error", "TYPE_MISMATCH_INPUT", `Edge ${e.id} output type ${srcArr.join("|")} not convertible to target input ${dstNode.typeId}.${e.target.handle} (${declaredIn})`, {
|
|
3721
|
+
const srcArr = normOut(srcDeclared);
|
|
3722
|
+
if (srcArr.length > 0 && !canFlow(srcArr, declaredInArr)) {
|
|
3723
|
+
pushIssue("error", "TYPE_MISMATCH_INPUT", `Edge ${e.id} output type ${srcArr.join("|")} not convertible to target input ${dstNode.typeId}.${e.target.handle} (${declaredInArr.join("|")})`, {
|
|
3643
3724
|
edgeId: e.id,
|
|
3644
3725
|
nodeId: dstNode.nodeId,
|
|
3645
3726
|
input: e.target.handle,
|
|
3646
|
-
declared:
|
|
3647
|
-
|
|
3727
|
+
declared: declaredInArr.join("|"),
|
|
3728
|
+
typeId: srcArr.join("|"),
|
|
3648
3729
|
});
|
|
3649
3730
|
}
|
|
3650
3731
|
}
|
|
3651
|
-
else if (!canFlow(
|
|
3652
|
-
|
|
3732
|
+
else if (e.typeId && !canFlow([e.typeId], declaredInArr)) {
|
|
3733
|
+
// External source with explicit type
|
|
3734
|
+
pushIssue("error", "TYPE_MISMATCH_INPUT", `Edge ${e.id} explicit type ${e.typeId} mismatches target input ${dstNode.typeId}.${e.target.handle} (${declaredInArr.join("|")}) and no coercion exists`, {
|
|
3653
3735
|
edgeId: e.id,
|
|
3654
3736
|
nodeId: dstNode.nodeId,
|
|
3655
3737
|
input: e.target.handle,
|
|
3656
|
-
declared:
|
|
3657
|
-
|
|
3738
|
+
declared: declaredInArr.join("|"),
|
|
3739
|
+
typeId: e.typeId,
|
|
3658
3740
|
});
|
|
3659
3741
|
}
|
|
3660
3742
|
}
|
|
@@ -5590,9 +5672,17 @@ function buildTypeMaps(def) {
|
|
|
5590
5672
|
const nodeOutputTypes = new Map();
|
|
5591
5673
|
if (node.resolvedHandles?.inputs) {
|
|
5592
5674
|
for (const [handleId, handleDesc] of Object.entries(node.resolvedHandles.inputs)) {
|
|
5593
|
-
|
|
5594
|
-
|
|
5595
|
-
|
|
5675
|
+
let typeId;
|
|
5676
|
+
if (typeof handleDesc === "string") {
|
|
5677
|
+
typeId = handleDesc;
|
|
5678
|
+
}
|
|
5679
|
+
else if (Array.isArray(handleDesc)) {
|
|
5680
|
+
typeId = handleDesc[0]; // Use first type for type map (backward compat)
|
|
5681
|
+
}
|
|
5682
|
+
else {
|
|
5683
|
+
const descTypeId = handleDesc.typeId;
|
|
5684
|
+
typeId = Array.isArray(descTypeId) ? descTypeId[0] : descTypeId;
|
|
5685
|
+
}
|
|
5596
5686
|
if (typeId)
|
|
5597
5687
|
nodeInputTypes.set(handleId, typeId);
|
|
5598
5688
|
}
|
|
@@ -5615,9 +5705,17 @@ function buildTypeMaps(def) {
|
|
|
5615
5705
|
if (!nodeInputTypes.has(handleId) && node.resolvedHandles?.inputs) {
|
|
5616
5706
|
const inputDesc = node.resolvedHandles.inputs[handleId];
|
|
5617
5707
|
if (inputDesc) {
|
|
5618
|
-
|
|
5619
|
-
|
|
5620
|
-
|
|
5708
|
+
let typeId;
|
|
5709
|
+
if (typeof inputDesc === "string") {
|
|
5710
|
+
typeId = inputDesc;
|
|
5711
|
+
}
|
|
5712
|
+
else if (Array.isArray(inputDesc)) {
|
|
5713
|
+
typeId = inputDesc[0]; // Use first type for type map (backward compat)
|
|
5714
|
+
}
|
|
5715
|
+
else {
|
|
5716
|
+
const descTypeId = inputDesc.typeId;
|
|
5717
|
+
typeId = Array.isArray(descTypeId) ? descTypeId[0] : descTypeId;
|
|
5718
|
+
}
|
|
5621
5719
|
if (typeId)
|
|
5622
5720
|
nodeInputTypes.set(handleId, typeId);
|
|
5623
5721
|
}
|
|
@@ -6053,5 +6151,5 @@ function buildValueConverter(config) {
|
|
|
6053
6151
|
};
|
|
6054
6152
|
}
|
|
6055
6153
|
|
|
6056
|
-
export { BaseCompareOperation, BaseLogicOperation, BaseMathOperation, CompositeCategory, ComputeCategory, GraphBuilder, GraphRuntime, LevelLogger, LocalEngine, Registry, buildValueConverter, computeGraphCenter, convertSnapshot, createAsyncGraphDef, createAsyncGraphRegistry, createProgressGraphDef, createProgressGraphRegistry, createSimpleGraphDef, createSimpleGraphRegistry, createValidationGraphDef, createValidationGraphRegistry, findMatchingPaths, generateId, getInputHandleMetadata, getInputTypeId, getTypedOutputTypeId, getTypedOutputValue, getValueAtPath, installLogging, isInputPrivate, isTypedOutput, mergeInputHandleDescriptors, mergeRuntimeState, mergeSnapshots, offsetImportedPositions, parseJsonPath, registerDelayNode, registerProgressNodes, setValueAtPath, setValueAtPathWithCreation, typed };
|
|
6154
|
+
export { BaseCompareOperation, BaseLogicOperation, BaseMathOperation, CompositeCategory, ComputeCategory, GraphBuilder, GraphRuntime, LevelLogger, LocalEngine, Registry, buildValueConverter, computeGraphCenter, convertSnapshot, createAsyncGraphDef, createAsyncGraphRegistry, createProgressGraphDef, createProgressGraphRegistry, createSimpleGraphDef, createSimpleGraphRegistry, createValidationGraphDef, createValidationGraphRegistry, findMatchingPaths, generateId, getInputDeclaredTypes, getInputHandleMetadata, getInputTypeId, getTypedOutputTypeId, getTypedOutputValue, getValueAtPath, installLogging, isInputPrivate, isTypedOutput, mergeInputHandleDescriptors, mergeRuntimeState, mergeSnapshots, offsetImportedPositions, parseJsonPath, registerDelayNode, registerProgressNodes, setValueAtPath, setValueAtPathWithCreation, typed };
|
|
6057
6155
|
//# sourceMappingURL=index.js.map
|