@kaskad/core 0.0.6 → 0.0.8
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/fesm2022/kaskad-core.mjs
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
export * from '@kaskad/types';
|
|
2
2
|
import { DefinitionStore } from '@kaskad/definition';
|
|
3
3
|
export * from '@kaskad/definition';
|
|
4
|
-
import { isObject, loadTemplates, templateRegistry, unfoldNodeSchema
|
|
4
|
+
import { unfoldComponentDefinitions, isObject, loadTemplates, templateRegistry, unfoldNodeSchema } from '@kaskad/schema';
|
|
5
5
|
export { loadTemplates, templateRegistry, unfoldComponentDefinitions, unfoldNodeSchema } from '@kaskad/schema';
|
|
6
|
-
import {
|
|
6
|
+
import { FunctionExecutionStateBuilder, FunctionRegistry, evaluateNode, wrapImperativeAsReactive } from '@kaskad/eval-tree';
|
|
7
7
|
export { FunctionRegistry } from '@kaskad/eval-tree';
|
|
8
8
|
import { ComponentTreeApi, ComponentStore, getComponent, componentTreeConfig } from '@kaskad/component-tree';
|
|
9
9
|
export { ComponentStore, ComponentTreeApi, createRootNode } from '@kaskad/component-tree';
|
|
10
|
-
import { reaction, comparer, runInAction, when,
|
|
10
|
+
import { computed, reaction, comparer, runInAction, when, isComputed } from 'mobx';
|
|
11
11
|
import { log, Delimiters } from '@kaskad/config';
|
|
12
12
|
import { parseFormula } from '@kaskad/formula-parser';
|
|
13
13
|
import { Observable, firstValueFrom } from 'rxjs';
|
|
@@ -46,1663 +46,2046 @@ class TemplateLoadingTracker {
|
|
|
46
46
|
// Export a singleton instance for tracking template loading operations
|
|
47
47
|
const templateLoadingTracker = new TemplateLoadingTracker();
|
|
48
48
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
args: [
|
|
57
|
-
{
|
|
58
|
-
type: 'value',
|
|
59
|
-
value: astNode.name,
|
|
60
|
-
},
|
|
61
|
-
],
|
|
62
|
-
});
|
|
63
|
-
const lowerIdentifier = (astNode) => ({
|
|
64
|
-
type: 'value',
|
|
65
|
-
value: astNode.name,
|
|
66
|
-
});
|
|
67
|
-
const lowerArray = (astNode) => ({
|
|
68
|
-
type: 'array',
|
|
69
|
-
items: astNode.items.map(lowerFormulaAstNode),
|
|
70
|
-
});
|
|
71
|
-
const lowerObject = (astNode) => ({
|
|
72
|
-
type: 'object',
|
|
73
|
-
properties: astNode.properties.map(({ key, value }) => ({
|
|
74
|
-
key: lowerFormulaAstNode(key),
|
|
75
|
-
value: lowerFormulaAstNode(value),
|
|
76
|
-
})),
|
|
77
|
-
});
|
|
78
|
-
const lowerFunction = (astNode) => ({
|
|
79
|
-
type: 'function',
|
|
80
|
-
name: astNode.name,
|
|
81
|
-
args: astNode.args.map(lowerFormulaAstNode),
|
|
49
|
+
function execute$U(_ctx, ms) {
|
|
50
|
+
return new Promise((resolve) => setTimeout(() => resolve(), ms));
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
var delay$1 = /*#__PURE__*/Object.freeze({
|
|
54
|
+
__proto__: null,
|
|
55
|
+
execute: execute$U
|
|
82
56
|
});
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
}
|
|
87
|
-
return {
|
|
88
|
-
type: 'function',
|
|
89
|
-
name: 'not',
|
|
90
|
-
args: [lowerFormulaAstNode(astNode.operand)],
|
|
91
|
-
};
|
|
92
|
-
};
|
|
93
|
-
const lowerGroup = (astNode) => lowerFormulaAstNode(astNode.item);
|
|
94
|
-
const lowerTernary = (astNode) => {
|
|
95
|
-
if (!astNode.thenBranch || !astNode.elseBranch) {
|
|
96
|
-
throw new Error('Ternary expression must have both then and else branches');
|
|
97
|
-
}
|
|
98
|
-
return {
|
|
99
|
-
type: 'function',
|
|
100
|
-
name: 'if',
|
|
101
|
-
args: [
|
|
102
|
-
lowerFormulaAstNode(astNode.condition),
|
|
103
|
-
lowerFormulaAstNode(astNode.thenBranch),
|
|
104
|
-
lowerFormulaAstNode(astNode.elseBranch),
|
|
105
|
-
],
|
|
106
|
-
};
|
|
57
|
+
|
|
58
|
+
const commands$1 = {
|
|
59
|
+
delay: delay$1,
|
|
107
60
|
};
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Variadic AND function with short-circuit evaluation.
|
|
64
|
+
* Stops at the first falsy value.
|
|
65
|
+
*/
|
|
66
|
+
const and = {
|
|
67
|
+
kind: 'reactive',
|
|
68
|
+
execute: (args) => {
|
|
69
|
+
if (args.length === 0) {
|
|
70
|
+
throw new Error('and requires at least 1 argument');
|
|
71
|
+
}
|
|
72
|
+
return computed(() => {
|
|
73
|
+
const state = new FunctionExecutionStateBuilder();
|
|
74
|
+
for (const argComputed of args) {
|
|
75
|
+
const argState = argComputed.get();
|
|
76
|
+
const earlyReturn = state.checkReady(argState);
|
|
77
|
+
if (earlyReturn)
|
|
78
|
+
return earlyReturn;
|
|
79
|
+
if (!argState.value) {
|
|
80
|
+
return state.success(false);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return state.success(true);
|
|
84
|
+
});
|
|
85
|
+
},
|
|
86
|
+
signature: '(...unknown) => boolean',
|
|
117
87
|
};
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
minus: (astNode) => lowerBinaryOperation(astNode),
|
|
130
|
-
eq: (astNode) => lowerBinaryOperation(astNode),
|
|
131
|
-
neq: (astNode) => lowerBinaryOperation(astNode),
|
|
132
|
-
gt: (astNode) => lowerBinaryOperation(astNode),
|
|
133
|
-
lt: (astNode) => lowerBinaryOperation(astNode),
|
|
134
|
-
gte: (astNode) => lowerBinaryOperation(astNode),
|
|
135
|
-
lte: (astNode) => lowerBinaryOperation(astNode),
|
|
136
|
-
group: (astNode) => lowerGroup(astNode),
|
|
137
|
-
ternary: (astNode) => lowerTernary(astNode),
|
|
88
|
+
|
|
89
|
+
function execute$T(source, path) {
|
|
90
|
+
const takeDeep = (source, path) => path.reduce((current, step) => {
|
|
91
|
+
return current?.[step];
|
|
92
|
+
}, source);
|
|
93
|
+
return source.map((element) => takeDeep(element, path));
|
|
94
|
+
}
|
|
95
|
+
const arrayPluck = {
|
|
96
|
+
kind: 'imperative',
|
|
97
|
+
execute: execute$T,
|
|
98
|
+
signature: '(unknown{}[], string[]) => unknown',
|
|
138
99
|
};
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
return lowerer(astNode);
|
|
143
|
-
}
|
|
144
|
-
throw new Error(`Unsupported Formula AST node type: ${astNode.type}`);
|
|
100
|
+
|
|
101
|
+
function execute$S(value, index) {
|
|
102
|
+
return value[index];
|
|
145
103
|
}
|
|
104
|
+
const at = {
|
|
105
|
+
kind: 'imperative',
|
|
106
|
+
execute: execute$S,
|
|
107
|
+
signature: '(unknown[], number) => unknown',
|
|
108
|
+
};
|
|
146
109
|
|
|
147
|
-
function
|
|
148
|
-
|
|
149
|
-
try {
|
|
150
|
-
formulaAst = parseFormula(formula);
|
|
151
|
-
}
|
|
152
|
-
catch (e) {
|
|
153
|
-
log.trace(e);
|
|
154
|
-
return { type: 'value', value: null };
|
|
155
|
-
}
|
|
156
|
-
return lowerFormulaAstNode(formulaAst);
|
|
110
|
+
function execute$R(value) {
|
|
111
|
+
return Boolean(value);
|
|
157
112
|
}
|
|
113
|
+
const bool = {
|
|
114
|
+
kind: 'imperative',
|
|
115
|
+
execute: execute$R,
|
|
116
|
+
signature: '(unknown) => boolean',
|
|
117
|
+
};
|
|
158
118
|
|
|
159
|
-
function
|
|
160
|
-
|
|
161
|
-
const evalNode = lowerFormula(`propArray('${componentSelector}', '${valueProp}')`);
|
|
162
|
-
if (!node.position.componentId) {
|
|
163
|
-
throw new Error('Node does not have a component context');
|
|
164
|
-
}
|
|
165
|
-
const { computed, disposers } = evaluateNode(evalNode, {
|
|
166
|
-
componentId: node.position.componentId,
|
|
167
|
-
});
|
|
168
|
-
node.disposers.push(...disposers);
|
|
169
|
-
const disposer = reaction(() => [
|
|
170
|
-
node.extractedValue,
|
|
171
|
-
ComponentTreeApi.findComponentsIds(component.id, componentSelector),
|
|
172
|
-
computed.get(),
|
|
173
|
-
], ([value, componentsIds, evalState], prev) => {
|
|
174
|
-
let newValue;
|
|
175
|
-
if (!prev) {
|
|
176
|
-
// first run
|
|
177
|
-
if (value && value.length > 0) {
|
|
178
|
-
newValue = [...value];
|
|
179
|
-
}
|
|
180
|
-
else {
|
|
181
|
-
newValue = evalState.value;
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
else {
|
|
185
|
-
if (!comparer.structural(value, prev[0])) {
|
|
186
|
-
// console.log('100', JSON.stringify(value), JSON.stringify(prev[0]));
|
|
187
|
-
newValue = value ? [...value] : [];
|
|
188
|
-
}
|
|
189
|
-
else {
|
|
190
|
-
// console.log('200');
|
|
191
|
-
newValue = [...evalState.value];
|
|
192
|
-
if (value && evalState.value.length > prev[2].value.length) {
|
|
193
|
-
newValue = [...value];
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
// console.log(JSON.stringify(newValue));
|
|
198
|
-
const components = componentsIds.map((id) => ComponentStore.getInstance().getComponentOrThrow(id));
|
|
199
|
-
runInAction(() => {
|
|
200
|
-
const store = ComponentStore.getInstance();
|
|
201
|
-
store.setNodeRawSchema(node, newValue);
|
|
202
|
-
for (let i = 0; i < components.length; i++) {
|
|
203
|
-
const c = components[i];
|
|
204
|
-
const value = newValue[i];
|
|
205
|
-
const valueNode = c.getNode(valueProp);
|
|
206
|
-
store.setNodeRawSchema(valueNode, value);
|
|
207
|
-
}
|
|
208
|
-
});
|
|
209
|
-
}, { fireImmediately: true, equals: comparer.structural });
|
|
210
|
-
node.disposers.push(disposer);
|
|
119
|
+
function execute$Q(value) {
|
|
120
|
+
return Math.ceil(value);
|
|
211
121
|
}
|
|
122
|
+
const ceil = {
|
|
123
|
+
kind: 'imperative',
|
|
124
|
+
execute: execute$Q,
|
|
125
|
+
signature: '(number) => number',
|
|
126
|
+
};
|
|
212
127
|
|
|
213
|
-
function
|
|
214
|
-
|
|
215
|
-
let targetNode;
|
|
216
|
-
try {
|
|
217
|
-
// For Facade components, start lookup from parent. This handles inline bindings
|
|
218
|
-
// on template contract variables, where the Facade has a variable with the same
|
|
219
|
-
// name - we need to find the parent's variable, not self.
|
|
220
|
-
const lookupFromId = component.componentType === 'sys.Facade' ? component.position.componentId : component.id;
|
|
221
|
-
if (!lookupFromId) {
|
|
222
|
-
log.error(`Cannot activate mirror binding: no parent component for selector "${cfg.selector}"`);
|
|
223
|
-
return;
|
|
224
|
-
}
|
|
225
|
-
targetNode = store.getNode(lookupFromId, cfg.selector);
|
|
226
|
-
}
|
|
227
|
-
catch (error) {
|
|
228
|
-
log.error(`Cannot activate mirror binding: ${error}`);
|
|
229
|
-
return;
|
|
230
|
-
}
|
|
231
|
-
const disposer = reaction(() => [targetNode.extractedValue, node.extractedValue], (curr, prev) => {
|
|
232
|
-
const [targetValue, sourceValue = null] = curr;
|
|
233
|
-
const [prevTargetValue, prevSourceValue] = prev || [null, null];
|
|
234
|
-
if (comparer.structural(targetValue, sourceValue)) {
|
|
235
|
-
return;
|
|
236
|
-
}
|
|
237
|
-
if (!prev && targetValue !== null) {
|
|
238
|
-
store.setNodeRawSchema(node, targetValue);
|
|
239
|
-
return;
|
|
240
|
-
}
|
|
241
|
-
if (targetValue !== prevTargetValue) {
|
|
242
|
-
store.setNodeRawSchema(node, targetValue);
|
|
243
|
-
return;
|
|
244
|
-
}
|
|
245
|
-
if (sourceValue !== prevSourceValue) {
|
|
246
|
-
store.setNodeRawSchema(targetNode, sourceValue);
|
|
247
|
-
}
|
|
248
|
-
}, { fireImmediately: true });
|
|
249
|
-
node.disposers.push(disposer);
|
|
128
|
+
function execute$P(strings, separator = '') {
|
|
129
|
+
return strings.join(separator);
|
|
250
130
|
}
|
|
131
|
+
const concat = {
|
|
132
|
+
kind: 'imperative',
|
|
133
|
+
execute: execute$P,
|
|
134
|
+
signature: '(unknown[], string) => string',
|
|
135
|
+
};
|
|
251
136
|
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
const disposer = reaction(() => [
|
|
264
|
-
node.extractedValue,
|
|
265
|
-
ComponentTreeApi.findComponentsIds(component.id, componentSelector),
|
|
266
|
-
computed.get(),
|
|
267
|
-
], ([nodeValue, componentsIds, evalState], prev) => {
|
|
268
|
-
const currentValue = nodeValue || {};
|
|
269
|
-
if (comparer.structural(evalState.value, currentValue)) {
|
|
270
|
-
return;
|
|
271
|
-
}
|
|
272
|
-
const firstRun = !prev;
|
|
273
|
-
const nodeChanged = !firstRun && !comparer.structural(nodeValue, prev[0]);
|
|
274
|
-
if (firstRun || nodeChanged) {
|
|
275
|
-
preservedNodeValue = currentValue;
|
|
276
|
-
}
|
|
277
|
-
else {
|
|
278
|
-
preservedNodeValue = shallowMerge(preservedNodeValue, evalState.value);
|
|
279
|
-
}
|
|
280
|
-
let componentValues;
|
|
281
|
-
if (firstRun) {
|
|
282
|
-
const hasInitialValue = Object.keys(currentValue).length > 0;
|
|
283
|
-
componentValues = hasInitialValue
|
|
284
|
-
? syncNodeValueAndComponents$1(currentValue, evalState)
|
|
285
|
-
: { ...evalState.value };
|
|
286
|
-
}
|
|
287
|
-
else if (nodeChanged) {
|
|
288
|
-
componentValues = syncNodeValueAndComponents$1(currentValue, evalState);
|
|
289
|
-
}
|
|
290
|
-
else {
|
|
291
|
-
componentValues = handleComponentsChanged(evalState, preservedNodeValue);
|
|
292
|
-
}
|
|
293
|
-
runInAction(() => {
|
|
294
|
-
const store = ComponentStore.getInstance();
|
|
295
|
-
store.setNodeRawSchema(node, componentValues);
|
|
296
|
-
updateComponentsValues$1(componentsIds, componentValues, keyProp, valueProp);
|
|
297
|
-
});
|
|
298
|
-
}, { fireImmediately: true, equals: comparer.structural });
|
|
299
|
-
node.disposers.push(disposer);
|
|
137
|
+
const execute$O = (value) => {
|
|
138
|
+
return new Promise((resolve) => setTimeout(() => resolve(value), 500));
|
|
139
|
+
};
|
|
140
|
+
const delay = {
|
|
141
|
+
kind: 'imperative',
|
|
142
|
+
execute: execute$O,
|
|
143
|
+
signature: '(unknown) => unknown',
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
function execute$N(num1, num2) {
|
|
147
|
+
return num1 / num2;
|
|
300
148
|
}
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
componentValues[inputKey] = currentValue ?? preservedValue;
|
|
310
|
-
}
|
|
311
|
-
return componentValues;
|
|
149
|
+
const divide = {
|
|
150
|
+
kind: 'imperative',
|
|
151
|
+
execute: execute$N,
|
|
152
|
+
signature: '(number, number) => number',
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
function execute$M(items) {
|
|
156
|
+
return items.length === 0;
|
|
312
157
|
}
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
}
|
|
322
|
-
merged[key] = preservedValue[key];
|
|
323
|
-
}
|
|
324
|
-
return merged;
|
|
158
|
+
const empty = {
|
|
159
|
+
kind: 'imperative',
|
|
160
|
+
execute: execute$M,
|
|
161
|
+
signature: '(unknown[]) => boolean',
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
function execute$L(object) {
|
|
165
|
+
return Object.keys(object).length === 0;
|
|
325
166
|
}
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
167
|
+
const emptyObject = {
|
|
168
|
+
kind: 'imperative',
|
|
169
|
+
execute: execute$L,
|
|
170
|
+
signature: '(unknown{}) => boolean',
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
const execute$K = (a, b) => a === b;
|
|
174
|
+
const eq = {
|
|
175
|
+
kind: 'imperative',
|
|
176
|
+
execute: execute$K,
|
|
177
|
+
signature: '(unknown, unknown) => boolean',
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
function execute$J(items) {
|
|
181
|
+
return items.every((item) => !!item);
|
|
336
182
|
}
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
183
|
+
const every = {
|
|
184
|
+
kind: 'imperative',
|
|
185
|
+
execute: execute$J,
|
|
186
|
+
signature: '(unknown[]) => boolean',
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
function execute$I(array, allowedValues) {
|
|
190
|
+
if (!allowedValues) {
|
|
191
|
+
return [];
|
|
192
|
+
}
|
|
193
|
+
if (allowedValues instanceof Set) {
|
|
194
|
+
return array.filter((item) => allowedValues.has(item));
|
|
347
195
|
}
|
|
196
|
+
return array.filter((item) => allowedValues.includes(item));
|
|
348
197
|
}
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
198
|
+
const filterIn = {
|
|
199
|
+
kind: 'imperative',
|
|
200
|
+
execute: execute$I,
|
|
201
|
+
signature: '(unknown[], unknown[]) => unknown[]',
|
|
202
|
+
};
|
|
203
|
+
|
|
204
|
+
function execute$H(collection, key, values) {
|
|
205
|
+
return values
|
|
206
|
+
.map((value) => collection.find((element) => element[key] === value))
|
|
207
|
+
.filter((item) => item !== undefined);
|
|
208
|
+
}
|
|
209
|
+
const findAllBy = {
|
|
210
|
+
kind: 'imperative',
|
|
211
|
+
execute: execute$H,
|
|
212
|
+
signature: '(unknown{}[], string, unknown[]) => unknown{}[]',
|
|
213
|
+
};
|
|
214
|
+
|
|
215
|
+
function execute$G(collection, key, value) {
|
|
216
|
+
const found = collection.find((element) => element[key] === value);
|
|
217
|
+
return found || null;
|
|
218
|
+
}
|
|
219
|
+
const findBy = {
|
|
220
|
+
kind: 'imperative',
|
|
221
|
+
execute: execute$G,
|
|
222
|
+
signature: '(unknown{}[], string, unknown) => unknown',
|
|
223
|
+
};
|
|
224
|
+
|
|
225
|
+
function execute$F(array) {
|
|
226
|
+
return array.flat();
|
|
227
|
+
}
|
|
228
|
+
const flatten = {
|
|
229
|
+
kind: 'imperative',
|
|
230
|
+
execute: execute$F,
|
|
231
|
+
signature: '(unknown[][]) => unknown[]',
|
|
232
|
+
};
|
|
233
|
+
|
|
234
|
+
function execute$E(value) {
|
|
235
|
+
return Math.floor(value);
|
|
236
|
+
}
|
|
237
|
+
const floor = {
|
|
238
|
+
kind: 'imperative',
|
|
239
|
+
execute: execute$E,
|
|
240
|
+
signature: '(number) => number',
|
|
241
|
+
};
|
|
242
|
+
|
|
243
|
+
const execute$D = (a, b) => a > b;
|
|
244
|
+
const gt = {
|
|
245
|
+
kind: 'imperative',
|
|
246
|
+
execute: execute$D,
|
|
247
|
+
signature: '(number, number) => boolean',
|
|
248
|
+
};
|
|
249
|
+
|
|
250
|
+
const execute$C = (a, b) => a >= b;
|
|
251
|
+
const gte = {
|
|
252
|
+
kind: 'imperative',
|
|
253
|
+
execute: execute$C,
|
|
254
|
+
signature: '(number, number) => boolean',
|
|
255
|
+
};
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* Conditional branching with lazy evaluation.
|
|
259
|
+
* Only evaluates the selected branch.
|
|
260
|
+
*/
|
|
261
|
+
const ifFn = {
|
|
262
|
+
kind: 'reactive',
|
|
263
|
+
execute: (args) => {
|
|
264
|
+
if (args.length !== 3) {
|
|
265
|
+
throw new Error('if requires exactly 3 arguments: condition, trueValue, falseValue');
|
|
358
266
|
}
|
|
359
|
-
|
|
267
|
+
const [conditionComputed, trueComputed, falseComputed] = args;
|
|
268
|
+
return computed(() => {
|
|
269
|
+
const state = new FunctionExecutionStateBuilder();
|
|
270
|
+
const conditionState = conditionComputed.get();
|
|
271
|
+
const earlyReturn = state.checkReady(conditionState);
|
|
272
|
+
if (earlyReturn)
|
|
273
|
+
return earlyReturn;
|
|
274
|
+
const branchState = conditionState.value ? trueComputed.get() : falseComputed.get();
|
|
275
|
+
const branchEarlyReturn = state.checkReady(branchState);
|
|
276
|
+
if (branchEarlyReturn)
|
|
277
|
+
return branchEarlyReturn;
|
|
278
|
+
return state.success(branchState.value);
|
|
279
|
+
});
|
|
280
|
+
},
|
|
281
|
+
signature: '(unknown, unknown, unknown) => unknown',
|
|
282
|
+
};
|
|
283
|
+
|
|
284
|
+
function execute$B(collection, value) {
|
|
285
|
+
if (collection instanceof Set) {
|
|
286
|
+
return collection.has(value);
|
|
360
287
|
}
|
|
361
|
-
return
|
|
288
|
+
return collection.includes(value);
|
|
362
289
|
}
|
|
290
|
+
const inFn = {
|
|
291
|
+
kind: 'imperative',
|
|
292
|
+
execute: execute$B,
|
|
293
|
+
signature: '(unknown[], unknown) => boolean',
|
|
294
|
+
};
|
|
363
295
|
|
|
364
|
-
function
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
if (!node.position.componentId) {
|
|
368
|
-
throw new Error('Node does not have a component context');
|
|
296
|
+
function replacer(_key, value) {
|
|
297
|
+
if (value instanceof Set) {
|
|
298
|
+
return Array.from(value);
|
|
369
299
|
}
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
300
|
+
return value;
|
|
301
|
+
}
|
|
302
|
+
function execute$A(arg) {
|
|
303
|
+
return JSON.stringify(arg, replacer);
|
|
304
|
+
}
|
|
305
|
+
const json = {
|
|
306
|
+
kind: 'imperative',
|
|
307
|
+
execute: execute$A,
|
|
308
|
+
signature: '(unknown) => string',
|
|
309
|
+
};
|
|
310
|
+
|
|
311
|
+
function execute$z(object) {
|
|
312
|
+
return Object.keys(object);
|
|
313
|
+
}
|
|
314
|
+
const keys = {
|
|
315
|
+
kind: 'imperative',
|
|
316
|
+
execute: execute$z,
|
|
317
|
+
signature: '(unknown{}) => string[]',
|
|
318
|
+
};
|
|
319
|
+
|
|
320
|
+
function execute$y(value) {
|
|
321
|
+
return value.length;
|
|
322
|
+
}
|
|
323
|
+
const length = {
|
|
324
|
+
kind: 'imperative',
|
|
325
|
+
execute: execute$y,
|
|
326
|
+
signature: '(unknown[]) => number',
|
|
327
|
+
};
|
|
328
|
+
|
|
329
|
+
const execute$x = (a, b) => a < b;
|
|
330
|
+
const lt = {
|
|
331
|
+
kind: 'imperative',
|
|
332
|
+
execute: execute$x,
|
|
333
|
+
signature: '(number, number) => boolean',
|
|
334
|
+
};
|
|
335
|
+
|
|
336
|
+
const execute$w = (a, b) => a <= b;
|
|
337
|
+
const lte = {
|
|
338
|
+
kind: 'imperative',
|
|
339
|
+
execute: execute$w,
|
|
340
|
+
signature: '(number, number) => boolean',
|
|
341
|
+
};
|
|
342
|
+
|
|
343
|
+
function execute$v(num, delta) {
|
|
344
|
+
return num - delta;
|
|
345
|
+
}
|
|
346
|
+
const minus = {
|
|
347
|
+
kind: 'imperative',
|
|
348
|
+
execute: execute$v,
|
|
349
|
+
signature: '(number, number) => number',
|
|
350
|
+
};
|
|
351
|
+
|
|
352
|
+
function execute$u(a, b) {
|
|
353
|
+
return a % b;
|
|
354
|
+
}
|
|
355
|
+
const modulo = {
|
|
356
|
+
kind: 'imperative',
|
|
357
|
+
execute: execute$u,
|
|
358
|
+
signature: '(number, number) => number',
|
|
359
|
+
};
|
|
360
|
+
|
|
361
|
+
function execute$t(num1, num2) {
|
|
362
|
+
return num1 * num2;
|
|
363
|
+
}
|
|
364
|
+
const multiply = {
|
|
365
|
+
kind: 'imperative',
|
|
366
|
+
execute: execute$t,
|
|
367
|
+
signature: '(number, number) => number',
|
|
368
|
+
};
|
|
369
|
+
|
|
370
|
+
function execute$s(num) {
|
|
371
|
+
return -num;
|
|
372
|
+
}
|
|
373
|
+
const negate = {
|
|
374
|
+
kind: 'imperative',
|
|
375
|
+
execute: execute$s,
|
|
376
|
+
signature: '(number) => number',
|
|
377
|
+
};
|
|
378
|
+
|
|
379
|
+
const execute$r = (a, b) => a !== b;
|
|
380
|
+
const neq = {
|
|
381
|
+
kind: 'imperative',
|
|
382
|
+
execute: execute$r,
|
|
383
|
+
signature: '(unknown, unknown) => boolean',
|
|
384
|
+
};
|
|
385
|
+
|
|
386
|
+
function execute$q(value) {
|
|
387
|
+
return !value;
|
|
388
|
+
}
|
|
389
|
+
const not = {
|
|
390
|
+
kind: 'imperative',
|
|
391
|
+
execute: execute$q,
|
|
392
|
+
signature: '(unknown) => boolean',
|
|
393
|
+
};
|
|
394
|
+
|
|
395
|
+
/**
|
|
396
|
+
* Null coalescing with lazy evaluation.
|
|
397
|
+
* Returns left if non-null, otherwise evaluates and returns right.
|
|
398
|
+
*/
|
|
399
|
+
const nullCoalesce = {
|
|
400
|
+
kind: 'reactive',
|
|
401
|
+
execute: (args) => {
|
|
402
|
+
if (args.length !== 2) {
|
|
403
|
+
throw new Error('nullCoalesce requires exactly 2 arguments');
|
|
395
404
|
}
|
|
396
|
-
|
|
397
|
-
|
|
405
|
+
const [leftComputed, rightComputed] = args;
|
|
406
|
+
return computed(() => {
|
|
407
|
+
const state = new FunctionExecutionStateBuilder();
|
|
408
|
+
const leftState = leftComputed.get();
|
|
409
|
+
const earlyReturn = state.checkReady(leftState);
|
|
410
|
+
if (earlyReturn)
|
|
411
|
+
return earlyReturn;
|
|
412
|
+
if (leftState.value != null) {
|
|
413
|
+
return state.success(leftState.value);
|
|
414
|
+
}
|
|
415
|
+
const rightState = rightComputed.get();
|
|
416
|
+
const rightEarlyReturn = state.checkReady(rightState);
|
|
417
|
+
if (rightEarlyReturn)
|
|
418
|
+
return rightEarlyReturn;
|
|
419
|
+
return state.success(rightState.value);
|
|
420
|
+
});
|
|
421
|
+
},
|
|
422
|
+
signature: '(unknown, unknown) => unknown',
|
|
423
|
+
};
|
|
424
|
+
|
|
425
|
+
function execute$p(value) {
|
|
426
|
+
const number = Number(value);
|
|
427
|
+
if (Number.isNaN(number)) {
|
|
428
|
+
throw new Error(`Cannot convert value ${value} to number`);
|
|
429
|
+
}
|
|
430
|
+
return number;
|
|
431
|
+
}
|
|
432
|
+
const number = {
|
|
433
|
+
kind: 'imperative',
|
|
434
|
+
execute: execute$p,
|
|
435
|
+
signature: '(unknown) => number',
|
|
436
|
+
};
|
|
437
|
+
|
|
438
|
+
function execute$o(parts) {
|
|
439
|
+
const result = {};
|
|
440
|
+
for (let i = 0; i < parts.length; i += 2) {
|
|
441
|
+
const key = parts[i];
|
|
442
|
+
if (typeof key !== 'string') {
|
|
443
|
+
throw new Error(`Invalid key type: ${typeof key}. Expected string`);
|
|
398
444
|
}
|
|
399
|
-
|
|
400
|
-
|
|
445
|
+
result[key] = parts[i + 1];
|
|
446
|
+
}
|
|
447
|
+
return result;
|
|
448
|
+
}
|
|
449
|
+
const objectFn = {
|
|
450
|
+
kind: 'imperative',
|
|
451
|
+
execute: execute$o,
|
|
452
|
+
signature: '(unknown[]) => unknown{}',
|
|
453
|
+
};
|
|
454
|
+
|
|
455
|
+
/**
|
|
456
|
+
* Variadic OR function with short-circuit evaluation.
|
|
457
|
+
* Stops at the first truthy value.
|
|
458
|
+
*/
|
|
459
|
+
const or = {
|
|
460
|
+
kind: 'reactive',
|
|
461
|
+
execute: (args) => {
|
|
462
|
+
if (args.length === 0) {
|
|
463
|
+
throw new Error('or requires at least 1 argument');
|
|
401
464
|
}
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
const
|
|
405
|
-
|
|
406
|
-
|
|
465
|
+
return computed(() => {
|
|
466
|
+
const state = new FunctionExecutionStateBuilder();
|
|
467
|
+
for (const argComputed of args) {
|
|
468
|
+
const argState = argComputed.get();
|
|
469
|
+
const earlyReturn = state.checkReady(argState);
|
|
470
|
+
if (earlyReturn)
|
|
471
|
+
return earlyReturn;
|
|
472
|
+
if (argState.value) {
|
|
473
|
+
return state.success(true);
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
return state.success(false);
|
|
407
477
|
});
|
|
408
|
-
},
|
|
409
|
-
|
|
478
|
+
},
|
|
479
|
+
signature: '(...unknown) => boolean',
|
|
480
|
+
};
|
|
481
|
+
|
|
482
|
+
function execute$n(source, path) {
|
|
483
|
+
return path.reduce((current, step) => {
|
|
484
|
+
return current?.[step];
|
|
485
|
+
}, source);
|
|
410
486
|
}
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
487
|
+
const pluck = {
|
|
488
|
+
kind: 'imperative',
|
|
489
|
+
execute: execute$n,
|
|
490
|
+
signature: '(unknown{}, string[]) => unknown',
|
|
491
|
+
};
|
|
492
|
+
|
|
493
|
+
function execute$m(a, b) {
|
|
494
|
+
return a + b;
|
|
495
|
+
}
|
|
496
|
+
const plus = {
|
|
497
|
+
kind: 'imperative',
|
|
498
|
+
execute: execute$m,
|
|
499
|
+
signature: '(unknown, unknown) => unknown',
|
|
500
|
+
};
|
|
501
|
+
|
|
502
|
+
function execute$l(value, precision = 0) {
|
|
503
|
+
const multiplier = Math.pow(10, precision);
|
|
504
|
+
return Math.round(value * multiplier) / multiplier;
|
|
505
|
+
}
|
|
506
|
+
const round = {
|
|
507
|
+
kind: 'imperative',
|
|
508
|
+
execute: execute$l,
|
|
509
|
+
signature: '(number, number) => number',
|
|
510
|
+
};
|
|
511
|
+
|
|
512
|
+
function execute$k(value, start, end) {
|
|
513
|
+
return value.slice(start, end);
|
|
514
|
+
}
|
|
515
|
+
const slice = {
|
|
516
|
+
kind: 'imperative',
|
|
517
|
+
execute: execute$k,
|
|
518
|
+
signature: '(unknown[], number, number) => unknown[]',
|
|
519
|
+
};
|
|
520
|
+
|
|
521
|
+
function execute$j(items) {
|
|
522
|
+
return items.some((item) => !!item);
|
|
523
|
+
}
|
|
524
|
+
const some = {
|
|
525
|
+
kind: 'imperative',
|
|
526
|
+
execute: execute$j,
|
|
527
|
+
signature: '(unknown[]) => boolean',
|
|
528
|
+
};
|
|
529
|
+
|
|
530
|
+
function execute$i(value) {
|
|
531
|
+
return String(value);
|
|
532
|
+
}
|
|
533
|
+
const string = {
|
|
534
|
+
kind: 'imperative',
|
|
535
|
+
execute: execute$i,
|
|
536
|
+
signature: '(unknown) => string',
|
|
537
|
+
};
|
|
538
|
+
|
|
539
|
+
/**
|
|
540
|
+
* Switch statement with lazy case evaluation.
|
|
541
|
+
* Supports array mode (legacy) and variadic mode.
|
|
542
|
+
*/
|
|
543
|
+
const switchFn = {
|
|
544
|
+
kind: 'reactive',
|
|
545
|
+
execute: (args) => {
|
|
546
|
+
if (args.length < 2) {
|
|
547
|
+
throw new Error('switch requires at least 2 arguments: value and default');
|
|
417
548
|
}
|
|
549
|
+
const valueComputed = args[0];
|
|
550
|
+
return computed(() => {
|
|
551
|
+
const state = new FunctionExecutionStateBuilder();
|
|
552
|
+
const valueState = valueComputed.get();
|
|
553
|
+
const earlyReturn = state.checkReady(valueState);
|
|
554
|
+
if (earlyReturn)
|
|
555
|
+
return earlyReturn;
|
|
556
|
+
const value = valueState.value;
|
|
557
|
+
if (args.length === 3) {
|
|
558
|
+
const casesState = args[1].get();
|
|
559
|
+
const defaultState = args[2].get();
|
|
560
|
+
const casesEarlyReturn = state.checkReady(casesState);
|
|
561
|
+
if (casesEarlyReturn)
|
|
562
|
+
return casesEarlyReturn;
|
|
563
|
+
const defaultEarlyReturn = state.checkReady(defaultState);
|
|
564
|
+
if (defaultEarlyReturn)
|
|
565
|
+
return defaultEarlyReturn;
|
|
566
|
+
const cases = casesState.value;
|
|
567
|
+
if (Array.isArray(cases)) {
|
|
568
|
+
if (cases.length % 2 !== 0) {
|
|
569
|
+
throw new Error('Cases array should have even number of elements');
|
|
570
|
+
}
|
|
571
|
+
const matchIndex = cases.findIndex((caseValue, index) => index % 2 === 0 && caseValue === value);
|
|
572
|
+
const returnValue = matchIndex >= 0 ? cases[matchIndex + 1] : defaultState.value;
|
|
573
|
+
return state.success(returnValue);
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
const defaultComputed = args[args.length - 1];
|
|
577
|
+
const caseArgs = args.slice(1, -1);
|
|
578
|
+
if (caseArgs.length % 2 !== 0) {
|
|
579
|
+
throw new Error('switch requires an even number of case arguments (key-value pairs)');
|
|
580
|
+
}
|
|
581
|
+
for (let i = 0; i < caseArgs.length; i += 2) {
|
|
582
|
+
const caseKeyComputed = caseArgs[i];
|
|
583
|
+
const caseValueComputed = caseArgs[i + 1];
|
|
584
|
+
const caseKeyState = caseKeyComputed.get();
|
|
585
|
+
const keyEarlyReturn = state.checkReady(caseKeyState);
|
|
586
|
+
if (keyEarlyReturn)
|
|
587
|
+
return keyEarlyReturn;
|
|
588
|
+
const caseKey = caseKeyState.value;
|
|
589
|
+
if (caseKey === value) {
|
|
590
|
+
const caseValueState = caseValueComputed.get();
|
|
591
|
+
const valueEarlyReturn = state.checkReady(caseValueState);
|
|
592
|
+
if (valueEarlyReturn)
|
|
593
|
+
return valueEarlyReturn;
|
|
594
|
+
return state.success(caseValueState.value);
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
const defaultState = defaultComputed.get();
|
|
598
|
+
const defaultEarlyReturn = state.checkReady(defaultState);
|
|
599
|
+
if (defaultEarlyReturn)
|
|
600
|
+
return defaultEarlyReturn;
|
|
601
|
+
return state.success(defaultState.value);
|
|
602
|
+
});
|
|
603
|
+
},
|
|
604
|
+
signature: '(...unknown) => unknown',
|
|
605
|
+
};
|
|
606
|
+
|
|
607
|
+
function execute$h(value) {
|
|
608
|
+
return value.toLowerCase();
|
|
609
|
+
}
|
|
610
|
+
const toLowerCase = {
|
|
611
|
+
kind: 'imperative',
|
|
612
|
+
execute: execute$h,
|
|
613
|
+
signature: '(string) => string',
|
|
614
|
+
};
|
|
615
|
+
|
|
616
|
+
function execute$g(value) {
|
|
617
|
+
return value.toUpperCase();
|
|
618
|
+
}
|
|
619
|
+
const toUpperCase = {
|
|
620
|
+
kind: 'imperative',
|
|
621
|
+
execute: execute$g,
|
|
622
|
+
signature: '(string) => string',
|
|
623
|
+
};
|
|
624
|
+
|
|
625
|
+
/**
|
|
626
|
+
* Shared utility formula functions.
|
|
627
|
+
*
|
|
628
|
+
* Control flow functions use reactive implementations with lazy evaluation:
|
|
629
|
+
* - `if`: Conditional evaluation (3 args: condition, trueValue, falseValue)
|
|
630
|
+
* - `and`, `or`: Variadic logical operators with short-circuit evaluation
|
|
631
|
+
* - `switch`: Variadic pattern matching with lazy case evaluation
|
|
632
|
+
* - `some`, `every`: Array element checkers (imperative, not lazy)
|
|
633
|
+
*/
|
|
634
|
+
const formulaFunctions$2 = {
|
|
635
|
+
// Collection functions
|
|
636
|
+
findBy,
|
|
637
|
+
findAllBy,
|
|
638
|
+
at,
|
|
639
|
+
not,
|
|
640
|
+
// Array element checkers (imperative)
|
|
641
|
+
some,
|
|
642
|
+
every,
|
|
643
|
+
// Control flow (reactive with lazy evaluation)
|
|
644
|
+
if: ifFn,
|
|
645
|
+
and,
|
|
646
|
+
or,
|
|
647
|
+
nullCoalesce,
|
|
648
|
+
switch: switchFn,
|
|
649
|
+
// Utilities
|
|
650
|
+
in: inFn,
|
|
651
|
+
object: objectFn,
|
|
652
|
+
bool,
|
|
653
|
+
length,
|
|
654
|
+
empty,
|
|
655
|
+
concat,
|
|
656
|
+
pluck,
|
|
657
|
+
flatten,
|
|
658
|
+
json,
|
|
659
|
+
minus,
|
|
660
|
+
modulo,
|
|
661
|
+
negate,
|
|
662
|
+
plus,
|
|
663
|
+
divide,
|
|
664
|
+
multiply,
|
|
665
|
+
emptyObject,
|
|
666
|
+
arrayPluck,
|
|
667
|
+
string,
|
|
668
|
+
number,
|
|
669
|
+
delay,
|
|
670
|
+
keys,
|
|
671
|
+
toUpperCase,
|
|
672
|
+
toLowerCase,
|
|
673
|
+
ceil,
|
|
674
|
+
floor,
|
|
675
|
+
round,
|
|
676
|
+
slice,
|
|
677
|
+
filterIn,
|
|
678
|
+
eq,
|
|
679
|
+
neq,
|
|
680
|
+
gt,
|
|
681
|
+
lt,
|
|
682
|
+
gte,
|
|
683
|
+
lte,
|
|
684
|
+
};
|
|
685
|
+
|
|
686
|
+
const common = {
|
|
687
|
+
commands: commands$1,
|
|
688
|
+
functions: formulaFunctions$2,
|
|
689
|
+
};
|
|
690
|
+
|
|
691
|
+
function registerPlugin(plugin) {
|
|
692
|
+
const defStore = DefinitionStore.getInstance();
|
|
693
|
+
// setup() may register shapes/variant shapes needed by definitions
|
|
694
|
+
if (plugin.setup) {
|
|
695
|
+
plugin.setup();
|
|
418
696
|
}
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
697
|
+
// Shapes must be registered before definitions (definitions reference shape types)
|
|
698
|
+
if (plugin.shapes) {
|
|
699
|
+
for (const [shapeType, properties] of Object.entries(plugin.shapes)) {
|
|
700
|
+
defStore.setShape(shapeType, properties);
|
|
422
701
|
}
|
|
423
702
|
}
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
function syncComponentsAndPreserved(evalState, preservedNodeValue, currentValue) {
|
|
427
|
-
const componentValues = { ...evalState.value };
|
|
428
|
-
if (preservedNodeValue) {
|
|
429
|
-
for (const key of Object.keys(evalState.value)) {
|
|
430
|
-
if (evalState.value[key] === null) {
|
|
431
|
-
componentValues[key] = preservedNodeValue[key] ?? false;
|
|
432
|
-
}
|
|
433
|
-
}
|
|
434
|
-
// Preserve selection for components being recreated
|
|
435
|
-
for (const key of Object.keys(preservedNodeValue)) {
|
|
436
|
-
if (!(key in componentValues)) {
|
|
437
|
-
componentValues[key] = preservedNodeValue[key];
|
|
438
|
-
}
|
|
439
|
-
}
|
|
703
|
+
if (plugin.definitions) {
|
|
704
|
+
defStore.setComponents(unfoldComponentDefinitions(plugin.definitions));
|
|
440
705
|
}
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
if (!(key in componentValues)) {
|
|
444
|
-
componentValues[key] = currentValue[key];
|
|
445
|
-
}
|
|
706
|
+
if (plugin.commands) {
|
|
707
|
+
defStore.setCommands(plugin.commands);
|
|
446
708
|
}
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
function updateComponentsValues(componentsIds, componentValues, keyProp, valueProp) {
|
|
450
|
-
const store = ComponentStore.getInstance();
|
|
451
|
-
const components = componentsIds.map((id) => store.getComponentOrThrow(id));
|
|
452
|
-
for (const cmp of components) {
|
|
453
|
-
const key = cmp.getNodeValue(keyProp);
|
|
454
|
-
if (!key)
|
|
455
|
-
continue;
|
|
456
|
-
const value = componentValues[key];
|
|
457
|
-
const valueNode = cmp.getNode(valueProp);
|
|
458
|
-
store.setNodeRawSchema(valueNode, value);
|
|
709
|
+
if (plugin.functions) {
|
|
710
|
+
FunctionRegistry.getInstance().setFunctions(plugin.functions);
|
|
459
711
|
}
|
|
460
712
|
}
|
|
461
|
-
function
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
.map(([key]) => key));
|
|
465
|
-
}
|
|
466
|
-
function toObject(selectionSet) {
|
|
467
|
-
return Object.fromEntries(Array.from(selectionSet || []).map((key) => [key, true]));
|
|
468
|
-
}
|
|
469
|
-
|
|
470
|
-
async function addBinding(node, extra = false) {
|
|
471
|
-
await when(() => !node.evaluating);
|
|
472
|
-
const store = ComponentStore.getInstance();
|
|
473
|
-
if (!node.position.componentId) {
|
|
474
|
-
throw new Error('Cannot add binding without component context');
|
|
475
|
-
}
|
|
476
|
-
const component = store.getComponent(node.position.componentId);
|
|
477
|
-
if (!component) {
|
|
478
|
-
return;
|
|
479
|
-
}
|
|
480
|
-
const bindingSchema = extra ? node.extraBinding : node.bindingSchema;
|
|
481
|
-
if (!bindingSchema) {
|
|
482
|
-
return;
|
|
483
|
-
}
|
|
484
|
-
const valueType = node.valueType;
|
|
485
|
-
switch (bindingSchema.bindingType) {
|
|
486
|
-
case 'object':
|
|
487
|
-
bindObject(node, component, {
|
|
488
|
-
componentSelector: bindingSchema.componentSelector,
|
|
489
|
-
keyProp: bindingSchema.mapping.key,
|
|
490
|
-
valueProp: bindingSchema.mapping.value,
|
|
491
|
-
valueType,
|
|
492
|
-
});
|
|
493
|
-
break;
|
|
494
|
-
case 'selection':
|
|
495
|
-
bindSelection(node, component, {
|
|
496
|
-
componentSelector: bindingSchema.componentSelector,
|
|
497
|
-
keyProp: bindingSchema.mapping.key,
|
|
498
|
-
valueProp: bindingSchema.mapping.selected,
|
|
499
|
-
valueType,
|
|
500
|
-
});
|
|
501
|
-
break;
|
|
502
|
-
case 'array':
|
|
503
|
-
bindArray(node, component, {
|
|
504
|
-
componentSelector: bindingSchema.componentSelector,
|
|
505
|
-
valueProp: bindingSchema.mapping.value,
|
|
506
|
-
valueType,
|
|
507
|
-
});
|
|
508
|
-
break;
|
|
509
|
-
case 'mirror':
|
|
510
|
-
bindMirror(component, node, bindingSchema);
|
|
511
|
-
break;
|
|
713
|
+
function registerPlugins(...plugins) {
|
|
714
|
+
for (const plugin of plugins) {
|
|
715
|
+
registerPlugin(plugin);
|
|
512
716
|
}
|
|
513
717
|
}
|
|
514
718
|
|
|
515
|
-
const
|
|
516
|
-
return [position.componentId, position.path.join(Delimiters.NodePath), thing].join('|');
|
|
517
|
-
};
|
|
518
|
-
const componentInstanceMap = new Map();
|
|
519
|
-
|
|
520
|
-
const lowerSimpleValue = (schema) => ({
|
|
719
|
+
const lowerValue = (astNode) => ({
|
|
521
720
|
type: 'value',
|
|
522
|
-
value:
|
|
721
|
+
value: astNode.value,
|
|
523
722
|
});
|
|
524
|
-
const
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
}
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
};
|
|
549
|
-
const
|
|
550
|
-
|
|
551
|
-
|
|
723
|
+
const lowerReference = (astNode) => ({
|
|
724
|
+
type: 'function',
|
|
725
|
+
name: 'get',
|
|
726
|
+
args: [
|
|
727
|
+
{
|
|
728
|
+
type: 'value',
|
|
729
|
+
value: astNode.name,
|
|
730
|
+
},
|
|
731
|
+
],
|
|
732
|
+
});
|
|
733
|
+
const lowerIdentifier = (astNode) => ({
|
|
734
|
+
type: 'value',
|
|
735
|
+
value: astNode.name,
|
|
736
|
+
});
|
|
737
|
+
const lowerArray = (astNode) => ({
|
|
738
|
+
type: 'array',
|
|
739
|
+
items: astNode.items.map(lowerFormulaAstNode),
|
|
740
|
+
});
|
|
741
|
+
const lowerObject = (astNode) => ({
|
|
742
|
+
type: 'object',
|
|
743
|
+
properties: astNode.properties.map(({ key, value }) => ({
|
|
744
|
+
key: lowerFormulaAstNode(key),
|
|
745
|
+
value: lowerFormulaAstNode(value),
|
|
746
|
+
})),
|
|
747
|
+
});
|
|
748
|
+
const lowerFunction = (astNode) => ({
|
|
749
|
+
type: 'function',
|
|
750
|
+
name: astNode.name,
|
|
751
|
+
args: astNode.args.map(lowerFormulaAstNode),
|
|
752
|
+
});
|
|
753
|
+
const lowerNot = (astNode) => {
|
|
754
|
+
if (!astNode.operand) {
|
|
755
|
+
throw new Error('Invert node must have an item');
|
|
552
756
|
}
|
|
553
|
-
const variantShapeValue = schema.value;
|
|
554
|
-
const variantField = `${schema.valueType.shapeType}Type`;
|
|
555
|
-
const entries = Object.entries(variantShapeValue);
|
|
556
|
-
const properties = entries
|
|
557
|
-
.filter(([key]) => key !== 'kind')
|
|
558
|
-
.map(([key, value]) => ({
|
|
559
|
-
key: { type: 'value', value: key },
|
|
560
|
-
value: typeof value === 'string' ? { type: 'value', value } : lowerSchema(value),
|
|
561
|
-
}));
|
|
562
|
-
properties.push({
|
|
563
|
-
key: { type: 'value', value: variantField },
|
|
564
|
-
value: { type: 'value', value: variantShapeValue['kind'] },
|
|
565
|
-
});
|
|
566
757
|
return {
|
|
567
|
-
type: '
|
|
568
|
-
|
|
758
|
+
type: 'function',
|
|
759
|
+
name: 'not',
|
|
760
|
+
args: [lowerFormulaAstNode(astNode.operand)],
|
|
569
761
|
};
|
|
570
762
|
};
|
|
571
|
-
const
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
boolean: lowerSimpleValue,
|
|
575
|
-
unknown: lowerSimpleValue,
|
|
576
|
-
component: lowerSimpleValue,
|
|
577
|
-
command: lowerSimpleValue,
|
|
578
|
-
componentSchema: lowerSimpleValue,
|
|
579
|
-
object: lowerObjectOrMap,
|
|
580
|
-
map: lowerObjectOrMap,
|
|
581
|
-
array: lowerArrayOrSet,
|
|
582
|
-
set: lowerArrayOrSet,
|
|
583
|
-
shape: lowerShape,
|
|
584
|
-
variantShape: lowerVariantShape,
|
|
585
|
-
};
|
|
586
|
-
function lowerSchema(schema) {
|
|
587
|
-
// If schema has a computation, lower it
|
|
588
|
-
if (schema.computation) {
|
|
589
|
-
return lowerComputationSchema(schema.computation);
|
|
590
|
-
}
|
|
591
|
-
// Otherwise lower the value based on valueType
|
|
592
|
-
const lowerer = schemaLowerers[schema.valueType.type];
|
|
593
|
-
if (lowerer) {
|
|
594
|
-
return lowerer(schema);
|
|
763
|
+
const lowerNegate = (astNode) => {
|
|
764
|
+
if (!astNode.operand) {
|
|
765
|
+
throw new Error('Negate node must have an operand');
|
|
595
766
|
}
|
|
596
|
-
throw new Error(`Unsupported value type: ${schema.valueType.type}`);
|
|
597
|
-
}
|
|
598
|
-
|
|
599
|
-
function lowerForLoop(forComputation) {
|
|
600
|
-
const dimensionsNode = {
|
|
601
|
-
type: 'array',
|
|
602
|
-
items: forComputation.dimensions.map((dimension) => {
|
|
603
|
-
// Extract trackBy expression to be evaluated in RefSpace context where $item is available
|
|
604
|
-
let trackByExpression = null;
|
|
605
|
-
if (dimension.trackBy.computation && dimension.trackBy.computation.computationType === 'formula') {
|
|
606
|
-
trackByExpression = `=${dimension.trackBy.computation.formula}`;
|
|
607
|
-
}
|
|
608
|
-
else if (dimension.trackBy.value !== null) {
|
|
609
|
-
trackByExpression = dimension.trackBy.value;
|
|
610
|
-
}
|
|
611
|
-
return {
|
|
612
|
-
type: 'object',
|
|
613
|
-
properties: [
|
|
614
|
-
{ key: { type: 'value', value: 'items' }, value: lowerSchema(dimension.items) },
|
|
615
|
-
{ key: { type: 'value', value: 'itemsType' }, value: { type: 'value', value: dimension.itemsType } },
|
|
616
|
-
{ key: { type: 'value', value: 'item' }, value: lowerSchema(dimension.item) },
|
|
617
|
-
{ key: { type: 'value', value: 'index' }, value: lowerSchema(dimension.index) },
|
|
618
|
-
{ key: { type: 'value', value: 'first' }, value: lowerSchema(dimension.first) },
|
|
619
|
-
{ key: { type: 'value', value: 'last' }, value: lowerSchema(dimension.last) },
|
|
620
|
-
{ key: { type: 'value', value: 'trackBy' }, value: { type: 'value', value: trackByExpression } },
|
|
621
|
-
],
|
|
622
|
-
};
|
|
623
|
-
}),
|
|
624
|
-
};
|
|
625
|
-
const yieldNode = lowerSchema(forComputation.yield);
|
|
626
|
-
return {
|
|
627
|
-
type: 'function',
|
|
628
|
-
name: 'repeat',
|
|
629
|
-
args: [dimensionsNode, yieldNode],
|
|
630
|
-
};
|
|
631
|
-
}
|
|
632
|
-
function lowerTemplate(templateComputation) {
|
|
633
767
|
return {
|
|
634
|
-
type: '
|
|
635
|
-
|
|
768
|
+
type: 'function',
|
|
769
|
+
name: 'negate',
|
|
770
|
+
args: [lowerFormulaAstNode(astNode.operand)],
|
|
636
771
|
};
|
|
637
|
-
}
|
|
638
|
-
|
|
772
|
+
};
|
|
773
|
+
const lowerGroup = (astNode) => lowerFormulaAstNode(astNode.item);
|
|
774
|
+
const lowerTernary = (astNode) => {
|
|
775
|
+
if (!astNode.thenBranch || !astNode.elseBranch) {
|
|
776
|
+
throw new Error('Ternary expression must have both then and else branches');
|
|
777
|
+
}
|
|
639
778
|
return {
|
|
640
779
|
type: 'function',
|
|
641
780
|
name: 'if',
|
|
642
|
-
args: [
|
|
781
|
+
args: [
|
|
782
|
+
lowerFormulaAstNode(astNode.condition),
|
|
783
|
+
lowerFormulaAstNode(astNode.thenBranch),
|
|
784
|
+
lowerFormulaAstNode(astNode.elseBranch),
|
|
785
|
+
],
|
|
643
786
|
};
|
|
644
|
-
}
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
// Build cases array as flat array: [value1, result1, value2, result2, ...]
|
|
649
|
-
// Extract .value from ComponentSchemaNodeSchema to get the actual component schema
|
|
650
|
-
const casesArrayItems = [];
|
|
651
|
-
for (const caseItem of switchComputation.cases) {
|
|
652
|
-
casesArrayItems.push({ type: 'value', value: caseItem.equals });
|
|
653
|
-
// caseItem.then is a ComponentSchemaNodeSchema, extract its .value property
|
|
654
|
-
casesArrayItems.push({ type: 'value', value: caseItem.then.value });
|
|
787
|
+
};
|
|
788
|
+
const lowerBinaryOperation = (astNode) => {
|
|
789
|
+
if (!astNode.right) {
|
|
790
|
+
throw new Error(`Binary operation "${astNode.type}" must have a right operand`);
|
|
655
791
|
}
|
|
656
|
-
const casesArrayNode = {
|
|
657
|
-
type: 'array',
|
|
658
|
-
items: casesArrayItems,
|
|
659
|
-
};
|
|
660
|
-
// Lower the default value - extract .value from ComponentSchemaNodeSchema
|
|
661
|
-
const defaultNode = { type: 'value', value: switchComputation.default.value };
|
|
662
792
|
return {
|
|
663
793
|
type: 'function',
|
|
664
|
-
name:
|
|
665
|
-
args: [
|
|
794
|
+
name: astNode.type,
|
|
795
|
+
args: [lowerFormulaAstNode(astNode.left), lowerFormulaAstNode(astNode.right)],
|
|
666
796
|
};
|
|
667
|
-
}
|
|
668
|
-
const computationLowerers = {
|
|
669
|
-
formula: (schema) => lowerFormula(schema.formula),
|
|
670
|
-
for: (schema) => lowerForLoop(schema),
|
|
671
|
-
template: (schema) => lowerTemplate(schema),
|
|
672
|
-
if: (schema) => lowerIfStatement(schema),
|
|
673
|
-
switch: (schema) => lowerSwitch(schema),
|
|
674
797
|
};
|
|
675
|
-
|
|
676
|
-
|
|
798
|
+
const astNodeLowerers = {
|
|
799
|
+
value: (astNode) => lowerValue(astNode),
|
|
800
|
+
reference: (astNode) => lowerReference(astNode),
|
|
801
|
+
identifier: (astNode) => lowerIdentifier(astNode),
|
|
802
|
+
array: (astNode) => lowerArray(astNode),
|
|
803
|
+
object: (astNode) => lowerObject(astNode),
|
|
804
|
+
function: (astNode) => lowerFunction(astNode),
|
|
805
|
+
not: (astNode) => lowerNot(astNode),
|
|
806
|
+
negate: (astNode) => lowerNegate(astNode),
|
|
807
|
+
multiply: (astNode) => lowerBinaryOperation(astNode),
|
|
808
|
+
divide: (astNode) => lowerBinaryOperation(astNode),
|
|
809
|
+
modulo: (astNode) => lowerBinaryOperation(astNode),
|
|
810
|
+
plus: (astNode) => lowerBinaryOperation(astNode),
|
|
811
|
+
minus: (astNode) => lowerBinaryOperation(astNode),
|
|
812
|
+
eq: (astNode) => lowerBinaryOperation(astNode),
|
|
813
|
+
neq: (astNode) => lowerBinaryOperation(astNode),
|
|
814
|
+
gt: (astNode) => lowerBinaryOperation(astNode),
|
|
815
|
+
lt: (astNode) => lowerBinaryOperation(astNode),
|
|
816
|
+
gte: (astNode) => lowerBinaryOperation(astNode),
|
|
817
|
+
lte: (astNode) => lowerBinaryOperation(astNode),
|
|
818
|
+
and: (astNode) => lowerBinaryOperation(astNode),
|
|
819
|
+
or: (astNode) => lowerBinaryOperation(astNode),
|
|
820
|
+
nullCoalesce: (astNode) => lowerBinaryOperation(astNode),
|
|
821
|
+
group: (astNode) => lowerGroup(astNode),
|
|
822
|
+
ternary: (astNode) => lowerTernary(astNode),
|
|
823
|
+
};
|
|
824
|
+
function lowerFormulaAstNode(astNode) {
|
|
825
|
+
const lowerer = astNodeLowerers[astNode.type];
|
|
677
826
|
if (lowerer) {
|
|
678
|
-
return lowerer(
|
|
827
|
+
return lowerer(astNode);
|
|
679
828
|
}
|
|
680
|
-
throw new Error(`Unsupported
|
|
829
|
+
throw new Error(`Unsupported Formula AST node type: ${astNode.type}`);
|
|
681
830
|
}
|
|
682
831
|
|
|
683
|
-
function
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
throw new Error('Cannot activate for computation: no current frame');
|
|
832
|
+
function lowerFormula(formula) {
|
|
833
|
+
let formulaAst;
|
|
834
|
+
try {
|
|
835
|
+
formulaAst = parseFormula(formula);
|
|
688
836
|
}
|
|
689
|
-
|
|
837
|
+
catch (e) {
|
|
838
|
+
log.trace(e);
|
|
839
|
+
return { type: 'value', value: null };
|
|
840
|
+
}
|
|
841
|
+
return lowerFormulaAstNode(formulaAst);
|
|
842
|
+
}
|
|
843
|
+
|
|
844
|
+
function bindArray(node, component, cfg) {
|
|
845
|
+
const { componentSelector, valueProp } = cfg;
|
|
846
|
+
const evalNode = lowerFormula(`propArray('${componentSelector}', '${valueProp}')`);
|
|
690
847
|
if (!node.position.componentId) {
|
|
691
848
|
throw new Error('Node does not have a component context');
|
|
692
849
|
}
|
|
693
850
|
const { computed, disposers } = evaluateNode(evalNode, {
|
|
694
851
|
componentId: node.position.componentId,
|
|
695
852
|
});
|
|
696
|
-
|
|
697
|
-
const
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
853
|
+
node.disposers.push(...disposers);
|
|
854
|
+
const disposer = reaction(() => [
|
|
855
|
+
node.extractedValue,
|
|
856
|
+
ComponentTreeApi.findComponentsIds(component.id, componentSelector),
|
|
857
|
+
computed.get(),
|
|
858
|
+
], ([value, componentsIds, evalState], prev) => {
|
|
859
|
+
let newValue;
|
|
860
|
+
if (!prev) {
|
|
861
|
+
// first run
|
|
862
|
+
if (value && value.length > 0) {
|
|
863
|
+
newValue = [...value];
|
|
864
|
+
}
|
|
865
|
+
else {
|
|
866
|
+
newValue = evalState.value;
|
|
705
867
|
}
|
|
706
868
|
}
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
function activateArrayStructure(node) {
|
|
713
|
-
const structure = node.structure;
|
|
714
|
-
if (structure === null) {
|
|
715
|
-
return;
|
|
716
|
-
}
|
|
717
|
-
structure.forEach((item) => {
|
|
718
|
-
activateNode(item);
|
|
719
|
-
});
|
|
720
|
-
}
|
|
721
|
-
|
|
722
|
-
/**
|
|
723
|
-
* Activates node change handlers for a component by setting up MobX reactions.
|
|
724
|
-
* Each handler watches a node selector and executes its command when the node value changes.
|
|
725
|
-
*/
|
|
726
|
-
function activateNodeChangeHandlers(component) {
|
|
727
|
-
for (const handler of component.onNodeChange) {
|
|
728
|
-
const disposer = reaction(
|
|
729
|
-
// Track the node value using the selector
|
|
730
|
-
() => component.getNodeValue(handler.selector),
|
|
731
|
-
// Execute the command when node value changes
|
|
732
|
-
async (nodeValue) => {
|
|
733
|
-
const src = component.sourceUrl ? `[${component.sourceUrl}] ` : '';
|
|
734
|
-
log.trace(`${src}onNodeChange "${handler.selector}" triggered on ${component.id}`);
|
|
735
|
-
try {
|
|
736
|
-
await handler.command.viewModel.execute(nodeValue);
|
|
869
|
+
else {
|
|
870
|
+
if (!comparer.structural(value, prev[0])) {
|
|
871
|
+
// console.log('100', JSON.stringify(value), JSON.stringify(prev[0]));
|
|
872
|
+
newValue = value ? [...value] : [];
|
|
737
873
|
}
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
874
|
+
else {
|
|
875
|
+
// console.log('200');
|
|
876
|
+
newValue = [...evalState.value];
|
|
877
|
+
if (value && evalState.value.length > prev[2].value.length) {
|
|
878
|
+
newValue = [...value];
|
|
879
|
+
}
|
|
880
|
+
}
|
|
881
|
+
}
|
|
882
|
+
// console.log(JSON.stringify(newValue));
|
|
883
|
+
const components = componentsIds.map((id) => ComponentStore.getInstance().getComponentOrThrow(id));
|
|
884
|
+
runInAction(() => {
|
|
885
|
+
const store = ComponentStore.getInstance();
|
|
886
|
+
store.setNodeRawSchema(node, newValue);
|
|
887
|
+
for (let i = 0; i < components.length; i++) {
|
|
888
|
+
const c = components[i];
|
|
889
|
+
const value = newValue[i];
|
|
890
|
+
const valueNode = c.getNode(valueProp);
|
|
891
|
+
store.setNodeRawSchema(valueNode, value);
|
|
743
892
|
}
|
|
744
|
-
}, {
|
|
745
|
-
// Fire immediately on setup to handle initial state
|
|
746
|
-
fireImmediately: true,
|
|
747
893
|
});
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
}
|
|
751
|
-
|
|
752
|
-
function activateComponentStructure(node) {
|
|
753
|
-
const structure = node.structure;
|
|
754
|
-
if (structure === null) {
|
|
755
|
-
return;
|
|
756
|
-
}
|
|
757
|
-
const component = ComponentStore.getInstance().getComponentOrThrow(structure);
|
|
758
|
-
activateComponent(component);
|
|
759
|
-
}
|
|
760
|
-
function activateComponent(component) {
|
|
761
|
-
ComponentStore.getInstance().componentsToPreload.add(component.componentType);
|
|
762
|
-
for (const node of component.props.values()) {
|
|
763
|
-
activateNode(node);
|
|
764
|
-
}
|
|
765
|
-
for (const node of component.variables.values()) {
|
|
766
|
-
activateNode(node);
|
|
767
|
-
}
|
|
768
|
-
for (const handler of component.onNodeChange) {
|
|
769
|
-
activateNode(handler.command);
|
|
770
|
-
}
|
|
771
|
-
activateNodeChangeHandlers(component);
|
|
772
|
-
}
|
|
773
|
-
|
|
774
|
-
function activateMapStructure(node) {
|
|
775
|
-
const structure = node.structure;
|
|
776
|
-
if (structure === null) {
|
|
777
|
-
return;
|
|
778
|
-
}
|
|
779
|
-
for (const item of Object.values(structure)) {
|
|
780
|
-
activateNode(item);
|
|
781
|
-
}
|
|
782
|
-
}
|
|
783
|
-
|
|
784
|
-
function activateObjectStructure(node) {
|
|
785
|
-
const structure = node.structure;
|
|
786
|
-
if (structure === null) {
|
|
787
|
-
return;
|
|
788
|
-
}
|
|
789
|
-
for (const node of Object.values(structure)) {
|
|
790
|
-
activateNode(node);
|
|
791
|
-
}
|
|
792
|
-
}
|
|
793
|
-
|
|
794
|
-
function activateShapeStructure(node) {
|
|
795
|
-
const { valueType, structure } = node;
|
|
796
|
-
if (structure === null) {
|
|
797
|
-
return;
|
|
798
|
-
}
|
|
799
|
-
const objectValueType = DefinitionStore.getInstance().getShape(valueType.shapeType);
|
|
800
|
-
for (const key of Object.keys(objectValueType.fields)) {
|
|
801
|
-
activateNode(structure[key]);
|
|
802
|
-
}
|
|
803
|
-
}
|
|
804
|
-
|
|
805
|
-
function activateVariantShapeStructure(node) {
|
|
806
|
-
const { valueType, structure } = node;
|
|
807
|
-
if (structure === null) {
|
|
808
|
-
return;
|
|
809
|
-
}
|
|
810
|
-
const objectValueType = DefinitionStore.getInstance().getVariantShape(valueType.shapeType, structure.kind);
|
|
811
|
-
for (const key of Object.keys(objectValueType.fields)) {
|
|
812
|
-
activateNode(structure.fields[key]);
|
|
813
|
-
}
|
|
894
|
+
}, { fireImmediately: true, equals: comparer.structural });
|
|
895
|
+
node.disposers.push(disposer);
|
|
814
896
|
}
|
|
815
897
|
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
898
|
+
function bindMirror(component, node, cfg) {
|
|
899
|
+
const store = ComponentStore.getInstance();
|
|
900
|
+
let targetNode;
|
|
901
|
+
try {
|
|
902
|
+
// For Facade components, start lookup from parent. This handles inline bindings
|
|
903
|
+
// on template contract variables, where the Facade has a variable with the same
|
|
904
|
+
// name - we need to find the parent's variable, not self.
|
|
905
|
+
const lookupFromId = component.componentType === 'sys.Facade' ? component.position.componentId : component.id;
|
|
906
|
+
if (!lookupFromId) {
|
|
907
|
+
log.error(`Cannot activate mirror binding: no parent component for selector "${cfg.selector}"`);
|
|
908
|
+
return;
|
|
909
|
+
}
|
|
910
|
+
targetNode = store.getNode(lookupFromId, cfg.selector);
|
|
828
911
|
}
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
912
|
+
catch (error) {
|
|
913
|
+
log.error(`Cannot activate mirror binding: ${error}`);
|
|
914
|
+
return;
|
|
832
915
|
}
|
|
916
|
+
const disposer = reaction(() => [targetNode.extractedValue, node.extractedValue], (curr, prev) => {
|
|
917
|
+
const [targetValue, sourceValue = null] = curr;
|
|
918
|
+
const [prevTargetValue, prevSourceValue] = prev || [null, null];
|
|
919
|
+
if (comparer.structural(targetValue, sourceValue)) {
|
|
920
|
+
return;
|
|
921
|
+
}
|
|
922
|
+
if (!prev && targetValue !== null) {
|
|
923
|
+
store.setNodeRawSchema(node, targetValue);
|
|
924
|
+
return;
|
|
925
|
+
}
|
|
926
|
+
if (targetValue !== prevTargetValue) {
|
|
927
|
+
store.setNodeRawSchema(node, targetValue);
|
|
928
|
+
return;
|
|
929
|
+
}
|
|
930
|
+
if (sourceValue !== prevSourceValue) {
|
|
931
|
+
store.setNodeRawSchema(targetNode, sourceValue);
|
|
932
|
+
}
|
|
933
|
+
}, { fireImmediately: true });
|
|
934
|
+
node.disposers.push(disposer);
|
|
833
935
|
}
|
|
834
936
|
|
|
835
|
-
function
|
|
836
|
-
const
|
|
837
|
-
const
|
|
838
|
-
if (!currentFrame) {
|
|
839
|
-
throw new Error('Cannot activate formula computation: no current frame');
|
|
840
|
-
}
|
|
841
|
-
const thisFrameDepth = node.computationStack.depth;
|
|
842
|
-
const evalNode = lowerComputationSchema(currentFrame.schema);
|
|
937
|
+
function bindObject(node, component, cfg) {
|
|
938
|
+
const { componentSelector, keyProp, valueProp } = cfg;
|
|
939
|
+
const evalNode = lowerFormula(`propObject('${componentSelector}', '${keyProp}', '${valueProp}')`);
|
|
843
940
|
if (!node.position.componentId) {
|
|
844
941
|
throw new Error('Node does not have a component context');
|
|
845
942
|
}
|
|
846
|
-
const component = getComponent(node);
|
|
847
943
|
const { computed, disposers } = evaluateNode(evalNode, {
|
|
848
944
|
componentId: node.position.componentId,
|
|
849
|
-
sourceUrl: component.sourceUrl ?? undefined,
|
|
850
945
|
});
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
node.
|
|
855
|
-
|
|
946
|
+
node.disposers.push(...disposers);
|
|
947
|
+
let preservedNodeValue = {};
|
|
948
|
+
const disposer = reaction(() => [
|
|
949
|
+
node.extractedValue,
|
|
950
|
+
ComponentTreeApi.findComponentsIds(component.id, componentSelector),
|
|
951
|
+
computed.get(),
|
|
952
|
+
], ([nodeValue, componentsIds, evalState], prev) => {
|
|
953
|
+
const currentValue = nodeValue || {};
|
|
954
|
+
if (comparer.structural(evalState.value, currentValue)) {
|
|
856
955
|
return;
|
|
857
956
|
}
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
store.setNodeRawSchema(node, rawSchema);
|
|
863
|
-
if (node.computationStack.depth > thisFrameDepth) {
|
|
864
|
-
// If a nested computation was pushed onto the stack, activate it
|
|
865
|
-
activateComputation(node);
|
|
957
|
+
const firstRun = !prev;
|
|
958
|
+
const nodeChanged = !firstRun && !comparer.structural(nodeValue, prev[0]);
|
|
959
|
+
if (firstRun || nodeChanged) {
|
|
960
|
+
preservedNodeValue = currentValue;
|
|
866
961
|
}
|
|
867
962
|
else {
|
|
868
|
-
|
|
963
|
+
preservedNodeValue = shallowMerge(preservedNodeValue, evalState.value);
|
|
869
964
|
}
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
965
|
+
let componentValues;
|
|
966
|
+
if (firstRun) {
|
|
967
|
+
const hasInitialValue = Object.keys(currentValue).length > 0;
|
|
968
|
+
componentValues = hasInitialValue
|
|
969
|
+
? syncNodeValueAndComponents$1(currentValue, evalState)
|
|
970
|
+
: { ...evalState.value };
|
|
971
|
+
}
|
|
972
|
+
else if (nodeChanged) {
|
|
973
|
+
componentValues = syncNodeValueAndComponents$1(currentValue, evalState);
|
|
974
|
+
}
|
|
975
|
+
else {
|
|
976
|
+
componentValues = handleComponentsChanged(evalState, preservedNodeValue);
|
|
977
|
+
}
|
|
978
|
+
runInAction(() => {
|
|
979
|
+
const store = ComponentStore.getInstance();
|
|
980
|
+
store.setNodeRawSchema(node, componentValues);
|
|
981
|
+
updateComponentsValues$1(componentsIds, componentValues, keyProp, valueProp);
|
|
982
|
+
});
|
|
983
|
+
}, { fireImmediately: true, equals: comparer.structural });
|
|
984
|
+
node.disposers.push(disposer);
|
|
876
985
|
}
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
const
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
986
|
+
function handleComponentsChanged(evalState, preservedNodeValue) {
|
|
987
|
+
const componentValues = {};
|
|
988
|
+
for (const [inputKey, currentValue] of Object.entries(evalState.value)) {
|
|
989
|
+
const preservedValue = preservedNodeValue[inputKey];
|
|
990
|
+
if (isObject(currentValue) && isObject(preservedValue)) {
|
|
991
|
+
componentValues[inputKey] = mergePreservedWithChildGroup(currentValue, preservedValue);
|
|
992
|
+
continue;
|
|
993
|
+
}
|
|
994
|
+
componentValues[inputKey] = currentValue ?? preservedValue;
|
|
885
995
|
}
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
templateLoadingTracker.finishLoading(taskKey);
|
|
899
|
-
return;
|
|
900
|
-
}
|
|
901
|
-
// Loading succeeded - create and set the template schema
|
|
902
|
-
setTemplateOnNode(node, cacheEntry, path, contractVariables, ref);
|
|
903
|
-
templateLoadingTracker.finishLoading(taskKey);
|
|
904
|
-
})
|
|
905
|
-
.catch((error) => {
|
|
906
|
-
// Handle any unhandled errors during template creation
|
|
907
|
-
log.error(`Failed to activate template "${path}":`, error);
|
|
908
|
-
store.setNodeSchema(node, defer.error);
|
|
909
|
-
templateLoadingTracker.finishLoading(taskKey);
|
|
910
|
-
});
|
|
911
|
-
// Mark as activated immediately (don't wait for loading)
|
|
912
|
-
currentFrame.markActivated();
|
|
913
|
-
return;
|
|
996
|
+
return componentValues;
|
|
997
|
+
}
|
|
998
|
+
function mergePreservedWithChildGroup(currentValue, preservedValue) {
|
|
999
|
+
const merged = { ...currentValue };
|
|
1000
|
+
for (const [key, value] of Object.entries(currentValue)) {
|
|
1001
|
+
if (value !== null) {
|
|
1002
|
+
continue;
|
|
1003
|
+
}
|
|
1004
|
+
if (preservedValue[key] === undefined || preservedValue[key] === null) {
|
|
1005
|
+
continue;
|
|
1006
|
+
}
|
|
1007
|
+
merged[key] = preservedValue[key];
|
|
914
1008
|
}
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
1009
|
+
return merged;
|
|
1010
|
+
}
|
|
1011
|
+
function syncNodeValueAndComponents$1(nodeValue, evalState) {
|
|
1012
|
+
const componentValues = {};
|
|
1013
|
+
for (const fieldKey of Object.keys(evalState.value)) {
|
|
1014
|
+
if (!(fieldKey in nodeValue)) {
|
|
1015
|
+
componentValues[fieldKey] = null;
|
|
1016
|
+
continue;
|
|
1017
|
+
}
|
|
1018
|
+
componentValues[fieldKey] = nodeValue[fieldKey];
|
|
919
1019
|
}
|
|
920
|
-
|
|
921
|
-
setTemplateOnNode(node, cacheEntry, path, contractVariables, ref);
|
|
922
|
-
currentFrame.markActivated();
|
|
1020
|
+
return componentValues;
|
|
923
1021
|
}
|
|
924
|
-
function
|
|
1022
|
+
function updateComponentsValues$1(componentsIds, componentValues, keyProp, valueProp) {
|
|
925
1023
|
const store = ComponentStore.getInstance();
|
|
926
|
-
const
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
const
|
|
932
|
-
|
|
933
|
-
|
|
1024
|
+
const components = componentsIds.map((id) => store.getComponentOrThrow(id));
|
|
1025
|
+
for (const cmp of components) {
|
|
1026
|
+
const key = cmp.getNodeValue(keyProp);
|
|
1027
|
+
if (!key)
|
|
1028
|
+
continue;
|
|
1029
|
+
const value = componentValues[key];
|
|
1030
|
+
const valueNode = cmp.getNode(valueProp);
|
|
1031
|
+
store.setNodeRawSchema(valueNode, value);
|
|
934
1032
|
}
|
|
935
1033
|
}
|
|
936
|
-
function
|
|
937
|
-
|
|
938
|
-
|
|
1034
|
+
function shallowMerge(target, source) {
|
|
1035
|
+
const merged = { ...target };
|
|
1036
|
+
for (const [key, value] of Object.entries(source)) {
|
|
1037
|
+
if (value === null || value === undefined) {
|
|
1038
|
+
continue;
|
|
1039
|
+
}
|
|
1040
|
+
if (isObject(value) && isObject(merged[key])) {
|
|
1041
|
+
merged[key] = { ...merged[key], ...value };
|
|
1042
|
+
continue;
|
|
1043
|
+
}
|
|
1044
|
+
merged[key] = value;
|
|
939
1045
|
}
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
1046
|
+
return merged;
|
|
1047
|
+
}
|
|
1048
|
+
|
|
1049
|
+
function bindSelection(node, component, cfg) {
|
|
1050
|
+
const { componentSelector, keyProp, valueProp } = cfg;
|
|
1051
|
+
const evalNode = lowerFormula(`propObject('${componentSelector}', '${keyProp}', '${valueProp}')`);
|
|
1052
|
+
if (!node.position.componentId) {
|
|
1053
|
+
throw new Error('Node does not have a component context');
|
|
1054
|
+
}
|
|
1055
|
+
const { computed, disposers } = evaluateNode(evalNode, {
|
|
1056
|
+
componentId: node.position.componentId,
|
|
1057
|
+
});
|
|
1058
|
+
node.disposers.push(...disposers);
|
|
1059
|
+
let preservedNodeValue = null;
|
|
1060
|
+
const disposer = reaction(() => [
|
|
1061
|
+
node.extractedValue,
|
|
1062
|
+
ComponentTreeApi.findComponentsIds(component.id, componentSelector),
|
|
1063
|
+
computed.get(),
|
|
1064
|
+
], ([nodeValue, componentsIds, evalState], prev) => {
|
|
1065
|
+
const currentValue = toObject(nodeValue);
|
|
1066
|
+
const firstRun = !prev;
|
|
1067
|
+
const nodeChanged = !firstRun && !comparer.structural(nodeValue, prev[0]);
|
|
1068
|
+
if (firstRun || nodeChanged) {
|
|
1069
|
+
preservedNodeValue = currentValue;
|
|
1070
|
+
}
|
|
1071
|
+
if (comparer.structural(evalState.value, currentValue)) {
|
|
1072
|
+
return;
|
|
1073
|
+
}
|
|
1074
|
+
let componentValues;
|
|
1075
|
+
if (firstRun) {
|
|
1076
|
+
const initialNodeValue = Object.keys(currentValue).length > 0;
|
|
1077
|
+
componentValues = initialNodeValue
|
|
1078
|
+
? syncNodeValueAndComponents(currentValue, evalState, preservedNodeValue)
|
|
1079
|
+
: { ...evalState.value };
|
|
1080
|
+
}
|
|
1081
|
+
else if (nodeChanged) {
|
|
1082
|
+
componentValues = syncNodeValueAndComponents(currentValue, evalState, preservedNodeValue);
|
|
1083
|
+
}
|
|
1084
|
+
else {
|
|
1085
|
+
componentValues = syncComponentsAndPreserved(evalState, preservedNodeValue, currentValue);
|
|
1086
|
+
}
|
|
1087
|
+
const selectionValue = toSelectionSet(componentValues);
|
|
1088
|
+
runInAction(() => {
|
|
1089
|
+
const store = ComponentStore.getInstance();
|
|
1090
|
+
store.setNodeRawSchema(node, selectionValue);
|
|
1091
|
+
updateComponentsValues(componentsIds, componentValues, keyProp, valueProp);
|
|
1092
|
+
});
|
|
1093
|
+
}, { fireImmediately: true, equals: comparer.structural });
|
|
1094
|
+
node.disposers.push(disposer);
|
|
1095
|
+
}
|
|
1096
|
+
function syncNodeValueAndComponents(nodeValue, evalState, preservedNodeValue) {
|
|
1097
|
+
const componentValues = { ...nodeValue };
|
|
1098
|
+
// Keep keys in preservedNodeValue to handle async component loading
|
|
1099
|
+
for (const key of Object.keys(componentValues)) {
|
|
1100
|
+
if (!(key in evalState.value) && (!preservedNodeValue || !(key in preservedNodeValue))) {
|
|
1101
|
+
delete componentValues[key];
|
|
1102
|
+
}
|
|
949
1103
|
}
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
valueTypes[facadeKey] = sourceNodeSchema.valueType;
|
|
1104
|
+
for (const key of Object.keys(evalState.value)) {
|
|
1105
|
+
if (!(key in componentValues)) {
|
|
1106
|
+
componentValues[key] = false;
|
|
1107
|
+
}
|
|
955
1108
|
}
|
|
956
|
-
|
|
957
|
-
const contentWithBindings = addSynchronizeBindings(contract, rootSchema);
|
|
958
|
-
// Return the raw facade schema object
|
|
959
|
-
return {
|
|
960
|
-
componentType: 'sys.Facade',
|
|
961
|
-
ref,
|
|
962
|
-
content: contentWithBindings,
|
|
963
|
-
...prefixedVariables,
|
|
964
|
-
};
|
|
1109
|
+
return componentValues;
|
|
965
1110
|
}
|
|
966
|
-
function
|
|
967
|
-
const
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
const regularProps = unmappedVariables.filter((key) => !key.startsWith('$') && !key.includes('@'));
|
|
974
|
-
if (variableDeclarations.length > 0) {
|
|
975
|
-
throw new Error(`Template "${templatePath}": Variable declarations cannot be siblings of templateUrl. ` +
|
|
976
|
-
`Found: ${variableDeclarations.join(', ')}. ` +
|
|
977
|
-
`Pass values directly or wrap templateUrl in a component.`);
|
|
1111
|
+
function syncComponentsAndPreserved(evalState, preservedNodeValue, currentValue) {
|
|
1112
|
+
const componentValues = { ...evalState.value };
|
|
1113
|
+
if (preservedNodeValue) {
|
|
1114
|
+
for (const key of Object.keys(evalState.value)) {
|
|
1115
|
+
if (evalState.value[key] === null) {
|
|
1116
|
+
componentValues[key] = preservedNodeValue[key] ?? false;
|
|
1117
|
+
}
|
|
978
1118
|
}
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
1119
|
+
// Preserve selection for components being recreated
|
|
1120
|
+
for (const key of Object.keys(preservedNodeValue)) {
|
|
1121
|
+
if (!(key in componentValues)) {
|
|
1122
|
+
componentValues[key] = preservedNodeValue[key];
|
|
1123
|
+
}
|
|
982
1124
|
}
|
|
983
1125
|
}
|
|
984
|
-
|
|
985
|
-
for (const
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
}
|
|
989
|
-
if ('slot' in contractVariables) {
|
|
990
|
-
const slotComponent = contractVariables['slot'];
|
|
991
|
-
let targetSlot = flatWrapperSlot;
|
|
992
|
-
// Find default component slot if not explicitly specified
|
|
993
|
-
if (!targetSlot) {
|
|
994
|
-
const componentSlots = Object.keys(valueTypes).filter((key) => valueTypes[key].type === 'component');
|
|
995
|
-
if (componentSlots.length !== 1) {
|
|
996
|
-
throw new Error(`Cannot find default slot for template computation. Found ${componentSlots.length} slots: ${componentSlots.join(', ')}`);
|
|
997
|
-
}
|
|
998
|
-
targetSlot = componentSlots[0];
|
|
1126
|
+
// Include user changes not yet in preservedNodeValue
|
|
1127
|
+
for (const key of Object.keys(currentValue)) {
|
|
1128
|
+
if (!(key in componentValues)) {
|
|
1129
|
+
componentValues[key] = currentValue[key];
|
|
999
1130
|
}
|
|
1000
|
-
const prefixedKey = `${Delimiters.Variable}${targetSlot}`;
|
|
1001
|
-
prefixedVariables[prefixedKey] = unfoldNodeSchema(slotComponent, valueTypes[targetSlot]);
|
|
1002
1131
|
}
|
|
1003
|
-
return
|
|
1132
|
+
return componentValues;
|
|
1004
1133
|
}
|
|
1005
|
-
function
|
|
1006
|
-
const
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
const
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1134
|
+
function updateComponentsValues(componentsIds, componentValues, keyProp, valueProp) {
|
|
1135
|
+
const store = ComponentStore.getInstance();
|
|
1136
|
+
const components = componentsIds.map((id) => store.getComponentOrThrow(id));
|
|
1137
|
+
for (const cmp of components) {
|
|
1138
|
+
const key = cmp.getNodeValue(keyProp);
|
|
1139
|
+
if (!key)
|
|
1140
|
+
continue;
|
|
1141
|
+
const value = componentValues[key];
|
|
1142
|
+
const valueNode = cmp.getNode(valueProp);
|
|
1143
|
+
store.setNodeRawSchema(valueNode, value);
|
|
1014
1144
|
}
|
|
1015
|
-
return rootSchema;
|
|
1016
1145
|
}
|
|
1017
|
-
function
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
`Ensure the template recipe declares "${key}" as a ${isVariable ? 'variable' : 'property'}.`);
|
|
1025
|
-
}
|
|
1026
|
-
const node = source.get(isVariable ? key.slice(1) : key);
|
|
1027
|
-
if (!node) {
|
|
1028
|
-
const kind = isVariable ? 'variable' : 'property';
|
|
1029
|
-
const lookupKey = isVariable ? key.slice(1) : key;
|
|
1030
|
-
const available = [...source.keys()].map((k) => (isVariable ? `$${k}` : k));
|
|
1031
|
-
throw new Error(`Template "${templatePath}": Contract key "${key}" not found as ${kind} "${lookupKey}" ` +
|
|
1032
|
-
`in root component "${rootValue.componentType}". ` +
|
|
1033
|
-
`Available ${kind}s: [${available.join(', ')}]`);
|
|
1034
|
-
}
|
|
1035
|
-
return node;
|
|
1146
|
+
function toSelectionSet(componentValues) {
|
|
1147
|
+
return new Set(Object.entries(componentValues)
|
|
1148
|
+
.filter(([, fieldValue]) => !!fieldValue)
|
|
1149
|
+
.map(([key]) => key));
|
|
1150
|
+
}
|
|
1151
|
+
function toObject(selectionSet) {
|
|
1152
|
+
return Object.fromEntries(Array.from(selectionSet || []).map((key) => [key, true]));
|
|
1036
1153
|
}
|
|
1037
1154
|
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
const frame = node.computationStack.top;
|
|
1047
|
-
if (!frame) {
|
|
1155
|
+
async function addBinding(node, extra = false) {
|
|
1156
|
+
await when(() => !node.evaluating);
|
|
1157
|
+
const store = ComponentStore.getInstance();
|
|
1158
|
+
if (!node.position.componentId) {
|
|
1159
|
+
throw new Error('Cannot add binding without component context');
|
|
1160
|
+
}
|
|
1161
|
+
const component = store.getComponent(node.position.componentId);
|
|
1162
|
+
if (!component) {
|
|
1048
1163
|
return;
|
|
1049
1164
|
}
|
|
1050
|
-
|
|
1051
|
-
if (
|
|
1165
|
+
const bindingSchema = extra ? node.extraBinding : node.bindingSchema;
|
|
1166
|
+
if (!bindingSchema) {
|
|
1052
1167
|
return;
|
|
1053
1168
|
}
|
|
1054
|
-
const
|
|
1055
|
-
|
|
1056
|
-
|
|
1169
|
+
const valueType = node.valueType;
|
|
1170
|
+
switch (bindingSchema.bindingType) {
|
|
1171
|
+
case 'object':
|
|
1172
|
+
bindObject(node, component, {
|
|
1173
|
+
componentSelector: bindingSchema.componentSelector,
|
|
1174
|
+
keyProp: bindingSchema.mapping.key,
|
|
1175
|
+
valueProp: bindingSchema.mapping.value,
|
|
1176
|
+
valueType,
|
|
1177
|
+
});
|
|
1178
|
+
break;
|
|
1179
|
+
case 'selection':
|
|
1180
|
+
bindSelection(node, component, {
|
|
1181
|
+
componentSelector: bindingSchema.componentSelector,
|
|
1182
|
+
keyProp: bindingSchema.mapping.key,
|
|
1183
|
+
valueProp: bindingSchema.mapping.selected,
|
|
1184
|
+
valueType,
|
|
1185
|
+
});
|
|
1186
|
+
break;
|
|
1187
|
+
case 'array':
|
|
1188
|
+
bindArray(node, component, {
|
|
1189
|
+
componentSelector: bindingSchema.componentSelector,
|
|
1190
|
+
valueProp: bindingSchema.mapping.value,
|
|
1191
|
+
valueType,
|
|
1192
|
+
});
|
|
1193
|
+
break;
|
|
1194
|
+
case 'mirror':
|
|
1195
|
+
bindMirror(component, node, bindingSchema);
|
|
1196
|
+
break;
|
|
1057
1197
|
}
|
|
1058
1198
|
}
|
|
1059
1199
|
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1200
|
+
const debugName = (position, thing) => {
|
|
1201
|
+
return [position.componentId, position.path.join(Delimiters.NodePath), thing].join('|');
|
|
1202
|
+
};
|
|
1203
|
+
const componentInstanceMap = new Map();
|
|
1204
|
+
|
|
1205
|
+
const lowerSimpleValue = (schema) => ({
|
|
1206
|
+
type: 'value',
|
|
1207
|
+
value: schema.value,
|
|
1208
|
+
});
|
|
1209
|
+
const lowerObjectOrMap = (schema) => {
|
|
1210
|
+
if (!schema.value) {
|
|
1211
|
+
return { type: 'value', value: null };
|
|
1063
1212
|
}
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1213
|
+
const entries = Object.entries(schema.value);
|
|
1214
|
+
return {
|
|
1215
|
+
type: 'object',
|
|
1216
|
+
properties: entries.map(([key, value]) => ({
|
|
1217
|
+
key: { type: 'value', value: key },
|
|
1218
|
+
value: lowerSchema(value),
|
|
1219
|
+
})),
|
|
1220
|
+
};
|
|
1221
|
+
};
|
|
1222
|
+
const lowerArrayOrSet = (schema) => {
|
|
1223
|
+
if (!schema.value) {
|
|
1224
|
+
throw new Error(`${schema.valueType.type} schema without value`);
|
|
1067
1225
|
}
|
|
1068
|
-
|
|
1069
|
-
|
|
1226
|
+
return {
|
|
1227
|
+
type: 'array',
|
|
1228
|
+
items: schema.value.map((item) => lowerSchema(item)),
|
|
1229
|
+
};
|
|
1230
|
+
};
|
|
1231
|
+
const lowerShape = () => {
|
|
1232
|
+
throw new Error('Shape lowering not implemented');
|
|
1233
|
+
};
|
|
1234
|
+
const lowerVariantShape = (schema) => {
|
|
1235
|
+
if (!schema.value) {
|
|
1236
|
+
return { type: 'value', value: null };
|
|
1070
1237
|
}
|
|
1071
|
-
|
|
1072
|
-
|
|
1238
|
+
const variantShapeValue = schema.value;
|
|
1239
|
+
const variantField = `${schema.valueType.shapeType}Type`;
|
|
1240
|
+
const entries = Object.entries(variantShapeValue);
|
|
1241
|
+
const properties = entries
|
|
1242
|
+
.filter(([key]) => key !== 'kind')
|
|
1243
|
+
.map(([key, value]) => ({
|
|
1244
|
+
key: { type: 'value', value: key },
|
|
1245
|
+
value: typeof value === 'string' ? { type: 'value', value } : lowerSchema(value),
|
|
1246
|
+
}));
|
|
1247
|
+
properties.push({
|
|
1248
|
+
key: { type: 'value', value: variantField },
|
|
1249
|
+
value: { type: 'value', value: variantShapeValue['kind'] },
|
|
1250
|
+
});
|
|
1251
|
+
return {
|
|
1252
|
+
type: 'object',
|
|
1253
|
+
properties,
|
|
1254
|
+
};
|
|
1255
|
+
};
|
|
1256
|
+
const schemaLowerers = {
|
|
1257
|
+
string: lowerSimpleValue,
|
|
1258
|
+
number: lowerSimpleValue,
|
|
1259
|
+
boolean: lowerSimpleValue,
|
|
1260
|
+
unknown: lowerSimpleValue,
|
|
1261
|
+
component: lowerSimpleValue,
|
|
1262
|
+
command: lowerSimpleValue,
|
|
1263
|
+
componentSchema: lowerSimpleValue,
|
|
1264
|
+
object: lowerObjectOrMap,
|
|
1265
|
+
map: lowerObjectOrMap,
|
|
1266
|
+
array: lowerArrayOrSet,
|
|
1267
|
+
set: lowerArrayOrSet,
|
|
1268
|
+
shape: lowerShape,
|
|
1269
|
+
variantShape: lowerVariantShape,
|
|
1270
|
+
};
|
|
1271
|
+
function lowerSchema(schema) {
|
|
1272
|
+
// If schema has a computation, lower it
|
|
1273
|
+
if (schema.computation) {
|
|
1274
|
+
return lowerComputationSchema(schema.computation);
|
|
1073
1275
|
}
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
ComponentTreeApi.appendArrayItem(ctx.componentId, selector, item);
|
|
1079
|
-
const arrayNode = ComponentTreeApi.findNode(ctx.componentId, selector);
|
|
1080
|
-
if (arrayNode) {
|
|
1081
|
-
// Activate the last item in the array (the one we just appended)
|
|
1082
|
-
const lastIndex = (arrayNode.structure?.length ?? 1) - 1;
|
|
1083
|
-
const newItem = arrayNode.structure?.[lastIndex];
|
|
1084
|
-
if (newItem) {
|
|
1085
|
-
activateNode(newItem);
|
|
1086
|
-
}
|
|
1276
|
+
// Otherwise lower the value based on valueType
|
|
1277
|
+
const lowerer = schemaLowerers[schema.valueType.type];
|
|
1278
|
+
if (lowerer) {
|
|
1279
|
+
return lowerer(schema);
|
|
1087
1280
|
}
|
|
1281
|
+
throw new Error(`Unsupported value type: ${schema.valueType.type}`);
|
|
1088
1282
|
}
|
|
1089
1283
|
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
}
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1284
|
+
function lowerForLoop(forComputation) {
|
|
1285
|
+
const dimensionsNode = {
|
|
1286
|
+
type: 'array',
|
|
1287
|
+
items: forComputation.dimensions.map((dimension) => {
|
|
1288
|
+
// Extract trackBy expression to be evaluated in RefSpace context where $item is available
|
|
1289
|
+
let trackByExpression = null;
|
|
1290
|
+
if (dimension.trackBy.computation && dimension.trackBy.computation.computationType === 'formula') {
|
|
1291
|
+
trackByExpression = `=${dimension.trackBy.computation.formula}`;
|
|
1292
|
+
}
|
|
1293
|
+
else if (dimension.trackBy.value !== null) {
|
|
1294
|
+
trackByExpression = dimension.trackBy.value;
|
|
1295
|
+
}
|
|
1296
|
+
return {
|
|
1297
|
+
type: 'object',
|
|
1298
|
+
properties: [
|
|
1299
|
+
{ key: { type: 'value', value: 'items' }, value: lowerSchema(dimension.items) },
|
|
1300
|
+
{ key: { type: 'value', value: 'itemsType' }, value: { type: 'value', value: dimension.itemsType } },
|
|
1301
|
+
{ key: { type: 'value', value: 'item' }, value: lowerSchema(dimension.item) },
|
|
1302
|
+
{ key: { type: 'value', value: 'index' }, value: lowerSchema(dimension.index) },
|
|
1303
|
+
{ key: { type: 'value', value: 'first' }, value: lowerSchema(dimension.first) },
|
|
1304
|
+
{ key: { type: 'value', value: 'last' }, value: lowerSchema(dimension.last) },
|
|
1305
|
+
{ key: { type: 'value', value: 'trackBy' }, value: { type: 'value', value: trackByExpression } },
|
|
1306
|
+
],
|
|
1307
|
+
};
|
|
1308
|
+
}),
|
|
1309
|
+
};
|
|
1310
|
+
const yieldNode = lowerSchema(forComputation.yield);
|
|
1311
|
+
return {
|
|
1312
|
+
type: 'function',
|
|
1313
|
+
name: 'repeat',
|
|
1314
|
+
args: [dimensionsNode, yieldNode],
|
|
1315
|
+
};
|
|
1106
1316
|
}
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
}
|
|
1112
|
-
|
|
1113
|
-
function execute$Q(_ctx, ms) {
|
|
1114
|
-
return new Promise((resolve) => setTimeout(() => resolve(), ms));
|
|
1317
|
+
function lowerTemplate(templateComputation) {
|
|
1318
|
+
return {
|
|
1319
|
+
type: 'value',
|
|
1320
|
+
value: templateComputation,
|
|
1321
|
+
};
|
|
1115
1322
|
}
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
function execute$P(ctx, selector) {
|
|
1123
|
-
return ComponentTreeApi.findNode(ctx.componentId, selector)?.extractedValue ?? null;
|
|
1323
|
+
function lowerIfStatement(ifNode) {
|
|
1324
|
+
return {
|
|
1325
|
+
type: 'function',
|
|
1326
|
+
name: 'if',
|
|
1327
|
+
args: [lowerSchema(ifNode.if), lowerSchema(ifNode.then), lowerSchema(ifNode.else)],
|
|
1328
|
+
};
|
|
1124
1329
|
}
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1330
|
+
function lowerSwitch(switchComputation) {
|
|
1331
|
+
// Lower the source
|
|
1332
|
+
const sourceEvalNode = lowerSchema(switchComputation.source);
|
|
1333
|
+
// Build cases array as flat array: [value1, result1, value2, result2, ...]
|
|
1334
|
+
// Extract .value from ComponentSchemaNodeSchema to get the actual component schema
|
|
1335
|
+
const casesArrayItems = [];
|
|
1336
|
+
for (const caseItem of switchComputation.cases) {
|
|
1337
|
+
casesArrayItems.push({ type: 'value', value: caseItem.equals });
|
|
1338
|
+
// caseItem.then is a ComponentSchemaNodeSchema, extract its .value property
|
|
1339
|
+
casesArrayItems.push({ type: 'value', value: caseItem.then.value });
|
|
1340
|
+
}
|
|
1341
|
+
const casesArrayNode = {
|
|
1342
|
+
type: 'array',
|
|
1343
|
+
items: casesArrayItems,
|
|
1344
|
+
};
|
|
1345
|
+
// Lower the default value - extract .value from ComponentSchemaNodeSchema
|
|
1346
|
+
const defaultNode = { type: 'value', value: switchComputation.default.value };
|
|
1347
|
+
return {
|
|
1348
|
+
type: 'function',
|
|
1349
|
+
name: 'switch',
|
|
1350
|
+
args: [sourceEvalNode, casesArrayNode, defaultNode],
|
|
1351
|
+
};
|
|
1133
1352
|
}
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1353
|
+
const computationLowerers = {
|
|
1354
|
+
formula: (schema) => lowerFormula(schema.formula),
|
|
1355
|
+
for: (schema) => lowerForLoop(schema),
|
|
1356
|
+
template: (schema) => lowerTemplate(schema),
|
|
1357
|
+
if: (schema) => lowerIfStatement(schema),
|
|
1358
|
+
switch: (schema) => lowerSwitch(schema),
|
|
1359
|
+
};
|
|
1360
|
+
function lowerComputationSchema(computationSchema) {
|
|
1361
|
+
const lowerer = computationLowerers[computationSchema.computationType];
|
|
1362
|
+
if (lowerer) {
|
|
1363
|
+
return lowerer(computationSchema);
|
|
1364
|
+
}
|
|
1365
|
+
throw new Error(`Unsupported computation type: ${computationSchema.computationType}`);
|
|
1142
1366
|
}
|
|
1143
1367
|
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
function execute$M(ctx, componentSelector, methodName, ...args) {
|
|
1150
|
-
const component = ComponentTreeApi.getComponent(ctx.componentId, componentSelector);
|
|
1151
|
-
const instance = componentInstanceMap.get(component.id);
|
|
1152
|
-
if (!instance) {
|
|
1153
|
-
throw new Error(`Cannot find component instance for component with id "${component.id}"`);
|
|
1368
|
+
function activateForComputation(node) {
|
|
1369
|
+
const store = ComponentStore.getInstance();
|
|
1370
|
+
const currentFrame = node.computationStack.top;
|
|
1371
|
+
if (!currentFrame) {
|
|
1372
|
+
throw new Error('Cannot activate for computation: no current frame');
|
|
1154
1373
|
}
|
|
1155
|
-
const
|
|
1156
|
-
if (!
|
|
1157
|
-
throw new Error(
|
|
1374
|
+
const evalNode = lowerComputationSchema(currentFrame.schema);
|
|
1375
|
+
if (!node.position.componentId) {
|
|
1376
|
+
throw new Error('Node does not have a component context');
|
|
1158
1377
|
}
|
|
1159
|
-
|
|
1378
|
+
const { computed, disposers } = evaluateNode(evalNode, {
|
|
1379
|
+
componentId: node.position.componentId,
|
|
1380
|
+
});
|
|
1381
|
+
currentFrame.disposers.push(...disposers);
|
|
1382
|
+
const computationDisposer = reaction(() => computed.get(), ({ value: newItems }) => {
|
|
1383
|
+
const toAdd = store.reconcileForLoopChildren(node, newItems);
|
|
1384
|
+
// Activate only newly added children
|
|
1385
|
+
const structure = node.structure || [];
|
|
1386
|
+
for (const index of toAdd) {
|
|
1387
|
+
const child = structure[index];
|
|
1388
|
+
if (child) {
|
|
1389
|
+
activateNode(child);
|
|
1390
|
+
}
|
|
1391
|
+
}
|
|
1392
|
+
}, { fireImmediately: true, name: debugName(node.position, 'repeatable-reaction') });
|
|
1393
|
+
currentFrame.disposers.push(computationDisposer);
|
|
1394
|
+
currentFrame.markActivated();
|
|
1160
1395
|
}
|
|
1161
1396
|
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
function execute$L(ctx, selector, value) {
|
|
1168
|
-
ComponentTreeApi.setNodeRawSchema(ctx.componentId, selector, value);
|
|
1169
|
-
const node = ComponentTreeApi.findNode(ctx.componentId, selector);
|
|
1170
|
-
if (node) {
|
|
1171
|
-
activateStructure(node);
|
|
1397
|
+
function activateArrayStructure(node) {
|
|
1398
|
+
const structure = node.structure;
|
|
1399
|
+
if (structure === null) {
|
|
1400
|
+
return;
|
|
1172
1401
|
}
|
|
1402
|
+
structure.forEach((item) => {
|
|
1403
|
+
activateNode(item);
|
|
1404
|
+
});
|
|
1173
1405
|
}
|
|
1174
1406
|
|
|
1175
|
-
var set = /*#__PURE__*/Object.freeze({
|
|
1176
|
-
__proto__: null,
|
|
1177
|
-
execute: execute$L
|
|
1178
|
-
});
|
|
1179
|
-
|
|
1180
|
-
const commands = {
|
|
1181
|
-
delay: delay$1,
|
|
1182
|
-
// New names
|
|
1183
|
-
collectValuesMap: collectValuesMap$1,
|
|
1184
|
-
collectValuesArray: collectValuesArray$1,
|
|
1185
|
-
// Legacy aliases for backwards compatibility
|
|
1186
|
-
propObject: collectValuesMap$1,
|
|
1187
|
-
propArray: collectValuesArray$1,
|
|
1188
|
-
appendArrayItem,
|
|
1189
|
-
removeArrayItem,
|
|
1190
|
-
runComponentMethod,
|
|
1191
|
-
get,
|
|
1192
|
-
set,
|
|
1193
|
-
run,
|
|
1194
|
-
};
|
|
1195
|
-
|
|
1196
1407
|
/**
|
|
1197
|
-
*
|
|
1198
|
-
*
|
|
1408
|
+
* Activates node change handlers for a component by setting up MobX reactions.
|
|
1409
|
+
* Each handler watches a node selector and executes its command when the node value changes.
|
|
1199
1410
|
*/
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
for (const argComputed of args) {
|
|
1209
|
-
const argState = argComputed.get();
|
|
1210
|
-
const earlyReturn = state.checkReady(argState);
|
|
1211
|
-
if (earlyReturn)
|
|
1212
|
-
return earlyReturn;
|
|
1213
|
-
if (!argState.value) {
|
|
1214
|
-
return state.success(false);
|
|
1215
|
-
}
|
|
1216
|
-
}
|
|
1217
|
-
return state.success(true);
|
|
1411
|
+
function activateNodeChangeHandlers(component) {
|
|
1412
|
+
for (const handler of component.onNodeChange) {
|
|
1413
|
+
const disposer = reaction(() => component.getNodeValue(handler.selector), (nodeValue) => {
|
|
1414
|
+
const src = component.sourceUrl ? `[${component.sourceUrl}] ` : '';
|
|
1415
|
+
log.trace(`${src}onNodeChange "${handler.selector}" triggered on ${component.id}`);
|
|
1416
|
+
handler.command.viewModel.execute(nodeValue);
|
|
1417
|
+
}, {
|
|
1418
|
+
fireImmediately: true,
|
|
1218
1419
|
});
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
}
|
|
1222
|
-
|
|
1223
|
-
function execute$K(source, path) {
|
|
1224
|
-
const takeDeep = (source, path) => path.reduce((current, step) => {
|
|
1225
|
-
return current?.[step];
|
|
1226
|
-
}, source);
|
|
1227
|
-
return source.map((element) => takeDeep(element, path));
|
|
1228
|
-
}
|
|
1229
|
-
const arrayPluck = {
|
|
1230
|
-
kind: 'imperative',
|
|
1231
|
-
execute: execute$K,
|
|
1232
|
-
signature: '(unknown{}[], string[]) => unknown',
|
|
1233
|
-
};
|
|
1234
|
-
|
|
1235
|
-
function execute$J(value, index) {
|
|
1236
|
-
return value[index];
|
|
1237
|
-
}
|
|
1238
|
-
const at = {
|
|
1239
|
-
kind: 'imperative',
|
|
1240
|
-
execute: execute$J,
|
|
1241
|
-
signature: '(unknown[], number) => unknown',
|
|
1242
|
-
};
|
|
1420
|
+
component.handlerDisposers.push(disposer);
|
|
1421
|
+
}
|
|
1422
|
+
}
|
|
1243
1423
|
|
|
1244
|
-
function
|
|
1245
|
-
|
|
1424
|
+
function activateComponentStructure(node) {
|
|
1425
|
+
const structure = node.structure;
|
|
1426
|
+
if (structure === null) {
|
|
1427
|
+
return;
|
|
1428
|
+
}
|
|
1429
|
+
const component = ComponentStore.getInstance().getComponentOrThrow(structure);
|
|
1430
|
+
activateComponent(component);
|
|
1431
|
+
}
|
|
1432
|
+
function activateComponent(component) {
|
|
1433
|
+
ComponentStore.getInstance().componentsToPreload.add(component.componentType);
|
|
1434
|
+
for (const node of component.props.values()) {
|
|
1435
|
+
activateNode(node);
|
|
1436
|
+
}
|
|
1437
|
+
for (const node of component.variables.values()) {
|
|
1438
|
+
activateNode(node);
|
|
1439
|
+
}
|
|
1440
|
+
for (const handler of component.onNodeChange) {
|
|
1441
|
+
activateNode(handler.command);
|
|
1442
|
+
}
|
|
1443
|
+
activateNodeChangeHandlers(component);
|
|
1246
1444
|
}
|
|
1247
|
-
const bool = {
|
|
1248
|
-
kind: 'imperative',
|
|
1249
|
-
execute: execute$I,
|
|
1250
|
-
signature: '(unknown) => boolean',
|
|
1251
|
-
};
|
|
1252
1445
|
|
|
1253
|
-
function
|
|
1254
|
-
|
|
1446
|
+
function activateMapStructure(node) {
|
|
1447
|
+
const structure = node.structure;
|
|
1448
|
+
if (structure === null) {
|
|
1449
|
+
return;
|
|
1450
|
+
}
|
|
1451
|
+
for (const item of Object.values(structure)) {
|
|
1452
|
+
activateNode(item);
|
|
1453
|
+
}
|
|
1255
1454
|
}
|
|
1256
|
-
const ceil = {
|
|
1257
|
-
kind: 'imperative',
|
|
1258
|
-
execute: execute$H,
|
|
1259
|
-
signature: '(number) => number',
|
|
1260
|
-
};
|
|
1261
1455
|
|
|
1262
|
-
function
|
|
1263
|
-
|
|
1456
|
+
function activateObjectStructure(node) {
|
|
1457
|
+
const structure = node.structure;
|
|
1458
|
+
if (structure === null) {
|
|
1459
|
+
return;
|
|
1460
|
+
}
|
|
1461
|
+
for (const node of Object.values(structure)) {
|
|
1462
|
+
activateNode(node);
|
|
1463
|
+
}
|
|
1264
1464
|
}
|
|
1265
|
-
const collectValuesArray = {
|
|
1266
|
-
kind: 'imperative',
|
|
1267
|
-
contextual: true,
|
|
1268
|
-
execute: execute$G,
|
|
1269
|
-
signature: '(string, string) => unknown[]',
|
|
1270
|
-
};
|
|
1271
1465
|
|
|
1272
|
-
function
|
|
1273
|
-
|
|
1466
|
+
function activateShapeStructure(node) {
|
|
1467
|
+
const { valueType, structure } = node;
|
|
1468
|
+
if (structure === null) {
|
|
1469
|
+
return;
|
|
1470
|
+
}
|
|
1471
|
+
const objectValueType = DefinitionStore.getInstance().getShape(valueType.shapeType);
|
|
1472
|
+
for (const key of Object.keys(objectValueType.fields)) {
|
|
1473
|
+
activateNode(structure[key]);
|
|
1474
|
+
}
|
|
1274
1475
|
}
|
|
1275
|
-
const collectValuesMap = {
|
|
1276
|
-
kind: 'imperative',
|
|
1277
|
-
contextual: true,
|
|
1278
|
-
execute: execute$F,
|
|
1279
|
-
signature: '(string, string, string) => unknown{}',
|
|
1280
|
-
};
|
|
1281
1476
|
|
|
1282
|
-
function
|
|
1283
|
-
|
|
1477
|
+
function activateVariantShapeStructure(node) {
|
|
1478
|
+
const { valueType, structure } = node;
|
|
1479
|
+
if (structure === null) {
|
|
1480
|
+
return;
|
|
1481
|
+
}
|
|
1482
|
+
const objectValueType = DefinitionStore.getInstance().getVariantShape(valueType.shapeType, structure.kind);
|
|
1483
|
+
for (const key of Object.keys(objectValueType.fields)) {
|
|
1484
|
+
activateNode(structure.fields[key]);
|
|
1485
|
+
}
|
|
1284
1486
|
}
|
|
1285
|
-
const concat = {
|
|
1286
|
-
kind: 'imperative',
|
|
1287
|
-
execute: execute$E,
|
|
1288
|
-
signature: '(unknown[], string) => string',
|
|
1289
|
-
};
|
|
1290
1487
|
|
|
1291
|
-
const
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1488
|
+
const structureActivators = {
|
|
1489
|
+
shape: (node) => activateShapeStructure(node),
|
|
1490
|
+
variantShape: (node) => activateVariantShapeStructure(node),
|
|
1491
|
+
array: (node) => activateArrayStructure(node),
|
|
1492
|
+
object: (node) => activateObjectStructure(node),
|
|
1493
|
+
map: (node) => activateMapStructure(node),
|
|
1494
|
+
component: (node) => activateComponentStructure(node),
|
|
1298
1495
|
};
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1496
|
+
function activateStructure(node) {
|
|
1497
|
+
const value = node.structure;
|
|
1498
|
+
if (value === null) {
|
|
1499
|
+
return;
|
|
1500
|
+
}
|
|
1501
|
+
const activator = structureActivators[node.nodeType];
|
|
1502
|
+
if (activator) {
|
|
1503
|
+
activator(node);
|
|
1504
|
+
}
|
|
1302
1505
|
}
|
|
1303
|
-
const divide = {
|
|
1304
|
-
kind: 'imperative',
|
|
1305
|
-
execute: execute$C,
|
|
1306
|
-
signature: '(number, number) => number',
|
|
1307
|
-
};
|
|
1308
1506
|
|
|
1309
|
-
function
|
|
1310
|
-
|
|
1507
|
+
function activateFormulaComputation(node) {
|
|
1508
|
+
const store = ComponentStore.getInstance();
|
|
1509
|
+
const currentFrame = node.computationStack.top;
|
|
1510
|
+
if (!currentFrame) {
|
|
1511
|
+
throw new Error('Cannot activate formula computation: no current frame');
|
|
1512
|
+
}
|
|
1513
|
+
const thisFrameDepth = node.computationStack.depth;
|
|
1514
|
+
const evalNode = lowerComputationSchema(currentFrame.schema);
|
|
1515
|
+
if (!node.position.componentId) {
|
|
1516
|
+
throw new Error('Node does not have a component context');
|
|
1517
|
+
}
|
|
1518
|
+
const component = getComponent(node);
|
|
1519
|
+
const { computed, disposers } = evaluateNode(evalNode, {
|
|
1520
|
+
componentId: node.position.componentId,
|
|
1521
|
+
sourceUrl: component.sourceUrl ?? undefined,
|
|
1522
|
+
});
|
|
1523
|
+
currentFrame.disposers.push(...disposers);
|
|
1524
|
+
const computationDisposer = reaction(() => computed.get(), (computationState) => {
|
|
1525
|
+
const { evaluating, value: rawSchema, failed } = computationState;
|
|
1526
|
+
node.evaluating = evaluating;
|
|
1527
|
+
if (evaluating) {
|
|
1528
|
+
return;
|
|
1529
|
+
}
|
|
1530
|
+
node.failed = failed;
|
|
1531
|
+
// Clear result frames from this depth onward (not all results!)
|
|
1532
|
+
// Example: if this is depth 2, clear frames 2, 3, 4... but keep 0, 1
|
|
1533
|
+
node.computationStack.popFrom(thisFrameDepth);
|
|
1534
|
+
store.setNodeRawSchema(node, rawSchema);
|
|
1535
|
+
if (node.computationStack.depth > thisFrameDepth) {
|
|
1536
|
+
// If a nested computation was pushed onto the stack, activate it
|
|
1537
|
+
activateComputation(node);
|
|
1538
|
+
}
|
|
1539
|
+
else {
|
|
1540
|
+
activateStructure(node);
|
|
1541
|
+
}
|
|
1542
|
+
}, {
|
|
1543
|
+
fireImmediately: true,
|
|
1544
|
+
name: debugName(node.position, 'formula-reaction'),
|
|
1545
|
+
});
|
|
1546
|
+
currentFrame.disposers.push(computationDisposer);
|
|
1547
|
+
currentFrame.markActivated();
|
|
1311
1548
|
}
|
|
1312
|
-
const empty = {
|
|
1313
|
-
kind: 'imperative',
|
|
1314
|
-
execute: execute$B,
|
|
1315
|
-
signature: '(unknown[]) => boolean',
|
|
1316
|
-
};
|
|
1317
1549
|
|
|
1318
|
-
function
|
|
1319
|
-
|
|
1550
|
+
function activateTemplateComputation(node) {
|
|
1551
|
+
const store = ComponentStore.getInstance();
|
|
1552
|
+
const nodePath = node.position.path;
|
|
1553
|
+
const component = getComponent(node);
|
|
1554
|
+
const currentFrame = node.computationStack.top;
|
|
1555
|
+
if (!currentFrame) {
|
|
1556
|
+
throw new Error('Cannot activate template computation: no current frame');
|
|
1557
|
+
}
|
|
1558
|
+
const { defer, path, contractVariables, ref } = currentFrame.schema;
|
|
1559
|
+
const taskKey = `template-${component.id}-${nodePath}`;
|
|
1560
|
+
if (defer) {
|
|
1561
|
+
templateLoadingTracker.startLoading(taskKey);
|
|
1562
|
+
store.setNodeSchema(node, defer.placeholder);
|
|
1563
|
+
// Fire-and-forget: load template asynchronously
|
|
1564
|
+
loadTemplates({ templateUrl: path })
|
|
1565
|
+
.then(() => {
|
|
1566
|
+
const cacheEntry = templateRegistry.get(path);
|
|
1567
|
+
if (!cacheEntry) {
|
|
1568
|
+
// Loading failed - show error schema
|
|
1569
|
+
store.setNodeSchema(node, defer.error);
|
|
1570
|
+
templateLoadingTracker.finishLoading(taskKey);
|
|
1571
|
+
return;
|
|
1572
|
+
}
|
|
1573
|
+
// Loading succeeded - create and set the template schema
|
|
1574
|
+
setTemplateOnNode(node, cacheEntry, path, contractVariables, ref);
|
|
1575
|
+
templateLoadingTracker.finishLoading(taskKey);
|
|
1576
|
+
})
|
|
1577
|
+
.catch((error) => {
|
|
1578
|
+
// Handle any unhandled errors during template creation
|
|
1579
|
+
log.error(`Failed to activate template "${path}":`, error);
|
|
1580
|
+
store.setNodeSchema(node, defer.error);
|
|
1581
|
+
templateLoadingTracker.finishLoading(taskKey);
|
|
1582
|
+
});
|
|
1583
|
+
// Mark as activated immediately (don't wait for loading)
|
|
1584
|
+
currentFrame.markActivated();
|
|
1585
|
+
return;
|
|
1586
|
+
}
|
|
1587
|
+
const cacheEntry = templateRegistry.get(path);
|
|
1588
|
+
if (!cacheEntry) {
|
|
1589
|
+
const src = component.sourceUrl ? `[${component.sourceUrl}] ` : '';
|
|
1590
|
+
throw new Error(`${src}Template not found in cache: ${path}`);
|
|
1591
|
+
}
|
|
1592
|
+
// Non-defer path: template is already loaded, create schema synchronously
|
|
1593
|
+
setTemplateOnNode(node, cacheEntry, path, contractVariables, ref);
|
|
1594
|
+
currentFrame.markActivated();
|
|
1320
1595
|
}
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
const
|
|
1328
|
-
const
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
};
|
|
1333
|
-
|
|
1334
|
-
function execute$y(value1, value2) {
|
|
1335
|
-
return value1 === value2;
|
|
1596
|
+
function setTemplateOnNode(node, cacheEntry, path, contractVariables, ref) {
|
|
1597
|
+
const store = ComponentStore.getInstance();
|
|
1598
|
+
const rawFacadeSchema = createRawFacadeSchema(cacheEntry, path, contractVariables, ref);
|
|
1599
|
+
store.setNodeRawSchema(node, rawFacadeSchema);
|
|
1600
|
+
// Activate the facade component after it's created (only for regular component nodes)
|
|
1601
|
+
if (node.nodeType !== 'componentSchema') {
|
|
1602
|
+
const facadeId = node.structure;
|
|
1603
|
+
const facade = store.getComponentOrThrow(facadeId);
|
|
1604
|
+
facade.sourceUrl = path;
|
|
1605
|
+
activateComponent(facade);
|
|
1606
|
+
}
|
|
1336
1607
|
}
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
};
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1608
|
+
function createRawFacadeSchema(cacheEntry, path, contractVariables, ref) {
|
|
1609
|
+
if (!cacheEntry) {
|
|
1610
|
+
throw new Error(`Template cache entry is undefined for path: ${path}`);
|
|
1611
|
+
}
|
|
1612
|
+
const { recipe } = cacheEntry;
|
|
1613
|
+
const { types: _types, importTypes: _importTypes, contract = {}, defaultSlot, ...componentRecipe } = recipe;
|
|
1614
|
+
const rootSchema = unfoldNodeSchema(componentRecipe, { type: 'component' });
|
|
1615
|
+
const rootValue = rootSchema.value;
|
|
1616
|
+
if (!rootValue) {
|
|
1617
|
+
const recipeKeys = Object.keys(componentRecipe).join(', ');
|
|
1618
|
+
throw new Error(`Template "${path}": Root schema has no value. ` +
|
|
1619
|
+
`The recipe root must define a component (implicit or explicit componentType). ` +
|
|
1620
|
+
`Found keys: [${recipeKeys}]`);
|
|
1621
|
+
}
|
|
1622
|
+
// Collect value types from the root schema for each mapped variable
|
|
1623
|
+
const valueTypes = {};
|
|
1624
|
+
for (const [facadeKey, rootKey] of Object.entries(contract)) {
|
|
1625
|
+
const sourceNodeSchema = getSourceNodeOrThrow(rootValue, rootKey, path);
|
|
1626
|
+
valueTypes[facadeKey] = sourceNodeSchema.valueType;
|
|
1627
|
+
}
|
|
1628
|
+
const prefixedVariables = createFacadeVariables(path, contractVariables, contract, valueTypes, defaultSlot);
|
|
1629
|
+
const contentWithBindings = addSynchronizeBindings(contract, rootSchema);
|
|
1630
|
+
// Return the raw facade schema object
|
|
1631
|
+
return {
|
|
1632
|
+
componentType: 'sys.Facade',
|
|
1633
|
+
ref,
|
|
1634
|
+
content: contentWithBindings,
|
|
1635
|
+
...prefixedVariables,
|
|
1636
|
+
};
|
|
1345
1637
|
}
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1638
|
+
function createFacadeVariables(templatePath, contractVariables, contract, valueTypes, flatWrapperSlot) {
|
|
1639
|
+
const contractKeys = Object.keys(contractVariables);
|
|
1640
|
+
const contractPropKeys = Object.keys(contract);
|
|
1641
|
+
const unmappedVariables = contractKeys.filter((key) => key !== 'slot' && !contractPropKeys.includes(key));
|
|
1642
|
+
if (unmappedVariables.length > 0) {
|
|
1643
|
+
// Detect if unmapped keys look like variable declarations (have $ prefix or @ type annotation)
|
|
1644
|
+
const variableDeclarations = unmappedVariables.filter((key) => key.startsWith('$') || key.includes('@'));
|
|
1645
|
+
const regularProps = unmappedVariables.filter((key) => !key.startsWith('$') && !key.includes('@'));
|
|
1646
|
+
if (variableDeclarations.length > 0) {
|
|
1647
|
+
throw new Error(`Template "${templatePath}": Variable declarations cannot be siblings of templateUrl. ` +
|
|
1648
|
+
`Found: ${variableDeclarations.join(', ')}. ` +
|
|
1649
|
+
`Pass values directly or wrap templateUrl in a component.`);
|
|
1650
|
+
}
|
|
1651
|
+
else if (regularProps.length > 0) {
|
|
1652
|
+
log.warn(`Template "${templatePath}": Unknown properties: ${regularProps.join(', ')}. ` +
|
|
1653
|
+
`Expected: ${contractPropKeys.join(', ')}`);
|
|
1654
|
+
}
|
|
1655
|
+
}
|
|
1656
|
+
const prefixedVariables = {};
|
|
1657
|
+
for (const facadeKey of contractPropKeys) {
|
|
1658
|
+
const prefixedKey = `${Delimiters.Variable}${facadeKey}`;
|
|
1659
|
+
prefixedVariables[prefixedKey] = unfoldNodeSchema(contractVariables[facadeKey], valueTypes[facadeKey]);
|
|
1660
|
+
}
|
|
1661
|
+
if ('slot' in contractVariables) {
|
|
1662
|
+
const slotComponent = contractVariables['slot'];
|
|
1663
|
+
let targetSlot = flatWrapperSlot;
|
|
1664
|
+
// Find default component slot if not explicitly specified
|
|
1665
|
+
if (!targetSlot) {
|
|
1666
|
+
const componentSlots = Object.keys(valueTypes).filter((key) => valueTypes[key].type === 'component');
|
|
1667
|
+
if (componentSlots.length !== 1) {
|
|
1668
|
+
throw new Error(`Cannot find default slot for template computation. Found ${componentSlots.length} slots: ${componentSlots.join(', ')}`);
|
|
1669
|
+
}
|
|
1670
|
+
targetSlot = componentSlots[0];
|
|
1671
|
+
}
|
|
1672
|
+
const prefixedKey = `${Delimiters.Variable}${targetSlot}`;
|
|
1673
|
+
prefixedVariables[prefixedKey] = unfoldNodeSchema(slotComponent, valueTypes[targetSlot]);
|
|
1674
|
+
}
|
|
1675
|
+
return prefixedVariables;
|
|
1355
1676
|
}
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1677
|
+
function addSynchronizeBindings(contract, rootSchema) {
|
|
1678
|
+
const rootValue = rootSchema.value;
|
|
1679
|
+
for (const [facadeKey, templateKey] of Object.entries(contract)) {
|
|
1680
|
+
// This will always succeed because mapping was already validated in createRawFacadeSchema
|
|
1681
|
+
const sourceNodeSchema = getSourceNodeOrThrow(rootValue, templateKey, '');
|
|
1682
|
+
sourceNodeSchema.extraBinding = {
|
|
1683
|
+
bindingType: 'mirror',
|
|
1684
|
+
selector: `^sys.Facade->$${facadeKey}`,
|
|
1685
|
+
};
|
|
1686
|
+
}
|
|
1687
|
+
return rootSchema;
|
|
1364
1688
|
}
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
}
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
if (!allowedValues) {
|
|
1374
|
-
return [];
|
|
1689
|
+
function getSourceNodeOrThrow(rootValue, key, templatePath) {
|
|
1690
|
+
const isVariable = key.startsWith('$');
|
|
1691
|
+
const source = isVariable ? rootValue.variables : rootValue.props;
|
|
1692
|
+
if (!source) {
|
|
1693
|
+
const kind = isVariable ? 'variables' : 'props';
|
|
1694
|
+
throw new Error(`Template "${templatePath}": Cannot resolve contract key "${key}" — ` +
|
|
1695
|
+
`root component "${rootValue.componentType}" has no ${kind}. ` +
|
|
1696
|
+
`Ensure the template recipe declares "${key}" as a ${isVariable ? 'variable' : 'property'}.`);
|
|
1375
1697
|
}
|
|
1376
|
-
|
|
1377
|
-
|
|
1698
|
+
const node = source.get(isVariable ? key.slice(1) : key);
|
|
1699
|
+
if (!node) {
|
|
1700
|
+
const kind = isVariable ? 'variable' : 'property';
|
|
1701
|
+
const lookupKey = isVariable ? key.slice(1) : key;
|
|
1702
|
+
const available = [...source.keys()].map((k) => (isVariable ? `$${k}` : k));
|
|
1703
|
+
throw new Error(`Template "${templatePath}": Contract key "${key}" not found as ${kind} "${lookupKey}" ` +
|
|
1704
|
+
`in root component "${rootValue.componentType}". ` +
|
|
1705
|
+
`Available ${kind}s: [${available.join(', ')}]`);
|
|
1378
1706
|
}
|
|
1379
|
-
return
|
|
1380
|
-
}
|
|
1381
|
-
const filterIn = {
|
|
1382
|
-
kind: 'imperative',
|
|
1383
|
-
execute: execute$u,
|
|
1384
|
-
signature: '(unknown[], unknown[]) => unknown[]',
|
|
1385
|
-
};
|
|
1386
|
-
|
|
1387
|
-
function execute$t(collection, key, values) {
|
|
1388
|
-
return values
|
|
1389
|
-
.map((value) => collection.find((element) => element[key] === value))
|
|
1390
|
-
.filter((item) => item !== undefined);
|
|
1707
|
+
return node;
|
|
1391
1708
|
}
|
|
1392
|
-
const findAllBy = {
|
|
1393
|
-
kind: 'imperative',
|
|
1394
|
-
execute: execute$t,
|
|
1395
|
-
signature: '(unknown{}[], string, unknown[]) => unknown{}[]',
|
|
1396
|
-
};
|
|
1397
1709
|
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
execute: execute$s,
|
|
1405
|
-
signature: '(unknown{}[], string, unknown) => unknown',
|
|
1710
|
+
const computationActivators = {
|
|
1711
|
+
if: (node) => activateFormulaComputation(node),
|
|
1712
|
+
formula: (node) => activateFormulaComputation(node),
|
|
1713
|
+
switch: (node) => activateFormulaComputation(node),
|
|
1714
|
+
for: (node) => activateForComputation(node),
|
|
1715
|
+
template: (node) => activateTemplateComputation(node),
|
|
1406
1716
|
};
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1717
|
+
function activateComputation(node) {
|
|
1718
|
+
const frame = node.computationStack.top;
|
|
1719
|
+
if (!frame) {
|
|
1720
|
+
return;
|
|
1721
|
+
}
|
|
1722
|
+
// Idempotency: don't re-activate an already activated frame
|
|
1723
|
+
if (frame.activated) {
|
|
1724
|
+
return;
|
|
1725
|
+
}
|
|
1726
|
+
const activator = computationActivators[frame.schema.computationType];
|
|
1727
|
+
if (activator) {
|
|
1728
|
+
activator(node);
|
|
1729
|
+
}
|
|
1410
1730
|
}
|
|
1411
|
-
const flatten = {
|
|
1412
|
-
kind: 'imperative',
|
|
1413
|
-
execute: execute$r,
|
|
1414
|
-
signature: '(unknown[][]) => unknown[]',
|
|
1415
|
-
};
|
|
1416
1731
|
|
|
1417
|
-
function
|
|
1418
|
-
|
|
1732
|
+
function activateNode(node) {
|
|
1733
|
+
if (node.fullyActivated) {
|
|
1734
|
+
return;
|
|
1735
|
+
}
|
|
1736
|
+
activateStructure(node);
|
|
1737
|
+
if (!node.computationStack.isEmpty) {
|
|
1738
|
+
activateComputation(node);
|
|
1739
|
+
}
|
|
1740
|
+
if (node.bindingSchema) {
|
|
1741
|
+
void addBinding(node);
|
|
1742
|
+
}
|
|
1743
|
+
if (node.extraBinding) {
|
|
1744
|
+
void addBinding(node, true);
|
|
1745
|
+
}
|
|
1746
|
+
node.markActivated();
|
|
1419
1747
|
}
|
|
1420
|
-
const floor = {
|
|
1421
|
-
kind: 'imperative',
|
|
1422
|
-
execute: execute$q,
|
|
1423
|
-
signature: '(number) => number',
|
|
1424
|
-
};
|
|
1425
1748
|
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
}
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
const name = isVariable ? baseName.slice(1) : baseName;
|
|
1438
|
-
const type = isVariable ? 'Variable' : 'Property';
|
|
1439
|
-
log.trace(`${type} "${name}" not found`);
|
|
1749
|
+
const compiledCache = new WeakMap();
|
|
1750
|
+
function getOrCompile(structure, key) {
|
|
1751
|
+
let cached = compiledCache.get(structure);
|
|
1752
|
+
if (!cached) {
|
|
1753
|
+
cached = {};
|
|
1754
|
+
compiledCache.set(structure, cached);
|
|
1755
|
+
}
|
|
1756
|
+
if (!cached[key]) {
|
|
1757
|
+
cached[key] = createJsFunction(structure[key]);
|
|
1758
|
+
}
|
|
1759
|
+
return cached[key];
|
|
1440
1760
|
}
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1761
|
+
async function runCommand(node, ...args) {
|
|
1762
|
+
const structure = node.structure;
|
|
1763
|
+
if (!structure) {
|
|
1764
|
+
const comp = node.position.componentId
|
|
1765
|
+
? ComponentStore.getInstance().getComponent(node.position.componentId)
|
|
1766
|
+
: null;
|
|
1767
|
+
const src = comp?.sourceUrl ? `[${comp.sourceUrl}] ` : '';
|
|
1768
|
+
log.trace(`${src}Command is empty — no handler was bound to it.`);
|
|
1769
|
+
return null;
|
|
1770
|
+
}
|
|
1771
|
+
const component = ComponentStore.getInstance().getComponentOrThrow(structure.owner);
|
|
1772
|
+
const src = component.sourceUrl ? `[${component.sourceUrl}] ` : '';
|
|
1773
|
+
const functionsProxy = proxifySubCommands(component);
|
|
1774
|
+
try {
|
|
1775
|
+
if (structure.init) {
|
|
1776
|
+
log.trace(`${src}Running init hook`);
|
|
1777
|
+
const initFunc = getOrCompile(structure, 'init');
|
|
1778
|
+
await initFunc(functionsProxy, args);
|
|
1779
|
+
}
|
|
1780
|
+
if (structure.runnerType === 'inline') {
|
|
1781
|
+
log.trace(`${src}Executing inline callback (${args.length} args)`);
|
|
1782
|
+
return await structure.target(...args);
|
|
1783
|
+
}
|
|
1784
|
+
const preview = structure.target.slice(0, 80);
|
|
1785
|
+
log.trace(`${src}Executing command: ${preview}`);
|
|
1786
|
+
const targetFunc = getOrCompile(structure, 'target');
|
|
1787
|
+
return await targetFunc(functionsProxy, args);
|
|
1788
|
+
}
|
|
1789
|
+
catch (e) {
|
|
1790
|
+
throw new Error(`${src}Error executing ${structure.runnerType === 'inline' ? 'inline callback' : 'command'}`, {
|
|
1791
|
+
cause: e,
|
|
1792
|
+
});
|
|
1793
|
+
}
|
|
1794
|
+
finally {
|
|
1795
|
+
if (structure.finalize) {
|
|
1796
|
+
try {
|
|
1797
|
+
log.trace(`${src}Running finalize hook`);
|
|
1798
|
+
const finalizeFunc = getOrCompile(structure, 'finalize');
|
|
1799
|
+
await finalizeFunc(functionsProxy, args);
|
|
1466
1800
|
}
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
return state.success(isOptional ? null : createFailedAsyncValue(new Error(`Node not found: ${selector}`)));
|
|
1801
|
+
catch (finalizeError) {
|
|
1802
|
+
log.error(`${src}Error in finalize hook`, finalizeError);
|
|
1470
1803
|
}
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1804
|
+
}
|
|
1805
|
+
}
|
|
1806
|
+
}
|
|
1807
|
+
function proxifySubCommands(component) {
|
|
1808
|
+
return new Proxy({}, {
|
|
1809
|
+
get(target, functionName) {
|
|
1810
|
+
return (...functionArgs) => {
|
|
1811
|
+
let execute;
|
|
1812
|
+
if (functionName in target) {
|
|
1813
|
+
execute = target[functionName];
|
|
1814
|
+
}
|
|
1815
|
+
else {
|
|
1816
|
+
const def = DefinitionStore.getInstance().getCommand(functionName);
|
|
1817
|
+
execute = target[functionName] = def.execute;
|
|
1818
|
+
}
|
|
1819
|
+
const commandCtx = {
|
|
1820
|
+
componentId: component.id,
|
|
1478
1821
|
};
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
}
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
};
|
|
1493
|
-
|
|
1494
|
-
const execute$o = (a, b) => a >= b;
|
|
1495
|
-
const gte = {
|
|
1496
|
-
kind: 'imperative',
|
|
1497
|
-
execute: execute$o,
|
|
1498
|
-
signature: '(number, number) => boolean',
|
|
1499
|
-
};
|
|
1500
|
-
|
|
1501
|
-
function execute$n(ctx, componentSelector) {
|
|
1502
|
-
return ComponentTreeApi.findComponent(ctx.componentId, componentSelector)?.id ?? null;
|
|
1822
|
+
const result = execute(commandCtx, ...functionArgs);
|
|
1823
|
+
if (result instanceof Observable) {
|
|
1824
|
+
return firstValueFrom(result);
|
|
1825
|
+
}
|
|
1826
|
+
if (result instanceof Promise) {
|
|
1827
|
+
return result;
|
|
1828
|
+
}
|
|
1829
|
+
if (isComputed(result)) {
|
|
1830
|
+
return result.get();
|
|
1831
|
+
}
|
|
1832
|
+
return result;
|
|
1833
|
+
};
|
|
1834
|
+
},
|
|
1835
|
+
});
|
|
1503
1836
|
}
|
|
1504
|
-
const idFn = {
|
|
1505
|
-
kind: 'imperative',
|
|
1506
|
-
contextual: true,
|
|
1507
|
-
execute: execute$n,
|
|
1508
|
-
signature: '(string) => string',
|
|
1509
|
-
};
|
|
1510
|
-
|
|
1511
1837
|
/**
|
|
1512
|
-
*
|
|
1513
|
-
*
|
|
1838
|
+
* Creates a JavaScript function from a string of code.
|
|
1839
|
+
*
|
|
1840
|
+
* SECURITY WARNING: This function uses `new Function()` to execute dynamic code.
|
|
1841
|
+
* Only use with schemas from trusted sources. Malicious schemas could execute
|
|
1842
|
+
* arbitrary code in the browser context, leading to XSS or data theft.
|
|
1843
|
+
*
|
|
1844
|
+
* The code has access to:
|
|
1845
|
+
* - All registered commands via destructured parameters
|
|
1846
|
+
* - Function arguments via the `args` parameter
|
|
1514
1847
|
*/
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
}
|
|
1521
|
-
const [conditionComputed, trueComputed, falseComputed] = args;
|
|
1522
|
-
return computed(() => {
|
|
1523
|
-
const state = new FunctionExecutionStateBuilder();
|
|
1524
|
-
const conditionState = conditionComputed.get();
|
|
1525
|
-
const earlyReturn = state.checkReady(conditionState);
|
|
1526
|
-
if (earlyReturn)
|
|
1527
|
-
return earlyReturn;
|
|
1528
|
-
const branchState = conditionState.value ? trueComputed.get() : falseComputed.get();
|
|
1529
|
-
const branchEarlyReturn = state.checkReady(branchState);
|
|
1530
|
-
if (branchEarlyReturn)
|
|
1531
|
-
return branchEarlyReturn;
|
|
1532
|
-
return state.success(branchState.value);
|
|
1533
|
-
});
|
|
1534
|
-
},
|
|
1535
|
-
signature: '(unknown, unknown, unknown) => unknown',
|
|
1536
|
-
};
|
|
1848
|
+
function createJsFunction(func) {
|
|
1849
|
+
const commandNames = DefinitionStore.getInstance().getCommandNames();
|
|
1850
|
+
const commandsStr = commandNames.length ? `{ ${commandNames.join(', ')} }` : 'commands';
|
|
1851
|
+
return new Function(commandsStr, 'args', `return (async () => { ${func} })();`);
|
|
1852
|
+
}
|
|
1537
1853
|
|
|
1538
|
-
function execute$
|
|
1539
|
-
|
|
1540
|
-
|
|
1854
|
+
function execute$f(ctx, selector, item) {
|
|
1855
|
+
ComponentTreeApi.appendArrayItem(ctx.componentId, selector, item);
|
|
1856
|
+
const arrayNode = ComponentTreeApi.findNode(ctx.componentId, selector);
|
|
1857
|
+
if (arrayNode) {
|
|
1858
|
+
// Activate the last item in the array (the one we just appended)
|
|
1859
|
+
const lastIndex = (arrayNode.structure?.length ?? 1) - 1;
|
|
1860
|
+
const newItem = arrayNode.structure?.[lastIndex];
|
|
1861
|
+
if (newItem) {
|
|
1862
|
+
activateNode(newItem);
|
|
1863
|
+
}
|
|
1541
1864
|
}
|
|
1542
|
-
return collection.includes(value);
|
|
1543
1865
|
}
|
|
1544
|
-
const inFn = {
|
|
1545
|
-
kind: 'imperative',
|
|
1546
|
-
execute: execute$m,
|
|
1547
|
-
signature: '(unknown[], unknown) => boolean',
|
|
1548
|
-
};
|
|
1549
1866
|
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1867
|
+
var appendArrayItem = /*#__PURE__*/Object.freeze({
|
|
1868
|
+
__proto__: null,
|
|
1869
|
+
execute: execute$f
|
|
1870
|
+
});
|
|
1871
|
+
|
|
1872
|
+
function execute$e(ctx, selector) {
|
|
1873
|
+
return ComponentTreeApi.findNode(ctx.componentId, selector)?.extractedValue ?? null;
|
|
1555
1874
|
}
|
|
1556
|
-
|
|
1557
|
-
|
|
1875
|
+
|
|
1876
|
+
var get = /*#__PURE__*/Object.freeze({
|
|
1877
|
+
__proto__: null,
|
|
1878
|
+
execute: execute$e
|
|
1879
|
+
});
|
|
1880
|
+
|
|
1881
|
+
function execute$d(ctx, selector, path) {
|
|
1882
|
+
return ComponentTreeApi.collectValuesArray(ctx.componentId, selector, path);
|
|
1558
1883
|
}
|
|
1559
|
-
const json = {
|
|
1560
|
-
kind: 'imperative',
|
|
1561
|
-
execute: execute$l,
|
|
1562
|
-
signature: '(unknown) => string',
|
|
1563
|
-
};
|
|
1564
1884
|
|
|
1565
|
-
|
|
1566
|
-
|
|
1885
|
+
var propArray$1 = /*#__PURE__*/Object.freeze({
|
|
1886
|
+
__proto__: null,
|
|
1887
|
+
execute: execute$d
|
|
1888
|
+
});
|
|
1889
|
+
|
|
1890
|
+
function execute$c(ctx, selector, objectKey, objectValue) {
|
|
1891
|
+
return ComponentTreeApi.collectValuesMap(ctx.componentId, selector, objectKey, objectValue);
|
|
1567
1892
|
}
|
|
1568
|
-
const keys = {
|
|
1569
|
-
kind: 'imperative',
|
|
1570
|
-
execute: execute$k,
|
|
1571
|
-
signature: '(unknown{}) => string[]',
|
|
1572
|
-
};
|
|
1573
1893
|
|
|
1574
|
-
|
|
1575
|
-
|
|
1894
|
+
var propObject$1 = /*#__PURE__*/Object.freeze({
|
|
1895
|
+
__proto__: null,
|
|
1896
|
+
execute: execute$c
|
|
1897
|
+
});
|
|
1898
|
+
|
|
1899
|
+
function execute$b(ctx, selector, index) {
|
|
1900
|
+
ComponentTreeApi.removeArrayItem(ctx.componentId, selector, index);
|
|
1576
1901
|
}
|
|
1577
|
-
const length = {
|
|
1578
|
-
kind: 'imperative',
|
|
1579
|
-
execute: execute$j,
|
|
1580
|
-
signature: '(unknown[]) => number',
|
|
1581
|
-
};
|
|
1582
1902
|
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
signature: '(number, number) => boolean',
|
|
1588
|
-
};
|
|
1903
|
+
var removeArrayItem = /*#__PURE__*/Object.freeze({
|
|
1904
|
+
__proto__: null,
|
|
1905
|
+
execute: execute$b
|
|
1906
|
+
});
|
|
1589
1907
|
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
execute: execute$h,
|
|
1594
|
-
signature: '(number, number) => boolean',
|
|
1595
|
-
};
|
|
1908
|
+
function execute$a(ctx, selector, ...args) {
|
|
1909
|
+
return ComponentTreeApi.runCommandNode(ctx.componentId, selector, ...args);
|
|
1910
|
+
}
|
|
1596
1911
|
|
|
1597
|
-
|
|
1598
|
-
|
|
1912
|
+
var run = /*#__PURE__*/Object.freeze({
|
|
1913
|
+
__proto__: null,
|
|
1914
|
+
execute: execute$a
|
|
1915
|
+
});
|
|
1916
|
+
|
|
1917
|
+
function execute$9(ctx, componentSelector, methodName, ...args) {
|
|
1918
|
+
const component = ComponentTreeApi.getComponent(ctx.componentId, componentSelector);
|
|
1919
|
+
const instance = componentInstanceMap.get(component.id);
|
|
1920
|
+
if (!instance) {
|
|
1921
|
+
throw new Error(`Cannot find component instance for component with id "${component.id}"`);
|
|
1922
|
+
}
|
|
1923
|
+
const method = instance[methodName];
|
|
1924
|
+
if (!method || typeof method !== 'function') {
|
|
1925
|
+
throw new Error(`Cannot find method "${methodName}" in component of type "${component.componentType}"`);
|
|
1926
|
+
}
|
|
1927
|
+
return method.call(instance, ...args);
|
|
1599
1928
|
}
|
|
1600
|
-
const minus = {
|
|
1601
|
-
kind: 'imperative',
|
|
1602
|
-
execute: execute$g,
|
|
1603
|
-
signature: '(number, number) => number',
|
|
1604
|
-
};
|
|
1605
1929
|
|
|
1606
|
-
|
|
1607
|
-
|
|
1930
|
+
var runComponentMethod = /*#__PURE__*/Object.freeze({
|
|
1931
|
+
__proto__: null,
|
|
1932
|
+
execute: execute$9
|
|
1933
|
+
});
|
|
1934
|
+
|
|
1935
|
+
function execute$8(ctx, selector, value) {
|
|
1936
|
+
ComponentTreeApi.setNodeRawSchema(ctx.componentId, selector, value);
|
|
1937
|
+
const node = ComponentTreeApi.findNode(ctx.componentId, selector);
|
|
1938
|
+
if (node) {
|
|
1939
|
+
activateStructure(node);
|
|
1940
|
+
}
|
|
1608
1941
|
}
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1942
|
+
|
|
1943
|
+
var set = /*#__PURE__*/Object.freeze({
|
|
1944
|
+
__proto__: null,
|
|
1945
|
+
execute: execute$8
|
|
1946
|
+
});
|
|
1947
|
+
|
|
1948
|
+
const commands = {
|
|
1949
|
+
propObject: propObject$1,
|
|
1950
|
+
propArray: propArray$1,
|
|
1951
|
+
appendArrayItem,
|
|
1952
|
+
removeArrayItem,
|
|
1953
|
+
runComponentMethod,
|
|
1954
|
+
get,
|
|
1955
|
+
set,
|
|
1956
|
+
run,
|
|
1613
1957
|
};
|
|
1614
1958
|
|
|
1615
|
-
const
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1959
|
+
const componentsDefinitions$2 = {
|
|
1960
|
+
'sys.Box': {
|
|
1961
|
+
properties: {
|
|
1962
|
+
'content@component': null,
|
|
1963
|
+
},
|
|
1964
|
+
},
|
|
1965
|
+
'sys.Group': {
|
|
1966
|
+
properties: {
|
|
1967
|
+
'children@component[]': [],
|
|
1968
|
+
},
|
|
1969
|
+
},
|
|
1970
|
+
'sys.RefSpace': {
|
|
1971
|
+
traits: ['sys.Box'],
|
|
1972
|
+
properties: {},
|
|
1973
|
+
},
|
|
1974
|
+
'sys.Facade': {
|
|
1975
|
+
traits: ['sys.Box'],
|
|
1976
|
+
properties: {},
|
|
1977
|
+
},
|
|
1620
1978
|
};
|
|
1621
1979
|
|
|
1622
|
-
function execute$
|
|
1623
|
-
return
|
|
1980
|
+
function execute$7(ctx, selector) {
|
|
1981
|
+
return ComponentTreeApi.getNode(ctx.componentId, selector).evaluating;
|
|
1624
1982
|
}
|
|
1625
|
-
const
|
|
1983
|
+
const evaluating = {
|
|
1626
1984
|
kind: 'imperative',
|
|
1627
|
-
|
|
1628
|
-
|
|
1985
|
+
contextual: true,
|
|
1986
|
+
execute: execute$7,
|
|
1987
|
+
signature: '(string) => boolean',
|
|
1629
1988
|
};
|
|
1630
1989
|
|
|
1631
|
-
function execute$
|
|
1632
|
-
|
|
1633
|
-
if (Number.isNaN(number)) {
|
|
1634
|
-
throw new Error(`Cannot convert value ${value} to number`);
|
|
1635
|
-
}
|
|
1636
|
-
return number;
|
|
1990
|
+
function execute$6(ctx, selector) {
|
|
1991
|
+
return ComponentTreeApi.getNode(ctx.componentId, selector).failed;
|
|
1637
1992
|
}
|
|
1638
|
-
const
|
|
1993
|
+
const failed = {
|
|
1639
1994
|
kind: 'imperative',
|
|
1640
|
-
|
|
1641
|
-
|
|
1995
|
+
contextual: true,
|
|
1996
|
+
execute: execute$6,
|
|
1997
|
+
signature: '(string) => boolean',
|
|
1642
1998
|
};
|
|
1643
1999
|
|
|
1644
|
-
function
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
result[key] = parts[i + 1];
|
|
1652
|
-
}
|
|
1653
|
-
return result;
|
|
2000
|
+
function createFailedAsyncValue(error) {
|
|
2001
|
+
return {
|
|
2002
|
+
kind: 'promise',
|
|
2003
|
+
current: null,
|
|
2004
|
+
error: error instanceof Error ? error : new Error('Node lookup failed'),
|
|
2005
|
+
pending: false,
|
|
2006
|
+
};
|
|
1654
2007
|
}
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
* Stops at the first truthy value.
|
|
1664
|
-
*/
|
|
1665
|
-
const or = {
|
|
2008
|
+
function warnNodeNotFound(selector) {
|
|
2009
|
+
const baseName = selector.split('.')[0];
|
|
2010
|
+
const isVariable = baseName.startsWith('$');
|
|
2011
|
+
const name = isVariable ? baseName.slice(1) : baseName;
|
|
2012
|
+
const type = isVariable ? 'Variable' : 'Property';
|
|
2013
|
+
log.trace(`${type} "${name}" not found`);
|
|
2014
|
+
}
|
|
2015
|
+
const getFn = {
|
|
1666
2016
|
kind: 'reactive',
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
throw new Error('or requires at least 1 argument');
|
|
1670
|
-
}
|
|
2017
|
+
contextual: true,
|
|
2018
|
+
execute: (ctx, args) => {
|
|
1671
2019
|
return computed(() => {
|
|
1672
2020
|
const state = new FunctionExecutionStateBuilder();
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
2021
|
+
// Check if selector argument is ready
|
|
2022
|
+
const selectorState = args[0].get();
|
|
2023
|
+
const earlyReturn = state.checkReady(selectorState);
|
|
2024
|
+
if (earlyReturn)
|
|
2025
|
+
return earlyReturn;
|
|
2026
|
+
const selector = selectorState.value;
|
|
2027
|
+
const isOptional = selector.includes('?->') || selector.includes('?.');
|
|
2028
|
+
// Try to find the target node
|
|
2029
|
+
let targetNode;
|
|
2030
|
+
try {
|
|
2031
|
+
targetNode = ComponentTreeApi.findNode(ctx.componentId, selector);
|
|
2032
|
+
}
|
|
2033
|
+
catch (error) {
|
|
2034
|
+
// Warn about non-existing variables/properties (only for required selectors)
|
|
2035
|
+
if (!isOptional && error instanceof Error && error.message.includes('not found')) {
|
|
2036
|
+
warnNodeNotFound(selector);
|
|
1680
2037
|
}
|
|
2038
|
+
// Optional selectors return null, required selectors fail with AsyncValue
|
|
2039
|
+
return state.success(isOptional ? null : createFailedAsyncValue(error));
|
|
1681
2040
|
}
|
|
1682
|
-
|
|
2041
|
+
// Handle case where findNode returns null (e.g., optional component selector, or traversing missing path)
|
|
2042
|
+
if (!targetNode) {
|
|
2043
|
+
return state.success(isOptional ? null : createFailedAsyncValue(new Error(`Node not found: ${selector}`)));
|
|
2044
|
+
}
|
|
2045
|
+
// Wrap node value in AsyncValue if needed to propagate evaluating/failed state
|
|
2046
|
+
if (targetNode.evaluating || targetNode.failed) {
|
|
2047
|
+
const asyncValue = {
|
|
2048
|
+
kind: 'promise',
|
|
2049
|
+
current: targetNode.extractedValue,
|
|
2050
|
+
error: targetNode.failed ? new Error('Target node failed') : null,
|
|
2051
|
+
pending: targetNode.evaluating,
|
|
2052
|
+
};
|
|
2053
|
+
return state.success(asyncValue);
|
|
2054
|
+
}
|
|
2055
|
+
return state.success(targetNode.extractedValue);
|
|
1683
2056
|
});
|
|
1684
2057
|
},
|
|
1685
|
-
signature: '(
|
|
2058
|
+
signature: '(string) => unknown',
|
|
1686
2059
|
};
|
|
1687
2060
|
|
|
1688
|
-
function execute$
|
|
1689
|
-
return
|
|
1690
|
-
return current?.[step];
|
|
1691
|
-
}, source);
|
|
2061
|
+
function execute$5(ctx, componentSelector) {
|
|
2062
|
+
return ComponentTreeApi.findComponent(ctx.componentId, componentSelector)?.id ?? null;
|
|
1692
2063
|
}
|
|
1693
|
-
const
|
|
2064
|
+
const idFn = {
|
|
1694
2065
|
kind: 'imperative',
|
|
1695
|
-
|
|
1696
|
-
|
|
2066
|
+
contextual: true,
|
|
2067
|
+
execute: execute$5,
|
|
2068
|
+
signature: '(string) => string',
|
|
1697
2069
|
};
|
|
1698
2070
|
|
|
1699
|
-
function execute$
|
|
1700
|
-
return
|
|
2071
|
+
function execute$4(ctx, selector, path) {
|
|
2072
|
+
return ComponentTreeApi.collectValuesArray(ctx.componentId, selector, path);
|
|
1701
2073
|
}
|
|
1702
|
-
const
|
|
2074
|
+
const propArray = {
|
|
1703
2075
|
kind: 'imperative',
|
|
1704
|
-
|
|
1705
|
-
|
|
2076
|
+
contextual: true,
|
|
2077
|
+
execute: execute$4,
|
|
2078
|
+
signature: '(string, string) => unknown[]',
|
|
2079
|
+
};
|
|
2080
|
+
|
|
2081
|
+
function execute$3(ctx, selector, objectKey, objectValue) {
|
|
2082
|
+
return ComponentTreeApi.collectValuesMap(ctx.componentId, selector, objectKey, objectValue);
|
|
2083
|
+
}
|
|
2084
|
+
const propObject = {
|
|
2085
|
+
kind: 'imperative',
|
|
2086
|
+
contextual: true,
|
|
2087
|
+
execute: execute$3,
|
|
2088
|
+
signature: '(string, string, string) => unknown{}',
|
|
1706
2089
|
};
|
|
1707
2090
|
|
|
1708
2091
|
/**
|
|
@@ -1723,7 +2106,7 @@ function getNestedProperty(obj, path) {
|
|
|
1723
2106
|
}
|
|
1724
2107
|
return current;
|
|
1725
2108
|
}
|
|
1726
|
-
function execute$
|
|
2109
|
+
function execute$2(dimensions, content) {
|
|
1727
2110
|
return generateCombinations(dimensions).map(({ variables }) => ({
|
|
1728
2111
|
componentType: 'sys.RefSpace',
|
|
1729
2112
|
content,
|
|
@@ -1788,366 +2171,54 @@ function generateCombinations(dimensions) {
|
|
|
1788
2171
|
else {
|
|
1789
2172
|
keyPart = index;
|
|
1790
2173
|
}
|
|
1791
|
-
const prevKey = result.key;
|
|
1792
|
-
const key = dimensionIndex === 0 ? keyPart : `${prevKey}:${keyPart}`;
|
|
1793
|
-
newVariables[`${Delimiters.Variable}trackBy`] = {
|
|
1794
|
-
_valueType: { type: 'string' },
|
|
1795
|
-
_value: String(key),
|
|
1796
|
-
_computation: null,
|
|
1797
|
-
_binding: null,
|
|
1798
|
-
};
|
|
1799
|
-
tempResults.push({ variables: newVariables, key });
|
|
1800
|
-
});
|
|
1801
|
-
});
|
|
1802
|
-
results = tempResults;
|
|
1803
|
-
});
|
|
1804
|
-
return results;
|
|
1805
|
-
}
|
|
1806
|
-
const repeat = {
|
|
1807
|
-
kind: 'imperative',
|
|
1808
|
-
execute: execute$8,
|
|
1809
|
-
signature: '({items: unknown[], itemsType: unknown, item: string, index: string, first: unknown, last: unknown, trackBy: unknown}[], componentSchema) => componentSchema[]',
|
|
1810
|
-
};
|
|
1811
|
-
|
|
1812
|
-
function execute$7(value, precision = 0) {
|
|
1813
|
-
const multiplier = Math.pow(10, precision);
|
|
1814
|
-
return Math.round(value * multiplier) / multiplier;
|
|
1815
|
-
}
|
|
1816
|
-
const round = {
|
|
1817
|
-
kind: 'imperative',
|
|
1818
|
-
execute: execute$7,
|
|
1819
|
-
signature: '(number, number) => number',
|
|
1820
|
-
};
|
|
1821
|
-
|
|
1822
|
-
function execute$6(ctx, selector) {
|
|
1823
|
-
return ComponentTreeApi.isCommandRunning(ctx.componentId, selector);
|
|
1824
|
-
}
|
|
1825
|
-
const running = {
|
|
1826
|
-
kind: 'imperative',
|
|
1827
|
-
contextual: true,
|
|
1828
|
-
execute: execute$6,
|
|
1829
|
-
signature: '(string) => boolean',
|
|
1830
|
-
};
|
|
1831
|
-
|
|
1832
|
-
function execute$5(value, start, end) {
|
|
1833
|
-
return value.slice(start, end);
|
|
1834
|
-
}
|
|
1835
|
-
const slice = {
|
|
1836
|
-
kind: 'imperative',
|
|
1837
|
-
execute: execute$5,
|
|
1838
|
-
signature: '(unknown[], number, number) => unknown[]',
|
|
1839
|
-
};
|
|
1840
|
-
|
|
1841
|
-
function execute$4(items) {
|
|
1842
|
-
return items.some((item) => !!item);
|
|
1843
|
-
}
|
|
1844
|
-
const some = {
|
|
1845
|
-
kind: 'imperative',
|
|
1846
|
-
execute: execute$4,
|
|
1847
|
-
signature: '(unknown[]) => boolean',
|
|
1848
|
-
};
|
|
1849
|
-
|
|
1850
|
-
function execute$3(value) {
|
|
1851
|
-
return String(value);
|
|
1852
|
-
}
|
|
1853
|
-
const string = {
|
|
1854
|
-
kind: 'imperative',
|
|
1855
|
-
execute: execute$3,
|
|
1856
|
-
signature: '(unknown) => string',
|
|
1857
|
-
};
|
|
1858
|
-
|
|
1859
|
-
/**
|
|
1860
|
-
* Switch statement with lazy case evaluation.
|
|
1861
|
-
* Supports array mode (legacy) and variadic mode.
|
|
1862
|
-
*/
|
|
1863
|
-
const switchFn = {
|
|
1864
|
-
kind: 'reactive',
|
|
1865
|
-
execute: (args) => {
|
|
1866
|
-
if (args.length < 2) {
|
|
1867
|
-
throw new Error('switch requires at least 2 arguments: value and default');
|
|
1868
|
-
}
|
|
1869
|
-
const valueComputed = args[0];
|
|
1870
|
-
return computed(() => {
|
|
1871
|
-
const state = new FunctionExecutionStateBuilder();
|
|
1872
|
-
const valueState = valueComputed.get();
|
|
1873
|
-
const earlyReturn = state.checkReady(valueState);
|
|
1874
|
-
if (earlyReturn)
|
|
1875
|
-
return earlyReturn;
|
|
1876
|
-
const value = valueState.value;
|
|
1877
|
-
if (args.length === 3) {
|
|
1878
|
-
const casesState = args[1].get();
|
|
1879
|
-
const defaultState = args[2].get();
|
|
1880
|
-
const casesEarlyReturn = state.checkReady(casesState);
|
|
1881
|
-
if (casesEarlyReturn)
|
|
1882
|
-
return casesEarlyReturn;
|
|
1883
|
-
const defaultEarlyReturn = state.checkReady(defaultState);
|
|
1884
|
-
if (defaultEarlyReturn)
|
|
1885
|
-
return defaultEarlyReturn;
|
|
1886
|
-
const cases = casesState.value;
|
|
1887
|
-
if (Array.isArray(cases)) {
|
|
1888
|
-
if (cases.length % 2 !== 0) {
|
|
1889
|
-
throw new Error('Cases array should have even number of elements');
|
|
1890
|
-
}
|
|
1891
|
-
const matchIndex = cases.findIndex((caseValue, index) => index % 2 === 0 && caseValue === value);
|
|
1892
|
-
const returnValue = matchIndex >= 0 ? cases[matchIndex + 1] : defaultState.value;
|
|
1893
|
-
return state.success(returnValue);
|
|
1894
|
-
}
|
|
1895
|
-
}
|
|
1896
|
-
const defaultComputed = args[args.length - 1];
|
|
1897
|
-
const caseArgs = args.slice(1, -1);
|
|
1898
|
-
if (caseArgs.length % 2 !== 0) {
|
|
1899
|
-
throw new Error('switch requires an even number of case arguments (key-value pairs)');
|
|
1900
|
-
}
|
|
1901
|
-
for (let i = 0; i < caseArgs.length; i += 2) {
|
|
1902
|
-
const caseKeyComputed = caseArgs[i];
|
|
1903
|
-
const caseValueComputed = caseArgs[i + 1];
|
|
1904
|
-
const caseKeyState = caseKeyComputed.get();
|
|
1905
|
-
const keyEarlyReturn = state.checkReady(caseKeyState);
|
|
1906
|
-
if (keyEarlyReturn)
|
|
1907
|
-
return keyEarlyReturn;
|
|
1908
|
-
const caseKey = caseKeyState.value;
|
|
1909
|
-
if (caseKey === value) {
|
|
1910
|
-
const caseValueState = caseValueComputed.get();
|
|
1911
|
-
const valueEarlyReturn = state.checkReady(caseValueState);
|
|
1912
|
-
if (valueEarlyReturn)
|
|
1913
|
-
return valueEarlyReturn;
|
|
1914
|
-
return state.success(caseValueState.value);
|
|
1915
|
-
}
|
|
1916
|
-
}
|
|
1917
|
-
const defaultState = defaultComputed.get();
|
|
1918
|
-
const defaultEarlyReturn = state.checkReady(defaultState);
|
|
1919
|
-
if (defaultEarlyReturn)
|
|
1920
|
-
return defaultEarlyReturn;
|
|
1921
|
-
return state.success(defaultState.value);
|
|
2174
|
+
const prevKey = result.key;
|
|
2175
|
+
const key = dimensionIndex === 0 ? keyPart : `${prevKey}:${keyPart}`;
|
|
2176
|
+
newVariables[`${Delimiters.Variable}trackBy`] = {
|
|
2177
|
+
_valueType: { type: 'string' },
|
|
2178
|
+
_value: String(key),
|
|
2179
|
+
_computation: null,
|
|
2180
|
+
_binding: null,
|
|
2181
|
+
};
|
|
2182
|
+
tempResults.push({ variables: newVariables, key });
|
|
2183
|
+
});
|
|
1922
2184
|
});
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
function execute$2(value) {
|
|
1928
|
-
return value.toLowerCase();
|
|
2185
|
+
results = tempResults;
|
|
2186
|
+
});
|
|
2187
|
+
return results;
|
|
1929
2188
|
}
|
|
1930
|
-
const
|
|
2189
|
+
const repeat = {
|
|
1931
2190
|
kind: 'imperative',
|
|
1932
2191
|
execute: execute$2,
|
|
1933
|
-
signature: '(string) =>
|
|
2192
|
+
signature: '({items: unknown[], itemsType: unknown, item: string, index: string, first: unknown, last: unknown, trackBy: unknown}[], componentSchema) => componentSchema[]',
|
|
1934
2193
|
};
|
|
1935
2194
|
|
|
1936
|
-
function execute$1(
|
|
1937
|
-
return
|
|
2195
|
+
function execute$1(ctx, selector) {
|
|
2196
|
+
return ComponentTreeApi.isCommandRunning(ctx.componentId, selector);
|
|
1938
2197
|
}
|
|
1939
|
-
const
|
|
2198
|
+
const running = {
|
|
1940
2199
|
kind: 'imperative',
|
|
2200
|
+
contextual: true,
|
|
1941
2201
|
execute: execute$1,
|
|
1942
|
-
signature: '(string) =>
|
|
2202
|
+
signature: '(string) => boolean',
|
|
1943
2203
|
};
|
|
1944
2204
|
|
|
1945
|
-
/**
|
|
1946
|
-
* All formula functions available in the system.
|
|
1947
|
-
*
|
|
1948
|
-
* Control flow functions use reactive implementations with lazy evaluation:
|
|
1949
|
-
* - `if`: Conditional evaluation (3 args: condition, trueValue, falseValue)
|
|
1950
|
-
* - `and`, `or`: Variadic logical operators with short-circuit evaluation
|
|
1951
|
-
* - `switch`: Variadic pattern matching with lazy case evaluation
|
|
1952
|
-
* - `some`, `every`: Array element checkers (imperative, not lazy)
|
|
1953
|
-
*/
|
|
1954
2205
|
const formulaFunctions$1 = {
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
collectValuesArray,
|
|
1958
|
-
propObject: collectValuesMap,
|
|
1959
|
-
propArray: collectValuesArray,
|
|
1960
|
-
findBy,
|
|
1961
|
-
findAllBy,
|
|
1962
|
-
at,
|
|
1963
|
-
not,
|
|
1964
|
-
equal,
|
|
1965
|
-
// Array element checkers (imperative)
|
|
1966
|
-
some,
|
|
1967
|
-
every,
|
|
1968
|
-
// Control flow (reactive with lazy evaluation)
|
|
1969
|
-
if: ifFn,
|
|
1970
|
-
and,
|
|
1971
|
-
or,
|
|
1972
|
-
switch: switchFn,
|
|
1973
|
-
// Utilities
|
|
1974
|
-
in: inFn,
|
|
1975
|
-
object: objectFn,
|
|
1976
|
-
bool,
|
|
1977
|
-
length,
|
|
1978
|
-
empty,
|
|
1979
|
-
concat,
|
|
1980
|
-
pluck,
|
|
1981
|
-
flatten,
|
|
1982
|
-
json,
|
|
1983
|
-
minus,
|
|
1984
|
-
plus,
|
|
1985
|
-
divide,
|
|
1986
|
-
multiply,
|
|
1987
|
-
running,
|
|
2206
|
+
propObject,
|
|
2207
|
+
propArray,
|
|
1988
2208
|
get: getFn,
|
|
1989
2209
|
id: idFn,
|
|
1990
|
-
repeat,
|
|
1991
|
-
emptyObject,
|
|
1992
|
-
arrayPluck,
|
|
1993
|
-
string,
|
|
1994
|
-
number,
|
|
1995
|
-
delay,
|
|
1996
2210
|
evaluating,
|
|
1997
2211
|
failed,
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
toLowerCase,
|
|
2001
|
-
ceil,
|
|
2002
|
-
floor,
|
|
2003
|
-
round,
|
|
2004
|
-
slice,
|
|
2005
|
-
filterIn,
|
|
2006
|
-
eq,
|
|
2007
|
-
neq,
|
|
2008
|
-
gt,
|
|
2009
|
-
lt,
|
|
2010
|
-
gte,
|
|
2011
|
-
lte,
|
|
2212
|
+
running,
|
|
2213
|
+
repeat,
|
|
2012
2214
|
};
|
|
2013
2215
|
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
FunctionRegistry.getInstance().setFunctions(formulaFunctions$1);
|
|
2019
|
-
}
|
|
2020
|
-
|
|
2021
|
-
const compiledCache = new WeakMap();
|
|
2022
|
-
function getOrCompile(structure, key) {
|
|
2023
|
-
let cached = compiledCache.get(structure);
|
|
2024
|
-
if (!cached) {
|
|
2025
|
-
cached = {};
|
|
2026
|
-
compiledCache.set(structure, cached);
|
|
2027
|
-
}
|
|
2028
|
-
if (!cached[key]) {
|
|
2029
|
-
cached[key] = createJsFunction(structure[key]);
|
|
2030
|
-
}
|
|
2031
|
-
return cached[key];
|
|
2032
|
-
}
|
|
2033
|
-
async function runCommand(node, ...args) {
|
|
2034
|
-
const structure = node.structure;
|
|
2035
|
-
if (!structure) {
|
|
2036
|
-
const comp = node.position.componentId
|
|
2037
|
-
? ComponentStore.getInstance().getComponent(node.position.componentId)
|
|
2038
|
-
: null;
|
|
2039
|
-
const src = comp?.sourceUrl ? `[${comp.sourceUrl}] ` : '';
|
|
2040
|
-
log.trace(`${src}Command is empty — no handler was bound to it.`);
|
|
2041
|
-
return null;
|
|
2042
|
-
}
|
|
2043
|
-
const component = ComponentStore.getInstance().getComponentOrThrow(structure.owner);
|
|
2044
|
-
const src = component.sourceUrl ? `[${component.sourceUrl}] ` : '';
|
|
2045
|
-
const functionsProxy = proxifySubCommands(component);
|
|
2046
|
-
try {
|
|
2047
|
-
if (structure.init) {
|
|
2048
|
-
log.trace(`${src}Running init hook`);
|
|
2049
|
-
const initFunc = getOrCompile(structure, 'init');
|
|
2050
|
-
await initFunc(functionsProxy, args);
|
|
2051
|
-
}
|
|
2052
|
-
if (structure.runnerType === 'inline') {
|
|
2053
|
-
log.trace(`${src}Executing inline callback (${args.length} args)`);
|
|
2054
|
-
return await structure.target(...args);
|
|
2055
|
-
}
|
|
2056
|
-
const preview = structure.target.slice(0, 80);
|
|
2057
|
-
log.trace(`${src}Executing command: ${preview}`);
|
|
2058
|
-
const targetFunc = getOrCompile(structure, 'target');
|
|
2059
|
-
return await targetFunc(functionsProxy, args);
|
|
2060
|
-
}
|
|
2061
|
-
catch (e) {
|
|
2062
|
-
throw new Error(`${src}Error executing ${structure.runnerType === 'inline' ? 'inline callback' : 'command'}`, {
|
|
2063
|
-
cause: e,
|
|
2064
|
-
});
|
|
2065
|
-
}
|
|
2066
|
-
finally {
|
|
2067
|
-
if (structure.finalize) {
|
|
2068
|
-
try {
|
|
2069
|
-
log.trace(`${src}Running finalize hook`);
|
|
2070
|
-
const finalizeFunc = getOrCompile(structure, 'finalize');
|
|
2071
|
-
await finalizeFunc(functionsProxy, args);
|
|
2072
|
-
}
|
|
2073
|
-
catch (finalizeError) {
|
|
2074
|
-
log.error(`${src}Error in finalize hook`, finalizeError);
|
|
2075
|
-
}
|
|
2076
|
-
}
|
|
2077
|
-
}
|
|
2078
|
-
}
|
|
2079
|
-
function proxifySubCommands(component) {
|
|
2080
|
-
return new Proxy({}, {
|
|
2081
|
-
get(target, functionName) {
|
|
2082
|
-
return (...functionArgs) => {
|
|
2083
|
-
let execute;
|
|
2084
|
-
if (functionName in target) {
|
|
2085
|
-
execute = target[functionName];
|
|
2086
|
-
}
|
|
2087
|
-
else {
|
|
2088
|
-
const def = DefinitionStore.getInstance().getCommand(functionName);
|
|
2089
|
-
execute = target[functionName] = def.execute;
|
|
2090
|
-
}
|
|
2091
|
-
const commandCtx = {
|
|
2092
|
-
componentId: component.id,
|
|
2093
|
-
};
|
|
2094
|
-
const result = execute(commandCtx, ...functionArgs);
|
|
2095
|
-
if (result instanceof Observable) {
|
|
2096
|
-
return firstValueFrom(result);
|
|
2097
|
-
}
|
|
2098
|
-
if (result instanceof Promise) {
|
|
2099
|
-
return result;
|
|
2100
|
-
}
|
|
2101
|
-
if (isComputed(result)) {
|
|
2102
|
-
return result.get();
|
|
2103
|
-
}
|
|
2104
|
-
return result;
|
|
2105
|
-
};
|
|
2106
|
-
},
|
|
2107
|
-
});
|
|
2108
|
-
}
|
|
2109
|
-
/**
|
|
2110
|
-
* Creates a JavaScript function from a string of code.
|
|
2111
|
-
*
|
|
2112
|
-
* SECURITY WARNING: This function uses `new Function()` to execute dynamic code.
|
|
2113
|
-
* Only use with schemas from trusted sources. Malicious schemas could execute
|
|
2114
|
-
* arbitrary code in the browser context, leading to XSS or data theft.
|
|
2115
|
-
*
|
|
2116
|
-
* The code has access to:
|
|
2117
|
-
* - All registered commands via destructured parameters
|
|
2118
|
-
* - Function arguments via the `args` parameter
|
|
2119
|
-
*/
|
|
2120
|
-
function createJsFunction(func) {
|
|
2121
|
-
const commandNames = DefinitionStore.getInstance().getCommandNames();
|
|
2122
|
-
const commandsStr = commandNames.length ? `{ ${commandNames.join(', ')} }` : 'commands';
|
|
2123
|
-
return new Function(commandsStr, 'args', `return (async () => { ${func} })();`);
|
|
2124
|
-
}
|
|
2125
|
-
|
|
2126
|
-
const componentsDefinitions$2 = {
|
|
2127
|
-
'sys.Box': {
|
|
2128
|
-
properties: {
|
|
2129
|
-
'content@component': null,
|
|
2130
|
-
},
|
|
2131
|
-
},
|
|
2132
|
-
'sys.Group': {
|
|
2133
|
-
properties: {
|
|
2134
|
-
'children@component[]': [],
|
|
2135
|
-
},
|
|
2136
|
-
},
|
|
2137
|
-
'sys.RefSpace': {
|
|
2138
|
-
traits: ['sys.Box'],
|
|
2139
|
-
properties: {},
|
|
2140
|
-
},
|
|
2141
|
-
'sys.Facade': {
|
|
2142
|
-
traits: ['sys.Box'],
|
|
2143
|
-
properties: {},
|
|
2144
|
-
},
|
|
2216
|
+
const sys = {
|
|
2217
|
+
definitions: componentsDefinitions$2,
|
|
2218
|
+
commands,
|
|
2219
|
+
functions: formulaFunctions$1,
|
|
2145
2220
|
};
|
|
2146
2221
|
|
|
2147
|
-
function autoRegisterCommonDefinitions() {
|
|
2148
|
-
DefinitionStore.getInstance().setComponents(unfoldComponentDefinitions(componentsDefinitions$2));
|
|
2149
|
-
}
|
|
2150
|
-
|
|
2151
2222
|
const componentsDefinitions$1 = {
|
|
2152
2223
|
'browser.Styled': {
|
|
2153
2224
|
properties: {
|
|
@@ -2166,26 +2237,92 @@ const componentsDefinitions$1 = {
|
|
|
2166
2237
|
properties: {
|
|
2167
2238
|
'click@()': null,
|
|
2168
2239
|
'stopPropagation@boolean': null,
|
|
2240
|
+
'contextMenu@()': null,
|
|
2169
2241
|
},
|
|
2170
2242
|
},
|
|
2171
2243
|
'browser.Focusable': {
|
|
2172
2244
|
traits: ['sys.Box'],
|
|
2173
2245
|
properties: {
|
|
2174
2246
|
'tabIndex@number': null,
|
|
2175
|
-
'blur@
|
|
2247
|
+
'blur@()': null,
|
|
2176
2248
|
},
|
|
2177
2249
|
},
|
|
2178
2250
|
'browser.Dialog': {
|
|
2179
2251
|
traits: ['sys.Box', 'browser.Styled'],
|
|
2180
2252
|
properties: {
|
|
2181
|
-
'close@(
|
|
2253
|
+
'close@()': null,
|
|
2254
|
+
},
|
|
2255
|
+
},
|
|
2256
|
+
'browser.Popover': {
|
|
2257
|
+
traits: ['sys.Box', 'browser.Styled'],
|
|
2258
|
+
properties: {
|
|
2259
|
+
'close@()': null,
|
|
2260
|
+
'mode@string': 'auto',
|
|
2261
|
+
'anchor@string': null,
|
|
2262
|
+
'positionArea@string': null,
|
|
2263
|
+
},
|
|
2264
|
+
},
|
|
2265
|
+
'browser.Link': {
|
|
2266
|
+
traits: ['sys.Group', 'browser.Styled'],
|
|
2267
|
+
properties: {
|
|
2268
|
+
'href@string': null,
|
|
2269
|
+
'target@string': null,
|
|
2270
|
+
'rel@string': null,
|
|
2271
|
+
},
|
|
2272
|
+
},
|
|
2273
|
+
'browser.Image': {
|
|
2274
|
+
traits: ['browser.Styled'],
|
|
2275
|
+
properties: {
|
|
2276
|
+
'src@string': null,
|
|
2277
|
+
'alt@string': null,
|
|
2278
|
+
'loading@string': null,
|
|
2279
|
+
},
|
|
2280
|
+
},
|
|
2281
|
+
'browser.Hoverable': {
|
|
2282
|
+
traits: ['sys.Box'],
|
|
2283
|
+
properties: {
|
|
2284
|
+
'mouseEnter@()': null,
|
|
2285
|
+
'mouseLeave@()': null,
|
|
2286
|
+
},
|
|
2287
|
+
},
|
|
2288
|
+
'browser.KeyListener': {
|
|
2289
|
+
traits: ['sys.Box'],
|
|
2290
|
+
properties: {
|
|
2291
|
+
'keyDown@(string)': null,
|
|
2292
|
+
'keyUp@(string)': null,
|
|
2293
|
+
},
|
|
2294
|
+
},
|
|
2295
|
+
'browser.Scrollable': {
|
|
2296
|
+
traits: ['sys.Box'],
|
|
2297
|
+
properties: {
|
|
2298
|
+
'scroll@()': null,
|
|
2299
|
+
},
|
|
2300
|
+
},
|
|
2301
|
+
'browser.Animated': {
|
|
2302
|
+
traits: ['sys.Box'],
|
|
2303
|
+
properties: {
|
|
2304
|
+
'animationEnd@()': null,
|
|
2305
|
+
'transitionEnd@()': null,
|
|
2306
|
+
},
|
|
2307
|
+
},
|
|
2308
|
+
'browser.Visible': {
|
|
2309
|
+
traits: ['sys.Box'],
|
|
2310
|
+
properties: {
|
|
2311
|
+
'visible@()': null,
|
|
2312
|
+
'invisible@()': null,
|
|
2313
|
+
},
|
|
2314
|
+
},
|
|
2315
|
+
'browser.Resizable': {
|
|
2316
|
+
traits: ['sys.Box'],
|
|
2317
|
+
properties: {
|
|
2318
|
+
'resize@()': null,
|
|
2182
2319
|
},
|
|
2183
2320
|
},
|
|
2184
2321
|
};
|
|
2185
2322
|
|
|
2186
|
-
|
|
2187
|
-
|
|
2188
|
-
}
|
|
2323
|
+
const browser = {
|
|
2324
|
+
definitions: componentsDefinitions$1,
|
|
2325
|
+
};
|
|
2189
2326
|
|
|
2190
2327
|
const componentsDefinitions = {
|
|
2191
2328
|
'forms.Input': {
|
|
@@ -2483,12 +2620,14 @@ function registerShapes() {
|
|
|
2483
2620
|
},
|
|
2484
2621
|
});
|
|
2485
2622
|
}
|
|
2486
|
-
|
|
2487
|
-
|
|
2488
|
-
|
|
2489
|
-
|
|
2490
|
-
|
|
2491
|
-
|
|
2623
|
+
const forms = {
|
|
2624
|
+
definitions: componentsDefinitions,
|
|
2625
|
+
functions: formulaFunctions,
|
|
2626
|
+
setup() {
|
|
2627
|
+
registerShapes();
|
|
2628
|
+
registerValidators(validators);
|
|
2629
|
+
},
|
|
2630
|
+
};
|
|
2492
2631
|
|
|
2493
2632
|
function initRuntime() {
|
|
2494
2633
|
componentTreeConfig.runCommand = runCommand;
|
|
@@ -2498,5 +2637,5 @@ function initRuntime() {
|
|
|
2498
2637
|
* Generated bundle index. Do not edit.
|
|
2499
2638
|
*/
|
|
2500
2639
|
|
|
2501
|
-
export { activateNode, activateStructure,
|
|
2640
|
+
export { activateNode, activateStructure, browser, common, componentInstanceMap, debugName, forms, initRuntime, registerPlugin, registerPlugins, registerValidator, registerValidators, runCommand, sys, templateLoadingTracker };
|
|
2502
2641
|
//# sourceMappingURL=kaskad-core.mjs.map
|