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

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