Bladeren bron

refactor(variable): toJSON to force to be set for every AST (#958)

* chore: remove inject opts type generic

* chore: force toJSON implementation in ASTNode

* chore: key path expression distinct until changed

* fix: ci
Yiwei Mao 2 maanden geleden
bovenliggende
commit
f4cabf59be
27 gewijzigde bestanden met toevoegingen van 144 en 114 verwijderingen
  1. 2 2
      packages/variable-engine/variable-core/__tests__/ast/__snapshots__/key-path-expression-v2.test.ts.snap
  2. 6 29
      packages/variable-engine/variable-core/__tests__/ast/__snapshots__/variable-declaration.test.ts.snap
  3. 2 2
      packages/variable-engine/variable-core/__tests__/ast/__snapshots__/variable-with-initializer.test.ts.snap
  4. 13 0
      packages/variable-engine/variable-core/__tests__/ast/ast-decorators.test.ts
  5. 11 4
      packages/variable-engine/variable-core/__tests__/case-run-down/blockwise-python-expression.test.ts
  6. 20 15
      packages/variable-engine/variable-core/src/ast/ast-node.ts
  7. 10 2
      packages/variable-engine/variable-core/src/ast/ast-registers.ts
  8. 1 1
      packages/variable-engine/variable-core/src/ast/common/list-node.ts
  9. 1 1
      packages/variable-engine/variable-core/src/ast/common/map-node.ts
  10. 5 6
      packages/variable-engine/variable-core/src/ast/declaration/base-variable-field.ts
  11. 1 4
      packages/variable-engine/variable-core/src/ast/declaration/property.ts
  12. 2 2
      packages/variable-engine/variable-core/src/ast/declaration/variable-declaration-list.ts
  13. 12 1
      packages/variable-engine/variable-core/src/ast/declaration/variable-declaration.ts
  14. 2 5
      packages/variable-engine/variable-core/src/ast/expression/base-expression.ts
  15. 1 1
      packages/variable-engine/variable-core/src/ast/expression/enumerate-expression.ts
  16. 16 14
      packages/variable-engine/variable-core/src/ast/expression/keypath-expression.ts
  17. 5 5
      packages/variable-engine/variable-core/src/ast/expression/legacy-keypath-expression.ts
  18. 1 1
      packages/variable-engine/variable-core/src/ast/expression/wrap-array-expression.ts
  19. 1 1
      packages/variable-engine/variable-core/src/ast/type/array.ts
  20. 1 14
      packages/variable-engine/variable-core/src/ast/type/base-type.ts
  21. 4 0
      packages/variable-engine/variable-core/src/ast/type/boolean.ts
  22. 6 0
      packages/variable-engine/variable-core/src/ast/type/custom-type.ts
  23. 4 0
      packages/variable-engine/variable-core/src/ast/type/integer.ts
  24. 1 1
      packages/variable-engine/variable-core/src/ast/type/map.ts
  25. 4 0
      packages/variable-engine/variable-core/src/ast/type/number.ts
  26. 1 2
      packages/variable-engine/variable-core/src/ast/type/object.ts
  27. 11 1
      packages/variable-engine/variable-core/src/ast/type/string.ts

+ 2 - 2
packages/variable-engine/variable-core/__tests__/ast/__snapshots__/key-path-expression-v2.test.ts.snap

@@ -11,7 +11,7 @@ exports[`test Key Path Expression V2 > init const test_key_path = source.a 1`] =
   },
   "key": "test_key_path",
   "kind": "VariableDeclaration",
-  "meta": undefined,
+  "order": 0,
   "type": {
     "kind": "String",
   },
@@ -82,7 +82,7 @@ exports[`test Key Path Expression V2 > subscribe variable changes by expression
   },
   "key": "test_key_path",
   "kind": "VariableDeclaration",
-  "meta": undefined,
+  "order": 0,
   "type": {
     "kind": "Number",
   },

+ 6 - 29
packages/variable-engine/variable-core/__tests__/ast/__snapshots__/variable-declaration.test.ts.snap

@@ -24,71 +24,60 @@ exports[`test Basic Variable Declaration > test simple variable declarations 1`]
 {
   "declarations": [
     {
-      "initializer": undefined,
       "key": "string",
       "kind": "VariableDeclaration",
-      "meta": undefined,
+      "order": 0,
       "type": {
         "kind": "String",
       },
     },
     {
-      "initializer": undefined,
       "key": "boolean",
       "kind": "VariableDeclaration",
-      "meta": undefined,
+      "order": 1,
       "type": {
         "kind": "Boolean",
       },
     },
     {
-      "initializer": undefined,
       "key": "number",
       "kind": "VariableDeclaration",
-      "meta": undefined,
+      "order": 2,
       "type": {
         "kind": "Number",
       },
     },
     {
-      "initializer": undefined,
       "key": "integer",
       "kind": "VariableDeclaration",
-      "meta": undefined,
+      "order": 3,
       "type": {
         "kind": "Integer",
       },
     },
     {
-      "initializer": undefined,
       "key": "object",
       "kind": "VariableDeclaration",
-      "meta": undefined,
+      "order": 4,
       "type": {
         "kind": "Object",
         "properties": [
           {
-            "initializer": undefined,
             "key": "key1",
             "kind": "Property",
-            "meta": undefined,
             "type": {
               "kind": "String",
             },
           },
           {
-            "initializer": undefined,
             "key": "key2",
             "kind": "Property",
-            "meta": undefined,
             "type": {
               "kind": "Object",
               "properties": [
                 {
-                  "initializer": undefined,
                   "key": "key1",
                   "kind": "Property",
-                  "meta": undefined,
                   "type": {
                     "kind": "Number",
                   },
@@ -97,29 +86,22 @@ exports[`test Basic Variable Declaration > test simple variable declarations 1`]
             },
           },
           {
-            "initializer": undefined,
             "key": "key3",
             "kind": "Property",
-            "meta": undefined,
             "type": {
-              "items": undefined,
               "kind": "Array",
             },
           },
           {
-            "initializer": undefined,
             "key": "key4",
             "kind": "Property",
-            "meta": undefined,
             "type": {
               "items": {
                 "kind": "Object",
                 "properties": [
                   {
-                    "initializer": undefined,
                     "key": "key1",
                     "kind": "Property",
-                    "meta": undefined,
                     "type": {
                       "kind": "Boolean",
                     },
@@ -133,10 +115,9 @@ exports[`test Basic Variable Declaration > test simple variable declarations 1`]
       },
     },
     {
-      "initializer": undefined,
       "key": "map",
       "kind": "VariableDeclaration",
-      "meta": undefined,
+      "order": 5,
       "type": {
         "keyType": {
           "kind": "String",
@@ -163,10 +144,8 @@ exports[`test Basic Variable Declaration > variable declaration subscribe 2`] =
   "kind": "Object",
   "properties": [
     {
-      "initializer": undefined,
       "key": "key1",
       "kind": "Property",
-      "meta": undefined,
       "type": {
         "kind": "String",
       },
@@ -180,10 +159,8 @@ exports[`test Basic Variable Declaration > variable declaration subscribe 3`] =
   "kind": "Object",
   "properties": [
     {
-      "initializer": undefined,
       "key": "key1",
       "kind": "Property",
-      "meta": undefined,
       "type": {
         "kind": "Number",
       },

+ 2 - 2
packages/variable-engine/variable-core/__tests__/ast/__snapshots__/variable-with-initializer.test.ts.snap

@@ -11,7 +11,7 @@ exports[`test Variable With Initializer > init const test_key_path = source.a 1`
   },
   "key": "test_key_path",
   "kind": "VariableDeclaration",
-  "meta": undefined,
+  "order": 0,
   "type": {
     "kind": "String",
   },
@@ -82,7 +82,7 @@ exports[`test Variable With Initializer > subscribe variable changes by expressi
   },
   "key": "test_key_path",
   "kind": "VariableDeclaration",
-  "meta": undefined,
+  "order": 0,
   "type": {
     "kind": "Number",
   },

+ 13 - 0
packages/variable-engine/variable-core/__tests__/ast/ast-decorators.test.ts

@@ -33,6 +33,12 @@ describe('test ast decorators', () => {
       fromJSON(json: any): void {
         // do nothing
       }
+
+      toJSON() {
+        return {
+          testFlag: this.testFlag,
+        };
+      }
     }
 
     variableEngine.astRegisters.registerAST(PostConstructTest);
@@ -70,6 +76,13 @@ describe('test ast decorators', () => {
         fromJSON(json: any): void {
           // do nothing
         }
+
+        toJSON() {
+          return {
+            testFlag1: this.testFlag1,
+            testFlag2: this.testFlag2,
+          };
+        }
       }
       variableEngine.astRegisters.registerAST(PostConstructTest2);
     }).toThrowError();

+ 11 - 4
packages/variable-engine/variable-core/__tests__/case-run-down/blockwise-python-expression.test.ts

@@ -51,16 +51,16 @@ describe('Case Run Down: Python Expression In Blockwise', () => {
 
     static kind: string = 'BlockwisePythonExpression';
 
-    _uri: string;
+    _uri?: string;
 
-    _content: string;
+    _content?: string;
 
     // Blockwise 通过 schema 变更时输出的方式来进行类型推导
     getRefFields() {
       return [];
     }
 
-    returnType: BaseType<any, any> | undefined;
+    returnType: BaseType<any> | undefined;
 
     _prevType: any;
 
@@ -76,13 +76,20 @@ describe('Case Run Down: Python Expression In Blockwise', () => {
       }
     }
 
+    toJSON(): PyExpressionJSON {
+      return {
+        content: this._content!,
+        uri: this._uri!,
+      };
+    }
+
     constructor(params: CreateASTParams) {
       super(params);
 
       this.toDispose.push(
         // 监听后端触发批量校验
         this.service.onBatchInfer(() => {
-          const nextType = this.service.uriToType[this._uri];
+          const nextType = this.service.uriToType[this._uri!];
 
           if (!isEqual(nextType, this._prevType)) {
             this.updateChildNodeByKey('returnType', nextType);

+ 20 - 15
packages/variable-engine/variable-core/src/ast/ast-node.ts

@@ -13,6 +13,7 @@ import {
   tap,
 } from 'rxjs';
 import { nanoid } from 'nanoid';
+import { isNil, omitBy } from 'lodash-es';
 import { shallowEqual } from 'fast-equals';
 import { Disposable, DisposableCollection } from '@flowgram.ai/utils';
 
@@ -32,9 +33,9 @@ import {
 } from './types';
 import { ASTNodeFlags } from './flags';
 
-export interface ASTNodeRegistry<JSON extends ASTNodeJSON = any, InjectOpts = any> {
+export interface ASTNodeRegistry<JSON extends ASTNodeJSON = any> {
   kind: string;
-  new (params: CreateASTParams, injectOpts: InjectOpts): ASTNode<JSON>;
+  new (params: CreateASTParams, injectOpts: any): ASTNode<JSON>;
 }
 
 /**
@@ -50,16 +51,14 @@ export interface ASTNodeRegistry<JSON extends ASTNodeJSON = any, InjectOpts = an
  * - **Reactive**: Changes in an ASTNode's value trigger events, enabling reactive programming patterns.
  * - **Serializable**: ASTNodes can be converted to and from a JSON format (ASTNodeJSON) for storage or transmission.
  */
-export abstract class ASTNode<JSON extends ASTNodeJSON = any, InjectOpts = any>
-  implements Disposable
-{
+export abstract class ASTNode<JSON extends ASTNodeJSON = any> implements Disposable {
   /**
    * @deprecated
    * Get the injected options for the ASTNode.
    *
    * Please use `@injectToAst(XXXService) declare xxxService: XXXService` to achieve external dependency injection.
    */
-  public readonly opts?: InjectOpts;
+  public readonly opts?: any;
 
   /**
    * The unique identifier of the ASTNode, which is **immutable**.
@@ -145,7 +144,7 @@ export abstract class ASTNode<JSON extends ASTNodeJSON = any, InjectOpts = any>
    * @param createParams Necessary parameters for creating an ASTNode.
    * @param injectOptions Dependency injection for various modules.
    */
-  constructor({ key, parent, scope }: CreateASTParams, opts?: InjectOpts) {
+  constructor({ key, parent, scope }: CreateASTParams, opts?: any) {
     this.scope = scope;
     this.parent = parent;
     this.opts = opts;
@@ -155,6 +154,19 @@ export abstract class ASTNode<JSON extends ASTNodeJSON = any, InjectOpts = any>
 
     // All `fireChange` calls within the subsequent `fromJSON` will be merged into one.
     this.fromJSON = this.withBatchUpdate(this.fromJSON.bind(this));
+
+    // Add the kind field to the JSON output.
+    const rawToJSON = this.toJSON?.bind(this);
+    this.toJSON = () =>
+      omitBy(
+        {
+          // always include kind
+          kind: this.kind,
+          ...(rawToJSON?.() || {}),
+        },
+        // remove undefined fields
+        isNil
+      ) as JSON;
   }
 
   /**
@@ -184,14 +196,7 @@ export abstract class ASTNode<JSON extends ASTNodeJSON = any, InjectOpts = any>
    * Serializes the current ASTNode to ASTNodeJSON.
    * @returns
    */
-  toJSON(): ASTNodeJSON {
-    // Prompt the user to implement the toJSON method for the ASTNode themselves, instead of using the fallback implementation.
-    console.warn('[VariableEngine] Please Implement toJSON method for ' + this.kind);
-
-    return {
-      kind: this.kind,
-    };
-  }
+  abstract toJSON(): JSON;
 
   /**
    * Creates a child ASTNode.

+ 10 - 2
packages/variable-engine/variable-core/src/ast/ast-registers.ts

@@ -30,6 +30,9 @@ type DataInjector = () => Record<string, any>;
  */
 @injectable()
 export class ASTRegisters {
+  /**
+   * @deprecated Please use `@injectToAst(XXXService) declare xxxService: XXXService` to achieve external dependency injection.
+   */
   protected injectors: Map<ASTKindType, DataInjector> = new Map();
 
   protected astMap: Map<ASTKindType, ASTNodeRegistry> = new Map();
@@ -110,9 +113,14 @@ export class ASTRegisters {
   /**
    * Registers an AST node.
    * @param ASTNode
-   * @param injector
    */
-  registerAST(ASTNode: ASTNodeRegistry, injector?: DataInjector) {
+  registerAST(
+    ASTNode: ASTNodeRegistry,
+    /**
+     * @deprecated Please use `@injectToAst(XXXService) declare xxxService: XXXService` to achieve external dependency injection.
+     */
+    injector?: DataInjector
+  ) {
     this.astMap.set(ASTNode.kind, ASTNode);
     if (injector) {
       this.injectors.set(ASTNode.kind, injector);

+ 1 - 1
packages/variable-engine/variable-core/src/ast/common/list-node.ts

@@ -61,7 +61,7 @@ export class ListNode extends ASTNode<ListNodeJSON> {
    * Serialize the `ListNode` to `ListNodeJSON`.
    * @returns The JSON representation of `ListNode`.
    */
-  toJSON(): ASTNodeJSON {
+  toJSON() {
     return {
       kind: ASTKind.ListNode,
       list: this._list.map((item) => item.toJSON()),

+ 1 - 1
packages/variable-engine/variable-core/src/ast/common/map-node.ts

@@ -46,7 +46,7 @@ export class MapNode extends ASTNode<MapNodeJSON> {
    * Serialize the `MapNode` to `MapNodeJSON`.
    * @returns The JSON representation of `MapNode`.
    */
-  toJSON(): ASTNodeJSON {
+  toJSON() {
     return {
       kind: ASTKind.MapNode,
       map: Array.from(this.map.entries()),

+ 5 - 6
packages/variable-engine/variable-core/src/ast/declaration/base-variable-field.ts

@@ -15,13 +15,13 @@ import { ASTNode } from '../ast-node';
 /**
  * ASTNodeJSON representation of `BaseVariableField`
  */
-export type BaseVariableFieldJSON<VariableMeta = any> = {
+export interface BaseVariableFieldJSON<VariableMeta = any> extends ASTNodeJSON {
   /**
    * key of the variable field
    * - For `VariableDeclaration`, the key should be global unique.
    * - For `Property`, the key is the property name.
    */
-  key?: Identifier;
+  key: Identifier;
   /**
    * type of the variable field, similar to js code:
    * `const v: string`
@@ -38,7 +38,7 @@ export type BaseVariableFieldJSON<VariableMeta = any> = {
    * meta data of the variable field, you cans store information like `title`, `icon`, etc.
    */
   meta?: VariableMeta;
-};
+}
 
 /**
  * Variable Field abstract class, which is the base class for `VariableDeclaration` and `Property`
@@ -107,7 +107,7 @@ export abstract class BaseVariableField<VariableMeta = any> extends ASTNode<
    * Deserialize the `BaseVariableFieldJSON` to the `BaseVariableField`.
    * @param json ASTJSON representation of `BaseVariableField`
    */
-  fromJSON({ type, initializer, meta }: BaseVariableFieldJSON<VariableMeta>): void {
+  fromJSON({ type, initializer, meta }: Omit<BaseVariableFieldJSON<VariableMeta>, 'key'>): void {
     // 类型变化
     this.updateType(type);
 
@@ -173,9 +173,8 @@ export abstract class BaseVariableField<VariableMeta = any> extends ASTNode<
    * Serialize the variable field to JSON
    * @returns ASTNodeJSON representation of `BaseVariableField`
    */
-  toJSON(): BaseVariableFieldJSON<VariableMeta> & { kind: string } {
+  toJSON(): BaseVariableFieldJSON<VariableMeta> {
     return {
-      kind: this.kind,
       key: this.key,
       type: this.type?.toJSON(),
       initializer: this.initializer?.toJSON(),

+ 1 - 4
packages/variable-engine/variable-core/src/ast/declaration/property.ts

@@ -9,10 +9,7 @@ import { BaseVariableField, BaseVariableFieldJSON } from './base-variable-field'
 /**
  * ASTNodeJSON representation of the `Property`.
  */
-export type PropertyJSON<VariableMeta = any> = BaseVariableFieldJSON<VariableMeta> & {
-  // Key is a required field.
-  key: string;
-};
+export type PropertyJSON<VariableMeta = any> = BaseVariableFieldJSON<VariableMeta>;
 
 /**
  * `Property` is a variable field that represents a property of a `ObjectType`.

+ 2 - 2
packages/variable-engine/variable-core/src/ast/declaration/variable-declaration-list.ts

@@ -3,7 +3,7 @@
  * SPDX-License-Identifier: MIT
  */
 
-import { ASTKind, ASTNodeJSON } from '../types';
+import { ASTKind } from '../types';
 import { GlobalEventActionType } from '../types';
 import { ASTNode } from '../ast-node';
 import { type VariableDeclarationJSON, VariableDeclaration } from './variable-declaration';
@@ -103,7 +103,7 @@ export class VariableDeclarationList extends ASTNode<VariableDeclarationListJSON
    * Serialize the `VariableDeclarationList` to the `VariableDeclarationListJSON`.
    * @returns ASTJSON representation of `VariableDeclarationList`
    */
-  toJSON(): ASTNodeJSON {
+  toJSON() {
     return {
       kind: ASTKind.VariableDeclarationList,
       declarations: this.declarations.map((_declaration) => _declaration.toJSON()),

+ 12 - 1
packages/variable-engine/variable-core/src/ast/declaration/variable-declaration.ts

@@ -43,7 +43,7 @@ export class VariableDeclaration<VariableMeta = any> extends BaseVariableField<V
   /**
    * Deserialize the `VariableDeclarationJSON` to the `VariableDeclaration`.
    */
-  fromJSON({ order, ...rest }: VariableDeclarationJSON<VariableMeta>): void {
+  fromJSON({ order, ...rest }: Omit<VariableDeclarationJSON<VariableMeta>, 'key'>): void {
     // Update order.
     this.updateOrder(order);
 
@@ -64,4 +64,15 @@ export class VariableDeclaration<VariableMeta = any> extends BaseVariableField<V
       this.fireChange();
     }
   }
+
+  /**
+   * Serialize the `VariableDeclaration` to `VariableDeclarationJSON`.
+   * @returns The JSON representation of `VariableDeclaration`.
+   */
+  toJSON(): VariableDeclarationJSON<VariableMeta> {
+    return {
+      ...super.toJSON(),
+      order: this.order,
+    };
+  }
 }

+ 2 - 5
packages/variable-engine/variable-core/src/ast/expression/base-expression.ts

@@ -31,10 +31,7 @@ type ExpressionRefs = (BaseVariableField | undefined)[];
  *
  * All other expressions should extend this class.
  */
-export abstract class BaseExpression<
-  JSON extends ASTNodeJSON = any,
-  InjectOpts = any
-> extends ASTNode<JSON, InjectOpts> {
+export abstract class BaseExpression<JSON extends ASTNodeJSON = any> extends ASTNode<JSON> {
   public flags: ASTNodeFlags = ASTNodeFlags.Expression;
 
   /**
@@ -105,7 +102,7 @@ export abstract class BaseExpression<
     share()
   );
 
-  constructor(params: CreateASTParams, opts?: InjectOpts) {
+  constructor(params: CreateASTParams, opts?: any) {
     super(params, opts);
 
     this.toDispose.push(

+ 1 - 1
packages/variable-engine/variable-core/src/ast/expression/enumerate-expression.ts

@@ -68,7 +68,7 @@ export class EnumerateExpression extends BaseExpression<EnumerateExpressionJSON>
    * Serialize the `EnumerateExpression` to `EnumerateExpressionJSON`.
    * @returns The JSON representation of `EnumerateExpression`.
    */
-  toJSON(): ASTNodeJSON {
+  toJSON() {
     return {
       kind: ASTKind.EnumerateExpression,
       enumerateFor: this.enumerateFor?.toJSON(),

+ 16 - 14
packages/variable-engine/variable-core/src/ast/expression/keypath-expression.ts

@@ -3,6 +3,7 @@
  * SPDX-License-Identifier: MIT
  */
 
+import { distinctUntilChanged } from 'rxjs';
 import { shallowEqual } from 'fast-equals';
 
 import { checkRefCycle } from '../utils/expression';
@@ -36,6 +37,8 @@ export class KeyPathExpression<
 
   protected _keyPath: string[] = [];
 
+  protected _rawPathJson: CustomPathJSON;
+
   /**
    * The key path of the variable.
    */
@@ -98,6 +101,7 @@ export class KeyPathExpression<
 
     if (!shallowEqual(keyPath, this._keyPath)) {
       this._keyPath = keyPath;
+      this._rawPathJson = json;
 
       // After the keyPath is updated, the referenced variables need to be refreshed.
       this.refreshRefs();
@@ -113,8 +117,6 @@ export class KeyPathExpression<
     return _ref?.type?.toJSON();
   }
 
-  protected prevRefTypeHash: string | undefined;
-
   constructor(params: CreateASTParams, opts: any) {
     super(params, opts);
 
@@ -130,14 +132,17 @@ export class KeyPathExpression<
         }
       }),
       subsToDisposable(
-        this.refs$.subscribe((_type) => {
-          const [ref] = this._refs;
-
-          if (this.prevRefTypeHash !== ref?.type?.hash) {
-            this.prevRefTypeHash = ref?.type?.hash;
+        this.refs$
+          .pipe(
+            distinctUntilChanged(
+              (prev, next) => prev === next,
+              (_refs) => _refs?.[0]?.type?.hash
+            )
+          )
+          .subscribe((_type) => {
+            const [ref] = this._refs;
             this.updateChildNodeByKey('_returnType', this.getReturnTypeJSONByRef(ref));
-          }
-        })
+          })
       ),
     ]);
   }
@@ -146,10 +151,7 @@ export class KeyPathExpression<
    * Serialize the `KeyPathExpression` to `KeyPathExpressionJSON`.
    * @returns The JSON representation of `KeyPathExpression`.
    */
-  toJSON(): ASTNodeJSON {
-    return {
-      kind: ASTKind.KeyPathExpression,
-      keyPath: this._keyPath,
-    };
+  toJSON() {
+    return this._rawPathJson;
   }
 }

+ 5 - 5
packages/variable-engine/variable-core/src/ast/expression/legacy-keypath-expression.ts

@@ -32,6 +32,8 @@ export class LegacyKeyPathExpression<
 
   protected _keyPath: string[] = [];
 
+  protected _rawPathJson: CustomPathJSON;
+
   /**
    * The key path of the variable.
    */
@@ -83,6 +85,7 @@ export class LegacyKeyPathExpression<
 
     if (!shallowEqual(keyPath, this._keyPath)) {
       this._keyPath = keyPath;
+      this._rawPathJson = json;
 
       // After the keyPath is updated, the referenced variables need to be refreshed.
       this.refreshRefs();
@@ -110,10 +113,7 @@ export class LegacyKeyPathExpression<
    * Serialize the `KeyPathExpression` to `KeyPathExpressionJSON`.
    * @returns The JSON representation of `KeyPathExpression`.
    */
-  toJSON(): ASTNodeJSON {
-    return {
-      kind: ASTKind.KeyPathExpression,
-      keyPath: this._keyPath,
-    };
+  toJSON() {
+    return this._rawPathJson;
   }
 }

+ 1 - 1
packages/variable-engine/variable-core/src/ast/expression/wrap-array-expression.ts

@@ -75,7 +75,7 @@ export class WrapArrayExpression extends BaseExpression<WrapArrayExpressionJSON>
    * Serialize the `WrapArrayExpression` to `WrapArrayExpressionJSON`.
    * @returns The JSON representation of `WrapArrayExpression`.
    */
-  toJSON(): ASTNodeJSON {
+  toJSON() {
     return {
       kind: ASTKind.WrapArrayExpression,
       wrapFor: this.wrapFor?.toJSON(),

+ 1 - 1
packages/variable-engine/variable-core/src/ast/type/array.ts

@@ -100,7 +100,7 @@ export class ArrayType extends BaseType<ArrayJSON> {
    * Serialize the `ArrayType` to `ArrayJSON`
    * @returns The JSON representation of `ArrayType`.
    */
-  toJSON(): ASTNodeJSON {
+  toJSON() {
     return {
       kind: ASTKind.Array,
       items: this.items?.toJSON(),

+ 1 - 14
packages/variable-engine/variable-core/src/ast/type/base-type.ts

@@ -15,10 +15,7 @@ import { UnionJSON } from './union';
  *
  * All other types should extend this class.
  */
-export abstract class BaseType<JSON extends ASTNodeJSON = any, InjectOpts = any> extends ASTNode<
-  JSON,
-  InjectOpts
-> {
+export abstract class BaseType<JSON extends ASTNodeJSON = any> extends ASTNode<JSON> {
   public flags: number = ASTNodeFlags.BasicType;
 
   /**
@@ -49,14 +46,4 @@ export abstract class BaseType<JSON extends ASTNodeJSON = any, InjectOpts = any>
   getByKeyPath(keyPath: string[] = []): BaseVariableField | undefined {
     throw new Error(`Get By Key Path is not implemented for Type: ${this.kind}`);
   }
-
-  /**
-   * Serialize the node to a JSON object.
-   * @returns The JSON representation of the node.
-   */
-  toJSON(): ASTNodeJSON {
-    return {
-      kind: this.kind,
-    };
-  }
 }

+ 4 - 0
packages/variable-engine/variable-core/src/ast/type/boolean.ts

@@ -19,4 +19,8 @@ export class BooleanType extends BaseType {
   fromJSON(): void {
     // noop
   }
+
+  toJSON() {
+    return {};
+  }
 }

+ 6 - 0
packages/variable-engine/variable-core/src/ast/type/custom-type.ts

@@ -61,4 +61,10 @@ export class CustomType extends BaseType<CustomTypeJSON> {
 
     return targetTypeJSON?.kind === this.kind && targetTypeJSON?.typeName === this.typeName;
   }
+
+  toJSON() {
+    return {
+      typeName: this.typeName,
+    };
+  }
 }

+ 4 - 0
packages/variable-engine/variable-core/src/ast/type/integer.ts

@@ -22,4 +22,8 @@ export class IntegerType extends BaseType {
   fromJSON(): void {
     // noop
   }
+
+  toJSON() {
+    return {};
+  }
 }

+ 1 - 1
packages/variable-engine/variable-core/src/ast/type/map.ts

@@ -86,7 +86,7 @@ export class MapType extends BaseType<MapJSON> {
    * Serialize the node to a JSON object.
    * @returns The JSON representation of the node.
    */
-  toJSON(): ASTNodeJSON {
+  toJSON() {
     return {
       kind: ASTKind.Map,
       keyType: this.keyType?.toJSON(),

+ 4 - 0
packages/variable-engine/variable-core/src/ast/type/number.ts

@@ -19,4 +19,8 @@ export class NumberType extends BaseType {
   fromJSON(): void {
     // noop
   }
+
+  toJSON() {
+    return {};
+  }
 }

+ 1 - 2
packages/variable-engine/variable-core/src/ast/type/object.ts

@@ -106,9 +106,8 @@ export class ObjectType extends BaseType<ObjectJSON> {
    * Serialize the `ObjectType` to `ObjectJSON`.
    * @returns The JSON representation of `ObjectType`.
    */
-  toJSON(): ASTNodeJSON {
+  toJSON() {
     return {
-      kind: ASTKind.Object,
       properties: this.properties.map((_property) => _property.toJSON()),
     };
   }

+ 11 - 1
packages/variable-engine/variable-core/src/ast/type/string.ts

@@ -17,7 +17,7 @@ export interface StringJSON {
   format?: string;
 }
 
-export class StringType extends BaseType {
+export class StringType extends BaseType<StringJSON> {
   public flags: ASTNodeFlags = ASTNodeFlags.BasicType;
 
   static kind: string = ASTKind.String;
@@ -42,4 +42,14 @@ export class StringType extends BaseType {
       this.fireChange();
     }
   }
+
+  /**
+   * Serialize the `StringType` to `StringJSON`.
+   * @returns The JSON representation of `StringType`.
+   */
+  toJSON() {
+    return {
+      format: this._format,
+    };
+  }
 }