@flowgram-vue/variable-core 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. package/LICENSE +22 -0
  2. package/dist/index.cjs +2630 -0
  3. package/dist/index.cjs.map +1 -0
  4. package/dist/index.d.ts +2293 -0
  5. package/dist/index.js +2592 -0
  6. package/dist/index.js.map +1 -0
  7. package/package.json +68 -0
  8. package/src/ast/ast-node.ts +374 -0
  9. package/src/ast/ast-registers.ts +129 -0
  10. package/src/ast/common/data-node.ts +63 -0
  11. package/src/ast/common/index.ts +8 -0
  12. package/src/ast/common/list-node.ts +70 -0
  13. package/src/ast/common/map-node.ts +89 -0
  14. package/src/ast/declaration/base-variable-field.ts +184 -0
  15. package/src/ast/declaration/index.ts +13 -0
  16. package/src/ast/declaration/property.ts +19 -0
  17. package/src/ast/declaration/variable-declaration-list.ts +112 -0
  18. package/src/ast/declaration/variable-declaration.ts +78 -0
  19. package/src/ast/expression/base-expression.ts +117 -0
  20. package/src/ast/expression/enumerate-expression.ts +77 -0
  21. package/src/ast/expression/index.ts +10 -0
  22. package/src/ast/expression/keypath-expression.ts +157 -0
  23. package/src/ast/expression/legacy-keypath-expression.ts +119 -0
  24. package/src/ast/expression/wrap-array-expression.ts +96 -0
  25. package/src/ast/factory.ts +163 -0
  26. package/src/ast/flags.ts +50 -0
  27. package/src/ast/index.ts +26 -0
  28. package/src/ast/match.ts +146 -0
  29. package/src/ast/type/array.ts +109 -0
  30. package/src/ast/type/base-type.ts +49 -0
  31. package/src/ast/type/boolean.ts +26 -0
  32. package/src/ast/type/custom-type.ts +70 -0
  33. package/src/ast/type/index.ts +19 -0
  34. package/src/ast/type/integer.ts +29 -0
  35. package/src/ast/type/map.ts +96 -0
  36. package/src/ast/type/number.ts +26 -0
  37. package/src/ast/type/object.ts +185 -0
  38. package/src/ast/type/string.ts +55 -0
  39. package/src/ast/type/union.ts +13 -0
  40. package/src/ast/types.ts +188 -0
  41. package/src/ast/utils/expression.ts +61 -0
  42. package/src/ast/utils/helpers.ts +73 -0
  43. package/src/ast/utils/inversify.ts +42 -0
  44. package/src/ast/utils/observable.ts +5 -0
  45. package/src/ast/utils/variable-field.ts +25 -0
  46. package/src/composables/index.ts +9 -0
  47. package/src/composables/scope-provider.ts +78 -0
  48. package/src/composables/use-available-variables.ts +39 -0
  49. package/src/composables/use-output-variables.ts +36 -0
  50. package/src/composables/use-scope-available.ts +32 -0
  51. package/src/index.ts +14 -0
  52. package/src/providers.ts +22 -0
  53. package/src/scope/datas/index.ts +8 -0
  54. package/src/scope/datas/scope-available-data.ts +234 -0
  55. package/src/scope/datas/scope-event-data.ts +67 -0
  56. package/src/scope/datas/scope-output-data.ts +151 -0
  57. package/src/scope/index.ts +9 -0
  58. package/src/scope/scope-chain.ts +69 -0
  59. package/src/scope/scope.ts +200 -0
  60. package/src/scope/types.ts +102 -0
  61. package/src/scope/variable-table.ts +203 -0
  62. package/src/services/index.ts +6 -0
  63. package/src/services/variable-field-key-rename-service.ts +131 -0
  64. package/src/utils/memo.ts +38 -0
  65. package/src/utils/toDisposable.ts +16 -0
  66. package/src/variable-container-module.ts +28 -0
  67. package/src/variable-engine.ts +197 -0
package/dist/index.cjs ADDED
@@ -0,0 +1,2630 @@
1
+ 'use strict';
2
+
3
+ var inversify = require('inversify');
4
+ var rxjs = require('rxjs');
5
+ var utils = require('@flowgram-vue/utils');
6
+ var lodashEs = require('lodash-es');
7
+ var nanoid = require('nanoid');
8
+ var fastEquals = require('fast-equals');
9
+ var vue = require('vue');
10
+ var core = require('@flowgram-vue/core');
11
+
12
+ var __defProp = Object.defineProperty;
13
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
14
+ var __decorateClass = (decorators, target, key, kind) => {
15
+ var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
16
+ for (var i = decorators.length - 1, decorator; i >= 0; i--)
17
+ if (decorator = decorators[i])
18
+ result = (kind ? decorator(target, key, result) : decorator(result)) || result;
19
+ if (kind && result) __defProp(target, key, result);
20
+ return result;
21
+ };
22
+ var __decorateParam = (index, decorator) => (target, key) => decorator(target, key, index);
23
+ function subsToDisposable(subscription) {
24
+ return utils.Disposable.create(() => subscription.unsubscribe());
25
+ }
26
+
27
+ // src/utils/memo.ts
28
+ var createMemo = () => {
29
+ const _memoCache = /* @__PURE__ */ new Map();
30
+ const memo = (key, fn) => {
31
+ if (_memoCache.has(key)) {
32
+ return _memoCache.get(key);
33
+ }
34
+ const data = fn();
35
+ _memoCache.set(key, data);
36
+ return data;
37
+ };
38
+ const clear = (key) => {
39
+ if (key) {
40
+ _memoCache.delete(key);
41
+ } else {
42
+ _memoCache.clear();
43
+ }
44
+ };
45
+ memo.clear = clear;
46
+ return memo;
47
+ };
48
+ var VariableTable = class {
49
+ constructor(parentTable) {
50
+ this.parentTable = parentTable;
51
+ this.table = /* @__PURE__ */ new Map();
52
+ this.toDispose = new utils.DisposableCollection();
53
+ /**
54
+ * @deprecated
55
+ */
56
+ this.onDataChangeEmitter = new utils.Emitter();
57
+ this.variables$ = new rxjs.Subject();
58
+ /**
59
+ * An observable that listens for value changes on any variable within the table.
60
+ */
61
+ this.anyVariableChange$ = this.variables$.pipe(
62
+ rxjs.switchMap(
63
+ (_variables) => rxjs.merge(
64
+ ..._variables.map(
65
+ (_v) => _v.value$.pipe(
66
+ // Skip the initial value of the BehaviorSubject
67
+ rxjs.skip(1)
68
+ )
69
+ )
70
+ )
71
+ ),
72
+ rxjs.share()
73
+ );
74
+ /**
75
+ * @deprecated Use onListOrAnyVarChange instead.
76
+ */
77
+ this.onDataChange = this.onDataChangeEmitter.event;
78
+ this._version = 0;
79
+ this.toDispose.pushAll([
80
+ this.onDataChangeEmitter,
81
+ // Activate the share() operator
82
+ this.onAnyVariableChange(() => {
83
+ this.bumpVersion();
84
+ })
85
+ ]);
86
+ }
87
+ /**
88
+ * Subscribes to updates on any variable in the list.
89
+ * @param observer A function to be called when any variable's value changes.
90
+ * @returns A disposable object to unsubscribe from the updates.
91
+ */
92
+ onAnyVariableChange(observer) {
93
+ return subsToDisposable(this.anyVariableChange$.subscribe(observer));
94
+ }
95
+ /**
96
+ * Subscribes to changes in the variable list (additions or removals).
97
+ * @param observer A function to be called when the list of variables changes.
98
+ * @returns A disposable object to unsubscribe from the updates.
99
+ */
100
+ onVariableListChange(observer) {
101
+ return subsToDisposable(this.variables$.subscribe(observer));
102
+ }
103
+ /**
104
+ * Subscribes to both variable list changes and updates to any variable in the list.
105
+ * @param observer A function to be called when either the list or a variable in it changes.
106
+ * @returns A disposable collection to unsubscribe from both events.
107
+ */
108
+ onListOrAnyVarChange(observer) {
109
+ const disposables = new utils.DisposableCollection();
110
+ disposables.pushAll([this.onVariableListChange(observer), this.onAnyVariableChange(observer)]);
111
+ return disposables;
112
+ }
113
+ /**
114
+ * Fires change events to notify listeners that the data has been updated.
115
+ */
116
+ fireChange() {
117
+ this.bumpVersion();
118
+ this.onDataChangeEmitter.fire();
119
+ this.variables$.next(this.variables);
120
+ this.parentTable?.fireChange();
121
+ }
122
+ /**
123
+ * The current version of the variable table, incremented on each change.
124
+ */
125
+ get version() {
126
+ return this._version;
127
+ }
128
+ /**
129
+ * Increments the version number, resetting to 0 if it reaches MAX_SAFE_INTEGER.
130
+ */
131
+ bumpVersion() {
132
+ this._version = this._version + 1;
133
+ if (this._version === Number.MAX_SAFE_INTEGER) {
134
+ this._version = 0;
135
+ }
136
+ }
137
+ /**
138
+ * An array of all variables in the table.
139
+ */
140
+ get variables() {
141
+ return Array.from(this.table.values());
142
+ }
143
+ /**
144
+ * An array of all variable keys in the table.
145
+ */
146
+ get variableKeys() {
147
+ return Array.from(this.table.keys());
148
+ }
149
+ /**
150
+ * Retrieves a variable or a nested property field by its key path.
151
+ * @param keyPath An array of keys representing the path to the desired field.
152
+ * @returns The found variable or property field, or undefined if not found.
153
+ */
154
+ getByKeyPath(keyPath) {
155
+ const [variableKey, ...propertyKeys] = keyPath || [];
156
+ if (!variableKey) {
157
+ return;
158
+ }
159
+ const variable = this.getVariableByKey(variableKey);
160
+ return propertyKeys.length ? variable?.getByKeyPath(propertyKeys) : variable;
161
+ }
162
+ /**
163
+ * Retrieves a variable by its key.
164
+ * @param key The key of the variable to retrieve.
165
+ * @returns The variable declaration if found, otherwise undefined.
166
+ */
167
+ getVariableByKey(key) {
168
+ return this.table.get(key);
169
+ }
170
+ /**
171
+ * Adds a variable to the table.
172
+ * If a parent table exists, the variable is also added to the parent.
173
+ * @param variable The variable declaration to add.
174
+ */
175
+ addVariableToTable(variable) {
176
+ this.table.set(variable.key, variable);
177
+ if (this.parentTable) {
178
+ this.parentTable.addVariableToTable(variable);
179
+ }
180
+ }
181
+ /**
182
+ * Removes a variable from the table.
183
+ * If a parent table exists, the variable is also removed from the parent.
184
+ * @param key The key of the variable to remove.
185
+ */
186
+ removeVariableFromTable(key) {
187
+ this.table.delete(key);
188
+ if (this.parentTable) {
189
+ this.parentTable.removeVariableFromTable(key);
190
+ }
191
+ }
192
+ /**
193
+ * Disposes of all resources used by the variable table.
194
+ */
195
+ dispose() {
196
+ this.variableKeys.forEach(
197
+ (_key) => this.parentTable?.removeVariableFromTable(_key)
198
+ );
199
+ this.parentTable?.fireChange();
200
+ this.variables$.complete();
201
+ this.variables$.unsubscribe();
202
+ this.toDispose.dispose();
203
+ }
204
+ };
205
+
206
+ // src/providers.ts
207
+ var VariableEngineProvider = /* @__PURE__ */ Symbol("DynamicVariableEngine");
208
+ var ContainerProvider = /* @__PURE__ */ Symbol("ContainerProvider");
209
+
210
+ // src/scope/scope-chain.ts
211
+ exports.ScopeChain = class ScopeChain {
212
+ constructor() {
213
+ this.toDispose = new utils.DisposableCollection();
214
+ }
215
+ get variableEngine() {
216
+ return this.variableEngineProvider();
217
+ }
218
+ /**
219
+ * Refreshes the dependency and coverage relationships for all scopes.
220
+ */
221
+ refreshAllChange() {
222
+ this.variableEngine.getAllScopes().forEach((_scope) => {
223
+ _scope.refreshCovers();
224
+ _scope.refreshDeps();
225
+ });
226
+ }
227
+ dispose() {
228
+ this.toDispose.dispose();
229
+ }
230
+ get disposed() {
231
+ return this.toDispose.disposed;
232
+ }
233
+ get onDispose() {
234
+ return this.toDispose.onDispose;
235
+ }
236
+ };
237
+ __decorateClass([
238
+ inversify.inject(VariableEngineProvider)
239
+ ], exports.ScopeChain.prototype, "variableEngineProvider", 2);
240
+ exports.ScopeChain = __decorateClass([
241
+ inversify.injectable()
242
+ ], exports.ScopeChain);
243
+
244
+ // src/ast/types.ts
245
+ var ASTKind = /* @__PURE__ */ ((ASTKind2) => {
246
+ ASTKind2["String"] = "String";
247
+ ASTKind2["Number"] = "Number";
248
+ ASTKind2["Integer"] = "Integer";
249
+ ASTKind2["Boolean"] = "Boolean";
250
+ ASTKind2["Object"] = "Object";
251
+ ASTKind2["Array"] = "Array";
252
+ ASTKind2["Map"] = "Map";
253
+ ASTKind2["Union"] = "Union";
254
+ ASTKind2["Any"] = "Any";
255
+ ASTKind2["CustomType"] = "CustomType";
256
+ ASTKind2["Property"] = "Property";
257
+ ASTKind2["VariableDeclaration"] = "VariableDeclaration";
258
+ ASTKind2["VariableDeclarationList"] = "VariableDeclarationList";
259
+ ASTKind2["KeyPathExpression"] = "KeyPathExpression";
260
+ ASTKind2["EnumerateExpression"] = "EnumerateExpression";
261
+ ASTKind2["WrapArrayExpression"] = "WrapArrayExpression";
262
+ ASTKind2["ListNode"] = "ListNode";
263
+ ASTKind2["DataNode"] = "DataNode";
264
+ ASTKind2["MapNode"] = "MapNode";
265
+ return ASTKind2;
266
+ })(ASTKind || {});
267
+
268
+ // src/ast/utils/inversify.ts
269
+ var injectToAST = (serviceIdentifier) => function(target, propertyKey) {
270
+ if (!serviceIdentifier) {
271
+ throw new Error(
272
+ `ServiceIdentifier ${serviceIdentifier} in @lazyInject is Empty, it might be caused by file circular dependency, please check it.`
273
+ );
274
+ }
275
+ const descriptor = {
276
+ get() {
277
+ const container = this.scope.variableEngine.container;
278
+ return container.get(serviceIdentifier);
279
+ },
280
+ set() {
281
+ },
282
+ configurable: true,
283
+ enumerable: true
284
+ };
285
+ return descriptor;
286
+ };
287
+ var POST_CONSTRUCT_AST_SYMBOL = /* @__PURE__ */ Symbol("post_construct_ast");
288
+ var postConstructAST = () => (target, propertyKey) => {
289
+ if (!Reflect.hasMetadata(POST_CONSTRUCT_AST_SYMBOL, target)) {
290
+ Reflect.defineMetadata(POST_CONSTRUCT_AST_SYMBOL, propertyKey, target);
291
+ } else {
292
+ throw Error("Duplication Post Construct AST");
293
+ }
294
+ };
295
+
296
+ // src/ast/flags.ts
297
+ var ASTNodeFlags = /* @__PURE__ */ ((ASTNodeFlags2) => {
298
+ ASTNodeFlags2[ASTNodeFlags2["None"] = 0] = "None";
299
+ ASTNodeFlags2[ASTNodeFlags2["VariableField"] = 1] = "VariableField";
300
+ ASTNodeFlags2[ASTNodeFlags2["Expression"] = 4] = "Expression";
301
+ ASTNodeFlags2[ASTNodeFlags2["BasicType"] = 8] = "BasicType";
302
+ ASTNodeFlags2[ASTNodeFlags2["DrilldownType"] = 16] = "DrilldownType";
303
+ ASTNodeFlags2[ASTNodeFlags2["EnumerateType"] = 32] = "EnumerateType";
304
+ ASTNodeFlags2[ASTNodeFlags2["UnionType"] = 64] = "UnionType";
305
+ ASTNodeFlags2[ASTNodeFlags2["VariableType"] = 120] = "VariableType";
306
+ return ASTNodeFlags2;
307
+ })(ASTNodeFlags || {});
308
+
309
+ // src/ast/match.ts
310
+ exports.ASTMatch = void 0;
311
+ ((ASTMatch2) => {
312
+ ASTMatch2.isString = (node) => node?.kind === "String" /* String */;
313
+ ASTMatch2.isNumber = (node) => node?.kind === "Number" /* Number */;
314
+ ASTMatch2.isBoolean = (node) => node?.kind === "Boolean" /* Boolean */;
315
+ ASTMatch2.isInteger = (node) => node?.kind === "Integer" /* Integer */;
316
+ ASTMatch2.isObject = (node) => node?.kind === "Object" /* Object */;
317
+ ASTMatch2.isArray = (node) => node?.kind === "Array" /* Array */;
318
+ ASTMatch2.isMap = (node) => node?.kind === "Map" /* Map */;
319
+ ASTMatch2.isCustomType = (node) => node?.kind === "CustomType" /* CustomType */;
320
+ ASTMatch2.isVariableDeclaration = (node) => node?.kind === "VariableDeclaration" /* VariableDeclaration */;
321
+ ASTMatch2.isProperty = (node) => node?.kind === "Property" /* Property */;
322
+ ASTMatch2.isBaseVariableField = (node) => !!(node?.flags || 0 & 1 /* VariableField */);
323
+ ASTMatch2.isVariableDeclarationList = (node) => node?.kind === "VariableDeclarationList" /* VariableDeclarationList */;
324
+ ASTMatch2.isEnumerateExpression = (node) => node?.kind === "EnumerateExpression" /* EnumerateExpression */;
325
+ ASTMatch2.isWrapArrayExpression = (node) => node?.kind === "WrapArrayExpression" /* WrapArrayExpression */;
326
+ ASTMatch2.isKeyPathExpression = (node) => node?.kind === "KeyPathExpression" /* KeyPathExpression */;
327
+ function is(node, targetType) {
328
+ return node?.kind === targetType?.kind;
329
+ }
330
+ ASTMatch2.is = is;
331
+ })(exports.ASTMatch || (exports.ASTMatch = {}));
332
+
333
+ // src/ast/utils/helpers.ts
334
+ function updateChildNodeHelper({
335
+ getChildNode,
336
+ updateChildNode,
337
+ removeChildNode,
338
+ nextJSON
339
+ }) {
340
+ const currNode = getChildNode();
341
+ const isNewKind = currNode?.kind !== nextJSON?.kind;
342
+ const isNewKey = nextJSON?.key && nextJSON?.key !== currNode?.key;
343
+ if (isNewKind || isNewKey) {
344
+ if (currNode) {
345
+ currNode.dispose();
346
+ removeChildNode();
347
+ }
348
+ if (nextJSON) {
349
+ const newNode = this.createChildNode(nextJSON);
350
+ updateChildNode(newNode);
351
+ this.fireChange();
352
+ return newNode;
353
+ } else {
354
+ this.fireChange();
355
+ }
356
+ } else if (nextJSON) {
357
+ currNode?.fromJSON(nextJSON);
358
+ }
359
+ return currNode;
360
+ }
361
+ function parseTypeJsonOrKind(typeJSONOrKind) {
362
+ return typeof typeJSONOrKind === "string" ? { kind: typeJSONOrKind } : typeJSONOrKind;
363
+ }
364
+ function getAllChildren(ast) {
365
+ return [...ast.children, ...ast.children.map((_child) => getAllChildren(_child)).flat()];
366
+ }
367
+ function isMatchAST(node, targetType) {
368
+ return exports.ASTMatch.is(node, targetType);
369
+ }
370
+ var ASTNode = class _ASTNode {
371
+ /**
372
+ * Constructor.
373
+ * @param createParams Necessary parameters for creating an ASTNode.
374
+ * @param injectOptions Dependency injection for various modules.
375
+ */
376
+ constructor({ key, parent, scope }, opts) {
377
+ /**
378
+ * Node flags, used to record some flag information.
379
+ */
380
+ this.flags = 0 /* None */;
381
+ /**
382
+ * The version number of the ASTNode, which increments by 1 each time `fireChange` is called.
383
+ */
384
+ this._version = 0;
385
+ /**
386
+ * Update lock.
387
+ * - When set to `true`, `fireChange` will not trigger any events.
388
+ * - This is useful when multiple updates are needed, and you want to avoid multiple triggers.
389
+ */
390
+ this.changeLocked = false;
391
+ /**
392
+ * Parameters related to batch updates.
393
+ */
394
+ this._batch = {
395
+ batching: false,
396
+ hasChangesInBatch: false
397
+ };
398
+ /**
399
+ * AST node change Observable events, implemented based on RxJS.
400
+ * - Emits the current ASTNode value upon subscription.
401
+ * - Emits a new value whenever `fireChange` is called.
402
+ */
403
+ this.value$ = new rxjs.BehaviorSubject(this);
404
+ /**
405
+ * Child ASTNodes.
406
+ */
407
+ this._children = /* @__PURE__ */ new Set();
408
+ /**
409
+ * List of disposal handlers for the ASTNode.
410
+ */
411
+ this.toDispose = new utils.DisposableCollection(
412
+ utils.Disposable.create(() => {
413
+ this.parent?.fireChange();
414
+ this.children.forEach((child) => child.dispose());
415
+ })
416
+ );
417
+ /**
418
+ * Callback triggered upon disposal.
419
+ */
420
+ this.onDispose = this.toDispose.onDispose;
421
+ this.scope = scope;
422
+ this.parent = parent;
423
+ this.opts = opts;
424
+ this.key = key || nanoid.nanoid();
425
+ this.fromJSON = this.withBatchUpdate(this.fromJSON.bind(this));
426
+ const rawToJSON = this.toJSON?.bind(this);
427
+ this.toJSON = () => lodashEs.omitBy(
428
+ {
429
+ // always include kind
430
+ kind: this.kind,
431
+ ...rawToJSON?.() || {}
432
+ },
433
+ // remove undefined fields
434
+ lodashEs.isNil
435
+ );
436
+ }
437
+ /**
438
+ * The type of the ASTNode.
439
+ */
440
+ get kind() {
441
+ if (!this.constructor.kind) {
442
+ throw new Error(`ASTNode Registry need a kind: ${this.constructor.name}`);
443
+ }
444
+ return this.constructor.kind;
445
+ }
446
+ /**
447
+ * Gets all child ASTNodes of the current ASTNode.
448
+ */
449
+ get children() {
450
+ return Array.from(this._children);
451
+ }
452
+ /**
453
+ * Creates a child ASTNode.
454
+ * @param json The AST JSON of the child ASTNode.
455
+ * @returns
456
+ */
457
+ createChildNode(json) {
458
+ const astRegisters = this.scope.variableEngine.astRegisters;
459
+ const child = astRegisters.createAST(json, {
460
+ parent: this,
461
+ scope: this.scope
462
+ });
463
+ this._children.add(child);
464
+ child.toDispose.push(
465
+ utils.Disposable.create(() => {
466
+ this._children.delete(child);
467
+ })
468
+ );
469
+ return child;
470
+ }
471
+ /**
472
+ * Updates a child ASTNode, quickly implementing the consumption logic for child ASTNode updates.
473
+ * @param keyInThis The specified key on the current object.
474
+ */
475
+ updateChildNodeByKey(keyInThis, nextJSON) {
476
+ this.withBatchUpdate(updateChildNodeHelper).call(this, {
477
+ getChildNode: () => this[keyInThis],
478
+ updateChildNode: (_node) => this[keyInThis] = _node,
479
+ removeChildNode: () => this[keyInThis] = void 0,
480
+ nextJSON
481
+ });
482
+ }
483
+ /**
484
+ * Batch updates the ASTNode, merging all `fireChange` calls within the batch function into one.
485
+ * @param updater The batch function.
486
+ * @returns
487
+ */
488
+ withBatchUpdate(updater) {
489
+ return (...args) => {
490
+ if (this._batch.batching) {
491
+ return updater.call(this, ...args);
492
+ }
493
+ this._batch.hasChangesInBatch = false;
494
+ this._batch.batching = true;
495
+ const res = updater.call(this, ...args);
496
+ this._batch.batching = false;
497
+ if (this._batch.hasChangesInBatch) {
498
+ this.fireChange();
499
+ }
500
+ this._batch.hasChangesInBatch = false;
501
+ return res;
502
+ };
503
+ }
504
+ /**
505
+ * Triggers an update for the current node.
506
+ */
507
+ fireChange() {
508
+ if (this.changeLocked || this.disposed) {
509
+ return;
510
+ }
511
+ if (this._batch.batching) {
512
+ this._batch.hasChangesInBatch = true;
513
+ return;
514
+ }
515
+ this._version++;
516
+ this.value$.next(this);
517
+ this.dispatchGlobalEvent({ type: "UpdateAST" });
518
+ this.parent?.fireChange();
519
+ }
520
+ /**
521
+ * The version value of the ASTNode.
522
+ * - You can used to check whether ASTNode are updated.
523
+ */
524
+ get version() {
525
+ return this._version;
526
+ }
527
+ /**
528
+ * The unique hash value of the ASTNode.
529
+ * - It will update when the ASTNode is updated.
530
+ * - You can used to check two ASTNode are equal.
531
+ */
532
+ get hash() {
533
+ return `${this._version}${this.kind}${this.key}`;
534
+ }
535
+ /**
536
+ * Listens for changes to the ASTNode.
537
+ * @param observer The listener callback.
538
+ * @param selector Listens for specified data.
539
+ * @returns
540
+ */
541
+ subscribe(observer, { selector, debounceAnimation, triggerOnInit } = {}) {
542
+ return subsToDisposable(
543
+ this.value$.pipe(
544
+ rxjs.map(() => selector ? selector(this) : this),
545
+ rxjs.distinctUntilChanged(
546
+ (a, b) => fastEquals.shallowEqual(a, b),
547
+ (value) => {
548
+ if (value instanceof _ASTNode) {
549
+ return value.hash;
550
+ }
551
+ return value;
552
+ }
553
+ ),
554
+ // By default, skip the first trigger of BehaviorSubject.
555
+ triggerOnInit ? rxjs.tap(() => null) : rxjs.skip(1),
556
+ // All updates within each animationFrame are merged into one.
557
+ debounceAnimation ? rxjs.debounceTime(0, rxjs.animationFrameScheduler) : rxjs.tap(() => null)
558
+ ).subscribe(observer)
559
+ );
560
+ }
561
+ /**
562
+ * Dispatches a global event for the current ASTNode.
563
+ * @param event The global event.
564
+ */
565
+ dispatchGlobalEvent(event) {
566
+ this.scope.event.dispatch({
567
+ ...event,
568
+ ast: this
569
+ });
570
+ }
571
+ /**
572
+ * Disposes the ASTNode.
573
+ */
574
+ dispose() {
575
+ if (this.toDispose.disposed) {
576
+ return;
577
+ }
578
+ this.toDispose.dispose();
579
+ this.dispatchGlobalEvent({ type: "DisposeAST" });
580
+ this.value$.complete();
581
+ this.value$.unsubscribe();
582
+ }
583
+ get disposed() {
584
+ return this.toDispose.disposed;
585
+ }
586
+ };
587
+
588
+ // src/ast/type/base-type.ts
589
+ var BaseType = class extends ASTNode {
590
+ constructor() {
591
+ super(...arguments);
592
+ this.flags = 8 /* BasicType */;
593
+ }
594
+ /**
595
+ * Check if the current type is equal to the target type.
596
+ * @param targetTypeJSONOrKind The type to compare with.
597
+ * @returns `true` if the types are equal, `false` otherwise.
598
+ */
599
+ isTypeEqual(targetTypeJSONOrKind) {
600
+ const targetTypeJSON = parseTypeJsonOrKind(targetTypeJSONOrKind);
601
+ if (targetTypeJSON?.kind === "Union" /* Union */) {
602
+ return (targetTypeJSON?.types || [])?.some(
603
+ (_subType) => this.isTypeEqual(_subType)
604
+ );
605
+ }
606
+ return this.kind === targetTypeJSON?.kind;
607
+ }
608
+ /**
609
+ * Get a variable field by key path.
610
+ *
611
+ * This method should be implemented by drillable types.
612
+ * @param keyPath The key path to search for.
613
+ * @returns The variable field if found, otherwise `undefined`.
614
+ */
615
+ getByKeyPath(keyPath = []) {
616
+ throw new Error(`Get By Key Path is not implemented for Type: ${this.kind}`);
617
+ }
618
+ };
619
+
620
+ // src/ast/type/array.ts
621
+ var ArrayType = class extends BaseType {
622
+ constructor() {
623
+ super(...arguments);
624
+ this.flags = 16 /* DrilldownType */ | 32 /* EnumerateType */;
625
+ }
626
+ /**
627
+ * Deserializes the `ArrayJSON` to the `ArrayType`.
628
+ * @param json The `ArrayJSON` to deserialize.
629
+ */
630
+ fromJSON({ items }) {
631
+ this.updateChildNodeByKey("items", parseTypeJsonOrKind(items));
632
+ }
633
+ /**
634
+ * Whether the items type can be drilled down.
635
+ */
636
+ get canDrilldownItems() {
637
+ return !!(this.items?.flags & 16 /* DrilldownType */);
638
+ }
639
+ /**
640
+ * Get a variable field by key path.
641
+ * @param keyPath The key path to search for.
642
+ * @returns The variable field if found, otherwise `undefined`.
643
+ */
644
+ getByKeyPath(keyPath) {
645
+ const [curr, ...rest] = keyPath || [];
646
+ if (curr === "0" && this.canDrilldownItems) {
647
+ return this.items.getByKeyPath(rest);
648
+ }
649
+ return void 0;
650
+ }
651
+ /**
652
+ * Check if the current type is equal to the target type.
653
+ * @param targetTypeJSONOrKind The type to compare with.
654
+ * @returns `true` if the types are equal, `false` otherwise.
655
+ */
656
+ isTypeEqual(targetTypeJSONOrKind) {
657
+ const targetTypeJSON = parseTypeJsonOrKind(targetTypeJSONOrKind);
658
+ const isSuperEqual = super.isTypeEqual(targetTypeJSONOrKind);
659
+ if (targetTypeJSON?.weak || targetTypeJSON?.kind === "Union" /* Union */) {
660
+ return isSuperEqual;
661
+ }
662
+ return targetTypeJSON && isSuperEqual && // Weak comparison, only need to compare the Kind.
663
+ (targetTypeJSON?.weak || this.customStrongEqual(targetTypeJSON));
664
+ }
665
+ /**
666
+ * Array strong comparison.
667
+ * @param targetTypeJSON The type to compare with.
668
+ * @returns `true` if the types are equal, `false` otherwise.
669
+ */
670
+ customStrongEqual(targetTypeJSON) {
671
+ if (!this.items) {
672
+ return !targetTypeJSON?.items;
673
+ }
674
+ return this.items?.isTypeEqual(targetTypeJSON.items);
675
+ }
676
+ /**
677
+ * Serialize the `ArrayType` to `ArrayJSON`
678
+ * @returns The JSON representation of `ArrayType`.
679
+ */
680
+ toJSON() {
681
+ return {
682
+ kind: "Array" /* Array */,
683
+ items: this.items?.toJSON()
684
+ };
685
+ }
686
+ };
687
+ ArrayType.kind = "Array" /* Array */;
688
+
689
+ // src/ast/type/string.ts
690
+ var StringType = class extends BaseType {
691
+ constructor() {
692
+ super(...arguments);
693
+ this.flags = 8 /* BasicType */;
694
+ }
695
+ /**
696
+ * see https://json-schema.org/understanding-json-schema/reference/string#format
697
+ */
698
+ get format() {
699
+ return this._format;
700
+ }
701
+ /**
702
+ * Deserialize the `StringJSON` to the `StringType`.
703
+ *
704
+ * @param json StringJSON representation of the `StringType`.
705
+ */
706
+ fromJSON(json) {
707
+ if (json?.format !== this._format) {
708
+ this._format = json?.format;
709
+ this.fireChange();
710
+ }
711
+ }
712
+ /**
713
+ * Serialize the `StringType` to `StringJSON`.
714
+ * @returns The JSON representation of `StringType`.
715
+ */
716
+ toJSON() {
717
+ return {
718
+ format: this._format
719
+ };
720
+ }
721
+ };
722
+ StringType.kind = "String" /* String */;
723
+
724
+ // src/ast/type/integer.ts
725
+ var IntegerType = class extends BaseType {
726
+ constructor() {
727
+ super(...arguments);
728
+ this.flags = 8 /* BasicType */;
729
+ }
730
+ /**
731
+ * Deserializes the `IntegerJSON` to the `IntegerType`.
732
+ * @param json The `IntegerJSON` to deserialize.
733
+ */
734
+ fromJSON() {
735
+ }
736
+ toJSON() {
737
+ return {};
738
+ }
739
+ };
740
+ IntegerType.kind = "Integer" /* Integer */;
741
+
742
+ // src/ast/type/boolean.ts
743
+ var BooleanType = class extends BaseType {
744
+ /**
745
+ * Deserializes the `BooleanJSON` to the `BooleanType`.
746
+ * @param json The `BooleanJSON` to deserialize.
747
+ */
748
+ fromJSON() {
749
+ }
750
+ toJSON() {
751
+ return {};
752
+ }
753
+ };
754
+ BooleanType.kind = "Boolean" /* Boolean */;
755
+
756
+ // src/ast/type/number.ts
757
+ var NumberType = class extends BaseType {
758
+ /**
759
+ * Deserializes the `NumberJSON` to the `NumberType`.
760
+ * @param json The `NumberJSON` to deserialize.
761
+ */
762
+ fromJSON() {
763
+ }
764
+ toJSON() {
765
+ return {};
766
+ }
767
+ };
768
+ NumberType.kind = "Number" /* Number */;
769
+
770
+ // src/ast/type/map.ts
771
+ var MapType = class extends BaseType {
772
+ /**
773
+ * Deserializes the `MapJSON` to the `MapType`.
774
+ * @param json The `MapJSON` to deserialize.
775
+ */
776
+ fromJSON({ keyType = "String" /* String */, valueType }) {
777
+ this.updateChildNodeByKey("keyType", parseTypeJsonOrKind(keyType));
778
+ this.updateChildNodeByKey("valueType", parseTypeJsonOrKind(valueType));
779
+ }
780
+ /**
781
+ * Check if the current type is equal to the target type.
782
+ * @param targetTypeJSONOrKind The type to compare with.
783
+ * @returns `true` if the types are equal, `false` otherwise.
784
+ */
785
+ isTypeEqual(targetTypeJSONOrKind) {
786
+ const targetTypeJSON = parseTypeJsonOrKind(targetTypeJSONOrKind);
787
+ const isSuperEqual = super.isTypeEqual(targetTypeJSONOrKind);
788
+ if (targetTypeJSON?.weak || targetTypeJSON?.kind === "Union" /* Union */) {
789
+ return isSuperEqual;
790
+ }
791
+ return targetTypeJSON && isSuperEqual && // Weak comparison, only need to compare the Kind.
792
+ (targetTypeJSON?.weak || this.customStrongEqual(targetTypeJSON));
793
+ }
794
+ /**
795
+ * Map strong comparison.
796
+ * @param targetTypeJSON The type to compare with.
797
+ * @returns `true` if the types are equal, `false` otherwise.
798
+ */
799
+ customStrongEqual(targetTypeJSON) {
800
+ const { keyType = "String" /* String */, valueType } = targetTypeJSON;
801
+ const isValueTypeEqual = !valueType && !this.valueType || this.valueType?.isTypeEqual(valueType);
802
+ return isValueTypeEqual && this.keyType?.isTypeEqual(keyType);
803
+ }
804
+ /**
805
+ * Serialize the node to a JSON object.
806
+ * @returns The JSON representation of the node.
807
+ */
808
+ toJSON() {
809
+ return {
810
+ kind: "Map" /* Map */,
811
+ keyType: this.keyType?.toJSON(),
812
+ valueType: this.valueType?.toJSON()
813
+ };
814
+ }
815
+ };
816
+ MapType.kind = "Map" /* Map */;
817
+ var ObjectType = class extends BaseType {
818
+ constructor() {
819
+ super(...arguments);
820
+ this.flags = 16 /* DrilldownType */;
821
+ /**
822
+ * A map of property keys to `Property` instances.
823
+ */
824
+ this.propertyTable = /* @__PURE__ */ new Map();
825
+ }
826
+ /**
827
+ * Deserializes the `ObjectJSON` to the `ObjectType`.
828
+ * @param json The `ObjectJSON` to deserialize.
829
+ */
830
+ fromJSON({ properties }) {
831
+ const removedKeys = new Set(this.propertyTable.keys());
832
+ const prev = [...this.properties || []];
833
+ this.properties = (properties || []).map((property) => {
834
+ const existProperty = this.propertyTable.get(property.key);
835
+ removedKeys.delete(property.key);
836
+ if (existProperty) {
837
+ existProperty.fromJSON(property);
838
+ return existProperty;
839
+ } else {
840
+ const newProperty = this.createChildNode({
841
+ ...property,
842
+ kind: "Property" /* Property */
843
+ });
844
+ this.fireChange();
845
+ this.propertyTable.set(property.key, newProperty);
846
+ return newProperty;
847
+ }
848
+ });
849
+ removedKeys.forEach((key) => {
850
+ const property = this.propertyTable.get(key);
851
+ property?.dispose();
852
+ this.propertyTable.delete(key);
853
+ this.fireChange();
854
+ });
855
+ this.dispatchGlobalEvent({
856
+ type: "ObjectPropertiesChange",
857
+ payload: {
858
+ prev,
859
+ next: [...this.properties]
860
+ }
861
+ });
862
+ }
863
+ /**
864
+ * Serialize the `ObjectType` to `ObjectJSON`.
865
+ * @returns The JSON representation of `ObjectType`.
866
+ */
867
+ toJSON() {
868
+ return {
869
+ properties: this.properties.map((_property) => _property.toJSON())
870
+ };
871
+ }
872
+ /**
873
+ * Get a variable field by key path.
874
+ * @param keyPath The key path to search for.
875
+ * @returns The variable field if found, otherwise `undefined`.
876
+ */
877
+ getByKeyPath(keyPath) {
878
+ const [curr, ...restKeyPath] = keyPath;
879
+ const property = this.propertyTable.get(curr);
880
+ if (!restKeyPath.length) {
881
+ return property;
882
+ }
883
+ if (property?.type && property?.type?.flags & 16 /* DrilldownType */) {
884
+ return property.type.getByKeyPath(restKeyPath);
885
+ }
886
+ return void 0;
887
+ }
888
+ /**
889
+ * Check if the current type is equal to the target type.
890
+ * @param targetTypeJSONOrKind The type to compare with.
891
+ * @returns `true` if the types are equal, `false` otherwise.
892
+ */
893
+ isTypeEqual(targetTypeJSONOrKind) {
894
+ const targetTypeJSON = parseTypeJsonOrKind(targetTypeJSONOrKind);
895
+ const isSuperEqual = super.isTypeEqual(targetTypeJSONOrKind);
896
+ if (targetTypeJSON?.weak || targetTypeJSON?.kind === "Union" /* Union */) {
897
+ return isSuperEqual;
898
+ }
899
+ return targetTypeJSON && isSuperEqual && // Weak comparison, only need to compare the Kind.
900
+ (targetTypeJSON?.weak || this.customStrongEqual(targetTypeJSON));
901
+ }
902
+ /**
903
+ * Object type strong comparison.
904
+ * @param targetTypeJSON The type to compare with.
905
+ * @returns `true` if the types are equal, `false` otherwise.
906
+ */
907
+ customStrongEqual(targetTypeJSON) {
908
+ const targetProperties = targetTypeJSON.properties || [];
909
+ const sourcePropertyKeys = Array.from(this.propertyTable.keys());
910
+ const targetPropertyKeys = targetProperties.map((_target) => _target.key);
911
+ const isKeyStrongEqual = !lodashEs.xor(sourcePropertyKeys, targetPropertyKeys).length;
912
+ return isKeyStrongEqual && targetProperties.every((targetProperty) => {
913
+ const sourceProperty = this.propertyTable.get(targetProperty.key);
914
+ return sourceProperty && sourceProperty.key === targetProperty.key && sourceProperty.type?.isTypeEqual(targetProperty?.type);
915
+ });
916
+ }
917
+ };
918
+ ObjectType.kind = "Object" /* Object */;
919
+
920
+ // src/ast/type/custom-type.ts
921
+ var CustomType = class extends BaseType {
922
+ /**
923
+ * The name of the custom type.
924
+ */
925
+ get typeName() {
926
+ return this._typeName;
927
+ }
928
+ /**
929
+ * Deserializes the `CustomTypeJSON` to the `CustomType`.
930
+ * @param json The `CustomTypeJSON` to deserialize.
931
+ */
932
+ fromJSON(json) {
933
+ if (this._typeName !== json.typeName) {
934
+ this._typeName = json.typeName;
935
+ this.fireChange();
936
+ }
937
+ }
938
+ /**
939
+ * Check if the current type is equal to the target type.
940
+ * @param targetTypeJSONOrKind The type to compare with.
941
+ * @returns `true` if the types are equal, `false` otherwise.
942
+ */
943
+ isTypeEqual(targetTypeJSONOrKind) {
944
+ const targetTypeJSON = parseTypeJsonOrKind(targetTypeJSONOrKind);
945
+ if (targetTypeJSON?.kind === "Union" /* Union */) {
946
+ return (targetTypeJSON?.types || [])?.some(
947
+ (_subType) => this.isTypeEqual(_subType)
948
+ );
949
+ }
950
+ return targetTypeJSON?.kind === this.kind && targetTypeJSON?.typeName === this.typeName;
951
+ }
952
+ toJSON() {
953
+ return {
954
+ typeName: this.typeName
955
+ };
956
+ }
957
+ };
958
+ CustomType.kind = "CustomType" /* CustomType */;
959
+
960
+ // src/ast/utils/variable-field.ts
961
+ function getParentFields(ast) {
962
+ let curr = ast.parent;
963
+ const res = [];
964
+ while (curr) {
965
+ if (curr.flags & 1 /* VariableField */) {
966
+ res.push(curr);
967
+ }
968
+ curr = curr.parent;
969
+ }
970
+ return res;
971
+ }
972
+
973
+ // src/ast/expression/base-expression.ts
974
+ var BaseExpression = class extends ASTNode {
975
+ constructor(params, opts) {
976
+ super(params, opts);
977
+ this.flags = 4 /* Expression */;
978
+ /**
979
+ * The variable fields referenced by the expression.
980
+ */
981
+ this._refs = [];
982
+ this.refreshRefs$ = new rxjs.Subject();
983
+ /**
984
+ * An observable that emits the referenced variable fields when they change.
985
+ */
986
+ this.refs$ = this.refreshRefs$.pipe(
987
+ rxjs.map(() => this.getRefFields()),
988
+ rxjs.distinctUntilChanged(fastEquals.shallowEqual),
989
+ rxjs.switchMap(
990
+ (refs) => !refs?.length ? rxjs.of([]) : rxjs.combineLatest(
991
+ refs.map(
992
+ (ref) => ref ? ref.value$ : rxjs.of(void 0)
993
+ )
994
+ )
995
+ ),
996
+ rxjs.share()
997
+ );
998
+ this.toDispose.push(
999
+ subsToDisposable(
1000
+ this.refs$.subscribe((_refs) => {
1001
+ this._refs = _refs;
1002
+ this.fireChange();
1003
+ })
1004
+ )
1005
+ );
1006
+ }
1007
+ /**
1008
+ * Get the global variable table, which is used to access referenced variables.
1009
+ */
1010
+ get globalVariableTable() {
1011
+ return this.scope.variableEngine.globalVariableTable;
1012
+ }
1013
+ /**
1014
+ * Parent variable fields, sorted from closest to farthest.
1015
+ */
1016
+ get parentFields() {
1017
+ return getParentFields(this);
1018
+ }
1019
+ /**
1020
+ * The variable fields referenced by the expression.
1021
+ */
1022
+ get refs() {
1023
+ return this._refs;
1024
+ }
1025
+ /**
1026
+ * Refresh the variable references.
1027
+ */
1028
+ refreshRefs() {
1029
+ this.refreshRefs$.next();
1030
+ }
1031
+ };
1032
+
1033
+ // src/ast/expression/enumerate-expression.ts
1034
+ var EnumerateExpression = class extends BaseExpression {
1035
+ /**
1036
+ * The expression to be enumerated.
1037
+ */
1038
+ get enumerateFor() {
1039
+ return this._enumerateFor;
1040
+ }
1041
+ /**
1042
+ * The return type of the expression.
1043
+ */
1044
+ get returnType() {
1045
+ const childReturnType = this.enumerateFor?.returnType;
1046
+ if (childReturnType?.kind === "Array" /* Array */) {
1047
+ return childReturnType.items;
1048
+ }
1049
+ return void 0;
1050
+ }
1051
+ /**
1052
+ * Get the variable fields referenced by the expression.
1053
+ * @returns An empty array, as this expression does not reference any variables.
1054
+ */
1055
+ getRefFields() {
1056
+ return [];
1057
+ }
1058
+ /**
1059
+ * Deserializes the `EnumerateExpressionJSON` to the `EnumerateExpression`.
1060
+ * @param json The `EnumerateExpressionJSON` to deserialize.
1061
+ */
1062
+ fromJSON({ enumerateFor: expression }) {
1063
+ this.updateChildNodeByKey("_enumerateFor", expression);
1064
+ }
1065
+ /**
1066
+ * Serialize the `EnumerateExpression` to `EnumerateExpressionJSON`.
1067
+ * @returns The JSON representation of `EnumerateExpression`.
1068
+ */
1069
+ toJSON() {
1070
+ return {
1071
+ kind: "EnumerateExpression" /* EnumerateExpression */,
1072
+ enumerateFor: this.enumerateFor?.toJSON()
1073
+ };
1074
+ }
1075
+ };
1076
+ EnumerateExpression.kind = "EnumerateExpression" /* EnumerateExpression */;
1077
+ function getAllRefs(ast) {
1078
+ return getAllChildren(ast).filter((_child) => _child.flags & 4 /* Expression */).map((_child) => _child.refs).flat().filter(Boolean);
1079
+ }
1080
+ function checkRefCycle(curr, refNodes) {
1081
+ if (lodashEs.intersection(curr.scope.coverScopes, refNodes.map((_ref) => _ref?.scope).filter(Boolean)).length === 0) {
1082
+ return false;
1083
+ }
1084
+ const visited = /* @__PURE__ */ new Set();
1085
+ const queue = [...refNodes];
1086
+ while (queue.length) {
1087
+ const currNode = queue.shift();
1088
+ visited.add(currNode);
1089
+ for (const ref of getAllRefs(currNode).filter((_ref) => !visited.has(_ref))) {
1090
+ queue.push(ref);
1091
+ }
1092
+ }
1093
+ return lodashEs.intersection(Array.from(visited), getParentFields(curr)).length > 0;
1094
+ }
1095
+
1096
+ // src/ast/expression/keypath-expression.ts
1097
+ var KeyPathExpression = class extends BaseExpression {
1098
+ constructor(params, opts) {
1099
+ super(params, opts);
1100
+ this._keyPath = [];
1101
+ this.toDispose.pushAll([
1102
+ // Can be used when the variable list changes (when there are additions or deletions).
1103
+ this.scope.available.onVariableListChange(() => {
1104
+ this.refreshRefs();
1105
+ }),
1106
+ // When the referable variable pointed to by this._keyPath changes, refresh the reference data.
1107
+ this.scope.available.onAnyVariableChange((_v) => {
1108
+ if (_v.key === this._keyPath[0]) {
1109
+ this.refreshRefs();
1110
+ }
1111
+ }),
1112
+ subsToDisposable(
1113
+ this.refs$.pipe(
1114
+ rxjs.distinctUntilChanged(
1115
+ (prev, next) => prev === next,
1116
+ (_refs) => _refs?.[0]?.type?.hash
1117
+ )
1118
+ ).subscribe((_type) => {
1119
+ const [ref] = this._refs;
1120
+ this.updateChildNodeByKey("_returnType", this.getReturnTypeJSONByRef(ref));
1121
+ })
1122
+ )
1123
+ ]);
1124
+ }
1125
+ /**
1126
+ * The key path of the variable.
1127
+ */
1128
+ get keyPath() {
1129
+ return this._keyPath;
1130
+ }
1131
+ /**
1132
+ * Get the variable fields referenced by the expression.
1133
+ * @returns An array of referenced variable fields.
1134
+ */
1135
+ getRefFields() {
1136
+ const ref = this.scope.available.getByKeyPath(this._keyPath);
1137
+ if (checkRefCycle(this, [ref])) {
1138
+ console.warn(
1139
+ "[CustomKeyPathExpression] checkRefCycle: Reference Cycle Existed",
1140
+ this.parentFields.map((_field) => _field.key).reverse()
1141
+ );
1142
+ return [];
1143
+ }
1144
+ return ref ? [ref] : [];
1145
+ }
1146
+ /**
1147
+ * The return type of the expression.
1148
+ */
1149
+ get returnType() {
1150
+ return this._returnType;
1151
+ }
1152
+ /**
1153
+ * Parse the business-defined path expression into a key path.
1154
+ *
1155
+ * Businesses can quickly customize their own path expressions by modifying this method.
1156
+ * @param json The path expression defined by the business.
1157
+ * @returns The key path.
1158
+ */
1159
+ parseToKeyPath(json) {
1160
+ return json.keyPath;
1161
+ }
1162
+ /**
1163
+ * Deserializes the `KeyPathExpressionJSON` to the `KeyPathExpression`.
1164
+ * @param json The `KeyPathExpressionJSON` to deserialize.
1165
+ */
1166
+ fromJSON(json) {
1167
+ const keyPath = this.parseToKeyPath(json);
1168
+ if (!fastEquals.shallowEqual(keyPath, this._keyPath)) {
1169
+ this._keyPath = keyPath;
1170
+ this._rawPathJson = json;
1171
+ this.refreshRefs();
1172
+ }
1173
+ }
1174
+ /**
1175
+ * Get the return type JSON by reference.
1176
+ * @param _ref The referenced variable field.
1177
+ * @returns The JSON representation of the return type.
1178
+ */
1179
+ getReturnTypeJSONByRef(_ref) {
1180
+ return _ref?.type?.toJSON();
1181
+ }
1182
+ /**
1183
+ * Serialize the `KeyPathExpression` to `KeyPathExpressionJSON`.
1184
+ * @returns The JSON representation of `KeyPathExpression`.
1185
+ */
1186
+ toJSON() {
1187
+ return this._rawPathJson;
1188
+ }
1189
+ };
1190
+ KeyPathExpression.kind = "KeyPathExpression" /* KeyPathExpression */;
1191
+ var LegacyKeyPathExpression = class extends BaseExpression {
1192
+ constructor(params, opts) {
1193
+ super(params, opts);
1194
+ this._keyPath = [];
1195
+ this.toDispose.pushAll([
1196
+ // Can be used when the variable list changes (when there are additions or deletions).
1197
+ this.scope.available.onVariableListChange(() => {
1198
+ this.refreshRefs();
1199
+ }),
1200
+ // When the referable variable pointed to by this._keyPath changes, refresh the reference data.
1201
+ this.scope.available.onAnyVariableChange((_v) => {
1202
+ if (_v.key === this._keyPath[0]) {
1203
+ this.refreshRefs();
1204
+ }
1205
+ })
1206
+ ]);
1207
+ }
1208
+ /**
1209
+ * The key path of the variable.
1210
+ */
1211
+ get keyPath() {
1212
+ return this._keyPath;
1213
+ }
1214
+ /**
1215
+ * Get the variable fields referenced by the expression.
1216
+ * @returns An array of referenced variable fields.
1217
+ */
1218
+ getRefFields() {
1219
+ const ref = this.scope.available.getByKeyPath(this._keyPath);
1220
+ return ref ? [ref] : [];
1221
+ }
1222
+ /**
1223
+ * The return type of the expression.
1224
+ */
1225
+ get returnType() {
1226
+ const [refNode] = this._refs || [];
1227
+ if (refNode && refNode.flags & 1 /* VariableField */) {
1228
+ return refNode.type;
1229
+ }
1230
+ return;
1231
+ }
1232
+ /**
1233
+ * Parse the business-defined path expression into a key path.
1234
+ *
1235
+ * Businesses can quickly customize their own path expressions by modifying this method.
1236
+ * @param json The path expression defined by the business.
1237
+ * @returns The key path.
1238
+ */
1239
+ parseToKeyPath(json) {
1240
+ return json.keyPath;
1241
+ }
1242
+ /**
1243
+ * Deserializes the `KeyPathExpressionJSON` to the `KeyPathExpression`.
1244
+ * @param json The `KeyPathExpressionJSON` to deserialize.
1245
+ */
1246
+ fromJSON(json) {
1247
+ const keyPath = this.parseToKeyPath(json);
1248
+ if (!fastEquals.shallowEqual(keyPath, this._keyPath)) {
1249
+ this._keyPath = keyPath;
1250
+ this._rawPathJson = json;
1251
+ this.refreshRefs();
1252
+ }
1253
+ }
1254
+ /**
1255
+ * Serialize the `KeyPathExpression` to `KeyPathExpressionJSON`.
1256
+ * @returns The JSON representation of `KeyPathExpression`.
1257
+ */
1258
+ toJSON() {
1259
+ return this._rawPathJson;
1260
+ }
1261
+ };
1262
+ LegacyKeyPathExpression.kind = "KeyPathExpression" /* KeyPathExpression */;
1263
+
1264
+ // src/ast/expression/wrap-array-expression.ts
1265
+ var WrapArrayExpression = class extends BaseExpression {
1266
+ /**
1267
+ * The expression to be wrapped.
1268
+ */
1269
+ get wrapFor() {
1270
+ return this._wrapFor;
1271
+ }
1272
+ /**
1273
+ * The return type of the expression.
1274
+ */
1275
+ get returnType() {
1276
+ return this._returnType;
1277
+ }
1278
+ /**
1279
+ * Refresh the return type of the expression.
1280
+ */
1281
+ refreshReturnType() {
1282
+ const childReturnTypeJSON = this.wrapFor?.returnType?.toJSON();
1283
+ this.updateChildNodeByKey("_returnType", {
1284
+ kind: "Array" /* Array */,
1285
+ items: childReturnTypeJSON
1286
+ });
1287
+ }
1288
+ /**
1289
+ * Get the variable fields referenced by the expression.
1290
+ * @returns An empty array, as this expression does not reference any variables.
1291
+ */
1292
+ getRefFields() {
1293
+ return [];
1294
+ }
1295
+ /**
1296
+ * Deserializes the `WrapArrayExpressionJSON` to the `WrapArrayExpression`.
1297
+ * @param json The `WrapArrayExpressionJSON` to deserialize.
1298
+ */
1299
+ fromJSON({ wrapFor: expression }) {
1300
+ this.updateChildNodeByKey("_wrapFor", expression);
1301
+ }
1302
+ /**
1303
+ * Serialize the `WrapArrayExpression` to `WrapArrayExpressionJSON`.
1304
+ * @returns The JSON representation of `WrapArrayExpression`.
1305
+ */
1306
+ toJSON() {
1307
+ return {
1308
+ kind: "WrapArrayExpression" /* WrapArrayExpression */,
1309
+ wrapFor: this.wrapFor?.toJSON()
1310
+ };
1311
+ }
1312
+ init() {
1313
+ this.refreshReturnType = this.refreshReturnType.bind(this);
1314
+ this.toDispose.push(
1315
+ this.subscribe(this.refreshReturnType, {
1316
+ selector: (curr) => curr.wrapFor?.returnType,
1317
+ triggerOnInit: true
1318
+ })
1319
+ );
1320
+ }
1321
+ };
1322
+ WrapArrayExpression.kind = "WrapArrayExpression" /* WrapArrayExpression */;
1323
+ __decorateClass([
1324
+ postConstructAST()
1325
+ ], WrapArrayExpression.prototype, "init", 1);
1326
+ var BaseVariableField = class extends ASTNode {
1327
+ constructor() {
1328
+ super(...arguments);
1329
+ this.flags = 1 /* VariableField */;
1330
+ this._meta = {};
1331
+ }
1332
+ /**
1333
+ * Parent variable fields, sorted from closest to farthest
1334
+ */
1335
+ get parentFields() {
1336
+ return getParentFields(this);
1337
+ }
1338
+ /**
1339
+ * KeyPath of the variable field, sorted from farthest to closest
1340
+ */
1341
+ get keyPath() {
1342
+ return [...this.parentFields.reverse().map((_field) => _field.key), this.key];
1343
+ }
1344
+ /**
1345
+ * Metadata of the variable field, you cans store information like `title`, `icon`, etc.
1346
+ */
1347
+ get meta() {
1348
+ return this._meta;
1349
+ }
1350
+ /**
1351
+ * Type of the variable field, similar to js code:
1352
+ * `const v: string`
1353
+ */
1354
+ get type() {
1355
+ return this._initializer?.returnType || this._type;
1356
+ }
1357
+ /**
1358
+ * Initializer of the variable field, similar to js code:
1359
+ * `const v = 'hello'`
1360
+ *
1361
+ * with initializer, the type of field will be inferred from the initializer.
1362
+ */
1363
+ get initializer() {
1364
+ return this._initializer;
1365
+ }
1366
+ /**
1367
+ * The global unique hash of the field, and will be changed when the field is updated.
1368
+ */
1369
+ get hash() {
1370
+ return `[${this._version}]${this.keyPath.join(".")}`;
1371
+ }
1372
+ /**
1373
+ * Deserialize the `BaseVariableFieldJSON` to the `BaseVariableField`.
1374
+ * @param json ASTJSON representation of `BaseVariableField`
1375
+ */
1376
+ fromJSON({ type, initializer, meta }) {
1377
+ this.updateType(type);
1378
+ this.updateInitializer(initializer);
1379
+ this.updateMeta(meta);
1380
+ }
1381
+ /**
1382
+ * Update the type of the variable field
1383
+ * @param type type ASTJSON representation of Type
1384
+ */
1385
+ updateType(type) {
1386
+ const nextTypeJson = typeof type === "string" ? { kind: type } : type;
1387
+ this.updateChildNodeByKey("_type", nextTypeJson);
1388
+ }
1389
+ /**
1390
+ * Update the initializer of the variable field
1391
+ * @param nextInitializer initializer ASTJSON representation of Expression
1392
+ */
1393
+ updateInitializer(nextInitializer) {
1394
+ this.updateChildNodeByKey("_initializer", nextInitializer);
1395
+ }
1396
+ /**
1397
+ * Update the meta data of the variable field
1398
+ * @param nextMeta meta data of the variable field
1399
+ */
1400
+ updateMeta(nextMeta) {
1401
+ if (!fastEquals.shallowEqual(nextMeta, this._meta)) {
1402
+ this._meta = nextMeta;
1403
+ this.fireChange();
1404
+ }
1405
+ }
1406
+ /**
1407
+ * Get the variable field by keyPath, similar to js code:
1408
+ * `v.a.b`
1409
+ * @param keyPath
1410
+ * @returns
1411
+ */
1412
+ getByKeyPath(keyPath) {
1413
+ if (this.type?.flags & 16 /* DrilldownType */) {
1414
+ return this.type.getByKeyPath(keyPath);
1415
+ }
1416
+ return void 0;
1417
+ }
1418
+ /**
1419
+ * Subscribe to type change of the variable field
1420
+ * @param observer
1421
+ * @returns
1422
+ */
1423
+ onTypeChange(observer) {
1424
+ return this.subscribe(observer, { selector: (curr) => curr.type });
1425
+ }
1426
+ /**
1427
+ * Serialize the variable field to JSON
1428
+ * @returns ASTNodeJSON representation of `BaseVariableField`
1429
+ */
1430
+ toJSON() {
1431
+ return {
1432
+ key: this.key,
1433
+ type: this.type?.toJSON(),
1434
+ initializer: this.initializer?.toJSON(),
1435
+ meta: this._meta
1436
+ };
1437
+ }
1438
+ };
1439
+
1440
+ // src/ast/declaration/variable-declaration.ts
1441
+ var VariableDeclaration = class extends BaseVariableField {
1442
+ constructor(params) {
1443
+ super(params);
1444
+ this._order = 0;
1445
+ }
1446
+ /**
1447
+ * Variable sorting order, which is used to sort variables in `scope.outputs.variables`
1448
+ */
1449
+ get order() {
1450
+ return this._order;
1451
+ }
1452
+ /**
1453
+ * Deserialize the `VariableDeclarationJSON` to the `VariableDeclaration`.
1454
+ */
1455
+ fromJSON({ order, ...rest }) {
1456
+ this.updateOrder(order);
1457
+ super.fromJSON(rest);
1458
+ }
1459
+ /**
1460
+ * Update the sorting order of the variable declaration.
1461
+ * @param order Variable sorting order. Default is 0.
1462
+ */
1463
+ updateOrder(order = 0) {
1464
+ if (order !== this._order) {
1465
+ this._order = order;
1466
+ this.dispatchGlobalEvent({
1467
+ type: "ReSortVariableDeclarations"
1468
+ });
1469
+ this.fireChange();
1470
+ }
1471
+ }
1472
+ /**
1473
+ * Serialize the `VariableDeclaration` to `VariableDeclarationJSON`.
1474
+ * @returns The JSON representation of `VariableDeclaration`.
1475
+ */
1476
+ toJSON() {
1477
+ return {
1478
+ ...super.toJSON(),
1479
+ order: this.order
1480
+ };
1481
+ }
1482
+ };
1483
+ VariableDeclaration.kind = "VariableDeclaration" /* VariableDeclaration */;
1484
+
1485
+ // src/ast/declaration/variable-declaration-list.ts
1486
+ var VariableDeclarationList = class extends ASTNode {
1487
+ constructor() {
1488
+ super(...arguments);
1489
+ /**
1490
+ * Map of variable declarations, keyed by variable name.
1491
+ */
1492
+ this.declarationTable = /* @__PURE__ */ new Map();
1493
+ }
1494
+ /**
1495
+ * Deserialize the `VariableDeclarationListJSON` to the `VariableDeclarationList`.
1496
+ * - VariableDeclarationListChangeAction will be dispatched after deserialization.
1497
+ *
1498
+ * @param declarations Variable declarations.
1499
+ * @param startOrder The starting order number for variables. Default is 0.
1500
+ */
1501
+ fromJSON({ declarations, startOrder }) {
1502
+ const removedKeys = new Set(this.declarationTable.keys());
1503
+ const prev = [...this.declarations || []];
1504
+ this.declarations = (declarations || []).map(
1505
+ (declaration, idx) => {
1506
+ const order = (startOrder || 0) + idx;
1507
+ const declarationKey = declaration.key || this.declarations?.[idx]?.key;
1508
+ const existDeclaration = this.declarationTable.get(declarationKey);
1509
+ if (declarationKey) {
1510
+ removedKeys.delete(declarationKey);
1511
+ }
1512
+ if (existDeclaration) {
1513
+ existDeclaration.fromJSON({ order, ...declaration });
1514
+ return existDeclaration;
1515
+ } else {
1516
+ const newDeclaration = this.createChildNode({
1517
+ order,
1518
+ ...declaration,
1519
+ kind: "VariableDeclaration" /* VariableDeclaration */
1520
+ });
1521
+ this.fireChange();
1522
+ this.declarationTable.set(newDeclaration.key, newDeclaration);
1523
+ return newDeclaration;
1524
+ }
1525
+ }
1526
+ );
1527
+ removedKeys.forEach((key) => {
1528
+ const declaration = this.declarationTable.get(key);
1529
+ declaration?.dispose();
1530
+ this.declarationTable.delete(key);
1531
+ });
1532
+ this.dispatchGlobalEvent({
1533
+ type: "VariableListChange",
1534
+ payload: {
1535
+ prev,
1536
+ next: [...this.declarations]
1537
+ }
1538
+ });
1539
+ }
1540
+ /**
1541
+ * Serialize the `VariableDeclarationList` to the `VariableDeclarationListJSON`.
1542
+ * @returns ASTJSON representation of `VariableDeclarationList`
1543
+ */
1544
+ toJSON() {
1545
+ return {
1546
+ kind: "VariableDeclarationList" /* VariableDeclarationList */,
1547
+ declarations: this.declarations.map((_declaration) => _declaration.toJSON())
1548
+ };
1549
+ }
1550
+ };
1551
+ VariableDeclarationList.kind = "VariableDeclarationList" /* VariableDeclarationList */;
1552
+
1553
+ // src/ast/declaration/property.ts
1554
+ var Property = class extends BaseVariableField {
1555
+ };
1556
+ Property.kind = "Property" /* Property */;
1557
+ var DataNode = class extends ASTNode {
1558
+ /**
1559
+ * The data of the node.
1560
+ */
1561
+ get data() {
1562
+ return this._data;
1563
+ }
1564
+ /**
1565
+ * Deserializes the `DataNodeJSON` to the `DataNode`.
1566
+ * @param json The `DataNodeJSON` to deserialize.
1567
+ */
1568
+ fromJSON(json) {
1569
+ const { kind, ...restData } = json;
1570
+ if (!fastEquals.shallowEqual(restData, this._data)) {
1571
+ this._data = restData;
1572
+ this.fireChange();
1573
+ }
1574
+ }
1575
+ /**
1576
+ * Serialize the `DataNode` to `DataNodeJSON`.
1577
+ * @returns The JSON representation of `DataNode`.
1578
+ */
1579
+ toJSON() {
1580
+ return {
1581
+ kind: "DataNode" /* DataNode */,
1582
+ ...this._data
1583
+ };
1584
+ }
1585
+ /**
1586
+ * Partially update the data of the node.
1587
+ * @param nextData The data to be updated.
1588
+ */
1589
+ partialUpdate(nextData) {
1590
+ if (!fastEquals.shallowEqual(nextData, this._data)) {
1591
+ this._data = {
1592
+ ...this._data,
1593
+ ...nextData
1594
+ };
1595
+ this.fireChange();
1596
+ }
1597
+ }
1598
+ };
1599
+ DataNode.kind = "DataNode" /* DataNode */;
1600
+
1601
+ // src/ast/common/list-node.ts
1602
+ var ListNode = class extends ASTNode {
1603
+ /**
1604
+ * The list of nodes.
1605
+ */
1606
+ get list() {
1607
+ return this._list;
1608
+ }
1609
+ /**
1610
+ * Deserializes the `ListNodeJSON` to the `ListNode`.
1611
+ * @param json The `ListNodeJSON` to deserialize.
1612
+ */
1613
+ fromJSON({ list }) {
1614
+ this._list.slice(list.length).forEach((_item) => {
1615
+ _item.dispose();
1616
+ this.fireChange();
1617
+ });
1618
+ this._list = list.map((_item, idx) => {
1619
+ const prevItem = this._list[idx];
1620
+ if (prevItem.kind !== _item.kind) {
1621
+ prevItem.dispose();
1622
+ this.fireChange();
1623
+ return this.createChildNode(_item);
1624
+ }
1625
+ prevItem.fromJSON(_item);
1626
+ return prevItem;
1627
+ });
1628
+ }
1629
+ /**
1630
+ * Serialize the `ListNode` to `ListNodeJSON`.
1631
+ * @returns The JSON representation of `ListNode`.
1632
+ */
1633
+ toJSON() {
1634
+ return {
1635
+ kind: "ListNode" /* ListNode */,
1636
+ list: this._list.map((item) => item.toJSON())
1637
+ };
1638
+ }
1639
+ };
1640
+ ListNode.kind = "ListNode" /* ListNode */;
1641
+
1642
+ // src/ast/common/map-node.ts
1643
+ var MapNode = class extends ASTNode {
1644
+ constructor() {
1645
+ super(...arguments);
1646
+ this.map = /* @__PURE__ */ new Map();
1647
+ }
1648
+ /**
1649
+ * Deserializes the `MapNodeJSON` to the `MapNode`.
1650
+ * @param json The `MapNodeJSON` to deserialize.
1651
+ */
1652
+ fromJSON({ map: map4 }) {
1653
+ const removedKeys = new Set(this.map.keys());
1654
+ for (const [key, item] of map4 || []) {
1655
+ removedKeys.delete(key);
1656
+ this.set(key, item);
1657
+ }
1658
+ for (const removeKey of Array.from(removedKeys)) {
1659
+ this.remove(removeKey);
1660
+ }
1661
+ }
1662
+ /**
1663
+ * Serialize the `MapNode` to `MapNodeJSON`.
1664
+ * @returns The JSON representation of `MapNode`.
1665
+ */
1666
+ toJSON() {
1667
+ return {
1668
+ kind: "MapNode" /* MapNode */,
1669
+ map: Array.from(this.map.entries())
1670
+ };
1671
+ }
1672
+ /**
1673
+ * Set a node in the map.
1674
+ * @param key The key of the node.
1675
+ * @param nextJSON The JSON representation of the node.
1676
+ * @returns The node instance.
1677
+ */
1678
+ set(key, nextJSON) {
1679
+ return this.withBatchUpdate(updateChildNodeHelper).call(this, {
1680
+ getChildNode: () => this.get(key),
1681
+ removeChildNode: () => this.map.delete(key),
1682
+ updateChildNode: (nextNode) => this.map.set(key, nextNode),
1683
+ nextJSON
1684
+ });
1685
+ }
1686
+ /**
1687
+ * Remove a node from the map.
1688
+ * @param key The key of the node.
1689
+ */
1690
+ remove(key) {
1691
+ this.get(key)?.dispose();
1692
+ this.map.delete(key);
1693
+ this.fireChange();
1694
+ }
1695
+ /**
1696
+ * Get a node from the map.
1697
+ * @param key The key of the node.
1698
+ * @returns The node instance if found, otherwise `undefined`.
1699
+ */
1700
+ get(key) {
1701
+ return this.map.get(key);
1702
+ }
1703
+ };
1704
+ MapNode.kind = "MapNode" /* MapNode */;
1705
+
1706
+ // src/ast/ast-registers.ts
1707
+ exports.ASTRegisters = class ASTRegisters {
1708
+ /**
1709
+ * Core AST node registration.
1710
+ */
1711
+ constructor() {
1712
+ /**
1713
+ * @deprecated Please use `@injectToAst(XXXService) declare xxxService: XXXService` to achieve external dependency injection.
1714
+ */
1715
+ this.injectors = /* @__PURE__ */ new Map();
1716
+ this.astMap = /* @__PURE__ */ new Map();
1717
+ this.registerAST(StringType);
1718
+ this.registerAST(NumberType);
1719
+ this.registerAST(BooleanType);
1720
+ this.registerAST(IntegerType);
1721
+ this.registerAST(ObjectType);
1722
+ this.registerAST(ArrayType);
1723
+ this.registerAST(MapType);
1724
+ this.registerAST(CustomType);
1725
+ this.registerAST(Property);
1726
+ this.registerAST(VariableDeclaration);
1727
+ this.registerAST(VariableDeclarationList);
1728
+ this.registerAST(KeyPathExpression);
1729
+ this.registerAST(EnumerateExpression);
1730
+ this.registerAST(WrapArrayExpression);
1731
+ this.registerAST(MapNode);
1732
+ this.registerAST(DataNode);
1733
+ }
1734
+ /**
1735
+ * Creates an AST node.
1736
+ * @param param Creation parameters.
1737
+ * @returns
1738
+ */
1739
+ createAST(json, { parent, scope }) {
1740
+ const Registry = this.astMap.get(json.kind);
1741
+ if (!Registry) {
1742
+ throw Error(`ASTKind: ${String(json.kind)} can not find its ASTNode Registry`);
1743
+ }
1744
+ const injector = this.injectors.get(json.kind);
1745
+ const node = new Registry(
1746
+ {
1747
+ key: json.key,
1748
+ scope,
1749
+ parent
1750
+ },
1751
+ injector?.() || {}
1752
+ );
1753
+ node.changeLocked = true;
1754
+ node.fromJSON(lodashEs.omit(json, ["key", "kind"]));
1755
+ node.changeLocked = false;
1756
+ node.dispatchGlobalEvent({ type: "NewAST" });
1757
+ if (Reflect.hasMetadata(POST_CONSTRUCT_AST_SYMBOL, node)) {
1758
+ const postConstructKey = Reflect.getMetadata(POST_CONSTRUCT_AST_SYMBOL, node);
1759
+ node[postConstructKey]?.();
1760
+ }
1761
+ return node;
1762
+ }
1763
+ /**
1764
+ * Gets the node Registry by AST node type.
1765
+ * @param kind
1766
+ * @returns
1767
+ */
1768
+ getASTRegistryByKind(kind) {
1769
+ return this.astMap.get(kind);
1770
+ }
1771
+ /**
1772
+ * Registers an AST node.
1773
+ * @param ASTNode
1774
+ */
1775
+ registerAST(ASTNode2, injector) {
1776
+ this.astMap.set(ASTNode2.kind, ASTNode2);
1777
+ if (injector) {
1778
+ this.injectors.set(ASTNode2.kind, injector);
1779
+ }
1780
+ }
1781
+ };
1782
+ exports.ASTRegisters = __decorateClass([
1783
+ inversify.injectable()
1784
+ ], exports.ASTRegisters);
1785
+
1786
+ // src/ast/factory.ts
1787
+ exports.ASTFactory = void 0;
1788
+ ((ASTFactory2) => {
1789
+ ASTFactory2.createString = (json) => ({
1790
+ kind: "String" /* String */,
1791
+ ...json || {}
1792
+ });
1793
+ ASTFactory2.createNumber = () => ({ kind: "Number" /* Number */ });
1794
+ ASTFactory2.createBoolean = () => ({ kind: "Boolean" /* Boolean */ });
1795
+ ASTFactory2.createInteger = () => ({ kind: "Integer" /* Integer */ });
1796
+ ASTFactory2.createObject = (json) => ({
1797
+ kind: "Object" /* Object */,
1798
+ ...json
1799
+ });
1800
+ ASTFactory2.createArray = (json) => ({
1801
+ kind: "Array" /* Array */,
1802
+ ...json
1803
+ });
1804
+ ASTFactory2.createMap = (json) => ({
1805
+ kind: "Map" /* Map */,
1806
+ ...json
1807
+ });
1808
+ ASTFactory2.createUnion = (json) => ({
1809
+ kind: "Union" /* Union */,
1810
+ ...json
1811
+ });
1812
+ ASTFactory2.createCustomType = (json) => ({
1813
+ kind: "CustomType" /* CustomType */,
1814
+ ...json
1815
+ });
1816
+ ASTFactory2.createVariableDeclaration = (json) => ({
1817
+ kind: "VariableDeclaration" /* VariableDeclaration */,
1818
+ ...json
1819
+ });
1820
+ ASTFactory2.createProperty = (json) => ({
1821
+ kind: "Property" /* Property */,
1822
+ ...json
1823
+ });
1824
+ ASTFactory2.createVariableDeclarationList = (json) => ({
1825
+ kind: "VariableDeclarationList" /* VariableDeclarationList */,
1826
+ ...json
1827
+ });
1828
+ ASTFactory2.createEnumerateExpression = (json) => ({
1829
+ kind: "EnumerateExpression" /* EnumerateExpression */,
1830
+ ...json
1831
+ });
1832
+ ASTFactory2.createKeyPathExpression = (json) => ({
1833
+ kind: "KeyPathExpression" /* KeyPathExpression */,
1834
+ ...json
1835
+ });
1836
+ ASTFactory2.createWrapArrayExpression = (json) => ({
1837
+ kind: "WrapArrayExpression" /* WrapArrayExpression */,
1838
+ ...json
1839
+ });
1840
+ ASTFactory2.create = (targetType, json) => ({ kind: targetType.kind, ...json });
1841
+ })(exports.ASTFactory || (exports.ASTFactory = {}));
1842
+
1843
+ // src/scope/datas/scope-output-data.ts
1844
+ var ScopeOutputData = class {
1845
+ constructor(scope) {
1846
+ this.scope = scope;
1847
+ this.memo = createMemo();
1848
+ this._hasChanges = false;
1849
+ this.variableTable = new VariableTable(scope.variableEngine.globalVariableTable);
1850
+ this.scope.toDispose.pushAll([
1851
+ // When the root AST node is updated, check if there are any changes.
1852
+ this.scope.ast.subscribe(() => {
1853
+ if (this._hasChanges) {
1854
+ this.memo.clear();
1855
+ this.notifyCoversChange();
1856
+ this.variableTable.fireChange();
1857
+ this._hasChanges = false;
1858
+ }
1859
+ }),
1860
+ this.scope.event.on("DisposeAST", (_action) => {
1861
+ if (_action.ast?.kind === "VariableDeclaration" /* VariableDeclaration */) {
1862
+ this.removeVariableFromTable(_action.ast.key);
1863
+ }
1864
+ }),
1865
+ this.scope.event.on("NewAST", (_action) => {
1866
+ if (_action.ast?.kind === "VariableDeclaration" /* VariableDeclaration */) {
1867
+ this.addVariableToTable(_action.ast);
1868
+ }
1869
+ }),
1870
+ this.scope.event.on("ReSortVariableDeclarations", () => {
1871
+ this._hasChanges = true;
1872
+ }),
1873
+ this.variableTable
1874
+ ]);
1875
+ }
1876
+ /**
1877
+ * The variable engine instance.
1878
+ */
1879
+ get variableEngine() {
1880
+ return this.scope.variableEngine;
1881
+ }
1882
+ /**
1883
+ * The global variable table from the variable engine.
1884
+ */
1885
+ get globalVariableTable() {
1886
+ return this.scope.variableEngine.globalVariableTable;
1887
+ }
1888
+ /**
1889
+ * The current version of the output data, which increments on each change.
1890
+ */
1891
+ get version() {
1892
+ return this.variableTable.version;
1893
+ }
1894
+ /**
1895
+ * @deprecated use onListOrAnyVarChange instead
1896
+ */
1897
+ get onDataChange() {
1898
+ return this.variableTable.onDataChange.bind(this.variableTable);
1899
+ }
1900
+ /**
1901
+ * An event that fires when the list of output variables changes.
1902
+ */
1903
+ get onVariableListChange() {
1904
+ return this.variableTable.onVariableListChange.bind(this.variableTable);
1905
+ }
1906
+ /**
1907
+ * An event that fires when any output variable's value changes.
1908
+ */
1909
+ get onAnyVariableChange() {
1910
+ return this.variableTable.onAnyVariableChange.bind(this.variableTable);
1911
+ }
1912
+ /**
1913
+ * An event that fires when the output variable list changes or any variable's value is updated.
1914
+ */
1915
+ get onListOrAnyVarChange() {
1916
+ return this.variableTable.onListOrAnyVarChange.bind(this.variableTable);
1917
+ }
1918
+ /**
1919
+ * The output variable declarations of the scope, sorted by order.
1920
+ */
1921
+ get variables() {
1922
+ return this.memo(
1923
+ "variables",
1924
+ () => this.variableTable.variables.sort((a, b) => a.order - b.order)
1925
+ );
1926
+ }
1927
+ /**
1928
+ * The keys of the output variables.
1929
+ */
1930
+ get variableKeys() {
1931
+ return this.memo("variableKeys", () => this.variableTable.variableKeys);
1932
+ }
1933
+ addVariableToTable(variable) {
1934
+ if (variable.scope !== this.scope) {
1935
+ throw Error("VariableDeclaration must be a ast node in scope");
1936
+ }
1937
+ this.variableTable.addVariableToTable(variable);
1938
+ this._hasChanges = true;
1939
+ }
1940
+ removeVariableFromTable(key) {
1941
+ this.variableTable.removeVariableFromTable(key);
1942
+ this._hasChanges = true;
1943
+ }
1944
+ /**
1945
+ * Retrieves a variable declaration by its key.
1946
+ * @param key The key of the variable.
1947
+ * @returns The `VariableDeclaration` or `undefined` if not found.
1948
+ */
1949
+ getVariableByKey(key) {
1950
+ return this.variableTable.getVariableByKey(key);
1951
+ }
1952
+ /**
1953
+ * Notifies the covering scopes that the available variables have changed.
1954
+ */
1955
+ notifyCoversChange() {
1956
+ this.scope.coverScopes.forEach((scope) => scope.available.refresh());
1957
+ }
1958
+ };
1959
+ var ScopeAvailableData = class {
1960
+ constructor(scope) {
1961
+ this.scope = scope;
1962
+ this.memo = createMemo();
1963
+ this._version = 0;
1964
+ this.refresh$ = new rxjs.Subject();
1965
+ this._variables = [];
1966
+ /**
1967
+ * An observable that emits when the list of available variables changes.
1968
+ */
1969
+ this.variables$ = this.refresh$.pipe(
1970
+ // Map to the flattened list of variables from all dependency scopes.
1971
+ rxjs.map(() => lodashEs.flatten(this.depScopes.map((scope) => scope.output.variables || []))),
1972
+ // Use shallow equality to check if the variable list has changed.
1973
+ rxjs.distinctUntilChanged(fastEquals.shallowEqual),
1974
+ rxjs.share()
1975
+ );
1976
+ /**
1977
+ * An observable that emits when any variable in the available list changes its value.
1978
+ */
1979
+ this.anyVariableChange$ = this.variables$.pipe(
1980
+ rxjs.switchMap(
1981
+ (_variables) => rxjs.merge(
1982
+ ..._variables.map(
1983
+ (_v) => _v.value$.pipe(
1984
+ // Skip the initial value of the BehaviorSubject.
1985
+ rxjs.skip(1)
1986
+ )
1987
+ )
1988
+ )
1989
+ ),
1990
+ rxjs.share()
1991
+ );
1992
+ /**
1993
+ * @deprecated
1994
+ */
1995
+ this.onDataChangeEmitter = new utils.Emitter();
1996
+ this.onListOrAnyVarChangeEmitter = new utils.Emitter();
1997
+ /**
1998
+ * @deprecated use available.onListOrAnyVarChange instead
1999
+ */
2000
+ this.onDataChange = this.onDataChangeEmitter.event;
2001
+ /**
2002
+ * An event that fires when the variable list changes or any variable's value is updated.
2003
+ */
2004
+ this.onListOrAnyVarChange = this.onListOrAnyVarChangeEmitter.event;
2005
+ this.scope.toDispose.pushAll([
2006
+ this.onVariableListChange((_variables) => {
2007
+ this._variables = _variables;
2008
+ this.memo.clear();
2009
+ this.onDataChangeEmitter.fire(this._variables);
2010
+ this.bumpVersion();
2011
+ this.onListOrAnyVarChangeEmitter.fire(this._variables);
2012
+ }),
2013
+ this.onAnyVariableChange(() => {
2014
+ this.onDataChangeEmitter.fire(this._variables);
2015
+ this.bumpVersion();
2016
+ this.onListOrAnyVarChangeEmitter.fire(this._variables);
2017
+ }),
2018
+ utils.Disposable.create(() => {
2019
+ this.refresh$.complete();
2020
+ this.refresh$.unsubscribe();
2021
+ })
2022
+ ]);
2023
+ }
2024
+ /**
2025
+ * The global variable table from the variable engine.
2026
+ */
2027
+ get globalVariableTable() {
2028
+ return this.scope.variableEngine.globalVariableTable;
2029
+ }
2030
+ /**
2031
+ * The current version of the available data, which increments on each change.
2032
+ */
2033
+ get version() {
2034
+ return this._version;
2035
+ }
2036
+ bumpVersion() {
2037
+ this._version = this._version + 1;
2038
+ if (this._version === Number.MAX_SAFE_INTEGER) {
2039
+ this._version = 0;
2040
+ }
2041
+ }
2042
+ /**
2043
+ * Refreshes the list of available variables.
2044
+ * This should be called when the dependencies of the scope change.
2045
+ */
2046
+ refresh() {
2047
+ if (this.scope.disposed) {
2048
+ return;
2049
+ }
2050
+ this.refresh$.next();
2051
+ }
2052
+ /**
2053
+ * Subscribes to changes in any variable's value in the available list.
2054
+ * @param observer A function to be called with the changed variable.
2055
+ * @returns A disposable to unsubscribe from the changes.
2056
+ */
2057
+ onAnyVariableChange(observer) {
2058
+ return subsToDisposable(this.anyVariableChange$.subscribe(observer));
2059
+ }
2060
+ /**
2061
+ * Subscribes to changes in the list of available variables.
2062
+ * @param observer A function to be called with the new list of variables.
2063
+ * @returns A disposable to unsubscribe from the changes.
2064
+ */
2065
+ onVariableListChange(observer) {
2066
+ return subsToDisposable(this.variables$.subscribe(observer));
2067
+ }
2068
+ /**
2069
+ * Gets the list of available variables.
2070
+ */
2071
+ get variables() {
2072
+ return this._variables;
2073
+ }
2074
+ /**
2075
+ * Gets the keys of the available variables.
2076
+ */
2077
+ get variableKeys() {
2078
+ return this.memo("availableKeys", () => this._variables.map((_v) => _v.key));
2079
+ }
2080
+ /**
2081
+ * Gets the dependency scopes.
2082
+ */
2083
+ get depScopes() {
2084
+ return this.scope.depScopes;
2085
+ }
2086
+ /**
2087
+ * Retrieves a variable field by its key path from the available variables.
2088
+ * @param keyPath The key path to the variable field.
2089
+ * @returns The found `BaseVariableField` or `undefined`.
2090
+ */
2091
+ getByKeyPath(keyPath = []) {
2092
+ if (!this.variableKeys.includes(keyPath[0])) {
2093
+ return;
2094
+ }
2095
+ return this.globalVariableTable.getByKeyPath(keyPath);
2096
+ }
2097
+ /**
2098
+ * Tracks changes to a variable field by its key path.
2099
+ * This includes changes to its type, value, or any nested properties.
2100
+ * @param keyPath The key path to the variable field to track.
2101
+ * @param cb The callback to execute when the variable changes.
2102
+ * @param opts Configuration options for the subscription.
2103
+ * @returns A disposable to unsubscribe from the tracking.
2104
+ */
2105
+ trackByKeyPath(keyPath = [], cb, opts) {
2106
+ const { triggerOnInit = true, debounceAnimation, selector } = opts || {};
2107
+ return subsToDisposable(
2108
+ rxjs.merge(this.anyVariableChange$, this.variables$).pipe(
2109
+ triggerOnInit ? rxjs.startWith() : rxjs.tap(() => null),
2110
+ rxjs.map(() => {
2111
+ const v = this.getByKeyPath(keyPath);
2112
+ return selector ? selector(v) : v;
2113
+ }),
2114
+ rxjs.distinctUntilChanged(
2115
+ (a, b) => fastEquals.shallowEqual(a, b),
2116
+ (value) => {
2117
+ if (value instanceof ASTNode) {
2118
+ return value.hash;
2119
+ }
2120
+ return value;
2121
+ }
2122
+ ),
2123
+ // Debounce updates to a single emission per animation frame.
2124
+ debounceAnimation ? rxjs.debounceTime(0, rxjs.animationFrameScheduler) : rxjs.tap(() => null)
2125
+ ).subscribe(cb)
2126
+ );
2127
+ }
2128
+ };
2129
+ var ScopeEventData = class {
2130
+ constructor(scope) {
2131
+ this.scope = scope;
2132
+ this.event$ = new rxjs.Subject();
2133
+ scope.toDispose.pushAll([
2134
+ this.subscribe((_action) => {
2135
+ scope.variableEngine.fireGlobalEvent(_action);
2136
+ })
2137
+ ]);
2138
+ }
2139
+ /**
2140
+ * Dispatches a global event.
2141
+ * @param action The event action to dispatch.
2142
+ */
2143
+ dispatch(action) {
2144
+ if (this.scope.disposed) {
2145
+ return;
2146
+ }
2147
+ this.event$.next(action);
2148
+ }
2149
+ /**
2150
+ * Subscribes to all global events.
2151
+ * @param observer The observer function to call with the event action.
2152
+ * @returns A disposable to unsubscribe from the events.
2153
+ */
2154
+ subscribe(observer) {
2155
+ return subsToDisposable(this.event$.subscribe(observer));
2156
+ }
2157
+ /**
2158
+ * Subscribes to a specific type of global event.
2159
+ * @param type The type of the event to subscribe to.
2160
+ * @param observer The observer function to call with the event action.
2161
+ * @returns A disposable to unsubscribe from the event.
2162
+ */
2163
+ on(type, observer) {
2164
+ return subsToDisposable(
2165
+ this.event$.pipe(rxjs.filter((_action) => _action.type === type)).subscribe(observer)
2166
+ );
2167
+ }
2168
+ };
2169
+
2170
+ // src/scope/scope.ts
2171
+ var Scope = class {
2172
+ constructor(options) {
2173
+ /**
2174
+ * A memoization utility for caching computed values.
2175
+ */
2176
+ this.memo = createMemo();
2177
+ this.toDispose = new utils.DisposableCollection();
2178
+ this.onDispose = this.toDispose.onDispose;
2179
+ this.id = options.id;
2180
+ this.meta = options.meta || {};
2181
+ this.variableEngine = options.variableEngine;
2182
+ this.event = new ScopeEventData(this);
2183
+ this.ast = this.variableEngine.astRegisters.createAST(
2184
+ {
2185
+ kind: "MapNode" /* MapNode */,
2186
+ key: String(this.id)
2187
+ },
2188
+ {
2189
+ scope: this
2190
+ }
2191
+ );
2192
+ this.output = new ScopeOutputData(this);
2193
+ this.available = new ScopeAvailableData(this);
2194
+ }
2195
+ /**
2196
+ * Refreshes the covering scopes.
2197
+ */
2198
+ refreshCovers() {
2199
+ this.memo.clear("covers");
2200
+ }
2201
+ /**
2202
+ * Refreshes the dependency scopes and the available variables.
2203
+ */
2204
+ refreshDeps() {
2205
+ this.memo.clear("deps");
2206
+ this.available.refresh();
2207
+ }
2208
+ /**
2209
+ * Gets the scopes that this scope depends on.
2210
+ */
2211
+ get depScopes() {
2212
+ return this.memo(
2213
+ "deps",
2214
+ () => this.variableEngine.chain.getDeps(this).filter((_scope) => Boolean(_scope) && !_scope?.disposed)
2215
+ );
2216
+ }
2217
+ /**
2218
+ * Gets the scopes that are covered by this scope.
2219
+ */
2220
+ get coverScopes() {
2221
+ return this.memo(
2222
+ "covers",
2223
+ () => this.variableEngine.chain.getCovers(this).filter((_scope) => Boolean(_scope) && !_scope?.disposed)
2224
+ );
2225
+ }
2226
+ /**
2227
+ * Disposes of the scope and its resources.
2228
+ * This will also trigger updates in dependent and covering scopes.
2229
+ */
2230
+ dispose() {
2231
+ this.ast.dispose();
2232
+ this.toDispose.dispose();
2233
+ this.coverScopes.forEach((_scope) => _scope.refreshDeps());
2234
+ this.depScopes.forEach((_scope) => _scope.refreshCovers());
2235
+ }
2236
+ get disposed() {
2237
+ return this.toDispose.disposed;
2238
+ }
2239
+ setVar(arg1, arg2) {
2240
+ if (typeof arg1 === "string" && arg2 !== void 0) {
2241
+ return this.ast.set(arg1, arg2);
2242
+ }
2243
+ if (typeof arg1 === "object" && arg2 === void 0) {
2244
+ return this.ast.set("outputs", arg1);
2245
+ }
2246
+ throw new Error("Invalid arguments");
2247
+ }
2248
+ /**
2249
+ * Retrieves a variable from the scope by its key.
2250
+ *
2251
+ * @param key The key of the variable to retrieve. Defaults to 'outputs'.
2252
+ * @returns The AST node for the variable, or `undefined` if not found.
2253
+ */
2254
+ getVar(key = "outputs") {
2255
+ return this.ast.get(key);
2256
+ }
2257
+ /**
2258
+ * Clears a variable from the scope by its key.
2259
+ *
2260
+ * @param key The key of the variable to clear. Defaults to 'outputs'.
2261
+ */
2262
+ clearVar(key = "outputs") {
2263
+ return this.ast.remove(key);
2264
+ }
2265
+ };
2266
+
2267
+ // src/variable-engine.ts
2268
+ exports.VariableEngine = class VariableEngine {
2269
+ constructor(chain, astRegisters) {
2270
+ this.chain = chain;
2271
+ this.astRegisters = astRegisters;
2272
+ this.toDispose = new utils.DisposableCollection();
2273
+ this.memo = createMemo();
2274
+ this.scopeMap = /* @__PURE__ */ new Map();
2275
+ /**
2276
+ * A rxjs subject that emits global events occurring within the variable engine.
2277
+ */
2278
+ this.globalEvent$ = new rxjs.Subject();
2279
+ this.onScopeChangeEmitter = new utils.Emitter();
2280
+ /**
2281
+ * A table containing all global variables.
2282
+ */
2283
+ this.globalVariableTable = new VariableTable();
2284
+ /**
2285
+ * An event that fires whenever a scope is added, updated, or deleted.
2286
+ */
2287
+ this.onScopeChange = this.onScopeChangeEmitter.event;
2288
+ this.toDispose.pushAll([
2289
+ chain,
2290
+ utils.Disposable.create(() => {
2291
+ this.getAllScopes().forEach((scope) => scope.dispose());
2292
+ this.globalVariableTable.dispose();
2293
+ })
2294
+ ]);
2295
+ }
2296
+ /**
2297
+ * The Inversify container instance.
2298
+ */
2299
+ get container() {
2300
+ return this.containerProvider();
2301
+ }
2302
+ dispose() {
2303
+ this.toDispose.dispose();
2304
+ }
2305
+ /**
2306
+ * Retrieves a scope by its unique identifier.
2307
+ * @param scopeId The ID of the scope to retrieve.
2308
+ * @returns The scope if found, otherwise undefined.
2309
+ */
2310
+ getScopeById(scopeId) {
2311
+ return this.scopeMap.get(scopeId);
2312
+ }
2313
+ /**
2314
+ * Removes a scope by its unique identifier and disposes of it.
2315
+ * @param scopeId The ID of the scope to remove.
2316
+ */
2317
+ removeScopeById(scopeId) {
2318
+ this.getScopeById(scopeId)?.dispose();
2319
+ }
2320
+ /**
2321
+ * Creates a new scope or retrieves an existing one if the ID and type match.
2322
+ * @param id The unique identifier for the scope.
2323
+ * @param meta Optional metadata for the scope, defined by the user.
2324
+ * @param options Options for creating the scope.
2325
+ * @param options.ScopeConstructor The constructor to use for creating the scope. Defaults to `Scope`.
2326
+ * @returns The created or existing scope.
2327
+ */
2328
+ createScope(id, meta, options = {}) {
2329
+ const { ScopeConstructor = Scope } = options;
2330
+ let scope = this.getScopeById(id);
2331
+ if (!scope) {
2332
+ scope = new ScopeConstructor({ variableEngine: this, meta, id });
2333
+ this.scopeMap.set(id, scope);
2334
+ this.onScopeChangeEmitter.fire({ type: "add", scope });
2335
+ scope.toDispose.pushAll([
2336
+ scope.ast.subscribe(() => {
2337
+ this.onScopeChangeEmitter.fire({ type: "update", scope });
2338
+ }),
2339
+ // Fires when available variables change
2340
+ scope.available.onDataChange(() => {
2341
+ this.onScopeChangeEmitter.fire({ type: "available", scope });
2342
+ })
2343
+ ]);
2344
+ scope.onDispose(() => {
2345
+ this.scopeMap.delete(id);
2346
+ this.onScopeChangeEmitter.fire({ type: "delete", scope });
2347
+ });
2348
+ }
2349
+ return scope;
2350
+ }
2351
+ /**
2352
+ * Retrieves all scopes currently managed by the engine.
2353
+ * @param options Options for retrieving the scopes.
2354
+ * @param options.sort Whether to sort the scopes based on their dependency chain.
2355
+ * @returns An array of all scopes.
2356
+ */
2357
+ getAllScopes({
2358
+ sort
2359
+ } = {}) {
2360
+ const allScopes = Array.from(this.scopeMap.values());
2361
+ if (sort) {
2362
+ const sortScopes = this.chain.sortAll();
2363
+ const remainScopes = new Set(allScopes);
2364
+ sortScopes.forEach((_scope) => remainScopes.delete(_scope));
2365
+ return [...sortScopes, ...Array.from(remainScopes)];
2366
+ }
2367
+ return [...allScopes];
2368
+ }
2369
+ /**
2370
+ * Fires a global event to be broadcast to all listeners.
2371
+ * @param event The global event to fire.
2372
+ */
2373
+ fireGlobalEvent(event) {
2374
+ this.globalEvent$.next(event);
2375
+ }
2376
+ /**
2377
+ * Subscribes to a specific type of global event.
2378
+ * @param type The type of the event to listen for.
2379
+ * @param observer A function to be called when the event is observed.
2380
+ * @returns A disposable object to unsubscribe from the event.
2381
+ */
2382
+ onGlobalEvent(type, observer) {
2383
+ return subsToDisposable(
2384
+ this.globalEvent$.subscribe((_action) => {
2385
+ if (_action.type === type) {
2386
+ observer(_action);
2387
+ }
2388
+ })
2389
+ );
2390
+ }
2391
+ };
2392
+ __decorateClass([
2393
+ inversify.inject(ContainerProvider)
2394
+ ], exports.VariableEngine.prototype, "containerProvider", 2);
2395
+ __decorateClass([
2396
+ inversify.preDestroy()
2397
+ ], exports.VariableEngine.prototype, "dispose", 1);
2398
+ exports.VariableEngine = __decorateClass([
2399
+ inversify.injectable(),
2400
+ __decorateParam(0, inversify.inject(exports.ScopeChain)),
2401
+ __decorateParam(1, inversify.inject(exports.ASTRegisters))
2402
+ ], exports.VariableEngine);
2403
+ exports.VariableFieldKeyRenameService = class VariableFieldKeyRenameService {
2404
+ constructor() {
2405
+ this.toDispose = new utils.DisposableCollection();
2406
+ this.renameEmitter = new utils.Emitter();
2407
+ /**
2408
+ * Emits events for fields that are disposed of during a list change, but not renamed.
2409
+ * This helps distinguish between a field that was truly removed and one that was renamed.
2410
+ */
2411
+ this.disposeInListEmitter = new utils.Emitter();
2412
+ /**
2413
+ * An event that fires when a variable field key is successfully renamed.
2414
+ */
2415
+ this.onRename = this.renameEmitter.event;
2416
+ /**
2417
+ * An event that fires when a field is removed from a list (and not part of a rename).
2418
+ */
2419
+ this.onDisposeInList = this.disposeInListEmitter.event;
2420
+ }
2421
+ /**
2422
+ * Handles changes in a list of fields to detect rename operations.
2423
+ * @param ast The AST node where the change occurred.
2424
+ * @param prev The list of fields before the change.
2425
+ * @param next The list of fields after the change.
2426
+ */
2427
+ handleFieldListChange(ast, prev, next) {
2428
+ if (!ast || !prev?.length || !next?.length) {
2429
+ this.notifyFieldsDispose(prev, next);
2430
+ return;
2431
+ }
2432
+ if (prev.length !== next.length) {
2433
+ this.notifyFieldsDispose(prev, next);
2434
+ return;
2435
+ }
2436
+ let renameNodeInfo = null;
2437
+ let existFieldChanged = false;
2438
+ for (const [index, prevField] of prev.entries()) {
2439
+ const nextField = next[index];
2440
+ if (prevField.key !== nextField.key) {
2441
+ if (existFieldChanged) {
2442
+ this.notifyFieldsDispose(prev, next);
2443
+ return;
2444
+ }
2445
+ existFieldChanged = true;
2446
+ if (prevField.type?.kind === nextField.type?.kind) {
2447
+ renameNodeInfo = { before: prevField, after: nextField };
2448
+ }
2449
+ }
2450
+ }
2451
+ if (!renameNodeInfo) {
2452
+ this.notifyFieldsDispose(prev, next);
2453
+ return;
2454
+ }
2455
+ this.renameEmitter.fire(renameNodeInfo);
2456
+ }
2457
+ /**
2458
+ * Notifies listeners about fields that were removed from a list.
2459
+ * @param prev The list of fields before the change.
2460
+ * @param next The list of fields after the change.
2461
+ */
2462
+ notifyFieldsDispose(prev, next) {
2463
+ const removedFields = lodashEs.difference(prev || [], next || []);
2464
+ removedFields.forEach((_field) => this.disposeInListEmitter.fire(_field));
2465
+ }
2466
+ init() {
2467
+ this.toDispose.pushAll([
2468
+ this.variableEngine.onGlobalEvent(
2469
+ "VariableListChange",
2470
+ (_action) => {
2471
+ this.handleFieldListChange(_action.ast, _action.payload?.prev, _action.payload?.next);
2472
+ }
2473
+ ),
2474
+ this.variableEngine.onGlobalEvent(
2475
+ "ObjectPropertiesChange",
2476
+ (_action) => {
2477
+ this.handleFieldListChange(_action.ast, _action.payload?.prev, _action.payload?.next);
2478
+ }
2479
+ )
2480
+ ]);
2481
+ }
2482
+ dispose() {
2483
+ this.toDispose.dispose();
2484
+ }
2485
+ };
2486
+ __decorateClass([
2487
+ inversify.inject(exports.VariableEngine)
2488
+ ], exports.VariableFieldKeyRenameService.prototype, "variableEngine", 2);
2489
+ __decorateClass([
2490
+ inversify.postConstruct()
2491
+ ], exports.VariableFieldKeyRenameService.prototype, "init", 1);
2492
+ __decorateClass([
2493
+ inversify.preDestroy()
2494
+ ], exports.VariableFieldKeyRenameService.prototype, "dispose", 1);
2495
+ exports.VariableFieldKeyRenameService = __decorateClass([
2496
+ inversify.injectable()
2497
+ ], exports.VariableFieldKeyRenameService);
2498
+
2499
+ // src/variable-container-module.ts
2500
+ var VariableContainerModule = new inversify.ContainerModule((bind) => {
2501
+ bind(exports.VariableEngine).toSelf().inSingletonScope();
2502
+ bind(exports.ASTRegisters).toSelf().inSingletonScope();
2503
+ bind(exports.VariableFieldKeyRenameService).toSelf().inSingletonScope();
2504
+ bind(VariableEngineProvider).toDynamicValue((ctx) => () => ctx.container.get(exports.VariableEngine));
2505
+ bind(ContainerProvider).toDynamicValue((ctx) => () => ctx.container);
2506
+ });
2507
+ var ScopeKey = /* @__PURE__ */ Symbol("Scope");
2508
+ var ScopeProvider = vue.defineComponent({
2509
+ name: "ScopeProvider",
2510
+ props: {
2511
+ /**
2512
+ * scope used in the context
2513
+ */
2514
+ scope: {
2515
+ type: Object
2516
+ },
2517
+ /**
2518
+ * @deprecated use scope prop instead, this is kept for backward compatibility
2519
+ */
2520
+ value: {
2521
+ type: Object
2522
+ }
2523
+ },
2524
+ setup(props, { slots }) {
2525
+ const scopeToUse = vue.computed(() => props.scope || props.value?.scope);
2526
+ if (!scopeToUse.value) {
2527
+ throw new Error("[ScopeProvider] scope is required");
2528
+ }
2529
+ vue.provide(ScopeKey, scopeToUse);
2530
+ return () => slots.default?.();
2531
+ }
2532
+ });
2533
+ var useCurrentScope = (params) => {
2534
+ const { strict = false } = params || {};
2535
+ const context = vue.inject(ScopeKey, void 0);
2536
+ if (!context) {
2537
+ if (strict) {
2538
+ throw new Error("useCurrentScope must be used within a <ScopeProvider scope={scope}>");
2539
+ }
2540
+ console.warn("useCurrentScope should be used within a <ScopeProvider scope={scope}>");
2541
+ }
2542
+ return vue.unref(context);
2543
+ };
2544
+ function useScopeAvailable(params) {
2545
+ const { autoRefresh = true } = params || {};
2546
+ const scope = useCurrentScope({ strict: true });
2547
+ const tick = vue.shallowRef(0);
2548
+ if (autoRefresh) {
2549
+ const disposable = scope.available.onListOrAnyVarChange(() => {
2550
+ tick.value += 1;
2551
+ });
2552
+ vue.onScopeDispose(() => disposable.dispose());
2553
+ }
2554
+ return vue.computed(() => {
2555
+ tick.value;
2556
+ return scope.available;
2557
+ });
2558
+ }
2559
+ function useAvailableVariables() {
2560
+ const scope = useCurrentScope();
2561
+ const variableEngine = core.useService(exports.VariableEngine);
2562
+ const tick = vue.shallowRef(0);
2563
+ const disposable = !scope ? variableEngine.globalVariableTable.onListOrAnyVarChange(() => {
2564
+ tick.value += 1;
2565
+ }) : scope.available.onDataChange(() => {
2566
+ tick.value += 1;
2567
+ });
2568
+ vue.onScopeDispose(() => disposable.dispose());
2569
+ return vue.computed(() => {
2570
+ tick.value;
2571
+ return scope ? scope.available.variables : variableEngine.globalVariableTable.variables;
2572
+ });
2573
+ }
2574
+ function useOutputVariables() {
2575
+ const scope = useCurrentScope();
2576
+ const tick = vue.shallowRef(0);
2577
+ if (!scope) {
2578
+ throw new Error(
2579
+ "[useOutputVariables]: No scope found, useOutputVariables must be used in <ScopeProvider>"
2580
+ );
2581
+ }
2582
+ const disposable = scope.output.onListOrAnyVarChange(() => {
2583
+ tick.value += 1;
2584
+ });
2585
+ vue.onScopeDispose(() => disposable.dispose());
2586
+ return vue.computed(() => {
2587
+ tick.value;
2588
+ return scope.output.variables;
2589
+ });
2590
+ }
2591
+
2592
+ exports.ASTKind = ASTKind;
2593
+ exports.ASTNode = ASTNode;
2594
+ exports.ASTNodeFlags = ASTNodeFlags;
2595
+ exports.ArrayType = ArrayType;
2596
+ exports.BaseExpression = BaseExpression;
2597
+ exports.BaseType = BaseType;
2598
+ exports.BaseVariableField = BaseVariableField;
2599
+ exports.BooleanType = BooleanType;
2600
+ exports.CustomType = CustomType;
2601
+ exports.DataNode = DataNode;
2602
+ exports.EnumerateExpression = EnumerateExpression;
2603
+ exports.IntegerType = IntegerType;
2604
+ exports.KeyPathExpression = KeyPathExpression;
2605
+ exports.LegacyKeyPathExpression = LegacyKeyPathExpression;
2606
+ exports.ListNode = ListNode;
2607
+ exports.MapNode = MapNode;
2608
+ exports.MapType = MapType;
2609
+ exports.NumberType = NumberType;
2610
+ exports.ObjectType = ObjectType;
2611
+ exports.Property = Property;
2612
+ exports.Scope = Scope;
2613
+ exports.ScopeKey = ScopeKey;
2614
+ exports.ScopeOutputData = ScopeOutputData;
2615
+ exports.ScopeProvider = ScopeProvider;
2616
+ exports.StringType = StringType;
2617
+ exports.VariableContainerModule = VariableContainerModule;
2618
+ exports.VariableDeclaration = VariableDeclaration;
2619
+ exports.VariableDeclarationList = VariableDeclarationList;
2620
+ exports.VariableEngineProvider = VariableEngineProvider;
2621
+ exports.WrapArrayExpression = WrapArrayExpression;
2622
+ exports.injectToAST = injectToAST;
2623
+ exports.isMatchAST = isMatchAST;
2624
+ exports.postConstructAST = postConstructAST;
2625
+ exports.useAvailableVariables = useAvailableVariables;
2626
+ exports.useCurrentScope = useCurrentScope;
2627
+ exports.useOutputVariables = useOutputVariables;
2628
+ exports.useScopeAvailable = useScopeAvailable;
2629
+ //# sourceMappingURL=index.cjs.map
2630
+ //# sourceMappingURL=index.cjs.map