@vizij/node-graph-authoring 0.0.4 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +73 -1
- package/dist/chunk-6WQOBROM.js +3954 -0
- package/dist/cli/reportIr.cjs +3769 -0
- package/dist/cli/reportIr.js +246 -0
- package/dist/index.cjs +2459 -816
- package/dist/index.d.cts +380 -40
- package/dist/index.d.ts +380 -40
- package/dist/index.js +51 -2287
- package/package.json +15 -6
package/dist/index.cjs
CHANGED
|
@@ -20,125 +20,52 @@ 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
|
+
buildMachineReport: () => buildMachineReport,
|
|
32
37
|
buildRigGraphSpec: () => buildRigGraphSpec,
|
|
33
38
|
collectExpressionReferences: () => collectExpressionReferences,
|
|
39
|
+
compileIrGraph: () => compileIrGraph,
|
|
34
40
|
createDefaultBinding: () => createDefaultBinding,
|
|
35
41
|
createDefaultBindings: () => createDefaultBindings,
|
|
36
42
|
createDefaultInputValues: () => createDefaultInputValues,
|
|
37
|
-
createDefaultOperatorSettings: () => createDefaultOperatorSettings,
|
|
38
43
|
createDefaultParentBinding: () => createDefaultParentBinding,
|
|
39
|
-
|
|
44
|
+
createExpressionVariableTable: () => createExpressionVariableTable,
|
|
45
|
+
createIrGraphBuilder: () => createIrGraphBuilder,
|
|
46
|
+
createLegacyIrGraph: () => createLegacyIrGraph,
|
|
47
|
+
diffMachineReports: () => diffMachineReports,
|
|
40
48
|
ensureBindingStructure: () => ensureBindingStructure,
|
|
41
|
-
ensureOperatorParams: () => ensureOperatorParams,
|
|
42
|
-
getBindingOperatorDefinition: () => getBindingOperatorDefinition,
|
|
43
49
|
getPrimaryBindingSlot: () => getPrimaryBindingSlot,
|
|
44
50
|
mapExpression: () => mapExpression,
|
|
45
51
|
parseControlExpression: () => parseControlExpression,
|
|
46
52
|
reconcileBindings: () => reconcileBindings,
|
|
47
|
-
remapValue: () => remapValue,
|
|
48
53
|
removeBindingSlot: () => removeBindingSlot,
|
|
49
|
-
|
|
54
|
+
toIrBindingSummary: () => toIrBindingSummary,
|
|
50
55
|
updateBindingExpression: () => updateBindingExpression,
|
|
51
|
-
updateBindingOperatorParam: () => updateBindingOperatorParam,
|
|
52
56
|
updateBindingSlotAlias: () => updateBindingSlotAlias,
|
|
53
|
-
|
|
57
|
+
updateBindingSlotValueType: () => updateBindingSlotValueType,
|
|
54
58
|
updateBindingWithInput: () => updateBindingWithInput
|
|
55
59
|
});
|
|
56
60
|
module.exports = __toCommonJS(index_exports);
|
|
57
61
|
|
|
58
62
|
// src/graphBuilder.ts
|
|
59
|
-
var
|
|
60
|
-
var
|
|
63
|
+
var import_utils4 = require("@vizij/utils");
|
|
64
|
+
var import_utils5 = require("@vizij/utils");
|
|
65
|
+
var import_metadata2 = require("@vizij/node-graph-wasm/metadata");
|
|
61
66
|
|
|
62
67
|
// src/state.ts
|
|
63
68
|
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
69
|
var VECTOR_ANIMATABLE_TYPES = /* @__PURE__ */ new Set(["vector2", "vector3", "euler", "rgb"]);
|
|
143
70
|
function deriveComponentValueType(component) {
|
|
144
71
|
if (component.component) {
|
|
@@ -177,90 +104,10 @@ function bindingTargetFromInput(input) {
|
|
|
177
104
|
valueType: "scalar"
|
|
178
105
|
};
|
|
179
106
|
}
|
|
180
|
-
var DEFAULT_INPUT_RANGE = { min: -1, max: 1 };
|
|
181
|
-
var DEFAULT_INPUT_ANCHOR = 0;
|
|
182
|
-
var EPSILON = 1e-6;
|
|
183
107
|
var LEGACY_SLOT_PATTERN = /^slot_(\d+)$/i;
|
|
184
108
|
var ALIAS_SANITIZE_PATTERN = /[^A-Za-z0-9_]+/g;
|
|
185
109
|
var PRIMARY_SLOT_ID = "s1";
|
|
186
110
|
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
111
|
function defaultSlotId(index) {
|
|
265
112
|
return `s${index + 1}`;
|
|
266
113
|
}
|
|
@@ -332,125 +179,11 @@ function rewriteLegacyExpression(expression, replacements) {
|
|
|
332
179
|
return `s${digits}`;
|
|
333
180
|
});
|
|
334
181
|
}
|
|
335
|
-
function
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
function isFiniteNumber(value) {
|
|
339
|
-
return typeof value === "number" && Number.isFinite(value);
|
|
340
|
-
}
|
|
341
|
-
function deriveOutputDefaults(target) {
|
|
342
|
-
const { min, max } = target.range;
|
|
343
|
-
const anchor = clamp(target.defaultValue, min, max);
|
|
344
|
-
return {
|
|
345
|
-
outLow: min,
|
|
346
|
-
outAnchor: anchor,
|
|
347
|
-
outHigh: max
|
|
348
|
-
};
|
|
349
|
-
}
|
|
350
|
-
function deriveInputDefaults() {
|
|
351
|
-
return {
|
|
352
|
-
inLow: DEFAULT_INPUT_RANGE.min,
|
|
353
|
-
inAnchor: DEFAULT_INPUT_ANCHOR,
|
|
354
|
-
inHigh: DEFAULT_INPUT_RANGE.max
|
|
355
|
-
};
|
|
356
|
-
}
|
|
357
|
-
function migrateLegacyRemap(legacy, target) {
|
|
358
|
-
const inputDefaults = deriveInputDefaults();
|
|
359
|
-
const outputDefaults = deriveOutputDefaults(target);
|
|
360
|
-
const defaults = {
|
|
361
|
-
inLow: inputDefaults.inLow,
|
|
362
|
-
inAnchor: inputDefaults.inAnchor,
|
|
363
|
-
inHigh: inputDefaults.inHigh,
|
|
364
|
-
outLow: outputDefaults.outLow,
|
|
365
|
-
outAnchor: outputDefaults.outAnchor,
|
|
366
|
-
outHigh: outputDefaults.outHigh
|
|
367
|
-
};
|
|
368
|
-
if ("inLow" in legacy && "inHigh" in legacy && "outLow" in legacy && "outHigh" in legacy) {
|
|
369
|
-
const inLow2 = isFiniteNumber(legacy.inLow) ? legacy.inLow : defaults.inLow;
|
|
370
|
-
const inAnchor2 = isFiniteNumber(legacy.inAnchor) ? legacy.inAnchor : defaults.inAnchor;
|
|
371
|
-
const inHigh2 = isFiniteNumber(legacy.inHigh) ? legacy.inHigh : defaults.inHigh;
|
|
372
|
-
let outLow = isFiniteNumber(legacy.outLow) ? legacy.outLow : defaults.outLow;
|
|
373
|
-
let outHigh = isFiniteNumber(legacy.outHigh) ? legacy.outHigh : defaults.outHigh;
|
|
374
|
-
if (outLow > outHigh) {
|
|
375
|
-
const low = outHigh;
|
|
376
|
-
const high = outLow;
|
|
377
|
-
outLow = low;
|
|
378
|
-
outHigh = high;
|
|
379
|
-
}
|
|
380
|
-
const outAnchor2 = clamp(
|
|
381
|
-
isFiniteNumber(legacy.outAnchor) ? legacy.outAnchor : defaults.outAnchor,
|
|
382
|
-
outLow,
|
|
383
|
-
outHigh
|
|
384
|
-
);
|
|
385
|
-
return {
|
|
386
|
-
inLow: inLow2,
|
|
387
|
-
inAnchor: inAnchor2,
|
|
388
|
-
inHigh: inHigh2,
|
|
389
|
-
outLow,
|
|
390
|
-
outAnchor: outAnchor2,
|
|
391
|
-
outHigh
|
|
392
|
-
};
|
|
393
|
-
}
|
|
394
|
-
const legacyTyped = legacy;
|
|
395
|
-
const inLow = isFiniteNumber(legacyTyped.inMin) ? legacyTyped.inMin : defaults.inLow;
|
|
396
|
-
const inHigh = isFiniteNumber(legacyTyped.inMax) ? legacyTyped.inMax : defaults.inHigh;
|
|
397
|
-
const inAnchor = (inLow + inHigh) / 2;
|
|
398
|
-
const legacyOutMid = isFiniteNumber(legacyTyped.outMin) && isFiniteNumber(legacyTyped.outMax) ? (legacyTyped.outMin + legacyTyped.outMax) / 2 : defaults.outAnchor;
|
|
399
|
-
const outAnchor = clamp(legacyOutMid, defaults.outLow, defaults.outHigh);
|
|
400
|
-
return {
|
|
401
|
-
inLow,
|
|
402
|
-
inAnchor,
|
|
403
|
-
inHigh,
|
|
404
|
-
outLow: defaults.outLow,
|
|
405
|
-
outAnchor,
|
|
406
|
-
outHigh: defaults.outHigh
|
|
407
|
-
};
|
|
408
|
-
}
|
|
409
|
-
function normalizeRemap(remap, target) {
|
|
410
|
-
if (!remap) {
|
|
411
|
-
return createDefaultRemap(target);
|
|
412
|
-
}
|
|
413
|
-
return migrateLegacyRemap(remap, target);
|
|
414
|
-
}
|
|
415
|
-
function cloneRemap(remap) {
|
|
416
|
-
return (0, import_utils.cloneRemapSettings)(remap);
|
|
417
|
-
}
|
|
418
|
-
function sanitizeRemap(remap, target) {
|
|
419
|
-
const normalized = normalizeRemap(remap, target);
|
|
420
|
-
const outputDefaults = deriveOutputDefaults(target);
|
|
421
|
-
if (!Number.isFinite(normalized.outLow)) {
|
|
422
|
-
normalized.outLow = outputDefaults.outLow;
|
|
423
|
-
}
|
|
424
|
-
if (!Number.isFinite(normalized.outHigh)) {
|
|
425
|
-
normalized.outHigh = outputDefaults.outHigh;
|
|
426
|
-
}
|
|
427
|
-
if (!Number.isFinite(normalized.outAnchor)) {
|
|
428
|
-
normalized.outAnchor = outputDefaults.outAnchor;
|
|
182
|
+
function cloneBindingMetadata(metadata) {
|
|
183
|
+
if (!metadata) {
|
|
184
|
+
return void 0;
|
|
429
185
|
}
|
|
430
|
-
|
|
431
|
-
const low = normalized.outHigh;
|
|
432
|
-
const high = normalized.outLow;
|
|
433
|
-
normalized.outLow = low;
|
|
434
|
-
normalized.outHigh = high;
|
|
435
|
-
}
|
|
436
|
-
normalized.outAnchor = clamp(
|
|
437
|
-
normalized.outAnchor,
|
|
438
|
-
normalized.outLow,
|
|
439
|
-
normalized.outHigh
|
|
440
|
-
);
|
|
441
|
-
return normalized;
|
|
442
|
-
}
|
|
443
|
-
function createDefaultRemap(target) {
|
|
444
|
-
const inputDefaults = deriveInputDefaults();
|
|
445
|
-
const outputDefaults = deriveOutputDefaults(target);
|
|
446
|
-
return {
|
|
447
|
-
inLow: inputDefaults.inLow,
|
|
448
|
-
inAnchor: inputDefaults.inAnchor,
|
|
449
|
-
inHigh: inputDefaults.inHigh,
|
|
450
|
-
outLow: outputDefaults.outLow,
|
|
451
|
-
outAnchor: outputDefaults.outAnchor,
|
|
452
|
-
outHigh: outputDefaults.outHigh
|
|
453
|
-
};
|
|
186
|
+
return (0, import_utils.cloneDeepSafe)(metadata);
|
|
454
187
|
}
|
|
455
188
|
function createDefaultBindings(components) {
|
|
456
189
|
const bindings = {};
|
|
@@ -460,23 +193,20 @@ function createDefaultBindings(components) {
|
|
|
460
193
|
return bindings;
|
|
461
194
|
}
|
|
462
195
|
function createDefaultBinding(component) {
|
|
463
|
-
const remap = createDefaultRemap(component);
|
|
464
196
|
const valueType = getTargetValueType(component);
|
|
197
|
+
const slots = [
|
|
198
|
+
{
|
|
199
|
+
id: PRIMARY_SLOT_ID,
|
|
200
|
+
alias: PRIMARY_SLOT_ALIAS,
|
|
201
|
+
inputId: null,
|
|
202
|
+
valueType
|
|
203
|
+
}
|
|
204
|
+
];
|
|
465
205
|
return {
|
|
466
206
|
targetId: component.id,
|
|
467
207
|
inputId: null,
|
|
468
|
-
|
|
469
|
-
|
|
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()
|
|
208
|
+
slots,
|
|
209
|
+
expression: buildCanonicalExpressionFromSlots(slots)
|
|
480
210
|
};
|
|
481
211
|
}
|
|
482
212
|
function createDefaultParentBinding(component) {
|
|
@@ -496,11 +226,10 @@ function createDefaultParentBinding(component) {
|
|
|
496
226
|
...ensured,
|
|
497
227
|
inputId: import_utils.SELF_BINDING_ID,
|
|
498
228
|
slots,
|
|
499
|
-
expression:
|
|
229
|
+
expression: buildCanonicalExpressionFromSlots(slots)
|
|
500
230
|
};
|
|
501
231
|
}
|
|
502
232
|
function ensurePrimarySlot(binding, target) {
|
|
503
|
-
const normalizedBindingRemap = sanitizeRemap(binding.remap, target);
|
|
504
233
|
const targetValueType = getTargetValueType(target);
|
|
505
234
|
const aliasReplacements = /* @__PURE__ */ new Map();
|
|
506
235
|
const sourceSlots = Array.isArray(binding.slots) && binding.slots.length > 0 ? binding.slots : [
|
|
@@ -508,7 +237,6 @@ function ensurePrimarySlot(binding, target) {
|
|
|
508
237
|
id: PRIMARY_SLOT_ID,
|
|
509
238
|
alias: PRIMARY_SLOT_ALIAS,
|
|
510
239
|
inputId: binding.inputId ?? null,
|
|
511
|
-
remap: cloneRemap(normalizedBindingRemap),
|
|
512
240
|
valueType: targetValueType
|
|
513
241
|
}
|
|
514
242
|
];
|
|
@@ -523,8 +251,6 @@ function ensurePrimarySlot(binding, target) {
|
|
|
523
251
|
if (replaced && replaced !== normalizedAlias) {
|
|
524
252
|
aliasReplacements.set(replaced, normalizedAlias);
|
|
525
253
|
}
|
|
526
|
-
const slotRemapSource = slot.remap ?? (index === 0 ? normalizedBindingRemap : createDefaultRemap(target));
|
|
527
|
-
const normalizedSlotRemap = sanitizeRemap(slotRemapSource, target);
|
|
528
254
|
const inputId = slot.inputId !== void 0 && slot.inputId !== null ? slot.inputId : index === 0 ? binding.inputId ?? null : null;
|
|
529
255
|
const slotValueType = sanitizeSlotValueType(
|
|
530
256
|
slot.valueType,
|
|
@@ -534,13 +260,11 @@ function ensurePrimarySlot(binding, target) {
|
|
|
534
260
|
id: normalizedId,
|
|
535
261
|
alias: normalizedAlias,
|
|
536
262
|
inputId,
|
|
537
|
-
remap: cloneRemap(normalizedSlotRemap),
|
|
538
263
|
valueType: slotValueType
|
|
539
264
|
};
|
|
540
265
|
}
|
|
541
266
|
);
|
|
542
267
|
const primary = normalizedSlots[0];
|
|
543
|
-
const primaryRemap = sanitizeRemap(primary.remap, target);
|
|
544
268
|
const primaryInputId = primary.inputId === import_utils.SELF_BINDING_ID ? import_utils.SELF_BINDING_ID : primary.inputId ?? binding.inputId ?? null;
|
|
545
269
|
const primaryAlias = primaryInputId === import_utils.SELF_BINDING_ID ? "self" : primary.alias || PRIMARY_SLOT_ALIAS;
|
|
546
270
|
normalizedSlots[0] = {
|
|
@@ -548,37 +272,31 @@ function ensurePrimarySlot(binding, target) {
|
|
|
548
272
|
id: primary.id || PRIMARY_SLOT_ID,
|
|
549
273
|
alias: primaryAlias,
|
|
550
274
|
inputId: primaryInputId,
|
|
551
|
-
remap: cloneRemap(primaryRemap),
|
|
552
275
|
valueType: sanitizeSlotValueType(primary.valueType, targetValueType)
|
|
553
276
|
};
|
|
554
277
|
normalizedSlots.slice(1).forEach((slot, index) => {
|
|
555
|
-
const slotRemap = sanitizeRemap(slot.remap, target);
|
|
556
278
|
normalizedSlots[index + 1] = {
|
|
557
279
|
...slot,
|
|
558
280
|
id: slot.id || defaultSlotId(index + 1),
|
|
559
281
|
alias: slot.alias || defaultSlotId(index + 1),
|
|
560
|
-
remap: cloneRemap(slotRemap),
|
|
561
282
|
valueType: sanitizeSlotValueType(slot.valueType, targetValueType)
|
|
562
283
|
};
|
|
563
284
|
});
|
|
564
285
|
const rawExpression = typeof binding.expression === "string" ? binding.expression.trim() : "";
|
|
565
|
-
|
|
566
|
-
|
|
286
|
+
const canonicalExpression = buildCanonicalExpressionFromSlots(normalizedSlots);
|
|
287
|
+
let expression;
|
|
288
|
+
if (expressionMatchesAliasOnly(rawExpression, normalizedSlots)) {
|
|
289
|
+
expression = canonicalExpression;
|
|
290
|
+
} else {
|
|
291
|
+
expression = rewriteLegacyExpression(rawExpression, aliasReplacements);
|
|
292
|
+
}
|
|
567
293
|
const normalizedBinding = {
|
|
568
294
|
...binding,
|
|
569
295
|
inputId: normalizedSlots[0].inputId ?? null,
|
|
570
|
-
remap: cloneRemap(primaryRemap),
|
|
571
296
|
slots: normalizedSlots,
|
|
572
297
|
expression
|
|
573
298
|
};
|
|
574
|
-
|
|
575
|
-
if (operatorsEqual(normalizedBinding.operators, operators)) {
|
|
576
|
-
return normalizedBinding;
|
|
577
|
-
}
|
|
578
|
-
return {
|
|
579
|
-
...normalizedBinding,
|
|
580
|
-
operators
|
|
581
|
-
};
|
|
299
|
+
return normalizedBinding;
|
|
582
300
|
}
|
|
583
301
|
function createDefaultInputValues(inputs = []) {
|
|
584
302
|
const values = {};
|
|
@@ -601,14 +319,13 @@ function addBindingSlot(binding, target) {
|
|
|
601
319
|
const nextIndex = base.slots.length + 1;
|
|
602
320
|
const slotId = defaultSlotId(nextIndex - 1);
|
|
603
321
|
const alias = slotId;
|
|
604
|
-
const remap = createDefaultRemap(target);
|
|
605
322
|
const nextSlots = [
|
|
606
323
|
...base.slots,
|
|
607
324
|
{
|
|
608
325
|
id: slotId,
|
|
609
326
|
alias,
|
|
610
327
|
inputId: null,
|
|
611
|
-
|
|
328
|
+
valueType: getTargetValueType(target)
|
|
612
329
|
}
|
|
613
330
|
];
|
|
614
331
|
return ensurePrimarySlot(
|
|
@@ -689,206 +406,105 @@ function updateBindingSlotAlias(binding, target, slotId, nextAlias) {
|
|
|
689
406
|
);
|
|
690
407
|
return updated;
|
|
691
408
|
}
|
|
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;
|
|
409
|
+
function updateBindingSlotValueType(binding, target, slotId, nextValueType) {
|
|
410
|
+
const base = ensurePrimarySlot(binding, target);
|
|
411
|
+
const slotIndex = base.slots.findIndex((slot) => slot.id === slotId);
|
|
412
|
+
if (slotIndex < 0) {
|
|
413
|
+
return base;
|
|
713
414
|
}
|
|
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
|
|
415
|
+
const normalizedType = sanitizeSlotValueType(
|
|
416
|
+
nextValueType,
|
|
417
|
+
getTargetValueType(target)
|
|
724
418
|
);
|
|
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;
|
|
419
|
+
const slots = base.slots.map((slot, index) => {
|
|
420
|
+
if (index !== slotIndex) {
|
|
421
|
+
return slot;
|
|
742
422
|
}
|
|
743
|
-
changed = true;
|
|
744
423
|
return {
|
|
745
|
-
...
|
|
746
|
-
|
|
747
|
-
...operator.params,
|
|
748
|
-
[paramId]: nextValue
|
|
749
|
-
}
|
|
424
|
+
...slot,
|
|
425
|
+
valueType: normalizedType
|
|
750
426
|
};
|
|
751
427
|
});
|
|
752
|
-
if (!changed) {
|
|
753
|
-
return normalizedBinding;
|
|
754
|
-
}
|
|
755
|
-
if (operatorsEqual(normalizedBinding.operators, nextOperators)) {
|
|
756
|
-
return normalizedBinding;
|
|
757
|
-
}
|
|
758
428
|
return {
|
|
759
|
-
...
|
|
760
|
-
|
|
429
|
+
...base,
|
|
430
|
+
slots
|
|
761
431
|
};
|
|
762
432
|
}
|
|
763
433
|
function updateBindingExpression(binding, target, expression) {
|
|
764
434
|
const base = ensurePrimarySlot(binding, target);
|
|
765
435
|
const trimmed = expression.trim();
|
|
436
|
+
const canonicalExpression = buildCanonicalExpressionFromSlots(base.slots);
|
|
766
437
|
return {
|
|
767
438
|
...base,
|
|
768
|
-
expression: trimmed.length > 0 ? trimmed :
|
|
439
|
+
expression: trimmed.length > 0 ? trimmed : canonicalExpression
|
|
769
440
|
};
|
|
770
441
|
}
|
|
771
|
-
function updateBindingSlotRemap(binding, target, slotId, field, value) {
|
|
772
|
-
const base = ensurePrimarySlot(binding, target);
|
|
773
|
-
const nextSlots = base.slots.map((slot) => {
|
|
774
|
-
if (slot.id !== slotId) {
|
|
775
|
-
return slot;
|
|
776
|
-
}
|
|
777
|
-
const updatedRemap = {
|
|
778
|
-
...slot.remap,
|
|
779
|
-
[field]: value
|
|
780
|
-
};
|
|
781
|
-
const sanitized = sanitizeRemap(updatedRemap, target);
|
|
782
|
-
return {
|
|
783
|
-
...slot,
|
|
784
|
-
remap: cloneRemap(sanitized)
|
|
785
|
-
};
|
|
786
|
-
});
|
|
787
|
-
const updated = ensurePrimarySlot(
|
|
788
|
-
{
|
|
789
|
-
...base,
|
|
790
|
-
slots: nextSlots
|
|
791
|
-
},
|
|
792
|
-
target
|
|
793
|
-
);
|
|
794
|
-
if (updated.slots[0]?.id === slotId) {
|
|
795
|
-
updated.remap = {
|
|
796
|
-
...updated.remap,
|
|
797
|
-
[field]: value
|
|
798
|
-
};
|
|
799
|
-
}
|
|
800
|
-
return updated;
|
|
801
|
-
}
|
|
802
442
|
function updateBindingWithInput(binding, target, input, slotId = PRIMARY_SLOT_ID) {
|
|
803
443
|
const base = ensurePrimarySlot(binding, target);
|
|
444
|
+
const existingExpression = typeof base.expression === "string" ? base.expression.trim() : "";
|
|
445
|
+
const canonicalBefore = buildCanonicalExpressionFromSlots(base.slots);
|
|
446
|
+
const expressionWasDefault = expressionMatchesAliasOnly(existingExpression, base.slots) || expressionsEquivalent(existingExpression, canonicalBefore);
|
|
804
447
|
const slotIndex = base.slots.findIndex((slot) => slot.id === slotId);
|
|
805
448
|
const effectiveIndex = slotIndex >= 0 ? slotIndex : base.slots.length;
|
|
806
|
-
const slots = base.slots.map((slot) => ({
|
|
807
|
-
...slot,
|
|
808
|
-
remap: cloneRemap(slot.remap)
|
|
809
|
-
}));
|
|
449
|
+
const slots = base.slots.map((slot) => ({ ...slot }));
|
|
810
450
|
if (slotIndex === -1) {
|
|
811
451
|
const alias = slotId === PRIMARY_SLOT_ID && slots.length === 0 ? PRIMARY_SLOT_ALIAS : slotId;
|
|
812
452
|
slots.push({
|
|
813
453
|
id: slotId,
|
|
814
454
|
alias,
|
|
815
455
|
inputId: null,
|
|
816
|
-
|
|
456
|
+
valueType: getTargetValueType(target)
|
|
817
457
|
});
|
|
818
458
|
}
|
|
819
459
|
const currentSlot = slots[effectiveIndex];
|
|
460
|
+
let nextBinding;
|
|
820
461
|
if (!input) {
|
|
821
|
-
const normalizedSlotRemap = sanitizeRemap(currentSlot.remap, target);
|
|
822
|
-
const updatedRemap2 = {
|
|
823
|
-
...normalizedSlotRemap,
|
|
824
|
-
inLow: DEFAULT_INPUT_RANGE.min,
|
|
825
|
-
inAnchor: DEFAULT_INPUT_ANCHOR,
|
|
826
|
-
inHigh: DEFAULT_INPUT_RANGE.max
|
|
827
|
-
};
|
|
828
462
|
slots[effectiveIndex] = {
|
|
829
463
|
...currentSlot,
|
|
830
|
-
inputId: null
|
|
831
|
-
remap: cloneRemap(updatedRemap2)
|
|
464
|
+
inputId: null
|
|
832
465
|
};
|
|
833
466
|
if (effectiveIndex === 0) {
|
|
834
|
-
|
|
467
|
+
nextBinding = {
|
|
835
468
|
...base,
|
|
836
469
|
inputId: null,
|
|
837
|
-
|
|
470
|
+
slots
|
|
471
|
+
};
|
|
472
|
+
} else {
|
|
473
|
+
nextBinding = {
|
|
474
|
+
...base,
|
|
838
475
|
slots
|
|
839
476
|
};
|
|
840
477
|
}
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
478
|
+
} else {
|
|
479
|
+
slots[effectiveIndex] = {
|
|
480
|
+
...currentSlot,
|
|
481
|
+
inputId: input.id
|
|
844
482
|
};
|
|
483
|
+
if (effectiveIndex === 0) {
|
|
484
|
+
nextBinding = {
|
|
485
|
+
...base,
|
|
486
|
+
inputId: input.id,
|
|
487
|
+
slots
|
|
488
|
+
};
|
|
489
|
+
} else {
|
|
490
|
+
nextBinding = {
|
|
491
|
+
...base,
|
|
492
|
+
slots
|
|
493
|
+
};
|
|
494
|
+
}
|
|
845
495
|
}
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
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,
|
|
862
|
-
inputId: input.id,
|
|
863
|
-
remap: cloneRemap(updatedRemap),
|
|
864
|
-
slots
|
|
865
|
-
};
|
|
496
|
+
if (!expressionWasDefault) {
|
|
497
|
+
return nextBinding;
|
|
498
|
+
}
|
|
499
|
+
const canonicalAfter = buildCanonicalExpressionFromSlots(nextBinding.slots);
|
|
500
|
+
if (expressionsEquivalent(nextBinding.expression ?? "", canonicalAfter)) {
|
|
501
|
+
return nextBinding;
|
|
866
502
|
}
|
|
867
503
|
return {
|
|
868
|
-
...
|
|
869
|
-
|
|
504
|
+
...nextBinding,
|
|
505
|
+
expression: canonicalAfter
|
|
870
506
|
};
|
|
871
507
|
}
|
|
872
|
-
function remapValue(value, remap) {
|
|
873
|
-
const { inLow, inAnchor, inHigh, outLow, outAnchor, outHigh } = remap;
|
|
874
|
-
if (Number.isNaN(value)) {
|
|
875
|
-
return outAnchor;
|
|
876
|
-
}
|
|
877
|
-
if (value <= inAnchor) {
|
|
878
|
-
const span2 = inAnchor - inLow;
|
|
879
|
-
if (Math.abs(span2) < EPSILON) {
|
|
880
|
-
return outLow;
|
|
881
|
-
}
|
|
882
|
-
const t2 = (value - inLow) / span2;
|
|
883
|
-
return outLow + t2 * (outAnchor - outLow);
|
|
884
|
-
}
|
|
885
|
-
const span = inHigh - inAnchor;
|
|
886
|
-
if (Math.abs(span) < EPSILON) {
|
|
887
|
-
return outHigh;
|
|
888
|
-
}
|
|
889
|
-
const t = (value - inAnchor) / span;
|
|
890
|
-
return outAnchor + t * (outHigh - outAnchor);
|
|
891
|
-
}
|
|
892
508
|
function reconcileBindings(previous, components) {
|
|
893
509
|
const next = {};
|
|
894
510
|
components.forEach((component) => {
|
|
@@ -906,12 +522,10 @@ function reconcileBindings(previous, components) {
|
|
|
906
522
|
if (replaced && replaced !== normalizedAlias) {
|
|
907
523
|
aliasReplacements.set(replaced, normalizedAlias);
|
|
908
524
|
}
|
|
909
|
-
const slotRemap = sanitizeRemap(slot.remap, component);
|
|
910
525
|
return {
|
|
911
526
|
...slot,
|
|
912
527
|
id: normalizedId,
|
|
913
|
-
alias: normalizedAlias
|
|
914
|
-
remap: cloneRemap(slotRemap)
|
|
528
|
+
alias: normalizedAlias
|
|
915
529
|
};
|
|
916
530
|
});
|
|
917
531
|
const primary = slots[0];
|
|
@@ -921,7 +535,6 @@ function reconcileBindings(previous, components) {
|
|
|
921
535
|
...ensured,
|
|
922
536
|
targetId: component.id,
|
|
923
537
|
inputId: primary.inputId ?? null,
|
|
924
|
-
remap: cloneRemap(primary.remap),
|
|
925
538
|
slots,
|
|
926
539
|
expression
|
|
927
540
|
};
|
|
@@ -932,20 +545,11 @@ function reconcileBindings(previous, components) {
|
|
|
932
545
|
return next;
|
|
933
546
|
}
|
|
934
547
|
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
548
|
const definition = {
|
|
941
549
|
inputId: binding.inputId ?? null,
|
|
942
|
-
|
|
943
|
-
slots: binding.slots.map((slot) => ({
|
|
944
|
-
...slot,
|
|
945
|
-
remap: cloneRemap(slot.remap)
|
|
946
|
-
})),
|
|
550
|
+
slots: binding.slots.map((slot) => ({ ...slot })),
|
|
947
551
|
expression: binding.expression,
|
|
948
|
-
|
|
552
|
+
metadata: cloneBindingMetadata(binding.metadata)
|
|
949
553
|
};
|
|
950
554
|
return definition;
|
|
951
555
|
}
|
|
@@ -953,27 +557,57 @@ function bindingFromDefinition(target, definition) {
|
|
|
953
557
|
if (!definition) {
|
|
954
558
|
return createDefaultBinding(target);
|
|
955
559
|
}
|
|
956
|
-
const definitionOperators = definition.operators;
|
|
957
560
|
const binding = {
|
|
958
561
|
targetId: target.id,
|
|
959
562
|
inputId: definition.inputId ?? null,
|
|
960
|
-
|
|
961
|
-
slots: definition.slots.map((slot) => ({
|
|
962
|
-
...slot,
|
|
963
|
-
remap: cloneRemap(slot.remap)
|
|
964
|
-
})),
|
|
563
|
+
slots: definition.slots.map((slot) => ({ ...slot })),
|
|
965
564
|
expression: definition.expression,
|
|
966
|
-
|
|
967
|
-
type: operator.type,
|
|
968
|
-
enabled: !!operator.enabled,
|
|
969
|
-
params: { ...operator.params }
|
|
970
|
-
})) : void 0
|
|
565
|
+
metadata: cloneBindingMetadata(definition.metadata)
|
|
971
566
|
};
|
|
972
567
|
return ensureBindingStructure(binding, target);
|
|
973
568
|
}
|
|
569
|
+
function normalizeSlotAliasForExpression(slot, index) {
|
|
570
|
+
if (slot.alias && slot.alias.trim().length > 0) {
|
|
571
|
+
return slot.alias.trim();
|
|
572
|
+
}
|
|
573
|
+
if (slot.id && slot.id.trim().length > 0) {
|
|
574
|
+
return slot.id.trim();
|
|
575
|
+
}
|
|
576
|
+
return defaultSlotId(index);
|
|
577
|
+
}
|
|
578
|
+
function buildAliasOnlyExpression(slots) {
|
|
579
|
+
if (!slots.length) {
|
|
580
|
+
return PRIMARY_SLOT_ALIAS;
|
|
581
|
+
}
|
|
582
|
+
return slots.map((slot, index) => normalizeSlotAliasForExpression(slot, index)).join(" + ");
|
|
583
|
+
}
|
|
584
|
+
function buildCanonicalExpressionFromSlots(slots) {
|
|
585
|
+
return buildAliasOnlyExpression(slots);
|
|
586
|
+
}
|
|
587
|
+
function expressionsEquivalent(left, right) {
|
|
588
|
+
return left.trim() === right.trim();
|
|
589
|
+
}
|
|
590
|
+
function expressionMatchesAliasOnly(expression, slots) {
|
|
591
|
+
if (expression.trim().length === 0) {
|
|
592
|
+
return true;
|
|
593
|
+
}
|
|
594
|
+
const aliasOnly = buildAliasOnlyExpression(slots);
|
|
595
|
+
return expressionsEquivalent(expression, aliasOnly);
|
|
596
|
+
}
|
|
597
|
+
function buildCanonicalBindingExpression(binding) {
|
|
598
|
+
const slots = binding.slots ?? [];
|
|
599
|
+
return buildCanonicalExpressionFromSlots(slots);
|
|
600
|
+
}
|
|
974
601
|
|
|
975
602
|
// src/expression.ts
|
|
976
|
-
var
|
|
603
|
+
var STANDARD_WHITESPACE = /\s/;
|
|
604
|
+
var EXTRA_WHITESPACE_CHARS = /* @__PURE__ */ new Set(["\0", "\u200B", "\uFEFF"]);
|
|
605
|
+
function isWhitespaceCharacter(char) {
|
|
606
|
+
if (!char) {
|
|
607
|
+
return false;
|
|
608
|
+
}
|
|
609
|
+
return STANDARD_WHITESPACE.test(char) || EXTRA_WHITESPACE_CHARS.has(char);
|
|
610
|
+
}
|
|
977
611
|
var IDENT_START = /[A-Za-z_]/;
|
|
978
612
|
var IDENT_PART = /[A-Za-z0-9_]/;
|
|
979
613
|
var DIGIT = /[0-9]/;
|
|
@@ -1211,6 +845,10 @@ var ControlExpressionParser = class {
|
|
|
1211
845
|
});
|
|
1212
846
|
return null;
|
|
1213
847
|
}
|
|
848
|
+
if (char === "[") {
|
|
849
|
+
this.index += 1;
|
|
850
|
+
return this.parseVectorLiteral("]", "vector literal");
|
|
851
|
+
}
|
|
1214
852
|
if (IDENT_START.test(char)) {
|
|
1215
853
|
return this.parseIdentifierOrFunction();
|
|
1216
854
|
}
|
|
@@ -1239,6 +877,9 @@ var ControlExpressionParser = class {
|
|
|
1239
877
|
this.skipWhitespace();
|
|
1240
878
|
if (this.peek() === "(") {
|
|
1241
879
|
this.index += 1;
|
|
880
|
+
if (name.toLowerCase() === "vec") {
|
|
881
|
+
return this.parseVectorLiteral(")", `"${name}" literal`);
|
|
882
|
+
}
|
|
1242
883
|
const args = [];
|
|
1243
884
|
this.skipWhitespace();
|
|
1244
885
|
if (this.peek() === ")") {
|
|
@@ -1301,28 +942,134 @@ var ControlExpressionParser = class {
|
|
|
1301
942
|
name
|
|
1302
943
|
};
|
|
1303
944
|
}
|
|
1304
|
-
|
|
945
|
+
parseVectorLiteral(terminator, context) {
|
|
946
|
+
const values = this.parseVectorLiteralValues(terminator, context);
|
|
947
|
+
if (!values) {
|
|
948
|
+
return null;
|
|
949
|
+
}
|
|
950
|
+
return {
|
|
951
|
+
type: "VectorLiteral",
|
|
952
|
+
values
|
|
953
|
+
};
|
|
954
|
+
}
|
|
955
|
+
parseVectorLiteralValues(terminator, context) {
|
|
956
|
+
const values = [];
|
|
957
|
+
this.skipWhitespace();
|
|
958
|
+
if (this.peek() === terminator) {
|
|
959
|
+
this.errors.push({
|
|
960
|
+
index: this.index,
|
|
961
|
+
message: `Expected at least one value in ${context}.`
|
|
962
|
+
});
|
|
963
|
+
return null;
|
|
964
|
+
}
|
|
965
|
+
while (true) {
|
|
966
|
+
this.skipWhitespace();
|
|
967
|
+
const literalValue = this.parseNumericLiteralValue();
|
|
968
|
+
if (literalValue === null) {
|
|
969
|
+
this.errors.push({
|
|
970
|
+
index: this.index,
|
|
971
|
+
message: `Expected numeric literal in ${context}.`
|
|
972
|
+
});
|
|
973
|
+
return null;
|
|
974
|
+
}
|
|
975
|
+
values.push(literalValue);
|
|
976
|
+
this.skipWhitespace();
|
|
977
|
+
const next = this.peek();
|
|
978
|
+
if (next === ",") {
|
|
979
|
+
this.index += 1;
|
|
980
|
+
this.skipWhitespace();
|
|
981
|
+
if (this.peek() === terminator) {
|
|
982
|
+
this.errors.push({
|
|
983
|
+
index: this.index,
|
|
984
|
+
message: `Expected value after "," in ${context}.`
|
|
985
|
+
});
|
|
986
|
+
return null;
|
|
987
|
+
}
|
|
988
|
+
continue;
|
|
989
|
+
}
|
|
990
|
+
if (next === terminator) {
|
|
991
|
+
this.index += 1;
|
|
992
|
+
break;
|
|
993
|
+
}
|
|
994
|
+
if (next === null) {
|
|
995
|
+
this.errors.push({
|
|
996
|
+
index: this.index,
|
|
997
|
+
message: `Unterminated ${context}.`
|
|
998
|
+
});
|
|
999
|
+
} else {
|
|
1000
|
+
this.errors.push({
|
|
1001
|
+
index: this.index,
|
|
1002
|
+
message: `Expected "," or "${terminator}" in ${context}.`
|
|
1003
|
+
});
|
|
1004
|
+
}
|
|
1005
|
+
return null;
|
|
1006
|
+
}
|
|
1007
|
+
if (values.length === 0) {
|
|
1008
|
+
this.errors.push({
|
|
1009
|
+
index: this.index,
|
|
1010
|
+
message: `Expected at least one value in ${context}.`
|
|
1011
|
+
});
|
|
1012
|
+
return null;
|
|
1013
|
+
}
|
|
1014
|
+
return values;
|
|
1015
|
+
}
|
|
1016
|
+
parseNumericLiteralValue(allowLeadingSign = true) {
|
|
1305
1017
|
const start = this.index;
|
|
1018
|
+
if (allowLeadingSign && (this.peek() === "+" || this.peek() === "-")) {
|
|
1019
|
+
this.index += 1;
|
|
1020
|
+
}
|
|
1306
1021
|
let hasDigits = false;
|
|
1022
|
+
let seenDecimal = false;
|
|
1023
|
+
let seenExponent = false;
|
|
1024
|
+
let exponentDigits = false;
|
|
1025
|
+
let inExponent = false;
|
|
1307
1026
|
while (!this.isAtEnd()) {
|
|
1308
1027
|
const char = this.peek();
|
|
1309
1028
|
if (DIGIT.test(char)) {
|
|
1310
1029
|
hasDigits = true;
|
|
1030
|
+
if (inExponent) {
|
|
1031
|
+
exponentDigits = true;
|
|
1032
|
+
}
|
|
1311
1033
|
this.index += 1;
|
|
1312
1034
|
continue;
|
|
1313
1035
|
}
|
|
1314
|
-
if (char === ".") {
|
|
1036
|
+
if (char === "." && !seenDecimal && !seenExponent) {
|
|
1037
|
+
seenDecimal = true;
|
|
1315
1038
|
this.index += 1;
|
|
1316
1039
|
continue;
|
|
1317
1040
|
}
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1041
|
+
if ((char === "e" || char === "E") && !seenExponent && hasDigits) {
|
|
1042
|
+
seenExponent = true;
|
|
1043
|
+
inExponent = true;
|
|
1044
|
+
exponentDigits = false;
|
|
1045
|
+
this.index += 1;
|
|
1046
|
+
const sign = this.peek();
|
|
1047
|
+
if (sign === "+" || sign === "-") {
|
|
1048
|
+
this.index += 1;
|
|
1049
|
+
}
|
|
1050
|
+
continue;
|
|
1051
|
+
}
|
|
1052
|
+
break;
|
|
1053
|
+
}
|
|
1054
|
+
if (!hasDigits || seenExponent && !exponentDigits) {
|
|
1055
|
+
this.index = start;
|
|
1056
|
+
return null;
|
|
1057
|
+
}
|
|
1058
|
+
const raw = this.input.slice(start, this.index);
|
|
1059
|
+
const value = Number(raw);
|
|
1060
|
+
if (!Number.isFinite(value)) {
|
|
1061
|
+
this.index = start;
|
|
1062
|
+
return null;
|
|
1063
|
+
}
|
|
1064
|
+
return value;
|
|
1065
|
+
}
|
|
1066
|
+
parseNumber() {
|
|
1067
|
+
const start = this.index;
|
|
1068
|
+
const value = this.parseNumericLiteralValue(false);
|
|
1069
|
+
if (value === null) {
|
|
1323
1070
|
this.errors.push({
|
|
1324
1071
|
index: start,
|
|
1325
|
-
message:
|
|
1072
|
+
message: "Invalid numeric literal."
|
|
1326
1073
|
});
|
|
1327
1074
|
return null;
|
|
1328
1075
|
}
|
|
@@ -1341,130 +1088,1039 @@ var ControlExpressionParser = class {
|
|
|
1341
1088
|
return null;
|
|
1342
1089
|
}
|
|
1343
1090
|
skipWhitespace() {
|
|
1344
|
-
while (!this.isAtEnd()
|
|
1091
|
+
while (!this.isAtEnd()) {
|
|
1092
|
+
const char = this.peek();
|
|
1093
|
+
if (!isWhitespaceCharacter(char)) {
|
|
1094
|
+
break;
|
|
1095
|
+
}
|
|
1345
1096
|
this.index += 1;
|
|
1346
1097
|
}
|
|
1347
1098
|
}
|
|
1348
|
-
peek() {
|
|
1349
|
-
if (this.index >= this.input.length) {
|
|
1350
|
-
return null;
|
|
1351
|
-
}
|
|
1352
|
-
return this.input[this.index] ?? null;
|
|
1099
|
+
peek() {
|
|
1100
|
+
if (this.index >= this.input.length) {
|
|
1101
|
+
return null;
|
|
1102
|
+
}
|
|
1103
|
+
return this.input[this.index] ?? null;
|
|
1104
|
+
}
|
|
1105
|
+
isAtEnd() {
|
|
1106
|
+
return this.index >= this.input.length;
|
|
1107
|
+
}
|
|
1108
|
+
};
|
|
1109
|
+
function parseControlExpression(expression) {
|
|
1110
|
+
const parser = new ControlExpressionParser(expression);
|
|
1111
|
+
return parser.parse();
|
|
1112
|
+
}
|
|
1113
|
+
function collectExpressionReferences(node, target = /* @__PURE__ */ new Set()) {
|
|
1114
|
+
if (!node) {
|
|
1115
|
+
return target;
|
|
1116
|
+
}
|
|
1117
|
+
switch (node.type) {
|
|
1118
|
+
case "Reference":
|
|
1119
|
+
target.add(node.name);
|
|
1120
|
+
break;
|
|
1121
|
+
case "Unary":
|
|
1122
|
+
collectExpressionReferences(node.operand, target);
|
|
1123
|
+
break;
|
|
1124
|
+
case "Binary":
|
|
1125
|
+
collectExpressionReferences(node.left, target);
|
|
1126
|
+
collectExpressionReferences(node.right, target);
|
|
1127
|
+
break;
|
|
1128
|
+
case "Function":
|
|
1129
|
+
node.args.forEach((arg) => collectExpressionReferences(arg, target));
|
|
1130
|
+
break;
|
|
1131
|
+
default:
|
|
1132
|
+
break;
|
|
1133
|
+
}
|
|
1134
|
+
return target;
|
|
1135
|
+
}
|
|
1136
|
+
function mapExpression(node, visit) {
|
|
1137
|
+
visit(node);
|
|
1138
|
+
switch (node.type) {
|
|
1139
|
+
case "Unary":
|
|
1140
|
+
mapExpression(node.operand, visit);
|
|
1141
|
+
break;
|
|
1142
|
+
case "Binary":
|
|
1143
|
+
mapExpression(node.left, visit);
|
|
1144
|
+
mapExpression(node.right, visit);
|
|
1145
|
+
break;
|
|
1146
|
+
case "Function":
|
|
1147
|
+
node.args.forEach((arg) => mapExpression(arg, visit));
|
|
1148
|
+
break;
|
|
1149
|
+
default:
|
|
1150
|
+
break;
|
|
1151
|
+
}
|
|
1152
|
+
}
|
|
1153
|
+
|
|
1154
|
+
// src/expressionFunctions.ts
|
|
1155
|
+
var import_metadata = require("@vizij/node-graph-wasm/metadata");
|
|
1156
|
+
var FUNCTION_OVERRIDES = {
|
|
1157
|
+
case: {
|
|
1158
|
+
replaceInputs: [
|
|
1159
|
+
{ id: "selector", optional: false, valueType: "any" },
|
|
1160
|
+
{ id: "default", optional: false, valueType: "any" }
|
|
1161
|
+
],
|
|
1162
|
+
variadic: { id: "operand", min: 1, max: null, valueType: "any" },
|
|
1163
|
+
minArgs: 3,
|
|
1164
|
+
maxArgs: null,
|
|
1165
|
+
params: []
|
|
1166
|
+
},
|
|
1167
|
+
slew: {
|
|
1168
|
+
dropTrailingInputs: 1,
|
|
1169
|
+
params: [
|
|
1170
|
+
{
|
|
1171
|
+
id: "max_rate",
|
|
1172
|
+
label: "max_rate",
|
|
1173
|
+
optional: false,
|
|
1174
|
+
valueType: "scalar"
|
|
1175
|
+
}
|
|
1176
|
+
],
|
|
1177
|
+
minArgs: 2,
|
|
1178
|
+
maxArgs: 2
|
|
1179
|
+
}
|
|
1180
|
+
};
|
|
1181
|
+
var FUNCTION_CONFIGS = [
|
|
1182
|
+
{
|
|
1183
|
+
typeId: "sin",
|
|
1184
|
+
names: ["sin"],
|
|
1185
|
+
category: "math",
|
|
1186
|
+
description: "Sine of the input value (radians)."
|
|
1187
|
+
},
|
|
1188
|
+
{
|
|
1189
|
+
typeId: "cos",
|
|
1190
|
+
names: ["cos"],
|
|
1191
|
+
category: "math",
|
|
1192
|
+
description: "Cosine of the input value (radians)."
|
|
1193
|
+
},
|
|
1194
|
+
{
|
|
1195
|
+
typeId: "tan",
|
|
1196
|
+
names: ["tan"],
|
|
1197
|
+
category: "math",
|
|
1198
|
+
description: "Tangent of the input value (radians)."
|
|
1199
|
+
},
|
|
1200
|
+
{
|
|
1201
|
+
typeId: "power",
|
|
1202
|
+
names: ["power", "pow"],
|
|
1203
|
+
category: "math",
|
|
1204
|
+
description: "Raise a base value to an exponent."
|
|
1205
|
+
},
|
|
1206
|
+
{
|
|
1207
|
+
typeId: "log",
|
|
1208
|
+
names: ["log"],
|
|
1209
|
+
category: "math",
|
|
1210
|
+
description: "Logarithm of the input value."
|
|
1211
|
+
},
|
|
1212
|
+
{
|
|
1213
|
+
typeId: "clamp",
|
|
1214
|
+
names: ["clamp"],
|
|
1215
|
+
category: "utility",
|
|
1216
|
+
description: "Clamp an input between min/max."
|
|
1217
|
+
},
|
|
1218
|
+
{
|
|
1219
|
+
typeId: "remap",
|
|
1220
|
+
names: ["remap"],
|
|
1221
|
+
category: "utility",
|
|
1222
|
+
description: "Linearly map a value from the input range to the output range."
|
|
1223
|
+
},
|
|
1224
|
+
{
|
|
1225
|
+
typeId: "centered_remap",
|
|
1226
|
+
names: ["centeredremap", "centered_remap"],
|
|
1227
|
+
category: "utility",
|
|
1228
|
+
description: "Remap a value using in/out ranges that include explicit anchors."
|
|
1229
|
+
},
|
|
1230
|
+
{
|
|
1231
|
+
typeId: "piecewise_remap",
|
|
1232
|
+
names: ["piecewiseremap", "piecewise_remap"],
|
|
1233
|
+
category: "utility",
|
|
1234
|
+
description: "Map a value through piecewise-linear breakpoints."
|
|
1235
|
+
},
|
|
1236
|
+
{
|
|
1237
|
+
typeId: "abs",
|
|
1238
|
+
names: ["abs"],
|
|
1239
|
+
category: "math",
|
|
1240
|
+
description: "Absolute value of the input."
|
|
1241
|
+
},
|
|
1242
|
+
{
|
|
1243
|
+
typeId: "add",
|
|
1244
|
+
names: ["add"],
|
|
1245
|
+
category: "math",
|
|
1246
|
+
description: "Sum all operands together."
|
|
1247
|
+
},
|
|
1248
|
+
{
|
|
1249
|
+
typeId: "multiply",
|
|
1250
|
+
names: ["multiply"],
|
|
1251
|
+
category: "math",
|
|
1252
|
+
description: "Multiply operands together."
|
|
1253
|
+
},
|
|
1254
|
+
{
|
|
1255
|
+
typeId: "subtract",
|
|
1256
|
+
names: ["subtract"],
|
|
1257
|
+
category: "math",
|
|
1258
|
+
description: "Subtract rhs from lhs."
|
|
1259
|
+
},
|
|
1260
|
+
{
|
|
1261
|
+
typeId: "divide",
|
|
1262
|
+
names: ["divide"],
|
|
1263
|
+
category: "math",
|
|
1264
|
+
description: "Divide lhs by rhs."
|
|
1265
|
+
},
|
|
1266
|
+
{
|
|
1267
|
+
typeId: "min",
|
|
1268
|
+
names: ["min"],
|
|
1269
|
+
category: "math",
|
|
1270
|
+
description: "Minimum of all operands."
|
|
1271
|
+
},
|
|
1272
|
+
{
|
|
1273
|
+
typeId: "max",
|
|
1274
|
+
names: ["max"],
|
|
1275
|
+
category: "math",
|
|
1276
|
+
description: "Maximum of all operands."
|
|
1277
|
+
},
|
|
1278
|
+
{
|
|
1279
|
+
typeId: "modulo",
|
|
1280
|
+
names: ["modulo", "mod"],
|
|
1281
|
+
category: "math",
|
|
1282
|
+
description: "Modulo of lhs by rhs."
|
|
1283
|
+
},
|
|
1284
|
+
{
|
|
1285
|
+
typeId: "greaterthan",
|
|
1286
|
+
names: ["greaterthan", "gt"],
|
|
1287
|
+
minArgs: 2,
|
|
1288
|
+
maxArgs: 2,
|
|
1289
|
+
category: "logic",
|
|
1290
|
+
description: "Return true when lhs > rhs."
|
|
1291
|
+
},
|
|
1292
|
+
{
|
|
1293
|
+
typeId: "lessthan",
|
|
1294
|
+
names: ["lessthan", "lt"],
|
|
1295
|
+
minArgs: 2,
|
|
1296
|
+
maxArgs: 2,
|
|
1297
|
+
category: "logic",
|
|
1298
|
+
description: "Return true when lhs < rhs."
|
|
1299
|
+
},
|
|
1300
|
+
{
|
|
1301
|
+
typeId: "equal",
|
|
1302
|
+
names: ["equal", "eq"],
|
|
1303
|
+
minArgs: 2,
|
|
1304
|
+
maxArgs: 2,
|
|
1305
|
+
category: "logic",
|
|
1306
|
+
description: "Return true when operands are equal."
|
|
1307
|
+
},
|
|
1308
|
+
{
|
|
1309
|
+
typeId: "notequal",
|
|
1310
|
+
names: ["notequal", "neq", "ne"],
|
|
1311
|
+
minArgs: 2,
|
|
1312
|
+
maxArgs: 2,
|
|
1313
|
+
category: "logic",
|
|
1314
|
+
description: "Return true when operands differ."
|
|
1315
|
+
},
|
|
1316
|
+
{
|
|
1317
|
+
typeId: "and",
|
|
1318
|
+
names: ["and"],
|
|
1319
|
+
minArgs: 2,
|
|
1320
|
+
maxArgs: 2,
|
|
1321
|
+
category: "logic",
|
|
1322
|
+
description: "Logical AND."
|
|
1323
|
+
},
|
|
1324
|
+
{
|
|
1325
|
+
typeId: "or",
|
|
1326
|
+
names: ["or"],
|
|
1327
|
+
minArgs: 2,
|
|
1328
|
+
maxArgs: 2,
|
|
1329
|
+
category: "logic",
|
|
1330
|
+
description: "Logical OR."
|
|
1331
|
+
},
|
|
1332
|
+
{
|
|
1333
|
+
typeId: "xor",
|
|
1334
|
+
names: ["xor"],
|
|
1335
|
+
minArgs: 2,
|
|
1336
|
+
maxArgs: 2,
|
|
1337
|
+
category: "logic",
|
|
1338
|
+
description: "Logical XOR."
|
|
1339
|
+
},
|
|
1340
|
+
{
|
|
1341
|
+
typeId: "not",
|
|
1342
|
+
names: ["not"],
|
|
1343
|
+
minArgs: 1,
|
|
1344
|
+
maxArgs: 1,
|
|
1345
|
+
category: "logic",
|
|
1346
|
+
description: "Logical NOT of input."
|
|
1347
|
+
},
|
|
1348
|
+
{
|
|
1349
|
+
typeId: "if",
|
|
1350
|
+
names: ["if"],
|
|
1351
|
+
minArgs: 2,
|
|
1352
|
+
maxArgs: 3,
|
|
1353
|
+
category: "logic",
|
|
1354
|
+
description: "Conditional branch with optional fallback."
|
|
1355
|
+
},
|
|
1356
|
+
{
|
|
1357
|
+
typeId: "round",
|
|
1358
|
+
names: ["round"],
|
|
1359
|
+
category: "math",
|
|
1360
|
+
description: "Round input using the configured mode (floor/ceil/trunc)."
|
|
1361
|
+
},
|
|
1362
|
+
{
|
|
1363
|
+
typeId: "case",
|
|
1364
|
+
names: ["case"],
|
|
1365
|
+
minArgs: 3,
|
|
1366
|
+
category: "logic",
|
|
1367
|
+
description: "Route the selector value to matching labeled branches."
|
|
1368
|
+
},
|
|
1369
|
+
{
|
|
1370
|
+
typeId: "time",
|
|
1371
|
+
names: ["time"],
|
|
1372
|
+
minArgs: 0,
|
|
1373
|
+
maxArgs: 0,
|
|
1374
|
+
category: "time",
|
|
1375
|
+
description: "Graph time in seconds."
|
|
1376
|
+
},
|
|
1377
|
+
{
|
|
1378
|
+
typeId: "oscillator",
|
|
1379
|
+
names: ["oscillator"],
|
|
1380
|
+
minArgs: 2,
|
|
1381
|
+
maxArgs: 2,
|
|
1382
|
+
category: "time",
|
|
1383
|
+
description: "Sine/cosine oscillator driven by time."
|
|
1384
|
+
},
|
|
1385
|
+
{
|
|
1386
|
+
typeId: "spring",
|
|
1387
|
+
names: ["spring"],
|
|
1388
|
+
category: "time",
|
|
1389
|
+
description: "Spring toward the target with configurable stiffness and damping."
|
|
1390
|
+
},
|
|
1391
|
+
{
|
|
1392
|
+
typeId: "damp",
|
|
1393
|
+
names: ["damp"],
|
|
1394
|
+
category: "time",
|
|
1395
|
+
description: "Damp input values toward zero at the specified rate."
|
|
1396
|
+
},
|
|
1397
|
+
{
|
|
1398
|
+
typeId: "slew",
|
|
1399
|
+
names: ["slew"],
|
|
1400
|
+
category: "time",
|
|
1401
|
+
description: "Limit the rate of change between inputs over time."
|
|
1402
|
+
},
|
|
1403
|
+
{
|
|
1404
|
+
typeId: "default-blend",
|
|
1405
|
+
names: ["defaultblend", "blend"],
|
|
1406
|
+
category: "utility",
|
|
1407
|
+
description: "Blend operand values using optional baseline/offset and weight inputs."
|
|
1408
|
+
},
|
|
1409
|
+
{
|
|
1410
|
+
typeId: "blendweightedaverage",
|
|
1411
|
+
names: ["blendweightedaverage"],
|
|
1412
|
+
category: "utility",
|
|
1413
|
+
description: "Compute weighted average blends using aggregate sums."
|
|
1414
|
+
},
|
|
1415
|
+
{
|
|
1416
|
+
typeId: "blendadditive",
|
|
1417
|
+
names: ["blendadditive"],
|
|
1418
|
+
category: "utility",
|
|
1419
|
+
description: "Additive blending helper."
|
|
1420
|
+
},
|
|
1421
|
+
{
|
|
1422
|
+
typeId: "blendmultiply",
|
|
1423
|
+
names: ["blendmultiply"],
|
|
1424
|
+
category: "utility",
|
|
1425
|
+
description: "Multiplicative blending helper."
|
|
1426
|
+
},
|
|
1427
|
+
{
|
|
1428
|
+
typeId: "blendweightedoverlay",
|
|
1429
|
+
names: ["blendweightedoverlay"],
|
|
1430
|
+
category: "utility",
|
|
1431
|
+
description: "Overlay blending helper driven by weighted sums."
|
|
1432
|
+
},
|
|
1433
|
+
{
|
|
1434
|
+
typeId: "blendweightedaverageoverlay",
|
|
1435
|
+
names: ["blendweightedaverageoverlay"],
|
|
1436
|
+
category: "utility",
|
|
1437
|
+
description: "Overlay helper that adds averaged deltas to the base value."
|
|
1438
|
+
},
|
|
1439
|
+
{
|
|
1440
|
+
typeId: "blendmax",
|
|
1441
|
+
names: ["blendmax"],
|
|
1442
|
+
category: "utility",
|
|
1443
|
+
description: "Select the operand whose effective weight is largest."
|
|
1444
|
+
},
|
|
1445
|
+
{
|
|
1446
|
+
typeId: "vec3cross",
|
|
1447
|
+
names: ["vec3cross", "cross"],
|
|
1448
|
+
category: "vector",
|
|
1449
|
+
description: "Cross product of vectors A \xD7 B."
|
|
1450
|
+
},
|
|
1451
|
+
{
|
|
1452
|
+
typeId: "vectoradd",
|
|
1453
|
+
names: ["vectoradd", "vadd"],
|
|
1454
|
+
category: "vector",
|
|
1455
|
+
description: "Element-wise sum of vectors."
|
|
1456
|
+
},
|
|
1457
|
+
{
|
|
1458
|
+
typeId: "vectorsubtract",
|
|
1459
|
+
names: ["vectorsubtract", "vsub"],
|
|
1460
|
+
category: "vector",
|
|
1461
|
+
description: "Element-wise subtraction of vectors."
|
|
1462
|
+
},
|
|
1463
|
+
{
|
|
1464
|
+
typeId: "vectormultiply",
|
|
1465
|
+
names: ["vectormultiply", "vmul"],
|
|
1466
|
+
category: "vector",
|
|
1467
|
+
description: "Element-wise multiplication of vectors."
|
|
1468
|
+
},
|
|
1469
|
+
{
|
|
1470
|
+
typeId: "vectorscale",
|
|
1471
|
+
names: ["vectorscale", "vscale"],
|
|
1472
|
+
category: "vector",
|
|
1473
|
+
description: "Scale a vector by a scalar value."
|
|
1474
|
+
},
|
|
1475
|
+
{
|
|
1476
|
+
typeId: "vectornormalize",
|
|
1477
|
+
names: ["vectornormalize", "vnormalize"],
|
|
1478
|
+
category: "vector",
|
|
1479
|
+
description: "Normalize a vector to unit length."
|
|
1480
|
+
},
|
|
1481
|
+
{
|
|
1482
|
+
typeId: "vectordot",
|
|
1483
|
+
names: ["vectordot", "vdot"],
|
|
1484
|
+
category: "vector",
|
|
1485
|
+
description: "Dot product of vectors A \xB7 B."
|
|
1486
|
+
},
|
|
1487
|
+
{
|
|
1488
|
+
typeId: "vectorlength",
|
|
1489
|
+
names: ["vectorlength", "vlength"],
|
|
1490
|
+
category: "vector",
|
|
1491
|
+
description: "Euclidean length of a vector."
|
|
1492
|
+
},
|
|
1493
|
+
{
|
|
1494
|
+
typeId: "vectorindex",
|
|
1495
|
+
names: ["vectorindex", "vindex"],
|
|
1496
|
+
category: "vector",
|
|
1497
|
+
description: "Extract a component from a vector."
|
|
1498
|
+
},
|
|
1499
|
+
{
|
|
1500
|
+
typeId: "vectorconstant",
|
|
1501
|
+
names: ["vectorconstant", "vconst"],
|
|
1502
|
+
category: "vector",
|
|
1503
|
+
description: "Constant vector value."
|
|
1504
|
+
},
|
|
1505
|
+
{
|
|
1506
|
+
typeId: "join",
|
|
1507
|
+
names: ["join"],
|
|
1508
|
+
category: "vector",
|
|
1509
|
+
description: "Join scalar inputs into a vector."
|
|
1510
|
+
},
|
|
1511
|
+
{
|
|
1512
|
+
typeId: "split",
|
|
1513
|
+
names: ["split"],
|
|
1514
|
+
category: "vector",
|
|
1515
|
+
description: "Split a vector into scalar outputs."
|
|
1516
|
+
},
|
|
1517
|
+
{
|
|
1518
|
+
typeId: "vectormin",
|
|
1519
|
+
names: ["vectormin"],
|
|
1520
|
+
category: "vector",
|
|
1521
|
+
description: "Minimum component in a vector."
|
|
1522
|
+
},
|
|
1523
|
+
{
|
|
1524
|
+
typeId: "vectormax",
|
|
1525
|
+
names: ["vectormax"],
|
|
1526
|
+
category: "vector",
|
|
1527
|
+
description: "Maximum component in a vector."
|
|
1528
|
+
},
|
|
1529
|
+
{
|
|
1530
|
+
typeId: "vectormean",
|
|
1531
|
+
names: ["vectormean"],
|
|
1532
|
+
category: "vector",
|
|
1533
|
+
description: "Mean of the provided vector values."
|
|
1534
|
+
},
|
|
1535
|
+
{
|
|
1536
|
+
typeId: "vectormedian",
|
|
1537
|
+
names: ["vectormedian"],
|
|
1538
|
+
category: "vector",
|
|
1539
|
+
description: "Median of the provided vector values."
|
|
1540
|
+
},
|
|
1541
|
+
{
|
|
1542
|
+
typeId: "vectormode",
|
|
1543
|
+
names: ["vectormode"],
|
|
1544
|
+
category: "vector",
|
|
1545
|
+
description: "Mode of the provided vector values."
|
|
1546
|
+
},
|
|
1547
|
+
{
|
|
1548
|
+
typeId: "weightedsumvector",
|
|
1549
|
+
names: ["weightedsumvector", "vectorsum"],
|
|
1550
|
+
category: "vector",
|
|
1551
|
+
description: "Weighted sum across vectors with optional masks."
|
|
1552
|
+
}
|
|
1553
|
+
];
|
|
1554
|
+
var SCALAR_FUNCTIONS = /* @__PURE__ */ new Map();
|
|
1555
|
+
var SCALAR_FUNCTION_VOCABULARY = [];
|
|
1556
|
+
for (const config of FUNCTION_CONFIGS) {
|
|
1557
|
+
const signature = (0, import_metadata.requireNodeSignature)(config.typeId);
|
|
1558
|
+
const signatureInputs = signature.inputs;
|
|
1559
|
+
let inputs = signatureInputs.map((input) => ({
|
|
1560
|
+
id: input.id,
|
|
1561
|
+
optional: Boolean(input.optional),
|
|
1562
|
+
valueType: inferExpressionValueType(input.ty)
|
|
1563
|
+
}));
|
|
1564
|
+
let variadic = signature.variadic_inputs ? {
|
|
1565
|
+
id: signature.variadic_inputs.id,
|
|
1566
|
+
min: signature.variadic_inputs.min,
|
|
1567
|
+
max: typeof signature.variadic_inputs.max === "number" ? signature.variadic_inputs.max : null,
|
|
1568
|
+
valueType: inferExpressionValueType(signature.variadic_inputs.ty)
|
|
1569
|
+
} : null;
|
|
1570
|
+
const baseRequiredInputs = inputs.filter((input) => !input.optional).length;
|
|
1571
|
+
const variadicMin = variadic?.min ?? 0;
|
|
1572
|
+
const derivedMin = baseRequiredInputs + variadicMin;
|
|
1573
|
+
let derivedMax;
|
|
1574
|
+
if (variadic) {
|
|
1575
|
+
derivedMax = variadic.max === null ? null : inputs.length + (variadic.max ?? 0);
|
|
1576
|
+
} else {
|
|
1577
|
+
derivedMax = inputs.length;
|
|
1578
|
+
}
|
|
1579
|
+
let params = buildParamArgumentSpecs(signature);
|
|
1580
|
+
const override = FUNCTION_OVERRIDES[config.typeId];
|
|
1581
|
+
if (override) {
|
|
1582
|
+
if (override.replaceInputs) {
|
|
1583
|
+
inputs = override.replaceInputs.map((input) => ({ ...input }));
|
|
1584
|
+
} else if (override.dropTrailingInputs) {
|
|
1585
|
+
const dropCount = Math.min(override.dropTrailingInputs, inputs.length);
|
|
1586
|
+
inputs = inputs.slice(0, inputs.length - dropCount);
|
|
1587
|
+
}
|
|
1588
|
+
if ("variadic" in override) {
|
|
1589
|
+
variadic = override.variadic ?? null;
|
|
1590
|
+
}
|
|
1591
|
+
if (override.params) {
|
|
1592
|
+
params = override.params.map((param) => ({ ...param }));
|
|
1593
|
+
}
|
|
1594
|
+
}
|
|
1595
|
+
const requiredParamCount = params.filter((param) => !param.optional).length;
|
|
1596
|
+
const minArgs = override?.minArgs !== void 0 ? override.minArgs : config.minArgs !== void 0 ? config.minArgs : derivedMin + requiredParamCount;
|
|
1597
|
+
const maxArgs = override?.maxArgs !== void 0 ? override.maxArgs : config.maxArgs !== void 0 ? config.maxArgs : derivedMax === null ? null : derivedMax + params.length;
|
|
1598
|
+
const definition = {
|
|
1599
|
+
nodeType: config.typeId,
|
|
1600
|
+
inputs,
|
|
1601
|
+
variadic,
|
|
1602
|
+
params,
|
|
1603
|
+
minArgs,
|
|
1604
|
+
maxArgs,
|
|
1605
|
+
resultValueType: inferExpressionValueType(
|
|
1606
|
+
signature.outputs?.[0]?.ty ?? null
|
|
1607
|
+
)
|
|
1608
|
+
};
|
|
1609
|
+
if (config.typeId === "if" || config.typeId === "case") {
|
|
1610
|
+
const adjustedInputs = definition.inputs.map(
|
|
1611
|
+
(input, index) => {
|
|
1612
|
+
if (config.typeId === "if" && index === 0) {
|
|
1613
|
+
return input;
|
|
1614
|
+
}
|
|
1615
|
+
return {
|
|
1616
|
+
...input,
|
|
1617
|
+
valueType: "any"
|
|
1618
|
+
};
|
|
1619
|
+
}
|
|
1620
|
+
);
|
|
1621
|
+
definition.inputs = adjustedInputs;
|
|
1622
|
+
if (definition.variadic) {
|
|
1623
|
+
definition.variadic = {
|
|
1624
|
+
...definition.variadic,
|
|
1625
|
+
valueType: "any"
|
|
1626
|
+
};
|
|
1627
|
+
}
|
|
1628
|
+
definition.resultValueType = "any";
|
|
1629
|
+
}
|
|
1630
|
+
const names = new Set(
|
|
1631
|
+
[config.typeId, ...config.names].map((name) => name.toLowerCase())
|
|
1632
|
+
);
|
|
1633
|
+
names.forEach((name) => {
|
|
1634
|
+
SCALAR_FUNCTIONS.set(name, definition);
|
|
1635
|
+
});
|
|
1636
|
+
const orderedNames = Array.from(names);
|
|
1637
|
+
const displayName = orderedNames[0] ?? config.typeId;
|
|
1638
|
+
SCALAR_FUNCTION_VOCABULARY.push({
|
|
1639
|
+
name: displayName,
|
|
1640
|
+
aliases: orderedNames.slice(1),
|
|
1641
|
+
nodeType: config.typeId,
|
|
1642
|
+
category: config.category ?? "math",
|
|
1643
|
+
description: config.description
|
|
1644
|
+
});
|
|
1645
|
+
}
|
|
1646
|
+
function buildParamArgumentSpecs(signature) {
|
|
1647
|
+
if (!signature || !Array.isArray(signature.params)) {
|
|
1648
|
+
return [];
|
|
1649
|
+
}
|
|
1650
|
+
const params = signature.params;
|
|
1651
|
+
return params.map((param) => ({
|
|
1652
|
+
id: param.id,
|
|
1653
|
+
label: param.label ?? param.id,
|
|
1654
|
+
doc: param.doc ?? void 0,
|
|
1655
|
+
optional: param.default_json !== void 0,
|
|
1656
|
+
valueType: inferExpressionValueType(param.ty),
|
|
1657
|
+
min: typeof param.min === "number" ? param.min : void 0,
|
|
1658
|
+
max: typeof param.max === "number" ? param.max : void 0
|
|
1659
|
+
}));
|
|
1660
|
+
}
|
|
1661
|
+
function inferExpressionValueType(ty) {
|
|
1662
|
+
if (!ty) {
|
|
1663
|
+
return "scalar";
|
|
1664
|
+
}
|
|
1665
|
+
const normalized = ty.toLowerCase();
|
|
1666
|
+
if (normalized === "any") {
|
|
1667
|
+
return "any";
|
|
1668
|
+
}
|
|
1669
|
+
if (normalized === "vector" || normalized === "vec2" || normalized === "vec3" || normalized === "vec4" || normalized === "quat" || normalized === "colorrgba" || normalized === "transform" || normalized === "array" || normalized === "list" || normalized === "record") {
|
|
1670
|
+
return "vector";
|
|
1671
|
+
}
|
|
1672
|
+
if (normalized === "bool" || normalized === "boolean") {
|
|
1673
|
+
return "boolean";
|
|
1674
|
+
}
|
|
1675
|
+
return "scalar";
|
|
1676
|
+
}
|
|
1677
|
+
|
|
1678
|
+
// src/expressionVariables.ts
|
|
1679
|
+
var DefaultExpressionVariableTable = class {
|
|
1680
|
+
constructor() {
|
|
1681
|
+
this.variables = /* @__PURE__ */ new Map();
|
|
1682
|
+
this.order = [];
|
|
1683
|
+
}
|
|
1684
|
+
registerSlotVariable(options) {
|
|
1685
|
+
this.upsert({
|
|
1686
|
+
name: options.name,
|
|
1687
|
+
kind: "slot",
|
|
1688
|
+
nodeId: options.nodeId,
|
|
1689
|
+
metadata: {
|
|
1690
|
+
slotId: options.slotId,
|
|
1691
|
+
slotAlias: options.slotAlias,
|
|
1692
|
+
inputId: options.inputId,
|
|
1693
|
+
targetId: options.targetId,
|
|
1694
|
+
animatableId: options.animatableId,
|
|
1695
|
+
component: options.component,
|
|
1696
|
+
valueType: options.valueType
|
|
1697
|
+
}
|
|
1698
|
+
});
|
|
1699
|
+
}
|
|
1700
|
+
registerReservedVariable(options) {
|
|
1701
|
+
this.upsert({
|
|
1702
|
+
name: options.name,
|
|
1703
|
+
kind: "reserved",
|
|
1704
|
+
nodeId: options.nodeId,
|
|
1705
|
+
description: options.description,
|
|
1706
|
+
metadata: {
|
|
1707
|
+
targetId: options.targetId,
|
|
1708
|
+
animatableId: options.animatableId,
|
|
1709
|
+
component: options.component
|
|
1710
|
+
}
|
|
1711
|
+
});
|
|
1712
|
+
}
|
|
1713
|
+
resolve(name) {
|
|
1714
|
+
return this.variables.get(name) ?? null;
|
|
1715
|
+
}
|
|
1716
|
+
resolveNodeId(name) {
|
|
1717
|
+
return this.variables.get(name)?.nodeId ?? null;
|
|
1718
|
+
}
|
|
1719
|
+
entries() {
|
|
1720
|
+
return this.order.map((name) => this.variables.get(name)).filter((entry) => Boolean(entry));
|
|
1721
|
+
}
|
|
1722
|
+
firstNodeId() {
|
|
1723
|
+
for (const name of this.order) {
|
|
1724
|
+
const nodeId = this.variables.get(name)?.nodeId;
|
|
1725
|
+
if (nodeId) {
|
|
1726
|
+
return nodeId;
|
|
1727
|
+
}
|
|
1728
|
+
}
|
|
1729
|
+
return null;
|
|
1730
|
+
}
|
|
1731
|
+
missing(names) {
|
|
1732
|
+
const missing = [];
|
|
1733
|
+
for (const name of names) {
|
|
1734
|
+
const entry = this.variables.get(name);
|
|
1735
|
+
if (!entry) {
|
|
1736
|
+
missing.push({ name, reason: "unknown" });
|
|
1737
|
+
continue;
|
|
1738
|
+
}
|
|
1739
|
+
if (!entry.nodeId) {
|
|
1740
|
+
missing.push({
|
|
1741
|
+
name,
|
|
1742
|
+
reason: "unresolved",
|
|
1743
|
+
entry
|
|
1744
|
+
});
|
|
1745
|
+
}
|
|
1746
|
+
}
|
|
1747
|
+
return missing;
|
|
1748
|
+
}
|
|
1749
|
+
upsert(entry) {
|
|
1750
|
+
if (!this.variables.has(entry.name)) {
|
|
1751
|
+
this.order.push(entry.name);
|
|
1752
|
+
}
|
|
1753
|
+
this.variables.set(entry.name, entry);
|
|
1754
|
+
}
|
|
1755
|
+
};
|
|
1756
|
+
function createExpressionVariableTable() {
|
|
1757
|
+
return new DefaultExpressionVariableTable();
|
|
1758
|
+
}
|
|
1759
|
+
|
|
1760
|
+
// src/expressionVocabulary.ts
|
|
1761
|
+
var RESERVED_EXPRESSION_VARIABLES = [
|
|
1762
|
+
{
|
|
1763
|
+
name: "self",
|
|
1764
|
+
description: "Output of the current binding.",
|
|
1765
|
+
scope: "binding",
|
|
1766
|
+
defaultValueType: "scalar",
|
|
1767
|
+
available: true
|
|
1768
|
+
},
|
|
1769
|
+
{
|
|
1770
|
+
name: "time",
|
|
1771
|
+
description: "Elapsed time in seconds since the rig started.",
|
|
1772
|
+
scope: "graph",
|
|
1773
|
+
defaultValueType: "scalar",
|
|
1774
|
+
available: true
|
|
1775
|
+
},
|
|
1776
|
+
{
|
|
1777
|
+
name: "deltaTime",
|
|
1778
|
+
description: "Seconds elapsed since the previous frame update.",
|
|
1779
|
+
scope: "graph",
|
|
1780
|
+
defaultValueType: "scalar",
|
|
1781
|
+
available: true
|
|
1782
|
+
},
|
|
1783
|
+
{
|
|
1784
|
+
name: "frame",
|
|
1785
|
+
description: "Current frame counter.",
|
|
1786
|
+
scope: "graph",
|
|
1787
|
+
defaultValueType: "scalar",
|
|
1788
|
+
available: true
|
|
1789
|
+
}
|
|
1790
|
+
];
|
|
1791
|
+
var EXPRESSION_FUNCTION_VOCABULARY = SCALAR_FUNCTION_VOCABULARY;
|
|
1792
|
+
|
|
1793
|
+
// src/ir/builder.ts
|
|
1794
|
+
var graphSequence = 0;
|
|
1795
|
+
function generateGraphId(faceId) {
|
|
1796
|
+
graphSequence += 1;
|
|
1797
|
+
return `ir_${faceId}_${graphSequence}`;
|
|
1798
|
+
}
|
|
1799
|
+
var DefaultIrGraphBuilder = class {
|
|
1800
|
+
constructor(options) {
|
|
1801
|
+
this.nodes = [];
|
|
1802
|
+
this.edges = [];
|
|
1803
|
+
this.constants = [];
|
|
1804
|
+
this.issues = [];
|
|
1805
|
+
this.faceId = options.faceId;
|
|
1806
|
+
this.summary = {
|
|
1807
|
+
faceId: options.faceId,
|
|
1808
|
+
inputs: [],
|
|
1809
|
+
outputs: [],
|
|
1810
|
+
bindings: []
|
|
1811
|
+
};
|
|
1812
|
+
this.metadata = {
|
|
1813
|
+
source: options.source ?? "ir-builder",
|
|
1814
|
+
registryVersion: options.registryVersion,
|
|
1815
|
+
generatedAt: options.generatedAt,
|
|
1816
|
+
annotations: options.annotations
|
|
1817
|
+
};
|
|
1818
|
+
}
|
|
1819
|
+
addNode(node) {
|
|
1820
|
+
this.nodes.push(node);
|
|
1821
|
+
return node;
|
|
1822
|
+
}
|
|
1823
|
+
addEdge(edge) {
|
|
1824
|
+
this.edges.push(edge);
|
|
1825
|
+
return edge;
|
|
1826
|
+
}
|
|
1827
|
+
addConstant(constant) {
|
|
1828
|
+
this.constants.push(constant);
|
|
1829
|
+
return constant;
|
|
1830
|
+
}
|
|
1831
|
+
addIssue(issue) {
|
|
1832
|
+
this.issues.push(issue);
|
|
1833
|
+
return issue;
|
|
1834
|
+
}
|
|
1835
|
+
setSummary(summary) {
|
|
1836
|
+
this.summary = summary;
|
|
1837
|
+
}
|
|
1838
|
+
updateMetadata(metadata) {
|
|
1839
|
+
this.metadata = {
|
|
1840
|
+
...this.metadata,
|
|
1841
|
+
...metadata
|
|
1842
|
+
};
|
|
1843
|
+
}
|
|
1844
|
+
build() {
|
|
1845
|
+
return {
|
|
1846
|
+
id: generateGraphId(this.faceId),
|
|
1847
|
+
faceId: this.faceId,
|
|
1848
|
+
nodes: [...this.nodes],
|
|
1849
|
+
edges: [...this.edges],
|
|
1850
|
+
constants: [...this.constants],
|
|
1851
|
+
issues: [...this.issues],
|
|
1852
|
+
summary: { ...this.summary },
|
|
1853
|
+
metadata: { ...this.metadata }
|
|
1854
|
+
};
|
|
1855
|
+
}
|
|
1856
|
+
};
|
|
1857
|
+
function createIrGraphBuilder(options) {
|
|
1858
|
+
return new DefaultIrGraphBuilder(options);
|
|
1859
|
+
}
|
|
1860
|
+
function createLegacyIrGraph(payload) {
|
|
1861
|
+
const builder = createIrGraphBuilder({
|
|
1862
|
+
faceId: payload.faceId,
|
|
1863
|
+
registryVersion: payload.registryVersion,
|
|
1864
|
+
source: payload.source ?? "legacy-graph-builder",
|
|
1865
|
+
annotations: payload.annotations,
|
|
1866
|
+
generatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
1867
|
+
});
|
|
1868
|
+
builder.setSummary(payload.summary);
|
|
1869
|
+
(payload.issues ?? []).forEach((issue) => builder.addIssue(issue));
|
|
1870
|
+
const graph = builder.build();
|
|
1871
|
+
return {
|
|
1872
|
+
...graph,
|
|
1873
|
+
legacy: { spec: payload.spec }
|
|
1874
|
+
};
|
|
1875
|
+
}
|
|
1876
|
+
function toIrBindingSummary(summaries) {
|
|
1877
|
+
return summaries.map((summary) => ({
|
|
1878
|
+
...summary,
|
|
1879
|
+
issues: summary.issues ? [...summary.issues] : void 0
|
|
1880
|
+
}));
|
|
1881
|
+
}
|
|
1882
|
+
|
|
1883
|
+
// src/ir/compiler.ts
|
|
1884
|
+
var import_utils2 = require("@vizij/utils");
|
|
1885
|
+
function compileIrGraph(graph, options = {}) {
|
|
1886
|
+
const preferLegacy = options.preferLegacySpec === true;
|
|
1887
|
+
const legacySpec = graph.legacy?.spec;
|
|
1888
|
+
if (preferLegacy && legacySpec) {
|
|
1889
|
+
return {
|
|
1890
|
+
spec: legacySpec,
|
|
1891
|
+
issues: [...graph.issues]
|
|
1892
|
+
};
|
|
1893
|
+
}
|
|
1894
|
+
const convertedNodes = graph.nodes.map(convertIrNodeToNodeSpec);
|
|
1895
|
+
const existingNodeIds = new Set(convertedNodes.map((node) => node.id));
|
|
1896
|
+
graph.constants.forEach((constant) => {
|
|
1897
|
+
if (existingNodeIds.has(constant.id)) {
|
|
1898
|
+
return;
|
|
1899
|
+
}
|
|
1900
|
+
convertedNodes.push(convertIrConstantToNodeSpec(constant));
|
|
1901
|
+
});
|
|
1902
|
+
const convertedEdges = graph.edges.map(convertIrEdgeToGraphEdge);
|
|
1903
|
+
const spec = {
|
|
1904
|
+
nodes: convertedNodes,
|
|
1905
|
+
edges: convertedEdges.length > 0 ? convertedEdges : void 0
|
|
1906
|
+
};
|
|
1907
|
+
inlineSingleUseConstants(spec);
|
|
1908
|
+
const metadata = extractGraphSpecMetadata(graph);
|
|
1909
|
+
if (metadata !== void 0) {
|
|
1910
|
+
spec.metadata = metadata;
|
|
1911
|
+
}
|
|
1912
|
+
return {
|
|
1913
|
+
spec,
|
|
1914
|
+
issues: [...graph.issues]
|
|
1915
|
+
};
|
|
1916
|
+
}
|
|
1917
|
+
function convertIrNodeToNodeSpec(node) {
|
|
1918
|
+
const spec = {
|
|
1919
|
+
id: node.id,
|
|
1920
|
+
type: node.type
|
|
1921
|
+
};
|
|
1922
|
+
if (node.params) {
|
|
1923
|
+
spec.params = cloneJsonLike(node.params);
|
|
1924
|
+
}
|
|
1925
|
+
if (node.inputDefaults) {
|
|
1926
|
+
spec.input_defaults = cloneJsonLike(node.inputDefaults);
|
|
1927
|
+
}
|
|
1928
|
+
if (node.metadata) {
|
|
1929
|
+
spec.metadata = cloneJsonLike(node.metadata);
|
|
1930
|
+
}
|
|
1931
|
+
return spec;
|
|
1932
|
+
}
|
|
1933
|
+
function convertIrConstantToNodeSpec(constant) {
|
|
1934
|
+
const spec = {
|
|
1935
|
+
id: constant.id,
|
|
1936
|
+
type: "constant",
|
|
1937
|
+
params: {
|
|
1938
|
+
value: constant.value
|
|
1939
|
+
}
|
|
1940
|
+
};
|
|
1941
|
+
if (constant.metadata) {
|
|
1942
|
+
spec.metadata = cloneJsonLike(constant.metadata);
|
|
1943
|
+
}
|
|
1944
|
+
return spec;
|
|
1945
|
+
}
|
|
1946
|
+
function convertIrEdgeToGraphEdge(edge) {
|
|
1947
|
+
return {
|
|
1948
|
+
from: {
|
|
1949
|
+
node_id: edge.from.nodeId,
|
|
1950
|
+
output: edge.from.portId
|
|
1951
|
+
},
|
|
1952
|
+
to: {
|
|
1953
|
+
node_id: edge.to.nodeId,
|
|
1954
|
+
input: edge.to.portId
|
|
1955
|
+
}
|
|
1956
|
+
};
|
|
1957
|
+
}
|
|
1958
|
+
function extractGraphSpecMetadata(graph) {
|
|
1959
|
+
const annotations = graph.metadata.annotations;
|
|
1960
|
+
if (!annotations?.graphSpecMetadata) {
|
|
1961
|
+
return void 0;
|
|
1962
|
+
}
|
|
1963
|
+
return cloneJsonLike(annotations.graphSpecMetadata);
|
|
1964
|
+
}
|
|
1965
|
+
function cloneJsonLike(value) {
|
|
1966
|
+
if (value === void 0 || value === null) {
|
|
1967
|
+
return value;
|
|
1968
|
+
}
|
|
1969
|
+
return (0, import_utils2.cloneDeepSafe)(value);
|
|
1970
|
+
}
|
|
1971
|
+
function inlineSingleUseConstants(spec) {
|
|
1972
|
+
const nodes = spec.nodes ?? [];
|
|
1973
|
+
const edges = spec.edges ? [...spec.edges] : [];
|
|
1974
|
+
const nodeById = new Map(nodes.map((node) => [node.id, node]));
|
|
1975
|
+
const constantUsage = /* @__PURE__ */ new Map();
|
|
1976
|
+
edges.forEach((edge) => {
|
|
1977
|
+
const source = nodeById.get(edge.from.node_id);
|
|
1978
|
+
if (source?.type === "constant") {
|
|
1979
|
+
constantUsage.set(source.id, (constantUsage.get(source.id) ?? 0) + 1);
|
|
1980
|
+
}
|
|
1981
|
+
});
|
|
1982
|
+
const updatedEdges = [];
|
|
1983
|
+
const constantsToRemove = /* @__PURE__ */ new Set();
|
|
1984
|
+
edges.forEach((edge) => {
|
|
1985
|
+
const source = nodeById.get(edge.from.node_id);
|
|
1986
|
+
if (source?.type === "constant" && constantUsage.get(source.id) === 1 && source.params && Object.prototype.hasOwnProperty.call(source.params, "value")) {
|
|
1987
|
+
const target = nodeById.get(edge.to.node_id);
|
|
1988
|
+
if (target) {
|
|
1989
|
+
const value = source.params.value;
|
|
1990
|
+
if (value !== void 0) {
|
|
1991
|
+
target.input_defaults = {
|
|
1992
|
+
...target.input_defaults ?? {},
|
|
1993
|
+
[edge.to.input ?? "in"]: value
|
|
1994
|
+
};
|
|
1995
|
+
nodeById.set(target.id, target);
|
|
1996
|
+
constantsToRemove.add(source.id);
|
|
1997
|
+
return;
|
|
1998
|
+
}
|
|
1999
|
+
}
|
|
2000
|
+
}
|
|
2001
|
+
updatedEdges.push(edge);
|
|
2002
|
+
});
|
|
2003
|
+
spec.nodes = nodes.filter((node) => !constantsToRemove.has(node.id));
|
|
2004
|
+
spec.edges = updatedEdges.length > 0 ? updatedEdges : void 0;
|
|
2005
|
+
}
|
|
2006
|
+
|
|
2007
|
+
// src/bindingMetadata.ts
|
|
2008
|
+
var import_utils3 = require("@vizij/utils");
|
|
2009
|
+
function cloneOperand(entry) {
|
|
2010
|
+
return (0, import_utils3.cloneDeepSafe)(entry);
|
|
2011
|
+
}
|
|
2012
|
+
function describeSlot(entry) {
|
|
2013
|
+
const metadata = entry.metadata;
|
|
2014
|
+
return {
|
|
2015
|
+
kind: "slot",
|
|
2016
|
+
ref: entry.name,
|
|
2017
|
+
alias: metadata?.slotAlias ?? entry.name,
|
|
2018
|
+
slotId: metadata?.slotId,
|
|
2019
|
+
inputId: metadata?.inputId ?? null,
|
|
2020
|
+
valueType: metadata?.valueType
|
|
2021
|
+
};
|
|
2022
|
+
}
|
|
2023
|
+
function describeReserved(entry) {
|
|
2024
|
+
return {
|
|
2025
|
+
kind: "reserved",
|
|
2026
|
+
ref: entry.name,
|
|
2027
|
+
description: entry.description
|
|
2028
|
+
};
|
|
2029
|
+
}
|
|
2030
|
+
function describeReference(node, variables) {
|
|
2031
|
+
const entry = variables.resolve(node.name);
|
|
2032
|
+
if (!entry) {
|
|
2033
|
+
return {
|
|
2034
|
+
kind: "unknown",
|
|
2035
|
+
ref: node.name
|
|
2036
|
+
};
|
|
2037
|
+
}
|
|
2038
|
+
if (entry.kind === "slot") {
|
|
2039
|
+
return describeSlot(entry);
|
|
1353
2040
|
}
|
|
1354
|
-
|
|
1355
|
-
return
|
|
2041
|
+
if (entry.kind === "reserved") {
|
|
2042
|
+
return describeReserved(entry);
|
|
1356
2043
|
}
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
2044
|
+
return {
|
|
2045
|
+
kind: "unknown",
|
|
2046
|
+
ref: entry.name
|
|
2047
|
+
};
|
|
1361
2048
|
}
|
|
1362
|
-
function
|
|
1363
|
-
if (!node) {
|
|
1364
|
-
return target;
|
|
1365
|
-
}
|
|
2049
|
+
function stringifyExpression(node) {
|
|
1366
2050
|
switch (node.type) {
|
|
2051
|
+
case "Literal":
|
|
2052
|
+
return Number.isFinite(node.value) ? `${node.value} ` : "0";
|
|
2053
|
+
case "VectorLiteral":
|
|
2054
|
+
return `vec(${node.values.join(", ")})`;
|
|
1367
2055
|
case "Reference":
|
|
1368
|
-
|
|
1369
|
-
break;
|
|
2056
|
+
return node.name;
|
|
1370
2057
|
case "Unary":
|
|
1371
|
-
|
|
1372
|
-
break;
|
|
2058
|
+
return `${node.operator}${stringifyExpression(node.operand)} `;
|
|
1373
2059
|
case "Binary":
|
|
1374
|
-
|
|
1375
|
-
collectExpressionReferences(node.right, target);
|
|
1376
|
-
break;
|
|
2060
|
+
return `${stringifyExpression(node.left)} ${node.operator} ${stringifyExpression(node.right)} `;
|
|
1377
2061
|
case "Function":
|
|
1378
|
-
node.args.
|
|
1379
|
-
break;
|
|
2062
|
+
return `${node.name} (${node.args.map(stringifyExpression).join(", ")})`;
|
|
1380
2063
|
default:
|
|
1381
|
-
|
|
2064
|
+
return "";
|
|
1382
2065
|
}
|
|
1383
|
-
return target;
|
|
1384
2066
|
}
|
|
1385
|
-
function
|
|
1386
|
-
visit(node);
|
|
2067
|
+
function describeOperand(node, variables) {
|
|
1387
2068
|
switch (node.type) {
|
|
2069
|
+
case "Literal":
|
|
2070
|
+
return {
|
|
2071
|
+
kind: "literal",
|
|
2072
|
+
literalValue: node.value
|
|
2073
|
+
};
|
|
2074
|
+
case "Reference":
|
|
2075
|
+
return describeReference(node, variables);
|
|
1388
2076
|
case "Unary":
|
|
1389
|
-
mapExpression(node.operand, visit);
|
|
1390
|
-
break;
|
|
1391
2077
|
case "Binary":
|
|
1392
|
-
mapExpression(node.left, visit);
|
|
1393
|
-
mapExpression(node.right, visit);
|
|
1394
|
-
break;
|
|
1395
2078
|
case "Function":
|
|
1396
|
-
|
|
1397
|
-
|
|
2079
|
+
case "VectorLiteral":
|
|
2080
|
+
return {
|
|
2081
|
+
kind: "expression",
|
|
2082
|
+
expression: stringifyExpression(node)
|
|
2083
|
+
};
|
|
1398
2084
|
default:
|
|
1399
|
-
|
|
2085
|
+
return { kind: "unknown" };
|
|
1400
2086
|
}
|
|
1401
2087
|
}
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
{
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
];
|
|
1438
|
-
var SCALAR_FUNCTIONS = /* @__PURE__ */ new Map();
|
|
1439
|
-
for (const config of FUNCTION_CONFIGS) {
|
|
1440
|
-
const signature = (0, import_metadata2.requireNodeSignature)(config.typeId);
|
|
1441
|
-
const signatureInputs = signature.inputs;
|
|
1442
|
-
const inputs = signatureInputs.map((input) => ({
|
|
1443
|
-
id: input.id,
|
|
1444
|
-
optional: Boolean(input.optional)
|
|
1445
|
-
}));
|
|
1446
|
-
const variadic = signature.variadic_inputs ? {
|
|
1447
|
-
id: signature.variadic_inputs.id,
|
|
1448
|
-
min: signature.variadic_inputs.min,
|
|
1449
|
-
max: signature.variadic_inputs.max ?? null
|
|
1450
|
-
} : null;
|
|
1451
|
-
const derivedMin = variadic ? variadic.min : inputs.filter((input) => !input.optional).length;
|
|
1452
|
-
const derivedMax = variadic ? variadic.max : inputs.length;
|
|
1453
|
-
const minArgs = config.minArgs ?? derivedMin;
|
|
1454
|
-
const maxArgs = config.maxArgs !== void 0 ? config.maxArgs : derivedMax ?? null;
|
|
1455
|
-
const definition = {
|
|
1456
|
-
nodeType: config.typeId,
|
|
1457
|
-
inputs,
|
|
1458
|
-
variadic,
|
|
1459
|
-
minArgs,
|
|
1460
|
-
maxArgs
|
|
2088
|
+
function describeCaseExpression(node, variables) {
|
|
2089
|
+
if (node.type !== "Function") {
|
|
2090
|
+
return null;
|
|
2091
|
+
}
|
|
2092
|
+
if (node.name.toLowerCase() !== "case") {
|
|
2093
|
+
return null;
|
|
2094
|
+
}
|
|
2095
|
+
if ((node.args?.length ?? 0) < 3) {
|
|
2096
|
+
return null;
|
|
2097
|
+
}
|
|
2098
|
+
const [selector, defaultBranch, ...branches] = node.args;
|
|
2099
|
+
return {
|
|
2100
|
+
kind: "case",
|
|
2101
|
+
selector: describeOperand(selector, variables),
|
|
2102
|
+
defaultBranch: describeOperand(defaultBranch, variables),
|
|
2103
|
+
branches: branches.map((branch) => describeOperand(branch, variables))
|
|
2104
|
+
};
|
|
2105
|
+
}
|
|
2106
|
+
function buildBindingMetadataFromExpression(node, variables) {
|
|
2107
|
+
if (!node) {
|
|
2108
|
+
return void 0;
|
|
2109
|
+
}
|
|
2110
|
+
const caseMetadata = describeCaseExpression(node, variables);
|
|
2111
|
+
if (!caseMetadata) {
|
|
2112
|
+
return void 0;
|
|
2113
|
+
}
|
|
2114
|
+
return {
|
|
2115
|
+
expression: {
|
|
2116
|
+
case: {
|
|
2117
|
+
kind: "case",
|
|
2118
|
+
selector: caseMetadata.selector ? cloneOperand(caseMetadata.selector) : void 0,
|
|
2119
|
+
defaultBranch: caseMetadata.defaultBranch ? cloneOperand(caseMetadata.defaultBranch) : void 0,
|
|
2120
|
+
branches: caseMetadata.branches.map(cloneOperand)
|
|
2121
|
+
}
|
|
2122
|
+
}
|
|
1461
2123
|
};
|
|
1462
|
-
const names = new Set(
|
|
1463
|
-
[config.typeId, ...config.names].map((name) => name.toLowerCase())
|
|
1464
|
-
);
|
|
1465
|
-
names.forEach((name) => {
|
|
1466
|
-
SCALAR_FUNCTIONS.set(name, definition);
|
|
1467
|
-
});
|
|
1468
2124
|
}
|
|
1469
2125
|
|
|
1470
2126
|
// src/graphBuilder.ts
|
|
@@ -1484,10 +2140,14 @@ function evaluateBinding({
|
|
|
1484
2140
|
nodes,
|
|
1485
2141
|
edges,
|
|
1486
2142
|
constants: /* @__PURE__ */ new Map(),
|
|
1487
|
-
counter: 0
|
|
2143
|
+
counter: 0,
|
|
2144
|
+
reservedNodes: /* @__PURE__ */ new Map(),
|
|
2145
|
+
nodeValueTypes: /* @__PURE__ */ new Map(),
|
|
2146
|
+
graphReservedNodes: context.graphReservedNodes,
|
|
2147
|
+
generateReservedNodeId: context.generateReservedNodeId
|
|
1488
2148
|
};
|
|
1489
2149
|
const targetValueType = target.valueType === "vector" ? "vector" : "scalar";
|
|
1490
|
-
const
|
|
2150
|
+
const variableTable = createExpressionVariableTable();
|
|
1491
2151
|
const slotSummaries = [];
|
|
1492
2152
|
const expressionIssues = [];
|
|
1493
2153
|
const rawExpression = typeof binding.expression === "string" ? binding.expression : "";
|
|
@@ -1500,10 +2160,15 @@ function evaluateBinding({
|
|
|
1500
2160
|
const slotId = slot.id && slot.id.length > 0 ? slot.id : alias;
|
|
1501
2161
|
const slotValueType = slot.valueType === "vector" ? "vector" : "scalar";
|
|
1502
2162
|
let slotOutputId;
|
|
1503
|
-
if (slot.inputId ===
|
|
2163
|
+
if (slot.inputId === import_utils5.SELF_BINDING_ID) {
|
|
1504
2164
|
if (selfNodeId) {
|
|
1505
2165
|
slotOutputId = selfNodeId;
|
|
1506
2166
|
hasActiveSlot = true;
|
|
2167
|
+
setNodeValueType(
|
|
2168
|
+
exprContext,
|
|
2169
|
+
slotOutputId,
|
|
2170
|
+
slotValueType === "vector" ? "vector" : "scalar"
|
|
2171
|
+
);
|
|
1507
2172
|
} else {
|
|
1508
2173
|
expressionIssues.push("Self reference unavailable for this input.");
|
|
1509
2174
|
slotOutputId = getConstantNodeId(exprContext, target.defaultValue);
|
|
@@ -1511,25 +2176,13 @@ function evaluateBinding({
|
|
|
1511
2176
|
} else if (slot.inputId) {
|
|
1512
2177
|
const inputNode = ensureInputNode(slot.inputId);
|
|
1513
2178
|
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;
|
|
2179
|
+
slotOutputId = inputNode.nodeId;
|
|
1532
2180
|
hasActiveSlot = true;
|
|
2181
|
+
setNodeValueType(
|
|
2182
|
+
exprContext,
|
|
2183
|
+
slotOutputId,
|
|
2184
|
+
slotValueType === "vector" ? "vector" : "scalar"
|
|
2185
|
+
);
|
|
1533
2186
|
} else {
|
|
1534
2187
|
expressionIssues.push(`Missing standard input "${slot.inputId}".`);
|
|
1535
2188
|
slotOutputId = getConstantNodeId(exprContext, 0);
|
|
@@ -1537,7 +2190,22 @@ function evaluateBinding({
|
|
|
1537
2190
|
} else {
|
|
1538
2191
|
slotOutputId = getConstantNodeId(exprContext, 0);
|
|
1539
2192
|
}
|
|
1540
|
-
|
|
2193
|
+
variableTable.registerSlotVariable({
|
|
2194
|
+
name: alias,
|
|
2195
|
+
nodeId: slotOutputId,
|
|
2196
|
+
slotId,
|
|
2197
|
+
slotAlias: alias,
|
|
2198
|
+
inputId: slot.inputId ?? null,
|
|
2199
|
+
targetId,
|
|
2200
|
+
animatableId,
|
|
2201
|
+
component,
|
|
2202
|
+
valueType: slotValueType
|
|
2203
|
+
});
|
|
2204
|
+
setNodeValueType(
|
|
2205
|
+
exprContext,
|
|
2206
|
+
slotOutputId,
|
|
2207
|
+
slotValueType === "vector" ? "vector" : "scalar"
|
|
2208
|
+
);
|
|
1541
2209
|
slotSummaries.push({
|
|
1542
2210
|
targetId,
|
|
1543
2211
|
animatableId,
|
|
@@ -1545,14 +2213,31 @@ function evaluateBinding({
|
|
|
1545
2213
|
slotId,
|
|
1546
2214
|
slotAlias: alias,
|
|
1547
2215
|
inputId: slot.inputId ?? null,
|
|
1548
|
-
remap: { ...slot.remap },
|
|
1549
2216
|
expression: trimmedExpression,
|
|
1550
|
-
valueType: slotValueType
|
|
2217
|
+
valueType: slotValueType,
|
|
2218
|
+
nodeId: slotOutputId,
|
|
2219
|
+
expressionNodeId: slotOutputId
|
|
1551
2220
|
});
|
|
1552
2221
|
});
|
|
1553
2222
|
if (slotSummaries.length === 0) {
|
|
1554
2223
|
const alias = PRIMARY_SLOT_ALIAS;
|
|
1555
|
-
|
|
2224
|
+
const constantId = getConstantNodeId(exprContext, 0);
|
|
2225
|
+
variableTable.registerSlotVariable({
|
|
2226
|
+
name: alias,
|
|
2227
|
+
nodeId: constantId,
|
|
2228
|
+
slotId: PRIMARY_SLOT_ID,
|
|
2229
|
+
slotAlias: alias,
|
|
2230
|
+
inputId: null,
|
|
2231
|
+
targetId,
|
|
2232
|
+
animatableId,
|
|
2233
|
+
component,
|
|
2234
|
+
valueType: targetValueType
|
|
2235
|
+
});
|
|
2236
|
+
setNodeValueType(
|
|
2237
|
+
exprContext,
|
|
2238
|
+
constantId,
|
|
2239
|
+
targetValueType === "vector" ? "vector" : "scalar"
|
|
2240
|
+
);
|
|
1556
2241
|
slotSummaries.push({
|
|
1557
2242
|
targetId,
|
|
1558
2243
|
animatableId,
|
|
@@ -1560,28 +2245,52 @@ function evaluateBinding({
|
|
|
1560
2245
|
slotId: PRIMARY_SLOT_ID,
|
|
1561
2246
|
slotAlias: alias,
|
|
1562
2247
|
inputId: null,
|
|
1563
|
-
remap: createDefaultRemap(target),
|
|
1564
2248
|
expression: trimmedExpression,
|
|
1565
|
-
valueType: targetValueType
|
|
2249
|
+
valueType: targetValueType,
|
|
2250
|
+
nodeId: constantId,
|
|
2251
|
+
expressionNodeId: constantId
|
|
1566
2252
|
});
|
|
1567
2253
|
}
|
|
2254
|
+
RESERVED_EXPRESSION_VARIABLES.forEach((reserved) => {
|
|
2255
|
+
if (reserved.available === false) {
|
|
2256
|
+
return;
|
|
2257
|
+
}
|
|
2258
|
+
let nodeId = null;
|
|
2259
|
+
if (reserved.name === "self") {
|
|
2260
|
+
nodeId = selfNodeId ?? null;
|
|
2261
|
+
} else {
|
|
2262
|
+
nodeId = ensureReservedVariableNode(reserved.name, exprContext);
|
|
2263
|
+
}
|
|
2264
|
+
variableTable.registerReservedVariable({
|
|
2265
|
+
name: reserved.name,
|
|
2266
|
+
nodeId,
|
|
2267
|
+
description: reserved.description,
|
|
2268
|
+
targetId: reserved.scope === "binding" ? targetId : void 0,
|
|
2269
|
+
animatableId: reserved.scope === "binding" ? animatableId : void 0,
|
|
2270
|
+
component: reserved.scope === "binding" ? component : void 0
|
|
2271
|
+
});
|
|
2272
|
+
});
|
|
1568
2273
|
const defaultAlias = slotSummaries[0]?.slotAlias ?? PRIMARY_SLOT_ALIAS;
|
|
1569
2274
|
const expressionText = trimmedExpression.length > 0 ? trimmedExpression : defaultAlias;
|
|
1570
2275
|
const parseResult = parseControlExpression(expressionText);
|
|
1571
2276
|
let expressionAst = null;
|
|
1572
2277
|
if (parseResult.node && parseResult.errors.length === 0) {
|
|
1573
|
-
const references =
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
missing.push(ref);
|
|
1578
|
-
}
|
|
1579
|
-
});
|
|
2278
|
+
const references = Array.from(
|
|
2279
|
+
collectExpressionReferences(parseResult.node)
|
|
2280
|
+
);
|
|
2281
|
+
const missing = variableTable.missing(references);
|
|
1580
2282
|
if (missing.length === 0) {
|
|
1581
2283
|
expressionAst = parseResult.node;
|
|
1582
2284
|
} else {
|
|
1583
|
-
|
|
1584
|
-
|
|
2285
|
+
validateLiteralParamArguments(parseResult.node, expressionIssues);
|
|
2286
|
+
missing.forEach((missingVar) => {
|
|
2287
|
+
if (missingVar.reason === "unresolved" && missingVar.entry?.kind === "reserved") {
|
|
2288
|
+
expressionIssues.push(
|
|
2289
|
+
`Reserved variable "${missingVar.name}" is unavailable for this binding.`
|
|
2290
|
+
);
|
|
2291
|
+
} else {
|
|
2292
|
+
expressionIssues.push(`Unknown control "${missingVar.name}".`);
|
|
2293
|
+
}
|
|
1585
2294
|
});
|
|
1586
2295
|
}
|
|
1587
2296
|
} else {
|
|
@@ -1589,22 +2298,30 @@ function evaluateBinding({
|
|
|
1589
2298
|
expressionIssues.push(error.message);
|
|
1590
2299
|
});
|
|
1591
2300
|
}
|
|
2301
|
+
const expressionMetadata = buildBindingMetadataFromExpression(
|
|
2302
|
+
expressionAst,
|
|
2303
|
+
variableTable
|
|
2304
|
+
);
|
|
1592
2305
|
let valueNodeId = null;
|
|
1593
2306
|
if (expressionAst) {
|
|
1594
2307
|
valueNodeId = materializeExpression(
|
|
1595
2308
|
expressionAst,
|
|
1596
2309
|
exprContext,
|
|
1597
|
-
|
|
2310
|
+
variableTable,
|
|
1598
2311
|
expressionIssues
|
|
1599
2312
|
);
|
|
1600
2313
|
}
|
|
1601
2314
|
if (!valueNodeId) {
|
|
1602
|
-
const
|
|
1603
|
-
valueNodeId =
|
|
2315
|
+
const fallbackNodeId = variableTable.resolveNodeId(defaultAlias) ?? variableTable.firstNodeId();
|
|
2316
|
+
valueNodeId = fallbackNodeId ?? getConstantNodeId(exprContext, 0);
|
|
1604
2317
|
}
|
|
1605
2318
|
const issuesCopy = expressionIssues.length ? [...new Set(expressionIssues)] : void 0;
|
|
1606
2319
|
slotSummaries.forEach((summary) => {
|
|
1607
2320
|
summary.expression = expressionText;
|
|
2321
|
+
summary.expressionNodeId = valueNodeId;
|
|
2322
|
+
if (expressionMetadata) {
|
|
2323
|
+
summary.metadata = expressionMetadata;
|
|
2324
|
+
}
|
|
1608
2325
|
if (issuesCopy && issuesCopy.length > 0) {
|
|
1609
2326
|
summary.issues = issuesCopy;
|
|
1610
2327
|
const issueSet = bindingIssues.get(summary.targetId) ?? /* @__PURE__ */ new Set();
|
|
@@ -1622,8 +2339,25 @@ function sanitizeNodeId(value) {
|
|
|
1622
2339
|
return value.replace(/[^a-zA-Z0-9_]/g, "_");
|
|
1623
2340
|
}
|
|
1624
2341
|
function buildRigInputPath(faceId, inputPath) {
|
|
1625
|
-
|
|
1626
|
-
|
|
2342
|
+
let trimmed = inputPath.startsWith("/") ? inputPath.slice(1) : inputPath;
|
|
2343
|
+
if (!trimmed) {
|
|
2344
|
+
return `rig/${faceId}`;
|
|
2345
|
+
}
|
|
2346
|
+
while (trimmed.startsWith("rig/")) {
|
|
2347
|
+
const segments = trimmed.split("/");
|
|
2348
|
+
if (segments.length >= 3) {
|
|
2349
|
+
const existingFaceId = segments[1];
|
|
2350
|
+
const remainder = segments.slice(2).join("/");
|
|
2351
|
+
if (existingFaceId === faceId) {
|
|
2352
|
+
return trimmed;
|
|
2353
|
+
}
|
|
2354
|
+
trimmed = remainder || "";
|
|
2355
|
+
} else {
|
|
2356
|
+
trimmed = segments.slice(1).join("/");
|
|
2357
|
+
}
|
|
2358
|
+
}
|
|
2359
|
+
const suffix = trimmed ? `/${trimmed}` : "";
|
|
2360
|
+
return `rig/${faceId}${suffix}`;
|
|
1627
2361
|
}
|
|
1628
2362
|
function getComponentOrder(animatable) {
|
|
1629
2363
|
switch (animatable.type) {
|
|
@@ -1679,6 +2413,34 @@ function extractComponentDefault(value, component) {
|
|
|
1679
2413
|
}
|
|
1680
2414
|
return 0;
|
|
1681
2415
|
}
|
|
2416
|
+
function setNodeValueType(context, nodeId, valueType) {
|
|
2417
|
+
context.nodeValueTypes.set(nodeId, valueType);
|
|
2418
|
+
}
|
|
2419
|
+
function getNodeValueType(context, nodeId) {
|
|
2420
|
+
return context.nodeValueTypes.get(nodeId) ?? "any";
|
|
2421
|
+
}
|
|
2422
|
+
function matchesValueType(actual, expected) {
|
|
2423
|
+
if (expected === "any" || actual === "any") {
|
|
2424
|
+
return true;
|
|
2425
|
+
}
|
|
2426
|
+
if (expected === "scalar") {
|
|
2427
|
+
return actual === "scalar" || actual === "boolean";
|
|
2428
|
+
}
|
|
2429
|
+
return actual === expected;
|
|
2430
|
+
}
|
|
2431
|
+
function ensureOperandValueType(context, operandId, expected, functionName, inputId, issues) {
|
|
2432
|
+
if (expected === "any") {
|
|
2433
|
+
return;
|
|
2434
|
+
}
|
|
2435
|
+
const actual = getNodeValueType(context, operandId);
|
|
2436
|
+
if (matchesValueType(actual, expected)) {
|
|
2437
|
+
return;
|
|
2438
|
+
}
|
|
2439
|
+
const expectation = expected === "vector" ? "a vector" : expected === "boolean" ? "a boolean" : "a scalar";
|
|
2440
|
+
issues.push(
|
|
2441
|
+
`Function "${functionName}" expects ${expectation} input for "${inputId}", but the expression produced ${actual}.`
|
|
2442
|
+
);
|
|
2443
|
+
}
|
|
1682
2444
|
function getConstantNodeId(context, value) {
|
|
1683
2445
|
const key = Number.isFinite(value) ? value.toString() : "NaN";
|
|
1684
2446
|
const existing = context.constants.get(key);
|
|
@@ -1694,6 +2456,30 @@ function getConstantNodeId(context, value) {
|
|
|
1694
2456
|
}
|
|
1695
2457
|
});
|
|
1696
2458
|
context.constants.set(key, nodeId);
|
|
2459
|
+
setNodeValueType(context, nodeId, "scalar");
|
|
2460
|
+
return nodeId;
|
|
2461
|
+
}
|
|
2462
|
+
function getVectorConstantNodeId(context, values) {
|
|
2463
|
+
const normalized = values.map(
|
|
2464
|
+
(value) => Number.isFinite(value) ? value : 0
|
|
2465
|
+
);
|
|
2466
|
+
const key = `vector:${normalized.join(",")}`;
|
|
2467
|
+
const existing = context.constants.get(key);
|
|
2468
|
+
if (existing) {
|
|
2469
|
+
return existing;
|
|
2470
|
+
}
|
|
2471
|
+
const nodeId = `const_${context.componentSafeId}_${context.constants.size + 1}`;
|
|
2472
|
+
context.nodes.push({
|
|
2473
|
+
id: nodeId,
|
|
2474
|
+
type: "constant",
|
|
2475
|
+
params: {
|
|
2476
|
+
value: {
|
|
2477
|
+
vector: normalized
|
|
2478
|
+
}
|
|
2479
|
+
}
|
|
2480
|
+
});
|
|
2481
|
+
context.constants.set(key, nodeId);
|
|
2482
|
+
setNodeValueType(context, nodeId, "vector");
|
|
1697
2483
|
return nodeId;
|
|
1698
2484
|
}
|
|
1699
2485
|
function createBinaryOperationNode(context, operator, leftId, rightId) {
|
|
@@ -1702,15 +2488,16 @@ function createBinaryOperationNode(context, operator, leftId, rightId) {
|
|
|
1702
2488
|
id: nodeId,
|
|
1703
2489
|
type: operator
|
|
1704
2490
|
});
|
|
2491
|
+
setNodeValueType(context, nodeId, "scalar");
|
|
1705
2492
|
const leftInput = operator === "subtract" || operator === "divide" ? "lhs" : "operand_1";
|
|
1706
2493
|
const rightInput = operator === "subtract" || operator === "divide" ? "rhs" : "operand_2";
|
|
1707
2494
|
context.edges.push({
|
|
1708
|
-
from: {
|
|
1709
|
-
to: {
|
|
2495
|
+
from: { nodeId: leftId },
|
|
2496
|
+
to: { nodeId, portId: leftInput }
|
|
1710
2497
|
});
|
|
1711
2498
|
context.edges.push({
|
|
1712
|
-
from: {
|
|
1713
|
-
to: {
|
|
2499
|
+
from: { nodeId: rightId },
|
|
2500
|
+
to: { nodeId, portId: rightInput }
|
|
1714
2501
|
});
|
|
1715
2502
|
return nodeId;
|
|
1716
2503
|
}
|
|
@@ -1726,95 +2513,339 @@ function createVariadicOperationNode(context, operator, operandIds) {
|
|
|
1726
2513
|
id: nodeId,
|
|
1727
2514
|
type: operator
|
|
1728
2515
|
});
|
|
2516
|
+
setNodeValueType(context, nodeId, "scalar");
|
|
1729
2517
|
operandIds.forEach((operandId, index) => {
|
|
1730
2518
|
context.edges.push({
|
|
1731
|
-
from: {
|
|
1732
|
-
to: {
|
|
2519
|
+
from: { nodeId: operandId },
|
|
2520
|
+
to: { nodeId, portId: `operand_${index + 1}` }
|
|
1733
2521
|
});
|
|
1734
2522
|
});
|
|
1735
2523
|
return nodeId;
|
|
1736
2524
|
}
|
|
1737
|
-
function createNamedOperationNode(context, operator, inputNames, operandIds) {
|
|
2525
|
+
function createNamedOperationNode(context, operator, inputNames, operandIds, resultType = "scalar", params) {
|
|
1738
2526
|
const nodeId = `expr_${context.componentSafeId}_${context.counter++}`;
|
|
1739
|
-
|
|
2527
|
+
const node = {
|
|
1740
2528
|
id: nodeId,
|
|
1741
2529
|
type: operator
|
|
1742
|
-
}
|
|
2530
|
+
};
|
|
2531
|
+
if (params && Object.keys(params).length > 0) {
|
|
2532
|
+
node.params = params;
|
|
2533
|
+
}
|
|
2534
|
+
context.nodes.push(node);
|
|
2535
|
+
setNodeValueType(context, nodeId, resultType);
|
|
1743
2536
|
inputNames.forEach((inputName, index) => {
|
|
1744
2537
|
const operandId = operandIds[index];
|
|
1745
2538
|
context.edges.push({
|
|
1746
|
-
from: {
|
|
1747
|
-
to: {
|
|
2539
|
+
from: { nodeId: operandId },
|
|
2540
|
+
to: { nodeId, portId: inputName }
|
|
2541
|
+
});
|
|
2542
|
+
});
|
|
2543
|
+
return nodeId;
|
|
2544
|
+
}
|
|
2545
|
+
function ensureReservedVariableNode(name, context) {
|
|
2546
|
+
const existing = context.reservedNodes.get(name);
|
|
2547
|
+
if (existing) {
|
|
2548
|
+
return existing;
|
|
2549
|
+
}
|
|
2550
|
+
if (name === "time" || name === "deltaTime" || name === "frame") {
|
|
2551
|
+
const nodeId = ensureGraphTimeNode(context);
|
|
2552
|
+
context.reservedNodes.set(name, nodeId);
|
|
2553
|
+
return nodeId;
|
|
2554
|
+
}
|
|
2555
|
+
return null;
|
|
2556
|
+
}
|
|
2557
|
+
function ensureGraphTimeNode(context) {
|
|
2558
|
+
const existing = context.graphReservedNodes.get("time");
|
|
2559
|
+
if (existing) {
|
|
2560
|
+
return existing;
|
|
2561
|
+
}
|
|
2562
|
+
const nodeId = context.generateReservedNodeId("time");
|
|
2563
|
+
context.nodes.push({
|
|
2564
|
+
id: nodeId,
|
|
2565
|
+
type: "time",
|
|
2566
|
+
metadata: {
|
|
2567
|
+
reservedVariable: "time"
|
|
2568
|
+
}
|
|
2569
|
+
});
|
|
2570
|
+
setNodeValueType(context, nodeId, "scalar");
|
|
2571
|
+
context.graphReservedNodes.set("time", nodeId);
|
|
2572
|
+
return nodeId;
|
|
2573
|
+
}
|
|
2574
|
+
function emitScalarFunctionNode(definition, operands, argNodes, totalArgCount, context, variables, issues, paramArgOverride) {
|
|
2575
|
+
if (definition.nodeType === "case") {
|
|
2576
|
+
return emitCaseFunctionNode(
|
|
2577
|
+
definition,
|
|
2578
|
+
operands,
|
|
2579
|
+
argNodes,
|
|
2580
|
+
context,
|
|
2581
|
+
variables,
|
|
2582
|
+
issues
|
|
2583
|
+
);
|
|
2584
|
+
}
|
|
2585
|
+
const orderedOperands = operands.slice(0, definition.inputs.length);
|
|
2586
|
+
definition.inputs.forEach((input, index) => {
|
|
2587
|
+
const operandId = orderedOperands[index];
|
|
2588
|
+
if (!operandId) {
|
|
2589
|
+
return;
|
|
2590
|
+
}
|
|
2591
|
+
ensureOperandValueType(
|
|
2592
|
+
context,
|
|
2593
|
+
operandId,
|
|
2594
|
+
input.valueType,
|
|
2595
|
+
definition.nodeType,
|
|
2596
|
+
input.id,
|
|
2597
|
+
issues
|
|
2598
|
+
);
|
|
2599
|
+
});
|
|
2600
|
+
const availableAfterInputs = Math.max(
|
|
2601
|
+
0,
|
|
2602
|
+
totalArgCount - definition.inputs.length
|
|
2603
|
+
);
|
|
2604
|
+
const paramArgCount = definition.params.length > 0 ? Math.min(definition.params.length, availableAfterInputs) : 0;
|
|
2605
|
+
const variadicArgCount = definition.variadic ? Math.max(0, availableAfterInputs - paramArgCount) : 0;
|
|
2606
|
+
const variadicOperands = definition.variadic ? operands.slice(
|
|
2607
|
+
definition.inputs.length,
|
|
2608
|
+
definition.inputs.length + variadicArgCount
|
|
2609
|
+
) : [];
|
|
2610
|
+
if (definition.variadic) {
|
|
2611
|
+
variadicOperands.forEach((operandId, _variadicIndex) => {
|
|
2612
|
+
ensureOperandValueType(
|
|
2613
|
+
context,
|
|
2614
|
+
operandId,
|
|
2615
|
+
definition.variadic.valueType,
|
|
2616
|
+
definition.nodeType,
|
|
2617
|
+
definition.variadic.id,
|
|
2618
|
+
issues
|
|
2619
|
+
);
|
|
2620
|
+
});
|
|
2621
|
+
}
|
|
2622
|
+
const paramArgStart = definition.inputs.length + variadicArgCount;
|
|
2623
|
+
const paramArgNodes = paramArgCount > 0 ? paramArgOverride ?? argNodes.slice(paramArgStart, paramArgStart + paramArgCount) : [];
|
|
2624
|
+
const isSlewDebugEnabled = typeof process !== "undefined" && process?.env && process.env.DEBUG_SLEW === "1";
|
|
2625
|
+
if (isSlewDebugEnabled && definition.nodeType === "slew") {
|
|
2626
|
+
console.log("slew-debug", {
|
|
2627
|
+
totalArgs: totalArgCount,
|
|
2628
|
+
inputs: definition.inputs.length,
|
|
2629
|
+
paramCount: definition.params.length,
|
|
2630
|
+
paramArgCount,
|
|
2631
|
+
paramArgNodesTypes: paramArgNodes.map((node) => node?.type ?? null)
|
|
2632
|
+
});
|
|
2633
|
+
}
|
|
2634
|
+
const nodeParams = buildParamAssignments(definition, paramArgNodes, issues);
|
|
2635
|
+
if (definition.variadic && definition.inputs.length === 0) {
|
|
2636
|
+
const nodeId2 = `expr_${context.componentSafeId}_${context.counter++}`;
|
|
2637
|
+
const node = {
|
|
2638
|
+
id: nodeId2,
|
|
2639
|
+
type: definition.nodeType
|
|
2640
|
+
};
|
|
2641
|
+
if (nodeParams) {
|
|
2642
|
+
node.params = nodeParams;
|
|
2643
|
+
}
|
|
2644
|
+
context.nodes.push(node);
|
|
2645
|
+
variadicOperands.forEach((operandId, index) => {
|
|
2646
|
+
context.edges.push({
|
|
2647
|
+
from: { nodeId: operandId },
|
|
2648
|
+
to: {
|
|
2649
|
+
nodeId: nodeId2,
|
|
2650
|
+
portId: `${definition.variadic.id}_${index + 1}`
|
|
2651
|
+
}
|
|
2652
|
+
});
|
|
2653
|
+
});
|
|
2654
|
+
setNodeValueType(context, nodeId2, definition.resultValueType);
|
|
2655
|
+
return nodeId2;
|
|
2656
|
+
}
|
|
2657
|
+
const providedNames = [];
|
|
2658
|
+
const providedOperands = [];
|
|
2659
|
+
definition.inputs.forEach((input, index) => {
|
|
2660
|
+
const operandId = orderedOperands[index];
|
|
2661
|
+
if (!operandId) {
|
|
2662
|
+
return;
|
|
2663
|
+
}
|
|
2664
|
+
providedNames.push(input.id);
|
|
2665
|
+
providedOperands.push(operandId);
|
|
2666
|
+
});
|
|
2667
|
+
const nodeId = createNamedOperationNode(
|
|
2668
|
+
context,
|
|
2669
|
+
definition.nodeType,
|
|
2670
|
+
providedNames,
|
|
2671
|
+
providedOperands,
|
|
2672
|
+
definition.resultValueType,
|
|
2673
|
+
nodeParams ?? void 0
|
|
2674
|
+
);
|
|
2675
|
+
if (definition.variadic) {
|
|
2676
|
+
variadicOperands.forEach((operandId, index) => {
|
|
2677
|
+
context.edges.push({
|
|
2678
|
+
from: { nodeId: operandId },
|
|
2679
|
+
to: {
|
|
2680
|
+
nodeId,
|
|
2681
|
+
portId: `${definition.variadic.id}_${index + 1}`
|
|
2682
|
+
}
|
|
2683
|
+
});
|
|
2684
|
+
});
|
|
2685
|
+
}
|
|
2686
|
+
return nodeId;
|
|
2687
|
+
}
|
|
2688
|
+
function emitCaseFunctionNode(definition, operands, argNodes, context, variables, issues) {
|
|
2689
|
+
const selectorId = operands[0];
|
|
2690
|
+
const defaultId = operands[1];
|
|
2691
|
+
const branchOperands = operands.slice(2);
|
|
2692
|
+
const branchArgs = argNodes.slice(2);
|
|
2693
|
+
if (!selectorId || branchOperands.length === 0) {
|
|
2694
|
+
issues.push(
|
|
2695
|
+
'Function "case" requires a selector, default, and at least one branch.'
|
|
2696
|
+
);
|
|
2697
|
+
return getConstantNodeId(context, 0);
|
|
2698
|
+
}
|
|
2699
|
+
const nodeId = `expr_${context.componentSafeId}_${context.counter++}`;
|
|
2700
|
+
const caseLabels = branchOperands.map((_, index) => {
|
|
2701
|
+
const extracted = extractCaseLabel(branchArgs[index], variables);
|
|
2702
|
+
if (extracted) {
|
|
2703
|
+
return extracted;
|
|
2704
|
+
}
|
|
2705
|
+
const fallback = `case_${index + 1}`;
|
|
2706
|
+
issues.push(
|
|
2707
|
+
`Case branch ${index + 1} is missing an alias; generated fallback label ${fallback}.`
|
|
2708
|
+
);
|
|
2709
|
+
return fallback;
|
|
2710
|
+
});
|
|
2711
|
+
context.nodes.push({
|
|
2712
|
+
id: nodeId,
|
|
2713
|
+
type: definition.nodeType,
|
|
2714
|
+
params: caseLabels.length > 0 ? { case_labels: caseLabels } : void 0
|
|
2715
|
+
});
|
|
2716
|
+
ensureOperandValueType(
|
|
2717
|
+
context,
|
|
2718
|
+
selectorId,
|
|
2719
|
+
definition.inputs[0]?.valueType ?? "any",
|
|
2720
|
+
definition.nodeType,
|
|
2721
|
+
definition.inputs[0]?.id ?? "selector",
|
|
2722
|
+
issues
|
|
2723
|
+
);
|
|
2724
|
+
context.edges.push({
|
|
2725
|
+
from: { nodeId: selectorId },
|
|
2726
|
+
to: { nodeId, portId: definition.inputs[0]?.id ?? "selector" }
|
|
2727
|
+
});
|
|
2728
|
+
if (defaultId) {
|
|
2729
|
+
ensureOperandValueType(
|
|
2730
|
+
context,
|
|
2731
|
+
defaultId,
|
|
2732
|
+
definition.inputs[1]?.valueType ?? "any",
|
|
2733
|
+
definition.nodeType,
|
|
2734
|
+
"default",
|
|
2735
|
+
issues
|
|
2736
|
+
);
|
|
2737
|
+
context.edges.push({
|
|
2738
|
+
from: { nodeId: defaultId },
|
|
2739
|
+
to: { nodeId, portId: "default" }
|
|
2740
|
+
});
|
|
2741
|
+
}
|
|
2742
|
+
branchOperands.forEach((operandId, index) => {
|
|
2743
|
+
const portId = `${definition.variadic?.id ?? "operand"}_${index + 1}`;
|
|
2744
|
+
ensureOperandValueType(
|
|
2745
|
+
context,
|
|
2746
|
+
operandId,
|
|
2747
|
+
definition.variadic?.valueType ?? "any",
|
|
2748
|
+
definition.nodeType,
|
|
2749
|
+
portId,
|
|
2750
|
+
issues
|
|
2751
|
+
);
|
|
2752
|
+
context.edges.push({
|
|
2753
|
+
from: { nodeId: operandId },
|
|
2754
|
+
to: { nodeId, portId }
|
|
1748
2755
|
});
|
|
1749
2756
|
});
|
|
2757
|
+
setNodeValueType(context, nodeId, "any");
|
|
1750
2758
|
return nodeId;
|
|
1751
2759
|
}
|
|
1752
|
-
function
|
|
1753
|
-
if (definition.
|
|
1754
|
-
|
|
1755
|
-
context.nodes.push({
|
|
1756
|
-
id: nodeId,
|
|
1757
|
-
type: definition.nodeType
|
|
1758
|
-
});
|
|
1759
|
-
operands.forEach((operandId, index) => {
|
|
1760
|
-
context.edges.push({
|
|
1761
|
-
from: { node_id: operandId },
|
|
1762
|
-
to: {
|
|
1763
|
-
node_id: nodeId,
|
|
1764
|
-
input: `${definition.variadic.id}_${index + 1}`
|
|
1765
|
-
}
|
|
1766
|
-
});
|
|
1767
|
-
});
|
|
1768
|
-
return nodeId;
|
|
2760
|
+
function buildParamAssignments(definition, paramArgNodes, issues) {
|
|
2761
|
+
if (!definition.params.length || paramArgNodes.length === 0) {
|
|
2762
|
+
return null;
|
|
1769
2763
|
}
|
|
1770
|
-
const
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
if (!operandId) {
|
|
2764
|
+
const assignments = {};
|
|
2765
|
+
paramArgNodes.forEach((node, index) => {
|
|
2766
|
+
const spec = definition.params[index];
|
|
2767
|
+
if (!spec) {
|
|
1775
2768
|
return;
|
|
1776
2769
|
}
|
|
1777
|
-
|
|
1778
|
-
|
|
2770
|
+
const literal = extractParamLiteral(
|
|
2771
|
+
node,
|
|
2772
|
+
spec,
|
|
2773
|
+
definition.nodeType,
|
|
2774
|
+
issues
|
|
2775
|
+
);
|
|
2776
|
+
if (literal !== null) {
|
|
2777
|
+
assignments[spec.id] = literal;
|
|
2778
|
+
}
|
|
1779
2779
|
});
|
|
1780
|
-
return
|
|
1781
|
-
context,
|
|
1782
|
-
definition.nodeType,
|
|
1783
|
-
providedNames,
|
|
1784
|
-
providedOperands
|
|
1785
|
-
);
|
|
2780
|
+
return Object.keys(assignments).length > 0 ? assignments : null;
|
|
1786
2781
|
}
|
|
1787
|
-
function
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
2782
|
+
function extractParamLiteral(node, spec, functionName, issues) {
|
|
2783
|
+
if (spec.valueType === "vector") {
|
|
2784
|
+
if (node.type !== "VectorLiteral") {
|
|
2785
|
+
issues.push(
|
|
2786
|
+
`Function "${functionName}" requires a literal vector for "${spec.id}".`
|
|
2787
|
+
);
|
|
2788
|
+
return null;
|
|
1792
2789
|
}
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
return;
|
|
2790
|
+
if (!Array.isArray(node.values) || node.values.length === 0) {
|
|
2791
|
+
issues.push(
|
|
2792
|
+
`Function "${functionName}" requires at least one value for "${spec.id}".`
|
|
2793
|
+
);
|
|
2794
|
+
return null;
|
|
1798
2795
|
}
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
2796
|
+
return node.values.map((value) => clampScalarParamValue(value, spec));
|
|
2797
|
+
}
|
|
2798
|
+
if (node.type !== "Literal") {
|
|
2799
|
+
issues.push(
|
|
2800
|
+
`Function "${functionName}" requires a literal ${describeParamExpectation(spec.valueType)} for "${spec.id}".`
|
|
2801
|
+
);
|
|
2802
|
+
return null;
|
|
2803
|
+
}
|
|
2804
|
+
const numeric = Number(node.value);
|
|
2805
|
+
if (!Number.isFinite(numeric)) {
|
|
2806
|
+
issues.push(
|
|
2807
|
+
`Function "${functionName}" requires a finite ${describeParamExpectation(spec.valueType)} for "${spec.id}".`
|
|
2808
|
+
);
|
|
2809
|
+
return null;
|
|
2810
|
+
}
|
|
2811
|
+
const clamped = clampScalarParamValue(numeric, spec);
|
|
2812
|
+
if (spec.valueType === "boolean") {
|
|
2813
|
+
return clamped !== 0;
|
|
2814
|
+
}
|
|
2815
|
+
return clamped;
|
|
2816
|
+
}
|
|
2817
|
+
function clampScalarParamValue(value, spec) {
|
|
2818
|
+
let next = Number.isFinite(value) ? value : 0;
|
|
2819
|
+
if (typeof spec.min === "number" && next < spec.min) {
|
|
2820
|
+
next = spec.min;
|
|
2821
|
+
}
|
|
2822
|
+
if (typeof spec.max === "number" && next > spec.max) {
|
|
2823
|
+
next = spec.max;
|
|
2824
|
+
}
|
|
2825
|
+
return next;
|
|
2826
|
+
}
|
|
2827
|
+
function describeParamExpectation(valueType) {
|
|
2828
|
+
switch (valueType) {
|
|
2829
|
+
case "vector":
|
|
2830
|
+
return "vector";
|
|
2831
|
+
case "boolean":
|
|
2832
|
+
return "boolean";
|
|
2833
|
+
default:
|
|
2834
|
+
return "scalar";
|
|
2835
|
+
}
|
|
2836
|
+
}
|
|
2837
|
+
function extractCaseLabel(node, variables) {
|
|
2838
|
+
if (!node || node.type !== "Reference") {
|
|
2839
|
+
return null;
|
|
2840
|
+
}
|
|
2841
|
+
const entry = variables.resolve(node.name);
|
|
2842
|
+
if (entry && entry.metadata && "slotAlias" in entry.metadata) {
|
|
2843
|
+
const alias = entry.metadata.slotAlias?.trim();
|
|
2844
|
+
if (alias && alias.length > 0) {
|
|
2845
|
+
return alias;
|
|
2846
|
+
}
|
|
2847
|
+
}
|
|
2848
|
+
return node.name;
|
|
1818
2849
|
}
|
|
1819
2850
|
function collectOperands(node, operator, target) {
|
|
1820
2851
|
if (node.type === "Binary" && node.operator === operator) {
|
|
@@ -1824,6 +2855,42 @@ function collectOperands(node, operator, target) {
|
|
|
1824
2855
|
}
|
|
1825
2856
|
target.push(node);
|
|
1826
2857
|
}
|
|
2858
|
+
function validateLiteralParamArguments(node, issues) {
|
|
2859
|
+
if (node.type === "Function") {
|
|
2860
|
+
const definition = SCALAR_FUNCTIONS.get(node.name.toLowerCase());
|
|
2861
|
+
if (definition && definition.params.length > 0) {
|
|
2862
|
+
const totalArgCount = node.args.length;
|
|
2863
|
+
const availableAfterInputs = Math.max(
|
|
2864
|
+
0,
|
|
2865
|
+
totalArgCount - definition.inputs.length
|
|
2866
|
+
);
|
|
2867
|
+
const paramArgCount = Math.min(
|
|
2868
|
+
definition.params.length,
|
|
2869
|
+
availableAfterInputs
|
|
2870
|
+
);
|
|
2871
|
+
const variadicArgCount = definition.variadic ? Math.max(0, availableAfterInputs - paramArgCount) : 0;
|
|
2872
|
+
const paramArgStart = definition.inputs.length + variadicArgCount;
|
|
2873
|
+
for (let index = 0; index < paramArgCount; index++) {
|
|
2874
|
+
const spec = definition.params[index];
|
|
2875
|
+
const paramNode = node.args[paramArgStart + index];
|
|
2876
|
+
if (!spec || !paramNode) {
|
|
2877
|
+
continue;
|
|
2878
|
+
}
|
|
2879
|
+
extractParamLiteral(paramNode, spec, node.name, issues);
|
|
2880
|
+
}
|
|
2881
|
+
}
|
|
2882
|
+
node.args.forEach((child) => validateLiteralParamArguments(child, issues));
|
|
2883
|
+
return;
|
|
2884
|
+
}
|
|
2885
|
+
if (node.type === "Unary") {
|
|
2886
|
+
validateLiteralParamArguments(node.operand, issues);
|
|
2887
|
+
return;
|
|
2888
|
+
}
|
|
2889
|
+
if (node.type === "Binary") {
|
|
2890
|
+
validateLiteralParamArguments(node.left, issues);
|
|
2891
|
+
validateLiteralParamArguments(node.right, issues);
|
|
2892
|
+
}
|
|
2893
|
+
}
|
|
1827
2894
|
var BINARY_FUNCTION_OPERATOR_MAP = {
|
|
1828
2895
|
">": "greaterthan",
|
|
1829
2896
|
"<": "lessthan",
|
|
@@ -1832,24 +2899,28 @@ var BINARY_FUNCTION_OPERATOR_MAP = {
|
|
|
1832
2899
|
"&&": "and",
|
|
1833
2900
|
"||": "or"
|
|
1834
2901
|
};
|
|
1835
|
-
function materializeExpression(node, context,
|
|
2902
|
+
function materializeExpression(node, context, variables, issues) {
|
|
1836
2903
|
switch (node.type) {
|
|
1837
2904
|
case "Literal": {
|
|
1838
2905
|
return getConstantNodeId(context, node.value);
|
|
1839
2906
|
}
|
|
2907
|
+
case "VectorLiteral": {
|
|
2908
|
+
return getVectorConstantNodeId(context, node.values);
|
|
2909
|
+
}
|
|
1840
2910
|
case "Reference": {
|
|
1841
|
-
const
|
|
1842
|
-
if (!
|
|
2911
|
+
const entry = variables.resolve(node.name);
|
|
2912
|
+
if (!entry) {
|
|
1843
2913
|
issues.push(`Unknown control "${node.name}".`);
|
|
1844
2914
|
return getConstantNodeId(context, 0);
|
|
1845
2915
|
}
|
|
1846
|
-
|
|
2916
|
+
const mappedId = entry.nodeId ?? getConstantNodeId(context, 0);
|
|
2917
|
+
return mappedId;
|
|
1847
2918
|
}
|
|
1848
2919
|
case "Unary": {
|
|
1849
2920
|
const operandId = materializeExpression(
|
|
1850
2921
|
node.operand,
|
|
1851
2922
|
context,
|
|
1852
|
-
|
|
2923
|
+
variables,
|
|
1853
2924
|
issues
|
|
1854
2925
|
);
|
|
1855
2926
|
switch (node.operator) {
|
|
@@ -1868,7 +2939,15 @@ function materializeExpression(node, context, aliasNodes, issues) {
|
|
|
1868
2939
|
issues.push('Function "not" is not available in metadata.');
|
|
1869
2940
|
return getConstantNodeId(context, 0);
|
|
1870
2941
|
}
|
|
1871
|
-
return emitScalarFunctionNode(
|
|
2942
|
+
return emitScalarFunctionNode(
|
|
2943
|
+
definition,
|
|
2944
|
+
[operandId],
|
|
2945
|
+
[node.operand],
|
|
2946
|
+
1,
|
|
2947
|
+
context,
|
|
2948
|
+
variables,
|
|
2949
|
+
issues
|
|
2950
|
+
);
|
|
1872
2951
|
}
|
|
1873
2952
|
default:
|
|
1874
2953
|
issues.push("Unsupported unary operator.");
|
|
@@ -1881,7 +2960,7 @@ function materializeExpression(node, context, aliasNodes, issues) {
|
|
|
1881
2960
|
const children = [];
|
|
1882
2961
|
collectOperands(node, "+", children);
|
|
1883
2962
|
const operandIds = children.map(
|
|
1884
|
-
(child) => materializeExpression(child, context,
|
|
2963
|
+
(child) => materializeExpression(child, context, variables, issues)
|
|
1885
2964
|
);
|
|
1886
2965
|
return createVariadicOperationNode(context, "add", operandIds);
|
|
1887
2966
|
}
|
|
@@ -1889,20 +2968,20 @@ function materializeExpression(node, context, aliasNodes, issues) {
|
|
|
1889
2968
|
const children = [];
|
|
1890
2969
|
collectOperands(node, "*", children);
|
|
1891
2970
|
const operandIds = children.map(
|
|
1892
|
-
(child) => materializeExpression(child, context,
|
|
2971
|
+
(child) => materializeExpression(child, context, variables, issues)
|
|
1893
2972
|
);
|
|
1894
2973
|
return createVariadicOperationNode(context, "multiply", operandIds);
|
|
1895
2974
|
}
|
|
1896
2975
|
const leftId = materializeExpression(
|
|
1897
2976
|
node.left,
|
|
1898
2977
|
context,
|
|
1899
|
-
|
|
2978
|
+
variables,
|
|
1900
2979
|
issues
|
|
1901
2980
|
);
|
|
1902
2981
|
const rightId = materializeExpression(
|
|
1903
2982
|
node.right,
|
|
1904
2983
|
context,
|
|
1905
|
-
|
|
2984
|
+
variables,
|
|
1906
2985
|
issues
|
|
1907
2986
|
);
|
|
1908
2987
|
if (operator === "-") {
|
|
@@ -1918,7 +2997,15 @@ function materializeExpression(node, context, aliasNodes, issues) {
|
|
|
1918
2997
|
issues.push(`Function "${mappedFunction}" is not available.`);
|
|
1919
2998
|
return getConstantNodeId(context, 0);
|
|
1920
2999
|
}
|
|
1921
|
-
return emitScalarFunctionNode(
|
|
3000
|
+
return emitScalarFunctionNode(
|
|
3001
|
+
definition,
|
|
3002
|
+
[leftId, rightId],
|
|
3003
|
+
[node.left, node.right],
|
|
3004
|
+
2,
|
|
3005
|
+
context,
|
|
3006
|
+
variables,
|
|
3007
|
+
issues
|
|
3008
|
+
);
|
|
1922
3009
|
}
|
|
1923
3010
|
issues.push(`Unsupported operator "${operator}".`);
|
|
1924
3011
|
return getConstantNodeId(context, 0);
|
|
@@ -1931,22 +3018,55 @@ function materializeExpression(node, context, aliasNodes, issues) {
|
|
|
1931
3018
|
issues.push(`Unknown function "${name}".`);
|
|
1932
3019
|
return getConstantNodeId(context, 0);
|
|
1933
3020
|
}
|
|
1934
|
-
const
|
|
1935
|
-
|
|
1936
|
-
)
|
|
1937
|
-
if (operands.length < definition.minArgs) {
|
|
3021
|
+
const argNodes = node.args;
|
|
3022
|
+
const argCount = argNodes.length;
|
|
3023
|
+
if (argCount < definition.minArgs) {
|
|
1938
3024
|
issues.push(
|
|
1939
|
-
`Function "${name}" expects at least ${definition.minArgs} arguments, received ${
|
|
3025
|
+
`Function "${name}" expects at least ${definition.minArgs} arguments, received ${argCount}.`
|
|
1940
3026
|
);
|
|
1941
3027
|
return getConstantNodeId(context, 0);
|
|
1942
3028
|
}
|
|
1943
|
-
if (definition.maxArgs !== null &&
|
|
3029
|
+
if (definition.maxArgs !== null && argCount > definition.maxArgs) {
|
|
1944
3030
|
issues.push(
|
|
1945
|
-
`Function "${name}" expects at most ${definition.maxArgs} arguments, received ${
|
|
3031
|
+
`Function "${name}" expects at most ${definition.maxArgs} arguments, received ${argCount}.`
|
|
1946
3032
|
);
|
|
1947
3033
|
return getConstantNodeId(context, 0);
|
|
1948
3034
|
}
|
|
1949
|
-
|
|
3035
|
+
if (name === "slew") {
|
|
3036
|
+
const maxRateArg = argNodes[1];
|
|
3037
|
+
if (!maxRateArg || maxRateArg.type !== "Literal") {
|
|
3038
|
+
issues.push(
|
|
3039
|
+
'Function "slew" requires a literal scalar for "max_rate".'
|
|
3040
|
+
);
|
|
3041
|
+
}
|
|
3042
|
+
}
|
|
3043
|
+
const availableAfterInputs = Math.max(
|
|
3044
|
+
0,
|
|
3045
|
+
argCount - definition.inputs.length
|
|
3046
|
+
);
|
|
3047
|
+
const paramArgCount = definition.params.length > 0 ? Math.min(definition.params.length, availableAfterInputs) : 0;
|
|
3048
|
+
const variadicArgCount = definition.variadic ? Math.max(0, availableAfterInputs - paramArgCount) : 0;
|
|
3049
|
+
const operandLimit = Math.min(
|
|
3050
|
+
argCount,
|
|
3051
|
+
definition.inputs.length + variadicArgCount
|
|
3052
|
+
);
|
|
3053
|
+
const operandNodes = argNodes.slice(0, operandLimit);
|
|
3054
|
+
const operands = operandNodes.map(
|
|
3055
|
+
(arg, _index) => materializeExpression(arg, context, variables, issues)
|
|
3056
|
+
);
|
|
3057
|
+
const paramArgStart = operandLimit;
|
|
3058
|
+
const paramArgNodes = paramArgCount > 0 ? argNodes.slice(paramArgStart, paramArgStart + paramArgCount) : [];
|
|
3059
|
+
const paramOverride = definition.nodeType === "case" ? void 0 : paramArgNodes;
|
|
3060
|
+
return emitScalarFunctionNode(
|
|
3061
|
+
definition,
|
|
3062
|
+
operands,
|
|
3063
|
+
argNodes,
|
|
3064
|
+
argCount,
|
|
3065
|
+
context,
|
|
3066
|
+
variables,
|
|
3067
|
+
issues,
|
|
3068
|
+
paramOverride
|
|
3069
|
+
);
|
|
1950
3070
|
}
|
|
1951
3071
|
default: {
|
|
1952
3072
|
issues.push("Unsupported expression node.");
|
|
@@ -1960,10 +3080,25 @@ function buildRigGraphSpec({
|
|
|
1960
3080
|
components,
|
|
1961
3081
|
bindings,
|
|
1962
3082
|
inputsById,
|
|
1963
|
-
inputBindings
|
|
3083
|
+
inputBindings,
|
|
3084
|
+
inputMetadata
|
|
1964
3085
|
}) {
|
|
3086
|
+
const metadataByInputId = inputMetadata ?? /* @__PURE__ */ new Map();
|
|
3087
|
+
const irBuilder = createIrGraphBuilder({
|
|
3088
|
+
faceId,
|
|
3089
|
+
registryVersion: import_metadata2.nodeRegistryVersion,
|
|
3090
|
+
source: "graphBuilder",
|
|
3091
|
+
generatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
3092
|
+
});
|
|
1965
3093
|
const nodes = [];
|
|
1966
3094
|
const edges = [];
|
|
3095
|
+
const graphReservedNodes = /* @__PURE__ */ new Map();
|
|
3096
|
+
const reservedNodeCounters = /* @__PURE__ */ new Map();
|
|
3097
|
+
const generateReservedNodeId = (kind) => {
|
|
3098
|
+
const nextValue = (reservedNodeCounters.get(kind) ?? 0) + 1;
|
|
3099
|
+
reservedNodeCounters.set(kind, nextValue);
|
|
3100
|
+
return `reserved_${kind}_${nextValue}`;
|
|
3101
|
+
};
|
|
1967
3102
|
const inputNodes = /* @__PURE__ */ new Map();
|
|
1968
3103
|
const buildingDerived = /* @__PURE__ */ new Set();
|
|
1969
3104
|
const computedInputs = /* @__PURE__ */ new Set();
|
|
@@ -1993,7 +3128,7 @@ function buildRigGraphSpec({
|
|
|
1993
3128
|
try {
|
|
1994
3129
|
const target = bindingTargetFromInput(input);
|
|
1995
3130
|
const binding = ensureBindingStructure(inputBindingRaw, target);
|
|
1996
|
-
const requiresSelf = binding.inputId ===
|
|
3131
|
+
const requiresSelf = binding.inputId === import_utils5.SELF_BINDING_ID || binding.slots.some((slot) => slot.inputId === import_utils5.SELF_BINDING_ID);
|
|
1997
3132
|
let selfNodeId;
|
|
1998
3133
|
if (requiresSelf) {
|
|
1999
3134
|
const sliderNodeId = `input_raw_${sanitizeNodeId(inputId)}`;
|
|
@@ -2019,7 +3154,9 @@ function buildRigGraphSpec({
|
|
|
2019
3154
|
edges,
|
|
2020
3155
|
ensureInputNode,
|
|
2021
3156
|
bindingIssues,
|
|
2022
|
-
summaryBindings
|
|
3157
|
+
summaryBindings,
|
|
3158
|
+
graphReservedNodes,
|
|
3159
|
+
generateReservedNodeId
|
|
2023
3160
|
},
|
|
2024
3161
|
selfNodeId
|
|
2025
3162
|
});
|
|
@@ -2099,7 +3236,9 @@ function buildRigGraphSpec({
|
|
|
2099
3236
|
edges,
|
|
2100
3237
|
ensureInputNode,
|
|
2101
3238
|
bindingIssues,
|
|
2102
|
-
summaryBindings
|
|
3239
|
+
summaryBindings,
|
|
3240
|
+
graphReservedNodes,
|
|
3241
|
+
generateReservedNodeId
|
|
2103
3242
|
}
|
|
2104
3243
|
});
|
|
2105
3244
|
valueNodeId = producedNodeId;
|
|
@@ -2115,10 +3254,11 @@ function buildRigGraphSpec({
|
|
|
2115
3254
|
slotId: PRIMARY_SLOT_ID,
|
|
2116
3255
|
slotAlias: PRIMARY_SLOT_ALIAS,
|
|
2117
3256
|
inputId: null,
|
|
2118
|
-
remap: createDefaultRemap(target),
|
|
2119
3257
|
expression: PRIMARY_SLOT_ALIAS,
|
|
2120
3258
|
valueType: target.valueType === "vector" ? "vector" : "scalar",
|
|
2121
|
-
issues: ["Binding not found."]
|
|
3259
|
+
issues: ["Binding not found."],
|
|
3260
|
+
nodeId: PRIMARY_SLOT_ID,
|
|
3261
|
+
expressionNodeId: PRIMARY_SLOT_ID
|
|
2122
3262
|
});
|
|
2123
3263
|
const fallbackIssues = bindingIssues.get(component.id) ?? /* @__PURE__ */ new Set();
|
|
2124
3264
|
fallbackIssues.add("Binding not found.");
|
|
@@ -2128,15 +3268,7 @@ function buildRigGraphSpec({
|
|
|
2128
3268
|
entry.defaults.set(key, component.defaultValue);
|
|
2129
3269
|
return;
|
|
2130
3270
|
}
|
|
2131
|
-
|
|
2132
|
-
const finalNodeId = applyBindingOperators(
|
|
2133
|
-
operatorList,
|
|
2134
|
-
valueNodeId,
|
|
2135
|
-
component.safeId,
|
|
2136
|
-
nodes,
|
|
2137
|
-
edges
|
|
2138
|
-
);
|
|
2139
|
-
entry.values.set(key, finalNodeId);
|
|
3271
|
+
entry.values.set(key, valueNodeId);
|
|
2140
3272
|
});
|
|
2141
3273
|
inputsById.forEach((_input, inputId) => {
|
|
2142
3274
|
ensureInputNode(inputId);
|
|
@@ -2162,8 +3294,8 @@ function buildRigGraphSpec({
|
|
|
2162
3294
|
}
|
|
2163
3295
|
});
|
|
2164
3296
|
edges.push({
|
|
2165
|
-
from: {
|
|
2166
|
-
to: {
|
|
3297
|
+
from: { nodeId: valueNodeId },
|
|
3298
|
+
to: { nodeId: outputNodeId2, portId: "in" }
|
|
2167
3299
|
});
|
|
2168
3300
|
return;
|
|
2169
3301
|
}
|
|
@@ -2176,7 +3308,7 @@ function buildRigGraphSpec({
|
|
|
2176
3308
|
let sourceId = entry.values.get(componentKey);
|
|
2177
3309
|
if (!sourceId) {
|
|
2178
3310
|
const componentDefault = entry.defaults.get(componentKey) ?? extractComponentDefault(
|
|
2179
|
-
(0,
|
|
3311
|
+
(0, import_utils4.buildAnimatableValue)(entry.animatable, void 0),
|
|
2180
3312
|
componentKey
|
|
2181
3313
|
);
|
|
2182
3314
|
const constNodeId = `const_${safeId}_${componentKey}`;
|
|
@@ -2190,8 +3322,8 @@ function buildRigGraphSpec({
|
|
|
2190
3322
|
sourceId = constNodeId;
|
|
2191
3323
|
}
|
|
2192
3324
|
edges.push({
|
|
2193
|
-
from: {
|
|
2194
|
-
to: {
|
|
3325
|
+
from: { nodeId: sourceId },
|
|
3326
|
+
to: { nodeId: joinNodeId, portId: `operand_${index + 1}` }
|
|
2195
3327
|
});
|
|
2196
3328
|
});
|
|
2197
3329
|
const outputNodeId = `out_${safeId}`;
|
|
@@ -2203,8 +3335,8 @@ function buildRigGraphSpec({
|
|
|
2203
3335
|
}
|
|
2204
3336
|
});
|
|
2205
3337
|
edges.push({
|
|
2206
|
-
from: {
|
|
2207
|
-
to: {
|
|
3338
|
+
from: { nodeId: joinNodeId },
|
|
3339
|
+
to: { nodeId: outputNodeId, portId: "in" }
|
|
2208
3340
|
});
|
|
2209
3341
|
});
|
|
2210
3342
|
const nodeById = /* @__PURE__ */ new Map();
|
|
@@ -2213,7 +3345,7 @@ function buildRigGraphSpec({
|
|
|
2213
3345
|
});
|
|
2214
3346
|
const constantUsage = /* @__PURE__ */ new Map();
|
|
2215
3347
|
edges.forEach((edge) => {
|
|
2216
|
-
const source = nodeById.get(edge.from.
|
|
3348
|
+
const source = nodeById.get(edge.from.nodeId);
|
|
2217
3349
|
if (source?.type === "constant") {
|
|
2218
3350
|
constantUsage.set(source.id, (constantUsage.get(source.id) ?? 0) + 1);
|
|
2219
3351
|
}
|
|
@@ -2221,15 +3353,16 @@ function buildRigGraphSpec({
|
|
|
2221
3353
|
const updatedEdges = [];
|
|
2222
3354
|
const constantsToRemove = /* @__PURE__ */ new Set();
|
|
2223
3355
|
edges.forEach((edge) => {
|
|
2224
|
-
const source = nodeById.get(edge.from.
|
|
3356
|
+
const source = nodeById.get(edge.from.nodeId);
|
|
2225
3357
|
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.
|
|
3358
|
+
const target = nodeById.get(edge.to.nodeId);
|
|
2227
3359
|
if (target) {
|
|
2228
3360
|
const value = source.params.value;
|
|
2229
3361
|
if (value !== void 0) {
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
|
|
3362
|
+
const targetPort = edge.to.portId ?? "in";
|
|
3363
|
+
target.inputDefaults = {
|
|
3364
|
+
...target.inputDefaults ?? {},
|
|
3365
|
+
[targetPort]: value
|
|
2233
3366
|
};
|
|
2234
3367
|
nodeById.set(target.id, target);
|
|
2235
3368
|
constantsToRemove.add(source.id);
|
|
@@ -2246,18 +3379,17 @@ function buildRigGraphSpec({
|
|
|
2246
3379
|
const filteredSummaryBindings = summaryBindings.filter(
|
|
2247
3380
|
(binding) => outputs.has(binding.animatableId) || computedInputs.has(binding.animatableId)
|
|
2248
3381
|
);
|
|
2249
|
-
const
|
|
2250
|
-
|
|
2251
|
-
|
|
2252
|
-
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
|
|
2257
|
-
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
inputs: Array.from(inputsById.values()).map((input) => ({
|
|
3382
|
+
const vizijMetadata = {
|
|
3383
|
+
vizij: {
|
|
3384
|
+
faceId,
|
|
3385
|
+
inputs: Array.from(inputsById.values()).map((input) => {
|
|
3386
|
+
const meta = metadataByInputId.get(input.id);
|
|
3387
|
+
const derivedRoot = meta?.root ?? input.group;
|
|
3388
|
+
let derivedSource = meta?.source;
|
|
3389
|
+
if (!derivedSource && input.path.startsWith("/standard/")) {
|
|
3390
|
+
derivedSource = "preset";
|
|
3391
|
+
}
|
|
3392
|
+
const entry = {
|
|
2261
3393
|
id: input.id,
|
|
2262
3394
|
path: input.path,
|
|
2263
3395
|
sourceId: input.sourceId,
|
|
@@ -2268,15 +3400,22 @@ function buildRigGraphSpec({
|
|
|
2268
3400
|
min: input.range.min,
|
|
2269
3401
|
max: input.range.max
|
|
2270
3402
|
}
|
|
2271
|
-
}
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
}
|
|
3403
|
+
};
|
|
3404
|
+
if (derivedSource) {
|
|
3405
|
+
entry.source = derivedSource;
|
|
3406
|
+
}
|
|
3407
|
+
if (derivedRoot) {
|
|
3408
|
+
entry.root = derivedRoot;
|
|
3409
|
+
}
|
|
3410
|
+
return entry;
|
|
3411
|
+
}),
|
|
3412
|
+
bindings: filteredSummaryBindings.map((binding) => ({
|
|
3413
|
+
...binding,
|
|
3414
|
+
expression: binding.expression,
|
|
3415
|
+
valueType: binding.valueType,
|
|
3416
|
+
issues: binding.issues ? [...binding.issues] : void 0,
|
|
3417
|
+
metadata: binding.metadata ? cloneJsonLike2(binding.metadata) : void 0
|
|
3418
|
+
}))
|
|
2280
3419
|
}
|
|
2281
3420
|
};
|
|
2282
3421
|
const issuesByTarget = {};
|
|
@@ -2291,29 +3430,148 @@ function buildRigGraphSpec({
|
|
|
2291
3430
|
issues.forEach((issue) => fatalIssues.add(issue));
|
|
2292
3431
|
});
|
|
2293
3432
|
remapDefaultIssues.forEach((issue) => fatalIssues.add(issue));
|
|
3433
|
+
const summaryPayload = {
|
|
3434
|
+
faceId,
|
|
3435
|
+
inputs: Array.from(inputNodes.values()).map(
|
|
3436
|
+
({ input }) => buildRigInputPath(faceId, input.path)
|
|
3437
|
+
),
|
|
3438
|
+
outputs: [...dynamicOutputs, ...computedInputList],
|
|
3439
|
+
bindings: filteredSummaryBindings
|
|
3440
|
+
};
|
|
3441
|
+
const irSummary = {
|
|
3442
|
+
faceId: summaryPayload.faceId,
|
|
3443
|
+
inputs: [...summaryPayload.inputs],
|
|
3444
|
+
outputs: [...summaryPayload.outputs],
|
|
3445
|
+
bindings: toIrBindingSummary(
|
|
3446
|
+
filteredSummaryBindings.map((binding) => ({
|
|
3447
|
+
...binding,
|
|
3448
|
+
issues: binding.issues ? [...binding.issues] : void 0
|
|
3449
|
+
}))
|
|
3450
|
+
)
|
|
3451
|
+
};
|
|
3452
|
+
const fatalIssueList = Array.from(fatalIssues);
|
|
3453
|
+
const irIssues = createIrIssuesFromLegacy(issuesByTarget, fatalIssueList);
|
|
3454
|
+
filteredNodes.forEach((node) => {
|
|
3455
|
+
irBuilder.addNode(cloneIrNode(node));
|
|
3456
|
+
const constant = extractIrConstantFromNode(node);
|
|
3457
|
+
if (constant) {
|
|
3458
|
+
irBuilder.addConstant(constant);
|
|
3459
|
+
}
|
|
3460
|
+
});
|
|
3461
|
+
updatedEdges.forEach((edge) => {
|
|
3462
|
+
irBuilder.addEdge(cloneIrEdge(edge));
|
|
3463
|
+
});
|
|
3464
|
+
irBuilder.setSummary(irSummary);
|
|
3465
|
+
irIssues.forEach((issue) => irBuilder.addIssue(issue));
|
|
3466
|
+
irBuilder.updateMetadata({
|
|
3467
|
+
annotations: {
|
|
3468
|
+
graphSpecMetadata: cloneJsonLike2(vizijMetadata)
|
|
3469
|
+
}
|
|
3470
|
+
});
|
|
3471
|
+
const irGraph = irBuilder.build();
|
|
3472
|
+
const compiled = compileIrGraph(irGraph, { preferLegacySpec: false });
|
|
2294
3473
|
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
|
-
},
|
|
3474
|
+
spec: compiled.spec,
|
|
3475
|
+
summary: summaryPayload,
|
|
2304
3476
|
issues: {
|
|
2305
3477
|
byTarget: issuesByTarget,
|
|
2306
|
-
fatal:
|
|
3478
|
+
fatal: fatalIssueList
|
|
3479
|
+
},
|
|
3480
|
+
ir: {
|
|
3481
|
+
graph: irGraph,
|
|
3482
|
+
compile: (options) => compileIrGraph(irGraph, options)
|
|
3483
|
+
}
|
|
3484
|
+
};
|
|
3485
|
+
}
|
|
3486
|
+
function createIrIssuesFromLegacy(issuesByTarget, fatalIssues) {
|
|
3487
|
+
const fatalSet = new Set(fatalIssues);
|
|
3488
|
+
const collected = [];
|
|
3489
|
+
let counter = 0;
|
|
3490
|
+
Object.entries(issuesByTarget).forEach(([targetId, messages]) => {
|
|
3491
|
+
messages.forEach((message) => {
|
|
3492
|
+
counter += 1;
|
|
3493
|
+
collected.push({
|
|
3494
|
+
id: `issue_${counter}`,
|
|
3495
|
+
severity: fatalSet.has(message) ? "error" : "warning",
|
|
3496
|
+
message,
|
|
3497
|
+
targetId,
|
|
3498
|
+
tags: fatalSet.has(message) ? ["fatal"] : void 0
|
|
3499
|
+
});
|
|
3500
|
+
});
|
|
3501
|
+
});
|
|
3502
|
+
fatalSet.forEach((message) => {
|
|
3503
|
+
const alreadyCaptured = collected.some(
|
|
3504
|
+
(issue) => issue.message === message
|
|
3505
|
+
);
|
|
3506
|
+
if (alreadyCaptured) {
|
|
3507
|
+
return;
|
|
2307
3508
|
}
|
|
3509
|
+
counter += 1;
|
|
3510
|
+
collected.push({
|
|
3511
|
+
id: `issue_${counter}`,
|
|
3512
|
+
severity: "error",
|
|
3513
|
+
message,
|
|
3514
|
+
tags: ["fatal"]
|
|
3515
|
+
});
|
|
3516
|
+
});
|
|
3517
|
+
return collected;
|
|
3518
|
+
}
|
|
3519
|
+
function cloneIrNode(node) {
|
|
3520
|
+
return {
|
|
3521
|
+
id: node.id,
|
|
3522
|
+
type: node.type,
|
|
3523
|
+
category: node.category,
|
|
3524
|
+
label: node.label,
|
|
3525
|
+
description: node.description,
|
|
3526
|
+
params: cloneJsonLike2(node.params),
|
|
3527
|
+
inputDefaults: cloneJsonLike2(node.inputDefaults),
|
|
3528
|
+
metadata: cloneJsonLike2(node.metadata)
|
|
3529
|
+
};
|
|
3530
|
+
}
|
|
3531
|
+
function cloneIrEdge(edge) {
|
|
3532
|
+
return {
|
|
3533
|
+
id: edge.id,
|
|
3534
|
+
from: {
|
|
3535
|
+
nodeId: edge.from.nodeId,
|
|
3536
|
+
portId: edge.from.portId,
|
|
3537
|
+
component: edge.from.component
|
|
3538
|
+
},
|
|
3539
|
+
to: {
|
|
3540
|
+
nodeId: edge.to.nodeId,
|
|
3541
|
+
portId: edge.to.portId,
|
|
3542
|
+
component: edge.to.component
|
|
3543
|
+
},
|
|
3544
|
+
metadata: cloneJsonLike2(edge.metadata)
|
|
3545
|
+
};
|
|
3546
|
+
}
|
|
3547
|
+
function extractIrConstantFromNode(node) {
|
|
3548
|
+
if (node.type !== "constant") {
|
|
3549
|
+
return null;
|
|
3550
|
+
}
|
|
3551
|
+
const value = node.params?.value;
|
|
3552
|
+
if (typeof value !== "number" || !Number.isFinite(value)) {
|
|
3553
|
+
return null;
|
|
3554
|
+
}
|
|
3555
|
+
return {
|
|
3556
|
+
id: node.id,
|
|
3557
|
+
value,
|
|
3558
|
+
valueType: "scalar",
|
|
3559
|
+
metadata: cloneJsonLike2(node.metadata)
|
|
2308
3560
|
};
|
|
2309
3561
|
}
|
|
3562
|
+
function cloneJsonLike2(value) {
|
|
3563
|
+
if (value === void 0 || value === null) {
|
|
3564
|
+
return value;
|
|
3565
|
+
}
|
|
3566
|
+
return (0, import_utils4.cloneDeepSafe)(value);
|
|
3567
|
+
}
|
|
2310
3568
|
function validateRemapDefaults(nodes) {
|
|
2311
3569
|
const issues = [];
|
|
2312
3570
|
nodes.forEach((node) => {
|
|
2313
3571
|
if (node.type !== "centered_remap") {
|
|
2314
3572
|
return;
|
|
2315
3573
|
}
|
|
2316
|
-
const defaults = node.
|
|
3574
|
+
const defaults = node.inputDefaults ?? {};
|
|
2317
3575
|
[
|
|
2318
3576
|
"in_low",
|
|
2319
3577
|
"in_anchor",
|
|
@@ -2330,38 +3588,423 @@ function validateRemapDefaults(nodes) {
|
|
|
2330
3588
|
});
|
|
2331
3589
|
return issues;
|
|
2332
3590
|
}
|
|
3591
|
+
|
|
3592
|
+
// src/ir/inspection.ts
|
|
3593
|
+
var import_metadata3 = require("@vizij/node-graph-wasm/metadata");
|
|
3594
|
+
var import_utils6 = require("@vizij/utils");
|
|
3595
|
+
var MACHINE_REPORT_VERSION = 1;
|
|
3596
|
+
var DEFAULT_DIFF_LIMIT = 50;
|
|
3597
|
+
function buildMachineReport(result) {
|
|
3598
|
+
return {
|
|
3599
|
+
reportVersion: MACHINE_REPORT_VERSION,
|
|
3600
|
+
faceId: result.summary.faceId,
|
|
3601
|
+
summary: normalizeSummary(result.summary),
|
|
3602
|
+
issues: normalizeIssues(result.issues),
|
|
3603
|
+
irGraph: result.ir?.graph ? normalizeIrGraph(result.ir.graph) : void 0
|
|
3604
|
+
};
|
|
3605
|
+
}
|
|
3606
|
+
function diffMachineReports(actual, expected, options) {
|
|
3607
|
+
const limit = normalizeDiffLimit(options?.limit);
|
|
3608
|
+
const ctx = {
|
|
3609
|
+
differences: [],
|
|
3610
|
+
limit,
|
|
3611
|
+
limitReached: false
|
|
3612
|
+
};
|
|
3613
|
+
diffValues(actual, expected, "$", ctx);
|
|
3614
|
+
return {
|
|
3615
|
+
equal: ctx.differences.length === 0,
|
|
3616
|
+
differences: ctx.differences,
|
|
3617
|
+
limitReached: ctx.limitReached
|
|
3618
|
+
};
|
|
3619
|
+
}
|
|
3620
|
+
function normalizeSummary(summary) {
|
|
3621
|
+
return {
|
|
3622
|
+
faceId: summary.faceId,
|
|
3623
|
+
inputs: [...summary.inputs].sort(),
|
|
3624
|
+
outputs: [...summary.outputs].sort(),
|
|
3625
|
+
bindings: normalizeGraphBindingSummaries(summary.bindings)
|
|
3626
|
+
};
|
|
3627
|
+
}
|
|
3628
|
+
function normalizeGraphBindingSummaries(bindings) {
|
|
3629
|
+
const normalized = bindings.map((binding) => ({
|
|
3630
|
+
targetId: binding.targetId,
|
|
3631
|
+
animatableId: binding.animatableId,
|
|
3632
|
+
component: binding.component ?? void 0,
|
|
3633
|
+
slotId: binding.slotId,
|
|
3634
|
+
slotAlias: binding.slotAlias,
|
|
3635
|
+
inputId: binding.inputId ?? null,
|
|
3636
|
+
expression: binding.expression,
|
|
3637
|
+
valueType: binding.valueType,
|
|
3638
|
+
nodeId: binding.nodeId,
|
|
3639
|
+
expressionNodeId: binding.expressionNodeId,
|
|
3640
|
+
issues: normalizeStringArray(binding.issues),
|
|
3641
|
+
metadata: cloneBindingMetadata2(binding.metadata)
|
|
3642
|
+
}));
|
|
3643
|
+
normalized.sort((a, b) => bindingSortKey(a).localeCompare(bindingSortKey(b)));
|
|
3644
|
+
return normalized;
|
|
3645
|
+
}
|
|
3646
|
+
function cloneBindingMetadata2(metadata) {
|
|
3647
|
+
if (!metadata) {
|
|
3648
|
+
return void 0;
|
|
3649
|
+
}
|
|
3650
|
+
return (0, import_utils6.cloneDeepSafe)(metadata);
|
|
3651
|
+
}
|
|
3652
|
+
function normalizeIssues(issues) {
|
|
3653
|
+
const byTargetEntries = Object.entries(issues.byTarget ?? {}).map(
|
|
3654
|
+
([targetId, messages]) => [targetId, [...messages].sort()]
|
|
3655
|
+
);
|
|
3656
|
+
byTargetEntries.sort(([a], [b]) => a.localeCompare(b));
|
|
3657
|
+
const byTarget = {};
|
|
3658
|
+
byTargetEntries.forEach(([targetId, messages]) => {
|
|
3659
|
+
byTarget[targetId] = messages;
|
|
3660
|
+
});
|
|
3661
|
+
return {
|
|
3662
|
+
fatal: [...issues.fatal].sort(),
|
|
3663
|
+
byTarget
|
|
3664
|
+
};
|
|
3665
|
+
}
|
|
3666
|
+
function normalizeIrGraph(graph) {
|
|
3667
|
+
return {
|
|
3668
|
+
id: graph.id,
|
|
3669
|
+
faceId: graph.faceId,
|
|
3670
|
+
nodes: normalizeIrNodes(graph.nodes),
|
|
3671
|
+
edges: normalizeIrEdges(graph.edges),
|
|
3672
|
+
constants: normalizeIrConstants(graph.constants),
|
|
3673
|
+
issues: normalizeIrIssues(graph.issues),
|
|
3674
|
+
summary: normalizeIrGraphSummary(graph.summary),
|
|
3675
|
+
metadata: normalizeIrMetadata(graph.metadata)
|
|
3676
|
+
};
|
|
3677
|
+
}
|
|
3678
|
+
function normalizeIrNodes(nodes) {
|
|
3679
|
+
return [...nodes].map((node) => ({
|
|
3680
|
+
...node,
|
|
3681
|
+
inputDefaults: node.inputDefaults ? sortPlainObject(node.inputDefaults) : void 0,
|
|
3682
|
+
params: node.params ? sortPlainObject(node.params) : void 0,
|
|
3683
|
+
metadata: node.metadata ? sortPlainObject(node.metadata) : void 0,
|
|
3684
|
+
annotations: buildNodeAnnotations(node)
|
|
3685
|
+
})).sort((a, b) => a.id.localeCompare(b.id));
|
|
3686
|
+
}
|
|
3687
|
+
function normalizeIrEdges(edges) {
|
|
3688
|
+
return [...edges].map((edge) => ({
|
|
3689
|
+
...edge,
|
|
3690
|
+
from: normalizePortRef(edge.from),
|
|
3691
|
+
to: normalizePortRef(edge.to),
|
|
3692
|
+
metadata: edge.metadata ? sortPlainObject(edge.metadata) : void 0
|
|
3693
|
+
})).sort((a, b) => edgeSortKey(a).localeCompare(edgeSortKey(b)));
|
|
3694
|
+
}
|
|
3695
|
+
function normalizePortRef(edgeRef) {
|
|
3696
|
+
return {
|
|
3697
|
+
nodeId: edgeRef.nodeId,
|
|
3698
|
+
portId: edgeRef.portId ?? void 0,
|
|
3699
|
+
component: edgeRef.component ?? void 0
|
|
3700
|
+
};
|
|
3701
|
+
}
|
|
3702
|
+
function edgeSortKey(edge) {
|
|
3703
|
+
if (edge.id) {
|
|
3704
|
+
return edge.id;
|
|
3705
|
+
}
|
|
3706
|
+
const fromPort = edge.from.portId ?? "";
|
|
3707
|
+
const toPort = edge.to.portId ?? "";
|
|
3708
|
+
return `${edge.from.nodeId}:${fromPort}->${edge.to.nodeId}:${toPort}`;
|
|
3709
|
+
}
|
|
3710
|
+
function normalizeIrConstants(constants) {
|
|
3711
|
+
return [...constants].map((constant) => ({
|
|
3712
|
+
...constant,
|
|
3713
|
+
metadata: constant.metadata ? sortPlainObject(constant.metadata) : void 0
|
|
3714
|
+
})).sort((a, b) => a.id.localeCompare(b.id));
|
|
3715
|
+
}
|
|
3716
|
+
function normalizeIrIssues(issues) {
|
|
3717
|
+
return [...issues].map((issue) => ({
|
|
3718
|
+
...issue,
|
|
3719
|
+
tags: normalizeStringArray(issue.tags),
|
|
3720
|
+
details: issue.details ? sortPlainObject(issue.details) : void 0
|
|
3721
|
+
})).sort((a, b) => a.id.localeCompare(b.id));
|
|
3722
|
+
}
|
|
3723
|
+
function normalizeIrGraphSummary(summary) {
|
|
3724
|
+
return {
|
|
3725
|
+
faceId: summary.faceId,
|
|
3726
|
+
inputs: [...summary.inputs].sort(),
|
|
3727
|
+
outputs: [...summary.outputs].sort(),
|
|
3728
|
+
bindings: normalizeIrBindingSummaries(summary.bindings)
|
|
3729
|
+
};
|
|
3730
|
+
}
|
|
3731
|
+
function normalizeIrBindingSummaries(bindings) {
|
|
3732
|
+
const normalized = bindings.map((binding) => ({
|
|
3733
|
+
...binding,
|
|
3734
|
+
issues: normalizeStringArray(binding.issues)
|
|
3735
|
+
}));
|
|
3736
|
+
normalized.sort((a, b) => bindingSortKey(a).localeCompare(bindingSortKey(b)));
|
|
3737
|
+
return normalized;
|
|
3738
|
+
}
|
|
3739
|
+
function normalizeIrMetadata(metadata) {
|
|
3740
|
+
const normalized = {
|
|
3741
|
+
source: metadata.source ?? "unknown"
|
|
3742
|
+
};
|
|
3743
|
+
if (metadata.registryVersion) {
|
|
3744
|
+
normalized.registryVersion = metadata.registryVersion;
|
|
3745
|
+
}
|
|
3746
|
+
if (metadata.annotations) {
|
|
3747
|
+
const sorted = sortPlainObject(metadata.annotations);
|
|
3748
|
+
if (Object.keys(sorted).length > 0) {
|
|
3749
|
+
normalized.annotations = sorted;
|
|
3750
|
+
}
|
|
3751
|
+
}
|
|
3752
|
+
return normalized;
|
|
3753
|
+
}
|
|
3754
|
+
function buildNodeAnnotations(node) {
|
|
3755
|
+
const signature = findRegistrySignature(node.type);
|
|
3756
|
+
if (!signature) {
|
|
3757
|
+
return void 0;
|
|
3758
|
+
}
|
|
3759
|
+
return {
|
|
3760
|
+
registry: normalizeRegistrySignature(signature)
|
|
3761
|
+
};
|
|
3762
|
+
}
|
|
3763
|
+
function findRegistrySignature(typeId) {
|
|
3764
|
+
try {
|
|
3765
|
+
const signature = (0, import_metadata3.findNodeSignature)(typeId);
|
|
3766
|
+
if (!signature) {
|
|
3767
|
+
return void 0;
|
|
3768
|
+
}
|
|
3769
|
+
return signature;
|
|
3770
|
+
} catch {
|
|
3771
|
+
return void 0;
|
|
3772
|
+
}
|
|
3773
|
+
}
|
|
3774
|
+
function normalizeRegistrySignature(signature) {
|
|
3775
|
+
return {
|
|
3776
|
+
typeId: signature.type_id,
|
|
3777
|
+
name: signature.name,
|
|
3778
|
+
category: signature.category,
|
|
3779
|
+
doc: signature.doc,
|
|
3780
|
+
inputs: signature.inputs.map(normalizeRegistryPortSpec),
|
|
3781
|
+
variadicInputs: signature.variadic_inputs ? normalizeRegistryVariadicSpec(signature.variadic_inputs) : void 0,
|
|
3782
|
+
outputs: signature.outputs.map(normalizeRegistryPortSpec),
|
|
3783
|
+
variadicOutputs: signature.variadic_outputs ? normalizeRegistryVariadicSpec(signature.variadic_outputs) : void 0,
|
|
3784
|
+
params: signature.params.map(normalizeRegistryParamSpec)
|
|
3785
|
+
};
|
|
3786
|
+
}
|
|
3787
|
+
function normalizeRegistryPortSpec(port) {
|
|
3788
|
+
const normalized = {
|
|
3789
|
+
id: port.id,
|
|
3790
|
+
label: port.label,
|
|
3791
|
+
type: port.ty ?? "unknown"
|
|
3792
|
+
};
|
|
3793
|
+
if (port.doc) {
|
|
3794
|
+
normalized.doc = port.doc;
|
|
3795
|
+
}
|
|
3796
|
+
if (port.optional) {
|
|
3797
|
+
normalized.optional = true;
|
|
3798
|
+
}
|
|
3799
|
+
return normalized;
|
|
3800
|
+
}
|
|
3801
|
+
function normalizeRegistryVariadicSpec(spec) {
|
|
3802
|
+
const normalized = {
|
|
3803
|
+
id: spec.id,
|
|
3804
|
+
label: spec.label,
|
|
3805
|
+
type: spec.ty ?? "unknown",
|
|
3806
|
+
min: spec.min
|
|
3807
|
+
};
|
|
3808
|
+
if (spec.doc) {
|
|
3809
|
+
normalized.doc = spec.doc;
|
|
3810
|
+
}
|
|
3811
|
+
if (typeof spec.max === "number") {
|
|
3812
|
+
normalized.max = spec.max;
|
|
3813
|
+
}
|
|
3814
|
+
return normalized;
|
|
3815
|
+
}
|
|
3816
|
+
function normalizeRegistryParamSpec(param) {
|
|
3817
|
+
const normalized = {
|
|
3818
|
+
id: param.id,
|
|
3819
|
+
label: param.label,
|
|
3820
|
+
type: param.ty ?? "unknown"
|
|
3821
|
+
};
|
|
3822
|
+
if (param.doc) {
|
|
3823
|
+
normalized.doc = param.doc;
|
|
3824
|
+
}
|
|
3825
|
+
if (param.default_json !== void 0) {
|
|
3826
|
+
normalized.defaultValue = normalizePlainValue(param.default_json);
|
|
3827
|
+
}
|
|
3828
|
+
if (typeof param.min === "number") {
|
|
3829
|
+
normalized.min = param.min;
|
|
3830
|
+
}
|
|
3831
|
+
if (typeof param.max === "number") {
|
|
3832
|
+
normalized.max = param.max;
|
|
3833
|
+
}
|
|
3834
|
+
return normalized;
|
|
3835
|
+
}
|
|
3836
|
+
function normalizeStringArray(values) {
|
|
3837
|
+
if (!values || values.length === 0) {
|
|
3838
|
+
return void 0;
|
|
3839
|
+
}
|
|
3840
|
+
const unique = Array.from(new Set(values));
|
|
3841
|
+
unique.sort();
|
|
3842
|
+
return unique;
|
|
3843
|
+
}
|
|
3844
|
+
function bindingSortKey(binding) {
|
|
3845
|
+
const component = binding.component ?? "";
|
|
3846
|
+
return `${binding.targetId}::${component}::${binding.slotId}::${binding.slotAlias}::${binding.animatableId}`;
|
|
3847
|
+
}
|
|
3848
|
+
function sortPlainObject(record) {
|
|
3849
|
+
const sorted = {};
|
|
3850
|
+
Object.keys(record).sort().forEach((key) => {
|
|
3851
|
+
sorted[key] = normalizePlainValue(record[key]);
|
|
3852
|
+
});
|
|
3853
|
+
return sorted;
|
|
3854
|
+
}
|
|
3855
|
+
function normalizePlainValue(value) {
|
|
3856
|
+
if (Array.isArray(value)) {
|
|
3857
|
+
return value.map((entry) => normalizePlainValue(entry));
|
|
3858
|
+
}
|
|
3859
|
+
if (isPlainObject(value)) {
|
|
3860
|
+
return sortPlainObject(value);
|
|
3861
|
+
}
|
|
3862
|
+
return value;
|
|
3863
|
+
}
|
|
3864
|
+
function isPlainObject(value) {
|
|
3865
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
3866
|
+
}
|
|
3867
|
+
function diffValues(actual, expected, path, ctx) {
|
|
3868
|
+
if (ctx.differences.length >= ctx.limit) {
|
|
3869
|
+
ctx.limitReached = true;
|
|
3870
|
+
return;
|
|
3871
|
+
}
|
|
3872
|
+
if (Object.is(actual, expected)) {
|
|
3873
|
+
return;
|
|
3874
|
+
}
|
|
3875
|
+
if (Array.isArray(actual) && Array.isArray(expected)) {
|
|
3876
|
+
const compareLength = Math.min(actual.length, expected.length);
|
|
3877
|
+
for (let index = 0; index < compareLength; index += 1) {
|
|
3878
|
+
diffValues(actual[index], expected[index], pathIndex(path, index), ctx);
|
|
3879
|
+
if (ctx.differences.length >= ctx.limit) {
|
|
3880
|
+
ctx.limitReached = true;
|
|
3881
|
+
return;
|
|
3882
|
+
}
|
|
3883
|
+
}
|
|
3884
|
+
if (actual.length > expected.length) {
|
|
3885
|
+
for (let index = compareLength; index < actual.length; index += 1) {
|
|
3886
|
+
pushDifference(ctx, {
|
|
3887
|
+
kind: "unexpected",
|
|
3888
|
+
path: pathIndex(path, index),
|
|
3889
|
+
actual: actual[index]
|
|
3890
|
+
});
|
|
3891
|
+
if (ctx.differences.length >= ctx.limit) {
|
|
3892
|
+
ctx.limitReached = true;
|
|
3893
|
+
return;
|
|
3894
|
+
}
|
|
3895
|
+
}
|
|
3896
|
+
} else if (expected.length > actual.length) {
|
|
3897
|
+
for (let index = compareLength; index < expected.length; index += 1) {
|
|
3898
|
+
pushDifference(ctx, {
|
|
3899
|
+
kind: "missing",
|
|
3900
|
+
path: pathIndex(path, index),
|
|
3901
|
+
expected: expected[index]
|
|
3902
|
+
});
|
|
3903
|
+
if (ctx.differences.length >= ctx.limit) {
|
|
3904
|
+
ctx.limitReached = true;
|
|
3905
|
+
return;
|
|
3906
|
+
}
|
|
3907
|
+
}
|
|
3908
|
+
}
|
|
3909
|
+
return;
|
|
3910
|
+
}
|
|
3911
|
+
if (isPlainObject(actual) && isPlainObject(expected)) {
|
|
3912
|
+
const keys = /* @__PURE__ */ new Set([...Object.keys(actual), ...Object.keys(expected)]);
|
|
3913
|
+
const sortedKeys = Array.from(keys).sort();
|
|
3914
|
+
for (const key of sortedKeys) {
|
|
3915
|
+
if (!(key in actual)) {
|
|
3916
|
+
pushDifference(ctx, {
|
|
3917
|
+
kind: "missing",
|
|
3918
|
+
path: pathKey(path, key),
|
|
3919
|
+
expected: expected[key]
|
|
3920
|
+
});
|
|
3921
|
+
} else if (!(key in expected)) {
|
|
3922
|
+
pushDifference(ctx, {
|
|
3923
|
+
kind: "unexpected",
|
|
3924
|
+
path: pathKey(path, key),
|
|
3925
|
+
actual: actual[key]
|
|
3926
|
+
});
|
|
3927
|
+
} else {
|
|
3928
|
+
diffValues(actual[key], expected[key], pathKey(path, key), ctx);
|
|
3929
|
+
}
|
|
3930
|
+
if (ctx.differences.length >= ctx.limit) {
|
|
3931
|
+
ctx.limitReached = true;
|
|
3932
|
+
return;
|
|
3933
|
+
}
|
|
3934
|
+
}
|
|
3935
|
+
return;
|
|
3936
|
+
}
|
|
3937
|
+
pushDifference(ctx, {
|
|
3938
|
+
kind: "mismatch",
|
|
3939
|
+
path,
|
|
3940
|
+
actual,
|
|
3941
|
+
expected
|
|
3942
|
+
});
|
|
3943
|
+
}
|
|
3944
|
+
function pathKey(base, key) {
|
|
3945
|
+
if (base === "") {
|
|
3946
|
+
return key;
|
|
3947
|
+
}
|
|
3948
|
+
if (base.endsWith("]")) {
|
|
3949
|
+
return `${base}.${key}`;
|
|
3950
|
+
}
|
|
3951
|
+
return `${base}.${key}`;
|
|
3952
|
+
}
|
|
3953
|
+
function pathIndex(base, index) {
|
|
3954
|
+
return `${base}[${index}]`;
|
|
3955
|
+
}
|
|
3956
|
+
function pushDifference(ctx, entry) {
|
|
3957
|
+
if (ctx.differences.length < ctx.limit) {
|
|
3958
|
+
ctx.differences.push(entry);
|
|
3959
|
+
if (ctx.differences.length === ctx.limit) {
|
|
3960
|
+
ctx.limitReached = true;
|
|
3961
|
+
}
|
|
3962
|
+
} else {
|
|
3963
|
+
ctx.limitReached = true;
|
|
3964
|
+
}
|
|
3965
|
+
}
|
|
3966
|
+
function normalizeDiffLimit(limit) {
|
|
3967
|
+
if (typeof limit !== "number" || !Number.isFinite(limit) || limit <= 0) {
|
|
3968
|
+
return DEFAULT_DIFF_LIMIT;
|
|
3969
|
+
}
|
|
3970
|
+
return Math.floor(limit);
|
|
3971
|
+
}
|
|
2333
3972
|
// Annotate the CommonJS export names for ESM import in node:
|
|
2334
3973
|
0 && (module.exports = {
|
|
3974
|
+
EXPRESSION_FUNCTION_VOCABULARY,
|
|
3975
|
+
MACHINE_REPORT_VERSION,
|
|
2335
3976
|
PRIMARY_SLOT_ALIAS,
|
|
2336
3977
|
PRIMARY_SLOT_ID,
|
|
3978
|
+
RESERVED_EXPRESSION_VARIABLES,
|
|
3979
|
+
SCALAR_FUNCTIONS,
|
|
3980
|
+
SCALAR_FUNCTION_VOCABULARY,
|
|
2337
3981
|
addBindingSlot,
|
|
2338
3982
|
bindingFromDefinition,
|
|
2339
|
-
bindingOperatorDefinitions,
|
|
2340
|
-
bindingOperatorTypes,
|
|
2341
3983
|
bindingTargetFromComponent,
|
|
2342
3984
|
bindingTargetFromInput,
|
|
2343
3985
|
bindingToDefinition,
|
|
3986
|
+
buildCanonicalBindingExpression,
|
|
3987
|
+
buildMachineReport,
|
|
2344
3988
|
buildRigGraphSpec,
|
|
2345
3989
|
collectExpressionReferences,
|
|
3990
|
+
compileIrGraph,
|
|
2346
3991
|
createDefaultBinding,
|
|
2347
3992
|
createDefaultBindings,
|
|
2348
3993
|
createDefaultInputValues,
|
|
2349
|
-
createDefaultOperatorSettings,
|
|
2350
3994
|
createDefaultParentBinding,
|
|
2351
|
-
|
|
3995
|
+
createExpressionVariableTable,
|
|
3996
|
+
createIrGraphBuilder,
|
|
3997
|
+
createLegacyIrGraph,
|
|
3998
|
+
diffMachineReports,
|
|
2352
3999
|
ensureBindingStructure,
|
|
2353
|
-
ensureOperatorParams,
|
|
2354
|
-
getBindingOperatorDefinition,
|
|
2355
4000
|
getPrimaryBindingSlot,
|
|
2356
4001
|
mapExpression,
|
|
2357
4002
|
parseControlExpression,
|
|
2358
4003
|
reconcileBindings,
|
|
2359
|
-
remapValue,
|
|
2360
4004
|
removeBindingSlot,
|
|
2361
|
-
|
|
4005
|
+
toIrBindingSummary,
|
|
2362
4006
|
updateBindingExpression,
|
|
2363
|
-
updateBindingOperatorParam,
|
|
2364
4007
|
updateBindingSlotAlias,
|
|
2365
|
-
|
|
4008
|
+
updateBindingSlotValueType,
|
|
2366
4009
|
updateBindingWithInput
|
|
2367
4010
|
});
|