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