@bian-womp/spark-graph 0.1.20 → 0.1.22
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 +319 -30
- package/lib/cjs/index.cjs.map +1 -1
- package/lib/cjs/src/core/types.d.ts +2 -0
- package/lib/cjs/src/core/types.d.ts.map +1 -1
- package/lib/cjs/src/index.d.ts +2 -4
- package/lib/cjs/src/index.d.ts.map +1 -1
- package/lib/cjs/src/misc/base.d.ts.map +1 -1
- package/lib/cjs/src/runtime/GraphRuntime.d.ts.map +1 -1
- package/lib/esm/index.js +318 -31
- package/lib/esm/index.js.map +1 -1
- package/lib/esm/src/core/types.d.ts +2 -0
- package/lib/esm/src/core/types.d.ts.map +1 -1
- package/lib/esm/src/index.d.ts +2 -4
- package/lib/esm/src/index.d.ts.map +1 -1
- package/lib/esm/src/misc/base.d.ts.map +1 -1
- package/lib/esm/src/runtime/GraphRuntime.d.ts.map +1 -1
- package/package.json +2 -2
package/lib/cjs/index.cjs
CHANGED
|
@@ -1,5 +1,34 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
function typed(typeId, value) {
|
|
4
|
+
return { __spark_type: typeId, __spark_value: value };
|
|
5
|
+
}
|
|
6
|
+
function isTypedOutput(v) {
|
|
7
|
+
return (!!v &&
|
|
8
|
+
typeof v === "object" &&
|
|
9
|
+
Object.prototype.hasOwnProperty.call(v, "__spark_type"));
|
|
10
|
+
}
|
|
11
|
+
function getTypedOutputTypeId(v) {
|
|
12
|
+
if (isTypedOutput(v))
|
|
13
|
+
return String(v.__spark_type);
|
|
14
|
+
return undefined;
|
|
15
|
+
}
|
|
16
|
+
function getTypedOutputValue(v) {
|
|
17
|
+
if (isTypedOutput(v))
|
|
18
|
+
return v.__spark_value;
|
|
19
|
+
return v;
|
|
20
|
+
}
|
|
21
|
+
function getInputTypeId(inputs, handle) {
|
|
22
|
+
const v = inputs ? inputs[handle] : undefined;
|
|
23
|
+
if (!v)
|
|
24
|
+
return undefined;
|
|
25
|
+
return typeof v === "string" ? v : v.typeId;
|
|
26
|
+
}
|
|
27
|
+
function isInputPrivate(inputs, handle) {
|
|
28
|
+
const v = inputs ? inputs[handle] : undefined;
|
|
29
|
+
return !!(v && typeof v === "object" && v.private);
|
|
30
|
+
}
|
|
31
|
+
|
|
3
32
|
class CategoryRegistry {
|
|
4
33
|
constructor() {
|
|
5
34
|
this.categories = new Map();
|
|
@@ -372,25 +401,6 @@ class Registry {
|
|
|
372
401
|
}
|
|
373
402
|
}
|
|
374
403
|
|
|
375
|
-
function typed(typeId, value) {
|
|
376
|
-
return { __spark_type: typeId, __spark_value: value };
|
|
377
|
-
}
|
|
378
|
-
function isTypedOutput(v) {
|
|
379
|
-
return (!!v &&
|
|
380
|
-
typeof v === "object" &&
|
|
381
|
-
Object.prototype.hasOwnProperty.call(v, "__spark_type"));
|
|
382
|
-
}
|
|
383
|
-
function getInputTypeId(inputs, handle) {
|
|
384
|
-
const v = inputs ? inputs[handle] : undefined;
|
|
385
|
-
if (!v)
|
|
386
|
-
return undefined;
|
|
387
|
-
return typeof v === "string" ? v : v.typeId;
|
|
388
|
-
}
|
|
389
|
-
function isInputPrivate(inputs, handle) {
|
|
390
|
-
const v = inputs ? inputs[handle] : undefined;
|
|
391
|
-
return !!(v && typeof v === "object" && v.private);
|
|
392
|
-
}
|
|
393
|
-
|
|
394
404
|
class GraphRuntime {
|
|
395
405
|
constructor() {
|
|
396
406
|
this.nodes = new Map();
|
|
@@ -565,12 +575,12 @@ class GraphRuntime {
|
|
|
565
575
|
});
|
|
566
576
|
if (anyAsync) {
|
|
567
577
|
convertAsync = async (v, signal) => {
|
|
568
|
-
|
|
578
|
+
const typeId = getTypedOutputTypeId(v);
|
|
579
|
+
if (!typeId)
|
|
569
580
|
throw new Error(`Typed output required for union source; allowed: ${srcTypes.join("|")}`);
|
|
570
|
-
const typeId = String(v.__spark_type);
|
|
571
581
|
if (!srcTypes.includes(typeId))
|
|
572
582
|
throw new Error(`Invalid typed output ${typeId}; allowed: ${srcTypes.join("|")}`);
|
|
573
|
-
const payload =
|
|
583
|
+
const payload = typeId;
|
|
574
584
|
const res = registry.resolveCoercion(typeId, dstDeclared);
|
|
575
585
|
if (!res)
|
|
576
586
|
return payload;
|
|
@@ -581,12 +591,12 @@ class GraphRuntime {
|
|
|
581
591
|
}
|
|
582
592
|
else {
|
|
583
593
|
convert = (v) => {
|
|
584
|
-
|
|
594
|
+
const typeId = getTypedOutputTypeId(v);
|
|
595
|
+
if (!typeId)
|
|
585
596
|
throw new Error(`Typed output required for union source; allowed: ${srcTypes.join("|")}`);
|
|
586
|
-
const typeId = String(v.__spark_type);
|
|
587
597
|
if (!srcTypes.includes(typeId))
|
|
588
598
|
throw new Error(`Invalid typed output ${typeId}; allowed: ${srcTypes.join("|")}`);
|
|
589
|
-
const payload =
|
|
599
|
+
const payload = typeId;
|
|
590
600
|
const res = registry.resolveCoercion(typeId, dstDeclared);
|
|
591
601
|
if (!res)
|
|
592
602
|
return payload;
|
|
@@ -777,9 +787,7 @@ class GraphRuntime {
|
|
|
777
787
|
handle: srcHandle,
|
|
778
788
|
value,
|
|
779
789
|
io: "output",
|
|
780
|
-
runtimeTypeId:
|
|
781
|
-
? String(value.__spark_type)
|
|
782
|
-
: undefined,
|
|
790
|
+
runtimeTypeId: getTypedOutputTypeId(value),
|
|
783
791
|
});
|
|
784
792
|
// fan-out along all edges from this output
|
|
785
793
|
const outEdges = this.edges.filter((e) => e.source.nodeId === srcNodeId && e.source.handle === srcHandle);
|
|
@@ -811,7 +819,7 @@ class GraphRuntime {
|
|
|
811
819
|
handle: e.target.handle,
|
|
812
820
|
value: v,
|
|
813
821
|
io: "input",
|
|
814
|
-
runtimeTypeId:
|
|
822
|
+
runtimeTypeId: getTypedOutputTypeId(v),
|
|
815
823
|
});
|
|
816
824
|
if (!this.paused && this.allInboundHaveValue(e.target.nodeId))
|
|
817
825
|
this.scheduleInputsChanged(e.target.nodeId);
|
|
@@ -1778,6 +1786,96 @@ const lcg = (seed) => {
|
|
|
1778
1786
|
let s = seed >>> 0 || 1;
|
|
1779
1787
|
return () => (s = (s * 1664525 + 1013904223) >>> 0) / 0xffffffff;
|
|
1780
1788
|
};
|
|
1789
|
+
// JSON Pointer helpers (RFC 6901 subset)
|
|
1790
|
+
function jsonPointerGet(obj, pointer) {
|
|
1791
|
+
if (!pointer || pointer === "/")
|
|
1792
|
+
return obj;
|
|
1793
|
+
if (!pointer.startsWith("/"))
|
|
1794
|
+
return undefined;
|
|
1795
|
+
const parts = pointer
|
|
1796
|
+
.split("/")
|
|
1797
|
+
.slice(1)
|
|
1798
|
+
.map((p) => p.replace(/~1/g, "/").replace(/~0/g, "~"));
|
|
1799
|
+
let cur = obj;
|
|
1800
|
+
for (const key of parts) {
|
|
1801
|
+
if (cur === undefined || cur === null)
|
|
1802
|
+
return undefined;
|
|
1803
|
+
cur = cur[key];
|
|
1804
|
+
}
|
|
1805
|
+
return cur;
|
|
1806
|
+
}
|
|
1807
|
+
function jsonPointerSet(obj, pointer, value) {
|
|
1808
|
+
if (!pointer || pointer === "/")
|
|
1809
|
+
return value;
|
|
1810
|
+
if (!pointer.startsWith("/"))
|
|
1811
|
+
return obj;
|
|
1812
|
+
const parts = pointer
|
|
1813
|
+
.split("/")
|
|
1814
|
+
.slice(1)
|
|
1815
|
+
.map((p) => p.replace(/~1/g, "/").replace(/~0/g, "~"));
|
|
1816
|
+
const root = structuredClone(obj);
|
|
1817
|
+
let cur = root;
|
|
1818
|
+
for (let i = 0; i < parts.length; i++) {
|
|
1819
|
+
const key = parts[i];
|
|
1820
|
+
if (i === parts.length - 1) {
|
|
1821
|
+
if (Array.isArray(cur) && key === "-")
|
|
1822
|
+
cur.push(value);
|
|
1823
|
+
else
|
|
1824
|
+
cur[key] = value;
|
|
1825
|
+
}
|
|
1826
|
+
else {
|
|
1827
|
+
const next = cur[key];
|
|
1828
|
+
if (next === undefined || next === null) {
|
|
1829
|
+
// create container heuristically
|
|
1830
|
+
const nextKey = parts[i + 1];
|
|
1831
|
+
cur[key] =
|
|
1832
|
+
typeof nextKey === "string" && /^[0-9]+$/.test(nextKey) ? [] : {};
|
|
1833
|
+
}
|
|
1834
|
+
cur = cur[key];
|
|
1835
|
+
}
|
|
1836
|
+
}
|
|
1837
|
+
return root;
|
|
1838
|
+
}
|
|
1839
|
+
function jsonPointerRemove(obj, pointer) {
|
|
1840
|
+
if (!pointer || pointer === "/")
|
|
1841
|
+
return undefined;
|
|
1842
|
+
if (!pointer.startsWith("/"))
|
|
1843
|
+
return obj;
|
|
1844
|
+
const parts = pointer
|
|
1845
|
+
.split("/")
|
|
1846
|
+
.slice(1)
|
|
1847
|
+
.map((p) => p.replace(/~1/g, "/").replace(/~0/g, "~"));
|
|
1848
|
+
const root = structuredClone(obj);
|
|
1849
|
+
let cur = root;
|
|
1850
|
+
for (let i = 0; i < parts.length - 1; i++) {
|
|
1851
|
+
const key = parts[i];
|
|
1852
|
+
if (cur === undefined || cur === null)
|
|
1853
|
+
return root;
|
|
1854
|
+
cur = cur[key];
|
|
1855
|
+
}
|
|
1856
|
+
const last = parts[parts.length - 1];
|
|
1857
|
+
if (Array.isArray(cur)) {
|
|
1858
|
+
const idx = last === "-" ? cur.length - 1 : Number(last);
|
|
1859
|
+
if (Number.isFinite(idx))
|
|
1860
|
+
cur.splice(idx, 1);
|
|
1861
|
+
}
|
|
1862
|
+
else if (cur && typeof cur === "object") {
|
|
1863
|
+
delete cur[last];
|
|
1864
|
+
}
|
|
1865
|
+
return root;
|
|
1866
|
+
}
|
|
1867
|
+
function deepMerge(a, b) {
|
|
1868
|
+
if (Array.isArray(a) && Array.isArray(b))
|
|
1869
|
+
return [...a, ...b];
|
|
1870
|
+
if (isPlainObject(a) && isPlainObject(b)) {
|
|
1871
|
+
const out = { ...a };
|
|
1872
|
+
for (const [k, v] of Object.entries(b)) {
|
|
1873
|
+
out[k] = k in out ? deepMerge(out[k], v) : v;
|
|
1874
|
+
}
|
|
1875
|
+
return out;
|
|
1876
|
+
}
|
|
1877
|
+
return b;
|
|
1878
|
+
}
|
|
1781
1879
|
// JSON helpers
|
|
1782
1880
|
const isPlainObject = (v) => {
|
|
1783
1881
|
if (v === null || typeof v !== "object")
|
|
@@ -1816,7 +1914,7 @@ function setupBasicGraphRegistry() {
|
|
|
1816
1914
|
registry.registerType({
|
|
1817
1915
|
id: "base.object",
|
|
1818
1916
|
validate: (v) => isJson(v),
|
|
1819
|
-
}, { withArray:
|
|
1917
|
+
}, { withArray: false });
|
|
1820
1918
|
registry.registerType({
|
|
1821
1919
|
id: "base.vec3",
|
|
1822
1920
|
validate: (v) => Array.isArray(v) &&
|
|
@@ -2209,6 +2307,195 @@ function setupBasicGraphRegistry() {
|
|
|
2209
2307
|
},
|
|
2210
2308
|
},
|
|
2211
2309
|
});
|
|
2310
|
+
// ------------------------- JSON/object utilities -------------------------
|
|
2311
|
+
registry.registerNode({
|
|
2312
|
+
id: "base.objectGet",
|
|
2313
|
+
categoryId: "compute",
|
|
2314
|
+
inputs: { Object: "base.object", Pointers: "base.string[]" },
|
|
2315
|
+
outputs: { Values: "base.object" },
|
|
2316
|
+
impl: (ins) => {
|
|
2317
|
+
const obj = ins.Object;
|
|
2318
|
+
const pointers = (ins.Pointers || []).map(String);
|
|
2319
|
+
const out = {};
|
|
2320
|
+
for (const p of pointers)
|
|
2321
|
+
out[p] = jsonPointerGet(obj, p);
|
|
2322
|
+
return { Values: out };
|
|
2323
|
+
},
|
|
2324
|
+
});
|
|
2325
|
+
registry.registerNode({
|
|
2326
|
+
id: "base.objectSet",
|
|
2327
|
+
categoryId: "compute",
|
|
2328
|
+
inputs: {
|
|
2329
|
+
Object: "base.object",
|
|
2330
|
+
Pointers: "base.string[]",
|
|
2331
|
+
NewValues: "base.string[]",
|
|
2332
|
+
},
|
|
2333
|
+
outputs: { Result: "base.object" },
|
|
2334
|
+
impl: (ins) => {
|
|
2335
|
+
const pointers = (ins.Pointers || []).map(String);
|
|
2336
|
+
const values = (ins.NewValues || []).map(String);
|
|
2337
|
+
let cur = structuredClone(ins.Object);
|
|
2338
|
+
for (let i = 0; i < pointers.length; i++) {
|
|
2339
|
+
const p = pointers[i];
|
|
2340
|
+
const raw = values[i];
|
|
2341
|
+
let val = raw;
|
|
2342
|
+
if (typeof raw === "string") {
|
|
2343
|
+
try {
|
|
2344
|
+
val = JSON.parse(raw);
|
|
2345
|
+
}
|
|
2346
|
+
catch {
|
|
2347
|
+
/* keep as string */
|
|
2348
|
+
}
|
|
2349
|
+
}
|
|
2350
|
+
cur = jsonPointerSet(cur, p, val);
|
|
2351
|
+
}
|
|
2352
|
+
return { Result: cur };
|
|
2353
|
+
},
|
|
2354
|
+
});
|
|
2355
|
+
registry.registerNode({
|
|
2356
|
+
id: "base.objectRemove",
|
|
2357
|
+
categoryId: "compute",
|
|
2358
|
+
inputs: { Object: "base.object", Pointers: "base.string[]" },
|
|
2359
|
+
outputs: { Result: "base.object" },
|
|
2360
|
+
impl: (ins) => {
|
|
2361
|
+
const pointers = (ins.Pointers || []).map(String);
|
|
2362
|
+
let cur = structuredClone(ins.Object);
|
|
2363
|
+
for (const p of pointers)
|
|
2364
|
+
cur = jsonPointerRemove(cur, p);
|
|
2365
|
+
return { Result: cur };
|
|
2366
|
+
},
|
|
2367
|
+
});
|
|
2368
|
+
registry.registerNode({
|
|
2369
|
+
id: "base.objectMerge",
|
|
2370
|
+
categoryId: "compute",
|
|
2371
|
+
inputs: { A: "base.object", B: "base.object" },
|
|
2372
|
+
outputs: { Result: "base.object" },
|
|
2373
|
+
impl: (ins) => ({
|
|
2374
|
+
Result: deepMerge(ins.A, ins.B),
|
|
2375
|
+
}),
|
|
2376
|
+
});
|
|
2377
|
+
registry.registerNode({
|
|
2378
|
+
id: "base.objectKeys",
|
|
2379
|
+
categoryId: "compute",
|
|
2380
|
+
inputs: { Object: "base.object" },
|
|
2381
|
+
outputs: { Keys: "base.string[]" },
|
|
2382
|
+
impl: (ins) => {
|
|
2383
|
+
const obj = ins.Object;
|
|
2384
|
+
const keys = isPlainObject(obj)
|
|
2385
|
+
? Object.keys(obj)
|
|
2386
|
+
: Array.isArray(obj)
|
|
2387
|
+
? Object.keys(obj)
|
|
2388
|
+
: [];
|
|
2389
|
+
return { Keys: keys };
|
|
2390
|
+
},
|
|
2391
|
+
});
|
|
2392
|
+
registry.registerNode({
|
|
2393
|
+
id: "base.objectValues",
|
|
2394
|
+
categoryId: "compute",
|
|
2395
|
+
inputs: { Object: "base.object" },
|
|
2396
|
+
outputs: { Values: "base.object" },
|
|
2397
|
+
impl: (ins) => {
|
|
2398
|
+
const obj = ins.Object;
|
|
2399
|
+
const vals = isPlainObject(obj)
|
|
2400
|
+
? Object.values(obj)
|
|
2401
|
+
: Array.isArray(obj)
|
|
2402
|
+
? Object.values(obj)
|
|
2403
|
+
: [];
|
|
2404
|
+
return { Values: vals };
|
|
2405
|
+
},
|
|
2406
|
+
});
|
|
2407
|
+
registry.registerNode({
|
|
2408
|
+
id: "base.objectPatch",
|
|
2409
|
+
categoryId: "compute",
|
|
2410
|
+
inputs: { Object: "base.object", Ops: "base.object" },
|
|
2411
|
+
outputs: { Result: "base.object" },
|
|
2412
|
+
impl: (ins) => {
|
|
2413
|
+
const root = structuredClone(ins.Object);
|
|
2414
|
+
const opsRaw = ins.Ops;
|
|
2415
|
+
const ops = Array.isArray(opsRaw)
|
|
2416
|
+
? opsRaw
|
|
2417
|
+
: opsRaw
|
|
2418
|
+
? [opsRaw]
|
|
2419
|
+
: [];
|
|
2420
|
+
let cur = root;
|
|
2421
|
+
for (const op of ops) {
|
|
2422
|
+
if (!op || typeof op !== "object")
|
|
2423
|
+
continue;
|
|
2424
|
+
const kind = String(op.op || "");
|
|
2425
|
+
const path = String(op.path || "");
|
|
2426
|
+
if (kind === "add" || kind === "replace") {
|
|
2427
|
+
cur = jsonPointerSet(cur, path, op.value);
|
|
2428
|
+
}
|
|
2429
|
+
else if (kind === "remove") {
|
|
2430
|
+
cur = jsonPointerRemove(cur, path);
|
|
2431
|
+
}
|
|
2432
|
+
else if (kind === "test") {
|
|
2433
|
+
const got = jsonPointerGet(cur, path);
|
|
2434
|
+
const expected = op.value;
|
|
2435
|
+
const ok = JSON.stringify(got) === JSON.stringify(expected);
|
|
2436
|
+
if (!ok)
|
|
2437
|
+
throw new Error(`objectPatch test failed at ${path}`);
|
|
2438
|
+
}
|
|
2439
|
+
}
|
|
2440
|
+
return { Result: cur };
|
|
2441
|
+
},
|
|
2442
|
+
});
|
|
2443
|
+
registry.registerNode({
|
|
2444
|
+
id: "base.arrayConcat",
|
|
2445
|
+
categoryId: "compute",
|
|
2446
|
+
inputs: { A: "base.object", B: "base.object" },
|
|
2447
|
+
outputs: { Result: "base.object" },
|
|
2448
|
+
impl: (ins) => {
|
|
2449
|
+
const a = Array.isArray(ins.A) ? ins.A : [];
|
|
2450
|
+
const b = Array.isArray(ins.B) ? ins.B : [];
|
|
2451
|
+
return { Result: [...a, ...b] };
|
|
2452
|
+
},
|
|
2453
|
+
});
|
|
2454
|
+
registry.registerNode({
|
|
2455
|
+
id: "base.arrayFlatten",
|
|
2456
|
+
categoryId: "compute",
|
|
2457
|
+
inputs: { Objects: "base.object" },
|
|
2458
|
+
outputs: { Result: "base.object" },
|
|
2459
|
+
impl: (ins) => {
|
|
2460
|
+
const arr = Array.isArray(ins.Objects) ? ins.Objects : [];
|
|
2461
|
+
const out = [];
|
|
2462
|
+
for (const v of arr) {
|
|
2463
|
+
if (Array.isArray(v))
|
|
2464
|
+
out.push(...v);
|
|
2465
|
+
else
|
|
2466
|
+
out.push(v);
|
|
2467
|
+
}
|
|
2468
|
+
return { Result: out };
|
|
2469
|
+
},
|
|
2470
|
+
});
|
|
2471
|
+
registry.registerNode({
|
|
2472
|
+
id: "base.arraySortBy",
|
|
2473
|
+
categoryId: "compute",
|
|
2474
|
+
inputs: { Objects: "base.object", Pointers: "base.string[]" },
|
|
2475
|
+
outputs: { Result: "base.object" },
|
|
2476
|
+
impl: (ins) => {
|
|
2477
|
+
const arr = Array.isArray(ins.Objects) ? ins.Objects : [];
|
|
2478
|
+
const pointers = (ins.Pointers || []).map(String);
|
|
2479
|
+
const out = [...arr].sort((a, b) => {
|
|
2480
|
+
for (const p of pointers) {
|
|
2481
|
+
const av = jsonPointerGet(a, p);
|
|
2482
|
+
const bv = jsonPointerGet(b, p);
|
|
2483
|
+
if (av === bv)
|
|
2484
|
+
continue;
|
|
2485
|
+
if (av === undefined)
|
|
2486
|
+
return 1;
|
|
2487
|
+
if (bv === undefined)
|
|
2488
|
+
return -1;
|
|
2489
|
+
if (av < bv)
|
|
2490
|
+
return -1;
|
|
2491
|
+
if (av > bv)
|
|
2492
|
+
return 1;
|
|
2493
|
+
}
|
|
2494
|
+
return 0;
|
|
2495
|
+
});
|
|
2496
|
+
return { Result: out };
|
|
2497
|
+
},
|
|
2498
|
+
});
|
|
2212
2499
|
return registry;
|
|
2213
2500
|
}
|
|
2214
2501
|
function registerDelayNode(registry) {
|
|
@@ -2487,6 +2774,8 @@ exports.createSimpleGraphRegistry = createSimpleGraphRegistry;
|
|
|
2487
2774
|
exports.createValidationGraphDef = createValidationGraphDef;
|
|
2488
2775
|
exports.createValidationGraphRegistry = createValidationGraphRegistry;
|
|
2489
2776
|
exports.getInputTypeId = getInputTypeId;
|
|
2777
|
+
exports.getTypedOutputTypeId = getTypedOutputTypeId;
|
|
2778
|
+
exports.getTypedOutputValue = getTypedOutputValue;
|
|
2490
2779
|
exports.isInputPrivate = isInputPrivate;
|
|
2491
2780
|
exports.isTypedOutput = isTypedOutput;
|
|
2492
2781
|
exports.registerDelayNode = registerDelayNode;
|