@rkmodules/rules 0.0.169 → 0.0.171

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/dist/index.cjs.js CHANGED
@@ -546,31 +546,6 @@ function toArray(a) {
546
546
  return Object.values(a).flat();
547
547
  }
548
548
 
549
- var getType = {
550
- name: "getType",
551
- label: "Get Type",
552
- description: "Gets the type of a value as a string",
553
- inputs: {
554
- input: { type: "any" },
555
- },
556
- outputs: {
557
- type: "string",
558
- },
559
- impl: function (inputs, params) { return __awaiter(void 0, void 0, void 0, function () {
560
- return __generator(this, function (_a) {
561
- return [2 /*return*/, {
562
- type: mapTree(inputs.input, function (x) {
563
- if (x === undefined)
564
- return "empty";
565
- if (x === null)
566
- return "empty";
567
- return typeof x;
568
- }),
569
- }];
570
- });
571
- }); },
572
- };
573
-
574
549
  // utilities
575
550
  /**
576
551
  * merges two trees by concatenating the branches with the same path
@@ -642,6 +617,27 @@ function hasReference(value) {
642
617
  function parseReference(ref) {
643
618
  return ref.slice(1, -1);
644
619
  }
620
+ /** Reference paths using the same literal-array and token rules as interpolation. */
621
+ function getReferencePaths(value) {
622
+ var paths = new Set();
623
+ var visit = function (value) {
624
+ if (Array.isArray(value)) {
625
+ if (!value.every(Array.isArray))
626
+ value.forEach(visit);
627
+ }
628
+ else if (value && typeof value === "object") {
629
+ Object.values(value).forEach(visit);
630
+ }
631
+ else if (typeof value === "string") {
632
+ (value.match(/<.*?>/g) || []).forEach(function (token) {
633
+ if (isReference(token))
634
+ paths.add(parseReference(token));
635
+ });
636
+ }
637
+ };
638
+ visit(value);
639
+ return __spreadArray([], __read(paths), false);
640
+ }
645
641
  function uid$1() {
646
642
  return Math.random().toString(36).substring(2, 15);
647
643
  }
@@ -748,7 +744,200 @@ function interpolate(inputs, scope) {
748
744
  }));
749
745
  }
750
746
 
747
+ // Bounds count entries, not bytes. Each location keeps only its last successful result.
748
+ var MAX_SCOPES = 32;
749
+ var MAX_ENTRIES = 1024;
750
+ var cachePath = function (path) { return JSON.stringify(path); };
751
+ function sameRecord(a, b) {
752
+ var keys = Object.keys(a);
753
+ var otherKeys = Object.keys(b);
754
+ return keys.length === otherKeys.length && keys.every(function (key, i) { return key === otherKeys[i] && Object.is(a[key], b[key]); });
755
+ }
756
+ function put(map, key, value) {
757
+ map.delete(key);
758
+ map.set(key, value);
759
+ if (map.size > MAX_ENTRIES)
760
+ map.delete(map.keys().next().value);
761
+ }
762
+ /** Engine-owned caches; execution state is carried explicitly across async boundaries. */
763
+ var ExecutionCache = /** @class */ (function () {
764
+ function ExecutionCache() {
765
+ this.scopes = new Map();
766
+ }
767
+ ExecutionCache.prototype.begin = function (graph, options) {
768
+ var _a;
769
+ var cacheKey = (_a = options.cacheKey) !== null && _a !== void 0 ? _a : "";
770
+ var key = cachePath([graph, cacheKey]);
771
+ var scope = this.scopes.get(key);
772
+ if (!scope) {
773
+ scope = { graph: graph, cacheKey: cacheKey, generation: 0, run: 0,
774
+ interpolation: new Map(), pure: new Map(), preview: new Map() };
775
+ }
776
+ this.scopes.delete(key);
777
+ this.scopes.set(key, scope);
778
+ if (this.scopes.size > MAX_SCOPES) {
779
+ var oldest = this.scopes.keys().next().value;
780
+ this.scopes.get(oldest).generation++;
781
+ this.scopes.delete(oldest);
782
+ }
783
+ return { scope: scope, generation: scope.generation, run: ++scope.run,
784
+ options: __assign({}, options), visited: new Set() };
785
+ };
786
+ ExecutionCache.prototype.current = function (run) {
787
+ return run.generation === run.scope.generation && run.run === run.scope.run;
788
+ };
789
+ ExecutionCache.prototype.clear = function (options) {
790
+ var e_1, _a;
791
+ if (options === void 0) { options = {}; }
792
+ try {
793
+ for (var _b = __values(this.scopes.values()), _c = _b.next(); !_c.done; _c = _b.next()) {
794
+ var scope = _c.value;
795
+ if (options.graph !== undefined && scope.graph !== options.graph)
796
+ continue;
797
+ if (options.cacheKey !== undefined && scope.cacheKey !== options.cacheKey)
798
+ continue;
799
+ // Pending runs may finish for their callers, but cannot refill cleared caches.
800
+ scope.generation++;
801
+ if (!options.kind || options.kind === "all") {
802
+ scope.interpolation.clear();
803
+ scope.pure.clear();
804
+ scope.preview.clear();
805
+ }
806
+ else {
807
+ scope[options.kind].clear();
808
+ }
809
+ }
810
+ }
811
+ catch (e_1_1) { e_1 = { error: e_1_1 }; }
812
+ finally {
813
+ try {
814
+ if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
815
+ }
816
+ finally { if (e_1) throw e_1.error; }
817
+ }
818
+ };
819
+ ExecutionCache.prototype.visit = function (run, path) {
820
+ run.visited.add(cachePath(path));
821
+ };
822
+ ExecutionCache.prototype.finish = function (run) {
823
+ var e_2, _a, e_3, _b;
824
+ if (!this.current(run))
825
+ return;
826
+ try {
827
+ for (var _c = __values([run.scope.interpolation, run.scope.pure, run.scope.preview]), _d = _c.next(); !_d.done; _d = _c.next()) {
828
+ var map = _d.value;
829
+ try {
830
+ for (var _e = (e_3 = void 0, __values(map.keys())), _f = _e.next(); !_f.done; _f = _e.next()) {
831
+ var key = _f.value;
832
+ if (!run.visited.has(key))
833
+ map.delete(key);
834
+ }
835
+ }
836
+ catch (e_3_1) { e_3 = { error: e_3_1 }; }
837
+ finally {
838
+ try {
839
+ if (_f && !_f.done && (_b = _e.return)) _b.call(_e);
840
+ }
841
+ finally { if (e_3) throw e_3.error; }
842
+ }
843
+ }
844
+ }
845
+ catch (e_2_1) { e_2 = { error: e_2_1 }; }
846
+ finally {
847
+ try {
848
+ if (_d && !_d.done && (_a = _c.return)) _a.call(_c);
849
+ }
850
+ finally { if (e_2) throw e_2.error; }
851
+ }
852
+ };
853
+ ExecutionCache.prototype.interpolate = function (run, path, raw, scope) {
854
+ var key = cachePath(path);
855
+ run.visited.add(key);
856
+ if (!this.current(run))
857
+ return interpolate(raw, scope);
858
+ var previous = run.scope.interpolation.get(key);
859
+ var ports = new Map();
860
+ var entries = Object.entries(raw).map(function (_a) {
861
+ var _b = __read(_a, 2), name = _b[0], value = _b[1];
862
+ // Deep references depend on the base tree's identity. Unrelated scope
863
+ // entries never invalidate this port; a fresh execution context is fine.
864
+ var old = previous === null || previous === void 0 ? void 0 : previous.ports.get(name);
865
+ var paths = old && Object.is(old.raw, value) ? old.paths :
866
+ getReferencePaths(value).map(function (path) { return path.split(".").slice(0, 2).join("."); });
867
+ var dependencies = paths.map(function (path) { return getValue$1(scope, path); });
868
+ var same = old && Object.is(old.raw, value) &&
869
+ old.dependencies.length === dependencies.length &&
870
+ dependencies.every(function (value, i) { return Object.is(value, old.dependencies[i]); });
871
+ var port = same ? old : {
872
+ raw: value,
873
+ paths: paths,
874
+ dependencies: dependencies,
875
+ tree: interpolate({ value: value }, scope).value,
876
+ };
877
+ ports.set(name, port);
878
+ return [name, port.tree];
879
+ });
880
+ var next = Object.fromEntries(entries);
881
+ var result = previous && sameRecord(previous.result, next) ? previous.result : next;
882
+ put(run.scope.interpolation, key, { ports: ports, result: result });
883
+ return result;
884
+ };
885
+ ExecutionCache.prototype.key = function (call) {
886
+ call.inputs; call.params; var metadata = __rest(call, ["inputs", "params"]);
887
+ return metadata;
888
+ };
889
+ ExecutionCache.prototype.get = function (run, path, kind, fn, call, inputs, params) {
890
+ var key = cachePath(path);
891
+ run.visited.add(key);
892
+ if (!this.current(run))
893
+ return;
894
+ var entry = run.scope[kind].get(key);
895
+ if (entry && entry.definition === fn && entry.impl === fn.impl &&
896
+ sameRecord(entry.metadata, this.key(call)) && sameRecord(entry.inputs, inputs) &&
897
+ sameRecord(entry.params, params)) {
898
+ put(run.scope[kind], key, entry);
899
+ return entry;
900
+ }
901
+ };
902
+ ExecutionCache.prototype.set = function (run, path, kind, fn, call, inputs, params, result, impl, createdAt) {
903
+ if (!this.current(run))
904
+ return;
905
+ var key = cachePath(path);
906
+ run.visited.add(key);
907
+ put(run.scope[kind], key, { definition: fn, impl: impl, metadata: this.key(call),
908
+ inputs: __assign({}, inputs), params: __assign({}, params), result: result, info: { kind: kind, createdAt: createdAt } });
909
+ };
910
+ return ExecutionCache;
911
+ }());
912
+
913
+ var getType = {
914
+ pure: true,
915
+ name: "getType",
916
+ label: "Get Type",
917
+ description: "Gets the type of a value as a string",
918
+ inputs: {
919
+ input: { type: "any" },
920
+ },
921
+ outputs: {
922
+ type: "string",
923
+ },
924
+ impl: function (inputs, params) { return __awaiter(void 0, void 0, void 0, function () {
925
+ return __generator(this, function (_a) {
926
+ return [2 /*return*/, {
927
+ type: mapTree(inputs.input, function (x) {
928
+ if (x === undefined)
929
+ return "empty";
930
+ if (x === null)
931
+ return "empty";
932
+ return typeof x;
933
+ }),
934
+ }];
935
+ });
936
+ }); },
937
+ };
938
+
751
939
  var getValue = {
940
+ pure: true,
752
941
  name: "getValue",
753
942
  label: "Get Value",
754
943
  description: "Get a value from an object at a specified path.",
@@ -779,6 +968,8 @@ var getValue = {
779
968
  };
780
969
 
781
970
  var log = {
971
+ // Logging is a required side effect, even when the data is unchanged.
972
+ pure: false,
782
973
  name: "log",
783
974
  label: "Log",
784
975
  description: "Logs the input data to the console",
@@ -803,6 +994,7 @@ var log = {
803
994
  * value primitive function
804
995
  */
805
996
  var value = {
997
+ pure: true,
806
998
  name: "value",
807
999
  label: "Value",
808
1000
  description: "Outputs a constant value of a specified type",
@@ -854,6 +1046,7 @@ function isNumber() {
854
1046
  }
855
1047
 
856
1048
  var add$1 = {
1049
+ pure: true,
857
1050
  name: "add",
858
1051
  label: "Add",
859
1052
  description: "Add two numbers or strings",
@@ -899,6 +1092,8 @@ function evaluate(expression, scope) {
899
1092
  * TODO: need rank polymorhism on the tree item sizes
900
1093
  */
901
1094
  var calc = {
1095
+ // Expressions can use randomness; failed evaluations also log diagnostics.
1096
+ pure: false,
902
1097
  name: "calc",
903
1098
  label: "Calc",
904
1099
  nodeType: "Calc",
@@ -1037,6 +1232,7 @@ function getUnboundSymbols(expr, scope, extraBound) {
1037
1232
  }
1038
1233
 
1039
1234
  var cosDeg = {
1235
+ pure: true,
1040
1236
  name: "cosDeg",
1041
1237
  label: "Cosine",
1042
1238
  description: "Cosine of angle in degrees",
@@ -1060,6 +1256,7 @@ var cosDeg = {
1060
1256
  };
1061
1257
 
1062
1258
  var divide = {
1259
+ pure: true,
1063
1260
  name: "divide",
1064
1261
  label: "Divide",
1065
1262
  description: "Divide two numbers",
@@ -1086,6 +1283,7 @@ var divide = {
1086
1283
  };
1087
1284
 
1088
1285
  var equalTo = {
1286
+ pure: true,
1089
1287
  name: "equalTo",
1090
1288
  label: "Equal to",
1091
1289
  description: "Compare equal and not equal",
@@ -1116,6 +1314,7 @@ var equalTo = {
1116
1314
  };
1117
1315
 
1118
1316
  var greaterThan = {
1317
+ pure: true,
1119
1318
  name: "greaterThan",
1120
1319
  label: "Greater Than",
1121
1320
  description: "Compare on greater than or greater than or equal to",
@@ -1146,6 +1345,7 @@ var greaterThan = {
1146
1345
  };
1147
1346
 
1148
1347
  var lessThan = {
1348
+ pure: true,
1149
1349
  name: "lessThan",
1150
1350
  label: "Less Than",
1151
1351
  description: "Compare on less than or less than or equal to",
@@ -1176,6 +1376,7 @@ var lessThan = {
1176
1376
  };
1177
1377
 
1178
1378
  var modulo = {
1379
+ pure: true,
1179
1380
  name: "modulo",
1180
1381
  label: "Modulo",
1181
1382
  description: "Division remainder of two numbers",
@@ -1200,6 +1401,7 @@ var modulo = {
1200
1401
  };
1201
1402
 
1202
1403
  var multiply = {
1404
+ pure: true,
1203
1405
  name: "multiply",
1204
1406
  label: "Multiply",
1205
1407
  description: "Multiply two numbers",
@@ -1224,6 +1426,7 @@ var multiply = {
1224
1426
  };
1225
1427
 
1226
1428
  var pow = {
1429
+ pure: true,
1227
1430
  name: "pow",
1228
1431
  label: "Power",
1229
1432
  description: "Power a number",
@@ -1248,6 +1451,7 @@ var pow = {
1248
1451
  };
1249
1452
 
1250
1453
  var sinDeg = {
1454
+ pure: true,
1251
1455
  name: "sinDeg",
1252
1456
  label: "Sine",
1253
1457
  description: "Sine of angle in degrees",
@@ -1271,6 +1475,7 @@ var sinDeg = {
1271
1475
  };
1272
1476
 
1273
1477
  var sqrt = {
1478
+ pure: true,
1274
1479
  name: "sqrt",
1275
1480
  label: "Square root",
1276
1481
  description: "Square root of a number",
@@ -1296,6 +1501,7 @@ var sqrt = {
1296
1501
  };
1297
1502
 
1298
1503
  var subtract$1 = {
1504
+ pure: true,
1299
1505
  name: "subtract",
1300
1506
  label: "Subtract",
1301
1507
  description: "Subtract two numbers",
@@ -1320,6 +1526,7 @@ var subtract$1 = {
1320
1526
  };
1321
1527
 
1322
1528
  var tanDeg = {
1529
+ pure: true,
1323
1530
  name: "tanDeg",
1324
1531
  label: "Tangent",
1325
1532
  description: "Tangent of angle in degrees",
@@ -1343,6 +1550,7 @@ var tanDeg = {
1343
1550
  };
1344
1551
 
1345
1552
  var ceil = {
1553
+ pure: true,
1346
1554
  name: "ceil",
1347
1555
  label: "Round up",
1348
1556
  description: "Round a number up to the nearest integer",
@@ -1371,6 +1579,7 @@ var ceil = {
1371
1579
  };
1372
1580
 
1373
1581
  var floor = {
1582
+ pure: true,
1374
1583
  name: "floor",
1375
1584
  label: "Round down",
1376
1585
  description: "Round a number down to the nearest integer",
@@ -1399,6 +1608,7 @@ var floor = {
1399
1608
  };
1400
1609
 
1401
1610
  var round = {
1611
+ pure: true,
1402
1612
  name: "round",
1403
1613
  label: "Round",
1404
1614
  description: "Round a number to the nearest integer",
@@ -1427,6 +1637,7 @@ var round = {
1427
1637
  };
1428
1638
 
1429
1639
  var sum = {
1640
+ pure: true,
1430
1641
  name: "sum",
1431
1642
  label: "Sum",
1432
1643
  description: "Sum of all items in a group",
@@ -1477,6 +1688,7 @@ var primitives$8 = (_a$8 = {},
1477
1688
  _a$8);
1478
1689
 
1479
1690
  var joinStrings = {
1691
+ pure: true,
1480
1692
  name: "joinStrings",
1481
1693
  label: "Join Strings",
1482
1694
  description: "Join all strings in a group",
@@ -1505,6 +1717,7 @@ var joinStrings = {
1505
1717
  };
1506
1718
 
1507
1719
  var stringEqualTo = {
1720
+ pure: true,
1508
1721
  name: "stringEqualTo",
1509
1722
  label: "String Equal to",
1510
1723
  description: "Compare string equal and not equal",
@@ -1531,6 +1744,7 @@ var stringEqualTo = {
1531
1744
  };
1532
1745
 
1533
1746
  var stringTemplate = {
1747
+ pure: true,
1534
1748
  name: "stringTemplate",
1535
1749
  label: "String Template",
1536
1750
  description: "Assembles a string from inputs, use ${...} to interpolate inputs",
@@ -1570,6 +1784,7 @@ var stringTemplate = {
1570
1784
  };
1571
1785
 
1572
1786
  var toString = {
1787
+ pure: true,
1573
1788
  name: "toString",
1574
1789
  label: "To String",
1575
1790
  description: "convert to string",
@@ -1601,6 +1816,7 @@ var primitives$7 = (_a$7 = {},
1601
1816
  _a$7);
1602
1817
 
1603
1818
  var filterList = {
1819
+ pure: true,
1604
1820
  name: "filterList",
1605
1821
  label: "Filter List",
1606
1822
  description: "Filters the list by a boolean value",
@@ -1644,6 +1860,7 @@ var filterList = {
1644
1860
  };
1645
1861
 
1646
1862
  var listItem = {
1863
+ pure: true,
1647
1864
  name: "listItem",
1648
1865
  label: "List Item",
1649
1866
  description: "Retrieve the items from the list at the specified indices",
@@ -1692,6 +1909,7 @@ var listItem = {
1692
1909
  };
1693
1910
 
1694
1911
  var listLength = {
1912
+ pure: true,
1695
1913
  name: "listLength",
1696
1914
  label: "List Length",
1697
1915
  description: "Get the length of a list",
@@ -1713,6 +1931,7 @@ var listLength = {
1713
1931
  };
1714
1932
 
1715
1933
  var concat = {
1934
+ pure: true,
1716
1935
  name: "concat",
1717
1936
  label: "Concat Lists",
1718
1937
  description: "Concatenates two lists back to back",
@@ -1739,6 +1958,7 @@ var concat = {
1739
1958
  };
1740
1959
 
1741
1960
  var relativeItem = {
1961
+ pure: true,
1742
1962
  name: "relativeItem",
1743
1963
  label: "Relative Item",
1744
1964
  description: "Pairs each item in the tree with its next item",
@@ -1777,6 +1997,7 @@ var relativeItem = {
1777
1997
  };
1778
1998
 
1779
1999
  var relativeItems = {
2000
+ pure: true,
1780
2001
  name: "relativeItems",
1781
2002
  label: "Relative Items",
1782
2003
  description: "Pairs each item in the tree with an item in another tree at a specified offset",
@@ -1822,6 +2043,7 @@ function isNumStr(str) {
1822
2043
  return !isNaN(Number(str));
1823
2044
  }
1824
2045
  var listInput = {
2046
+ pure: true,
1825
2047
  name: "listInput",
1826
2048
  label: "List Input",
1827
2049
  description: "Input a list",
@@ -1862,6 +2084,7 @@ var listInput = {
1862
2084
  };
1863
2085
 
1864
2086
  var uniqueItems = {
2087
+ pure: true,
1865
2088
  name: "uniqueItems",
1866
2089
  label: "Unique Items",
1867
2090
  description: "Removes duplicate items from a list",
@@ -1898,6 +2121,7 @@ var uniqueItems = {
1898
2121
  };
1899
2122
 
1900
2123
  var coalesce = {
2124
+ pure: true,
1901
2125
  name: "coalesce",
1902
2126
  label: "Coalesce Items",
1903
2127
  description: "Outputs the first item if it's not empty, otherwise the second item",
@@ -1922,6 +2146,7 @@ var coalesce = {
1922
2146
  };
1923
2147
 
1924
2148
  var destructureList = {
2149
+ pure: true,
1925
2150
  name: "destructureList",
1926
2151
  label: "Destructure List",
1927
2152
  description: "Separates an list into a part with the specified values and the rest",
@@ -1946,7 +2171,7 @@ var destructureList = {
1946
2171
  var included = [];
1947
2172
  var excluded = [];
1948
2173
  var matches = [];
1949
- console.log("Destructuring list", list, items);
2174
+ // console.log("Destructuring list", list, items);
1950
2175
  list.forEach(function (value) {
1951
2176
  var m = items.includes(value);
1952
2177
  matches.push(m);
@@ -1992,6 +2217,7 @@ var primitives$6 = (_a$6 = {},
1992
2217
  _a$6);
1993
2218
 
1994
2219
  var splitGroup = {
2220
+ pure: true,
1995
2221
  name: "splitGroup",
1996
2222
  label: "Split Group",
1997
2223
  description: "Splits every item of a group into its own group",
@@ -2011,6 +2237,7 @@ var splitGroup = {
2011
2237
  };
2012
2238
 
2013
2239
  var mergeGroup = {
2240
+ pure: true,
2014
2241
  name: "mergeGroup",
2015
2242
  label: "Merge Group",
2016
2243
  description: "Merge the deepest groups into their parent.",
@@ -2036,6 +2263,7 @@ var mergeGroup = {
2036
2263
  };
2037
2264
 
2038
2265
  var cartesianGroups = {
2266
+ pure: true,
2039
2267
  name: "cartesianGroups",
2040
2268
  label: "Cartesian Groups",
2041
2269
  description: "Duplicate groups such that all pairings are created.",
@@ -2075,6 +2303,7 @@ var cartesianGroups = {
2075
2303
  };
2076
2304
 
2077
2305
  var mergeTree = {
2306
+ pure: true,
2078
2307
  name: "mergeTree",
2079
2308
  label: "Merge Tree",
2080
2309
  description: "Merge groups with the same index into a single tree.",
@@ -2103,6 +2332,7 @@ var mergeTree = {
2103
2332
  };
2104
2333
 
2105
2334
  var simplifyTree = {
2335
+ pure: true,
2106
2336
  name: "simplifyTree",
2107
2337
  label: "Simplify Groups",
2108
2338
  description: "Simplify a tree by removing redundant groups.",
@@ -2125,6 +2355,7 @@ var simplifyTree = {
2125
2355
  };
2126
2356
 
2127
2357
  var groupAll = {
2358
+ pure: true,
2128
2359
  name: "groupAll",
2129
2360
  label: "Group All",
2130
2361
  description: "Adds a group around all groups in the input tree",
@@ -2149,6 +2380,7 @@ var groupAll = {
2149
2380
  };
2150
2381
 
2151
2382
  var normalizeTree = {
2383
+ pure: true,
2152
2384
  name: "normalizeTree",
2153
2385
  label: "Normalize Groups",
2154
2386
  description: "Normalize a tree to consequtive groups and removed empty groups.",
@@ -2178,6 +2410,7 @@ var normalizeTree = {
2178
2410
  };
2179
2411
 
2180
2412
  var filterTree = {
2413
+ pure: true,
2181
2414
  name: "filterTree",
2182
2415
  label: "Filter Tree",
2183
2416
  description: "Filter groups by path matchers",
@@ -2223,6 +2456,7 @@ var filterTree = {
2223
2456
  };
2224
2457
 
2225
2458
  var treeItem = {
2459
+ pure: true,
2226
2460
  name: "treeItem",
2227
2461
  label: "Tree Item",
2228
2462
  description: "Retrieve the groups from a tree at specified indexes",
@@ -2265,6 +2499,7 @@ var primitives$5 = (_a$5 = {},
2265
2499
  _a$5);
2266
2500
 
2267
2501
  var series = {
2502
+ pure: true,
2268
2503
  name: "series",
2269
2504
  label: "Series",
2270
2505
  description: "Create a series of numbers.",
@@ -2305,6 +2540,7 @@ var primitives$4 = (_a$4 = {},
2305
2540
  _a$4);
2306
2541
 
2307
2542
  var booleanAnd = {
2543
+ pure: true,
2308
2544
  name: "booleanAnd",
2309
2545
  label: "And",
2310
2546
  description: "Returns true if both of the items are true",
@@ -2328,6 +2564,7 @@ var booleanAnd = {
2328
2564
  };
2329
2565
 
2330
2566
  var booleanNot = {
2567
+ pure: true,
2331
2568
  name: "booleanNot",
2332
2569
  label: "Not",
2333
2570
  description: "Inverts the input boolean value",
@@ -2350,6 +2587,7 @@ var booleanNot = {
2350
2587
  };
2351
2588
 
2352
2589
  var booleanOr = {
2590
+ pure: true,
2353
2591
  name: "booleanOr",
2354
2592
  label: "Or",
2355
2593
  description: "Returns true if one of the items is true",
@@ -2373,6 +2611,7 @@ var booleanOr = {
2373
2611
  };
2374
2612
 
2375
2613
  var groupAnd = {
2614
+ pure: true,
2376
2615
  name: "groupAnd",
2377
2616
  label: "Group and",
2378
2617
  description: "Returns true if all of the items in a group are true",
@@ -2402,6 +2641,7 @@ var groupAnd = {
2402
2641
  };
2403
2642
 
2404
2643
  var groupOr = {
2644
+ pure: true,
2405
2645
  name: "groupOr",
2406
2646
  label: "Group or",
2407
2647
  description: "Returns true if any of the items in a group are true",
@@ -2431,6 +2671,7 @@ var groupOr = {
2431
2671
  };
2432
2672
 
2433
2673
  var groupStats = {
2674
+ pure: true,
2434
2675
  name: "groupStats",
2435
2676
  label: "Group stats",
2436
2677
  description: "Returns statistics about a group of numbers",
@@ -2495,6 +2736,7 @@ var primitives$3 = (_a$3 = {},
2495
2736
  _a$3);
2496
2737
 
2497
2738
  var inputs = {
2739
+ pure: true,
2498
2740
  name: "inputs",
2499
2741
  label: "Input",
2500
2742
  description: "Data input.",
@@ -2511,6 +2753,7 @@ var inputs = {
2511
2753
  };
2512
2754
 
2513
2755
  var output = {
2756
+ pure: true,
2514
2757
  name: "output",
2515
2758
  label: "Output",
2516
2759
  description: "Data output.",
@@ -2531,6 +2774,7 @@ var primitives$2 = (_a$2 = {},
2531
2774
  _a$2);
2532
2775
 
2533
2776
  var mergeObject = {
2777
+ pure: true,
2534
2778
  name: "mergeObject",
2535
2779
  label: "Merge Object",
2536
2780
  description: "Merges objects in groups",
@@ -2559,6 +2803,7 @@ var mergeObject = {
2559
2803
  };
2560
2804
 
2561
2805
  var object = {
2806
+ pure: true,
2562
2807
  name: "object",
2563
2808
  label: "Object",
2564
2809
  description: "Creates an object",
@@ -2586,6 +2831,7 @@ var object = {
2586
2831
  };
2587
2832
 
2588
2833
  var listToArray = {
2834
+ pure: true,
2589
2835
  name: "listToArray",
2590
2836
  label: "To Array",
2591
2837
  description: "Converts each branch to an array",
@@ -2608,6 +2854,7 @@ var listToArray = {
2608
2854
  };
2609
2855
 
2610
2856
  var objectEntries = {
2857
+ pure: true,
2611
2858
  name: "objectEntries",
2612
2859
  label: "Entries",
2613
2860
  description: "Gets keys and pairs of an object",
@@ -2641,6 +2888,7 @@ var objectEntries = {
2641
2888
  };
2642
2889
 
2643
2890
  var arrayToList = {
2891
+ pure: true,
2644
2892
  name: "arrayToList",
2645
2893
  label: "Array to List",
2646
2894
  description: "Separates array",
@@ -2669,6 +2917,7 @@ var arrayToList = {
2669
2917
  };
2670
2918
 
2671
2919
  var explodeObject = {
2920
+ pure: true,
2672
2921
  name: "explodeObject",
2673
2922
  label: "Explode Object",
2674
2923
  description: "Separates all fields of an object",
@@ -2728,6 +2977,7 @@ var explodeObject = {
2728
2977
  };
2729
2978
 
2730
2979
  var setField = {
2980
+ pure: true,
2731
2981
  name: "setField",
2732
2982
  label: "Set Field",
2733
2983
  description: "Sets a field in an object to a specified value.",
@@ -2767,6 +3017,7 @@ var setField = {
2767
3017
  };
2768
3018
 
2769
3019
  var destructureObject = {
3020
+ pure: true,
2770
3021
  name: "destructureObject",
2771
3022
  label: "Destructure Object",
2772
3023
  description: "Separates an object into a part with the specified fields and the rest",
@@ -2836,6 +3087,8 @@ var primitives$1 = (_a$1 = {},
2836
3087
  var INFERRED = "inferred";
2837
3088
  var ary$1 = __spreadArray([INFERRED], __read(Intl.supportedValuesOf("timeZone")), false);
2838
3089
  var parseDate = {
3090
+ // Empty values fall back to the clock; parsing also logs to the console.
3091
+ pure: false,
2839
3092
  name: "parseDate",
2840
3093
  label: "Parse",
2841
3094
  description: "Parses a date string",
@@ -2873,6 +3126,8 @@ var parseDate = {
2873
3126
 
2874
3127
  var ary = Intl.supportedValuesOf("timeZone");
2875
3128
  var formatDate = {
3129
+ // Empty values fall back to the clock; omitted options use host locale/timezone.
3130
+ pure: false,
2876
3131
  name: "formatDate",
2877
3132
  label: "Format",
2878
3133
  description: "Formats a date",
@@ -2992,6 +3247,7 @@ var formatDate = {
2992
3247
  };
2993
3248
 
2994
3249
  var duration = {
3250
+ pure: true,
2995
3251
  name: "duration",
2996
3252
  label: "Duration",
2997
3253
  description: "Creates a duration",
@@ -3032,6 +3288,8 @@ var duration = {
3032
3288
  };
3033
3289
 
3034
3290
  var isoDate = {
3291
+ // Empty values fall back to the current clock.
3292
+ pure: false,
3035
3293
  name: "isoDate",
3036
3294
  label: "To ISO",
3037
3295
  description: "ISO 8601 format of a date",
@@ -3057,6 +3315,8 @@ var isoDate = {
3057
3315
  };
3058
3316
 
3059
3317
  var today = {
3318
+ // Reads the current clock on every evaluation.
3319
+ pure: false,
3060
3320
  name: "today",
3061
3321
  label: "Today",
3062
3322
  description: "The date of today",
@@ -3123,31 +3383,49 @@ function normalizeVarDef(varDef) {
3123
3383
  return varDef;
3124
3384
  }
3125
3385
  function getReferences(inputs) {
3126
- var references = [];
3127
- Object.entries(inputs).forEach(function (_a) {
3386
+ return Object.entries(inputs).flatMap(function (_a) {
3128
3387
  var _b = __read(_a, 2), name = _b[0], value = _b[1];
3129
- var values = Array.isArray(value) ? value : [value];
3130
- values.forEach(function (value) {
3131
- if (!isReference(value)) {
3132
- return;
3133
- }
3134
- var path = parseReference(value);
3388
+ return getReferencePaths(value).map(function (path) {
3135
3389
  var parts = path.split(".");
3136
- references.push({
3390
+ return {
3137
3391
  name: name,
3138
3392
  path: path,
3139
3393
  parts: parts,
3140
3394
  refNode: parts[0],
3141
3395
  refField: parts.slice(1).join("."),
3142
- });
3396
+ };
3143
3397
  });
3144
3398
  });
3145
- return references;
3146
3399
  }
3147
- function topSort(fn) {
3400
+ function getExecutionOrder(fn) {
3148
3401
  var ordered = [];
3149
3402
  var visiting = new Set();
3150
3403
  var done = new Set();
3404
+ var body = fn.body || {};
3405
+ var nodeIds = new Map();
3406
+ Object.keys(body).forEach(function (id) {
3407
+ var referenceId = safeName(id);
3408
+ if (referenceId === "inputs") {
3409
+ throw new Error("Node ID \"".concat(id, "\" is reserved for graph inputs"));
3410
+ }
3411
+ if (nodeIds.has(referenceId)) {
3412
+ throw new Error("Ambiguous node reference \"".concat(referenceId, "\": \"").concat(nodeIds.get(referenceId), "\" and \"").concat(id, "\""));
3413
+ }
3414
+ nodeIds.set(referenceId, id);
3415
+ });
3416
+ var resolve = function (ref, location) {
3417
+ if (ref.parts.length < 2 || ref.parts.some(function (part) { return !part; })) {
3418
+ throw new Error("Invalid reference <".concat(ref.path, "> in ").concat(location, ".").concat(ref.name));
3419
+ }
3420
+ // Public inputs can be supplied at runtime without static definitions.
3421
+ if (ref.refNode === "inputs")
3422
+ return;
3423
+ var id = nodeIds.get(ref.refNode);
3424
+ if (id === undefined) {
3425
+ throw new Error("Reference <".concat(ref.path, "> in ").concat(location, ".").concat(ref.name, " points to missing node \"").concat(ref.refNode, "\""));
3426
+ }
3427
+ return id;
3428
+ };
3151
3429
  var visit = function (id) {
3152
3430
  // if already done, return
3153
3431
  if (done.has(id))
@@ -3158,19 +3436,11 @@ function topSort(fn) {
3158
3436
  }
3159
3437
  // mark as visiting
3160
3438
  visiting.add(id);
3161
- var fnCall = fn.body[id];
3162
- if (!fnCall) {
3163
- console.warn("Function ".concat(id, " not found in body"), fn);
3164
- }
3165
- // check the inputs and visit them
3166
- Object.values(fnCall.inputs || {}).forEach(function (input) {
3167
- if (isReference(input)) {
3168
- var _a = __read(parseReference(input).split("."), 1), id_1 = _a[0];
3169
- // visit inputs
3170
- if (id_1 !== "inputs") {
3171
- visit(id_1);
3172
- }
3173
- }
3439
+ var fnCall = body[id];
3440
+ getReferences(fnCall.inputs || {}).forEach(function (ref) {
3441
+ var dependency = resolve(ref, "node \"".concat(id, "\" input"));
3442
+ if (dependency !== undefined)
3443
+ visit(dependency);
3174
3444
  });
3175
3445
  // push to end of the list
3176
3446
  ordered.push(id);
@@ -3179,7 +3449,12 @@ function topSort(fn) {
3179
3449
  // mark as done
3180
3450
  done.add(id);
3181
3451
  };
3182
- Object.keys(fn.body).forEach(visit);
3452
+ Object.keys(body).forEach(visit);
3453
+ getReferences(fn.outputs || {}).forEach(function (ref) { return resolve(ref, "output"); });
3454
+ return ordered;
3455
+ }
3456
+ function topSort(fn) {
3457
+ var ordered = getExecutionOrder(fn);
3183
3458
  var orderedBody = Object.fromEntries(ordered.map(function (id) { return [id, fn.body[id]]; }));
3184
3459
  return __assign(__assign({}, fn), { body: orderedBody });
3185
3460
  }
@@ -3191,41 +3466,161 @@ function getDefault(varDef, inputs) {
3191
3466
  }
3192
3467
  return normDef.default;
3193
3468
  }
3469
+ var removedReference = Symbol("removedReference");
3470
+ // Copy only containers that change, retaining unrelated values and references.
3471
+ // A removed standalone reference is omitted; in a template it becomes empty text.
3472
+ function removeReferences(value, matches) {
3473
+ if (isReference(value)) {
3474
+ return matches(value) ? removedReference : value;
3475
+ }
3476
+ if (typeof value === "string") {
3477
+ return value.replace(/<.*?>/g, function (ref) {
3478
+ return isReference(ref) && matches(ref) ? "" : ref;
3479
+ });
3480
+ }
3481
+ if (Array.isArray(value)) {
3482
+ var changed_1 = false;
3483
+ var items_1 = [];
3484
+ value.forEach(function (item) {
3485
+ var next = removeReferences(item, matches);
3486
+ if (next !== item)
3487
+ changed_1 = true;
3488
+ if (next !== removedReference)
3489
+ items_1.push(next);
3490
+ });
3491
+ return changed_1 ? items_1 : value;
3492
+ }
3493
+ if (value && typeof value === "object") {
3494
+ var prototype = Object.getPrototypeOf(value);
3495
+ if (prototype !== Object.prototype && prototype !== null)
3496
+ return value;
3497
+ var changed_2 = false;
3498
+ var entries_1 = [];
3499
+ Object.entries(value).forEach(function (_a) {
3500
+ var _b = __read(_a, 2), key = _b[0], item = _b[1];
3501
+ var next = removeReferences(item, matches);
3502
+ if (next !== item)
3503
+ changed_2 = true;
3504
+ if (next !== removedReference)
3505
+ entries_1.push([key, next]);
3506
+ });
3507
+ return changed_2 ? Object.fromEntries(entries_1) : value;
3508
+ }
3509
+ return value;
3510
+ }
3194
3511
  var Engine = /** @class */ (function () {
3195
3512
  function Engine(morePrimitives, env) {
3196
3513
  if (morePrimitives === void 0) { morePrimitives = {}; }
3197
3514
  if (env === void 0) { env = {}; }
3515
+ this.graphDefinitions = new WeakMap();
3516
+ this.automaticMounts = new Map();
3198
3517
  this.listeners = {};
3199
- this.cache = {};
3200
- this.cacheMiss = Symbol("cacheMiss");
3518
+ this.cache = new ExecutionCache();
3519
+ this.graphRunners = new WeakMap();
3520
+ this.executions = new WeakMap();
3521
+ this.latestRuns = new WeakMap();
3201
3522
  this.context = null;
3202
3523
  this.fnIndex = __assign(__assign({}, primitives), morePrimitives);
3203
3524
  this.env = env;
3204
3525
  }
3205
- Engine.prototype.checkCache = function (fnName, inputs) {
3206
- if (!this.cache[fnName]) {
3207
- return this.cacheMiss;
3208
- }
3209
- // TODO: need to check the interpolated inputs, as the references can be the same
3210
- // however, the interpolation does create new objects
3211
- return {};
3526
+ /** Clear successful results; running calls finish but cannot refill invalidated entries. */
3527
+ Engine.prototype.clearCache = function (options) {
3528
+ if (options === void 0) { options = {}; }
3529
+ this.cache.clear(options);
3212
3530
  };
3213
- Engine.prototype.runGraph = function (node, inputs, params) {
3531
+ Engine.prototype.executeCall = function (fn_1, call_1, inputs_1, params_1, context_1, name_1, executionId_1, run_1, path_1) {
3532
+ return __awaiter(this, arguments, void 0, function (fn, call, inputs, params, context, name, executionId, run, path, root) {
3533
+ var graphRunner, kind, hit, startTime, start, result, createdAt, impl, _a, endTime, event;
3534
+ if (root === void 0) { root = false; }
3535
+ return __generator(this, function (_b) {
3536
+ switch (_b.label) {
3537
+ case 0:
3538
+ this.cache.visit(run, path);
3539
+ graphRunner = this.graphRunners.get(fn);
3540
+ kind = graphRunner
3541
+ ? undefined
3542
+ : fn.pure
3543
+ ? "pure"
3544
+ : run.options.mode === "preview" && fn.previewCache
3545
+ ? "preview"
3546
+ : undefined;
3547
+ hit = kind
3548
+ ? this.cache.get(run, path, kind, fn, call, inputs, params)
3549
+ : undefined;
3550
+ startTime = performance.now();
3551
+ start = {
3552
+ name: name,
3553
+ fn: call.name,
3554
+ inputs: inputs,
3555
+ params: params,
3556
+ executionId: executionId,
3557
+ context: context,
3558
+ startTime: startTime,
3559
+ };
3560
+ if (!hit) return [3 /*break*/, 1];
3561
+ result = hit.result;
3562
+ createdAt = hit.info.createdAt;
3563
+ return [3 /*break*/, 8];
3564
+ case 1:
3565
+ context.activations[name] = true;
3566
+ impl = fn.impl;
3567
+ console.log("Executing function call: ".concat(name));
3568
+ _b.label = 2;
3569
+ case 2:
3570
+ _b.trys.push([2, , 7, 8]);
3571
+ this.fireEvent("functionCall", start);
3572
+ if (!graphRunner) return [3 /*break*/, 4];
3573
+ return [4 /*yield*/, graphRunner(inputs, params, run, path)];
3574
+ case 3:
3575
+ _a = (_b.sent()).result;
3576
+ return [3 /*break*/, 6];
3577
+ case 4: return [4 /*yield*/, impl.call(fn, inputs, params, this, root ? null : context, name)];
3578
+ case 5:
3579
+ _a = _b.sent();
3580
+ _b.label = 6;
3581
+ case 6:
3582
+ result = _a;
3583
+ createdAt = Date.now();
3584
+ if (kind)
3585
+ this.cache.set(run, path, kind, fn, call, inputs, params, result, impl, createdAt);
3586
+ return [3 /*break*/, 8];
3587
+ case 7:
3588
+ context.activations[name] = false;
3589
+ context.timings[name] = performance.now() - startTime;
3590
+ return [7 /*endfinally*/];
3591
+ case 8:
3592
+ endTime = performance.now();
3593
+ context.activations[name] = false;
3594
+ context.timings[name] = endTime - startTime;
3595
+ context.scope[name] = result;
3596
+ event = __assign(__assign({}, start), { result: result, endTime: endTime, duration: endTime - startTime, cached: !!hit, cache: kind ? { kind: kind, createdAt: createdAt } : undefined });
3597
+ // Hits still notify subscribers and populate a fresh context for the editor.
3598
+ this.fireEvent("functionResult", event);
3599
+ return [2 /*return*/, event];
3600
+ }
3601
+ });
3602
+ });
3603
+ };
3604
+ Engine.prototype.runGraph = function (node, suppliedInputs, params, executionOrder, run, path) {
3214
3605
  return __awaiter(this, void 0, void 0, function () {
3215
- var _a, body, executionId, context, startTime, _b, _c, _d, _i, name_1, fnCall, fn, inputs_1, params_1, result_1, cacheResult, startTime_1, endTime_1, result, endTime, response;
3216
- return __generator(this, function (_e) {
3217
- switch (_e.label) {
3606
+ var _a, body, executionId, defaults, mappedDefaults, inputs, context, startTime, executionOrder_1, executionOrder_1_1, name_1, fnCall, fn, callPath, inputs_1, params_1, e_1_1, result, endTime, response;
3607
+ var e_1, _b;
3608
+ return __generator(this, function (_c) {
3609
+ switch (_c.label) {
3218
3610
  case 0:
3219
3611
  _a = node.body, body = _a === void 0 ? {} : _a;
3220
3612
  executionId = uid$1();
3221
- // add input defaults
3613
+ defaults = {};
3222
3614
  Object.entries(node.inputs || {}).forEach(function (_a) {
3223
3615
  var _b = __read(_a, 2), name = _b[0], def = _b[1];
3224
3616
  var normDef = normalizeVarDef(def);
3225
- if (inputs[name] === undefined && normDef.default !== undefined) {
3226
- inputs[name] = getDefault(normDef, inputs);
3617
+ if (suppliedInputs[name] === undefined &&
3618
+ normDef.default !== undefined) {
3619
+ defaults[name] = getDefault(normDef, suppliedInputs);
3227
3620
  }
3228
3621
  });
3622
+ mappedDefaults = this.cache.interpolate(run, __spreadArray(__spreadArray([], __read(path), false), ["$defaults"], false), defaults, {});
3623
+ inputs = __assign(__assign({}, suppliedInputs), mappedDefaults);
3229
3624
  context = {
3230
3625
  scope: { inputs: inputs },
3231
3626
  calls: {},
@@ -3234,76 +3629,46 @@ var Engine = /** @class */ (function () {
3234
3629
  timings: {},
3235
3630
  activations: {},
3236
3631
  };
3632
+ this.executions.set(context, { run: run, path: path });
3237
3633
  startTime = performance.now();
3238
- _b = body;
3239
- _c = [];
3240
- for (_d in _b)
3241
- _c.push(_d);
3242
- _i = 0;
3243
- _e.label = 1;
3634
+ _c.label = 1;
3244
3635
  case 1:
3245
- if (!(_i < _c.length)) return [3 /*break*/, 5];
3246
- _d = _c[_i];
3247
- if (!(_d in _b)) return [3 /*break*/, 4];
3248
- name_1 = _d;
3636
+ _c.trys.push([1, 6, 7, 8]);
3637
+ executionOrder_1 = __values(executionOrder), executionOrder_1_1 = executionOrder_1.next();
3638
+ _c.label = 2;
3639
+ case 2:
3640
+ if (!!executionOrder_1_1.done) return [3 /*break*/, 5];
3641
+ name_1 = executionOrder_1_1.value;
3249
3642
  fnCall = body[name_1];
3250
3643
  fn = this.fnIndex[fnCall.name];
3251
- if (!fn) {
3644
+ if (!fn)
3252
3645
  throw new Error("function ".concat(fnCall.name, " not found in index"));
3253
- }
3254
- inputs_1 = interpolate(fnCall.inputs || {}, context.scope);
3646
+ callPath = __spreadArray(__spreadArray([], __read(path), false), [name_1], false);
3647
+ inputs_1 = this.cache.interpolate(run, __spreadArray(__spreadArray([], __read(callPath), false), ["$inputs"], false), fnCall.inputs || {}, context.scope);
3255
3648
  params_1 = fnCall.params || {};
3256
- result_1 = {};
3257
3649
  context.calls[name_1] = fnCall;
3258
3650
  context.inputs[name_1] = inputs_1;
3259
3651
  context.params[name_1] = params_1;
3260
- cacheResult = this.checkCache(name_1, inputs_1);
3261
- if (!(cacheResult !== this.cacheMiss)) return [3 /*break*/, 2];
3262
- // use as result
3263
- result_1 = cacheResult;
3264
- // store the result in the scope
3265
- context.scope[name_1] = result_1;
3266
- return [3 /*break*/, 4];
3267
- case 2:
3268
- // cache miss, call the function implementation
3269
- context.activations[name_1] = true;
3270
- startTime_1 = performance.now();
3271
- this.fireEvent("functionCall", {
3272
- name: name_1,
3273
- fn: fnCall.name,
3274
- inputs: inputs_1,
3275
- params: params_1,
3276
- executionId: executionId,
3277
- context: context,
3278
- startTime: startTime_1,
3279
- });
3280
- return [4 /*yield*/, fn.impl(inputs_1, params_1, this, context, name_1)];
3652
+ return [4 /*yield*/, this.executeCall(fn, fnCall, inputs_1, params_1, context, name_1, executionId, run, callPath)];
3281
3653
  case 3:
3282
- // call the implentation of sub functions
3283
- result_1 = _e.sent();
3284
- endTime_1 = performance.now();
3285
- context.activations[name_1] = false;
3286
- context.timings[name_1] = endTime_1 - startTime_1;
3287
- // store the result in the scope
3288
- context.scope[name_1] = result_1;
3289
- this.fireEvent("functionResult", {
3290
- name: name_1,
3291
- fn: fnCall.name,
3292
- inputs: inputs_1,
3293
- params: params_1,
3294
- executionId: executionId,
3295
- context: context,
3296
- result: result_1,
3297
- startTime: startTime_1,
3298
- endTime: endTime_1,
3299
- duration: endTime_1 - startTime_1,
3300
- });
3301
- _e.label = 4;
3654
+ _c.sent();
3655
+ _c.label = 4;
3302
3656
  case 4:
3303
- _i++;
3304
- return [3 /*break*/, 1];
3305
- case 5:
3306
- result = interpolate(node.outputs || {}, context.scope);
3657
+ executionOrder_1_1 = executionOrder_1.next();
3658
+ return [3 /*break*/, 2];
3659
+ case 5: return [3 /*break*/, 8];
3660
+ case 6:
3661
+ e_1_1 = _c.sent();
3662
+ e_1 = { error: e_1_1 };
3663
+ return [3 /*break*/, 8];
3664
+ case 7:
3665
+ try {
3666
+ if (executionOrder_1_1 && !executionOrder_1_1.done && (_b = executionOrder_1.return)) _b.call(executionOrder_1);
3667
+ }
3668
+ finally { if (e_1) throw e_1.error; }
3669
+ return [7 /*endfinally*/];
3670
+ case 8:
3671
+ result = this.cache.interpolate(run, __spreadArray(__spreadArray([], __read(path), false), ["$outputs"], false), node.outputs || {}, context.scope);
3307
3672
  endTime = performance.now();
3308
3673
  response = {
3309
3674
  name: node.name,
@@ -3339,6 +3704,16 @@ var Engine = /** @class */ (function () {
3339
3704
  return node;
3340
3705
  }
3341
3706
  var _a = node.body, body = _a === void 0 ? {} : _a, props = __rest(node, ["body"]);
3707
+ // Validate before registering or mounting, preserving the last working
3708
+ // definition if an edit introduces a broken reference or cycle.
3709
+ var executionOrder = getExecutionOrder(node);
3710
+ executionOrder.forEach(function (id) {
3711
+ var call = body[id];
3712
+ if (!Object.prototype.hasOwnProperty.call(_this.fnIndex, call.name) ||
3713
+ !_this.fnIndex[call.name]) {
3714
+ throw new Error("function ".concat(call.name, " not found in index (node \"").concat(id, "\")"));
3715
+ }
3716
+ });
3342
3717
  // create a primitive function, one that has an implementation and optional mounting function
3343
3718
  var primitive = __assign(__assign({}, props), { outputs: Object.fromEntries(Object.entries(node.outputs || {}).map(function (_a) {
3344
3719
  var _b = __read(_a, 2), key = _b[0]; _b[1];
@@ -3346,8 +3721,9 @@ var Engine = /** @class */ (function () {
3346
3721
  })), mount: function (trigger) {
3347
3722
  // mount all the nodes
3348
3723
  var unsubs = [];
3349
- Object.values(body).forEach(function (n) {
3724
+ executionOrder.forEach(function (id) {
3350
3725
  var _a;
3726
+ var n = body[id];
3351
3727
  var fn = _this.fnIndex[n.name];
3352
3728
  if (!fn) {
3353
3729
  console.warn("function ".concat(n.name, " not found in index"));
@@ -3359,7 +3735,7 @@ var Engine = /** @class */ (function () {
3359
3735
  }
3360
3736
  });
3361
3737
  return function () {
3362
- var e_1, _a;
3738
+ var e_2, _a;
3363
3739
  try {
3364
3740
  // console.log(`Unmounting function: ${node.name}`);
3365
3741
  // unmount all the nodes
@@ -3368,35 +3744,48 @@ var Engine = /** @class */ (function () {
3368
3744
  unsub();
3369
3745
  }
3370
3746
  }
3371
- catch (e_1_1) { e_1 = { error: e_1_1 }; }
3747
+ catch (e_2_1) { e_2 = { error: e_2_1 }; }
3372
3748
  finally {
3373
3749
  try {
3374
3750
  if (unsubs_1_1 && !unsubs_1_1.done && (_a = unsubs_1.return)) _a.call(unsubs_1);
3375
3751
  }
3376
- finally { if (e_1) throw e_1.error; }
3752
+ finally { if (e_2) throw e_2.error; }
3377
3753
  }
3378
3754
  };
3379
- }, impl: function (inputs, params, engine) { return __awaiter(_this, void 0, void 0, function () {
3380
- var response;
3755
+ }, impl: function (inputs, params, engine, context, name) { return __awaiter(_this, void 0, void 0, function () {
3756
+ var parent, run, path, response;
3381
3757
  return __generator(this, function (_a) {
3382
3758
  switch (_a.label) {
3383
- case 0: return [4 /*yield*/, engine.runGraph(node, inputs, params)];
3759
+ case 0:
3760
+ parent = context && engine.executions.get(context);
3761
+ run = (parent === null || parent === void 0 ? void 0 : parent.run) || engine.cache.begin(node.name, {});
3762
+ path = parent ? __spreadArray(__spreadArray([], __read(parent.path), false), [name], false) : ["_root"];
3763
+ return [4 /*yield*/, engine.runGraph(node, inputs, params, executionOrder, run, path)];
3384
3764
  case 1:
3385
3765
  response = _a.sent();
3766
+ if (!parent)
3767
+ engine.cache.finish(run);
3386
3768
  return [2 /*return*/, response.result];
3387
3769
  }
3388
3770
  });
3389
3771
  }); } });
3772
+ this.graphRunners.set(primitive, function (inputs, params, run, path) {
3773
+ return _this.runGraph(node, inputs, params, executionOrder, run, path);
3774
+ });
3390
3775
  // register the primitive
3391
3776
  this.fnIndex[primitive.name] = primitive;
3777
+ this.graphDefinitions.set(primitive, node);
3392
3778
  return primitive;
3393
3779
  };
3394
- Engine.prototype.mount = function (node) {
3780
+ Engine.prototype.mount = function (node, inputs, options) {
3395
3781
  var _this = this;
3396
3782
  var _a;
3783
+ if (inputs === void 0) { inputs = {}; }
3784
+ if (options === void 0) { options = {}; }
3397
3785
  return (_a = node.mount) === null || _a === void 0 ? void 0 : _a.call(node, function () {
3398
- // console.log(`Triggering node: ${node.name}`);
3399
- _this.run(node);
3786
+ var _a, _b;
3787
+ var latest = _this.latestRuns.get(node);
3788
+ void _this.run(node, (_a = latest === null || latest === void 0 ? void 0 : latest.inputs) !== null && _a !== void 0 ? _a : inputs, (_b = latest === null || latest === void 0 ? void 0 : latest.options) !== null && _b !== void 0 ? _b : options);
3400
3789
  });
3401
3790
  };
3402
3791
  Engine.prototype.getContext = function () {
@@ -3415,138 +3804,188 @@ var Engine = /** @class */ (function () {
3415
3804
  };
3416
3805
  };
3417
3806
  Engine.prototype.fireEvent = function (eventName, event) {
3418
- var e_2, _a;
3807
+ var e_3, _a;
3419
3808
  try {
3420
3809
  for (var _b = __values(this.listeners[eventName] || []), _c = _b.next(); !_c.done; _c = _b.next()) {
3421
3810
  var listener = _c.value;
3422
3811
  listener(event);
3423
3812
  }
3424
3813
  }
3425
- catch (e_2_1) { e_2 = { error: e_2_1 }; }
3814
+ catch (e_3_1) { e_3 = { error: e_3_1 }; }
3426
3815
  finally {
3427
3816
  try {
3428
3817
  if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
3429
3818
  }
3430
- finally { if (e_2) throw e_2.error; }
3819
+ finally { if (e_3) throw e_3.error; }
3431
3820
  }
3432
3821
  };
3433
3822
  Engine.prototype.run = function (node_1) {
3434
- return __awaiter(this, arguments, void 0, function (node, inputs) {
3435
- var builtFn, mappedInputs, result;
3823
+ return __awaiter(this, arguments, void 0, function (node, inputs, options) {
3824
+ if (inputs === void 0) { inputs = {}; }
3825
+ if (options === void 0) { options = {}; }
3826
+ return __generator(this, function (_a) {
3827
+ switch (_a.label) {
3828
+ case 0: return [4 /*yield*/, this.runDetailed(node, inputs, options)];
3829
+ case 1: return [2 /*return*/, (_a.sent()).result];
3830
+ }
3831
+ });
3832
+ });
3833
+ };
3834
+ Engine.prototype.runDetailed = function (node_1) {
3835
+ return __awaiter(this, arguments, void 0, function (node, inputs, options) {
3836
+ var builtFn, rebuilt, mounted, unmount, run, mappedInputs, runner, response, context;
3436
3837
  var _a;
3437
3838
  if (inputs === void 0) { inputs = {}; }
3839
+ if (options === void 0) { options = {}; }
3438
3840
  return __generator(this, function (_b) {
3439
3841
  switch (_b.label) {
3440
3842
  case 0:
3441
3843
  if (!isPrimitive(node)) {
3442
3844
  builtFn = this.getFunction(node.name);
3443
- if (!builtFn) {
3444
- // not yet build
3845
+ rebuilt = false;
3846
+ // Graphs are edited immutably: the name identifies a registry slot,
3847
+ // while object identity tells us whether its definition is current.
3848
+ if (!builtFn || this.graphDefinitions.get(builtFn) !== node) {
3445
3849
  builtFn = this.build(node);
3446
- // mount if needed
3447
- this.mount(builtFn);
3850
+ rebuilt = true;
3851
+ }
3852
+ mounted = this.automaticMounts.get(node.name);
3853
+ if (rebuilt || (mounted && mounted.fn !== builtFn)) {
3854
+ // Only replace subscriptions owned by run(); explicit mount()
3855
+ // callers retain ownership of their cleanup callbacks.
3856
+ (_a = mounted === null || mounted === void 0 ? void 0 : mounted.unmount) === null || _a === void 0 ? void 0 : _a.call(mounted);
3857
+ this.automaticMounts.delete(node.name);
3858
+ unmount = this.mount(builtFn);
3859
+ this.automaticMounts.set(node.name, {
3860
+ fn: builtFn,
3861
+ unmount: unmount || undefined,
3862
+ });
3448
3863
  }
3449
- return [2 /*return*/, this.run(builtFn, inputs)];
3864
+ node = builtFn;
3450
3865
  }
3451
- mappedInputs = interpolate(inputs, {});
3452
- return [4 /*yield*/, ((_a = node.impl) === null || _a === void 0 ? void 0 : _a.call(node, mappedInputs, {}, this, null, "_root"))];
3866
+ this.latestRuns.set(node, { inputs: inputs, options: __assign({}, options) });
3867
+ run = this.cache.begin(node.name, options);
3868
+ mappedInputs = this.cache.interpolate(run, ["$inputs"], inputs, {});
3869
+ runner = this.graphRunners.get(node);
3870
+ if (!runner) return [3 /*break*/, 2];
3871
+ return [4 /*yield*/, runner(mappedInputs, {}, run, ["_root"])];
3453
3872
  case 1:
3454
- result = _b.sent();
3455
- // console.log("Engine run complete", result);
3456
- return [2 /*return*/, result];
3873
+ response = _b.sent();
3874
+ return [3 /*break*/, 4];
3875
+ case 2:
3876
+ context = {
3877
+ scope: { inputs: mappedInputs },
3878
+ calls: { _root: { name: node.name } },
3879
+ inputs: { _root: mappedInputs },
3880
+ params: { _root: {} },
3881
+ timings: {},
3882
+ activations: {},
3883
+ };
3884
+ return [4 /*yield*/, this.executeCall(node, context.calls._root, mappedInputs, {}, context, "_root", uid$1(), run, ["_root"], true)];
3885
+ case 3:
3886
+ response = _b.sent();
3887
+ response = __assign(__assign({}, response), { name: node.name, fn: "root" });
3888
+ this.fireEvent("result", response);
3889
+ this.context = context;
3890
+ _b.label = 4;
3891
+ case 4:
3892
+ this.cache.finish(run);
3893
+ return [2 /*return*/, response];
3457
3894
  }
3458
3895
  });
3459
3896
  });
3460
3897
  };
3461
- Engine.prototype.runDetailed = function (node_1) {
3462
- return __awaiter(this, arguments, void 0, function (node, inputs) {
3463
- var _this = this;
3464
- if (inputs === void 0) { inputs = {}; }
3465
- return __generator(this, function (_a) {
3466
- return [2 /*return*/, new Promise(function (resolve, reject) {
3467
- var unsub = _this.subscribe("result", function (event) {
3468
- if (event.name === node.name) {
3469
- resolve(event);
3470
- unsub();
3471
- }
3472
- });
3473
- _this.run(node, inputs).catch(function (e) {
3474
- unsub();
3475
- reject(e);
3476
- });
3477
- })];
3478
- });
3479
- });
3480
- };
3481
3898
  Engine.prototype.getFunction = function (name) {
3482
3899
  return this.fnIndex[name];
3483
3900
  };
3484
3901
  // node handlers
3485
3902
  Engine.prototype.applyNodeDelete = function (oldFn, nodeIds) {
3486
- var newFn = __assign(__assign({}, oldFn), { body: __assign({}, oldFn.body) });
3487
- if (nodeIds.every(function (id) { return id === "output"; })) {
3488
- // cannot delete output node
3903
+ var deletedIds = new Set(nodeIds.filter(function (id) { return id !== "output"; }));
3904
+ if (!deletedIds.size) {
3905
+ // The generated output node is protected, including in bulk deletes.
3489
3906
  return oldFn;
3490
3907
  }
3491
- if (nodeIds.includes("inputs")) {
3908
+ var newFn = __assign(__assign({}, oldFn), { body: __assign({}, oldFn.body) });
3909
+ if (deletedIds.has("inputs")) {
3492
3910
  delete newFn.inputs;
3493
3911
  }
3494
- nodeIds.forEach(function (id) {
3912
+ deletedIds.forEach(function (id) {
3495
3913
  delete newFn.body[id];
3496
3914
  });
3497
- // remove any references to the deleted nodes
3915
+ var matches = function (ref) {
3916
+ return deletedIds.has(parseReference(ref).split(".")[0]);
3917
+ };
3918
+ // Clone affected nodes as well as their inputs so shallow comparisons work.
3498
3919
  Object.entries(newFn.body).forEach(function (_a) {
3499
3920
  var _b = __read(_a, 2), id = _b[0], node = _b[1];
3500
- Object.entries(node.inputs || {}).forEach(function (_a) {
3501
- var _b;
3502
- var _c = __read(_a, 2), name = _c[0], value = _c[1];
3503
- if (isReference(value)) {
3504
- var path = parseReference(value);
3505
- var parts = path.split(".");
3506
- if (nodeIds.includes(parts[0])) {
3507
- (_b = newFn.body[id].inputs) === null || _b === void 0 ? true : delete _b[name];
3508
- }
3921
+ if (!node.inputs)
3922
+ return;
3923
+ var inputs = removeReferences(node.inputs, matches);
3924
+ if (inputs !== node.inputs) {
3925
+ newFn.body[id] = __assign(__assign({}, node), { inputs: inputs });
3926
+ }
3927
+ });
3928
+ Object.entries(oldFn.outputs || {}).forEach(function (_a) {
3929
+ var _b = __read(_a, 2), name = _b[0], value = _b[1];
3930
+ var next = removeReferences(value, matches);
3931
+ if (next !== value) {
3932
+ if (newFn.outputs === oldFn.outputs) {
3933
+ newFn.outputs = __assign({}, oldFn.outputs);
3509
3934
  }
3510
- });
3935
+ // Keep the public port, matching explicit output-edge deletion.
3936
+ newFn.outputs[name] = next === removedReference ? "" : next;
3937
+ }
3511
3938
  });
3512
3939
  return newFn;
3513
3940
  };
3514
3941
  Engine.prototype.applyEdgeDelete = function (oldFn, fromNode, toNode, fromField, toField) {
3515
3942
  var _a, _b;
3516
- var newFn = __assign(__assign({}, oldFn), { body: __assign({}, oldFn.body), outputs: __assign({}, oldFn.outputs) });
3943
+ var _c, _d, _e;
3944
+ var matches = function (ref) { return ref === "<".concat(fromNode, ".").concat(fromField, ">"); };
3517
3945
  if (toNode === "output") {
3518
- // deleting of output edges
3519
- if ((_a = newFn.outputs) === null || _a === void 0 ? void 0 : _a[toField]) {
3520
- // set to empty to prevent port from being removed, as that would cause the output node to be deleted
3521
- newFn.outputs[toField] = "";
3522
- }
3523
- return newFn;
3524
- }
3525
- var to = newFn.body[toNode];
3946
+ var value_1 = (_c = oldFn.outputs) === null || _c === void 0 ? void 0 : _c[toField];
3947
+ if (value_1 === undefined)
3948
+ return oldFn;
3949
+ var next_1 = removeReferences(value_1, matches);
3950
+ if (next_1 === value_1)
3951
+ return oldFn;
3952
+ return __assign(__assign({}, oldFn), { outputs: __assign(__assign({}, oldFn.outputs), (_a = {}, _a[toField] = next_1 === removedReference ? "" : next_1, _a)) });
3953
+ }
3954
+ var to = oldFn.body[toNode];
3526
3955
  var fn = this.fnIndex[to === null || to === void 0 ? void 0 : to.name];
3527
3956
  if (!to) {
3528
3957
  console.warn("Invalid nodes for edge deletion");
3529
- return newFn;
3958
+ return oldFn;
3530
3959
  }
3531
3960
  if (!fn) {
3532
3961
  console.warn("Function ".concat(to === null || to === void 0 ? void 0 : to.name, " not found in index, which is unexpected as you are deleting an edge to it."));
3533
- return newFn;
3962
+ return oldFn;
3963
+ }
3964
+ var value = (_d = to.inputs) === null || _d === void 0 ? void 0 : _d[toField];
3965
+ if (value === undefined) {
3966
+ console.warn("No matching edge found to delete");
3967
+ return oldFn;
3534
3968
  }
3535
- if (to.inputs && to.inputs[toField] === "<".concat(fromNode, ".").concat(fromField, ">")) {
3536
- // delete the incoming edge
3537
- delete to.inputs[toField];
3969
+ var next = removeReferences(value, matches);
3970
+ if (next === value) {
3971
+ console.warn("No matching edge found to delete");
3972
+ return oldFn;
3973
+ }
3974
+ var inputs = __assign({}, to.inputs);
3975
+ if (next === removedReference) {
3976
+ delete inputs[toField];
3538
3977
  // revert to default value if exists
3539
- if ((_b = fn.inputs) === null || _b === void 0 ? void 0 : _b[toField]) {
3978
+ if ((_e = fn.inputs) === null || _e === void 0 ? void 0 : _e[toField]) {
3540
3979
  var normDef = normalizeVarDef(fn.inputs[toField]);
3541
3980
  if (normDef.default !== undefined) {
3542
- to.inputs[toField] = getDefault(normDef, to.inputs);
3981
+ inputs[toField] = getDefault(normDef, inputs);
3543
3982
  }
3544
3983
  }
3545
3984
  }
3546
3985
  else {
3547
- console.warn("No matching edge found to delete");
3986
+ inputs[toField] = next;
3548
3987
  }
3549
- return newFn;
3988
+ return __assign(__assign({}, oldFn), { body: __assign(__assign({}, oldFn.body), (_b = {}, _b[toNode] = __assign(__assign({}, to), { inputs: inputs }), _b)) });
3550
3989
  };
3551
3990
  Engine.prototype.applyNodeAdd = function (oldFn, nodeName, callback) {
3552
3991
  var newFn = __assign(__assign({}, oldFn), { body: __assign({}, oldFn.body) });
@@ -3593,25 +4032,20 @@ var Engine = /** @class */ (function () {
3593
4032
  return topSort(newFn);
3594
4033
  };
3595
4034
  Engine.prototype.applyNodeConnect = function (oldFn, fromNode, toNode, fromField, toField) {
3596
- var _a;
4035
+ var _a, _b;
3597
4036
  var newFn = __assign(__assign({}, oldFn), { body: __assign({}, oldFn.body) });
3598
4037
  if (toNode === "output") {
3599
4038
  newFn.outputs = __assign(__assign({}, oldFn.outputs), (_a = {}, _a[toField] = "<".concat(fromNode, ".").concat(fromField, ">"), _a));
3600
4039
  // no need to sort, as only output has changed
3601
4040
  return newFn;
3602
4041
  }
3603
- // const from = newFn.body[fromNode];
3604
- var to = __assign({}, newFn.body[toNode]);
4042
+ var to = oldFn.body[toNode];
3605
4043
  if (!to) {
3606
4044
  console.warn("Invalid nodes for connection");
3607
- return newFn;
3608
- }
3609
- if (!to.inputs) {
3610
- to.inputs = {};
4045
+ return oldFn;
3611
4046
  }
3612
- // add the reference
3613
- to.inputs[toField] = "<".concat(fromNode, ".").concat(fromField, ">");
3614
- newFn.body[toNode] = to;
4047
+ // Copy the inputs before assigning: copying only the node still aliases them.
4048
+ newFn.body[toNode] = __assign(__assign({}, to), { inputs: __assign(__assign({}, to.inputs), (_b = {}, _b[toField] = "<".concat(fromNode, ".").concat(fromField, ">"), _b)) });
3615
4049
  return topSort(newFn);
3616
4050
  };
3617
4051
  return Engine;
@@ -6738,16 +7172,17 @@ Log.displayName = "LogNode";
6738
7172
 
6739
7173
  function GenericNode(_a) {
6740
7174
  var _b;
6741
- var _c;
7175
+ var _c, _d;
6742
7176
  var id = _a.id, data = _a.data, selected = _a.selected, inputs = _a.inputs, outputs = _a.outputs, params = _a.params, children = _a.children;
6743
7177
  var inputEntries = Object.entries(inputs || data.inputDefs || {});
6744
7178
  var outputEntries = Object.entries(outputs || data.outputDefs || {});
6745
7179
  var paramEntries = Object.entries(params || data.paramDefs || {});
6746
7180
  var engine = useEngine();
6747
- var _d = __read(React.useState({}), 2), result = _d[0], setResult = _d[1];
6748
- var _e = __read(React.useState(null), 2), duration = _e[0], setDuration = _e[1];
6749
- var _f = __read(useInner.useInner(((_c = outputEntries[0]) === null || _c === void 0 ? void 0 : _c[0]) || null, [outputs, data.outputDefs]), 2), focus = _f[0], setFocus = _f[1];
6750
- var _g = __read(React.useState(false), 2), showPreview = _g[0], setShowPreview = _g[1];
7181
+ var _e = __read(React.useState({}), 2), result = _e[0], setResult = _e[1];
7182
+ var _f = __read(React.useState(), 2), cache = _f[0], setCache = _f[1];
7183
+ var _g = __read(React.useState(null), 2), duration = _g[0], setDuration = _g[1];
7184
+ var _h = __read(useInner.useInner(((_c = outputEntries[0]) === null || _c === void 0 ? void 0 : _c[0]) || null, [outputs, data.outputDefs]), 2), focus = _h[0], setFocus = _h[1];
7185
+ var _j = __read(React.useState(false), 2), showPreview = _j[0], setShowPreview = _j[1];
6751
7186
  var previewValue = focus ? result[focus] : Object.values(result)[0];
6752
7187
  React.useEffect(function () {
6753
7188
  return engine.subscribe("functionResult", function (event) {
@@ -6755,10 +7190,11 @@ function GenericNode(_a) {
6755
7190
  if (event.name === id) {
6756
7191
  setResult(event.result || {});
6757
7192
  setDuration((_a = event.duration) !== null && _a !== void 0 ? _a : null);
7193
+ setCache(event.cached ? event.cache : undefined);
6758
7194
  }
6759
7195
  });
6760
- }, []);
6761
- return (React.createElement(NodeContainer, { label: data.label, selected: selected, id: id },
7196
+ }, [engine, id]);
7197
+ return (React.createElement(NodeContainer, { label: data.label, selected: selected, id: id, className: (_d = data.nodeProps) === null || _d === void 0 ? void 0 : _d.className },
6762
7198
  React.createElement("div", { className: styles$1.Description }, data.description),
6763
7199
  children,
6764
7200
  React.createElement("div", { className: styles$1.Ports },
@@ -6779,9 +7215,10 @@ function GenericNode(_a) {
6779
7215
  _b)), onClick: function () { return setShowPreview(!showPreview); } }, "Preview")),
6780
7216
  showPreview && (React.createElement("div", { className: styles$1.Preview },
6781
7217
  React.createElement(TreeView, { value: previewValue }),
6782
- duration !== null && (React.createElement("div", { className: styles$1.Duration },
6783
- duration.toFixed(2),
6784
- " ms"))))));
7218
+ duration !== null && (React.createElement("div", { className: styles$1.Duration }, cache ? (React.createElement("span", { title: "Result computed ".concat(new Date(cache.createdAt).toLocaleString()) },
7219
+ cache.kind === "preview" ? "Cached preview" : "Cached",
7220
+ " · ",
7221
+ new Date(cache.createdAt).toLocaleTimeString())) : "".concat(duration.toFixed(2), " ms")))))));
6785
7222
  }
6786
7223
 
6787
7224
  var math = mathjs.create(mathjs.all, {});
@@ -7847,44 +8284,58 @@ function useDraggableNode(name, itemProps) {
7847
8284
  return function (ref) { return drag(ref); };
7848
8285
  }
7849
8286
 
7850
- /**
7851
- * using functions
7852
- *
7853
- * in React context
7854
- * - use useFunction. This will build the function, mount it if needed and provides a run function.
7855
- *
7856
- *
7857
- * in Vanilla context
7858
- * - use engine.build(fn) to build the function
7859
- * - use engine.mount(fn) to mount the function (if it has a mount function)
7860
- * - use await engine.run(fn, inputs) to run the function and get the result
8287
+ /** Build a graph, optionally subscribe to triggers, and retain the latest run inputs.
8288
+ * Preview caching requires { mode: "preview" }; refresh clears external preview
8289
+ * results for this graph/session and reruns with the latest inputs.
7861
8290
  */
7862
- function useFunction(engine, fn, mount) {
8291
+ function useFunction(engine, fn, mount, options) {
7863
8292
  var _this = this;
7864
- var _a = __read(React.useState(null), 2), result = _a[0], setResult = _a[1];
7865
- var builtFn = React.useMemo(function () { return engine.build(fn); }, [fn]);
8293
+ if (options === void 0) { options = {}; }
8294
+ var _a = options.mode, mode = _a === void 0 ? "normal" : _a, _b = options.cacheKey, cacheKey = _b === void 0 ? "" : _b;
8295
+ var _c = __read(React.useState(null), 2), result = _c[0], setResult = _c[1];
8296
+ var builtFn = React.useMemo(function () { return engine.build(fn); }, [engine, fn]);
8297
+ var latestInputs = React.useRef({});
8298
+ var sequence = React.useRef(0);
8299
+ var currentDefinition = React.useRef(builtFn);
8300
+ currentDefinition.current = builtFn;
8301
+ var run = React.useCallback(function () {
8302
+ var args_1 = [];
8303
+ for (var _i = 0; _i < arguments.length; _i++) {
8304
+ args_1[_i] = arguments[_i];
8305
+ }
8306
+ return __awaiter(_this, __spreadArray([], __read(args_1), false), void 0, function (inputs) {
8307
+ var request, result;
8308
+ if (inputs === void 0) { inputs = latestInputs.current; }
8309
+ return __generator(this, function (_a) {
8310
+ switch (_a.label) {
8311
+ case 0:
8312
+ latestInputs.current = inputs;
8313
+ request = ++sequence.current;
8314
+ return [4 /*yield*/, engine.run(builtFn, inputs, { mode: mode, cacheKey: cacheKey })];
8315
+ case 1:
8316
+ result = _a.sent();
8317
+ if (request === sequence.current && currentDefinition.current === builtFn) {
8318
+ setResult(result);
8319
+ }
8320
+ return [2 /*return*/, result];
8321
+ }
8322
+ });
8323
+ });
8324
+ }, [engine, builtFn, mode, cacheKey]);
8325
+ var latestRun = React.useRef(run);
8326
+ latestRun.current = run;
7866
8327
  React.useEffect(function () {
8328
+ var _a;
7867
8329
  if (mount) {
7868
- return engine.mount(builtFn);
8330
+ // Keep this hook's inputs/options even when another editor shares the engine.
8331
+ return (_a = builtFn.mount) === null || _a === void 0 ? void 0 : _a.call(builtFn, function () { void latestRun.current(); });
7869
8332
  }
7870
8333
  }, [builtFn, mount]);
7871
- var run = React.useCallback(function (inputs) { return __awaiter(_this, void 0, void 0, function () {
7872
- var result;
7873
- return __generator(this, function (_a) {
7874
- switch (_a.label) {
7875
- case 0: return [4 /*yield*/, engine.run(builtFn, inputs)];
7876
- case 1:
7877
- result = _a.sent();
7878
- setResult(result);
7879
- return [2 /*return*/, result];
7880
- }
7881
- });
7882
- }); }, [builtFn]);
7883
- return React.useMemo(function () { return ({
7884
- fn: builtFn,
7885
- run: run,
7886
- result: result,
7887
- }); }, [builtFn, run, result]);
8334
+ var refresh = React.useCallback(function () {
8335
+ engine.clearCache({ kind: "preview", graph: fn.name, cacheKey: cacheKey });
8336
+ return run();
8337
+ }, [engine, fn.name, cacheKey, run]);
8338
+ return React.useMemo(function () { return ({ fn: builtFn, run: run, refresh: refresh, result: result }); }, [builtFn, run, refresh, result]);
7888
8339
  }
7889
8340
 
7890
8341
  // cheap lodash replacements
@@ -8898,6 +9349,7 @@ exports.getBranches = getBranches;
8898
9349
  exports.getItem = getItem;
8899
9350
  exports.getPaths = getPaths;
8900
9351
  exports.getPositions = getPositions;
9352
+ exports.getReferencePaths = getReferencePaths;
8901
9353
  exports.getReferences = getReferences;
8902
9354
  exports.getValue = getValue$1;
8903
9355
  exports.getVariable = getVariable;