@flowgram.ai/variable-core 0.1.0-alpha.3 → 0.1.0-alpha.31

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