@vizij/node-graph-authoring 0.0.4 → 0.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +74 -1
- package/dist/chunk-XYPRZPXJ.js +4334 -0
- package/dist/cli/reportIr.cjs +4046 -0
- package/dist/cli/reportIr.js +246 -0
- package/dist/index.cjs +2544 -512
- package/dist/index.d.cts +387 -36
- package/dist/index.d.ts +387 -36
- package/dist/index.js +58 -2284
- package/package.json +14 -5
package/dist/index.cjs
CHANGED
|
@@ -20,37 +20,46 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
20
20
|
// src/index.ts
|
|
21
21
|
var index_exports = {};
|
|
22
22
|
__export(index_exports, {
|
|
23
|
+
EXPRESSION_FUNCTION_VOCABULARY: () => EXPRESSION_FUNCTION_VOCABULARY,
|
|
24
|
+
MACHINE_REPORT_VERSION: () => MACHINE_REPORT_VERSION,
|
|
23
25
|
PRIMARY_SLOT_ALIAS: () => PRIMARY_SLOT_ALIAS,
|
|
24
26
|
PRIMARY_SLOT_ID: () => PRIMARY_SLOT_ID,
|
|
27
|
+
RESERVED_EXPRESSION_VARIABLES: () => RESERVED_EXPRESSION_VARIABLES,
|
|
28
|
+
SCALAR_FUNCTIONS: () => SCALAR_FUNCTIONS,
|
|
29
|
+
SCALAR_FUNCTION_VOCABULARY: () => SCALAR_FUNCTION_VOCABULARY,
|
|
25
30
|
addBindingSlot: () => addBindingSlot,
|
|
26
31
|
bindingFromDefinition: () => bindingFromDefinition,
|
|
27
|
-
bindingOperatorDefinitions: () => bindingOperatorDefinitions,
|
|
28
|
-
bindingOperatorTypes: () => bindingOperatorTypes,
|
|
29
32
|
bindingTargetFromComponent: () => bindingTargetFromComponent,
|
|
30
33
|
bindingTargetFromInput: () => bindingTargetFromInput,
|
|
31
34
|
bindingToDefinition: () => bindingToDefinition,
|
|
35
|
+
buildCanonicalBindingExpression: () => buildCanonicalBindingExpression,
|
|
36
|
+
buildDefaultSlotExpression: () => buildDefaultSlotExpression,
|
|
37
|
+
buildMachineReport: () => buildMachineReport,
|
|
38
|
+
buildPiecewiseRemapExpression: () => buildPiecewiseRemapExpression,
|
|
32
39
|
buildRigGraphSpec: () => buildRigGraphSpec,
|
|
33
40
|
collectExpressionReferences: () => collectExpressionReferences,
|
|
41
|
+
compileIrGraph: () => compileIrGraph,
|
|
34
42
|
createDefaultBinding: () => createDefaultBinding,
|
|
35
43
|
createDefaultBindings: () => createDefaultBindings,
|
|
36
44
|
createDefaultInputValues: () => createDefaultInputValues,
|
|
37
|
-
createDefaultOperatorSettings: () => createDefaultOperatorSettings,
|
|
38
45
|
createDefaultParentBinding: () => createDefaultParentBinding,
|
|
39
46
|
createDefaultRemap: () => createDefaultRemap,
|
|
47
|
+
createExpressionVariableTable: () => createExpressionVariableTable,
|
|
48
|
+
createIrGraphBuilder: () => createIrGraphBuilder,
|
|
49
|
+
createLegacyIrGraph: () => createLegacyIrGraph,
|
|
50
|
+
diffMachineReports: () => diffMachineReports,
|
|
40
51
|
ensureBindingStructure: () => ensureBindingStructure,
|
|
41
|
-
ensureOperatorParams: () => ensureOperatorParams,
|
|
42
|
-
getBindingOperatorDefinition: () => getBindingOperatorDefinition,
|
|
43
52
|
getPrimaryBindingSlot: () => getPrimaryBindingSlot,
|
|
44
53
|
mapExpression: () => mapExpression,
|
|
45
54
|
parseControlExpression: () => parseControlExpression,
|
|
46
55
|
reconcileBindings: () => reconcileBindings,
|
|
47
56
|
remapValue: () => remapValue,
|
|
48
57
|
removeBindingSlot: () => removeBindingSlot,
|
|
49
|
-
|
|
58
|
+
toIrBindingSummary: () => toIrBindingSummary,
|
|
50
59
|
updateBindingExpression: () => updateBindingExpression,
|
|
51
|
-
updateBindingOperatorParam: () => updateBindingOperatorParam,
|
|
52
60
|
updateBindingSlotAlias: () => updateBindingSlotAlias,
|
|
53
61
|
updateBindingSlotRemap: () => updateBindingSlotRemap,
|
|
62
|
+
updateBindingSlotValueType: () => updateBindingSlotValueType,
|
|
54
63
|
updateBindingWithInput: () => updateBindingWithInput
|
|
55
64
|
});
|
|
56
65
|
module.exports = __toCommonJS(index_exports);
|
|
@@ -61,84 +70,6 @@ var import_utils3 = require("@vizij/utils");
|
|
|
61
70
|
|
|
62
71
|
// src/state.ts
|
|
63
72
|
var import_utils = require("@vizij/utils");
|
|
64
|
-
|
|
65
|
-
// src/operators.ts
|
|
66
|
-
var import_metadata = require("@vizij/node-graph-wasm/metadata");
|
|
67
|
-
var OPERATOR_TYPES = [
|
|
68
|
-
"spring",
|
|
69
|
-
"damp",
|
|
70
|
-
"slew"
|
|
71
|
-
];
|
|
72
|
-
function valueJsonToNumber(value) {
|
|
73
|
-
if (!value || typeof value !== "object") {
|
|
74
|
-
return typeof value === "number" ? value : 0;
|
|
75
|
-
}
|
|
76
|
-
if ("float" in value && typeof value.float === "number") {
|
|
77
|
-
return value.float;
|
|
78
|
-
}
|
|
79
|
-
if ("int" in value && typeof value.int === "number") {
|
|
80
|
-
return value.int;
|
|
81
|
-
}
|
|
82
|
-
return 0;
|
|
83
|
-
}
|
|
84
|
-
var operatorDefinitionMap = /* @__PURE__ */ new Map();
|
|
85
|
-
OPERATOR_TYPES.forEach((type) => {
|
|
86
|
-
const signature = (0, import_metadata.requireNodeSignature)(type);
|
|
87
|
-
const params = signature.params.map(
|
|
88
|
-
(param) => ({
|
|
89
|
-
id: param.id,
|
|
90
|
-
label: param.label,
|
|
91
|
-
doc: param.doc,
|
|
92
|
-
min: param.min ?? void 0,
|
|
93
|
-
max: param.max ?? void 0,
|
|
94
|
-
defaultValue: valueJsonToNumber(param.default_json)
|
|
95
|
-
})
|
|
96
|
-
);
|
|
97
|
-
operatorDefinitionMap.set(type, {
|
|
98
|
-
type,
|
|
99
|
-
nodeType: signature.type_id,
|
|
100
|
-
label: signature.name,
|
|
101
|
-
description: signature.doc,
|
|
102
|
-
inputs: signature.inputs.map((input) => input.id),
|
|
103
|
-
params
|
|
104
|
-
});
|
|
105
|
-
});
|
|
106
|
-
function getBindingOperatorDefinition(type) {
|
|
107
|
-
const definition = operatorDefinitionMap.get(type);
|
|
108
|
-
if (!definition) {
|
|
109
|
-
throw new Error(`Unknown binding operator type '${type}'.`);
|
|
110
|
-
}
|
|
111
|
-
return definition;
|
|
112
|
-
}
|
|
113
|
-
var bindingOperatorDefinitions = OPERATOR_TYPES.map((type) => getBindingOperatorDefinition(type));
|
|
114
|
-
function createDefaultOperatorSettings(type) {
|
|
115
|
-
const definition = getBindingOperatorDefinition(type);
|
|
116
|
-
const params = {};
|
|
117
|
-
definition.params.forEach((param) => {
|
|
118
|
-
params[param.id] = param.defaultValue;
|
|
119
|
-
});
|
|
120
|
-
return {
|
|
121
|
-
type,
|
|
122
|
-
enabled: false,
|
|
123
|
-
params
|
|
124
|
-
};
|
|
125
|
-
}
|
|
126
|
-
function ensureOperatorParams(operator) {
|
|
127
|
-
const definition = getBindingOperatorDefinition(operator.type);
|
|
128
|
-
const params = {};
|
|
129
|
-
definition.params.forEach((param) => {
|
|
130
|
-
const value = operator.params?.[param.id];
|
|
131
|
-
params[param.id] = typeof value === "number" ? value : param.defaultValue;
|
|
132
|
-
});
|
|
133
|
-
return {
|
|
134
|
-
type: operator.type,
|
|
135
|
-
enabled: !!operator.enabled,
|
|
136
|
-
params
|
|
137
|
-
};
|
|
138
|
-
}
|
|
139
|
-
var bindingOperatorTypes = OPERATOR_TYPES;
|
|
140
|
-
|
|
141
|
-
// src/state.ts
|
|
142
73
|
var VECTOR_ANIMATABLE_TYPES = /* @__PURE__ */ new Set(["vector2", "vector3", "euler", "rgb"]);
|
|
143
74
|
function deriveComponentValueType(component) {
|
|
144
75
|
if (component.component) {
|
|
@@ -184,83 +115,6 @@ var LEGACY_SLOT_PATTERN = /^slot_(\d+)$/i;
|
|
|
184
115
|
var ALIAS_SANITIZE_PATTERN = /[^A-Za-z0-9_]+/g;
|
|
185
116
|
var PRIMARY_SLOT_ID = "s1";
|
|
186
117
|
var PRIMARY_SLOT_ALIAS = "s1";
|
|
187
|
-
function createDefaultOperators() {
|
|
188
|
-
return bindingOperatorTypes.map(
|
|
189
|
-
(type) => createDefaultOperatorSettings(type)
|
|
190
|
-
);
|
|
191
|
-
}
|
|
192
|
-
function normalizeOperator(operator) {
|
|
193
|
-
const normalized = ensureOperatorParams(operator);
|
|
194
|
-
const definition = getBindingOperatorDefinition(normalized.type);
|
|
195
|
-
const params = {};
|
|
196
|
-
definition.params.forEach((param) => {
|
|
197
|
-
const value = normalized.params[param.id];
|
|
198
|
-
params[param.id] = typeof value === "number" ? value : param.defaultValue;
|
|
199
|
-
});
|
|
200
|
-
return {
|
|
201
|
-
type: normalized.type,
|
|
202
|
-
enabled: !!normalized.enabled,
|
|
203
|
-
params
|
|
204
|
-
};
|
|
205
|
-
}
|
|
206
|
-
function ensureOperators(binding) {
|
|
207
|
-
const existing = /* @__PURE__ */ new Map();
|
|
208
|
-
(binding.operators ?? []).forEach((operator) => {
|
|
209
|
-
try {
|
|
210
|
-
existing.set(operator.type, normalizeOperator(operator));
|
|
211
|
-
} catch {
|
|
212
|
-
}
|
|
213
|
-
});
|
|
214
|
-
return bindingOperatorTypes.map((type) => {
|
|
215
|
-
const current = existing.get(type);
|
|
216
|
-
if (current) {
|
|
217
|
-
return current;
|
|
218
|
-
}
|
|
219
|
-
return createDefaultOperatorSettings(type);
|
|
220
|
-
});
|
|
221
|
-
}
|
|
222
|
-
function paramsEqual(a, b) {
|
|
223
|
-
const aKeys = Object.keys(a);
|
|
224
|
-
const bKeys = Object.keys(b);
|
|
225
|
-
if (aKeys.length !== bKeys.length) {
|
|
226
|
-
return false;
|
|
227
|
-
}
|
|
228
|
-
for (const key of aKeys) {
|
|
229
|
-
if (a[key] !== b[key]) {
|
|
230
|
-
return false;
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
return true;
|
|
234
|
-
}
|
|
235
|
-
function operatorsEqual(a, b) {
|
|
236
|
-
if (!a || a.length !== b.length) {
|
|
237
|
-
return false;
|
|
238
|
-
}
|
|
239
|
-
for (let index = 0; index < a.length; index += 1) {
|
|
240
|
-
const left = a[index];
|
|
241
|
-
const right = b[index];
|
|
242
|
-
if (left.type !== right.type || left.enabled !== right.enabled) {
|
|
243
|
-
return false;
|
|
244
|
-
}
|
|
245
|
-
if (!paramsEqual(left.params, right.params)) {
|
|
246
|
-
return false;
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
return true;
|
|
250
|
-
}
|
|
251
|
-
function normalizeBindingWithOperators(binding) {
|
|
252
|
-
const operators = ensureOperators(binding);
|
|
253
|
-
if (operatorsEqual(binding.operators, operators)) {
|
|
254
|
-
return { binding, operators };
|
|
255
|
-
}
|
|
256
|
-
return {
|
|
257
|
-
binding: {
|
|
258
|
-
...binding,
|
|
259
|
-
operators
|
|
260
|
-
},
|
|
261
|
-
operators
|
|
262
|
-
};
|
|
263
|
-
}
|
|
264
118
|
function defaultSlotId(index) {
|
|
265
119
|
return `s${index + 1}`;
|
|
266
120
|
}
|
|
@@ -415,6 +269,12 @@ function normalizeRemap(remap, target) {
|
|
|
415
269
|
function cloneRemap(remap) {
|
|
416
270
|
return (0, import_utils.cloneRemapSettings)(remap);
|
|
417
271
|
}
|
|
272
|
+
function cloneBindingMetadata(metadata) {
|
|
273
|
+
if (!metadata) {
|
|
274
|
+
return void 0;
|
|
275
|
+
}
|
|
276
|
+
return JSON.parse(JSON.stringify(metadata));
|
|
277
|
+
}
|
|
418
278
|
function sanitizeRemap(remap, target) {
|
|
419
279
|
const normalized = normalizeRemap(remap, target);
|
|
420
280
|
const outputDefaults = deriveOutputDefaults(target);
|
|
@@ -462,21 +322,21 @@ function createDefaultBindings(components) {
|
|
|
462
322
|
function createDefaultBinding(component) {
|
|
463
323
|
const remap = createDefaultRemap(component);
|
|
464
324
|
const valueType = getTargetValueType(component);
|
|
325
|
+
const slots = [
|
|
326
|
+
{
|
|
327
|
+
id: PRIMARY_SLOT_ID,
|
|
328
|
+
alias: PRIMARY_SLOT_ALIAS,
|
|
329
|
+
inputId: null,
|
|
330
|
+
remap: cloneRemap(remap),
|
|
331
|
+
valueType
|
|
332
|
+
}
|
|
333
|
+
];
|
|
465
334
|
return {
|
|
466
335
|
targetId: component.id,
|
|
467
336
|
inputId: null,
|
|
468
337
|
remap,
|
|
469
|
-
slots
|
|
470
|
-
|
|
471
|
-
id: PRIMARY_SLOT_ID,
|
|
472
|
-
alias: PRIMARY_SLOT_ALIAS,
|
|
473
|
-
inputId: null,
|
|
474
|
-
remap: cloneRemap(remap),
|
|
475
|
-
valueType
|
|
476
|
-
}
|
|
477
|
-
],
|
|
478
|
-
expression: PRIMARY_SLOT_ALIAS,
|
|
479
|
-
operators: createDefaultOperators()
|
|
338
|
+
slots,
|
|
339
|
+
expression: buildCanonicalExpressionFromSlots(slots)
|
|
480
340
|
};
|
|
481
341
|
}
|
|
482
342
|
function createDefaultParentBinding(component) {
|
|
@@ -496,7 +356,7 @@ function createDefaultParentBinding(component) {
|
|
|
496
356
|
...ensured,
|
|
497
357
|
inputId: import_utils.SELF_BINDING_ID,
|
|
498
358
|
slots,
|
|
499
|
-
expression:
|
|
359
|
+
expression: buildCanonicalExpressionFromSlots(slots)
|
|
500
360
|
};
|
|
501
361
|
}
|
|
502
362
|
function ensurePrimarySlot(binding, target) {
|
|
@@ -562,8 +422,13 @@ function ensurePrimarySlot(binding, target) {
|
|
|
562
422
|
};
|
|
563
423
|
});
|
|
564
424
|
const rawExpression = typeof binding.expression === "string" ? binding.expression.trim() : "";
|
|
565
|
-
|
|
566
|
-
|
|
425
|
+
const canonicalExpression = buildCanonicalExpressionFromSlots(normalizedSlots);
|
|
426
|
+
let expression;
|
|
427
|
+
if (expressionMatchesAliasOnly(rawExpression, normalizedSlots)) {
|
|
428
|
+
expression = canonicalExpression;
|
|
429
|
+
} else {
|
|
430
|
+
expression = rewriteLegacyExpression(rawExpression, aliasReplacements);
|
|
431
|
+
}
|
|
567
432
|
const normalizedBinding = {
|
|
568
433
|
...binding,
|
|
569
434
|
inputId: normalizedSlots[0].inputId ?? null,
|
|
@@ -571,14 +436,7 @@ function ensurePrimarySlot(binding, target) {
|
|
|
571
436
|
slots: normalizedSlots,
|
|
572
437
|
expression
|
|
573
438
|
};
|
|
574
|
-
|
|
575
|
-
if (operatorsEqual(normalizedBinding.operators, operators)) {
|
|
576
|
-
return normalizedBinding;
|
|
577
|
-
}
|
|
578
|
-
return {
|
|
579
|
-
...normalizedBinding,
|
|
580
|
-
operators
|
|
581
|
-
};
|
|
439
|
+
return normalizedBinding;
|
|
582
440
|
}
|
|
583
441
|
function createDefaultInputValues(inputs = []) {
|
|
584
442
|
const values = {};
|
|
@@ -689,87 +547,44 @@ function updateBindingSlotAlias(binding, target, slotId, nextAlias) {
|
|
|
689
547
|
);
|
|
690
548
|
return updated;
|
|
691
549
|
}
|
|
692
|
-
function
|
|
693
|
-
const
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
return operator;
|
|
698
|
-
}
|
|
699
|
-
if (operator.enabled === enabled) {
|
|
700
|
-
return operator;
|
|
701
|
-
}
|
|
702
|
-
changed = true;
|
|
703
|
-
return {
|
|
704
|
-
...operator,
|
|
705
|
-
enabled
|
|
706
|
-
};
|
|
707
|
-
});
|
|
708
|
-
if (!changed) {
|
|
709
|
-
return normalizedBinding;
|
|
710
|
-
}
|
|
711
|
-
if (operatorsEqual(normalizedBinding.operators, nextOperators)) {
|
|
712
|
-
return normalizedBinding;
|
|
550
|
+
function updateBindingSlotValueType(binding, target, slotId, nextValueType) {
|
|
551
|
+
const base = ensurePrimarySlot(binding, target);
|
|
552
|
+
const slotIndex = base.slots.findIndex((slot) => slot.id === slotId);
|
|
553
|
+
if (slotIndex < 0) {
|
|
554
|
+
return base;
|
|
713
555
|
}
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
};
|
|
718
|
-
}
|
|
719
|
-
function updateBindingOperatorParam(binding, type, paramId, value) {
|
|
720
|
-
const { binding: normalizedBinding, operators } = normalizeBindingWithOperators(binding);
|
|
721
|
-
const definition = getBindingOperatorDefinition(type);
|
|
722
|
-
const paramDefinition = definition.params.find(
|
|
723
|
-
(param) => param.id === paramId
|
|
556
|
+
const normalizedType = sanitizeSlotValueType(
|
|
557
|
+
nextValueType,
|
|
558
|
+
getTargetValueType(target)
|
|
724
559
|
);
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
let nextValue = value;
|
|
729
|
-
if (typeof paramDefinition.min === "number") {
|
|
730
|
-
nextValue = Math.max(paramDefinition.min, nextValue);
|
|
731
|
-
}
|
|
732
|
-
if (typeof paramDefinition.max === "number") {
|
|
733
|
-
nextValue = Math.min(paramDefinition.max, nextValue);
|
|
734
|
-
}
|
|
735
|
-
let changed = false;
|
|
736
|
-
const nextOperators = operators.map((operator) => {
|
|
737
|
-
if (operator.type !== type) {
|
|
738
|
-
return operator;
|
|
739
|
-
}
|
|
740
|
-
if (operator.params[paramId] === nextValue) {
|
|
741
|
-
return operator;
|
|
560
|
+
const slots = base.slots.map((slot, index) => {
|
|
561
|
+
if (index !== slotIndex) {
|
|
562
|
+
return slot;
|
|
742
563
|
}
|
|
743
|
-
changed = true;
|
|
744
564
|
return {
|
|
745
|
-
...
|
|
746
|
-
|
|
747
|
-
...operator.params,
|
|
748
|
-
[paramId]: nextValue
|
|
749
|
-
}
|
|
565
|
+
...slot,
|
|
566
|
+
valueType: normalizedType
|
|
750
567
|
};
|
|
751
568
|
});
|
|
752
|
-
if (!changed) {
|
|
753
|
-
return normalizedBinding;
|
|
754
|
-
}
|
|
755
|
-
if (operatorsEqual(normalizedBinding.operators, nextOperators)) {
|
|
756
|
-
return normalizedBinding;
|
|
757
|
-
}
|
|
758
569
|
return {
|
|
759
|
-
...
|
|
760
|
-
|
|
570
|
+
...base,
|
|
571
|
+
slots
|
|
761
572
|
};
|
|
762
573
|
}
|
|
763
574
|
function updateBindingExpression(binding, target, expression) {
|
|
764
575
|
const base = ensurePrimarySlot(binding, target);
|
|
765
576
|
const trimmed = expression.trim();
|
|
577
|
+
const canonicalExpression = buildCanonicalExpressionFromSlots(base.slots);
|
|
766
578
|
return {
|
|
767
579
|
...base,
|
|
768
|
-
expression: trimmed.length > 0 ? trimmed :
|
|
580
|
+
expression: trimmed.length > 0 ? trimmed : canonicalExpression
|
|
769
581
|
};
|
|
770
582
|
}
|
|
771
583
|
function updateBindingSlotRemap(binding, target, slotId, field, value) {
|
|
772
584
|
const base = ensurePrimarySlot(binding, target);
|
|
585
|
+
const existingExpression = typeof base.expression === "string" ? base.expression.trim() : "";
|
|
586
|
+
const canonicalBefore = buildCanonicalExpressionFromSlots(base.slots);
|
|
587
|
+
const expressionWasDefault = expressionMatchesAliasOnly(existingExpression, base.slots) || expressionsEquivalent(existingExpression, canonicalBefore);
|
|
773
588
|
const nextSlots = base.slots.map((slot) => {
|
|
774
589
|
if (slot.id !== slotId) {
|
|
775
590
|
return slot;
|
|
@@ -797,10 +612,23 @@ function updateBindingSlotRemap(binding, target, slotId, field, value) {
|
|
|
797
612
|
[field]: value
|
|
798
613
|
};
|
|
799
614
|
}
|
|
800
|
-
|
|
615
|
+
if (!expressionWasDefault) {
|
|
616
|
+
return updated;
|
|
617
|
+
}
|
|
618
|
+
const canonicalAfter = buildCanonicalExpressionFromSlots(updated.slots);
|
|
619
|
+
if (expressionsEquivalent(updated.expression ?? "", canonicalAfter)) {
|
|
620
|
+
return updated;
|
|
621
|
+
}
|
|
622
|
+
return {
|
|
623
|
+
...updated,
|
|
624
|
+
expression: canonicalAfter
|
|
625
|
+
};
|
|
801
626
|
}
|
|
802
627
|
function updateBindingWithInput(binding, target, input, slotId = PRIMARY_SLOT_ID) {
|
|
803
628
|
const base = ensurePrimarySlot(binding, target);
|
|
629
|
+
const existingExpression = typeof base.expression === "string" ? base.expression.trim() : "";
|
|
630
|
+
const canonicalBefore = buildCanonicalExpressionFromSlots(base.slots);
|
|
631
|
+
const expressionWasDefault = expressionMatchesAliasOnly(existingExpression, base.slots) || expressionsEquivalent(existingExpression, canonicalBefore);
|
|
804
632
|
const slotIndex = base.slots.findIndex((slot) => slot.id === slotId);
|
|
805
633
|
const effectiveIndex = slotIndex >= 0 ? slotIndex : base.slots.length;
|
|
806
634
|
const slots = base.slots.map((slot) => ({
|
|
@@ -817,9 +645,10 @@ function updateBindingWithInput(binding, target, input, slotId = PRIMARY_SLOT_ID
|
|
|
817
645
|
});
|
|
818
646
|
}
|
|
819
647
|
const currentSlot = slots[effectiveIndex];
|
|
648
|
+
let nextBinding;
|
|
820
649
|
if (!input) {
|
|
821
650
|
const normalizedSlotRemap = sanitizeRemap(currentSlot.remap, target);
|
|
822
|
-
const
|
|
651
|
+
const updatedRemap = {
|
|
823
652
|
...normalizedSlotRemap,
|
|
824
653
|
inLow: DEFAULT_INPUT_RANGE.min,
|
|
825
654
|
inAnchor: DEFAULT_INPUT_ANCHOR,
|
|
@@ -828,45 +657,59 @@ function updateBindingWithInput(binding, target, input, slotId = PRIMARY_SLOT_ID
|
|
|
828
657
|
slots[effectiveIndex] = {
|
|
829
658
|
...currentSlot,
|
|
830
659
|
inputId: null,
|
|
831
|
-
remap: cloneRemap(
|
|
660
|
+
remap: cloneRemap(updatedRemap)
|
|
832
661
|
};
|
|
833
662
|
if (effectiveIndex === 0) {
|
|
834
|
-
|
|
663
|
+
nextBinding = {
|
|
835
664
|
...base,
|
|
836
665
|
inputId: null,
|
|
837
|
-
remap: cloneRemap(
|
|
666
|
+
remap: cloneRemap(updatedRemap),
|
|
667
|
+
slots
|
|
668
|
+
};
|
|
669
|
+
} else {
|
|
670
|
+
nextBinding = {
|
|
671
|
+
...base,
|
|
838
672
|
slots
|
|
839
673
|
};
|
|
840
674
|
}
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
675
|
+
} else {
|
|
676
|
+
const normalizedRemap = sanitizeRemap(currentSlot.remap, target);
|
|
677
|
+
const updatedRemap = {
|
|
678
|
+
...normalizedRemap,
|
|
679
|
+
inLow: input.range.min,
|
|
680
|
+
inAnchor: clamp(input.defaultValue, input.range.min, input.range.max),
|
|
681
|
+
inHigh: input.range.max,
|
|
682
|
+
...deriveOutputDefaults(target)
|
|
844
683
|
};
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
const updatedRemap = {
|
|
848
|
-
...normalizedRemap,
|
|
849
|
-
inLow: input.range.min,
|
|
850
|
-
inAnchor: clamp(input.defaultValue, input.range.min, input.range.max),
|
|
851
|
-
inHigh: input.range.max,
|
|
852
|
-
...deriveOutputDefaults(target)
|
|
853
|
-
};
|
|
854
|
-
slots[effectiveIndex] = {
|
|
855
|
-
...currentSlot,
|
|
856
|
-
inputId: input.id,
|
|
857
|
-
remap: cloneRemap(updatedRemap)
|
|
858
|
-
};
|
|
859
|
-
if (effectiveIndex === 0) {
|
|
860
|
-
return {
|
|
861
|
-
...base,
|
|
684
|
+
slots[effectiveIndex] = {
|
|
685
|
+
...currentSlot,
|
|
862
686
|
inputId: input.id,
|
|
863
|
-
remap: cloneRemap(updatedRemap)
|
|
864
|
-
slots
|
|
687
|
+
remap: cloneRemap(updatedRemap)
|
|
865
688
|
};
|
|
689
|
+
if (effectiveIndex === 0) {
|
|
690
|
+
nextBinding = {
|
|
691
|
+
...base,
|
|
692
|
+
inputId: input.id,
|
|
693
|
+
remap: cloneRemap(updatedRemap),
|
|
694
|
+
slots
|
|
695
|
+
};
|
|
696
|
+
} else {
|
|
697
|
+
nextBinding = {
|
|
698
|
+
...base,
|
|
699
|
+
slots
|
|
700
|
+
};
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
if (!expressionWasDefault) {
|
|
704
|
+
return nextBinding;
|
|
705
|
+
}
|
|
706
|
+
const canonicalAfter = buildCanonicalExpressionFromSlots(nextBinding.slots);
|
|
707
|
+
if (expressionsEquivalent(nextBinding.expression ?? "", canonicalAfter)) {
|
|
708
|
+
return nextBinding;
|
|
866
709
|
}
|
|
867
710
|
return {
|
|
868
|
-
...
|
|
869
|
-
|
|
711
|
+
...nextBinding,
|
|
712
|
+
expression: canonicalAfter
|
|
870
713
|
};
|
|
871
714
|
}
|
|
872
715
|
function remapValue(value, remap) {
|
|
@@ -932,11 +775,6 @@ function reconcileBindings(previous, components) {
|
|
|
932
775
|
return next;
|
|
933
776
|
}
|
|
934
777
|
function bindingToDefinition(binding) {
|
|
935
|
-
const operators = binding.operators ? binding.operators.map((operator) => ({
|
|
936
|
-
type: operator.type,
|
|
937
|
-
enabled: !!operator.enabled,
|
|
938
|
-
params: { ...operator.params }
|
|
939
|
-
})) : void 0;
|
|
940
778
|
const definition = {
|
|
941
779
|
inputId: binding.inputId ?? null,
|
|
942
780
|
remap: cloneRemap(binding.remap),
|
|
@@ -945,7 +783,7 @@ function bindingToDefinition(binding) {
|
|
|
945
783
|
remap: cloneRemap(slot.remap)
|
|
946
784
|
})),
|
|
947
785
|
expression: binding.expression,
|
|
948
|
-
|
|
786
|
+
metadata: cloneBindingMetadata(binding.metadata)
|
|
949
787
|
};
|
|
950
788
|
return definition;
|
|
951
789
|
}
|
|
@@ -953,7 +791,6 @@ function bindingFromDefinition(target, definition) {
|
|
|
953
791
|
if (!definition) {
|
|
954
792
|
return createDefaultBinding(target);
|
|
955
793
|
}
|
|
956
|
-
const definitionOperators = definition.operators;
|
|
957
794
|
const binding = {
|
|
958
795
|
targetId: target.id,
|
|
959
796
|
inputId: definition.inputId ?? null,
|
|
@@ -963,17 +800,91 @@ function bindingFromDefinition(target, definition) {
|
|
|
963
800
|
remap: cloneRemap(slot.remap)
|
|
964
801
|
})),
|
|
965
802
|
expression: definition.expression,
|
|
966
|
-
|
|
967
|
-
type: operator.type,
|
|
968
|
-
enabled: !!operator.enabled,
|
|
969
|
-
params: { ...operator.params }
|
|
970
|
-
})) : void 0
|
|
803
|
+
metadata: cloneBindingMetadata(definition.metadata)
|
|
971
804
|
};
|
|
972
805
|
return ensureBindingStructure(binding, target);
|
|
973
806
|
}
|
|
807
|
+
function sanitizeLiteral(value) {
|
|
808
|
+
if (!Number.isFinite(value)) {
|
|
809
|
+
return 0;
|
|
810
|
+
}
|
|
811
|
+
if (Object.is(value, -0)) {
|
|
812
|
+
return 0;
|
|
813
|
+
}
|
|
814
|
+
return value;
|
|
815
|
+
}
|
|
816
|
+
function formatVectorLiteral(values) {
|
|
817
|
+
return `vec(${values.map((value) => sanitizeLiteral(value)).join(", ")})`;
|
|
818
|
+
}
|
|
819
|
+
function buildPiecewiseRemapExpression(alias, remap) {
|
|
820
|
+
const sanitizedAlias = alias && alias.trim().length > 0 ? alias.trim() : PRIMARY_SLOT_ALIAS;
|
|
821
|
+
const inputBreakpoints = [remap.inLow, remap.inAnchor, remap.inHigh];
|
|
822
|
+
const outputBreakpoints = [remap.outLow, remap.outAnchor, remap.outHigh];
|
|
823
|
+
return `piecewise_remap(${sanitizedAlias}, ${formatVectorLiteral(
|
|
824
|
+
inputBreakpoints
|
|
825
|
+
)}, ${formatVectorLiteral(outputBreakpoints)})`;
|
|
826
|
+
}
|
|
827
|
+
function isSelfAlias(alias) {
|
|
828
|
+
return alias.trim().toLowerCase() === "self";
|
|
829
|
+
}
|
|
830
|
+
function buildDefaultSlotExpression(alias, inputId, remap) {
|
|
831
|
+
const sanitizedAlias = alias && alias.trim().length > 0 ? alias.trim() : PRIMARY_SLOT_ALIAS;
|
|
832
|
+
if (inputId === import_utils.SELF_BINDING_ID || isSelfAlias(sanitizedAlias)) {
|
|
833
|
+
return sanitizedAlias;
|
|
834
|
+
}
|
|
835
|
+
return buildPiecewiseRemapExpression(sanitizedAlias, remap);
|
|
836
|
+
}
|
|
837
|
+
function normalizeSlotAliasForExpression(slot, index) {
|
|
838
|
+
if (slot.alias && slot.alias.trim().length > 0) {
|
|
839
|
+
return slot.alias.trim();
|
|
840
|
+
}
|
|
841
|
+
if (slot.id && slot.id.trim().length > 0) {
|
|
842
|
+
return slot.id.trim();
|
|
843
|
+
}
|
|
844
|
+
return defaultSlotId(index);
|
|
845
|
+
}
|
|
846
|
+
function buildAliasOnlyExpression(slots) {
|
|
847
|
+
if (!slots.length) {
|
|
848
|
+
return PRIMARY_SLOT_ALIAS;
|
|
849
|
+
}
|
|
850
|
+
return slots.map((slot, index) => normalizeSlotAliasForExpression(slot, index)).join(" + ");
|
|
851
|
+
}
|
|
852
|
+
function buildCanonicalExpressionFromSlots(slots) {
|
|
853
|
+
if (!slots.length) {
|
|
854
|
+
return PRIMARY_SLOT_ALIAS;
|
|
855
|
+
}
|
|
856
|
+
return slots.map(
|
|
857
|
+
(slot, index) => buildDefaultSlotExpression(
|
|
858
|
+
normalizeSlotAliasForExpression(slot, index),
|
|
859
|
+
slot.inputId ?? null,
|
|
860
|
+
slot.remap
|
|
861
|
+
)
|
|
862
|
+
).join(" + ");
|
|
863
|
+
}
|
|
864
|
+
function expressionsEquivalent(left, right) {
|
|
865
|
+
return left.trim() === right.trim();
|
|
866
|
+
}
|
|
867
|
+
function expressionMatchesAliasOnly(expression, slots) {
|
|
868
|
+
if (expression.trim().length === 0) {
|
|
869
|
+
return true;
|
|
870
|
+
}
|
|
871
|
+
const aliasOnly = buildAliasOnlyExpression(slots);
|
|
872
|
+
return expressionsEquivalent(expression, aliasOnly);
|
|
873
|
+
}
|
|
874
|
+
function buildCanonicalBindingExpression(binding) {
|
|
875
|
+
const slots = binding.slots ?? [];
|
|
876
|
+
return buildCanonicalExpressionFromSlots(slots);
|
|
877
|
+
}
|
|
974
878
|
|
|
975
879
|
// src/expression.ts
|
|
976
|
-
var
|
|
880
|
+
var STANDARD_WHITESPACE = /\s/;
|
|
881
|
+
var EXTRA_WHITESPACE_CHARS = /* @__PURE__ */ new Set(["\0", "\u200B", "\uFEFF"]);
|
|
882
|
+
function isWhitespaceCharacter(char) {
|
|
883
|
+
if (!char) {
|
|
884
|
+
return false;
|
|
885
|
+
}
|
|
886
|
+
return STANDARD_WHITESPACE.test(char) || EXTRA_WHITESPACE_CHARS.has(char);
|
|
887
|
+
}
|
|
977
888
|
var IDENT_START = /[A-Za-z_]/;
|
|
978
889
|
var IDENT_PART = /[A-Za-z0-9_]/;
|
|
979
890
|
var DIGIT = /[0-9]/;
|
|
@@ -1211,6 +1122,10 @@ var ControlExpressionParser = class {
|
|
|
1211
1122
|
});
|
|
1212
1123
|
return null;
|
|
1213
1124
|
}
|
|
1125
|
+
if (char === "[") {
|
|
1126
|
+
this.index += 1;
|
|
1127
|
+
return this.parseVectorLiteral("]", "vector literal");
|
|
1128
|
+
}
|
|
1214
1129
|
if (IDENT_START.test(char)) {
|
|
1215
1130
|
return this.parseIdentifierOrFunction();
|
|
1216
1131
|
}
|
|
@@ -1239,6 +1154,9 @@ var ControlExpressionParser = class {
|
|
|
1239
1154
|
this.skipWhitespace();
|
|
1240
1155
|
if (this.peek() === "(") {
|
|
1241
1156
|
this.index += 1;
|
|
1157
|
+
if (name.toLowerCase() === "vec") {
|
|
1158
|
+
return this.parseVectorLiteral(")", `"${name}" literal`);
|
|
1159
|
+
}
|
|
1242
1160
|
const args = [];
|
|
1243
1161
|
this.skipWhitespace();
|
|
1244
1162
|
if (this.peek() === ")") {
|
|
@@ -1301,28 +1219,134 @@ var ControlExpressionParser = class {
|
|
|
1301
1219
|
name
|
|
1302
1220
|
};
|
|
1303
1221
|
}
|
|
1304
|
-
|
|
1222
|
+
parseVectorLiteral(terminator, context) {
|
|
1223
|
+
const values = this.parseVectorLiteralValues(terminator, context);
|
|
1224
|
+
if (!values) {
|
|
1225
|
+
return null;
|
|
1226
|
+
}
|
|
1227
|
+
return {
|
|
1228
|
+
type: "VectorLiteral",
|
|
1229
|
+
values
|
|
1230
|
+
};
|
|
1231
|
+
}
|
|
1232
|
+
parseVectorLiteralValues(terminator, context) {
|
|
1233
|
+
const values = [];
|
|
1234
|
+
this.skipWhitespace();
|
|
1235
|
+
if (this.peek() === terminator) {
|
|
1236
|
+
this.errors.push({
|
|
1237
|
+
index: this.index,
|
|
1238
|
+
message: `Expected at least one value in ${context}.`
|
|
1239
|
+
});
|
|
1240
|
+
return null;
|
|
1241
|
+
}
|
|
1242
|
+
while (true) {
|
|
1243
|
+
this.skipWhitespace();
|
|
1244
|
+
const literalValue = this.parseNumericLiteralValue();
|
|
1245
|
+
if (literalValue === null) {
|
|
1246
|
+
this.errors.push({
|
|
1247
|
+
index: this.index,
|
|
1248
|
+
message: `Expected numeric literal in ${context}.`
|
|
1249
|
+
});
|
|
1250
|
+
return null;
|
|
1251
|
+
}
|
|
1252
|
+
values.push(literalValue);
|
|
1253
|
+
this.skipWhitespace();
|
|
1254
|
+
const next = this.peek();
|
|
1255
|
+
if (next === ",") {
|
|
1256
|
+
this.index += 1;
|
|
1257
|
+
this.skipWhitespace();
|
|
1258
|
+
if (this.peek() === terminator) {
|
|
1259
|
+
this.errors.push({
|
|
1260
|
+
index: this.index,
|
|
1261
|
+
message: `Expected value after "," in ${context}.`
|
|
1262
|
+
});
|
|
1263
|
+
return null;
|
|
1264
|
+
}
|
|
1265
|
+
continue;
|
|
1266
|
+
}
|
|
1267
|
+
if (next === terminator) {
|
|
1268
|
+
this.index += 1;
|
|
1269
|
+
break;
|
|
1270
|
+
}
|
|
1271
|
+
if (next === null) {
|
|
1272
|
+
this.errors.push({
|
|
1273
|
+
index: this.index,
|
|
1274
|
+
message: `Unterminated ${context}.`
|
|
1275
|
+
});
|
|
1276
|
+
} else {
|
|
1277
|
+
this.errors.push({
|
|
1278
|
+
index: this.index,
|
|
1279
|
+
message: `Expected "," or "${terminator}" in ${context}.`
|
|
1280
|
+
});
|
|
1281
|
+
}
|
|
1282
|
+
return null;
|
|
1283
|
+
}
|
|
1284
|
+
if (values.length === 0) {
|
|
1285
|
+
this.errors.push({
|
|
1286
|
+
index: this.index,
|
|
1287
|
+
message: `Expected at least one value in ${context}.`
|
|
1288
|
+
});
|
|
1289
|
+
return null;
|
|
1290
|
+
}
|
|
1291
|
+
return values;
|
|
1292
|
+
}
|
|
1293
|
+
parseNumericLiteralValue(allowLeadingSign = true) {
|
|
1305
1294
|
const start = this.index;
|
|
1295
|
+
if (allowLeadingSign && (this.peek() === "+" || this.peek() === "-")) {
|
|
1296
|
+
this.index += 1;
|
|
1297
|
+
}
|
|
1306
1298
|
let hasDigits = false;
|
|
1299
|
+
let seenDecimal = false;
|
|
1300
|
+
let seenExponent = false;
|
|
1301
|
+
let exponentDigits = false;
|
|
1302
|
+
let inExponent = false;
|
|
1307
1303
|
while (!this.isAtEnd()) {
|
|
1308
1304
|
const char = this.peek();
|
|
1309
1305
|
if (DIGIT.test(char)) {
|
|
1310
1306
|
hasDigits = true;
|
|
1307
|
+
if (inExponent) {
|
|
1308
|
+
exponentDigits = true;
|
|
1309
|
+
}
|
|
1310
|
+
this.index += 1;
|
|
1311
|
+
continue;
|
|
1312
|
+
}
|
|
1313
|
+
if (char === "." && !seenDecimal && !seenExponent) {
|
|
1314
|
+
seenDecimal = true;
|
|
1311
1315
|
this.index += 1;
|
|
1312
1316
|
continue;
|
|
1313
1317
|
}
|
|
1314
|
-
if (char === "
|
|
1318
|
+
if ((char === "e" || char === "E") && !seenExponent && hasDigits) {
|
|
1319
|
+
seenExponent = true;
|
|
1320
|
+
inExponent = true;
|
|
1321
|
+
exponentDigits = false;
|
|
1315
1322
|
this.index += 1;
|
|
1323
|
+
const sign = this.peek();
|
|
1324
|
+
if (sign === "+" || sign === "-") {
|
|
1325
|
+
this.index += 1;
|
|
1326
|
+
}
|
|
1316
1327
|
continue;
|
|
1317
1328
|
}
|
|
1318
1329
|
break;
|
|
1319
1330
|
}
|
|
1331
|
+
if (!hasDigits || seenExponent && !exponentDigits) {
|
|
1332
|
+
this.index = start;
|
|
1333
|
+
return null;
|
|
1334
|
+
}
|
|
1320
1335
|
const raw = this.input.slice(start, this.index);
|
|
1321
1336
|
const value = Number(raw);
|
|
1322
|
-
if (!
|
|
1337
|
+
if (!Number.isFinite(value)) {
|
|
1338
|
+
this.index = start;
|
|
1339
|
+
return null;
|
|
1340
|
+
}
|
|
1341
|
+
return value;
|
|
1342
|
+
}
|
|
1343
|
+
parseNumber() {
|
|
1344
|
+
const start = this.index;
|
|
1345
|
+
const value = this.parseNumericLiteralValue(false);
|
|
1346
|
+
if (value === null) {
|
|
1323
1347
|
this.errors.push({
|
|
1324
1348
|
index: start,
|
|
1325
|
-
message:
|
|
1349
|
+
message: "Invalid numeric literal."
|
|
1326
1350
|
});
|
|
1327
1351
|
return null;
|
|
1328
1352
|
}
|
|
@@ -1341,7 +1365,11 @@ var ControlExpressionParser = class {
|
|
|
1341
1365
|
return null;
|
|
1342
1366
|
}
|
|
1343
1367
|
skipWhitespace() {
|
|
1344
|
-
while (!this.isAtEnd()
|
|
1368
|
+
while (!this.isAtEnd()) {
|
|
1369
|
+
const char = this.peek();
|
|
1370
|
+
if (!isWhitespaceCharacter(char)) {
|
|
1371
|
+
break;
|
|
1372
|
+
}
|
|
1345
1373
|
this.index += 1;
|
|
1346
1374
|
}
|
|
1347
1375
|
}
|
|
@@ -1401,70 +1429,979 @@ function mapExpression(node, visit) {
|
|
|
1401
1429
|
}
|
|
1402
1430
|
|
|
1403
1431
|
// src/expressionFunctions.ts
|
|
1404
|
-
var
|
|
1405
|
-
var
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
{
|
|
1417
|
-
|
|
1418
|
-
|
|
1432
|
+
var import_metadata = require("@vizij/node-graph-wasm/metadata");
|
|
1433
|
+
var FUNCTION_OVERRIDES = {
|
|
1434
|
+
case: {
|
|
1435
|
+
replaceInputs: [
|
|
1436
|
+
{ id: "selector", optional: false, valueType: "any" },
|
|
1437
|
+
{ id: "default", optional: false, valueType: "any" }
|
|
1438
|
+
],
|
|
1439
|
+
variadic: { id: "operand", min: 1, max: null, valueType: "any" },
|
|
1440
|
+
minArgs: 3,
|
|
1441
|
+
maxArgs: null,
|
|
1442
|
+
params: []
|
|
1443
|
+
},
|
|
1444
|
+
slew: {
|
|
1445
|
+
dropTrailingInputs: 1,
|
|
1446
|
+
params: [
|
|
1447
|
+
{
|
|
1448
|
+
id: "max_rate",
|
|
1449
|
+
label: "max_rate",
|
|
1450
|
+
optional: false,
|
|
1451
|
+
valueType: "scalar"
|
|
1452
|
+
}
|
|
1453
|
+
],
|
|
1419
1454
|
minArgs: 2,
|
|
1420
1455
|
maxArgs: 2
|
|
1456
|
+
}
|
|
1457
|
+
};
|
|
1458
|
+
var FUNCTION_CONFIGS = [
|
|
1459
|
+
{
|
|
1460
|
+
typeId: "sin",
|
|
1461
|
+
names: ["sin"],
|
|
1462
|
+
category: "math",
|
|
1463
|
+
description: "Sine of the input value (radians)."
|
|
1421
1464
|
},
|
|
1422
|
-
{ typeId: "lessthan", names: ["lessthan", "lt"], minArgs: 2, maxArgs: 2 },
|
|
1423
|
-
{ typeId: "equal", names: ["equal", "eq"], minArgs: 2, maxArgs: 2 },
|
|
1424
1465
|
{
|
|
1425
|
-
typeId: "
|
|
1426
|
-
names: ["
|
|
1427
|
-
|
|
1428
|
-
|
|
1466
|
+
typeId: "cos",
|
|
1467
|
+
names: ["cos"],
|
|
1468
|
+
category: "math",
|
|
1469
|
+
description: "Cosine of the input value (radians)."
|
|
1429
1470
|
},
|
|
1430
|
-
{
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
{
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1471
|
+
{
|
|
1472
|
+
typeId: "tan",
|
|
1473
|
+
names: ["tan"],
|
|
1474
|
+
category: "math",
|
|
1475
|
+
description: "Tangent of the input value (radians)."
|
|
1476
|
+
},
|
|
1477
|
+
{
|
|
1478
|
+
typeId: "power",
|
|
1479
|
+
names: ["power", "pow"],
|
|
1480
|
+
category: "math",
|
|
1481
|
+
description: "Raise a base value to an exponent."
|
|
1482
|
+
},
|
|
1483
|
+
{
|
|
1484
|
+
typeId: "log",
|
|
1485
|
+
names: ["log"],
|
|
1486
|
+
category: "math",
|
|
1487
|
+
description: "Logarithm of the input value."
|
|
1488
|
+
},
|
|
1489
|
+
{
|
|
1490
|
+
typeId: "clamp",
|
|
1491
|
+
names: ["clamp"],
|
|
1492
|
+
category: "utility",
|
|
1493
|
+
description: "Clamp an input between min/max."
|
|
1494
|
+
},
|
|
1495
|
+
{
|
|
1496
|
+
typeId: "remap",
|
|
1497
|
+
names: ["remap"],
|
|
1498
|
+
category: "utility",
|
|
1499
|
+
description: "Linearly map a value from the input range to the output range."
|
|
1500
|
+
},
|
|
1501
|
+
{
|
|
1502
|
+
typeId: "centered_remap",
|
|
1503
|
+
names: ["centeredremap", "centered_remap"],
|
|
1504
|
+
category: "utility",
|
|
1505
|
+
description: "Remap a value using in/out ranges that include explicit anchors."
|
|
1506
|
+
},
|
|
1507
|
+
{
|
|
1508
|
+
typeId: "piecewise_remap",
|
|
1509
|
+
names: ["piecewiseremap", "piecewise_remap"],
|
|
1510
|
+
category: "utility",
|
|
1511
|
+
description: "Map a value through piecewise-linear breakpoints."
|
|
1512
|
+
},
|
|
1513
|
+
{
|
|
1514
|
+
typeId: "abs",
|
|
1515
|
+
names: ["abs"],
|
|
1516
|
+
category: "math",
|
|
1517
|
+
description: "Absolute value of the input."
|
|
1518
|
+
},
|
|
1519
|
+
{
|
|
1520
|
+
typeId: "add",
|
|
1521
|
+
names: ["add"],
|
|
1522
|
+
category: "math",
|
|
1523
|
+
description: "Sum all operands together."
|
|
1524
|
+
},
|
|
1525
|
+
{
|
|
1526
|
+
typeId: "multiply",
|
|
1527
|
+
names: ["multiply"],
|
|
1528
|
+
category: "math",
|
|
1529
|
+
description: "Multiply operands together."
|
|
1530
|
+
},
|
|
1531
|
+
{
|
|
1532
|
+
typeId: "subtract",
|
|
1533
|
+
names: ["subtract"],
|
|
1534
|
+
category: "math",
|
|
1535
|
+
description: "Subtract rhs from lhs."
|
|
1536
|
+
},
|
|
1537
|
+
{
|
|
1538
|
+
typeId: "divide",
|
|
1539
|
+
names: ["divide"],
|
|
1540
|
+
category: "math",
|
|
1541
|
+
description: "Divide lhs by rhs."
|
|
1542
|
+
},
|
|
1543
|
+
{
|
|
1544
|
+
typeId: "min",
|
|
1545
|
+
names: ["min"],
|
|
1546
|
+
category: "math",
|
|
1547
|
+
description: "Minimum of all operands."
|
|
1548
|
+
},
|
|
1549
|
+
{
|
|
1550
|
+
typeId: "max",
|
|
1551
|
+
names: ["max"],
|
|
1552
|
+
category: "math",
|
|
1553
|
+
description: "Maximum of all operands."
|
|
1554
|
+
},
|
|
1555
|
+
{
|
|
1556
|
+
typeId: "modulo",
|
|
1557
|
+
names: ["modulo", "mod"],
|
|
1558
|
+
category: "math",
|
|
1559
|
+
description: "Modulo of lhs by rhs."
|
|
1560
|
+
},
|
|
1561
|
+
{
|
|
1562
|
+
typeId: "greaterthan",
|
|
1563
|
+
names: ["greaterthan", "gt"],
|
|
1564
|
+
minArgs: 2,
|
|
1565
|
+
maxArgs: 2,
|
|
1566
|
+
category: "logic",
|
|
1567
|
+
description: "Return true when lhs > rhs."
|
|
1568
|
+
},
|
|
1569
|
+
{
|
|
1570
|
+
typeId: "lessthan",
|
|
1571
|
+
names: ["lessthan", "lt"],
|
|
1572
|
+
minArgs: 2,
|
|
1573
|
+
maxArgs: 2,
|
|
1574
|
+
category: "logic",
|
|
1575
|
+
description: "Return true when lhs < rhs."
|
|
1576
|
+
},
|
|
1577
|
+
{
|
|
1578
|
+
typeId: "equal",
|
|
1579
|
+
names: ["equal", "eq"],
|
|
1580
|
+
minArgs: 2,
|
|
1581
|
+
maxArgs: 2,
|
|
1582
|
+
category: "logic",
|
|
1583
|
+
description: "Return true when operands are equal."
|
|
1584
|
+
},
|
|
1585
|
+
{
|
|
1586
|
+
typeId: "notequal",
|
|
1587
|
+
names: ["notequal", "neq", "ne"],
|
|
1588
|
+
minArgs: 2,
|
|
1589
|
+
maxArgs: 2,
|
|
1590
|
+
category: "logic",
|
|
1591
|
+
description: "Return true when operands differ."
|
|
1592
|
+
},
|
|
1593
|
+
{
|
|
1594
|
+
typeId: "and",
|
|
1595
|
+
names: ["and"],
|
|
1596
|
+
minArgs: 2,
|
|
1597
|
+
maxArgs: 2,
|
|
1598
|
+
category: "logic",
|
|
1599
|
+
description: "Logical AND."
|
|
1600
|
+
},
|
|
1601
|
+
{
|
|
1602
|
+
typeId: "or",
|
|
1603
|
+
names: ["or"],
|
|
1604
|
+
minArgs: 2,
|
|
1605
|
+
maxArgs: 2,
|
|
1606
|
+
category: "logic",
|
|
1607
|
+
description: "Logical OR."
|
|
1608
|
+
},
|
|
1609
|
+
{
|
|
1610
|
+
typeId: "xor",
|
|
1611
|
+
names: ["xor"],
|
|
1612
|
+
minArgs: 2,
|
|
1613
|
+
maxArgs: 2,
|
|
1614
|
+
category: "logic",
|
|
1615
|
+
description: "Logical XOR."
|
|
1616
|
+
},
|
|
1617
|
+
{
|
|
1618
|
+
typeId: "not",
|
|
1619
|
+
names: ["not"],
|
|
1620
|
+
minArgs: 1,
|
|
1621
|
+
maxArgs: 1,
|
|
1622
|
+
category: "logic",
|
|
1623
|
+
description: "Logical NOT of input."
|
|
1624
|
+
},
|
|
1625
|
+
{
|
|
1626
|
+
typeId: "if",
|
|
1627
|
+
names: ["if"],
|
|
1628
|
+
minArgs: 2,
|
|
1629
|
+
maxArgs: 3,
|
|
1630
|
+
category: "logic",
|
|
1631
|
+
description: "Conditional branch with optional fallback."
|
|
1632
|
+
},
|
|
1633
|
+
{
|
|
1634
|
+
typeId: "round",
|
|
1635
|
+
names: ["round"],
|
|
1636
|
+
category: "math",
|
|
1637
|
+
description: "Round input using the configured mode (floor/ceil/trunc)."
|
|
1638
|
+
},
|
|
1639
|
+
{
|
|
1640
|
+
typeId: "case",
|
|
1641
|
+
names: ["case"],
|
|
1642
|
+
minArgs: 3,
|
|
1643
|
+
category: "logic",
|
|
1644
|
+
description: "Route the selector value to matching labeled branches."
|
|
1645
|
+
},
|
|
1646
|
+
{
|
|
1647
|
+
typeId: "time",
|
|
1648
|
+
names: ["time"],
|
|
1649
|
+
minArgs: 0,
|
|
1650
|
+
maxArgs: 0,
|
|
1651
|
+
category: "time",
|
|
1652
|
+
description: "Graph time in seconds."
|
|
1653
|
+
},
|
|
1654
|
+
{
|
|
1655
|
+
typeId: "oscillator",
|
|
1656
|
+
names: ["oscillator"],
|
|
1657
|
+
minArgs: 2,
|
|
1658
|
+
maxArgs: 2,
|
|
1659
|
+
category: "time",
|
|
1660
|
+
description: "Sine/cosine oscillator driven by time."
|
|
1661
|
+
},
|
|
1662
|
+
{
|
|
1663
|
+
typeId: "spring",
|
|
1664
|
+
names: ["spring"],
|
|
1665
|
+
category: "time",
|
|
1666
|
+
description: "Spring toward the target with configurable stiffness and damping."
|
|
1667
|
+
},
|
|
1668
|
+
{
|
|
1669
|
+
typeId: "damp",
|
|
1670
|
+
names: ["damp"],
|
|
1671
|
+
category: "time",
|
|
1672
|
+
description: "Damp input values toward zero at the specified rate."
|
|
1673
|
+
},
|
|
1674
|
+
{
|
|
1675
|
+
typeId: "slew",
|
|
1676
|
+
names: ["slew"],
|
|
1677
|
+
category: "time",
|
|
1678
|
+
description: "Limit the rate of change between inputs over time."
|
|
1679
|
+
},
|
|
1680
|
+
{
|
|
1681
|
+
typeId: "default-blend",
|
|
1682
|
+
names: ["defaultblend", "blend"],
|
|
1683
|
+
category: "utility",
|
|
1684
|
+
description: "Blend operand values using optional baseline/offset and weight inputs."
|
|
1685
|
+
},
|
|
1686
|
+
{
|
|
1687
|
+
typeId: "blendweightedaverage",
|
|
1688
|
+
names: ["blendweightedaverage"],
|
|
1689
|
+
category: "utility",
|
|
1690
|
+
description: "Compute weighted average blends using aggregate sums."
|
|
1691
|
+
},
|
|
1692
|
+
{
|
|
1693
|
+
typeId: "blendadditive",
|
|
1694
|
+
names: ["blendadditive"],
|
|
1695
|
+
category: "utility",
|
|
1696
|
+
description: "Additive blending helper."
|
|
1697
|
+
},
|
|
1698
|
+
{
|
|
1699
|
+
typeId: "blendmultiply",
|
|
1700
|
+
names: ["blendmultiply"],
|
|
1701
|
+
category: "utility",
|
|
1702
|
+
description: "Multiplicative blending helper."
|
|
1703
|
+
},
|
|
1704
|
+
{
|
|
1705
|
+
typeId: "blendweightedoverlay",
|
|
1706
|
+
names: ["blendweightedoverlay"],
|
|
1707
|
+
category: "utility",
|
|
1708
|
+
description: "Overlay blending helper driven by weighted sums."
|
|
1709
|
+
},
|
|
1710
|
+
{
|
|
1711
|
+
typeId: "blendweightedaverageoverlay",
|
|
1712
|
+
names: ["blendweightedaverageoverlay"],
|
|
1713
|
+
category: "utility",
|
|
1714
|
+
description: "Overlay helper that adds averaged deltas to the base value."
|
|
1715
|
+
},
|
|
1716
|
+
{
|
|
1717
|
+
typeId: "blendmax",
|
|
1718
|
+
names: ["blendmax"],
|
|
1719
|
+
category: "utility",
|
|
1720
|
+
description: "Select the operand whose effective weight is largest."
|
|
1721
|
+
},
|
|
1722
|
+
{
|
|
1723
|
+
typeId: "vec3cross",
|
|
1724
|
+
names: ["vec3cross", "cross"],
|
|
1725
|
+
category: "vector",
|
|
1726
|
+
description: "Cross product of vectors A \xD7 B."
|
|
1727
|
+
},
|
|
1728
|
+
{
|
|
1729
|
+
typeId: "vectoradd",
|
|
1730
|
+
names: ["vectoradd", "vadd"],
|
|
1731
|
+
category: "vector",
|
|
1732
|
+
description: "Element-wise sum of vectors."
|
|
1733
|
+
},
|
|
1734
|
+
{
|
|
1735
|
+
typeId: "vectorsubtract",
|
|
1736
|
+
names: ["vectorsubtract", "vsub"],
|
|
1737
|
+
category: "vector",
|
|
1738
|
+
description: "Element-wise subtraction of vectors."
|
|
1739
|
+
},
|
|
1740
|
+
{
|
|
1741
|
+
typeId: "vectormultiply",
|
|
1742
|
+
names: ["vectormultiply", "vmul"],
|
|
1743
|
+
category: "vector",
|
|
1744
|
+
description: "Element-wise multiplication of vectors."
|
|
1745
|
+
},
|
|
1746
|
+
{
|
|
1747
|
+
typeId: "vectorscale",
|
|
1748
|
+
names: ["vectorscale", "vscale"],
|
|
1749
|
+
category: "vector",
|
|
1750
|
+
description: "Scale a vector by a scalar value."
|
|
1751
|
+
},
|
|
1752
|
+
{
|
|
1753
|
+
typeId: "vectornormalize",
|
|
1754
|
+
names: ["vectornormalize", "vnormalize"],
|
|
1755
|
+
category: "vector",
|
|
1756
|
+
description: "Normalize a vector to unit length."
|
|
1757
|
+
},
|
|
1758
|
+
{
|
|
1759
|
+
typeId: "vectordot",
|
|
1760
|
+
names: ["vectordot", "vdot"],
|
|
1761
|
+
category: "vector",
|
|
1762
|
+
description: "Dot product of vectors A \xB7 B."
|
|
1763
|
+
},
|
|
1764
|
+
{
|
|
1765
|
+
typeId: "vectorlength",
|
|
1766
|
+
names: ["vectorlength", "vlength"],
|
|
1767
|
+
category: "vector",
|
|
1768
|
+
description: "Euclidean length of a vector."
|
|
1769
|
+
},
|
|
1770
|
+
{
|
|
1771
|
+
typeId: "vectorindex",
|
|
1772
|
+
names: ["vectorindex", "vindex"],
|
|
1773
|
+
category: "vector",
|
|
1774
|
+
description: "Extract a component from a vector."
|
|
1775
|
+
},
|
|
1776
|
+
{
|
|
1777
|
+
typeId: "vectorconstant",
|
|
1778
|
+
names: ["vectorconstant", "vconst"],
|
|
1779
|
+
category: "vector",
|
|
1780
|
+
description: "Constant vector value."
|
|
1781
|
+
},
|
|
1782
|
+
{
|
|
1783
|
+
typeId: "join",
|
|
1784
|
+
names: ["join"],
|
|
1785
|
+
category: "vector",
|
|
1786
|
+
description: "Join scalar inputs into a vector."
|
|
1787
|
+
},
|
|
1788
|
+
{
|
|
1789
|
+
typeId: "split",
|
|
1790
|
+
names: ["split"],
|
|
1791
|
+
category: "vector",
|
|
1792
|
+
description: "Split a vector into scalar outputs."
|
|
1793
|
+
},
|
|
1794
|
+
{
|
|
1795
|
+
typeId: "vectormin",
|
|
1796
|
+
names: ["vectormin"],
|
|
1797
|
+
category: "vector",
|
|
1798
|
+
description: "Minimum component in a vector."
|
|
1799
|
+
},
|
|
1800
|
+
{
|
|
1801
|
+
typeId: "vectormax",
|
|
1802
|
+
names: ["vectormax"],
|
|
1803
|
+
category: "vector",
|
|
1804
|
+
description: "Maximum component in a vector."
|
|
1805
|
+
},
|
|
1806
|
+
{
|
|
1807
|
+
typeId: "vectormean",
|
|
1808
|
+
names: ["vectormean"],
|
|
1809
|
+
category: "vector",
|
|
1810
|
+
description: "Mean of the provided vector values."
|
|
1811
|
+
},
|
|
1812
|
+
{
|
|
1813
|
+
typeId: "vectormedian",
|
|
1814
|
+
names: ["vectormedian"],
|
|
1815
|
+
category: "vector",
|
|
1816
|
+
description: "Median of the provided vector values."
|
|
1817
|
+
},
|
|
1818
|
+
{
|
|
1819
|
+
typeId: "vectormode",
|
|
1820
|
+
names: ["vectormode"],
|
|
1821
|
+
category: "vector",
|
|
1822
|
+
description: "Mode of the provided vector values."
|
|
1823
|
+
},
|
|
1824
|
+
{
|
|
1825
|
+
typeId: "weightedsumvector",
|
|
1826
|
+
names: ["weightedsumvector", "vectorsum"],
|
|
1827
|
+
category: "vector",
|
|
1828
|
+
description: "Weighted sum across vectors with optional masks."
|
|
1829
|
+
}
|
|
1830
|
+
];
|
|
1831
|
+
var SCALAR_FUNCTIONS = /* @__PURE__ */ new Map();
|
|
1832
|
+
var SCALAR_FUNCTION_VOCABULARY = [];
|
|
1833
|
+
for (const config of FUNCTION_CONFIGS) {
|
|
1834
|
+
const signature = (0, import_metadata.requireNodeSignature)(config.typeId);
|
|
1835
|
+
const signatureInputs = signature.inputs;
|
|
1836
|
+
let inputs = signatureInputs.map((input) => ({
|
|
1837
|
+
id: input.id,
|
|
1838
|
+
optional: Boolean(input.optional),
|
|
1839
|
+
valueType: inferExpressionValueType(input.ty)
|
|
1840
|
+
}));
|
|
1841
|
+
let variadic = signature.variadic_inputs ? {
|
|
1842
|
+
id: signature.variadic_inputs.id,
|
|
1448
1843
|
min: signature.variadic_inputs.min,
|
|
1449
|
-
max: signature.variadic_inputs.max
|
|
1844
|
+
max: typeof signature.variadic_inputs.max === "number" ? signature.variadic_inputs.max : null,
|
|
1845
|
+
valueType: inferExpressionValueType(signature.variadic_inputs.ty)
|
|
1450
1846
|
} : null;
|
|
1451
|
-
const
|
|
1452
|
-
const
|
|
1453
|
-
const
|
|
1454
|
-
|
|
1847
|
+
const baseRequiredInputs = inputs.filter((input) => !input.optional).length;
|
|
1848
|
+
const variadicMin = variadic?.min ?? 0;
|
|
1849
|
+
const derivedMin = baseRequiredInputs + variadicMin;
|
|
1850
|
+
let derivedMax;
|
|
1851
|
+
if (variadic) {
|
|
1852
|
+
derivedMax = variadic.max === null ? null : inputs.length + (variadic.max ?? 0);
|
|
1853
|
+
} else {
|
|
1854
|
+
derivedMax = inputs.length;
|
|
1855
|
+
}
|
|
1856
|
+
let params = buildParamArgumentSpecs(signature);
|
|
1857
|
+
const override = FUNCTION_OVERRIDES[config.typeId];
|
|
1858
|
+
if (override) {
|
|
1859
|
+
if (override.replaceInputs) {
|
|
1860
|
+
inputs = override.replaceInputs.map((input) => ({ ...input }));
|
|
1861
|
+
} else if (override.dropTrailingInputs) {
|
|
1862
|
+
const dropCount = Math.min(override.dropTrailingInputs, inputs.length);
|
|
1863
|
+
inputs = inputs.slice(0, inputs.length - dropCount);
|
|
1864
|
+
}
|
|
1865
|
+
if ("variadic" in override) {
|
|
1866
|
+
variadic = override.variadic ?? null;
|
|
1867
|
+
}
|
|
1868
|
+
if (override.params) {
|
|
1869
|
+
params = override.params.map((param) => ({ ...param }));
|
|
1870
|
+
}
|
|
1871
|
+
}
|
|
1872
|
+
const requiredParamCount = params.filter((param) => !param.optional).length;
|
|
1873
|
+
const minArgs = override?.minArgs !== void 0 ? override.minArgs : config.minArgs !== void 0 ? config.minArgs : derivedMin + requiredParamCount;
|
|
1874
|
+
const maxArgs = override?.maxArgs !== void 0 ? override.maxArgs : config.maxArgs !== void 0 ? config.maxArgs : derivedMax === null ? null : derivedMax + params.length;
|
|
1455
1875
|
const definition = {
|
|
1456
1876
|
nodeType: config.typeId,
|
|
1457
1877
|
inputs,
|
|
1458
1878
|
variadic,
|
|
1879
|
+
params,
|
|
1459
1880
|
minArgs,
|
|
1460
|
-
maxArgs
|
|
1881
|
+
maxArgs,
|
|
1882
|
+
resultValueType: inferExpressionValueType(
|
|
1883
|
+
signature.outputs?.[0]?.ty ?? null
|
|
1884
|
+
)
|
|
1461
1885
|
};
|
|
1886
|
+
if (config.typeId === "if" || config.typeId === "case") {
|
|
1887
|
+
const adjustedInputs = definition.inputs.map(
|
|
1888
|
+
(input, index) => {
|
|
1889
|
+
if (config.typeId === "if" && index === 0) {
|
|
1890
|
+
return input;
|
|
1891
|
+
}
|
|
1892
|
+
return {
|
|
1893
|
+
...input,
|
|
1894
|
+
valueType: "any"
|
|
1895
|
+
};
|
|
1896
|
+
}
|
|
1897
|
+
);
|
|
1898
|
+
definition.inputs = adjustedInputs;
|
|
1899
|
+
if (definition.variadic) {
|
|
1900
|
+
definition.variadic = {
|
|
1901
|
+
...definition.variadic,
|
|
1902
|
+
valueType: "any"
|
|
1903
|
+
};
|
|
1904
|
+
}
|
|
1905
|
+
definition.resultValueType = "any";
|
|
1906
|
+
}
|
|
1462
1907
|
const names = new Set(
|
|
1463
1908
|
[config.typeId, ...config.names].map((name) => name.toLowerCase())
|
|
1464
1909
|
);
|
|
1465
1910
|
names.forEach((name) => {
|
|
1466
1911
|
SCALAR_FUNCTIONS.set(name, definition);
|
|
1467
1912
|
});
|
|
1913
|
+
const orderedNames = Array.from(names);
|
|
1914
|
+
const displayName = orderedNames[0] ?? config.typeId;
|
|
1915
|
+
SCALAR_FUNCTION_VOCABULARY.push({
|
|
1916
|
+
name: displayName,
|
|
1917
|
+
aliases: orderedNames.slice(1),
|
|
1918
|
+
nodeType: config.typeId,
|
|
1919
|
+
category: config.category ?? "math",
|
|
1920
|
+
description: config.description
|
|
1921
|
+
});
|
|
1922
|
+
}
|
|
1923
|
+
function buildParamArgumentSpecs(signature) {
|
|
1924
|
+
if (!signature || !Array.isArray(signature.params)) {
|
|
1925
|
+
return [];
|
|
1926
|
+
}
|
|
1927
|
+
const params = signature.params;
|
|
1928
|
+
return params.map((param) => ({
|
|
1929
|
+
id: param.id,
|
|
1930
|
+
label: param.label ?? param.id,
|
|
1931
|
+
doc: param.doc ?? void 0,
|
|
1932
|
+
optional: param.default_json !== void 0,
|
|
1933
|
+
valueType: inferExpressionValueType(param.ty),
|
|
1934
|
+
min: typeof param.min === "number" ? param.min : void 0,
|
|
1935
|
+
max: typeof param.max === "number" ? param.max : void 0
|
|
1936
|
+
}));
|
|
1937
|
+
}
|
|
1938
|
+
function inferExpressionValueType(ty) {
|
|
1939
|
+
if (!ty) {
|
|
1940
|
+
return "scalar";
|
|
1941
|
+
}
|
|
1942
|
+
const normalized = ty.toLowerCase();
|
|
1943
|
+
if (normalized === "any") {
|
|
1944
|
+
return "any";
|
|
1945
|
+
}
|
|
1946
|
+
if (normalized === "vector" || normalized === "vec2" || normalized === "vec3" || normalized === "vec4" || normalized === "quat" || normalized === "colorrgba" || normalized === "transform" || normalized === "array" || normalized === "list" || normalized === "record") {
|
|
1947
|
+
return "vector";
|
|
1948
|
+
}
|
|
1949
|
+
if (normalized === "bool" || normalized === "boolean") {
|
|
1950
|
+
return "boolean";
|
|
1951
|
+
}
|
|
1952
|
+
return "scalar";
|
|
1953
|
+
}
|
|
1954
|
+
|
|
1955
|
+
// src/expressionVariables.ts
|
|
1956
|
+
var DefaultExpressionVariableTable = class {
|
|
1957
|
+
constructor() {
|
|
1958
|
+
this.variables = /* @__PURE__ */ new Map();
|
|
1959
|
+
this.order = [];
|
|
1960
|
+
}
|
|
1961
|
+
registerSlotVariable(options) {
|
|
1962
|
+
this.upsert({
|
|
1963
|
+
name: options.name,
|
|
1964
|
+
kind: "slot",
|
|
1965
|
+
nodeId: options.nodeId,
|
|
1966
|
+
metadata: {
|
|
1967
|
+
slotId: options.slotId,
|
|
1968
|
+
slotAlias: options.slotAlias,
|
|
1969
|
+
inputId: options.inputId,
|
|
1970
|
+
targetId: options.targetId,
|
|
1971
|
+
animatableId: options.animatableId,
|
|
1972
|
+
component: options.component,
|
|
1973
|
+
valueType: options.valueType,
|
|
1974
|
+
remap: options.remap,
|
|
1975
|
+
autoRemap: options.autoRemap
|
|
1976
|
+
}
|
|
1977
|
+
});
|
|
1978
|
+
}
|
|
1979
|
+
registerReservedVariable(options) {
|
|
1980
|
+
this.upsert({
|
|
1981
|
+
name: options.name,
|
|
1982
|
+
kind: "reserved",
|
|
1983
|
+
nodeId: options.nodeId,
|
|
1984
|
+
description: options.description,
|
|
1985
|
+
metadata: {
|
|
1986
|
+
targetId: options.targetId,
|
|
1987
|
+
animatableId: options.animatableId,
|
|
1988
|
+
component: options.component
|
|
1989
|
+
}
|
|
1990
|
+
});
|
|
1991
|
+
}
|
|
1992
|
+
resolve(name) {
|
|
1993
|
+
return this.variables.get(name) ?? null;
|
|
1994
|
+
}
|
|
1995
|
+
resolveNodeId(name) {
|
|
1996
|
+
return this.variables.get(name)?.nodeId ?? null;
|
|
1997
|
+
}
|
|
1998
|
+
entries() {
|
|
1999
|
+
return this.order.map((name) => this.variables.get(name)).filter((entry) => Boolean(entry));
|
|
2000
|
+
}
|
|
2001
|
+
firstNodeId() {
|
|
2002
|
+
for (const name of this.order) {
|
|
2003
|
+
const nodeId = this.variables.get(name)?.nodeId;
|
|
2004
|
+
if (nodeId) {
|
|
2005
|
+
return nodeId;
|
|
2006
|
+
}
|
|
2007
|
+
}
|
|
2008
|
+
return null;
|
|
2009
|
+
}
|
|
2010
|
+
missing(names) {
|
|
2011
|
+
const missing = [];
|
|
2012
|
+
for (const name of names) {
|
|
2013
|
+
const entry = this.variables.get(name);
|
|
2014
|
+
if (!entry) {
|
|
2015
|
+
missing.push({ name, reason: "unknown" });
|
|
2016
|
+
continue;
|
|
2017
|
+
}
|
|
2018
|
+
if (!entry.nodeId) {
|
|
2019
|
+
missing.push({
|
|
2020
|
+
name,
|
|
2021
|
+
reason: "unresolved",
|
|
2022
|
+
entry
|
|
2023
|
+
});
|
|
2024
|
+
}
|
|
2025
|
+
}
|
|
2026
|
+
return missing;
|
|
2027
|
+
}
|
|
2028
|
+
upsert(entry) {
|
|
2029
|
+
if (!this.variables.has(entry.name)) {
|
|
2030
|
+
this.order.push(entry.name);
|
|
2031
|
+
}
|
|
2032
|
+
this.variables.set(entry.name, entry);
|
|
2033
|
+
}
|
|
2034
|
+
};
|
|
2035
|
+
function createExpressionVariableTable() {
|
|
2036
|
+
return new DefaultExpressionVariableTable();
|
|
2037
|
+
}
|
|
2038
|
+
|
|
2039
|
+
// src/expressionVocabulary.ts
|
|
2040
|
+
var RESERVED_EXPRESSION_VARIABLES = [
|
|
2041
|
+
{
|
|
2042
|
+
name: "self",
|
|
2043
|
+
description: "Output of the current binding.",
|
|
2044
|
+
scope: "binding",
|
|
2045
|
+
defaultValueType: "scalar",
|
|
2046
|
+
available: true
|
|
2047
|
+
},
|
|
2048
|
+
{
|
|
2049
|
+
name: "time",
|
|
2050
|
+
description: "Elapsed time in seconds since the rig started.",
|
|
2051
|
+
scope: "graph",
|
|
2052
|
+
defaultValueType: "scalar",
|
|
2053
|
+
available: true
|
|
2054
|
+
},
|
|
2055
|
+
{
|
|
2056
|
+
name: "deltaTime",
|
|
2057
|
+
description: "Seconds elapsed since the previous frame update.",
|
|
2058
|
+
scope: "graph",
|
|
2059
|
+
defaultValueType: "scalar",
|
|
2060
|
+
available: true
|
|
2061
|
+
},
|
|
2062
|
+
{
|
|
2063
|
+
name: "frame",
|
|
2064
|
+
description: "Current frame counter.",
|
|
2065
|
+
scope: "graph",
|
|
2066
|
+
defaultValueType: "scalar",
|
|
2067
|
+
available: true
|
|
2068
|
+
}
|
|
2069
|
+
];
|
|
2070
|
+
var EXPRESSION_FUNCTION_VOCABULARY = SCALAR_FUNCTION_VOCABULARY;
|
|
2071
|
+
|
|
2072
|
+
// src/graphBuilder.ts
|
|
2073
|
+
var import_metadata2 = require("@vizij/node-graph-wasm/metadata");
|
|
2074
|
+
|
|
2075
|
+
// src/ir/builder.ts
|
|
2076
|
+
var graphSequence = 0;
|
|
2077
|
+
function generateGraphId(faceId) {
|
|
2078
|
+
graphSequence += 1;
|
|
2079
|
+
return `ir_${faceId}_${graphSequence}`;
|
|
2080
|
+
}
|
|
2081
|
+
var DefaultIrGraphBuilder = class {
|
|
2082
|
+
constructor(options) {
|
|
2083
|
+
this.nodes = [];
|
|
2084
|
+
this.edges = [];
|
|
2085
|
+
this.constants = [];
|
|
2086
|
+
this.issues = [];
|
|
2087
|
+
this.faceId = options.faceId;
|
|
2088
|
+
this.summary = {
|
|
2089
|
+
faceId: options.faceId,
|
|
2090
|
+
inputs: [],
|
|
2091
|
+
outputs: [],
|
|
2092
|
+
bindings: []
|
|
2093
|
+
};
|
|
2094
|
+
this.metadata = {
|
|
2095
|
+
source: options.source ?? "ir-builder",
|
|
2096
|
+
registryVersion: options.registryVersion,
|
|
2097
|
+
generatedAt: options.generatedAt,
|
|
2098
|
+
annotations: options.annotations
|
|
2099
|
+
};
|
|
2100
|
+
}
|
|
2101
|
+
addNode(node) {
|
|
2102
|
+
this.nodes.push(node);
|
|
2103
|
+
return node;
|
|
2104
|
+
}
|
|
2105
|
+
addEdge(edge) {
|
|
2106
|
+
this.edges.push(edge);
|
|
2107
|
+
return edge;
|
|
2108
|
+
}
|
|
2109
|
+
addConstant(constant) {
|
|
2110
|
+
this.constants.push(constant);
|
|
2111
|
+
return constant;
|
|
2112
|
+
}
|
|
2113
|
+
addIssue(issue) {
|
|
2114
|
+
this.issues.push(issue);
|
|
2115
|
+
return issue;
|
|
2116
|
+
}
|
|
2117
|
+
setSummary(summary) {
|
|
2118
|
+
this.summary = summary;
|
|
2119
|
+
}
|
|
2120
|
+
updateMetadata(metadata) {
|
|
2121
|
+
this.metadata = {
|
|
2122
|
+
...this.metadata,
|
|
2123
|
+
...metadata
|
|
2124
|
+
};
|
|
2125
|
+
}
|
|
2126
|
+
build() {
|
|
2127
|
+
return {
|
|
2128
|
+
id: generateGraphId(this.faceId),
|
|
2129
|
+
faceId: this.faceId,
|
|
2130
|
+
nodes: [...this.nodes],
|
|
2131
|
+
edges: [...this.edges],
|
|
2132
|
+
constants: [...this.constants],
|
|
2133
|
+
issues: [...this.issues],
|
|
2134
|
+
summary: { ...this.summary },
|
|
2135
|
+
metadata: { ...this.metadata }
|
|
2136
|
+
};
|
|
2137
|
+
}
|
|
2138
|
+
};
|
|
2139
|
+
function createIrGraphBuilder(options) {
|
|
2140
|
+
return new DefaultIrGraphBuilder(options);
|
|
2141
|
+
}
|
|
2142
|
+
function createLegacyIrGraph(payload) {
|
|
2143
|
+
const builder = createIrGraphBuilder({
|
|
2144
|
+
faceId: payload.faceId,
|
|
2145
|
+
registryVersion: payload.registryVersion,
|
|
2146
|
+
source: payload.source ?? "legacy-graph-builder",
|
|
2147
|
+
annotations: payload.annotations,
|
|
2148
|
+
generatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
2149
|
+
});
|
|
2150
|
+
builder.setSummary(payload.summary);
|
|
2151
|
+
(payload.issues ?? []).forEach((issue) => builder.addIssue(issue));
|
|
2152
|
+
const graph = builder.build();
|
|
2153
|
+
return {
|
|
2154
|
+
...graph,
|
|
2155
|
+
legacy: { spec: payload.spec }
|
|
2156
|
+
};
|
|
2157
|
+
}
|
|
2158
|
+
function toIrBindingSummary(summaries) {
|
|
2159
|
+
return summaries.map((summary) => ({
|
|
2160
|
+
...summary,
|
|
2161
|
+
remap: { ...summary.remap },
|
|
2162
|
+
issues: summary.issues ? [...summary.issues] : void 0
|
|
2163
|
+
}));
|
|
2164
|
+
}
|
|
2165
|
+
|
|
2166
|
+
// src/ir/compiler.ts
|
|
2167
|
+
function compileIrGraph(graph, options = {}) {
|
|
2168
|
+
const preferLegacy = options.preferLegacySpec === true;
|
|
2169
|
+
const legacySpec = graph.legacy?.spec;
|
|
2170
|
+
if (preferLegacy && legacySpec) {
|
|
2171
|
+
return {
|
|
2172
|
+
spec: legacySpec,
|
|
2173
|
+
issues: [...graph.issues]
|
|
2174
|
+
};
|
|
2175
|
+
}
|
|
2176
|
+
const convertedNodes = graph.nodes.map(convertIrNodeToNodeSpec);
|
|
2177
|
+
const existingNodeIds = new Set(convertedNodes.map((node) => node.id));
|
|
2178
|
+
graph.constants.forEach((constant) => {
|
|
2179
|
+
if (existingNodeIds.has(constant.id)) {
|
|
2180
|
+
return;
|
|
2181
|
+
}
|
|
2182
|
+
convertedNodes.push(convertIrConstantToNodeSpec(constant));
|
|
2183
|
+
});
|
|
2184
|
+
const convertedEdges = graph.edges.map(convertIrEdgeToGraphEdge);
|
|
2185
|
+
const spec = {
|
|
2186
|
+
nodes: convertedNodes,
|
|
2187
|
+
edges: convertedEdges.length > 0 ? convertedEdges : void 0
|
|
2188
|
+
};
|
|
2189
|
+
inlineSingleUseConstants(spec);
|
|
2190
|
+
const metadata = extractGraphSpecMetadata(graph);
|
|
2191
|
+
if (metadata !== void 0) {
|
|
2192
|
+
spec.metadata = metadata;
|
|
2193
|
+
}
|
|
2194
|
+
return {
|
|
2195
|
+
spec,
|
|
2196
|
+
issues: [...graph.issues]
|
|
2197
|
+
};
|
|
2198
|
+
}
|
|
2199
|
+
function convertIrNodeToNodeSpec(node) {
|
|
2200
|
+
const spec = {
|
|
2201
|
+
id: node.id,
|
|
2202
|
+
type: node.type
|
|
2203
|
+
};
|
|
2204
|
+
if (node.params) {
|
|
2205
|
+
spec.params = cloneJsonLike(node.params);
|
|
2206
|
+
}
|
|
2207
|
+
if (node.inputDefaults) {
|
|
2208
|
+
spec.input_defaults = cloneJsonLike(node.inputDefaults);
|
|
2209
|
+
}
|
|
2210
|
+
if (node.metadata) {
|
|
2211
|
+
spec.metadata = cloneJsonLike(node.metadata);
|
|
2212
|
+
}
|
|
2213
|
+
return spec;
|
|
2214
|
+
}
|
|
2215
|
+
function convertIrConstantToNodeSpec(constant) {
|
|
2216
|
+
const spec = {
|
|
2217
|
+
id: constant.id,
|
|
2218
|
+
type: "constant",
|
|
2219
|
+
params: {
|
|
2220
|
+
value: constant.value
|
|
2221
|
+
}
|
|
2222
|
+
};
|
|
2223
|
+
if (constant.metadata) {
|
|
2224
|
+
spec.metadata = cloneJsonLike(constant.metadata);
|
|
2225
|
+
}
|
|
2226
|
+
return spec;
|
|
2227
|
+
}
|
|
2228
|
+
function convertIrEdgeToGraphEdge(edge) {
|
|
2229
|
+
return {
|
|
2230
|
+
from: {
|
|
2231
|
+
node_id: edge.from.nodeId,
|
|
2232
|
+
output: edge.from.portId
|
|
2233
|
+
},
|
|
2234
|
+
to: {
|
|
2235
|
+
node_id: edge.to.nodeId,
|
|
2236
|
+
input: edge.to.portId
|
|
2237
|
+
}
|
|
2238
|
+
};
|
|
2239
|
+
}
|
|
2240
|
+
function extractGraphSpecMetadata(graph) {
|
|
2241
|
+
const annotations = graph.metadata.annotations;
|
|
2242
|
+
if (!annotations?.graphSpecMetadata) {
|
|
2243
|
+
return void 0;
|
|
2244
|
+
}
|
|
2245
|
+
return cloneJsonLike(annotations.graphSpecMetadata);
|
|
2246
|
+
}
|
|
2247
|
+
function cloneJsonLike(value) {
|
|
2248
|
+
if (value === void 0 || value === null) {
|
|
2249
|
+
return value;
|
|
2250
|
+
}
|
|
2251
|
+
return JSON.parse(JSON.stringify(value));
|
|
2252
|
+
}
|
|
2253
|
+
function inlineSingleUseConstants(spec) {
|
|
2254
|
+
const nodes = spec.nodes ?? [];
|
|
2255
|
+
const edges = spec.edges ? [...spec.edges] : [];
|
|
2256
|
+
const nodeById = new Map(nodes.map((node) => [node.id, node]));
|
|
2257
|
+
const constantUsage = /* @__PURE__ */ new Map();
|
|
2258
|
+
edges.forEach((edge) => {
|
|
2259
|
+
const source = nodeById.get(edge.from.node_id);
|
|
2260
|
+
if (source?.type === "constant") {
|
|
2261
|
+
constantUsage.set(source.id, (constantUsage.get(source.id) ?? 0) + 1);
|
|
2262
|
+
}
|
|
2263
|
+
});
|
|
2264
|
+
const updatedEdges = [];
|
|
2265
|
+
const constantsToRemove = /* @__PURE__ */ new Set();
|
|
2266
|
+
edges.forEach((edge) => {
|
|
2267
|
+
const source = nodeById.get(edge.from.node_id);
|
|
2268
|
+
if (source?.type === "constant" && constantUsage.get(source.id) === 1 && source.params && Object.prototype.hasOwnProperty.call(source.params, "value")) {
|
|
2269
|
+
const target = nodeById.get(edge.to.node_id);
|
|
2270
|
+
if (target) {
|
|
2271
|
+
const value = source.params.value;
|
|
2272
|
+
if (value !== void 0) {
|
|
2273
|
+
target.input_defaults = {
|
|
2274
|
+
...target.input_defaults ?? {},
|
|
2275
|
+
[edge.to.input ?? "in"]: value
|
|
2276
|
+
};
|
|
2277
|
+
nodeById.set(target.id, target);
|
|
2278
|
+
constantsToRemove.add(source.id);
|
|
2279
|
+
return;
|
|
2280
|
+
}
|
|
2281
|
+
}
|
|
2282
|
+
}
|
|
2283
|
+
updatedEdges.push(edge);
|
|
2284
|
+
});
|
|
2285
|
+
spec.nodes = nodes.filter((node) => !constantsToRemove.has(node.id));
|
|
2286
|
+
spec.edges = updatedEdges.length > 0 ? updatedEdges : void 0;
|
|
2287
|
+
}
|
|
2288
|
+
|
|
2289
|
+
// src/bindingMetadata.ts
|
|
2290
|
+
function cloneOperand(entry) {
|
|
2291
|
+
return JSON.parse(JSON.stringify(entry));
|
|
2292
|
+
}
|
|
2293
|
+
function describeSlot(entry) {
|
|
2294
|
+
const metadata = entry.metadata;
|
|
2295
|
+
return {
|
|
2296
|
+
kind: "slot",
|
|
2297
|
+
ref: entry.name,
|
|
2298
|
+
alias: metadata?.slotAlias ?? entry.name,
|
|
2299
|
+
slotId: metadata?.slotId,
|
|
2300
|
+
inputId: metadata?.inputId ?? null,
|
|
2301
|
+
valueType: metadata?.valueType
|
|
2302
|
+
};
|
|
2303
|
+
}
|
|
2304
|
+
function describeReserved(entry) {
|
|
2305
|
+
return {
|
|
2306
|
+
kind: "reserved",
|
|
2307
|
+
ref: entry.name,
|
|
2308
|
+
description: entry.description
|
|
2309
|
+
};
|
|
2310
|
+
}
|
|
2311
|
+
function describeReference(node, variables) {
|
|
2312
|
+
const entry = variables.resolve(node.name);
|
|
2313
|
+
if (!entry) {
|
|
2314
|
+
return {
|
|
2315
|
+
kind: "unknown",
|
|
2316
|
+
ref: node.name
|
|
2317
|
+
};
|
|
2318
|
+
}
|
|
2319
|
+
if (entry.kind === "slot") {
|
|
2320
|
+
return describeSlot(entry);
|
|
2321
|
+
}
|
|
2322
|
+
if (entry.kind === "reserved") {
|
|
2323
|
+
return describeReserved(entry);
|
|
2324
|
+
}
|
|
2325
|
+
return {
|
|
2326
|
+
kind: "unknown",
|
|
2327
|
+
ref: entry.name
|
|
2328
|
+
};
|
|
2329
|
+
}
|
|
2330
|
+
function stringifyExpression(node) {
|
|
2331
|
+
switch (node.type) {
|
|
2332
|
+
case "Literal":
|
|
2333
|
+
return Number.isFinite(node.value) ? `${node.value}` : "0";
|
|
2334
|
+
case "VectorLiteral":
|
|
2335
|
+
return `vec(${node.values.join(", ")})`;
|
|
2336
|
+
case "Reference":
|
|
2337
|
+
return node.name;
|
|
2338
|
+
case "Unary":
|
|
2339
|
+
return `${node.operator}${stringifyExpression(node.operand)}`;
|
|
2340
|
+
case "Binary":
|
|
2341
|
+
return `${stringifyExpression(node.left)} ${node.operator} ${stringifyExpression(node.right)}`;
|
|
2342
|
+
case "Function":
|
|
2343
|
+
return `${node.name}(${node.args.map(stringifyExpression).join(", ")})`;
|
|
2344
|
+
default:
|
|
2345
|
+
return "";
|
|
2346
|
+
}
|
|
2347
|
+
}
|
|
2348
|
+
function describeOperand(node, variables) {
|
|
2349
|
+
switch (node.type) {
|
|
2350
|
+
case "Literal":
|
|
2351
|
+
return {
|
|
2352
|
+
kind: "literal",
|
|
2353
|
+
literalValue: node.value
|
|
2354
|
+
};
|
|
2355
|
+
case "Reference":
|
|
2356
|
+
return describeReference(node, variables);
|
|
2357
|
+
case "Unary":
|
|
2358
|
+
case "Binary":
|
|
2359
|
+
case "Function":
|
|
2360
|
+
case "VectorLiteral":
|
|
2361
|
+
return {
|
|
2362
|
+
kind: "expression",
|
|
2363
|
+
expression: stringifyExpression(node)
|
|
2364
|
+
};
|
|
2365
|
+
default:
|
|
2366
|
+
return { kind: "unknown" };
|
|
2367
|
+
}
|
|
2368
|
+
}
|
|
2369
|
+
function describeCaseExpression(node, variables) {
|
|
2370
|
+
if (node.type !== "Function") {
|
|
2371
|
+
return null;
|
|
2372
|
+
}
|
|
2373
|
+
if (node.name.toLowerCase() !== "case") {
|
|
2374
|
+
return null;
|
|
2375
|
+
}
|
|
2376
|
+
if ((node.args?.length ?? 0) < 3) {
|
|
2377
|
+
return null;
|
|
2378
|
+
}
|
|
2379
|
+
const [selector, defaultBranch, ...branches] = node.args;
|
|
2380
|
+
return {
|
|
2381
|
+
kind: "case",
|
|
2382
|
+
selector: describeOperand(selector, variables),
|
|
2383
|
+
defaultBranch: describeOperand(defaultBranch, variables),
|
|
2384
|
+
branches: branches.map((branch) => describeOperand(branch, variables))
|
|
2385
|
+
};
|
|
2386
|
+
}
|
|
2387
|
+
function buildBindingMetadataFromExpression(node, variables) {
|
|
2388
|
+
if (!node) {
|
|
2389
|
+
return void 0;
|
|
2390
|
+
}
|
|
2391
|
+
const caseMetadata = describeCaseExpression(node, variables);
|
|
2392
|
+
if (!caseMetadata) {
|
|
2393
|
+
return void 0;
|
|
2394
|
+
}
|
|
2395
|
+
return {
|
|
2396
|
+
expression: {
|
|
2397
|
+
case: {
|
|
2398
|
+
kind: "case",
|
|
2399
|
+
selector: caseMetadata.selector ? cloneOperand(caseMetadata.selector) : void 0,
|
|
2400
|
+
defaultBranch: caseMetadata.defaultBranch ? cloneOperand(caseMetadata.defaultBranch) : void 0,
|
|
2401
|
+
branches: caseMetadata.branches.map(cloneOperand)
|
|
2402
|
+
}
|
|
2403
|
+
}
|
|
2404
|
+
};
|
|
1468
2405
|
}
|
|
1469
2406
|
|
|
1470
2407
|
// src/graphBuilder.ts
|
|
@@ -1484,10 +2421,15 @@ function evaluateBinding({
|
|
|
1484
2421
|
nodes,
|
|
1485
2422
|
edges,
|
|
1486
2423
|
constants: /* @__PURE__ */ new Map(),
|
|
1487
|
-
counter: 0
|
|
2424
|
+
counter: 0,
|
|
2425
|
+
reservedNodes: /* @__PURE__ */ new Map(),
|
|
2426
|
+
nodeValueTypes: /* @__PURE__ */ new Map(),
|
|
2427
|
+
slotRemapNodes: /* @__PURE__ */ new Map(),
|
|
2428
|
+
graphReservedNodes: context.graphReservedNodes,
|
|
2429
|
+
generateReservedNodeId: context.generateReservedNodeId
|
|
1488
2430
|
};
|
|
1489
2431
|
const targetValueType = target.valueType === "vector" ? "vector" : "scalar";
|
|
1490
|
-
const
|
|
2432
|
+
const variableTable = createExpressionVariableTable();
|
|
1491
2433
|
const slotSummaries = [];
|
|
1492
2434
|
const expressionIssues = [];
|
|
1493
2435
|
const rawExpression = typeof binding.expression === "string" ? binding.expression : "";
|
|
@@ -1504,6 +2446,11 @@ function evaluateBinding({
|
|
|
1504
2446
|
if (selfNodeId) {
|
|
1505
2447
|
slotOutputId = selfNodeId;
|
|
1506
2448
|
hasActiveSlot = true;
|
|
2449
|
+
setNodeValueType(
|
|
2450
|
+
exprContext,
|
|
2451
|
+
slotOutputId,
|
|
2452
|
+
slotValueType === "vector" ? "vector" : "scalar"
|
|
2453
|
+
);
|
|
1507
2454
|
} else {
|
|
1508
2455
|
expressionIssues.push("Self reference unavailable for this input.");
|
|
1509
2456
|
slotOutputId = getConstantNodeId(exprContext, target.defaultValue);
|
|
@@ -1511,25 +2458,13 @@ function evaluateBinding({
|
|
|
1511
2458
|
} else if (slot.inputId) {
|
|
1512
2459
|
const inputNode = ensureInputNode(slot.inputId);
|
|
1513
2460
|
if (inputNode) {
|
|
1514
|
-
|
|
1515
|
-
nodes.push({
|
|
1516
|
-
id: remapNodeId,
|
|
1517
|
-
type: "centered_remap",
|
|
1518
|
-
input_defaults: {
|
|
1519
|
-
in_low: slot.remap.inLow,
|
|
1520
|
-
in_anchor: slot.remap.inAnchor,
|
|
1521
|
-
in_high: slot.remap.inHigh,
|
|
1522
|
-
out_low: slot.remap.outLow,
|
|
1523
|
-
out_anchor: slot.remap.outAnchor,
|
|
1524
|
-
out_high: slot.remap.outHigh
|
|
1525
|
-
}
|
|
1526
|
-
});
|
|
1527
|
-
edges.push({
|
|
1528
|
-
from: { node_id: inputNode.nodeId },
|
|
1529
|
-
to: { node_id: remapNodeId, input: "in" }
|
|
1530
|
-
});
|
|
1531
|
-
slotOutputId = remapNodeId;
|
|
2461
|
+
slotOutputId = inputNode.nodeId;
|
|
1532
2462
|
hasActiveSlot = true;
|
|
2463
|
+
setNodeValueType(
|
|
2464
|
+
exprContext,
|
|
2465
|
+
slotOutputId,
|
|
2466
|
+
slotValueType === "vector" ? "vector" : "scalar"
|
|
2467
|
+
);
|
|
1533
2468
|
} else {
|
|
1534
2469
|
expressionIssues.push(`Missing standard input "${slot.inputId}".`);
|
|
1535
2470
|
slotOutputId = getConstantNodeId(exprContext, 0);
|
|
@@ -1537,7 +2472,24 @@ function evaluateBinding({
|
|
|
1537
2472
|
} else {
|
|
1538
2473
|
slotOutputId = getConstantNodeId(exprContext, 0);
|
|
1539
2474
|
}
|
|
1540
|
-
|
|
2475
|
+
variableTable.registerSlotVariable({
|
|
2476
|
+
name: alias,
|
|
2477
|
+
nodeId: slotOutputId,
|
|
2478
|
+
slotId,
|
|
2479
|
+
slotAlias: alias,
|
|
2480
|
+
inputId: slot.inputId ?? null,
|
|
2481
|
+
targetId,
|
|
2482
|
+
animatableId,
|
|
2483
|
+
component,
|
|
2484
|
+
valueType: slotValueType,
|
|
2485
|
+
remap: { ...slot.remap },
|
|
2486
|
+
autoRemap: slot.inputId !== import_utils3.SELF_BINDING_ID && slotValueType === "scalar"
|
|
2487
|
+
});
|
|
2488
|
+
setNodeValueType(
|
|
2489
|
+
exprContext,
|
|
2490
|
+
slotOutputId,
|
|
2491
|
+
slotValueType === "vector" ? "vector" : "scalar"
|
|
2492
|
+
);
|
|
1541
2493
|
slotSummaries.push({
|
|
1542
2494
|
targetId,
|
|
1543
2495
|
animatableId,
|
|
@@ -1547,12 +2499,32 @@ function evaluateBinding({
|
|
|
1547
2499
|
inputId: slot.inputId ?? null,
|
|
1548
2500
|
remap: { ...slot.remap },
|
|
1549
2501
|
expression: trimmedExpression,
|
|
1550
|
-
valueType: slotValueType
|
|
2502
|
+
valueType: slotValueType,
|
|
2503
|
+
nodeId: slotOutputId,
|
|
2504
|
+
expressionNodeId: slotOutputId
|
|
1551
2505
|
});
|
|
1552
2506
|
});
|
|
1553
2507
|
if (slotSummaries.length === 0) {
|
|
1554
2508
|
const alias = PRIMARY_SLOT_ALIAS;
|
|
1555
|
-
|
|
2509
|
+
const constantId = getConstantNodeId(exprContext, 0);
|
|
2510
|
+
variableTable.registerSlotVariable({
|
|
2511
|
+
name: alias,
|
|
2512
|
+
nodeId: constantId,
|
|
2513
|
+
slotId: PRIMARY_SLOT_ID,
|
|
2514
|
+
slotAlias: alias,
|
|
2515
|
+
inputId: null,
|
|
2516
|
+
targetId,
|
|
2517
|
+
animatableId,
|
|
2518
|
+
component,
|
|
2519
|
+
valueType: targetValueType,
|
|
2520
|
+
remap: createDefaultRemap(target),
|
|
2521
|
+
autoRemap: false
|
|
2522
|
+
});
|
|
2523
|
+
setNodeValueType(
|
|
2524
|
+
exprContext,
|
|
2525
|
+
constantId,
|
|
2526
|
+
targetValueType === "vector" ? "vector" : "scalar"
|
|
2527
|
+
);
|
|
1556
2528
|
slotSummaries.push({
|
|
1557
2529
|
targetId,
|
|
1558
2530
|
animatableId,
|
|
@@ -1562,26 +2534,51 @@ function evaluateBinding({
|
|
|
1562
2534
|
inputId: null,
|
|
1563
2535
|
remap: createDefaultRemap(target),
|
|
1564
2536
|
expression: trimmedExpression,
|
|
1565
|
-
valueType: targetValueType
|
|
2537
|
+
valueType: targetValueType,
|
|
2538
|
+
nodeId: constantId,
|
|
2539
|
+
expressionNodeId: constantId
|
|
1566
2540
|
});
|
|
1567
2541
|
}
|
|
2542
|
+
RESERVED_EXPRESSION_VARIABLES.forEach((reserved) => {
|
|
2543
|
+
if (reserved.available === false) {
|
|
2544
|
+
return;
|
|
2545
|
+
}
|
|
2546
|
+
let nodeId = null;
|
|
2547
|
+
if (reserved.name === "self") {
|
|
2548
|
+
nodeId = selfNodeId ?? null;
|
|
2549
|
+
} else {
|
|
2550
|
+
nodeId = ensureReservedVariableNode(reserved.name, exprContext);
|
|
2551
|
+
}
|
|
2552
|
+
variableTable.registerReservedVariable({
|
|
2553
|
+
name: reserved.name,
|
|
2554
|
+
nodeId,
|
|
2555
|
+
description: reserved.description,
|
|
2556
|
+
targetId: reserved.scope === "binding" ? targetId : void 0,
|
|
2557
|
+
animatableId: reserved.scope === "binding" ? animatableId : void 0,
|
|
2558
|
+
component: reserved.scope === "binding" ? component : void 0
|
|
2559
|
+
});
|
|
2560
|
+
});
|
|
1568
2561
|
const defaultAlias = slotSummaries[0]?.slotAlias ?? PRIMARY_SLOT_ALIAS;
|
|
1569
2562
|
const expressionText = trimmedExpression.length > 0 ? trimmedExpression : defaultAlias;
|
|
1570
2563
|
const parseResult = parseControlExpression(expressionText);
|
|
1571
2564
|
let expressionAst = null;
|
|
1572
2565
|
if (parseResult.node && parseResult.errors.length === 0) {
|
|
1573
|
-
const references =
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
missing.push(ref);
|
|
1578
|
-
}
|
|
1579
|
-
});
|
|
2566
|
+
const references = Array.from(
|
|
2567
|
+
collectExpressionReferences(parseResult.node)
|
|
2568
|
+
);
|
|
2569
|
+
const missing = variableTable.missing(references);
|
|
1580
2570
|
if (missing.length === 0) {
|
|
1581
2571
|
expressionAst = parseResult.node;
|
|
1582
2572
|
} else {
|
|
1583
|
-
|
|
1584
|
-
|
|
2573
|
+
validateLiteralParamArguments(parseResult.node, expressionIssues);
|
|
2574
|
+
missing.forEach((missingVar) => {
|
|
2575
|
+
if (missingVar.reason === "unresolved" && missingVar.entry?.kind === "reserved") {
|
|
2576
|
+
expressionIssues.push(
|
|
2577
|
+
`Reserved variable "${missingVar.name}" is unavailable for this binding.`
|
|
2578
|
+
);
|
|
2579
|
+
} else {
|
|
2580
|
+
expressionIssues.push(`Unknown control "${missingVar.name}".`);
|
|
2581
|
+
}
|
|
1585
2582
|
});
|
|
1586
2583
|
}
|
|
1587
2584
|
} else {
|
|
@@ -1589,22 +2586,30 @@ function evaluateBinding({
|
|
|
1589
2586
|
expressionIssues.push(error.message);
|
|
1590
2587
|
});
|
|
1591
2588
|
}
|
|
2589
|
+
const expressionMetadata = buildBindingMetadataFromExpression(
|
|
2590
|
+
expressionAst,
|
|
2591
|
+
variableTable
|
|
2592
|
+
);
|
|
1592
2593
|
let valueNodeId = null;
|
|
1593
2594
|
if (expressionAst) {
|
|
1594
2595
|
valueNodeId = materializeExpression(
|
|
1595
2596
|
expressionAst,
|
|
1596
2597
|
exprContext,
|
|
1597
|
-
|
|
2598
|
+
variableTable,
|
|
1598
2599
|
expressionIssues
|
|
1599
2600
|
);
|
|
1600
2601
|
}
|
|
1601
2602
|
if (!valueNodeId) {
|
|
1602
|
-
const
|
|
1603
|
-
valueNodeId =
|
|
2603
|
+
const fallbackNodeId = variableTable.resolveNodeId(defaultAlias) ?? variableTable.firstNodeId();
|
|
2604
|
+
valueNodeId = fallbackNodeId ?? getConstantNodeId(exprContext, 0);
|
|
1604
2605
|
}
|
|
1605
2606
|
const issuesCopy = expressionIssues.length ? [...new Set(expressionIssues)] : void 0;
|
|
1606
2607
|
slotSummaries.forEach((summary) => {
|
|
1607
2608
|
summary.expression = expressionText;
|
|
2609
|
+
summary.expressionNodeId = valueNodeId;
|
|
2610
|
+
if (expressionMetadata) {
|
|
2611
|
+
summary.metadata = expressionMetadata;
|
|
2612
|
+
}
|
|
1608
2613
|
if (issuesCopy && issuesCopy.length > 0) {
|
|
1609
2614
|
summary.issues = issuesCopy;
|
|
1610
2615
|
const issueSet = bindingIssues.get(summary.targetId) ?? /* @__PURE__ */ new Set();
|
|
@@ -1622,8 +2627,25 @@ function sanitizeNodeId(value) {
|
|
|
1622
2627
|
return value.replace(/[^a-zA-Z0-9_]/g, "_");
|
|
1623
2628
|
}
|
|
1624
2629
|
function buildRigInputPath(faceId, inputPath) {
|
|
1625
|
-
|
|
1626
|
-
|
|
2630
|
+
let trimmed = inputPath.startsWith("/") ? inputPath.slice(1) : inputPath;
|
|
2631
|
+
if (!trimmed) {
|
|
2632
|
+
return `rig/${faceId}`;
|
|
2633
|
+
}
|
|
2634
|
+
while (trimmed.startsWith("rig/")) {
|
|
2635
|
+
const segments = trimmed.split("/");
|
|
2636
|
+
if (segments.length >= 3) {
|
|
2637
|
+
const existingFaceId = segments[1];
|
|
2638
|
+
const remainder = segments.slice(2).join("/");
|
|
2639
|
+
if (existingFaceId === faceId) {
|
|
2640
|
+
return trimmed;
|
|
2641
|
+
}
|
|
2642
|
+
trimmed = remainder || "";
|
|
2643
|
+
} else {
|
|
2644
|
+
trimmed = segments.slice(1).join("/");
|
|
2645
|
+
}
|
|
2646
|
+
}
|
|
2647
|
+
const suffix = trimmed ? `/${trimmed}` : "";
|
|
2648
|
+
return `rig/${faceId}${suffix}`;
|
|
1627
2649
|
}
|
|
1628
2650
|
function getComponentOrder(animatable) {
|
|
1629
2651
|
switch (animatable.type) {
|
|
@@ -1679,6 +2701,101 @@ function extractComponentDefault(value, component) {
|
|
|
1679
2701
|
}
|
|
1680
2702
|
return 0;
|
|
1681
2703
|
}
|
|
2704
|
+
function setNodeValueType(context, nodeId, valueType) {
|
|
2705
|
+
context.nodeValueTypes.set(nodeId, valueType);
|
|
2706
|
+
}
|
|
2707
|
+
function getNodeValueType(context, nodeId) {
|
|
2708
|
+
return context.nodeValueTypes.get(nodeId) ?? "any";
|
|
2709
|
+
}
|
|
2710
|
+
function matchesValueType(actual, expected) {
|
|
2711
|
+
if (expected === "any" || actual === "any") {
|
|
2712
|
+
return true;
|
|
2713
|
+
}
|
|
2714
|
+
if (expected === "scalar") {
|
|
2715
|
+
return actual === "scalar" || actual === "boolean";
|
|
2716
|
+
}
|
|
2717
|
+
return actual === expected;
|
|
2718
|
+
}
|
|
2719
|
+
function ensureOperandValueType(context, operandId, expected, functionName, inputId, issues) {
|
|
2720
|
+
if (expected === "any") {
|
|
2721
|
+
return;
|
|
2722
|
+
}
|
|
2723
|
+
const actual = getNodeValueType(context, operandId);
|
|
2724
|
+
if (matchesValueType(actual, expected)) {
|
|
2725
|
+
return;
|
|
2726
|
+
}
|
|
2727
|
+
const expectation = expected === "vector" ? "a vector" : expected === "boolean" ? "a boolean" : "a scalar";
|
|
2728
|
+
issues.push(
|
|
2729
|
+
`Function "${functionName}" expects ${expectation} input for "${inputId}", but the expression produced ${actual}.`
|
|
2730
|
+
);
|
|
2731
|
+
}
|
|
2732
|
+
function resolveSlotReferenceNode(entry, fallbackNodeId, context) {
|
|
2733
|
+
if (entry.kind !== "slot") {
|
|
2734
|
+
return fallbackNodeId;
|
|
2735
|
+
}
|
|
2736
|
+
const metadata = entry.metadata;
|
|
2737
|
+
if (!metadata || metadata.autoRemap === false || !metadata.remap) {
|
|
2738
|
+
return fallbackNodeId;
|
|
2739
|
+
}
|
|
2740
|
+
if (metadata.valueType !== "scalar") {
|
|
2741
|
+
return fallbackNodeId;
|
|
2742
|
+
}
|
|
2743
|
+
if (isIdentityRemap(metadata.remap)) {
|
|
2744
|
+
return fallbackNodeId;
|
|
2745
|
+
}
|
|
2746
|
+
const cacheKey = metadata.slotId ?? entry.name;
|
|
2747
|
+
const existing = context.slotRemapNodes.get(cacheKey);
|
|
2748
|
+
if (existing) {
|
|
2749
|
+
return existing;
|
|
2750
|
+
}
|
|
2751
|
+
const remapNodeId = createSlotRemapNode(
|
|
2752
|
+
context,
|
|
2753
|
+
fallbackNodeId,
|
|
2754
|
+
metadata.remap,
|
|
2755
|
+
metadata.slotAlias ?? cacheKey
|
|
2756
|
+
);
|
|
2757
|
+
context.slotRemapNodes.set(cacheKey, remapNodeId);
|
|
2758
|
+
return remapNodeId;
|
|
2759
|
+
}
|
|
2760
|
+
function createSlotRemapNode(context, sourceNodeId, remap, slotKey) {
|
|
2761
|
+
const safeSlotKey = sanitizeNodeId(slotKey || "slot");
|
|
2762
|
+
const nodeId = `slot_remap_${safeSlotKey}_${context.counter++}`;
|
|
2763
|
+
context.nodes.push({
|
|
2764
|
+
id: nodeId,
|
|
2765
|
+
type: "centered_remap",
|
|
2766
|
+
inputDefaults: {
|
|
2767
|
+
in_low: remap.inLow,
|
|
2768
|
+
in_anchor: remap.inAnchor,
|
|
2769
|
+
in_high: remap.inHigh,
|
|
2770
|
+
out_low: remap.outLow,
|
|
2771
|
+
out_anchor: remap.outAnchor,
|
|
2772
|
+
out_high: remap.outHigh
|
|
2773
|
+
}
|
|
2774
|
+
});
|
|
2775
|
+
context.edges.push({
|
|
2776
|
+
from: { nodeId: sourceNodeId },
|
|
2777
|
+
to: { nodeId, portId: "in" }
|
|
2778
|
+
});
|
|
2779
|
+
setNodeValueType(context, nodeId, "scalar");
|
|
2780
|
+
return nodeId;
|
|
2781
|
+
}
|
|
2782
|
+
function isIdentityRemap(remap) {
|
|
2783
|
+
return nearlyEqual(remap.inLow, remap.outLow) && nearlyEqual(remap.inAnchor, remap.outAnchor) && nearlyEqual(remap.inHigh, remap.outHigh);
|
|
2784
|
+
}
|
|
2785
|
+
function nearlyEqual(a, b, epsilon = 1e-4) {
|
|
2786
|
+
return Math.abs(a - b) <= epsilon;
|
|
2787
|
+
}
|
|
2788
|
+
var REMAP_FUNCTION_NODE_TYPES = /* @__PURE__ */ new Set([
|
|
2789
|
+
"piecewise_remap",
|
|
2790
|
+
"centered_remap",
|
|
2791
|
+
"remap"
|
|
2792
|
+
]);
|
|
2793
|
+
function shouldSkipAutoRemapForArgument(nodeType, index) {
|
|
2794
|
+
if (!REMAP_FUNCTION_NODE_TYPES.has(nodeType)) {
|
|
2795
|
+
return false;
|
|
2796
|
+
}
|
|
2797
|
+
return index === 0;
|
|
2798
|
+
}
|
|
1682
2799
|
function getConstantNodeId(context, value) {
|
|
1683
2800
|
const key = Number.isFinite(value) ? value.toString() : "NaN";
|
|
1684
2801
|
const existing = context.constants.get(key);
|
|
@@ -1694,6 +2811,30 @@ function getConstantNodeId(context, value) {
|
|
|
1694
2811
|
}
|
|
1695
2812
|
});
|
|
1696
2813
|
context.constants.set(key, nodeId);
|
|
2814
|
+
setNodeValueType(context, nodeId, "scalar");
|
|
2815
|
+
return nodeId;
|
|
2816
|
+
}
|
|
2817
|
+
function getVectorConstantNodeId(context, values) {
|
|
2818
|
+
const normalized = values.map(
|
|
2819
|
+
(value) => Number.isFinite(value) ? value : 0
|
|
2820
|
+
);
|
|
2821
|
+
const key = `vector:${normalized.join(",")}`;
|
|
2822
|
+
const existing = context.constants.get(key);
|
|
2823
|
+
if (existing) {
|
|
2824
|
+
return existing;
|
|
2825
|
+
}
|
|
2826
|
+
const nodeId = `const_${context.componentSafeId}_${context.constants.size + 1}`;
|
|
2827
|
+
context.nodes.push({
|
|
2828
|
+
id: nodeId,
|
|
2829
|
+
type: "constant",
|
|
2830
|
+
params: {
|
|
2831
|
+
value: {
|
|
2832
|
+
vector: normalized
|
|
2833
|
+
}
|
|
2834
|
+
}
|
|
2835
|
+
});
|
|
2836
|
+
context.constants.set(key, nodeId);
|
|
2837
|
+
setNodeValueType(context, nodeId, "vector");
|
|
1697
2838
|
return nodeId;
|
|
1698
2839
|
}
|
|
1699
2840
|
function createBinaryOperationNode(context, operator, leftId, rightId) {
|
|
@@ -1702,15 +2843,16 @@ function createBinaryOperationNode(context, operator, leftId, rightId) {
|
|
|
1702
2843
|
id: nodeId,
|
|
1703
2844
|
type: operator
|
|
1704
2845
|
});
|
|
2846
|
+
setNodeValueType(context, nodeId, "scalar");
|
|
1705
2847
|
const leftInput = operator === "subtract" || operator === "divide" ? "lhs" : "operand_1";
|
|
1706
2848
|
const rightInput = operator === "subtract" || operator === "divide" ? "rhs" : "operand_2";
|
|
1707
2849
|
context.edges.push({
|
|
1708
|
-
from: {
|
|
1709
|
-
to: {
|
|
2850
|
+
from: { nodeId: leftId },
|
|
2851
|
+
to: { nodeId, portId: leftInput }
|
|
1710
2852
|
});
|
|
1711
2853
|
context.edges.push({
|
|
1712
|
-
from: {
|
|
1713
|
-
to: {
|
|
2854
|
+
from: { nodeId: rightId },
|
|
2855
|
+
to: { nodeId, portId: rightInput }
|
|
1714
2856
|
});
|
|
1715
2857
|
return nodeId;
|
|
1716
2858
|
}
|
|
@@ -1726,95 +2868,339 @@ function createVariadicOperationNode(context, operator, operandIds) {
|
|
|
1726
2868
|
id: nodeId,
|
|
1727
2869
|
type: operator
|
|
1728
2870
|
});
|
|
2871
|
+
setNodeValueType(context, nodeId, "scalar");
|
|
1729
2872
|
operandIds.forEach((operandId, index) => {
|
|
1730
2873
|
context.edges.push({
|
|
1731
|
-
from: {
|
|
1732
|
-
to: {
|
|
2874
|
+
from: { nodeId: operandId },
|
|
2875
|
+
to: { nodeId, portId: `operand_${index + 1}` }
|
|
1733
2876
|
});
|
|
1734
2877
|
});
|
|
1735
2878
|
return nodeId;
|
|
1736
2879
|
}
|
|
1737
|
-
function createNamedOperationNode(context, operator, inputNames, operandIds) {
|
|
2880
|
+
function createNamedOperationNode(context, operator, inputNames, operandIds, resultType = "scalar", params) {
|
|
1738
2881
|
const nodeId = `expr_${context.componentSafeId}_${context.counter++}`;
|
|
1739
|
-
|
|
2882
|
+
const node = {
|
|
1740
2883
|
id: nodeId,
|
|
1741
2884
|
type: operator
|
|
1742
|
-
}
|
|
2885
|
+
};
|
|
2886
|
+
if (params && Object.keys(params).length > 0) {
|
|
2887
|
+
node.params = params;
|
|
2888
|
+
}
|
|
2889
|
+
context.nodes.push(node);
|
|
2890
|
+
setNodeValueType(context, nodeId, resultType);
|
|
1743
2891
|
inputNames.forEach((inputName, index) => {
|
|
1744
2892
|
const operandId = operandIds[index];
|
|
1745
2893
|
context.edges.push({
|
|
1746
|
-
from: {
|
|
1747
|
-
to: {
|
|
2894
|
+
from: { nodeId: operandId },
|
|
2895
|
+
to: { nodeId, portId: inputName }
|
|
1748
2896
|
});
|
|
1749
2897
|
});
|
|
1750
2898
|
return nodeId;
|
|
1751
2899
|
}
|
|
1752
|
-
function
|
|
2900
|
+
function ensureReservedVariableNode(name, context) {
|
|
2901
|
+
const existing = context.reservedNodes.get(name);
|
|
2902
|
+
if (existing) {
|
|
2903
|
+
return existing;
|
|
2904
|
+
}
|
|
2905
|
+
if (name === "time" || name === "deltaTime" || name === "frame") {
|
|
2906
|
+
const nodeId = ensureGraphTimeNode(context);
|
|
2907
|
+
context.reservedNodes.set(name, nodeId);
|
|
2908
|
+
return nodeId;
|
|
2909
|
+
}
|
|
2910
|
+
return null;
|
|
2911
|
+
}
|
|
2912
|
+
function ensureGraphTimeNode(context) {
|
|
2913
|
+
const existing = context.graphReservedNodes.get("time");
|
|
2914
|
+
if (existing) {
|
|
2915
|
+
return existing;
|
|
2916
|
+
}
|
|
2917
|
+
const nodeId = context.generateReservedNodeId("time");
|
|
2918
|
+
context.nodes.push({
|
|
2919
|
+
id: nodeId,
|
|
2920
|
+
type: "time",
|
|
2921
|
+
metadata: {
|
|
2922
|
+
reservedVariable: "time"
|
|
2923
|
+
}
|
|
2924
|
+
});
|
|
2925
|
+
setNodeValueType(context, nodeId, "scalar");
|
|
2926
|
+
context.graphReservedNodes.set("time", nodeId);
|
|
2927
|
+
return nodeId;
|
|
2928
|
+
}
|
|
2929
|
+
function emitScalarFunctionNode(definition, operands, argNodes, totalArgCount, context, variables, issues, paramArgOverride) {
|
|
2930
|
+
if (definition.nodeType === "case") {
|
|
2931
|
+
return emitCaseFunctionNode(
|
|
2932
|
+
definition,
|
|
2933
|
+
operands,
|
|
2934
|
+
argNodes,
|
|
2935
|
+
context,
|
|
2936
|
+
variables,
|
|
2937
|
+
issues
|
|
2938
|
+
);
|
|
2939
|
+
}
|
|
2940
|
+
const orderedOperands = operands.slice(0, definition.inputs.length);
|
|
2941
|
+
definition.inputs.forEach((input, index) => {
|
|
2942
|
+
const operandId = orderedOperands[index];
|
|
2943
|
+
if (!operandId) {
|
|
2944
|
+
return;
|
|
2945
|
+
}
|
|
2946
|
+
ensureOperandValueType(
|
|
2947
|
+
context,
|
|
2948
|
+
operandId,
|
|
2949
|
+
input.valueType,
|
|
2950
|
+
definition.nodeType,
|
|
2951
|
+
input.id,
|
|
2952
|
+
issues
|
|
2953
|
+
);
|
|
2954
|
+
});
|
|
2955
|
+
const availableAfterInputs = Math.max(
|
|
2956
|
+
0,
|
|
2957
|
+
totalArgCount - definition.inputs.length
|
|
2958
|
+
);
|
|
2959
|
+
const paramArgCount = definition.params.length > 0 ? Math.min(definition.params.length, availableAfterInputs) : 0;
|
|
2960
|
+
const variadicArgCount = definition.variadic ? Math.max(0, availableAfterInputs - paramArgCount) : 0;
|
|
2961
|
+
const variadicOperands = definition.variadic ? operands.slice(
|
|
2962
|
+
definition.inputs.length,
|
|
2963
|
+
definition.inputs.length + variadicArgCount
|
|
2964
|
+
) : [];
|
|
1753
2965
|
if (definition.variadic) {
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
2966
|
+
variadicOperands.forEach((operandId, _variadicIndex) => {
|
|
2967
|
+
ensureOperandValueType(
|
|
2968
|
+
context,
|
|
2969
|
+
operandId,
|
|
2970
|
+
definition.variadic.valueType,
|
|
2971
|
+
definition.nodeType,
|
|
2972
|
+
definition.variadic.id,
|
|
2973
|
+
issues
|
|
2974
|
+
);
|
|
2975
|
+
});
|
|
2976
|
+
}
|
|
2977
|
+
const paramArgStart = definition.inputs.length + variadicArgCount;
|
|
2978
|
+
const paramArgNodes = paramArgCount > 0 ? paramArgOverride ?? argNodes.slice(paramArgStart, paramArgStart + paramArgCount) : [];
|
|
2979
|
+
const isSlewDebugEnabled = typeof process !== "undefined" && process?.env && process.env.DEBUG_SLEW === "1";
|
|
2980
|
+
if (isSlewDebugEnabled && definition.nodeType === "slew") {
|
|
2981
|
+
console.log("slew-debug", {
|
|
2982
|
+
totalArgs: totalArgCount,
|
|
2983
|
+
inputs: definition.inputs.length,
|
|
2984
|
+
paramCount: definition.params.length,
|
|
2985
|
+
paramArgCount,
|
|
2986
|
+
paramArgNodesTypes: paramArgNodes.map((node) => node?.type ?? null)
|
|
1758
2987
|
});
|
|
1759
|
-
|
|
2988
|
+
}
|
|
2989
|
+
const nodeParams = buildParamAssignments(definition, paramArgNodes, issues);
|
|
2990
|
+
if (definition.variadic && definition.inputs.length === 0) {
|
|
2991
|
+
const nodeId2 = `expr_${context.componentSafeId}_${context.counter++}`;
|
|
2992
|
+
const node = {
|
|
2993
|
+
id: nodeId2,
|
|
2994
|
+
type: definition.nodeType
|
|
2995
|
+
};
|
|
2996
|
+
if (nodeParams) {
|
|
2997
|
+
node.params = nodeParams;
|
|
2998
|
+
}
|
|
2999
|
+
context.nodes.push(node);
|
|
3000
|
+
variadicOperands.forEach((operandId, index) => {
|
|
1760
3001
|
context.edges.push({
|
|
1761
|
-
from: {
|
|
3002
|
+
from: { nodeId: operandId },
|
|
1762
3003
|
to: {
|
|
1763
|
-
|
|
1764
|
-
|
|
3004
|
+
nodeId: nodeId2,
|
|
3005
|
+
portId: `${definition.variadic.id}_${index + 1}`
|
|
1765
3006
|
}
|
|
1766
3007
|
});
|
|
1767
3008
|
});
|
|
1768
|
-
|
|
3009
|
+
setNodeValueType(context, nodeId2, definition.resultValueType);
|
|
3010
|
+
return nodeId2;
|
|
1769
3011
|
}
|
|
1770
3012
|
const providedNames = [];
|
|
1771
3013
|
const providedOperands = [];
|
|
1772
3014
|
definition.inputs.forEach((input, index) => {
|
|
1773
|
-
const operandId =
|
|
3015
|
+
const operandId = orderedOperands[index];
|
|
1774
3016
|
if (!operandId) {
|
|
1775
3017
|
return;
|
|
1776
3018
|
}
|
|
1777
3019
|
providedNames.push(input.id);
|
|
1778
3020
|
providedOperands.push(operandId);
|
|
1779
3021
|
});
|
|
1780
|
-
|
|
3022
|
+
const nodeId = createNamedOperationNode(
|
|
3023
|
+
context,
|
|
3024
|
+
definition.nodeType,
|
|
3025
|
+
providedNames,
|
|
3026
|
+
providedOperands,
|
|
3027
|
+
definition.resultValueType,
|
|
3028
|
+
nodeParams ?? void 0
|
|
3029
|
+
);
|
|
3030
|
+
if (definition.variadic) {
|
|
3031
|
+
variadicOperands.forEach((operandId, index) => {
|
|
3032
|
+
context.edges.push({
|
|
3033
|
+
from: { nodeId: operandId },
|
|
3034
|
+
to: {
|
|
3035
|
+
nodeId,
|
|
3036
|
+
portId: `${definition.variadic.id}_${index + 1}`
|
|
3037
|
+
}
|
|
3038
|
+
});
|
|
3039
|
+
});
|
|
3040
|
+
}
|
|
3041
|
+
return nodeId;
|
|
3042
|
+
}
|
|
3043
|
+
function emitCaseFunctionNode(definition, operands, argNodes, context, variables, issues) {
|
|
3044
|
+
const selectorId = operands[0];
|
|
3045
|
+
const defaultId = operands[1];
|
|
3046
|
+
const branchOperands = operands.slice(2);
|
|
3047
|
+
const branchArgs = argNodes.slice(2);
|
|
3048
|
+
if (!selectorId || branchOperands.length === 0) {
|
|
3049
|
+
issues.push(
|
|
3050
|
+
'Function "case" requires a selector, default, and at least one branch.'
|
|
3051
|
+
);
|
|
3052
|
+
return getConstantNodeId(context, 0);
|
|
3053
|
+
}
|
|
3054
|
+
const nodeId = `expr_${context.componentSafeId}_${context.counter++}`;
|
|
3055
|
+
const caseLabels = branchOperands.map((_, index) => {
|
|
3056
|
+
const extracted = extractCaseLabel(branchArgs[index], variables);
|
|
3057
|
+
if (extracted) {
|
|
3058
|
+
return extracted;
|
|
3059
|
+
}
|
|
3060
|
+
const fallback = `case_${index + 1}`;
|
|
3061
|
+
issues.push(
|
|
3062
|
+
`Case branch ${index + 1} is missing an alias; generated fallback label ${fallback}.`
|
|
3063
|
+
);
|
|
3064
|
+
return fallback;
|
|
3065
|
+
});
|
|
3066
|
+
context.nodes.push({
|
|
3067
|
+
id: nodeId,
|
|
3068
|
+
type: definition.nodeType,
|
|
3069
|
+
params: caseLabels.length > 0 ? { case_labels: caseLabels } : void 0
|
|
3070
|
+
});
|
|
3071
|
+
ensureOperandValueType(
|
|
1781
3072
|
context,
|
|
3073
|
+
selectorId,
|
|
3074
|
+
definition.inputs[0]?.valueType ?? "any",
|
|
1782
3075
|
definition.nodeType,
|
|
1783
|
-
|
|
1784
|
-
|
|
3076
|
+
definition.inputs[0]?.id ?? "selector",
|
|
3077
|
+
issues
|
|
1785
3078
|
);
|
|
3079
|
+
context.edges.push({
|
|
3080
|
+
from: { nodeId: selectorId },
|
|
3081
|
+
to: { nodeId, portId: definition.inputs[0]?.id ?? "selector" }
|
|
3082
|
+
});
|
|
3083
|
+
if (defaultId) {
|
|
3084
|
+
ensureOperandValueType(
|
|
3085
|
+
context,
|
|
3086
|
+
defaultId,
|
|
3087
|
+
definition.inputs[1]?.valueType ?? "any",
|
|
3088
|
+
definition.nodeType,
|
|
3089
|
+
"default",
|
|
3090
|
+
issues
|
|
3091
|
+
);
|
|
3092
|
+
context.edges.push({
|
|
3093
|
+
from: { nodeId: defaultId },
|
|
3094
|
+
to: { nodeId, portId: "default" }
|
|
3095
|
+
});
|
|
3096
|
+
}
|
|
3097
|
+
branchOperands.forEach((operandId, index) => {
|
|
3098
|
+
const portId = `${definition.variadic?.id ?? "operand"}_${index + 1}`;
|
|
3099
|
+
ensureOperandValueType(
|
|
3100
|
+
context,
|
|
3101
|
+
operandId,
|
|
3102
|
+
definition.variadic?.valueType ?? "any",
|
|
3103
|
+
definition.nodeType,
|
|
3104
|
+
portId,
|
|
3105
|
+
issues
|
|
3106
|
+
);
|
|
3107
|
+
context.edges.push({
|
|
3108
|
+
from: { nodeId: operandId },
|
|
3109
|
+
to: { nodeId, portId }
|
|
3110
|
+
});
|
|
3111
|
+
});
|
|
3112
|
+
setNodeValueType(context, nodeId, "any");
|
|
3113
|
+
return nodeId;
|
|
1786
3114
|
}
|
|
1787
|
-
function
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
3115
|
+
function buildParamAssignments(definition, paramArgNodes, issues) {
|
|
3116
|
+
if (!definition.params.length || paramArgNodes.length === 0) {
|
|
3117
|
+
return null;
|
|
3118
|
+
}
|
|
3119
|
+
const assignments = {};
|
|
3120
|
+
paramArgNodes.forEach((node, index) => {
|
|
3121
|
+
const spec = definition.params[index];
|
|
3122
|
+
if (!spec) {
|
|
1791
3123
|
return;
|
|
1792
3124
|
}
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
3125
|
+
const literal = extractParamLiteral(
|
|
3126
|
+
node,
|
|
3127
|
+
spec,
|
|
3128
|
+
definition.nodeType,
|
|
3129
|
+
issues
|
|
3130
|
+
);
|
|
3131
|
+
if (literal !== null) {
|
|
3132
|
+
assignments[spec.id] = literal;
|
|
1798
3133
|
}
|
|
1799
|
-
const nodeId = `${operator.type}_${safeId}_${index + 1}`;
|
|
1800
|
-
const params = {};
|
|
1801
|
-
definition.params.forEach((param) => {
|
|
1802
|
-
const configured = operator.params?.[param.id];
|
|
1803
|
-
params[param.id] = typeof configured === "number" ? configured : param.defaultValue;
|
|
1804
|
-
});
|
|
1805
|
-
nodes.push({
|
|
1806
|
-
id: nodeId,
|
|
1807
|
-
type: definition.nodeType,
|
|
1808
|
-
params
|
|
1809
|
-
});
|
|
1810
|
-
const inputId = definition.inputs[0] ?? "in";
|
|
1811
|
-
edges.push({
|
|
1812
|
-
from: { node_id: currentNodeId },
|
|
1813
|
-
to: { node_id: nodeId, input: inputId }
|
|
1814
|
-
});
|
|
1815
|
-
currentNodeId = nodeId;
|
|
1816
3134
|
});
|
|
1817
|
-
return
|
|
3135
|
+
return Object.keys(assignments).length > 0 ? assignments : null;
|
|
3136
|
+
}
|
|
3137
|
+
function extractParamLiteral(node, spec, functionName, issues) {
|
|
3138
|
+
if (spec.valueType === "vector") {
|
|
3139
|
+
if (node.type !== "VectorLiteral") {
|
|
3140
|
+
issues.push(
|
|
3141
|
+
`Function "${functionName}" requires a literal vector for "${spec.id}".`
|
|
3142
|
+
);
|
|
3143
|
+
return null;
|
|
3144
|
+
}
|
|
3145
|
+
if (!Array.isArray(node.values) || node.values.length === 0) {
|
|
3146
|
+
issues.push(
|
|
3147
|
+
`Function "${functionName}" requires at least one value for "${spec.id}".`
|
|
3148
|
+
);
|
|
3149
|
+
return null;
|
|
3150
|
+
}
|
|
3151
|
+
return node.values.map((value) => clampScalarParamValue(value, spec));
|
|
3152
|
+
}
|
|
3153
|
+
if (node.type !== "Literal") {
|
|
3154
|
+
issues.push(
|
|
3155
|
+
`Function "${functionName}" requires a literal ${describeParamExpectation(spec.valueType)} for "${spec.id}".`
|
|
3156
|
+
);
|
|
3157
|
+
return null;
|
|
3158
|
+
}
|
|
3159
|
+
const numeric = Number(node.value);
|
|
3160
|
+
if (!Number.isFinite(numeric)) {
|
|
3161
|
+
issues.push(
|
|
3162
|
+
`Function "${functionName}" requires a finite ${describeParamExpectation(spec.valueType)} for "${spec.id}".`
|
|
3163
|
+
);
|
|
3164
|
+
return null;
|
|
3165
|
+
}
|
|
3166
|
+
const clamped = clampScalarParamValue(numeric, spec);
|
|
3167
|
+
if (spec.valueType === "boolean") {
|
|
3168
|
+
return clamped !== 0;
|
|
3169
|
+
}
|
|
3170
|
+
return clamped;
|
|
3171
|
+
}
|
|
3172
|
+
function clampScalarParamValue(value, spec) {
|
|
3173
|
+
let next = Number.isFinite(value) ? value : 0;
|
|
3174
|
+
if (typeof spec.min === "number" && next < spec.min) {
|
|
3175
|
+
next = spec.min;
|
|
3176
|
+
}
|
|
3177
|
+
if (typeof spec.max === "number" && next > spec.max) {
|
|
3178
|
+
next = spec.max;
|
|
3179
|
+
}
|
|
3180
|
+
return next;
|
|
3181
|
+
}
|
|
3182
|
+
function describeParamExpectation(valueType) {
|
|
3183
|
+
switch (valueType) {
|
|
3184
|
+
case "vector":
|
|
3185
|
+
return "vector";
|
|
3186
|
+
case "boolean":
|
|
3187
|
+
return "boolean";
|
|
3188
|
+
default:
|
|
3189
|
+
return "scalar";
|
|
3190
|
+
}
|
|
3191
|
+
}
|
|
3192
|
+
function extractCaseLabel(node, variables) {
|
|
3193
|
+
if (!node || node.type !== "Reference") {
|
|
3194
|
+
return null;
|
|
3195
|
+
}
|
|
3196
|
+
const entry = variables.resolve(node.name);
|
|
3197
|
+
if (entry && entry.metadata && "slotAlias" in entry.metadata) {
|
|
3198
|
+
const alias = entry.metadata.slotAlias?.trim();
|
|
3199
|
+
if (alias && alias.length > 0) {
|
|
3200
|
+
return alias;
|
|
3201
|
+
}
|
|
3202
|
+
}
|
|
3203
|
+
return node.name;
|
|
1818
3204
|
}
|
|
1819
3205
|
function collectOperands(node, operator, target) {
|
|
1820
3206
|
if (node.type === "Binary" && node.operator === operator) {
|
|
@@ -1824,6 +3210,42 @@ function collectOperands(node, operator, target) {
|
|
|
1824
3210
|
}
|
|
1825
3211
|
target.push(node);
|
|
1826
3212
|
}
|
|
3213
|
+
function validateLiteralParamArguments(node, issues) {
|
|
3214
|
+
if (node.type === "Function") {
|
|
3215
|
+
const definition = SCALAR_FUNCTIONS.get(node.name.toLowerCase());
|
|
3216
|
+
if (definition && definition.params.length > 0) {
|
|
3217
|
+
const totalArgCount = node.args.length;
|
|
3218
|
+
const availableAfterInputs = Math.max(
|
|
3219
|
+
0,
|
|
3220
|
+
totalArgCount - definition.inputs.length
|
|
3221
|
+
);
|
|
3222
|
+
const paramArgCount = Math.min(
|
|
3223
|
+
definition.params.length,
|
|
3224
|
+
availableAfterInputs
|
|
3225
|
+
);
|
|
3226
|
+
const variadicArgCount = definition.variadic ? Math.max(0, availableAfterInputs - paramArgCount) : 0;
|
|
3227
|
+
const paramArgStart = definition.inputs.length + variadicArgCount;
|
|
3228
|
+
for (let index = 0; index < paramArgCount; index++) {
|
|
3229
|
+
const spec = definition.params[index];
|
|
3230
|
+
const paramNode = node.args[paramArgStart + index];
|
|
3231
|
+
if (!spec || !paramNode) {
|
|
3232
|
+
continue;
|
|
3233
|
+
}
|
|
3234
|
+
extractParamLiteral(paramNode, spec, node.name, issues);
|
|
3235
|
+
}
|
|
3236
|
+
}
|
|
3237
|
+
node.args.forEach((child) => validateLiteralParamArguments(child, issues));
|
|
3238
|
+
return;
|
|
3239
|
+
}
|
|
3240
|
+
if (node.type === "Unary") {
|
|
3241
|
+
validateLiteralParamArguments(node.operand, issues);
|
|
3242
|
+
return;
|
|
3243
|
+
}
|
|
3244
|
+
if (node.type === "Binary") {
|
|
3245
|
+
validateLiteralParamArguments(node.left, issues);
|
|
3246
|
+
validateLiteralParamArguments(node.right, issues);
|
|
3247
|
+
}
|
|
3248
|
+
}
|
|
1827
3249
|
var BINARY_FUNCTION_OPERATOR_MAP = {
|
|
1828
3250
|
">": "greaterthan",
|
|
1829
3251
|
"<": "lessthan",
|
|
@@ -1832,24 +3254,32 @@ var BINARY_FUNCTION_OPERATOR_MAP = {
|
|
|
1832
3254
|
"&&": "and",
|
|
1833
3255
|
"||": "or"
|
|
1834
3256
|
};
|
|
1835
|
-
function materializeExpression(node, context,
|
|
3257
|
+
function materializeExpression(node, context, variables, issues, options) {
|
|
3258
|
+
const autoRemap = options?.autoRemap !== false;
|
|
1836
3259
|
switch (node.type) {
|
|
1837
3260
|
case "Literal": {
|
|
1838
3261
|
return getConstantNodeId(context, node.value);
|
|
1839
3262
|
}
|
|
3263
|
+
case "VectorLiteral": {
|
|
3264
|
+
return getVectorConstantNodeId(context, node.values);
|
|
3265
|
+
}
|
|
1840
3266
|
case "Reference": {
|
|
1841
|
-
const
|
|
1842
|
-
if (!
|
|
3267
|
+
const entry = variables.resolve(node.name);
|
|
3268
|
+
if (!entry) {
|
|
1843
3269
|
issues.push(`Unknown control "${node.name}".`);
|
|
1844
3270
|
return getConstantNodeId(context, 0);
|
|
1845
3271
|
}
|
|
1846
|
-
|
|
3272
|
+
const mappedId = entry.nodeId ?? getConstantNodeId(context, 0);
|
|
3273
|
+
if (!autoRemap || entry.kind !== "slot") {
|
|
3274
|
+
return mappedId;
|
|
3275
|
+
}
|
|
3276
|
+
return resolveSlotReferenceNode(entry, mappedId, context);
|
|
1847
3277
|
}
|
|
1848
3278
|
case "Unary": {
|
|
1849
3279
|
const operandId = materializeExpression(
|
|
1850
3280
|
node.operand,
|
|
1851
3281
|
context,
|
|
1852
|
-
|
|
3282
|
+
variables,
|
|
1853
3283
|
issues
|
|
1854
3284
|
);
|
|
1855
3285
|
switch (node.operator) {
|
|
@@ -1868,7 +3298,15 @@ function materializeExpression(node, context, aliasNodes, issues) {
|
|
|
1868
3298
|
issues.push('Function "not" is not available in metadata.');
|
|
1869
3299
|
return getConstantNodeId(context, 0);
|
|
1870
3300
|
}
|
|
1871
|
-
return emitScalarFunctionNode(
|
|
3301
|
+
return emitScalarFunctionNode(
|
|
3302
|
+
definition,
|
|
3303
|
+
[operandId],
|
|
3304
|
+
[node.operand],
|
|
3305
|
+
1,
|
|
3306
|
+
context,
|
|
3307
|
+
variables,
|
|
3308
|
+
issues
|
|
3309
|
+
);
|
|
1872
3310
|
}
|
|
1873
3311
|
default:
|
|
1874
3312
|
issues.push("Unsupported unary operator.");
|
|
@@ -1881,7 +3319,7 @@ function materializeExpression(node, context, aliasNodes, issues) {
|
|
|
1881
3319
|
const children = [];
|
|
1882
3320
|
collectOperands(node, "+", children);
|
|
1883
3321
|
const operandIds = children.map(
|
|
1884
|
-
(child) => materializeExpression(child, context,
|
|
3322
|
+
(child) => materializeExpression(child, context, variables, issues)
|
|
1885
3323
|
);
|
|
1886
3324
|
return createVariadicOperationNode(context, "add", operandIds);
|
|
1887
3325
|
}
|
|
@@ -1889,20 +3327,20 @@ function materializeExpression(node, context, aliasNodes, issues) {
|
|
|
1889
3327
|
const children = [];
|
|
1890
3328
|
collectOperands(node, "*", children);
|
|
1891
3329
|
const operandIds = children.map(
|
|
1892
|
-
(child) => materializeExpression(child, context,
|
|
3330
|
+
(child) => materializeExpression(child, context, variables, issues)
|
|
1893
3331
|
);
|
|
1894
3332
|
return createVariadicOperationNode(context, "multiply", operandIds);
|
|
1895
3333
|
}
|
|
1896
3334
|
const leftId = materializeExpression(
|
|
1897
3335
|
node.left,
|
|
1898
3336
|
context,
|
|
1899
|
-
|
|
3337
|
+
variables,
|
|
1900
3338
|
issues
|
|
1901
3339
|
);
|
|
1902
3340
|
const rightId = materializeExpression(
|
|
1903
3341
|
node.right,
|
|
1904
3342
|
context,
|
|
1905
|
-
|
|
3343
|
+
variables,
|
|
1906
3344
|
issues
|
|
1907
3345
|
);
|
|
1908
3346
|
if (operator === "-") {
|
|
@@ -1918,7 +3356,15 @@ function materializeExpression(node, context, aliasNodes, issues) {
|
|
|
1918
3356
|
issues.push(`Function "${mappedFunction}" is not available.`);
|
|
1919
3357
|
return getConstantNodeId(context, 0);
|
|
1920
3358
|
}
|
|
1921
|
-
return emitScalarFunctionNode(
|
|
3359
|
+
return emitScalarFunctionNode(
|
|
3360
|
+
definition,
|
|
3361
|
+
[leftId, rightId],
|
|
3362
|
+
[node.left, node.right],
|
|
3363
|
+
2,
|
|
3364
|
+
context,
|
|
3365
|
+
variables,
|
|
3366
|
+
issues
|
|
3367
|
+
);
|
|
1922
3368
|
}
|
|
1923
3369
|
issues.push(`Unsupported operator "${operator}".`);
|
|
1924
3370
|
return getConstantNodeId(context, 0);
|
|
@@ -1931,22 +3377,61 @@ function materializeExpression(node, context, aliasNodes, issues) {
|
|
|
1931
3377
|
issues.push(`Unknown function "${name}".`);
|
|
1932
3378
|
return getConstantNodeId(context, 0);
|
|
1933
3379
|
}
|
|
1934
|
-
const
|
|
1935
|
-
|
|
1936
|
-
)
|
|
1937
|
-
if (operands.length < definition.minArgs) {
|
|
3380
|
+
const argNodes = node.args;
|
|
3381
|
+
const argCount = argNodes.length;
|
|
3382
|
+
if (argCount < definition.minArgs) {
|
|
1938
3383
|
issues.push(
|
|
1939
|
-
`Function "${name}" expects at least ${definition.minArgs} arguments, received ${
|
|
3384
|
+
`Function "${name}" expects at least ${definition.minArgs} arguments, received ${argCount}.`
|
|
1940
3385
|
);
|
|
1941
3386
|
return getConstantNodeId(context, 0);
|
|
1942
3387
|
}
|
|
1943
|
-
if (definition.maxArgs !== null &&
|
|
3388
|
+
if (definition.maxArgs !== null && argCount > definition.maxArgs) {
|
|
1944
3389
|
issues.push(
|
|
1945
|
-
`Function "${name}" expects at most ${definition.maxArgs} arguments, received ${
|
|
3390
|
+
`Function "${name}" expects at most ${definition.maxArgs} arguments, received ${argCount}.`
|
|
1946
3391
|
);
|
|
1947
3392
|
return getConstantNodeId(context, 0);
|
|
1948
3393
|
}
|
|
1949
|
-
|
|
3394
|
+
if (name === "slew") {
|
|
3395
|
+
const maxRateArg = argNodes[1];
|
|
3396
|
+
if (!maxRateArg || maxRateArg.type !== "Literal") {
|
|
3397
|
+
issues.push(
|
|
3398
|
+
'Function "slew" requires a literal scalar for "max_rate".'
|
|
3399
|
+
);
|
|
3400
|
+
}
|
|
3401
|
+
}
|
|
3402
|
+
const availableAfterInputs = Math.max(
|
|
3403
|
+
0,
|
|
3404
|
+
argCount - definition.inputs.length
|
|
3405
|
+
);
|
|
3406
|
+
const paramArgCount = definition.params.length > 0 ? Math.min(definition.params.length, availableAfterInputs) : 0;
|
|
3407
|
+
const variadicArgCount = definition.variadic ? Math.max(0, availableAfterInputs - paramArgCount) : 0;
|
|
3408
|
+
const operandLimit = Math.min(
|
|
3409
|
+
argCount,
|
|
3410
|
+
definition.inputs.length + variadicArgCount
|
|
3411
|
+
);
|
|
3412
|
+
const operandNodes = argNodes.slice(0, operandLimit);
|
|
3413
|
+
const operands = operandNodes.map(
|
|
3414
|
+
(arg, index) => materializeExpression(
|
|
3415
|
+
arg,
|
|
3416
|
+
context,
|
|
3417
|
+
variables,
|
|
3418
|
+
issues,
|
|
3419
|
+
shouldSkipAutoRemapForArgument(definition.nodeType, index) ? { autoRemap: false } : void 0
|
|
3420
|
+
)
|
|
3421
|
+
);
|
|
3422
|
+
const paramArgStart = operandLimit;
|
|
3423
|
+
const paramArgNodes = paramArgCount > 0 ? argNodes.slice(paramArgStart, paramArgStart + paramArgCount) : [];
|
|
3424
|
+
const paramOverride = definition.nodeType === "case" ? void 0 : paramArgNodes;
|
|
3425
|
+
return emitScalarFunctionNode(
|
|
3426
|
+
definition,
|
|
3427
|
+
operands,
|
|
3428
|
+
argNodes,
|
|
3429
|
+
argCount,
|
|
3430
|
+
context,
|
|
3431
|
+
variables,
|
|
3432
|
+
issues,
|
|
3433
|
+
paramOverride
|
|
3434
|
+
);
|
|
1950
3435
|
}
|
|
1951
3436
|
default: {
|
|
1952
3437
|
issues.push("Unsupported expression node.");
|
|
@@ -1960,10 +3445,25 @@ function buildRigGraphSpec({
|
|
|
1960
3445
|
components,
|
|
1961
3446
|
bindings,
|
|
1962
3447
|
inputsById,
|
|
1963
|
-
inputBindings
|
|
3448
|
+
inputBindings,
|
|
3449
|
+
inputMetadata
|
|
1964
3450
|
}) {
|
|
3451
|
+
const metadataByInputId = inputMetadata ?? /* @__PURE__ */ new Map();
|
|
3452
|
+
const irBuilder = createIrGraphBuilder({
|
|
3453
|
+
faceId,
|
|
3454
|
+
registryVersion: import_metadata2.nodeRegistryVersion,
|
|
3455
|
+
source: "graphBuilder",
|
|
3456
|
+
generatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
3457
|
+
});
|
|
1965
3458
|
const nodes = [];
|
|
1966
3459
|
const edges = [];
|
|
3460
|
+
const graphReservedNodes = /* @__PURE__ */ new Map();
|
|
3461
|
+
const reservedNodeCounters = /* @__PURE__ */ new Map();
|
|
3462
|
+
const generateReservedNodeId = (kind) => {
|
|
3463
|
+
const nextValue = (reservedNodeCounters.get(kind) ?? 0) + 1;
|
|
3464
|
+
reservedNodeCounters.set(kind, nextValue);
|
|
3465
|
+
return `reserved_${kind}_${nextValue}`;
|
|
3466
|
+
};
|
|
1967
3467
|
const inputNodes = /* @__PURE__ */ new Map();
|
|
1968
3468
|
const buildingDerived = /* @__PURE__ */ new Set();
|
|
1969
3469
|
const computedInputs = /* @__PURE__ */ new Set();
|
|
@@ -2019,7 +3519,9 @@ function buildRigGraphSpec({
|
|
|
2019
3519
|
edges,
|
|
2020
3520
|
ensureInputNode,
|
|
2021
3521
|
bindingIssues,
|
|
2022
|
-
summaryBindings
|
|
3522
|
+
summaryBindings,
|
|
3523
|
+
graphReservedNodes,
|
|
3524
|
+
generateReservedNodeId
|
|
2023
3525
|
},
|
|
2024
3526
|
selfNodeId
|
|
2025
3527
|
});
|
|
@@ -2099,7 +3601,9 @@ function buildRigGraphSpec({
|
|
|
2099
3601
|
edges,
|
|
2100
3602
|
ensureInputNode,
|
|
2101
3603
|
bindingIssues,
|
|
2102
|
-
summaryBindings
|
|
3604
|
+
summaryBindings,
|
|
3605
|
+
graphReservedNodes,
|
|
3606
|
+
generateReservedNodeId
|
|
2103
3607
|
}
|
|
2104
3608
|
});
|
|
2105
3609
|
valueNodeId = producedNodeId;
|
|
@@ -2118,7 +3622,9 @@ function buildRigGraphSpec({
|
|
|
2118
3622
|
remap: createDefaultRemap(target),
|
|
2119
3623
|
expression: PRIMARY_SLOT_ALIAS,
|
|
2120
3624
|
valueType: target.valueType === "vector" ? "vector" : "scalar",
|
|
2121
|
-
issues: ["Binding not found."]
|
|
3625
|
+
issues: ["Binding not found."],
|
|
3626
|
+
nodeId: PRIMARY_SLOT_ID,
|
|
3627
|
+
expressionNodeId: PRIMARY_SLOT_ID
|
|
2122
3628
|
});
|
|
2123
3629
|
const fallbackIssues = bindingIssues.get(component.id) ?? /* @__PURE__ */ new Set();
|
|
2124
3630
|
fallbackIssues.add("Binding not found.");
|
|
@@ -2128,15 +3634,7 @@ function buildRigGraphSpec({
|
|
|
2128
3634
|
entry.defaults.set(key, component.defaultValue);
|
|
2129
3635
|
return;
|
|
2130
3636
|
}
|
|
2131
|
-
|
|
2132
|
-
const finalNodeId = applyBindingOperators(
|
|
2133
|
-
operatorList,
|
|
2134
|
-
valueNodeId,
|
|
2135
|
-
component.safeId,
|
|
2136
|
-
nodes,
|
|
2137
|
-
edges
|
|
2138
|
-
);
|
|
2139
|
-
entry.values.set(key, finalNodeId);
|
|
3637
|
+
entry.values.set(key, valueNodeId);
|
|
2140
3638
|
});
|
|
2141
3639
|
inputsById.forEach((_input, inputId) => {
|
|
2142
3640
|
ensureInputNode(inputId);
|
|
@@ -2162,8 +3660,8 @@ function buildRigGraphSpec({
|
|
|
2162
3660
|
}
|
|
2163
3661
|
});
|
|
2164
3662
|
edges.push({
|
|
2165
|
-
from: {
|
|
2166
|
-
to: {
|
|
3663
|
+
from: { nodeId: valueNodeId },
|
|
3664
|
+
to: { nodeId: outputNodeId2, portId: "in" }
|
|
2167
3665
|
});
|
|
2168
3666
|
return;
|
|
2169
3667
|
}
|
|
@@ -2190,8 +3688,8 @@ function buildRigGraphSpec({
|
|
|
2190
3688
|
sourceId = constNodeId;
|
|
2191
3689
|
}
|
|
2192
3690
|
edges.push({
|
|
2193
|
-
from: {
|
|
2194
|
-
to: {
|
|
3691
|
+
from: { nodeId: sourceId },
|
|
3692
|
+
to: { nodeId: joinNodeId, portId: `operand_${index + 1}` }
|
|
2195
3693
|
});
|
|
2196
3694
|
});
|
|
2197
3695
|
const outputNodeId = `out_${safeId}`;
|
|
@@ -2203,8 +3701,8 @@ function buildRigGraphSpec({
|
|
|
2203
3701
|
}
|
|
2204
3702
|
});
|
|
2205
3703
|
edges.push({
|
|
2206
|
-
from: {
|
|
2207
|
-
to: {
|
|
3704
|
+
from: { nodeId: joinNodeId },
|
|
3705
|
+
to: { nodeId: outputNodeId, portId: "in" }
|
|
2208
3706
|
});
|
|
2209
3707
|
});
|
|
2210
3708
|
const nodeById = /* @__PURE__ */ new Map();
|
|
@@ -2213,7 +3711,7 @@ function buildRigGraphSpec({
|
|
|
2213
3711
|
});
|
|
2214
3712
|
const constantUsage = /* @__PURE__ */ new Map();
|
|
2215
3713
|
edges.forEach((edge) => {
|
|
2216
|
-
const source = nodeById.get(edge.from.
|
|
3714
|
+
const source = nodeById.get(edge.from.nodeId);
|
|
2217
3715
|
if (source?.type === "constant") {
|
|
2218
3716
|
constantUsage.set(source.id, (constantUsage.get(source.id) ?? 0) + 1);
|
|
2219
3717
|
}
|
|
@@ -2221,15 +3719,16 @@ function buildRigGraphSpec({
|
|
|
2221
3719
|
const updatedEdges = [];
|
|
2222
3720
|
const constantsToRemove = /* @__PURE__ */ new Set();
|
|
2223
3721
|
edges.forEach((edge) => {
|
|
2224
|
-
const source = nodeById.get(edge.from.
|
|
3722
|
+
const source = nodeById.get(edge.from.nodeId);
|
|
2225
3723
|
if (source?.type === "constant" && constantUsage.get(source.id) === 1 && source.params && Object.prototype.hasOwnProperty.call(source.params, "value")) {
|
|
2226
|
-
const target = nodeById.get(edge.to.
|
|
3724
|
+
const target = nodeById.get(edge.to.nodeId);
|
|
2227
3725
|
if (target) {
|
|
2228
3726
|
const value = source.params.value;
|
|
2229
3727
|
if (value !== void 0) {
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
|
|
3728
|
+
const targetPort = edge.to.portId ?? "in";
|
|
3729
|
+
target.inputDefaults = {
|
|
3730
|
+
...target.inputDefaults ?? {},
|
|
3731
|
+
[targetPort]: value
|
|
2233
3732
|
};
|
|
2234
3733
|
nodeById.set(target.id, target);
|
|
2235
3734
|
constantsToRemove.add(source.id);
|
|
@@ -2246,18 +3745,17 @@ function buildRigGraphSpec({
|
|
|
2246
3745
|
const filteredSummaryBindings = summaryBindings.filter(
|
|
2247
3746
|
(binding) => outputs.has(binding.animatableId) || computedInputs.has(binding.animatableId)
|
|
2248
3747
|
);
|
|
2249
|
-
const
|
|
2250
|
-
|
|
2251
|
-
|
|
2252
|
-
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
|
|
2257
|
-
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
inputs: Array.from(inputsById.values()).map((input) => ({
|
|
3748
|
+
const vizijMetadata = {
|
|
3749
|
+
vizij: {
|
|
3750
|
+
faceId,
|
|
3751
|
+
inputs: Array.from(inputsById.values()).map((input) => {
|
|
3752
|
+
const meta = metadataByInputId.get(input.id);
|
|
3753
|
+
const derivedRoot = meta?.root ?? input.group;
|
|
3754
|
+
let derivedSource = meta?.source;
|
|
3755
|
+
if (!derivedSource && input.path.startsWith("/standard/")) {
|
|
3756
|
+
derivedSource = "preset";
|
|
3757
|
+
}
|
|
3758
|
+
const entry = {
|
|
2261
3759
|
id: input.id,
|
|
2262
3760
|
path: input.path,
|
|
2263
3761
|
sourceId: input.sourceId,
|
|
@@ -2268,15 +3766,23 @@ function buildRigGraphSpec({
|
|
|
2268
3766
|
min: input.range.min,
|
|
2269
3767
|
max: input.range.max
|
|
2270
3768
|
}
|
|
2271
|
-
}
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
}
|
|
3769
|
+
};
|
|
3770
|
+
if (derivedSource) {
|
|
3771
|
+
entry.source = derivedSource;
|
|
3772
|
+
}
|
|
3773
|
+
if (derivedRoot) {
|
|
3774
|
+
entry.root = derivedRoot;
|
|
3775
|
+
}
|
|
3776
|
+
return entry;
|
|
3777
|
+
}),
|
|
3778
|
+
bindings: filteredSummaryBindings.map((binding) => ({
|
|
3779
|
+
...binding,
|
|
3780
|
+
remap: { ...binding.remap },
|
|
3781
|
+
expression: binding.expression,
|
|
3782
|
+
valueType: binding.valueType,
|
|
3783
|
+
issues: binding.issues ? [...binding.issues] : void 0,
|
|
3784
|
+
metadata: binding.metadata ? cloneJsonLike2(binding.metadata) : void 0
|
|
3785
|
+
}))
|
|
2280
3786
|
}
|
|
2281
3787
|
};
|
|
2282
3788
|
const issuesByTarget = {};
|
|
@@ -2291,29 +3797,149 @@ function buildRigGraphSpec({
|
|
|
2291
3797
|
issues.forEach((issue) => fatalIssues.add(issue));
|
|
2292
3798
|
});
|
|
2293
3799
|
remapDefaultIssues.forEach((issue) => fatalIssues.add(issue));
|
|
3800
|
+
const summaryPayload = {
|
|
3801
|
+
faceId,
|
|
3802
|
+
inputs: Array.from(inputNodes.values()).map(
|
|
3803
|
+
({ input }) => buildRigInputPath(faceId, input.path)
|
|
3804
|
+
),
|
|
3805
|
+
outputs: [...dynamicOutputs, ...computedInputList],
|
|
3806
|
+
bindings: filteredSummaryBindings
|
|
3807
|
+
};
|
|
3808
|
+
const irSummary = {
|
|
3809
|
+
faceId: summaryPayload.faceId,
|
|
3810
|
+
inputs: [...summaryPayload.inputs],
|
|
3811
|
+
outputs: [...summaryPayload.outputs],
|
|
3812
|
+
bindings: toIrBindingSummary(
|
|
3813
|
+
filteredSummaryBindings.map((binding) => ({
|
|
3814
|
+
...binding,
|
|
3815
|
+
remap: { ...binding.remap },
|
|
3816
|
+
issues: binding.issues ? [...binding.issues] : void 0
|
|
3817
|
+
}))
|
|
3818
|
+
)
|
|
3819
|
+
};
|
|
3820
|
+
const fatalIssueList = Array.from(fatalIssues);
|
|
3821
|
+
const irIssues = createIrIssuesFromLegacy(issuesByTarget, fatalIssueList);
|
|
3822
|
+
filteredNodes.forEach((node) => {
|
|
3823
|
+
irBuilder.addNode(cloneIrNode(node));
|
|
3824
|
+
const constant = extractIrConstantFromNode(node);
|
|
3825
|
+
if (constant) {
|
|
3826
|
+
irBuilder.addConstant(constant);
|
|
3827
|
+
}
|
|
3828
|
+
});
|
|
3829
|
+
updatedEdges.forEach((edge) => {
|
|
3830
|
+
irBuilder.addEdge(cloneIrEdge(edge));
|
|
3831
|
+
});
|
|
3832
|
+
irBuilder.setSummary(irSummary);
|
|
3833
|
+
irIssues.forEach((issue) => irBuilder.addIssue(issue));
|
|
3834
|
+
irBuilder.updateMetadata({
|
|
3835
|
+
annotations: {
|
|
3836
|
+
graphSpecMetadata: cloneJsonLike2(vizijMetadata)
|
|
3837
|
+
}
|
|
3838
|
+
});
|
|
3839
|
+
const irGraph = irBuilder.build();
|
|
3840
|
+
const compiled = compileIrGraph(irGraph, { preferLegacySpec: false });
|
|
2294
3841
|
return {
|
|
2295
|
-
spec:
|
|
2296
|
-
summary:
|
|
2297
|
-
faceId,
|
|
2298
|
-
inputs: Array.from(inputNodes.values()).map(
|
|
2299
|
-
({ input }) => buildRigInputPath(faceId, input.path)
|
|
2300
|
-
),
|
|
2301
|
-
outputs: [...dynamicOutputs, ...computedInputList],
|
|
2302
|
-
bindings: filteredSummaryBindings
|
|
2303
|
-
},
|
|
3842
|
+
spec: compiled.spec,
|
|
3843
|
+
summary: summaryPayload,
|
|
2304
3844
|
issues: {
|
|
2305
3845
|
byTarget: issuesByTarget,
|
|
2306
|
-
fatal:
|
|
3846
|
+
fatal: fatalIssueList
|
|
3847
|
+
},
|
|
3848
|
+
ir: {
|
|
3849
|
+
graph: irGraph,
|
|
3850
|
+
compile: (options) => compileIrGraph(irGraph, options)
|
|
3851
|
+
}
|
|
3852
|
+
};
|
|
3853
|
+
}
|
|
3854
|
+
function createIrIssuesFromLegacy(issuesByTarget, fatalIssues) {
|
|
3855
|
+
const fatalSet = new Set(fatalIssues);
|
|
3856
|
+
const collected = [];
|
|
3857
|
+
let counter = 0;
|
|
3858
|
+
Object.entries(issuesByTarget).forEach(([targetId, messages]) => {
|
|
3859
|
+
messages.forEach((message) => {
|
|
3860
|
+
counter += 1;
|
|
3861
|
+
collected.push({
|
|
3862
|
+
id: `issue_${counter}`,
|
|
3863
|
+
severity: fatalSet.has(message) ? "error" : "warning",
|
|
3864
|
+
message,
|
|
3865
|
+
targetId,
|
|
3866
|
+
tags: fatalSet.has(message) ? ["fatal"] : void 0
|
|
3867
|
+
});
|
|
3868
|
+
});
|
|
3869
|
+
});
|
|
3870
|
+
fatalSet.forEach((message) => {
|
|
3871
|
+
const alreadyCaptured = collected.some(
|
|
3872
|
+
(issue) => issue.message === message
|
|
3873
|
+
);
|
|
3874
|
+
if (alreadyCaptured) {
|
|
3875
|
+
return;
|
|
2307
3876
|
}
|
|
3877
|
+
counter += 1;
|
|
3878
|
+
collected.push({
|
|
3879
|
+
id: `issue_${counter}`,
|
|
3880
|
+
severity: "error",
|
|
3881
|
+
message,
|
|
3882
|
+
tags: ["fatal"]
|
|
3883
|
+
});
|
|
3884
|
+
});
|
|
3885
|
+
return collected;
|
|
3886
|
+
}
|
|
3887
|
+
function cloneIrNode(node) {
|
|
3888
|
+
return {
|
|
3889
|
+
id: node.id,
|
|
3890
|
+
type: node.type,
|
|
3891
|
+
category: node.category,
|
|
3892
|
+
label: node.label,
|
|
3893
|
+
description: node.description,
|
|
3894
|
+
params: cloneJsonLike2(node.params),
|
|
3895
|
+
inputDefaults: cloneJsonLike2(node.inputDefaults),
|
|
3896
|
+
metadata: cloneJsonLike2(node.metadata)
|
|
3897
|
+
};
|
|
3898
|
+
}
|
|
3899
|
+
function cloneIrEdge(edge) {
|
|
3900
|
+
return {
|
|
3901
|
+
id: edge.id,
|
|
3902
|
+
from: {
|
|
3903
|
+
nodeId: edge.from.nodeId,
|
|
3904
|
+
portId: edge.from.portId,
|
|
3905
|
+
component: edge.from.component
|
|
3906
|
+
},
|
|
3907
|
+
to: {
|
|
3908
|
+
nodeId: edge.to.nodeId,
|
|
3909
|
+
portId: edge.to.portId,
|
|
3910
|
+
component: edge.to.component
|
|
3911
|
+
},
|
|
3912
|
+
metadata: cloneJsonLike2(edge.metadata)
|
|
3913
|
+
};
|
|
3914
|
+
}
|
|
3915
|
+
function extractIrConstantFromNode(node) {
|
|
3916
|
+
if (node.type !== "constant") {
|
|
3917
|
+
return null;
|
|
3918
|
+
}
|
|
3919
|
+
const value = node.params?.value;
|
|
3920
|
+
if (typeof value !== "number" || !Number.isFinite(value)) {
|
|
3921
|
+
return null;
|
|
3922
|
+
}
|
|
3923
|
+
return {
|
|
3924
|
+
id: node.id,
|
|
3925
|
+
value,
|
|
3926
|
+
valueType: "scalar",
|
|
3927
|
+
metadata: cloneJsonLike2(node.metadata)
|
|
2308
3928
|
};
|
|
2309
3929
|
}
|
|
3930
|
+
function cloneJsonLike2(value) {
|
|
3931
|
+
if (value === void 0 || value === null) {
|
|
3932
|
+
return value;
|
|
3933
|
+
}
|
|
3934
|
+
return JSON.parse(JSON.stringify(value));
|
|
3935
|
+
}
|
|
2310
3936
|
function validateRemapDefaults(nodes) {
|
|
2311
3937
|
const issues = [];
|
|
2312
3938
|
nodes.forEach((node) => {
|
|
2313
3939
|
if (node.type !== "centered_remap") {
|
|
2314
3940
|
return;
|
|
2315
3941
|
}
|
|
2316
|
-
const defaults = node.
|
|
3942
|
+
const defaults = node.inputDefaults ?? {};
|
|
2317
3943
|
[
|
|
2318
3944
|
"in_low",
|
|
2319
3945
|
"in_anchor",
|
|
@@ -2330,38 +3956,444 @@ function validateRemapDefaults(nodes) {
|
|
|
2330
3956
|
});
|
|
2331
3957
|
return issues;
|
|
2332
3958
|
}
|
|
3959
|
+
|
|
3960
|
+
// src/ir/inspection.ts
|
|
3961
|
+
var import_metadata3 = require("@vizij/node-graph-wasm/metadata");
|
|
3962
|
+
var MACHINE_REPORT_VERSION = 1;
|
|
3963
|
+
var REMAP_KEYS = [
|
|
3964
|
+
"inLow",
|
|
3965
|
+
"inAnchor",
|
|
3966
|
+
"inHigh",
|
|
3967
|
+
"outLow",
|
|
3968
|
+
"outAnchor",
|
|
3969
|
+
"outHigh"
|
|
3970
|
+
];
|
|
3971
|
+
var DEFAULT_DIFF_LIMIT = 50;
|
|
3972
|
+
function buildMachineReport(result) {
|
|
3973
|
+
return {
|
|
3974
|
+
reportVersion: MACHINE_REPORT_VERSION,
|
|
3975
|
+
faceId: result.summary.faceId,
|
|
3976
|
+
summary: normalizeSummary(result.summary),
|
|
3977
|
+
issues: normalizeIssues(result.issues),
|
|
3978
|
+
irGraph: result.ir?.graph ? normalizeIrGraph(result.ir.graph) : void 0
|
|
3979
|
+
};
|
|
3980
|
+
}
|
|
3981
|
+
function diffMachineReports(actual, expected, options) {
|
|
3982
|
+
const limit = normalizeDiffLimit(options?.limit);
|
|
3983
|
+
const ctx = {
|
|
3984
|
+
differences: [],
|
|
3985
|
+
limit,
|
|
3986
|
+
limitReached: false
|
|
3987
|
+
};
|
|
3988
|
+
diffValues(actual, expected, "$", ctx);
|
|
3989
|
+
return {
|
|
3990
|
+
equal: ctx.differences.length === 0,
|
|
3991
|
+
differences: ctx.differences,
|
|
3992
|
+
limitReached: ctx.limitReached
|
|
3993
|
+
};
|
|
3994
|
+
}
|
|
3995
|
+
function normalizeSummary(summary) {
|
|
3996
|
+
return {
|
|
3997
|
+
faceId: summary.faceId,
|
|
3998
|
+
inputs: [...summary.inputs].sort(),
|
|
3999
|
+
outputs: [...summary.outputs].sort(),
|
|
4000
|
+
bindings: normalizeGraphBindingSummaries(summary.bindings)
|
|
4001
|
+
};
|
|
4002
|
+
}
|
|
4003
|
+
function normalizeGraphBindingSummaries(bindings) {
|
|
4004
|
+
const normalized = bindings.map((binding) => ({
|
|
4005
|
+
targetId: binding.targetId,
|
|
4006
|
+
animatableId: binding.animatableId,
|
|
4007
|
+
component: binding.component ?? void 0,
|
|
4008
|
+
slotId: binding.slotId,
|
|
4009
|
+
slotAlias: binding.slotAlias,
|
|
4010
|
+
inputId: binding.inputId ?? null,
|
|
4011
|
+
remap: normalizeRemap2(binding.remap),
|
|
4012
|
+
expression: binding.expression,
|
|
4013
|
+
valueType: binding.valueType,
|
|
4014
|
+
nodeId: binding.nodeId,
|
|
4015
|
+
expressionNodeId: binding.expressionNodeId,
|
|
4016
|
+
issues: normalizeStringArray(binding.issues),
|
|
4017
|
+
metadata: cloneBindingMetadata2(binding.metadata)
|
|
4018
|
+
}));
|
|
4019
|
+
normalized.sort((a, b) => bindingSortKey(a).localeCompare(bindingSortKey(b)));
|
|
4020
|
+
return normalized;
|
|
4021
|
+
}
|
|
4022
|
+
function cloneBindingMetadata2(metadata) {
|
|
4023
|
+
if (!metadata) {
|
|
4024
|
+
return void 0;
|
|
4025
|
+
}
|
|
4026
|
+
return JSON.parse(JSON.stringify(metadata));
|
|
4027
|
+
}
|
|
4028
|
+
function normalizeIssues(issues) {
|
|
4029
|
+
const byTargetEntries = Object.entries(issues.byTarget ?? {}).map(
|
|
4030
|
+
([targetId, messages]) => [targetId, [...messages].sort()]
|
|
4031
|
+
);
|
|
4032
|
+
byTargetEntries.sort(([a], [b]) => a.localeCompare(b));
|
|
4033
|
+
const byTarget = {};
|
|
4034
|
+
byTargetEntries.forEach(([targetId, messages]) => {
|
|
4035
|
+
byTarget[targetId] = messages;
|
|
4036
|
+
});
|
|
4037
|
+
return {
|
|
4038
|
+
fatal: [...issues.fatal].sort(),
|
|
4039
|
+
byTarget
|
|
4040
|
+
};
|
|
4041
|
+
}
|
|
4042
|
+
function normalizeIrGraph(graph) {
|
|
4043
|
+
return {
|
|
4044
|
+
id: graph.id,
|
|
4045
|
+
faceId: graph.faceId,
|
|
4046
|
+
nodes: normalizeIrNodes(graph.nodes),
|
|
4047
|
+
edges: normalizeIrEdges(graph.edges),
|
|
4048
|
+
constants: normalizeIrConstants(graph.constants),
|
|
4049
|
+
issues: normalizeIrIssues(graph.issues),
|
|
4050
|
+
summary: normalizeIrGraphSummary(graph.summary),
|
|
4051
|
+
metadata: normalizeIrMetadata(graph.metadata)
|
|
4052
|
+
};
|
|
4053
|
+
}
|
|
4054
|
+
function normalizeIrNodes(nodes) {
|
|
4055
|
+
return [...nodes].map((node) => ({
|
|
4056
|
+
...node,
|
|
4057
|
+
inputDefaults: node.inputDefaults ? sortPlainObject(node.inputDefaults) : void 0,
|
|
4058
|
+
params: node.params ? sortPlainObject(node.params) : void 0,
|
|
4059
|
+
metadata: node.metadata ? sortPlainObject(node.metadata) : void 0,
|
|
4060
|
+
annotations: buildNodeAnnotations(node)
|
|
4061
|
+
})).sort((a, b) => a.id.localeCompare(b.id));
|
|
4062
|
+
}
|
|
4063
|
+
function normalizeIrEdges(edges) {
|
|
4064
|
+
return [...edges].map((edge) => ({
|
|
4065
|
+
...edge,
|
|
4066
|
+
from: normalizePortRef(edge.from),
|
|
4067
|
+
to: normalizePortRef(edge.to),
|
|
4068
|
+
metadata: edge.metadata ? sortPlainObject(edge.metadata) : void 0
|
|
4069
|
+
})).sort((a, b) => edgeSortKey(a).localeCompare(edgeSortKey(b)));
|
|
4070
|
+
}
|
|
4071
|
+
function normalizePortRef(edgeRef) {
|
|
4072
|
+
return {
|
|
4073
|
+
nodeId: edgeRef.nodeId,
|
|
4074
|
+
portId: edgeRef.portId ?? void 0,
|
|
4075
|
+
component: edgeRef.component ?? void 0
|
|
4076
|
+
};
|
|
4077
|
+
}
|
|
4078
|
+
function edgeSortKey(edge) {
|
|
4079
|
+
if (edge.id) {
|
|
4080
|
+
return edge.id;
|
|
4081
|
+
}
|
|
4082
|
+
const fromPort = edge.from.portId ?? "";
|
|
4083
|
+
const toPort = edge.to.portId ?? "";
|
|
4084
|
+
return `${edge.from.nodeId}:${fromPort}->${edge.to.nodeId}:${toPort}`;
|
|
4085
|
+
}
|
|
4086
|
+
function normalizeIrConstants(constants) {
|
|
4087
|
+
return [...constants].map((constant) => ({
|
|
4088
|
+
...constant,
|
|
4089
|
+
metadata: constant.metadata ? sortPlainObject(constant.metadata) : void 0
|
|
4090
|
+
})).sort((a, b) => a.id.localeCompare(b.id));
|
|
4091
|
+
}
|
|
4092
|
+
function normalizeIrIssues(issues) {
|
|
4093
|
+
return [...issues].map((issue) => ({
|
|
4094
|
+
...issue,
|
|
4095
|
+
tags: normalizeStringArray(issue.tags),
|
|
4096
|
+
details: issue.details ? sortPlainObject(issue.details) : void 0
|
|
4097
|
+
})).sort((a, b) => a.id.localeCompare(b.id));
|
|
4098
|
+
}
|
|
4099
|
+
function normalizeIrGraphSummary(summary) {
|
|
4100
|
+
return {
|
|
4101
|
+
faceId: summary.faceId,
|
|
4102
|
+
inputs: [...summary.inputs].sort(),
|
|
4103
|
+
outputs: [...summary.outputs].sort(),
|
|
4104
|
+
bindings: normalizeIrBindingSummaries(summary.bindings)
|
|
4105
|
+
};
|
|
4106
|
+
}
|
|
4107
|
+
function normalizeIrBindingSummaries(bindings) {
|
|
4108
|
+
const normalized = bindings.map((binding) => ({
|
|
4109
|
+
...binding,
|
|
4110
|
+
remap: sortPlainObject(binding.remap),
|
|
4111
|
+
issues: normalizeStringArray(binding.issues)
|
|
4112
|
+
}));
|
|
4113
|
+
normalized.sort((a, b) => bindingSortKey(a).localeCompare(bindingSortKey(b)));
|
|
4114
|
+
return normalized;
|
|
4115
|
+
}
|
|
4116
|
+
function normalizeIrMetadata(metadata) {
|
|
4117
|
+
const normalized = {
|
|
4118
|
+
source: metadata.source ?? "unknown"
|
|
4119
|
+
};
|
|
4120
|
+
if (metadata.registryVersion) {
|
|
4121
|
+
normalized.registryVersion = metadata.registryVersion;
|
|
4122
|
+
}
|
|
4123
|
+
if (metadata.annotations) {
|
|
4124
|
+
const sorted = sortPlainObject(metadata.annotations);
|
|
4125
|
+
if (Object.keys(sorted).length > 0) {
|
|
4126
|
+
normalized.annotations = sorted;
|
|
4127
|
+
}
|
|
4128
|
+
}
|
|
4129
|
+
return normalized;
|
|
4130
|
+
}
|
|
4131
|
+
function buildNodeAnnotations(node) {
|
|
4132
|
+
const signature = findRegistrySignature(node.type);
|
|
4133
|
+
if (!signature) {
|
|
4134
|
+
return void 0;
|
|
4135
|
+
}
|
|
4136
|
+
return {
|
|
4137
|
+
registry: normalizeRegistrySignature(signature)
|
|
4138
|
+
};
|
|
4139
|
+
}
|
|
4140
|
+
function findRegistrySignature(typeId) {
|
|
4141
|
+
try {
|
|
4142
|
+
const signature = (0, import_metadata3.findNodeSignature)(typeId);
|
|
4143
|
+
if (!signature) {
|
|
4144
|
+
return void 0;
|
|
4145
|
+
}
|
|
4146
|
+
return signature;
|
|
4147
|
+
} catch {
|
|
4148
|
+
return void 0;
|
|
4149
|
+
}
|
|
4150
|
+
}
|
|
4151
|
+
function normalizeRegistrySignature(signature) {
|
|
4152
|
+
return {
|
|
4153
|
+
typeId: signature.type_id,
|
|
4154
|
+
name: signature.name,
|
|
4155
|
+
category: signature.category,
|
|
4156
|
+
doc: signature.doc,
|
|
4157
|
+
inputs: signature.inputs.map(normalizeRegistryPortSpec),
|
|
4158
|
+
variadicInputs: signature.variadic_inputs ? normalizeRegistryVariadicSpec(signature.variadic_inputs) : void 0,
|
|
4159
|
+
outputs: signature.outputs.map(normalizeRegistryPortSpec),
|
|
4160
|
+
variadicOutputs: signature.variadic_outputs ? normalizeRegistryVariadicSpec(signature.variadic_outputs) : void 0,
|
|
4161
|
+
params: signature.params.map(normalizeRegistryParamSpec)
|
|
4162
|
+
};
|
|
4163
|
+
}
|
|
4164
|
+
function normalizeRegistryPortSpec(port) {
|
|
4165
|
+
const normalized = {
|
|
4166
|
+
id: port.id,
|
|
4167
|
+
label: port.label,
|
|
4168
|
+
type: port.ty ?? "unknown"
|
|
4169
|
+
};
|
|
4170
|
+
if (port.doc) {
|
|
4171
|
+
normalized.doc = port.doc;
|
|
4172
|
+
}
|
|
4173
|
+
if (port.optional) {
|
|
4174
|
+
normalized.optional = true;
|
|
4175
|
+
}
|
|
4176
|
+
return normalized;
|
|
4177
|
+
}
|
|
4178
|
+
function normalizeRegistryVariadicSpec(spec) {
|
|
4179
|
+
const normalized = {
|
|
4180
|
+
id: spec.id,
|
|
4181
|
+
label: spec.label,
|
|
4182
|
+
type: spec.ty ?? "unknown",
|
|
4183
|
+
min: spec.min
|
|
4184
|
+
};
|
|
4185
|
+
if (spec.doc) {
|
|
4186
|
+
normalized.doc = spec.doc;
|
|
4187
|
+
}
|
|
4188
|
+
if (typeof spec.max === "number") {
|
|
4189
|
+
normalized.max = spec.max;
|
|
4190
|
+
}
|
|
4191
|
+
return normalized;
|
|
4192
|
+
}
|
|
4193
|
+
function normalizeRegistryParamSpec(param) {
|
|
4194
|
+
const normalized = {
|
|
4195
|
+
id: param.id,
|
|
4196
|
+
label: param.label,
|
|
4197
|
+
type: param.ty ?? "unknown"
|
|
4198
|
+
};
|
|
4199
|
+
if (param.doc) {
|
|
4200
|
+
normalized.doc = param.doc;
|
|
4201
|
+
}
|
|
4202
|
+
if (param.default_json !== void 0) {
|
|
4203
|
+
normalized.defaultValue = normalizePlainValue(param.default_json);
|
|
4204
|
+
}
|
|
4205
|
+
if (typeof param.min === "number") {
|
|
4206
|
+
normalized.min = param.min;
|
|
4207
|
+
}
|
|
4208
|
+
if (typeof param.max === "number") {
|
|
4209
|
+
normalized.max = param.max;
|
|
4210
|
+
}
|
|
4211
|
+
return normalized;
|
|
4212
|
+
}
|
|
4213
|
+
function normalizeRemap2(remap) {
|
|
4214
|
+
const normalized = {};
|
|
4215
|
+
REMAP_KEYS.forEach((key) => {
|
|
4216
|
+
normalized[key] = remap[key];
|
|
4217
|
+
});
|
|
4218
|
+
return normalized;
|
|
4219
|
+
}
|
|
4220
|
+
function normalizeStringArray(values) {
|
|
4221
|
+
if (!values || values.length === 0) {
|
|
4222
|
+
return void 0;
|
|
4223
|
+
}
|
|
4224
|
+
const unique = Array.from(new Set(values));
|
|
4225
|
+
unique.sort();
|
|
4226
|
+
return unique;
|
|
4227
|
+
}
|
|
4228
|
+
function bindingSortKey(binding) {
|
|
4229
|
+
const component = binding.component ?? "";
|
|
4230
|
+
return `${binding.targetId}::${component}::${binding.slotId}::${binding.slotAlias}::${binding.animatableId}`;
|
|
4231
|
+
}
|
|
4232
|
+
function sortPlainObject(record) {
|
|
4233
|
+
const sorted = {};
|
|
4234
|
+
Object.keys(record).sort().forEach((key) => {
|
|
4235
|
+
sorted[key] = normalizePlainValue(record[key]);
|
|
4236
|
+
});
|
|
4237
|
+
return sorted;
|
|
4238
|
+
}
|
|
4239
|
+
function normalizePlainValue(value) {
|
|
4240
|
+
if (Array.isArray(value)) {
|
|
4241
|
+
return value.map((entry) => normalizePlainValue(entry));
|
|
4242
|
+
}
|
|
4243
|
+
if (isPlainObject(value)) {
|
|
4244
|
+
return sortPlainObject(value);
|
|
4245
|
+
}
|
|
4246
|
+
return value;
|
|
4247
|
+
}
|
|
4248
|
+
function isPlainObject(value) {
|
|
4249
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
4250
|
+
}
|
|
4251
|
+
function diffValues(actual, expected, path, ctx) {
|
|
4252
|
+
if (ctx.differences.length >= ctx.limit) {
|
|
4253
|
+
ctx.limitReached = true;
|
|
4254
|
+
return;
|
|
4255
|
+
}
|
|
4256
|
+
if (Object.is(actual, expected)) {
|
|
4257
|
+
return;
|
|
4258
|
+
}
|
|
4259
|
+
if (Array.isArray(actual) && Array.isArray(expected)) {
|
|
4260
|
+
const compareLength = Math.min(actual.length, expected.length);
|
|
4261
|
+
for (let index = 0; index < compareLength; index += 1) {
|
|
4262
|
+
diffValues(actual[index], expected[index], pathIndex(path, index), ctx);
|
|
4263
|
+
if (ctx.differences.length >= ctx.limit) {
|
|
4264
|
+
ctx.limitReached = true;
|
|
4265
|
+
return;
|
|
4266
|
+
}
|
|
4267
|
+
}
|
|
4268
|
+
if (actual.length > expected.length) {
|
|
4269
|
+
for (let index = compareLength; index < actual.length; index += 1) {
|
|
4270
|
+
pushDifference(ctx, {
|
|
4271
|
+
kind: "unexpected",
|
|
4272
|
+
path: pathIndex(path, index),
|
|
4273
|
+
actual: actual[index]
|
|
4274
|
+
});
|
|
4275
|
+
if (ctx.differences.length >= ctx.limit) {
|
|
4276
|
+
ctx.limitReached = true;
|
|
4277
|
+
return;
|
|
4278
|
+
}
|
|
4279
|
+
}
|
|
4280
|
+
} else if (expected.length > actual.length) {
|
|
4281
|
+
for (let index = compareLength; index < expected.length; index += 1) {
|
|
4282
|
+
pushDifference(ctx, {
|
|
4283
|
+
kind: "missing",
|
|
4284
|
+
path: pathIndex(path, index),
|
|
4285
|
+
expected: expected[index]
|
|
4286
|
+
});
|
|
4287
|
+
if (ctx.differences.length >= ctx.limit) {
|
|
4288
|
+
ctx.limitReached = true;
|
|
4289
|
+
return;
|
|
4290
|
+
}
|
|
4291
|
+
}
|
|
4292
|
+
}
|
|
4293
|
+
return;
|
|
4294
|
+
}
|
|
4295
|
+
if (isPlainObject(actual) && isPlainObject(expected)) {
|
|
4296
|
+
const keys = /* @__PURE__ */ new Set([...Object.keys(actual), ...Object.keys(expected)]);
|
|
4297
|
+
const sortedKeys = Array.from(keys).sort();
|
|
4298
|
+
for (const key of sortedKeys) {
|
|
4299
|
+
if (!(key in actual)) {
|
|
4300
|
+
pushDifference(ctx, {
|
|
4301
|
+
kind: "missing",
|
|
4302
|
+
path: pathKey(path, key),
|
|
4303
|
+
expected: expected[key]
|
|
4304
|
+
});
|
|
4305
|
+
} else if (!(key in expected)) {
|
|
4306
|
+
pushDifference(ctx, {
|
|
4307
|
+
kind: "unexpected",
|
|
4308
|
+
path: pathKey(path, key),
|
|
4309
|
+
actual: actual[key]
|
|
4310
|
+
});
|
|
4311
|
+
} else {
|
|
4312
|
+
diffValues(actual[key], expected[key], pathKey(path, key), ctx);
|
|
4313
|
+
}
|
|
4314
|
+
if (ctx.differences.length >= ctx.limit) {
|
|
4315
|
+
ctx.limitReached = true;
|
|
4316
|
+
return;
|
|
4317
|
+
}
|
|
4318
|
+
}
|
|
4319
|
+
return;
|
|
4320
|
+
}
|
|
4321
|
+
pushDifference(ctx, {
|
|
4322
|
+
kind: "mismatch",
|
|
4323
|
+
path,
|
|
4324
|
+
actual,
|
|
4325
|
+
expected
|
|
4326
|
+
});
|
|
4327
|
+
}
|
|
4328
|
+
function pathKey(base, key) {
|
|
4329
|
+
if (base === "") {
|
|
4330
|
+
return key;
|
|
4331
|
+
}
|
|
4332
|
+
if (base.endsWith("]")) {
|
|
4333
|
+
return `${base}.${key}`;
|
|
4334
|
+
}
|
|
4335
|
+
return `${base}.${key}`;
|
|
4336
|
+
}
|
|
4337
|
+
function pathIndex(base, index) {
|
|
4338
|
+
return `${base}[${index}]`;
|
|
4339
|
+
}
|
|
4340
|
+
function pushDifference(ctx, entry) {
|
|
4341
|
+
if (ctx.differences.length < ctx.limit) {
|
|
4342
|
+
ctx.differences.push(entry);
|
|
4343
|
+
if (ctx.differences.length === ctx.limit) {
|
|
4344
|
+
ctx.limitReached = true;
|
|
4345
|
+
}
|
|
4346
|
+
} else {
|
|
4347
|
+
ctx.limitReached = true;
|
|
4348
|
+
}
|
|
4349
|
+
}
|
|
4350
|
+
function normalizeDiffLimit(limit) {
|
|
4351
|
+
if (typeof limit !== "number" || !Number.isFinite(limit) || limit <= 0) {
|
|
4352
|
+
return DEFAULT_DIFF_LIMIT;
|
|
4353
|
+
}
|
|
4354
|
+
return Math.floor(limit);
|
|
4355
|
+
}
|
|
2333
4356
|
// Annotate the CommonJS export names for ESM import in node:
|
|
2334
4357
|
0 && (module.exports = {
|
|
4358
|
+
EXPRESSION_FUNCTION_VOCABULARY,
|
|
4359
|
+
MACHINE_REPORT_VERSION,
|
|
2335
4360
|
PRIMARY_SLOT_ALIAS,
|
|
2336
4361
|
PRIMARY_SLOT_ID,
|
|
4362
|
+
RESERVED_EXPRESSION_VARIABLES,
|
|
4363
|
+
SCALAR_FUNCTIONS,
|
|
4364
|
+
SCALAR_FUNCTION_VOCABULARY,
|
|
2337
4365
|
addBindingSlot,
|
|
2338
4366
|
bindingFromDefinition,
|
|
2339
|
-
bindingOperatorDefinitions,
|
|
2340
|
-
bindingOperatorTypes,
|
|
2341
4367
|
bindingTargetFromComponent,
|
|
2342
4368
|
bindingTargetFromInput,
|
|
2343
4369
|
bindingToDefinition,
|
|
4370
|
+
buildCanonicalBindingExpression,
|
|
4371
|
+
buildDefaultSlotExpression,
|
|
4372
|
+
buildMachineReport,
|
|
4373
|
+
buildPiecewiseRemapExpression,
|
|
2344
4374
|
buildRigGraphSpec,
|
|
2345
4375
|
collectExpressionReferences,
|
|
4376
|
+
compileIrGraph,
|
|
2346
4377
|
createDefaultBinding,
|
|
2347
4378
|
createDefaultBindings,
|
|
2348
4379
|
createDefaultInputValues,
|
|
2349
|
-
createDefaultOperatorSettings,
|
|
2350
4380
|
createDefaultParentBinding,
|
|
2351
4381
|
createDefaultRemap,
|
|
4382
|
+
createExpressionVariableTable,
|
|
4383
|
+
createIrGraphBuilder,
|
|
4384
|
+
createLegacyIrGraph,
|
|
4385
|
+
diffMachineReports,
|
|
2352
4386
|
ensureBindingStructure,
|
|
2353
|
-
ensureOperatorParams,
|
|
2354
|
-
getBindingOperatorDefinition,
|
|
2355
4387
|
getPrimaryBindingSlot,
|
|
2356
4388
|
mapExpression,
|
|
2357
4389
|
parseControlExpression,
|
|
2358
4390
|
reconcileBindings,
|
|
2359
4391
|
remapValue,
|
|
2360
4392
|
removeBindingSlot,
|
|
2361
|
-
|
|
4393
|
+
toIrBindingSummary,
|
|
2362
4394
|
updateBindingExpression,
|
|
2363
|
-
updateBindingOperatorParam,
|
|
2364
4395
|
updateBindingSlotAlias,
|
|
2365
4396
|
updateBindingSlotRemap,
|
|
4397
|
+
updateBindingSlotValueType,
|
|
2366
4398
|
updateBindingWithInput
|
|
2367
4399
|
});
|