@field/cascade 0.7.1 → 0.8.0
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/CHANGELOG.md +46 -0
- package/dist/assets/{CodeEditor-D-N0C2jT.js → CodeEditor-BEk-kIBd.js} +29 -29
- package/dist/assets/CodePanel-CeSdjXkg.js +2 -0
- package/dist/assets/CustomNodeDialog-BQbEhIwL.js +1 -0
- package/dist/assets/{ExportDialog-BJu2Bpvv.js → ExportDialog-CjTbbTZJ.js} +2 -2
- package/dist/assets/OpenGraphDialog-DCwH9itM.js +1 -0
- package/dist/assets/ProjectSettings-Dg7M5xt9.js +2 -0
- package/dist/assets/SettingsDialog-e7GgsjB9.js +1 -0
- package/dist/assets/VersionHistoryDialog-D6VBzSQ0.js +3 -0
- package/dist/assets/{core-DlkL34JF.js → core-BInLG4gw.js} +1 -1
- package/dist/assets/{cssMode-DaSSFZYi.js → cssMode-DfR2qmYG.js} +1 -1
- package/dist/assets/definitions-DZpOjWKR.js +1 -0
- package/dist/assets/{editor.api-CHUMRaMm.js → editor.api-Ck8_vgQV.js} +1 -1
- package/dist/assets/{freemarker2-DQ604q2A.js → freemarker2-fVn10Wn3.js} +1 -1
- package/dist/assets/geo-D2VPjAdt.js +1 -0
- package/dist/assets/{handlebars-09pcWz8x.js → handlebars-BCSchLT2.js} +1 -1
- package/dist/assets/{html-DtIKrZiD.js → html-CVpSv_k9.js} +1 -1
- package/dist/assets/{htmlMode-DgJ_4m1_.js → htmlMode-Da4ESTv0.js} +1 -1
- package/dist/assets/{image-CtUE4_I-.js → image-BLn--oSF.js} +1 -1
- package/dist/assets/index-CMiBdEuT.js +212 -0
- package/dist/assets/index-DMIuml9a.css +1 -0
- package/dist/assets/index-client-BI2H82FJ.js +1 -0
- package/dist/assets/{javascript-kbIBYYGo.js → javascript-BpX0Gvcf.js} +1 -1
- package/dist/assets/{jsonMode-DblCG64t.js → jsonMode-CsLqaou7.js} +1 -1
- package/dist/assets/{legacy-CAj2_7QE.js → legacy-ZA7textG.js} +1 -1
- package/dist/assets/{liquid-D-qdTGhQ.js → liquid-efUz51Wf.js} +1 -1
- package/dist/assets/{lspLanguageFeatures-Bc6azcFQ.js → lspLanguageFeatures-DCi5-K0n.js} +1 -1
- package/dist/assets/math-B6hpxPJO.js +1 -0
- package/dist/assets/{mdx-TXg4xsyD.js → mdx-DP_sjGVy.js} +1 -1
- package/dist/assets/pop-CYUIjT6x.js +1 -0
- package/dist/assets/{python-C4SGyXJW.js → python-aAuP3LUi.js} +1 -1
- package/dist/assets/{razor-BZ-lEgY9.js → razor-7M6sMmC5.js} +1 -1
- package/dist/assets/{tsMode-BoaO1D7x.js → tsMode-Bf4CnoYK.js} +1 -1
- package/dist/assets/{typescript-D87dYk9k.js → typescript-ddhYBGyT.js} +1 -1
- package/dist/assets/{workers-ZrST7klJ.js → workers-X5la8DDT.js} +1 -1
- package/dist/assets/{xml-DT6r4F7G.js → xml-BzbXa3Ps.js} +1 -1
- package/dist/assets/{yaml-DxmQ8XYb.js → yaml-CXs-VzxL.js} +1 -1
- package/dist/cli/index.js +257 -229
- package/dist/index.html +6 -4
- package/package.json +1 -1
- package/dist/assets/CodePanel-EN411mp5.js +0 -2
- package/dist/assets/CustomNodeDialog-6z2n27VV.js +0 -1
- package/dist/assets/OpenGraphDialog-fMZjzIR3.js +0 -1
- package/dist/assets/ProjectSettings-BQ8PGNqo.js +0 -2
- package/dist/assets/SettingsDialog-IbYLm8Bx.js +0 -1
- package/dist/assets/VersionHistoryDialog-Bgh-q5Jg.js +0 -3
- package/dist/assets/definitions-CQBdsJYJ.js +0 -1
- package/dist/assets/geo-DcmMAcqM.js +0 -1
- package/dist/assets/index-CnylT98t.js +0 -212
- package/dist/assets/index-client-BoJgsN9M.js +0 -1
- package/dist/assets/index-ilgbOu6G.css +0 -1
- package/dist/assets/math-CY11tkoN.js +0 -1
- package/dist/assets/pop-Dr5-ARqQ.js +0 -1
package/dist/cli/index.js
CHANGED
|
@@ -212,9 +212,9 @@ function levelCount(geometry, level) {
|
|
|
212
212
|
if (level === "primitive") return geometry.primitiveCount;
|
|
213
213
|
return 1;
|
|
214
214
|
}
|
|
215
|
-
function checkName(name,
|
|
215
|
+
function checkName(name, path25) {
|
|
216
216
|
if (!NAME.test(name) || RESERVED_NAMES.has(name))
|
|
217
|
-
fail("invalid-name", `${
|
|
217
|
+
fail("invalid-name", `${path25}.${name} is not a valid attribute name`);
|
|
218
218
|
}
|
|
219
219
|
function checkAttributeSet(set, count, level) {
|
|
220
220
|
for (const [name, attribute] of Object.entries(set)) {
|
|
@@ -826,8 +826,8 @@ var init_values = __esm({
|
|
|
826
826
|
});
|
|
827
827
|
|
|
828
828
|
// packages/contracts/src/validate.ts
|
|
829
|
-
function diagnostic(code, message2,
|
|
830
|
-
return { phase: "definition", code: `definition/${code}`, message: message2, path:
|
|
829
|
+
function diagnostic(code, message2, path25) {
|
|
830
|
+
return { phase: "definition", code: `definition/${code}`, message: message2, path: path25 };
|
|
831
831
|
}
|
|
832
832
|
function isRecord2(value) {
|
|
833
833
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
@@ -842,12 +842,12 @@ function finiteJson(value) {
|
|
|
842
842
|
if (Array.isArray(value)) return value.every(finiteJson);
|
|
843
843
|
return isRecord2(value) && Object.values(value).every(finiteJson);
|
|
844
844
|
}
|
|
845
|
-
function unknownFields(value, allowed,
|
|
845
|
+
function unknownFields(value, allowed, path25) {
|
|
846
846
|
return Object.keys(value).filter((key2) => !allowed.has(key2)).map(
|
|
847
847
|
(key2) => diagnostic(
|
|
848
848
|
"unknown-field",
|
|
849
|
-
`${
|
|
850
|
-
`${
|
|
849
|
+
`${path25}.${key2} is not allowed`,
|
|
850
|
+
`${path25}.${key2}`
|
|
851
851
|
)
|
|
852
852
|
);
|
|
853
853
|
}
|
|
@@ -879,7 +879,7 @@ function validateNodeDefinition(value) {
|
|
|
879
879
|
if (!isRecord2(value))
|
|
880
880
|
return [diagnostic("not-object", "Definition must be an object")];
|
|
881
881
|
const result = unknownFields(value, TOP_FIELDS, "definition");
|
|
882
|
-
const add = (code, message2,
|
|
882
|
+
const add = (code, message2, path25) => result.push(diagnostic(code, message2, path25));
|
|
883
883
|
const environment = value.runsOn;
|
|
884
884
|
if (value.apiVersion !== 1)
|
|
885
885
|
add("api-version", "apiVersion must be 1", "apiVersion");
|
|
@@ -896,15 +896,15 @@ function validateNodeDefinition(value) {
|
|
|
896
896
|
);
|
|
897
897
|
const seen = /* @__PURE__ */ new Set();
|
|
898
898
|
for (const [index, capability] of (Array.isArray(value.capabilities) ? value.capabilities : []).entries()) {
|
|
899
|
-
const
|
|
899
|
+
const path25 = `capabilities.${index}`;
|
|
900
900
|
if (!seen.has(capability) && !allowed.includes(capability))
|
|
901
901
|
add(
|
|
902
902
|
"capability-not-allowed",
|
|
903
903
|
`${String(capability)} is not available on ${String(environment)}`,
|
|
904
|
-
|
|
904
|
+
path25
|
|
905
905
|
);
|
|
906
906
|
if (seen.has(capability))
|
|
907
|
-
add("duplicate-capability", `${String(capability)} is duplicated`,
|
|
907
|
+
add("duplicate-capability", `${String(capability)} is duplicated`, path25);
|
|
908
908
|
seen.add(capability);
|
|
909
909
|
}
|
|
910
910
|
const inward = /* @__PURE__ */ new Map();
|
|
@@ -917,31 +917,31 @@ function validateNodeDefinition(value) {
|
|
|
917
917
|
continue;
|
|
918
918
|
}
|
|
919
919
|
for (const [name, raw] of Object.entries(entries2)) {
|
|
920
|
-
const
|
|
920
|
+
const path25 = `${section}.${name}`;
|
|
921
921
|
if (!IDENTIFIER.test(name))
|
|
922
|
-
add("invalid-name", `${name} is not a valid identifier`,
|
|
923
|
-
if (RESERVED.has(name)) add("reserved-name", `${name} is reserved`,
|
|
922
|
+
add("invalid-name", `${name} is not a valid identifier`, path25);
|
|
923
|
+
if (RESERVED.has(name)) add("reserved-name", `${name} is reserved`, path25);
|
|
924
924
|
const names = section === "outputs" ? outward : inward;
|
|
925
925
|
const previous = names.get(name);
|
|
926
926
|
if (previous)
|
|
927
927
|
add(
|
|
928
928
|
"name-collision",
|
|
929
929
|
`${name} is declared in ${previous} and ${section}`,
|
|
930
|
-
|
|
930
|
+
path25
|
|
931
931
|
);
|
|
932
932
|
else names.set(name, section);
|
|
933
933
|
if (!isRecord2(raw)) {
|
|
934
|
-
add("invalid-entry", `${
|
|
934
|
+
add("invalid-entry", `${path25} must be an object`, path25);
|
|
935
935
|
continue;
|
|
936
936
|
}
|
|
937
937
|
const fields2 = section === "props" ? PROP_FIELDS : section === "outputs" ? OUTPUT_FIELDS : DATA_FIELDS;
|
|
938
938
|
if (section !== "props" && raw.kind !== "data" && raw.kind !== "trigger") {
|
|
939
939
|
add(
|
|
940
940
|
"invalid-kind",
|
|
941
|
-
`${
|
|
942
|
-
`${
|
|
941
|
+
`${path25}.kind must be data or trigger`,
|
|
942
|
+
`${path25}.kind`
|
|
943
943
|
);
|
|
944
|
-
result.push(...unknownFields(raw, fields2,
|
|
944
|
+
result.push(...unknownFields(raw, fields2, path25));
|
|
945
945
|
continue;
|
|
946
946
|
}
|
|
947
947
|
if (section !== "props" && raw.kind === "trigger") {
|
|
@@ -951,22 +951,22 @@ function validateNodeDefinition(value) {
|
|
|
951
951
|
add(
|
|
952
952
|
"trigger-extra",
|
|
953
953
|
"Trigger ports allow only kind and description",
|
|
954
|
-
|
|
954
|
+
path25
|
|
955
955
|
);
|
|
956
956
|
continue;
|
|
957
957
|
}
|
|
958
|
-
result.push(...unknownFields(raw, fields2,
|
|
958
|
+
result.push(...unknownFields(raw, fields2, path25));
|
|
959
959
|
if ("control" in raw && (typeof raw.control !== "string" || !CONTROLS.has(raw.control)))
|
|
960
960
|
add(
|
|
961
961
|
"invalid-control",
|
|
962
962
|
`${String(raw.control)} is not a Cascade control`,
|
|
963
|
-
`${
|
|
963
|
+
`${path25}.control`
|
|
964
964
|
);
|
|
965
965
|
if ("options" in raw && raw.control !== "select")
|
|
966
966
|
add(
|
|
967
967
|
"options-without-select",
|
|
968
968
|
"options require the select control",
|
|
969
|
-
`${
|
|
969
|
+
`${path25}.options`
|
|
970
970
|
);
|
|
971
971
|
if (Array.isArray(raw.options))
|
|
972
972
|
for (const [index, option] of raw.options.entries()) {
|
|
@@ -976,19 +976,19 @@ function validateNodeDefinition(value) {
|
|
|
976
976
|
add(
|
|
977
977
|
"invalid-option",
|
|
978
978
|
"a labelled option needs a value",
|
|
979
|
-
`${
|
|
979
|
+
`${path25}.options[${index}]`
|
|
980
980
|
);
|
|
981
981
|
if (typeof entry.label !== "string" || !entry.label)
|
|
982
982
|
add(
|
|
983
983
|
"invalid-option",
|
|
984
984
|
"a labelled option needs a non-empty label",
|
|
985
|
-
`${
|
|
985
|
+
`${path25}.options[${index}].label`
|
|
986
986
|
);
|
|
987
987
|
if ("disabled" in entry && typeof entry.disabled !== "boolean")
|
|
988
988
|
add(
|
|
989
989
|
"invalid-option",
|
|
990
990
|
"disabled must be a boolean",
|
|
991
|
-
`${
|
|
991
|
+
`${path25}.options[${index}].disabled`
|
|
992
992
|
);
|
|
993
993
|
}
|
|
994
994
|
const type = raw.type;
|
|
@@ -996,56 +996,56 @@ function validateNodeDefinition(value) {
|
|
|
996
996
|
add(
|
|
997
997
|
"invalid-type",
|
|
998
998
|
`${String(type)} is not a Cascade type`,
|
|
999
|
-
`${
|
|
999
|
+
`${path25}.type`
|
|
1000
1000
|
);
|
|
1001
1001
|
continue;
|
|
1002
1002
|
}
|
|
1003
1003
|
if (type === "texture" && environment !== "browser")
|
|
1004
|
-
add("texture-not-portable", "texture is browser-only", `${
|
|
1004
|
+
add("texture-not-portable", "texture is browser-only", `${path25}.type`);
|
|
1005
1005
|
if (type === "texture" && "default" in raw)
|
|
1006
1006
|
add(
|
|
1007
1007
|
"texture-default",
|
|
1008
1008
|
"texture cannot have a default",
|
|
1009
|
-
`${
|
|
1009
|
+
`${path25}.default`
|
|
1010
1010
|
);
|
|
1011
1011
|
if (section === "props" && !("default" in raw))
|
|
1012
|
-
add("missing-default", "Props require defaults", `${
|
|
1012
|
+
add("missing-default", "Props require defaults", `${path25}.default`);
|
|
1013
1013
|
if ("default" in raw && !finiteJson(raw.default))
|
|
1014
1014
|
add(
|
|
1015
1015
|
"invalid-default",
|
|
1016
1016
|
"Default must be finite JSON",
|
|
1017
|
-
`${
|
|
1017
|
+
`${path25}.default`
|
|
1018
1018
|
);
|
|
1019
1019
|
else if ("default" in raw && !defaultMatches(type, raw.default))
|
|
1020
1020
|
add(
|
|
1021
1021
|
"default-type",
|
|
1022
1022
|
`Default does not match ${type}`,
|
|
1023
|
-
`${
|
|
1023
|
+
`${path25}.default`
|
|
1024
1024
|
);
|
|
1025
1025
|
if (type === "int" && "default" in raw && (!Number.isFinite(raw.default) || !Number.isInteger(raw.default)))
|
|
1026
1026
|
add(
|
|
1027
1027
|
"non-integer",
|
|
1028
1028
|
"Integer defaults must be finite integers",
|
|
1029
|
-
`${
|
|
1029
|
+
`${path25}.default`
|
|
1030
1030
|
);
|
|
1031
1031
|
if ("step" in raw && (typeof raw.step !== "number" || !Number.isFinite(raw.step) || raw.step <= 0))
|
|
1032
|
-
add("invalid-step", "step must be greater than zero", `${
|
|
1032
|
+
add("invalid-step", "step must be greater than zero", `${path25}.step`);
|
|
1033
1033
|
if (section === "props" && "expression" in raw && (typeof raw.expression !== "string" || raw.expression.length === 0))
|
|
1034
1034
|
add(
|
|
1035
1035
|
"invalid-expression",
|
|
1036
1036
|
"expression must be a non-empty string",
|
|
1037
|
-
`${
|
|
1037
|
+
`${path25}.expression`
|
|
1038
1038
|
);
|
|
1039
1039
|
for (const field of ["min", "max"]) {
|
|
1040
1040
|
if (field in raw && (typeof raw[field] !== "number" || !Number.isFinite(raw[field])))
|
|
1041
1041
|
add(
|
|
1042
1042
|
`invalid-${field}`,
|
|
1043
1043
|
`${field} must be a finite number`,
|
|
1044
|
-
`${
|
|
1044
|
+
`${path25}.${field}`
|
|
1045
1045
|
);
|
|
1046
1046
|
}
|
|
1047
1047
|
if (typeof raw.min === "number" && typeof raw.max === "number" && raw.min > raw.max)
|
|
1048
|
-
add("invalid-range", "min must not exceed max",
|
|
1048
|
+
add("invalid-range", "min must not exceed max", path25);
|
|
1049
1049
|
}
|
|
1050
1050
|
}
|
|
1051
1051
|
return result;
|
|
@@ -1741,10 +1741,10 @@ var init_evaluator = __esm({
|
|
|
1741
1741
|
fframe: this.timeState.frameFraction,
|
|
1742
1742
|
fps: this.timeState.fps,
|
|
1743
1743
|
self: node,
|
|
1744
|
-
ch: (
|
|
1745
|
-
chs: (
|
|
1746
|
-
chv: (
|
|
1747
|
-
opexist: (
|
|
1744
|
+
ch: (path25) => this.ch(node, path25),
|
|
1745
|
+
chs: (path25) => this.chs(node, path25),
|
|
1746
|
+
chv: (path25) => this.chv(node, path25),
|
|
1747
|
+
opexist: (path25) => this.scope?.nodeExists(node, path25) ? 1 : 0,
|
|
1748
1748
|
opinput: (index) => this.scope?.inputNode(node, index) ?? null,
|
|
1749
1749
|
fit,
|
|
1750
1750
|
fit01,
|
|
@@ -1761,8 +1761,8 @@ var init_evaluator = __esm({
|
|
|
1761
1761
|
};
|
|
1762
1762
|
}
|
|
1763
1763
|
// ============ Channel functions ============
|
|
1764
|
-
ch(node,
|
|
1765
|
-
const resolved = this.resolveParam(node,
|
|
1764
|
+
ch(node, path25) {
|
|
1765
|
+
const resolved = this.resolveParam(node, path25);
|
|
1766
1766
|
if (!resolved) return 0;
|
|
1767
1767
|
const value = resolved.value;
|
|
1768
1768
|
if (typeof value === "number") return value;
|
|
@@ -1770,13 +1770,13 @@ var init_evaluator = __esm({
|
|
|
1770
1770
|
if (typeof value === "boolean") return value ? 1 : 0;
|
|
1771
1771
|
return 0;
|
|
1772
1772
|
}
|
|
1773
|
-
chs(node,
|
|
1774
|
-
const resolved = this.resolveParam(node,
|
|
1773
|
+
chs(node, path25) {
|
|
1774
|
+
const resolved = this.resolveParam(node, path25);
|
|
1775
1775
|
if (!resolved) return "";
|
|
1776
1776
|
return String(resolved.value ?? "");
|
|
1777
1777
|
}
|
|
1778
|
-
chv(node,
|
|
1779
|
-
const resolved = this.resolveParam(node,
|
|
1778
|
+
chv(node, path25) {
|
|
1779
|
+
const resolved = this.resolveParam(node, path25);
|
|
1780
1780
|
if (!resolved) return [];
|
|
1781
1781
|
const value = resolved.value;
|
|
1782
1782
|
if (Array.isArray(value)) {
|
|
@@ -1785,12 +1785,12 @@ var init_evaluator = __esm({
|
|
|
1785
1785
|
if (typeof value === "number") return [value];
|
|
1786
1786
|
return [];
|
|
1787
1787
|
}
|
|
1788
|
-
resolveParam(node,
|
|
1789
|
-
return this.scope?.resolveParam(node,
|
|
1788
|
+
resolveParam(node, path25) {
|
|
1789
|
+
return this.scope?.resolveParam(node, path25) ?? null;
|
|
1790
1790
|
}
|
|
1791
1791
|
/** True if a referenced path resolves from this node. */
|
|
1792
|
-
validatePath(fromNode,
|
|
1793
|
-
return this.resolveParam(fromNode,
|
|
1792
|
+
validatePath(fromNode, path25) {
|
|
1793
|
+
return this.resolveParam(fromNode, path25) !== null;
|
|
1794
1794
|
}
|
|
1795
1795
|
/** Parameter paths referenced through ch/chs/chv. */
|
|
1796
1796
|
extractDependencies(expression) {
|
|
@@ -1829,14 +1829,14 @@ function geometryError(code, message2) {
|
|
|
1829
1829
|
function attributeSet(geometry, level) {
|
|
1830
1830
|
return geometry[level];
|
|
1831
1831
|
}
|
|
1832
|
-
function numericAttribute(attribute,
|
|
1832
|
+
function numericAttribute(attribute, path25, sizes) {
|
|
1833
1833
|
if (attribute === void 0) return void 0;
|
|
1834
1834
|
if (isStringAttribute(attribute))
|
|
1835
|
-
geometryError("attribute-storage", `${
|
|
1835
|
+
geometryError("attribute-storage", `${path25} must be numeric`);
|
|
1836
1836
|
if (sizes !== void 0 && !sizes.includes(attribute.size))
|
|
1837
1837
|
geometryError(
|
|
1838
1838
|
"attribute-size",
|
|
1839
|
-
`${
|
|
1839
|
+
`${path25} has size ${attribute.size}; expected ${sizes.join(" or ")}`
|
|
1840
1840
|
);
|
|
1841
1841
|
return attribute;
|
|
1842
1842
|
}
|
|
@@ -2647,7 +2647,7 @@ function geometryToSvg(geometry, options2 = {}) {
|
|
|
2647
2647
|
if (mask2[primitive] === 1 && assigned[primitive] === -1)
|
|
2648
2648
|
assigned[primitive] = index;
|
|
2649
2649
|
}
|
|
2650
|
-
const
|
|
2650
|
+
const path25 = (primitive) => {
|
|
2651
2651
|
const attributes = [`d="${pathData(geometry, primitive, number)}"`];
|
|
2652
2652
|
const paint = paintOf(colour, primitive, "primitive");
|
|
2653
2653
|
if (paint !== void 0) {
|
|
@@ -2666,13 +2666,13 @@ function geometryToSvg(geometry, options2 = {}) {
|
|
|
2666
2666
|
const body = [];
|
|
2667
2667
|
if (names.length === 0) {
|
|
2668
2668
|
for (let primitive = 0; primitive < geometry.primitiveCount; primitive += 1)
|
|
2669
|
-
body.push(indent(
|
|
2669
|
+
body.push(indent(path25(primitive), 2));
|
|
2670
2670
|
} else {
|
|
2671
2671
|
for (let index = 0; index < names.length; index += 1) {
|
|
2672
2672
|
const members = [];
|
|
2673
2673
|
for (let primitive = 0; primitive < geometry.primitiveCount; primitive += 1)
|
|
2674
2674
|
if (assigned[primitive] === index)
|
|
2675
|
-
members.push(indent(
|
|
2675
|
+
members.push(indent(path25(primitive), 3));
|
|
2676
2676
|
body.push(
|
|
2677
2677
|
indent(`<g id="${escapeXml(names[index])}">`, 2),
|
|
2678
2678
|
...members,
|
|
@@ -2681,7 +2681,7 @@ function geometryToSvg(geometry, options2 = {}) {
|
|
|
2681
2681
|
}
|
|
2682
2682
|
const rest = [];
|
|
2683
2683
|
for (let primitive = 0; primitive < geometry.primitiveCount; primitive += 1)
|
|
2684
|
-
if (assigned[primitive] === -1) rest.push(indent(
|
|
2684
|
+
if (assigned[primitive] === -1) rest.push(indent(path25(primitive), 3));
|
|
2685
2685
|
if (rest.length > 0)
|
|
2686
2686
|
body.push(
|
|
2687
2687
|
indent(`<g id="${UNGROUPED}">`, 2),
|
|
@@ -2788,11 +2788,11 @@ function validateOptions(options2) {
|
|
|
2788
2788
|
if (!Number.isSafeInteger(precision) || precision < 0 || precision > 15)
|
|
2789
2789
|
geometryError("svg-precision", "precision must be an integer from 0 to 15");
|
|
2790
2790
|
}
|
|
2791
|
-
function validateRange(attribute,
|
|
2791
|
+
function validateRange(attribute, path25, accepts, expectation) {
|
|
2792
2792
|
if (attribute === void 0) return;
|
|
2793
2793
|
for (const value of attribute.data)
|
|
2794
2794
|
if (!accepts(value))
|
|
2795
|
-
geometryError("attribute-value", `${
|
|
2795
|
+
geometryError("attribute-value", `${path25} values must be ${expectation}`);
|
|
2796
2796
|
}
|
|
2797
2797
|
function indent(line2, depth) {
|
|
2798
2798
|
return `${" ".repeat(depth)}${line2}`;
|
|
@@ -3081,8 +3081,8 @@ var init_resolve = __esm({
|
|
|
3081
3081
|
});
|
|
3082
3082
|
|
|
3083
3083
|
// packages/runtime/src/params/animator.ts
|
|
3084
|
-
function split(
|
|
3085
|
-
return String(
|
|
3084
|
+
function split(path25) {
|
|
3085
|
+
return String(path25 ?? "").split("/").filter((segment) => segment.length > 0 && segment !== ".");
|
|
3086
3086
|
}
|
|
3087
3087
|
var PropAnimator;
|
|
3088
3088
|
var init_animator = __esm({
|
|
@@ -3150,8 +3150,8 @@ var init_animator = __esm({
|
|
|
3150
3150
|
*/
|
|
3151
3151
|
scope() {
|
|
3152
3152
|
return {
|
|
3153
|
-
resolveParam: (from,
|
|
3154
|
-
const segments = split(
|
|
3153
|
+
resolveParam: (from, path25) => {
|
|
3154
|
+
const segments = split(path25);
|
|
3155
3155
|
if (!segments.length) return null;
|
|
3156
3156
|
const name = segments[segments.length - 1];
|
|
3157
3157
|
const owner = this.owner(from, segments.slice(0, -1));
|
|
@@ -3161,8 +3161,8 @@ var init_animator = __esm({
|
|
|
3161
3161
|
if (name in owner.inputs) return { value: owner.inputs[name] };
|
|
3162
3162
|
return null;
|
|
3163
3163
|
},
|
|
3164
|
-
nodeExists: (from,
|
|
3165
|
-
const segments = split(
|
|
3164
|
+
nodeExists: (from, path25) => {
|
|
3165
|
+
const segments = split(path25);
|
|
3166
3166
|
if (!segments.length) return false;
|
|
3167
3167
|
const last = segments[segments.length - 1];
|
|
3168
3168
|
if (last === "..") return true;
|
|
@@ -5479,12 +5479,12 @@ function buildTrails(history, current, options2 = {}) {
|
|
|
5479
5479
|
for (const frame of frames) {
|
|
5480
5480
|
for (let index = 0; index < frame.id.length; index += 1) {
|
|
5481
5481
|
const id = frame.id[index];
|
|
5482
|
-
const
|
|
5483
|
-
|
|
5482
|
+
const path25 = paths.get(id) ?? [];
|
|
5483
|
+
path25.push(
|
|
5484
5484
|
frame.position[index * frame.size],
|
|
5485
5485
|
frame.position[index * frame.size + 1]
|
|
5486
5486
|
);
|
|
5487
|
-
paths.set(id,
|
|
5487
|
+
paths.set(id, path25);
|
|
5488
5488
|
}
|
|
5489
5489
|
}
|
|
5490
5490
|
if (result === "velocity") {
|
|
@@ -5492,11 +5492,11 @@ function buildTrails(history, current, options2 = {}) {
|
|
|
5492
5492
|
}
|
|
5493
5493
|
const builder = new GeometryBuilder({ positionSize: 2 });
|
|
5494
5494
|
const trailIds = [];
|
|
5495
|
-
for (const [id,
|
|
5496
|
-
if (
|
|
5495
|
+
for (const [id, path25] of paths) {
|
|
5496
|
+
if (path25.length < 4) continue;
|
|
5497
5497
|
const points = [];
|
|
5498
|
-
for (let at = 0; at <
|
|
5499
|
-
points.push(builder.addPoint(
|
|
5498
|
+
for (let at = 0; at < path25.length; at += 2) {
|
|
5499
|
+
points.push(builder.addPoint(path25[at], path25[at + 1]));
|
|
5500
5500
|
}
|
|
5501
5501
|
builder.addPrimitive(points, { closed: false, kind: "poly" });
|
|
5502
5502
|
trailIds.push(id);
|
|
@@ -5541,11 +5541,11 @@ function withDerivedVelocity(current, paths, velocityscale) {
|
|
|
5541
5541
|
const ids = current.point.id?.data;
|
|
5542
5542
|
const velocity = new Float32Array(current.pointCount * size);
|
|
5543
5543
|
for (let index = 0; index < current.pointCount; index += 1) {
|
|
5544
|
-
const
|
|
5545
|
-
if (!
|
|
5546
|
-
const last =
|
|
5547
|
-
velocity[index * size] = (
|
|
5548
|
-
velocity[index * size + 1] = (
|
|
5544
|
+
const path25 = ids ? paths.get(Number(ids[index])) : void 0;
|
|
5545
|
+
if (!path25 || path25.length < 4) continue;
|
|
5546
|
+
const last = path25.length;
|
|
5547
|
+
velocity[index * size] = (path25[last - 2] - path25[last - 4]) * velocityscale;
|
|
5548
|
+
velocity[index * size + 1] = (path25[last - 1] - path25[last - 3]) * velocityscale;
|
|
5549
5549
|
}
|
|
5550
5550
|
return {
|
|
5551
5551
|
...current,
|
|
@@ -7063,16 +7063,16 @@ function cloneValue(value, ancestors) {
|
|
|
7063
7063
|
ancestors.delete(value);
|
|
7064
7064
|
return Object.freeze(clone);
|
|
7065
7065
|
}
|
|
7066
|
-
function runtimeValue(value, type, allowUndefined,
|
|
7066
|
+
function runtimeValue(value, type, allowUndefined, path25) {
|
|
7067
7067
|
if (value === void 0) {
|
|
7068
7068
|
if (allowUndefined) return void 0;
|
|
7069
|
-
misuse("runtime/value-type", `${
|
|
7069
|
+
misuse("runtime/value-type", `${path25} requires a ${type} value`);
|
|
7070
7070
|
}
|
|
7071
7071
|
const tupleLength = TUPLE_LENGTHS[type];
|
|
7072
7072
|
const valid = type === "float" && typeof value === "number" && Number.isFinite(value) || type === "int" && typeof value === "number" && Number.isInteger(value) || type === "bool" && typeof value === "boolean" || type === "string" && typeof value === "string" || tupleLength !== void 0 && Array.isArray(value) && value.length === tupleLength && value.every(
|
|
7073
7073
|
(item) => type.endsWith("i") ? typeof item === "number" && Number.isInteger(item) : typeof item === "number" && Number.isFinite(item)
|
|
7074
7074
|
) || !tupleLength && type !== "float" && type !== "int" && type !== "bool" && type !== "string";
|
|
7075
|
-
if (!valid) misuse("runtime/value-type", `${
|
|
7075
|
+
if (!valid) misuse("runtime/value-type", `${path25} is not a valid ${type}`);
|
|
7076
7076
|
return snapshot(value);
|
|
7077
7077
|
}
|
|
7078
7078
|
var PREFLIGHT_WARNING_CODES, RUN_TOLERATED_CODES, MutableAbortSignal, Runtime, Graph, TUPLE_LENGTHS;
|
|
@@ -8352,32 +8352,32 @@ function extractNodeDefinition(source, fileName, ts4) {
|
|
|
8352
8352
|
diagnostics: [error.diagnostic]
|
|
8353
8353
|
};
|
|
8354
8354
|
}
|
|
8355
|
-
function read(node,
|
|
8355
|
+
function read(node, path25, depth) {
|
|
8356
8356
|
if (++visited > MAX_NODES)
|
|
8357
8357
|
throw extraction(
|
|
8358
8358
|
node,
|
|
8359
8359
|
"definition/size-limit",
|
|
8360
8360
|
"Definition exceeds 10,000 syntax nodes",
|
|
8361
|
-
|
|
8361
|
+
path25
|
|
8362
8362
|
);
|
|
8363
8363
|
if (depth > MAX_DEPTH)
|
|
8364
8364
|
throw extraction(
|
|
8365
8365
|
node,
|
|
8366
8366
|
"definition/depth-limit",
|
|
8367
8367
|
"Definition exceeds 32 levels",
|
|
8368
|
-
|
|
8368
|
+
path25
|
|
8369
8369
|
);
|
|
8370
8370
|
if (ts4.isParenthesizedExpression(node) || ts4.isSatisfiesExpression(node))
|
|
8371
|
-
return read(node.expression,
|
|
8371
|
+
return read(node.expression, path25, depth + 1);
|
|
8372
8372
|
if (ts4.isAsExpression(node)) {
|
|
8373
8373
|
if (node.type.getText(file) !== "const")
|
|
8374
8374
|
throw extraction(
|
|
8375
8375
|
node.type,
|
|
8376
8376
|
"definition/non-literal",
|
|
8377
8377
|
"Only 'as const' assertions are allowed",
|
|
8378
|
-
|
|
8378
|
+
path25
|
|
8379
8379
|
);
|
|
8380
|
-
return read(node.expression,
|
|
8380
|
+
return read(node.expression, path25, depth + 1);
|
|
8381
8381
|
}
|
|
8382
8382
|
if (ts4.isStringLiteral(node) || ts4.isNoSubstitutionTemplateLiteral(node))
|
|
8383
8383
|
return node.text;
|
|
@@ -8394,9 +8394,9 @@ function extractNodeDefinition(source, fileName, ts4) {
|
|
|
8394
8394
|
element,
|
|
8395
8395
|
"definition/spread",
|
|
8396
8396
|
"Spreads are not allowed",
|
|
8397
|
-
`${
|
|
8397
|
+
`${path25}.${index}`
|
|
8398
8398
|
);
|
|
8399
|
-
return read(element, `${
|
|
8399
|
+
return read(element, `${path25}.${index}`, depth + 1);
|
|
8400
8400
|
});
|
|
8401
8401
|
if (ts4.isObjectLiteralExpression(node)) {
|
|
8402
8402
|
const object = /* @__PURE__ */ Object.create(null);
|
|
@@ -8407,14 +8407,14 @@ function extractNodeDefinition(source, fileName, ts4) {
|
|
|
8407
8407
|
property,
|
|
8408
8408
|
"definition/spread",
|
|
8409
8409
|
"Spreads are not allowed",
|
|
8410
|
-
|
|
8410
|
+
path25
|
|
8411
8411
|
);
|
|
8412
8412
|
if (!ts4.isPropertyAssignment(property) || property.name && ts4.isComputedPropertyName(property.name))
|
|
8413
8413
|
throw extraction(
|
|
8414
8414
|
property,
|
|
8415
8415
|
"definition/non-literal",
|
|
8416
8416
|
"Only explicit properties are allowed",
|
|
8417
|
-
|
|
8417
|
+
path25
|
|
8418
8418
|
);
|
|
8419
8419
|
const key2 = ts4.isIdentifier(property.name) || ts4.isStringLiteral(property.name) || ts4.isNumericLiteral(property.name) ? property.name.text : void 0;
|
|
8420
8420
|
if (key2 === void 0)
|
|
@@ -8422,17 +8422,17 @@ function extractNodeDefinition(source, fileName, ts4) {
|
|
|
8422
8422
|
property,
|
|
8423
8423
|
"definition/non-literal",
|
|
8424
8424
|
"Property name must be literal",
|
|
8425
|
-
|
|
8425
|
+
path25
|
|
8426
8426
|
);
|
|
8427
8427
|
if (keys.has(key2))
|
|
8428
8428
|
throw extraction(
|
|
8429
8429
|
property.name,
|
|
8430
8430
|
"definition/duplicate-key",
|
|
8431
8431
|
`Duplicate key ${key2}`,
|
|
8432
|
-
`${
|
|
8432
|
+
`${path25}.${key2}`
|
|
8433
8433
|
);
|
|
8434
8434
|
keys.add(key2);
|
|
8435
|
-
object[key2] = read(property.initializer, `${
|
|
8435
|
+
object[key2] = read(property.initializer, `${path25}.${key2}`, depth + 1);
|
|
8436
8436
|
}
|
|
8437
8437
|
return object;
|
|
8438
8438
|
}
|
|
@@ -8440,19 +8440,19 @@ function extractNodeDefinition(source, fileName, ts4) {
|
|
|
8440
8440
|
node,
|
|
8441
8441
|
"definition/non-literal",
|
|
8442
8442
|
`Unsupported ${ts4.SyntaxKind[node.kind]}`,
|
|
8443
|
-
|
|
8443
|
+
path25
|
|
8444
8444
|
);
|
|
8445
8445
|
}
|
|
8446
8446
|
function location(node) {
|
|
8447
8447
|
const point = file.getLineAndCharacterOfPosition(node.getStart(file));
|
|
8448
8448
|
return { line: point.line + 1, column: point.character + 1 };
|
|
8449
8449
|
}
|
|
8450
|
-
function extraction(node, code, message2,
|
|
8450
|
+
function extraction(node, code, message2, path25) {
|
|
8451
8451
|
return new ExtractionFailure({
|
|
8452
8452
|
phase: "definition",
|
|
8453
8453
|
code,
|
|
8454
8454
|
message: message2,
|
|
8455
|
-
path:
|
|
8455
|
+
path: path25,
|
|
8456
8456
|
file: fileName,
|
|
8457
8457
|
...location(node)
|
|
8458
8458
|
});
|
|
@@ -9568,17 +9568,16 @@ export function execute(node, graph) {
|
|
|
9568
9568
|
import fs6 from "node:fs/promises";
|
|
9569
9569
|
import path6 from "node:path";
|
|
9570
9570
|
function createNodeFileCapability(project) {
|
|
9571
|
-
const
|
|
9572
|
-
|
|
9573
|
-
|
|
9574
|
-
|
|
9575
|
-
|
|
9576
|
-
|
|
9577
|
-
|
|
9578
|
-
|
|
9579
|
-
return full;
|
|
9571
|
+
const within3 = (relative, what) => {
|
|
9572
|
+
try {
|
|
9573
|
+
return project.resolve(relative.replace(/^\.?\//, ""));
|
|
9574
|
+
} catch (error) {
|
|
9575
|
+
throw new Error(
|
|
9576
|
+
`files: ${what} outside the project is refused \u2014 ${relative} (${error instanceof Error ? error.message : String(error)})`
|
|
9577
|
+
);
|
|
9578
|
+
}
|
|
9580
9579
|
};
|
|
9581
|
-
const cacheOnly =
|
|
9580
|
+
const cacheOnly = (relative) => {
|
|
9582
9581
|
const clean = relative.replace(/^\.?\//, "");
|
|
9583
9582
|
if (!clean.startsWith(".cascade-cache/"))
|
|
9584
9583
|
throw new Error(
|
|
@@ -9592,17 +9591,17 @@ function createNodeFileCapability(project) {
|
|
|
9592
9591
|
return {
|
|
9593
9592
|
async read(relative, options2) {
|
|
9594
9593
|
live(options2);
|
|
9595
|
-
return new Uint8Array(await fs6.readFile(
|
|
9594
|
+
return new Uint8Array(await fs6.readFile(within3(relative, "reading")));
|
|
9596
9595
|
},
|
|
9597
9596
|
async write(relative, data, options2) {
|
|
9598
9597
|
live(options2);
|
|
9599
|
-
const full =
|
|
9598
|
+
const full = cacheOnly(relative);
|
|
9600
9599
|
await fs6.mkdir(path6.dirname(full), { recursive: true });
|
|
9601
9600
|
await fs6.writeFile(full, data);
|
|
9602
9601
|
},
|
|
9603
9602
|
async list(relative, options2) {
|
|
9604
9603
|
live(options2);
|
|
9605
|
-
const full =
|
|
9604
|
+
const full = within3(relative, "listing");
|
|
9606
9605
|
try {
|
|
9607
9606
|
const entries2 = await fs6.readdir(full, { withFileTypes: true });
|
|
9608
9607
|
return entries2.map((entry) => entry.isDirectory() ? `${entry.name}/` : entry.name).sort();
|
|
@@ -9614,7 +9613,7 @@ function createNodeFileCapability(project) {
|
|
|
9614
9613
|
async stat(relative, options2) {
|
|
9615
9614
|
live(options2);
|
|
9616
9615
|
try {
|
|
9617
|
-
const stats = await fs6.stat(
|
|
9616
|
+
const stats = await fs6.stat(within3(relative, "reading"));
|
|
9618
9617
|
return { size: stats.size, modifiedAt: stats.mtimeMs };
|
|
9619
9618
|
} catch (error) {
|
|
9620
9619
|
if (error.code === "ENOENT") return null;
|
|
@@ -9623,22 +9622,6 @@ function createNodeFileCapability(project) {
|
|
|
9623
9622
|
}
|
|
9624
9623
|
};
|
|
9625
9624
|
}
|
|
9626
|
-
async function realOrSelf(full) {
|
|
9627
|
-
let current = full;
|
|
9628
|
-
const tail = [];
|
|
9629
|
-
for (let depth = 0; depth < 64; depth += 1) {
|
|
9630
|
-
try {
|
|
9631
|
-
const real = await fs6.realpath(current);
|
|
9632
|
-
return tail.length ? path6.join(real, ...tail.reverse()) : real;
|
|
9633
|
-
} catch {
|
|
9634
|
-
const parent = path6.dirname(current);
|
|
9635
|
-
if (parent === current) return full;
|
|
9636
|
-
tail.push(path6.basename(current));
|
|
9637
|
-
current = parent;
|
|
9638
|
-
}
|
|
9639
|
-
}
|
|
9640
|
-
return full;
|
|
9641
|
-
}
|
|
9642
9625
|
var init_nodeFiles = __esm({
|
|
9643
9626
|
"src/cli/nodeFiles.ts"() {
|
|
9644
9627
|
"use strict";
|
|
@@ -11038,6 +11021,8 @@ var init_git = __esm({
|
|
|
11038
11021
|
|
|
11039
11022
|
// server/src/routes/graph.ts
|
|
11040
11023
|
import { Router } from "express";
|
|
11024
|
+
import fs14 from "node:fs/promises";
|
|
11025
|
+
import path17 from "node:path";
|
|
11041
11026
|
function handleError(res, err) {
|
|
11042
11027
|
if (err instanceof PathSafetyError) {
|
|
11043
11028
|
res.status(400).json({ error: err.message });
|
|
@@ -11090,6 +11075,42 @@ function createGraphRouter(project) {
|
|
|
11090
11075
|
handleError(res, err);
|
|
11091
11076
|
}
|
|
11092
11077
|
});
|
|
11078
|
+
router.get("/:filename/workspace", async (req, res) => {
|
|
11079
|
+
try {
|
|
11080
|
+
const target = workspacePath(project, req.params.filename);
|
|
11081
|
+
await fs14.access(project.resolve(req.params.filename));
|
|
11082
|
+
let content;
|
|
11083
|
+
try {
|
|
11084
|
+
content = await fs14.readFile(target, "utf-8");
|
|
11085
|
+
} catch (err) {
|
|
11086
|
+
if (err?.code === "ENOENT") {
|
|
11087
|
+
res.json(null);
|
|
11088
|
+
return;
|
|
11089
|
+
}
|
|
11090
|
+
throw err;
|
|
11091
|
+
}
|
|
11092
|
+
res.type("application/json").send(content);
|
|
11093
|
+
} catch (err) {
|
|
11094
|
+
handleError(res, err);
|
|
11095
|
+
}
|
|
11096
|
+
});
|
|
11097
|
+
router.put("/:filename/workspace", async (req, res) => {
|
|
11098
|
+
try {
|
|
11099
|
+
const body = req.body;
|
|
11100
|
+
if (!body || typeof body !== "object" || Array.isArray(body) || !body.layout || typeof body.layout !== "object") {
|
|
11101
|
+
res.status(400).json({ error: "a workspace is an object with a layout" });
|
|
11102
|
+
return;
|
|
11103
|
+
}
|
|
11104
|
+
const slot = req.query.slot === "failed" ? "failed" : null;
|
|
11105
|
+
const target = workspacePath(project, req.params.filename, slot);
|
|
11106
|
+
const temporary = `${target}.${process.pid}.tmp`;
|
|
11107
|
+
await fs14.writeFile(temporary, JSON.stringify(body, null, 1), "utf-8");
|
|
11108
|
+
await fs14.rename(temporary, target);
|
|
11109
|
+
res.json({ ok: true, file: path17.basename(target) });
|
|
11110
|
+
} catch (err) {
|
|
11111
|
+
handleError(res, err);
|
|
11112
|
+
}
|
|
11113
|
+
});
|
|
11093
11114
|
router.get("/:filename/versions", async (req, res) => {
|
|
11094
11115
|
try {
|
|
11095
11116
|
const filename = req.params.filename;
|
|
@@ -11127,6 +11148,13 @@ function createGraphRouter(project) {
|
|
|
11127
11148
|
});
|
|
11128
11149
|
return router;
|
|
11129
11150
|
}
|
|
11151
|
+
function workspacePath(project, filename, slot = null) {
|
|
11152
|
+
if (!filename.endsWith(".cascade") || filename !== path17.basename(filename)) {
|
|
11153
|
+
throw new PathSafetyError(`not a .cascade file: ${filename}`);
|
|
11154
|
+
}
|
|
11155
|
+
const stem = filename.slice(0, -".cascade".length);
|
|
11156
|
+
return project.resolve(`${stem}.workspace${slot ? `.${slot}` : ""}.json`);
|
|
11157
|
+
}
|
|
11130
11158
|
function saveCommitMessage(filename, at = /* @__PURE__ */ new Date()) {
|
|
11131
11159
|
const time = at.toLocaleTimeString("en-GB", { hour: "2-digit", minute: "2-digit", hour12: false });
|
|
11132
11160
|
return `Saved ${filename} ${time}`;
|
|
@@ -11143,8 +11171,8 @@ var init_graph = __esm({
|
|
|
11143
11171
|
// server/src/routes/assets.ts
|
|
11144
11172
|
import { Router as Router2 } from "express";
|
|
11145
11173
|
import multer from "multer";
|
|
11146
|
-
import
|
|
11147
|
-
import
|
|
11174
|
+
import path18 from "path";
|
|
11175
|
+
import fs15 from "fs/promises";
|
|
11148
11176
|
function handleError2(res, err) {
|
|
11149
11177
|
if (err instanceof PathSafetyError) {
|
|
11150
11178
|
res.status(400).json({ error: err.message });
|
|
@@ -11160,8 +11188,8 @@ function createAssetsRouter(project) {
|
|
|
11160
11188
|
let assetType = "data";
|
|
11161
11189
|
if (file.mimetype.startsWith("image/")) assetType = "images";
|
|
11162
11190
|
else if (file.mimetype.startsWith("audio/")) assetType = "audio";
|
|
11163
|
-
const dir =
|
|
11164
|
-
await
|
|
11191
|
+
const dir = path18.join(assetsRoot, assetType);
|
|
11192
|
+
await fs15.mkdir(dir, { recursive: true });
|
|
11165
11193
|
cb(null, dir);
|
|
11166
11194
|
},
|
|
11167
11195
|
filename: (_req, file, cb) => cb(null, file.originalname)
|
|
@@ -11172,7 +11200,7 @@ function createAssetsRouter(project) {
|
|
|
11172
11200
|
res.status(400).json({ error: "no file uploaded" });
|
|
11173
11201
|
return;
|
|
11174
11202
|
}
|
|
11175
|
-
const relativePath =
|
|
11203
|
+
const relativePath = path18.relative(assetsRoot, req.file.path);
|
|
11176
11204
|
res.json({
|
|
11177
11205
|
id: req.file.filename,
|
|
11178
11206
|
path: `./assets/${relativePath}`,
|
|
@@ -11198,7 +11226,7 @@ function createAssetsRouter(project) {
|
|
|
11198
11226
|
try {
|
|
11199
11227
|
const rel = req.params.assetPath?.join("/") ?? "";
|
|
11200
11228
|
const full = resolveWithinRoot(assetsRoot, rel);
|
|
11201
|
-
await
|
|
11229
|
+
await fs15.unlink(full);
|
|
11202
11230
|
res.json({ ok: true });
|
|
11203
11231
|
} catch (err) {
|
|
11204
11232
|
handleError2(res, err);
|
|
@@ -11214,10 +11242,10 @@ var init_assets = __esm({
|
|
|
11214
11242
|
});
|
|
11215
11243
|
|
|
11216
11244
|
// server/src/nodeWatch.ts
|
|
11217
|
-
import
|
|
11218
|
-
import
|
|
11245
|
+
import fs16 from "node:fs";
|
|
11246
|
+
import path19 from "node:path";
|
|
11219
11247
|
function moduleNameFor(relative) {
|
|
11220
|
-
const segments = relative.split(
|
|
11248
|
+
const segments = relative.split(path19.sep).filter(Boolean);
|
|
11221
11249
|
if (segments.length < 2) return null;
|
|
11222
11250
|
const name = segments[0];
|
|
11223
11251
|
if (!name || name.startsWith(".")) return null;
|
|
@@ -11239,9 +11267,9 @@ function createNodeWatcher(project) {
|
|
|
11239
11267
|
);
|
|
11240
11268
|
}
|
|
11241
11269
|
function watch(directory, scope) {
|
|
11242
|
-
if (!
|
|
11270
|
+
if (!fs16.existsSync(directory)) return;
|
|
11243
11271
|
try {
|
|
11244
|
-
const watcher =
|
|
11272
|
+
const watcher = fs16.watch(directory, { recursive: true }, (_event, filename) => {
|
|
11245
11273
|
if (!filename) return;
|
|
11246
11274
|
if (scope === "shared") {
|
|
11247
11275
|
emit(ALL_MODULES);
|
|
@@ -11258,8 +11286,8 @@ function createNodeWatcher(project) {
|
|
|
11258
11286
|
}
|
|
11259
11287
|
watch(project.resolve("nodes"), "project");
|
|
11260
11288
|
try {
|
|
11261
|
-
const sharedNodes =
|
|
11262
|
-
watch(
|
|
11289
|
+
const sharedNodes = fs16.realpathSync(path19.join(project.root, "shared"));
|
|
11290
|
+
watch(path19.join(sharedNodes, "nodes"), "shared");
|
|
11263
11291
|
} catch {
|
|
11264
11292
|
}
|
|
11265
11293
|
return {
|
|
@@ -11929,15 +11957,15 @@ var init_eventBuffer = __esm({
|
|
|
11929
11957
|
});
|
|
11930
11958
|
|
|
11931
11959
|
// server/src/agent/allowlist.ts
|
|
11932
|
-
import
|
|
11960
|
+
import fs17 from "node:fs";
|
|
11933
11961
|
import os4 from "node:os";
|
|
11934
|
-
import
|
|
11962
|
+
import path20 from "node:path";
|
|
11935
11963
|
function allowlistHint(root, alias) {
|
|
11936
11964
|
return `Add this under "commands" in ${root}/cascade.json: "${alias}": "<path>"`;
|
|
11937
11965
|
}
|
|
11938
11966
|
function readManifest(root) {
|
|
11939
11967
|
try {
|
|
11940
|
-
return JSON.parse(
|
|
11968
|
+
return JSON.parse(fs17.readFileSync(path20.join(root, "cascade.json"), "utf8"));
|
|
11941
11969
|
} catch {
|
|
11942
11970
|
return {};
|
|
11943
11971
|
}
|
|
@@ -11957,8 +11985,8 @@ function agentExtraArgs(root, alias) {
|
|
|
11957
11985
|
}
|
|
11958
11986
|
function executableFile2(candidate) {
|
|
11959
11987
|
try {
|
|
11960
|
-
|
|
11961
|
-
return
|
|
11988
|
+
fs17.accessSync(candidate, fs17.constants.X_OK);
|
|
11989
|
+
return fs17.statSync(candidate).isFile() ? fs17.realpathSync(candidate) : null;
|
|
11962
11990
|
} catch {
|
|
11963
11991
|
return null;
|
|
11964
11992
|
}
|
|
@@ -11966,10 +11994,10 @@ function executableFile2(candidate) {
|
|
|
11966
11994
|
function resolveExecutable2(target) {
|
|
11967
11995
|
if (typeof target !== "string" || !target || target.includes("\0")) return null;
|
|
11968
11996
|
const expanded = target.replace(/^~(?=\/|$)/, os4.homedir());
|
|
11969
|
-
if (
|
|
11997
|
+
if (path20.isAbsolute(expanded)) return executableFile2(expanded);
|
|
11970
11998
|
if (!/[\\/]/.test(expanded)) {
|
|
11971
|
-
for (const dir of (process.env.PATH ?? "").split(
|
|
11972
|
-
const found = executableFile2(
|
|
11999
|
+
for (const dir of (process.env.PATH ?? "").split(path20.delimiter)) {
|
|
12000
|
+
const found = executableFile2(path20.join(dir, expanded));
|
|
11973
12001
|
if (found) return found;
|
|
11974
12002
|
}
|
|
11975
12003
|
return null;
|
|
@@ -12420,7 +12448,7 @@ var init_agent = __esm({
|
|
|
12420
12448
|
});
|
|
12421
12449
|
|
|
12422
12450
|
// server/src/graphWatch.ts
|
|
12423
|
-
import
|
|
12451
|
+
import fs18 from "node:fs";
|
|
12424
12452
|
function graphFileFor(relative) {
|
|
12425
12453
|
const segments = String(relative).split(/[\\/]/).filter(Boolean);
|
|
12426
12454
|
if (segments.length !== 1) return null;
|
|
@@ -12445,7 +12473,7 @@ function createGraphWatcher(project) {
|
|
|
12445
12473
|
);
|
|
12446
12474
|
}
|
|
12447
12475
|
try {
|
|
12448
|
-
watcher =
|
|
12476
|
+
watcher = fs18.watch(project.root, { recursive: false }, (_event, filename) => {
|
|
12449
12477
|
if (!filename) return;
|
|
12450
12478
|
const graph = graphFileFor(String(filename));
|
|
12451
12479
|
if (graph) emit(graph);
|
|
@@ -12631,8 +12659,8 @@ var init_net = __esm({
|
|
|
12631
12659
|
// server/src/routes/media.ts
|
|
12632
12660
|
import express, { Router as Router11 } from "express";
|
|
12633
12661
|
import crypto2 from "crypto";
|
|
12634
|
-
import
|
|
12635
|
-
import
|
|
12662
|
+
import fs19 from "fs";
|
|
12663
|
+
import path21 from "path";
|
|
12636
12664
|
async function loadSharp() {
|
|
12637
12665
|
if (sharpModule) return sharpModule;
|
|
12638
12666
|
if (sharpError) throw new Error(sharpError);
|
|
@@ -12719,11 +12747,11 @@ function fieldToGrey(array) {
|
|
|
12719
12747
|
}
|
|
12720
12748
|
function contentAddressed2(rel, body) {
|
|
12721
12749
|
const hash2 = crypto2.createHash("sha1").update(body).digest("hex").slice(0, 12);
|
|
12722
|
-
const dir =
|
|
12723
|
-
const name =
|
|
12750
|
+
const dir = path21.posix.dirname(rel);
|
|
12751
|
+
const name = path21.posix.basename(rel);
|
|
12724
12752
|
const [stem, ...rest] = name.split(".");
|
|
12725
12753
|
const tail = rest.length ? `.${rest.join(".")}` : "";
|
|
12726
|
-
return
|
|
12754
|
+
return path21.posix.join(dir, `${stem}.${hash2}${tail}`);
|
|
12727
12755
|
}
|
|
12728
12756
|
function clampInt(value, min, max) {
|
|
12729
12757
|
const n = Number(value);
|
|
@@ -12745,8 +12773,8 @@ function createMediaRouter(project) {
|
|
|
12745
12773
|
try {
|
|
12746
12774
|
const target = req.query.exact === "1" ? rel : contentAddressed2(rel, req.body);
|
|
12747
12775
|
const full = project.resolve(target);
|
|
12748
|
-
await
|
|
12749
|
-
await
|
|
12776
|
+
await fs19.promises.mkdir(path21.dirname(full), { recursive: true });
|
|
12777
|
+
await fs19.promises.writeFile(full, req.body);
|
|
12750
12778
|
res.json({ ok: true, path: target, bytes: req.body.length });
|
|
12751
12779
|
} catch (err) {
|
|
12752
12780
|
res.status(err instanceof PathSafetyError ? 400 : 500).json({ error: String(err) });
|
|
@@ -12763,13 +12791,13 @@ function createMediaRouter(project) {
|
|
|
12763
12791
|
}
|
|
12764
12792
|
let stat;
|
|
12765
12793
|
try {
|
|
12766
|
-
stat = await
|
|
12794
|
+
stat = await fs19.promises.stat(full);
|
|
12767
12795
|
if (!stat.isFile()) throw new Error("not a file");
|
|
12768
12796
|
} catch {
|
|
12769
12797
|
res.status(404).json({ error: `no such file: ${rel}` });
|
|
12770
12798
|
return;
|
|
12771
12799
|
}
|
|
12772
|
-
const ext =
|
|
12800
|
+
const ext = path21.extname(full).toLowerCase();
|
|
12773
12801
|
const width = clampInt(req.query.w, 1, 2e4);
|
|
12774
12802
|
const quality = clampInt(req.query.q, 1, 100) ?? 82;
|
|
12775
12803
|
const requested = String(req.query.fmt ?? "").toLowerCase();
|
|
@@ -12783,7 +12811,7 @@ function createMediaRouter(project) {
|
|
|
12783
12811
|
}
|
|
12784
12812
|
if (!raw && ext === ".npy") {
|
|
12785
12813
|
try {
|
|
12786
|
-
const array = readNpy(await
|
|
12814
|
+
const array = readNpy(await fs19.promises.readFile(full));
|
|
12787
12815
|
const { pixels, min, max } = fieldToGrey(array);
|
|
12788
12816
|
res.setHeader("X-Field-Shape", `${array.height}x${array.width}`);
|
|
12789
12817
|
res.setHeader("X-Field-Range", `${min}:${max}`);
|
|
@@ -12814,7 +12842,7 @@ function createMediaRouter(project) {
|
|
|
12814
12842
|
if (raw || !RASTER.has(ext)) {
|
|
12815
12843
|
res.type(MIME[ext] ?? "application/octet-stream");
|
|
12816
12844
|
res.setHeader("Content-Length", String(stat.size));
|
|
12817
|
-
|
|
12845
|
+
fs19.createReadStream(full).pipe(res);
|
|
12818
12846
|
return;
|
|
12819
12847
|
}
|
|
12820
12848
|
let format2 = requested;
|
|
@@ -12822,7 +12850,7 @@ function createMediaRouter(project) {
|
|
|
12822
12850
|
if (format2 === "gif") {
|
|
12823
12851
|
res.type("image/gif");
|
|
12824
12852
|
res.setHeader("Content-Length", String(stat.size));
|
|
12825
|
-
|
|
12853
|
+
fs19.createReadStream(full).pipe(res);
|
|
12826
12854
|
return;
|
|
12827
12855
|
}
|
|
12828
12856
|
try {
|
|
@@ -12889,11 +12917,11 @@ var init_media = __esm({
|
|
|
12889
12917
|
});
|
|
12890
12918
|
|
|
12891
12919
|
// server/src/build.ts
|
|
12892
|
-
import
|
|
12920
|
+
import fs20 from "node:fs";
|
|
12893
12921
|
import { createHash } from "node:crypto";
|
|
12894
12922
|
function buildId(distDir) {
|
|
12895
12923
|
try {
|
|
12896
|
-
const contents =
|
|
12924
|
+
const contents = fs20.readFileSync(`${distDir}/index.html`);
|
|
12897
12925
|
return createHash("sha256").update(contents).digest("hex").slice(0, 16);
|
|
12898
12926
|
} catch {
|
|
12899
12927
|
return null;
|
|
@@ -12908,8 +12936,8 @@ var init_build = __esm({
|
|
|
12908
12936
|
// server/src/index.ts
|
|
12909
12937
|
import express2 from "express";
|
|
12910
12938
|
import { createServer } from "http";
|
|
12911
|
-
import
|
|
12912
|
-
import
|
|
12939
|
+
import path22 from "path";
|
|
12940
|
+
import fs21 from "fs";
|
|
12913
12941
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
12914
12942
|
function startServer(project, opts = {}) {
|
|
12915
12943
|
const app = express2();
|
|
@@ -12976,7 +13004,7 @@ function startServer(project, opts = {}) {
|
|
|
12976
13004
|
app.get("/api/build", (_req, res) => {
|
|
12977
13005
|
res.json({ id: buildId(CASCADE_DIST) });
|
|
12978
13006
|
});
|
|
12979
|
-
if (
|
|
13007
|
+
if (fs21.existsSync(CASCADE_DIST)) {
|
|
12980
13008
|
app.use(express2.static(CASCADE_DIST, {
|
|
12981
13009
|
setHeaders(res, filePath) {
|
|
12982
13010
|
res.setHeader(
|
|
@@ -12988,7 +13016,7 @@ function startServer(project, opts = {}) {
|
|
|
12988
13016
|
app.get("/{*splat}", (req, res, next) => {
|
|
12989
13017
|
if (req.path.startsWith("/api") || req.path === "/health") return next();
|
|
12990
13018
|
res.setHeader("Cache-Control", "no-store");
|
|
12991
|
-
res.sendFile(
|
|
13019
|
+
res.sendFile(path22.join(CASCADE_DIST, "index.html"));
|
|
12992
13020
|
});
|
|
12993
13021
|
} else {
|
|
12994
13022
|
console.warn(`[cascade-server] no build found at ${CASCADE_DIST} \u2014 run "npm run build" in the Cascade repo first. API-only for now.`);
|
|
@@ -13021,18 +13049,18 @@ var init_src3 = __esm({
|
|
|
13021
13049
|
init_build();
|
|
13022
13050
|
init_service();
|
|
13023
13051
|
__filename = fileURLToPath3(import.meta.url);
|
|
13024
|
-
__dirname =
|
|
13025
|
-
CASCADE_DIST =
|
|
13052
|
+
__dirname = path22.dirname(__filename);
|
|
13053
|
+
CASCADE_DIST = path22.resolve(__dirname, "..", "..", "dist");
|
|
13026
13054
|
}
|
|
13027
13055
|
});
|
|
13028
13056
|
|
|
13029
13057
|
// server/src/projectTemplate.ts
|
|
13030
|
-
import
|
|
13031
|
-
import
|
|
13058
|
+
import fs22 from "node:fs";
|
|
13059
|
+
import path23 from "node:path";
|
|
13032
13060
|
function cascadeVersionRange() {
|
|
13033
13061
|
try {
|
|
13034
13062
|
const pkg = JSON.parse(
|
|
13035
|
-
|
|
13063
|
+
fs22.readFileSync(new URL("../../package.json", import.meta.url), "utf8")
|
|
13036
13064
|
);
|
|
13037
13065
|
const match = /^(\d+)\.(\d+)\./.exec(pkg.version ?? "");
|
|
13038
13066
|
return match ? `^${match[1]}.${match[2]}.0` : "*";
|
|
@@ -13044,14 +13072,14 @@ function createProject(projectsRoot, name) {
|
|
|
13044
13072
|
if (!PROJECT_NAME.test(name)) {
|
|
13045
13073
|
throw new Error("Project names use lowercase letters, numbers, and hyphens (maximum 64 characters).");
|
|
13046
13074
|
}
|
|
13047
|
-
const root =
|
|
13048
|
-
const directory =
|
|
13049
|
-
if (
|
|
13050
|
-
if (
|
|
13051
|
-
|
|
13052
|
-
|
|
13053
|
-
writeJson(
|
|
13054
|
-
writeJson(
|
|
13075
|
+
const root = path23.resolve(projectsRoot);
|
|
13076
|
+
const directory = path23.resolve(root, name);
|
|
13077
|
+
if (path23.dirname(directory) !== root) throw new Error("Project path escapes the configured projects directory.");
|
|
13078
|
+
if (fs22.existsSync(directory)) throw new Error(`Already exists: ${directory}`);
|
|
13079
|
+
fs22.mkdirSync(path23.join(directory, "nodes"), { recursive: true });
|
|
13080
|
+
fs22.mkdirSync(path23.join(directory, "assets"));
|
|
13081
|
+
writeJson(path23.join(directory, "cascade.json"), { name });
|
|
13082
|
+
writeJson(path23.join(directory, "index.cascade"), {
|
|
13055
13083
|
name,
|
|
13056
13084
|
version: "0.2",
|
|
13057
13085
|
viewport: { x: 0, y: 0, zoom: 1 },
|
|
@@ -13059,7 +13087,7 @@ function createProject(projectsRoot, name) {
|
|
|
13059
13087
|
connections: [],
|
|
13060
13088
|
annotations: []
|
|
13061
13089
|
});
|
|
13062
|
-
writeJson(
|
|
13090
|
+
writeJson(path23.join(directory, "package.json"), {
|
|
13063
13091
|
name,
|
|
13064
13092
|
private: true,
|
|
13065
13093
|
type: "module",
|
|
@@ -13079,7 +13107,7 @@ function createProject(projectsRoot, name) {
|
|
|
13079
13107
|
typescript: "^6.0.0"
|
|
13080
13108
|
}
|
|
13081
13109
|
});
|
|
13082
|
-
writeJson(
|
|
13110
|
+
writeJson(path23.join(directory, "tsconfig.json"), {
|
|
13083
13111
|
compilerOptions: {
|
|
13084
13112
|
target: "ES2022",
|
|
13085
13113
|
module: "ESNext",
|
|
@@ -13089,8 +13117,8 @@ function createProject(projectsRoot, name) {
|
|
|
13089
13117
|
},
|
|
13090
13118
|
include: ["nodes/**/*.ts"]
|
|
13091
13119
|
});
|
|
13092
|
-
|
|
13093
|
-
|
|
13120
|
+
fs22.writeFileSync(path23.join(directory, ".gitignore"), ".cascade-cache/\nrenders/\nnode_modules/\n");
|
|
13121
|
+
fs22.writeFileSync(path23.join(directory, "AGENTS.md"), `# Cascade project
|
|
13094
13122
|
|
|
13095
13123
|
Read \`node_modules/cascade/AGENTS.md\` for the framework itself. What follows is what an agent working in *this* project needs.
|
|
13096
13124
|
|
|
@@ -13245,14 +13273,14 @@ function createNode(projectRoot, name) {
|
|
|
13245
13273
|
if (!NODE_NAME.test(name)) {
|
|
13246
13274
|
throw new Error("Node names start with an uppercase letter and contain only letters or numbers.");
|
|
13247
13275
|
}
|
|
13248
|
-
const directory =
|
|
13249
|
-
if (
|
|
13250
|
-
|
|
13251
|
-
|
|
13276
|
+
const directory = path23.resolve(projectRoot, "nodes", name);
|
|
13277
|
+
if (fs22.existsSync(directory)) throw new Error(`Already exists: ${directory}`);
|
|
13278
|
+
fs22.mkdirSync(directory, { recursive: true });
|
|
13279
|
+
fs22.writeFileSync(path23.join(directory, "index.ts"), nodeSource(name));
|
|
13252
13280
|
return directory;
|
|
13253
13281
|
}
|
|
13254
13282
|
function writeJson(file, value) {
|
|
13255
|
-
|
|
13283
|
+
fs22.writeFileSync(file, `${JSON.stringify(value, null, 2)}
|
|
13256
13284
|
`);
|
|
13257
13285
|
}
|
|
13258
13286
|
function nodeSource(name) {
|
|
@@ -13290,8 +13318,8 @@ __export(cliCommands_exports, {
|
|
|
13290
13318
|
parseStudioArgs: () => parseStudioArgs,
|
|
13291
13319
|
runStudioCli: () => runStudioCli
|
|
13292
13320
|
});
|
|
13293
|
-
import
|
|
13294
|
-
import
|
|
13321
|
+
import fs23 from "node:fs";
|
|
13322
|
+
import path24 from "node:path";
|
|
13295
13323
|
import { execFile as execFile5 } from "node:child_process";
|
|
13296
13324
|
function parseStudioArgs(args) {
|
|
13297
13325
|
const positional = [];
|
|
@@ -13346,7 +13374,7 @@ async function runStudioCli(args) {
|
|
|
13346
13374
|
const config = loadConfig2();
|
|
13347
13375
|
if (positional[0] === "projects") {
|
|
13348
13376
|
if (positional[1]) {
|
|
13349
|
-
saveConfig({ projectsRoot:
|
|
13377
|
+
saveConfig({ projectsRoot: path24.resolve(positional[1].replace(/^~(?=\/|$)/, process.env.HOME ?? "~")) });
|
|
13350
13378
|
console.log(`[cascade] projects root set to ${loadConfig2().projectsRoot} (${configPath()})`);
|
|
13351
13379
|
} else console.log(loadConfig2().projectsRoot);
|
|
13352
13380
|
return;
|
|
@@ -13365,9 +13393,9 @@ async function runStudioCli(args) {
|
|
|
13365
13393
|
return;
|
|
13366
13394
|
}
|
|
13367
13395
|
let target = positional[0] ?? ".";
|
|
13368
|
-
if (!
|
|
13369
|
-
const projectTarget =
|
|
13370
|
-
if (
|
|
13396
|
+
if (!fs23.existsSync(path24.resolve(target))) {
|
|
13397
|
+
const projectTarget = path24.resolve(config.projectsRoot, target);
|
|
13398
|
+
if (fs23.existsSync(projectTarget)) target = projectTarget;
|
|
13371
13399
|
}
|
|
13372
13400
|
const project = ProjectRoot.fromArg(target);
|
|
13373
13401
|
const server = startServer(project, { host, port, trustedHosts });
|
|
@@ -13513,8 +13541,8 @@ var ExpressionEngine = class extends ExpressionEvaluator {
|
|
|
13513
13541
|
super();
|
|
13514
13542
|
this.graph = null;
|
|
13515
13543
|
const scope = {
|
|
13516
|
-
resolveParam: (from,
|
|
13517
|
-
nodeExists: (from,
|
|
13544
|
+
resolveParam: (from, path25) => this.resolveNodePath(from, path25),
|
|
13545
|
+
nodeExists: (from, path25) => from.node(path25) !== null,
|
|
13518
13546
|
inputNode: (from, index) => this.resolveInput(from, index)
|
|
13519
13547
|
};
|
|
13520
13548
|
this.setScope(scope);
|
|
@@ -13528,15 +13556,15 @@ var ExpressionEngine = class extends ExpressionEvaluator {
|
|
|
13528
13556
|
/**
|
|
13529
13557
|
* Resolve a path to get the parameter value
|
|
13530
13558
|
*/
|
|
13531
|
-
resolveNodePath(fromNode,
|
|
13532
|
-
const lastSlash =
|
|
13533
|
-
if (lastSlash === -1 ||
|
|
13534
|
-
const paramName2 =
|
|
13559
|
+
resolveNodePath(fromNode, path25) {
|
|
13560
|
+
const lastSlash = path25.lastIndexOf("/");
|
|
13561
|
+
if (lastSlash === -1 || path25.startsWith("./")) {
|
|
13562
|
+
const paramName2 = path25.replace("./", "");
|
|
13535
13563
|
const prop2 = fromNode.props[paramName2];
|
|
13536
13564
|
return prop2 ? { value: prop2.value } : null;
|
|
13537
13565
|
}
|
|
13538
|
-
const nodePath =
|
|
13539
|
-
const paramName =
|
|
13566
|
+
const nodePath = path25.substring(0, lastSlash) || ".";
|
|
13567
|
+
const paramName = path25.substring(lastSlash + 1);
|
|
13540
13568
|
const targetNode = fromNode.node(nodePath);
|
|
13541
13569
|
if (!targetNode) return null;
|
|
13542
13570
|
const prop = targetNode.props[paramName];
|
|
@@ -13563,14 +13591,14 @@ var ExpressionEngine = class extends ExpressionEvaluator {
|
|
|
13563
13591
|
for (const [propKey, prop] of Object.entries(node.props)) {
|
|
13564
13592
|
if (!prop.expression) continue;
|
|
13565
13593
|
const paths = this.extractDependencies(prop.expression);
|
|
13566
|
-
for (const
|
|
13567
|
-
if (!this.validatePath(node,
|
|
13594
|
+
for (const path25 of paths) {
|
|
13595
|
+
if (!this.validatePath(node, path25)) {
|
|
13568
13596
|
warnings.push({
|
|
13569
13597
|
nodeId: node.id,
|
|
13570
13598
|
nodePath: node.path(),
|
|
13571
13599
|
propName: propKey,
|
|
13572
13600
|
expression: prop.expression,
|
|
13573
|
-
brokenPath:
|
|
13601
|
+
brokenPath: path25
|
|
13574
13602
|
});
|
|
13575
13603
|
}
|
|
13576
13604
|
}
|
|
@@ -13611,24 +13639,24 @@ var CascadeContext = class {
|
|
|
13611
13639
|
/**
|
|
13612
13640
|
* Find a node by path (absolute or relative to pwd)
|
|
13613
13641
|
*/
|
|
13614
|
-
node(
|
|
13642
|
+
node(path25) {
|
|
13615
13643
|
if (!this._graph) return null;
|
|
13616
|
-
if (
|
|
13617
|
-
return this.resolveAbsolutePath(
|
|
13644
|
+
if (path25.startsWith("/")) {
|
|
13645
|
+
return this.resolveAbsolutePath(path25);
|
|
13618
13646
|
}
|
|
13619
13647
|
if (this._pwd) {
|
|
13620
|
-
return this._pwd.node(
|
|
13648
|
+
return this._pwd.node(path25);
|
|
13621
13649
|
}
|
|
13622
|
-
return this.resolveAbsolutePath("/" +
|
|
13650
|
+
return this.resolveAbsolutePath("/" + path25);
|
|
13623
13651
|
}
|
|
13624
13652
|
/**
|
|
13625
13653
|
* Find a parameter by path (e.g., "/node1/radius")
|
|
13626
13654
|
*/
|
|
13627
|
-
parm(
|
|
13628
|
-
const lastSlash =
|
|
13655
|
+
parm(path25) {
|
|
13656
|
+
const lastSlash = path25.lastIndexOf("/");
|
|
13629
13657
|
if (lastSlash === -1) return null;
|
|
13630
|
-
const nodePath =
|
|
13631
|
-
const parmName =
|
|
13658
|
+
const nodePath = path25.substring(0, lastSlash) || "/";
|
|
13659
|
+
const parmName = path25.substring(lastSlash + 1);
|
|
13632
13660
|
const node = this.node(nodePath);
|
|
13633
13661
|
return node?.parm(parmName) ?? null;
|
|
13634
13662
|
}
|
|
@@ -13654,12 +13682,12 @@ var CascadeContext = class {
|
|
|
13654
13682
|
/**
|
|
13655
13683
|
* Navigate to a path (like cd command)
|
|
13656
13684
|
*/
|
|
13657
|
-
cd(
|
|
13658
|
-
if (
|
|
13685
|
+
cd(path25) {
|
|
13686
|
+
if (path25 === "/") {
|
|
13659
13687
|
this._pwd = null;
|
|
13660
13688
|
return;
|
|
13661
13689
|
}
|
|
13662
|
-
const target = this.node(
|
|
13690
|
+
const target = this.node(path25);
|
|
13663
13691
|
if (target && target.isNetwork()) {
|
|
13664
13692
|
this._pwd = target;
|
|
13665
13693
|
}
|
|
@@ -13757,22 +13785,22 @@ var CascadeContext = class {
|
|
|
13757
13785
|
/**
|
|
13758
13786
|
* Get parameter value as number (shorthand)
|
|
13759
13787
|
*/
|
|
13760
|
-
ch(
|
|
13761
|
-
const p = this.parm(
|
|
13788
|
+
ch(path25) {
|
|
13789
|
+
const p = this.parm(path25);
|
|
13762
13790
|
return p?.evalAsFloat() ?? 0;
|
|
13763
13791
|
}
|
|
13764
13792
|
/**
|
|
13765
13793
|
* Get parameter value as string (shorthand)
|
|
13766
13794
|
*/
|
|
13767
|
-
chs(
|
|
13768
|
-
const p = this.parm(
|
|
13795
|
+
chs(path25) {
|
|
13796
|
+
const p = this.parm(path25);
|
|
13769
13797
|
return p?.evalAsString() ?? "";
|
|
13770
13798
|
}
|
|
13771
13799
|
/**
|
|
13772
13800
|
* Get parameter value as vector (shorthand)
|
|
13773
13801
|
*/
|
|
13774
|
-
chv(
|
|
13775
|
-
const p = this.parm(
|
|
13802
|
+
chv(path25) {
|
|
13803
|
+
const p = this.parm(path25);
|
|
13776
13804
|
const val = p?.eval();
|
|
13777
13805
|
if (Array.isArray(val)) return val;
|
|
13778
13806
|
if (typeof val === "number") return [val];
|
|
@@ -13809,9 +13837,9 @@ var CascadeContext = class {
|
|
|
13809
13837
|
return this.fframe();
|
|
13810
13838
|
}
|
|
13811
13839
|
// ============ Internal Helpers ============
|
|
13812
|
-
resolveAbsolutePath(
|
|
13840
|
+
resolveAbsolutePath(path25) {
|
|
13813
13841
|
if (!this._graph) return null;
|
|
13814
|
-
const segments =
|
|
13842
|
+
const segments = path25.replace(/^\//, "").split("/").filter((s) => s.length > 0);
|
|
13815
13843
|
if (segments.length === 0) {
|
|
13816
13844
|
return null;
|
|
13817
13845
|
}
|
|
@@ -13967,7 +13995,7 @@ async function runGraph(options2) {
|
|
|
13967
13995
|
}
|
|
13968
13996
|
|
|
13969
13997
|
// src/cli/index.ts
|
|
13970
|
-
import * as
|
|
13998
|
+
import * as fs24 from "fs/promises";
|
|
13971
13999
|
import { readFileSync } from "node:fs";
|
|
13972
14000
|
|
|
13973
14001
|
// src/cli/supervise.ts
|
|
@@ -14127,7 +14155,7 @@ image output nothing downstream consumes, or per output of --entry-node.
|
|
|
14127
14155
|
process.exit(1);
|
|
14128
14156
|
}
|
|
14129
14157
|
try {
|
|
14130
|
-
await
|
|
14158
|
+
await fs24.access(fileArg);
|
|
14131
14159
|
} catch {
|
|
14132
14160
|
console.error(`Error: File not found: ${fileArg}`);
|
|
14133
14161
|
process.exit(1);
|