This is an automated email from the ASF dual-hosted git repository.

chaokunyang pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/fory.git


The following commit(s) were added to refs/heads/main by this push:
     new 34b312ed0 feat(JavaScript): Impl xlang  JavaScript testcase (#3263)
34b312ed0 is described below

commit 34b312ed091f4d7cb4e3b3fdb7e101cab1f6b557
Author: weipeng <[email protected]>
AuthorDate: Thu Feb 5 15:54:39 2026 +0800

    feat(JavaScript): Impl xlang  JavaScript testcase (#3263)
    
    ## Why?
    
    
    
    ## What does this PR do?
    Impl xlang JavaScript testcase
    (test_simple_struct,test_named_simple_struct,test_list). Other cases
    will be submit on next PR.
    
    ## Related issues
    #3133
    
    
    ## Does this PR introduce any user-facing change?
    
    
    
    - [ ] Does this PR introduce any public API change?
    - [ ] Does this PR introduce any binary protocol compatibility change?
    
    ## Benchmark
---
 javascript/packages/fory/lib/gen/any.ts        | 30 +++++---
 javascript/packages/fory/lib/gen/collection.ts | 17 ++---
 javascript/packages/fory/lib/gen/map.ts        |  2 -
 javascript/packages/fory/lib/gen/number.ts     |  7 ++
 javascript/packages/fory/lib/meta/TypeMeta.ts  |  8 ++-
 javascript/packages/fory/lib/typeInfo.ts       |  7 ++
 javascript/packages/fory/lib/typeResolver.ts   | 29 ++++++--
 javascript/test/any.test.ts                    |  4 +-
 javascript/test/crossLanguage.test.ts          | 98 ++++++++++++--------------
 9 files changed, 121 insertions(+), 81 deletions(-)

diff --git a/javascript/packages/fory/lib/gen/any.ts 
b/javascript/packages/fory/lib/gen/any.ts
index d2330f4db..805cd9e28 100644
--- a/javascript/packages/fory/lib/gen/any.ts
+++ b/javascript/packages/fory/lib/gen/any.ts
@@ -24,6 +24,7 @@ import { CodegenRegistry } from "./router";
 import { Mode, Serializer, TypeId } from "../type";
 import { Scope } from "./scope";
 import Fory from "../fory";
+import { TypeMeta } from "../meta/TypeMeta";
 
 export class AnyHelper {
   static detectSerializer(fory: Fory) {
@@ -33,26 +34,37 @@ export class AnyHelper {
       userTypeId = fory.binaryReader.readVarUint32Small7();
     }
     let serializer: Serializer | undefined;
+
+    function tryUpdateSerializer(serializer: Serializer | undefined | null, 
typeMeta: TypeMeta) {
+      if (!serializer) {
+        throw new Error(`can't find implements of typeId: ${typeId}`);
+      }
+      const hash = serializer.getHash();
+      if (hash !== typeMeta.getHash()) {
+        return fory.typeMetaResolver.genSerializerByTypeMetaRuntime(typeMeta);
+      }
+      return serializer;
+    }
+
     switch (typeId) {
       case TypeId.COMPATIBLE_STRUCT:
+        {
+          const typeMeta = 
fory.typeMetaResolver.readTypeMeta(fory.binaryReader);
+          serializer = fory.typeResolver.getSerializerById(typeId, 
typeMeta.getUserTypeId());
+          serializer = tryUpdateSerializer(serializer, typeMeta);
+        }
+        break;
       case TypeId.NAMED_ENUM:
       case TypeId.NAMED_STRUCT:
       case TypeId.NAMED_EXT:
       case TypeId.NAMED_UNION:
       case TypeId.NAMED_COMPATIBLE_STRUCT:
-        if (fory.config.mode === Mode.Compatible || typeId === 
TypeId.COMPATIBLE_STRUCT) {
+        if (fory.config.mode === Mode.Compatible || typeId === 
TypeId.NAMED_COMPATIBLE_STRUCT) {
           const typeMeta = 
fory.typeMetaResolver.readTypeMeta(fory.binaryReader);
           const ns = typeMeta.getNs();
           const typeName = typeMeta.getTypeName();
           const named = `${ns}$${typeName}`;
-          serializer = fory.typeResolver.getSerializerByName(named);
-          if (!serializer) {
-            throw new Error(`can't find implements of typeId: ${typeId}`);
-          }
-          const hash = serializer.getHash();
-          if (hash !== typeMeta.getHash()) {
-            serializer = 
fory.typeMetaResolver.genSerializerByTypeMetaRuntime(typeMeta);
-          }
+          serializer = 
tryUpdateSerializer(fory.typeResolver.getSerializerByName(named), typeMeta);
         } else {
           const ns = fory.metaStringResolver.readNamespace(fory.binaryReader);
           const typeName = 
fory.metaStringResolver.readTypeName(fory.binaryReader);
diff --git a/javascript/packages/fory/lib/gen/collection.ts 
b/javascript/packages/fory/lib/gen/collection.ts
index 74c18946b..2d7941bfa 100644
--- a/javascript/packages/fory/lib/gen/collection.ts
+++ b/javascript/packages/fory/lib/gen/collection.ts
@@ -53,8 +53,9 @@ class CollectionAnySerializer {
     let trackingRef = false;
 
     for (const item of arr) {
-      if ((item === undefined || item === null) && !includeNone) {
+      if ((item === undefined || item === null)) {
         includeNone = true;
+        continue;
       }
       const current = this.fory.typeResolver.getSerializerByData(item);
       if (!current) {
@@ -105,9 +106,9 @@ class CollectionAnySerializer {
       } else if (includeNone) {
         for (const item of value) {
           if (item === null || item === undefined) {
-            this.fory.binaryWriter.uint8(RefFlags.NullFlag);
+            this.fory.binaryWriter.int8(RefFlags.NullFlag);
           } else {
-            this.fory.binaryWriter.uint8(RefFlags.NotNullValueFlag);
+            this.fory.binaryWriter.int8(RefFlags.NotNullValueFlag);
             serializer!.write(item);
           }
         }
@@ -125,10 +126,10 @@ class CollectionAnySerializer {
       } else if (includeNone) {
         for (const item of value) {
           if (item === null || item === undefined) {
-            this.fory.binaryWriter.uint8(RefFlags.NullFlag);
+            this.fory.binaryWriter.int8(RefFlags.NullFlag);
           } else {
             const serializer = 
this.fory.typeResolver.getSerializerByData(item);
-            this.fory.binaryWriter.uint8(RefFlags.NotNullValueFlag);
+            this.fory.binaryWriter.int8(RefFlags.NotNullValueFlag);
             serializer!.write(item);
           }
         }
@@ -166,7 +167,7 @@ class CollectionAnySerializer {
         }
       } else if (includeNone) {
         for (let i = 0; i < len; i++) {
-          const flag = this.fory.binaryReader.uint8();
+          const flag = this.fory.binaryReader.int8();
           if (flag === RefFlags.NullFlag) {
             accessor(result, i, null);
           } else {
@@ -186,7 +187,7 @@ class CollectionAnySerializer {
         }
       } else if (includeNone) {
         for (let i = 0; i < len; i++) {
-          const flag = this.fory.binaryReader.uint8();
+          const flag = this.fory.binaryReader.int8();
           if (flag === RefFlags.NullFlag) {
             accessor(result, i, null);
           } else {
@@ -317,7 +318,7 @@ export abstract class CollectionSerializerGenerator extends 
BaseSerializerGenera
                 }
             } else if (${flags} & ${CollectionFlags.HAS_NULL}) {
                 for (let ${idx} = 0; ${idx} < ${len}; ${idx}++) {
-                    if (${this.builder.reader.uint8()} == 
${RefFlags.NullFlag}) {
+                    if (${this.builder.reader.int8()} == ${RefFlags.NullFlag}) 
{
                         ${this.putAccessor(result, "null", idx)}
                     } else {
                         ${this.innerGenerator.read(x => 
`${this.putAccessor(result, x, idx)}`, "false")}
diff --git a/javascript/packages/fory/lib/gen/map.ts 
b/javascript/packages/fory/lib/gen/map.ts
index 7cb32e130..89066af8d 100644
--- a/javascript/packages/fory/lib/gen/map.ts
+++ b/javascript/packages/fory/lib/gen/map.ts
@@ -305,7 +305,6 @@ export class MapSerializerGenerator extends 
BaseSerializerGenerator {
             ${chunkSize} = 0;
           }
           ${chunkSizeOffset} = ${this.builder.writer.getCursor()}
-          debugger;
           ${this.builder.writer.uint16(
               `((${valueHeader} | (valueIsNull ? ${MapFlags.HAS_NULL} : 0)) << 
3) | (${keyHeader} | (keyIsNull ? ${MapFlags.HAS_NULL} : 0))`
             )
@@ -371,7 +370,6 @@ export class MapSerializerGenerator extends 
BaseSerializerGenerator {
 
     return `
       let ${count} = ${this.builder.reader.readVarUint32Small7()};
-      debugger;
       const ${result} = new Map();
       if (${refState}) {
         ${this.builder.referenceResolver.reference(result)}
diff --git a/javascript/packages/fory/lib/gen/number.ts 
b/javascript/packages/fory/lib/gen/number.ts
index a477c3d16..a33033975 100644
--- a/javascript/packages/fory/lib/gen/number.ts
+++ b/javascript/packages/fory/lib/gen/number.ts
@@ -155,3 +155,10 @@ CodegenRegistry.register(TypeId.TAGGED_UINT64,
     builder => builder.reader.varUInt64()
   )
 );
+
+CodegenRegistry.register(TypeId.VARINT64,
+  buildNumberSerializer(
+    (builder, accessor) => builder.writer.varUInt64(accessor),
+    builder => builder.reader.varUInt64()
+  )
+);
diff --git a/javascript/packages/fory/lib/meta/TypeMeta.ts 
b/javascript/packages/fory/lib/meta/TypeMeta.ts
index 649afc57e..985710c6f 100644
--- a/javascript/packages/fory/lib/meta/TypeMeta.ts
+++ b/javascript/packages/fory/lib/meta/TypeMeta.ts
@@ -228,6 +228,7 @@ export class TypeMeta {
   }
 
   static fromTypeInfo(typeInfo: StructTypeInfo) {
+    const structTypeInfo = typeInfo;
     let fieldInfo = Object.entries(typeInfo.options.props!).map(([fieldName, 
typeInfo]) => {
       let fieldTypeId = typeInfo.typeId;
       if (fieldTypeId === TypeId.NAMED_ENUM) {
@@ -235,12 +236,13 @@ export class TypeMeta {
       } else if (fieldTypeId === TypeId.NAMED_UNION || fieldTypeId === 
TypeId.TYPED_UNION) {
         fieldTypeId = TypeId.UNION;
       }
+      const { trackingRef, nullable } = 
structTypeInfo.options.fieldInfo?.[fieldName] || {};
       return new FieldInfo(
         fieldName,
         fieldTypeId,
-        -1,
-        false,
-        false,
+        typeInfo.userTypeId,
+        trackingRef,
+        nullable,
         typeInfo.options,
       );
     });
diff --git a/javascript/packages/fory/lib/typeInfo.ts 
b/javascript/packages/fory/lib/typeInfo.ts
index a4dd7e151..9a1b519cb 100644
--- a/javascript/packages/fory/lib/typeInfo.ts
+++ b/javascript/packages/fory/lib/typeInfo.ts
@@ -384,6 +384,8 @@ export type HintInput<T> = T extends {
     | typeof TypeId.UINT8
     | typeof TypeId.UINT16
     | typeof TypeId.UINT32
+    | typeof TypeId.UINT64
+    | typeof TypeId.VAR_UINT64
     | typeof TypeId.VAR_UINT32
     | typeof TypeId.FLOAT8
     | typeof TypeId.FLOAT16
@@ -657,6 +659,11 @@ export const Type = {
       (TypeId.VAR_UINT64),
     );
   },
+  varInt64() {
+    return TypeInfo.fromNonParam<typeof TypeId.VARINT64>(
+      (TypeId.VARINT64),
+    );
+  },
   taggedUInt64() {
     return TypeInfo.fromNonParam<typeof TypeId.TAGGED_UINT64>(
       (TypeId.TAGGED_UINT64),
diff --git a/javascript/packages/fory/lib/typeResolver.ts 
b/javascript/packages/fory/lib/typeResolver.ts
index e7af28b48..f4c5f5423 100644
--- a/javascript/packages/fory/lib/typeResolver.ts
+++ b/javascript/packages/fory/lib/typeResolver.ts
@@ -17,7 +17,7 @@
  * under the License.
  */
 
-import { ForyTypeInfoSymbol, WithForyClsInfo, Serializer, TypeId } from 
"./type";
+import { ForyTypeInfoSymbol, WithForyClsInfo, Serializer, TypeId, MaxInt32, 
MinInt32 } from "./type";
 import { Gen } from "./gen";
 import { Type, TypeInfo } from "./typeInfo";
 import Fory from "./fory";
@@ -91,6 +91,8 @@ export default class TypeResolver {
     registerSerializer(Type.int16());
     registerSerializer(Type.int32());
     registerSerializer(Type.varInt32());
+    registerSerializer(Type.varUInt64());
+    registerSerializer(Type.varInt64());
     registerSerializer(Type.int64());
     registerSerializer(Type.sliInt64());
     registerSerializer(Type.float16());
@@ -109,7 +111,10 @@ export default class TypeResolver {
     registerSerializer(Type.float32Array());
     registerSerializer(Type.float64Array());
 
-    this.numberSerializer = this.getSerializerById(TypeId.FLOAT64);
+    this.float64Serializer = this.getSerializerById(TypeId.FLOAT64);
+    this.float32Serializer = this.getSerializerById(TypeId.FLOAT32);
+    this.varint32Serializer = this.getSerializerById(TypeId.VARINT32);
+    this.taggedint64Serializer = this.getSerializerById(TypeId.TAGGED_INT64);
     this.int64Serializer = this.getSerializerById((TypeId.INT64));
     this.boolSerializer = this.getSerializerById((TypeId.BOOL));
     this.dateSerializer = this.getSerializerById((TypeId.TIMESTAMP));
@@ -127,7 +132,10 @@ export default class TypeResolver {
     this.int64ArraySerializer = this.getSerializerById(TypeId.INT64_ARRAY);
   }
 
-  private numberSerializer: null | Serializer = null;
+  private float64Serializer: null | Serializer = null;
+  private float32Serializer: null | Serializer = null;
+  private varint32Serializer: null | Serializer = null;
+  private taggedint64Serializer: null | Serializer = null;
   private int64Serializer: null | Serializer = null;
   private boolSerializer: null | Serializer = null;
   private dateSerializer: null | Serializer = null;
@@ -240,7 +248,20 @@ export default class TypeResolver {
   getSerializerByData(v: any) {
     // internal types
     if (typeof v === "number") {
-      return this.numberSerializer;
+      if (Number.isInteger(v)) {
+        if (v > MaxInt32 || v < MinInt32) {
+          return this.taggedint64Serializer;
+        }
+        return this.varint32Serializer;
+      }
+      if (v > MaxInt32 || v < MinInt32) {
+        return this.float64Serializer;
+      }
+      return this.float32Serializer;
+    }
+
+    if (typeof v === "bigint") {
+      return this.taggedint64Serializer;
     }
 
     if (typeof v === "string") {
diff --git a/javascript/test/any.test.ts b/javascript/test/any.test.ts
index 135363fbd..d27f4f7a2 100644
--- a/javascript/test/any.test.ts
+++ b/javascript/test/any.test.ts
@@ -47,7 +47,7 @@ describe('bool', () => {
     test('should write big number work', () => {
         const fory = new Fory();
         const bin = fory.serialize(3000000000);
-        expect(fory.deserialize(bin)).toBe(3000000000);
+        expect(fory.deserialize(bin)).toBe(3000000000n);
     });
 
     test('should write INFINITY work', () => {
@@ -59,7 +59,7 @@ describe('bool', () => {
     test('should write float work', () => {
         const fory = new Fory();
         const bin = fory.serialize(123.123);
-        expect(fory.deserialize(bin)).toBe(123.123)
+        expect(fory.deserialize(bin).toFixed(3)).toBe("123.123")
     });
 
     test('should write bigint work', () => {
diff --git a/javascript/test/crossLanguage.test.ts 
b/javascript/test/crossLanguage.test.ts
index 71601ab88..bc1e8aa67 100644
--- a/javascript/test/crossLanguage.test.ts
+++ b/javascript/test/crossLanguage.test.ts
@@ -218,29 +218,25 @@ describe("bool", () => {
     writeToFile(writer.dump() as Buffer);
   });
   test("test_string_serializer", () => {
-    const fory = new Fory();
-    const reader = new BinaryReader({});
-    reader.reset(content);
-
+    const fory = new Fory({
+      mode: Mode.Compatible
+    });
     // Deserialize strings from Java
     const deserializedStrings = [];
     let cursor = 0;
     for (let i = 0; i < 7; i++) { // 7 test strings
-      const deserializedString = fory.deserialize(content.slice(cursor));
+      const deserializedString = fory.deserialize(content.subarray(cursor));
       cursor += fory.binaryReader.getCursor();
       deserializedStrings.push(deserializedString);
     }
-
-    const writer = new BinaryWriter();
-    writer.reserve(1024);
-
+    const bfs = []
     // Serialize each deserialized string back
     for (const testString of deserializedStrings) {
       const serializedData = fory.serialize(testString);
-      writer.buffer(serializedData);
+      bfs.push(serializedData);
     }
 
-    writeToFile(writer.dump() as Buffer);
+    writeToFile(Buffer.concat(bfs));
   });
   test("test_cross_language_serializer", () => {
     if (Boolean("1")) { return; }
@@ -306,10 +302,12 @@ describe("bool", () => {
 
     // Define SimpleStruct class with field type registration
     @Type.struct(103, {
+      f1: Type.map(Type.varInt32(), Type.float64()),
       f2: Type.varInt32(),
       f3: Type.struct(102),
       f4: Type.string(),
       f5: Type.enum(101, Color),
+      f6: Type.array(Type.string()),
       f7: Type.varInt32(),
       f8: Type.varInt32(),
       last: Type.varInt32()
@@ -319,6 +317,8 @@ describe("bool", () => {
       f3: Item | null = null;
       f4: string = "";
       f5: number = 0; // Color enum value
+      f1 = new Map([[1, 1.0], [2, 2.0]])
+      f6 = ["f6"]
       f7: number = 0;
       f8: number = 0;
       last: number = 0;
@@ -334,15 +334,13 @@ describe("bool", () => {
     // Serialize the deserialized object back
     const serializedData = fory.serialize(deserializedObj);
 
-    const deserializedObj2 = fory.deserialize(serializedData);
-
-    console.log('===')
-    // writeToFile(serializedData as Buffer);
+    writeToFile(serializedData as Buffer);
   });
   test("test_named_simple_struct", () => {
-    if (Boolean("1")) { return; }
     // Same as test_simple_struct but with named registration
-    const fory = new Fory();
+    const fory = new Fory({
+      mode: Mode.Compatible
+    });
 
     // Define Color enum
     const Color = {
@@ -364,15 +362,15 @@ describe("bool", () => {
 
     // Define SimpleStruct class with field type registration
     @Type.struct({ namespace: "demo", typeName: "simple_struct" }, {
-      f1: Type.map(Type.int32(), Type.float64()),
-      f2: Type.int32(),
+      f1: Type.map(Type.varInt32(), Type.float64()),
+      f2: Type.varInt32(),
       f3: Type.struct({ namespace: "demo", typeName: "item" }),
       f4: Type.string(),
       f5: Type.enum({ namespace: 'demo', typeName: "color" }, Color),
       f6: Type.array(Type.string()),
-      f7: Type.int32(),
-      f8: Type.int32(),
-      last: Type.int32()
+      f7: Type.varInt32(),
+      f8: Type.varInt32(),
+      last: Type.varInt32()
     })
     class SimpleStruct {
       f1: Map<number, number> = new Map();
@@ -387,20 +385,17 @@ describe("bool", () => {
     }
     fory.registerSerializer(SimpleStruct);
 
-    const reader = new BinaryReader({});
-    reader.reset(content);
-
     // Deserialize the object from Java
-    const deserializedObj = 
fory.deserialize(reader.buffer(reader.varUInt32()));
-
+    const deserializedObj = fory.deserialize(content);
     // Serialize the deserialized object back
     const serializedData = fory.serialize(deserializedObj);
     writeToFile(serializedData as Buffer);
   });
 
   test("test_list", () => {
-    if (Boolean("1")) { return; }
-    const fory = new Fory();
+    const fory = new Fory({
+      mode: Mode.Compatible
+    });
 
     @Type.struct(102, {
       name: Type.string()
@@ -410,26 +405,24 @@ describe("bool", () => {
     }
     fory.registerSerializer(Item);
 
-    const reader = new BinaryReader({});
-    reader.reset(content);
 
     // Deserialize all lists from Java
     const deserializedLists = [];
+    let cursor = 0;
     for (let i = 0; i < 4; i++) { // 4 lists
-      const deserializedList = 
fory.deserialize(reader.buffer(reader.varUInt32()));
+      const deserializedList = fory.deserialize(content.subarray(cursor));
+      cursor += fory.binaryReader.getCursor();
       deserializedLists.push(deserializedList);
     }
 
-    const writer = new BinaryWriter();
-    writer.reserve(512);
+    const bfs = [];
 
     // Serialize each deserialized list back
     for (const list of deserializedLists) {
       const serializedData = fory.serialize(list);
-      writer.buffer(serializedData);
+      bfs.push(serializedData)
     }
-
-    writeToFile(writer.dump() as Buffer);
+    writeToFile(Buffer.concat(bfs));
   });
 
   test("test_map", () => {
@@ -468,16 +461,17 @@ describe("bool", () => {
   });
 
   test("test_integer", () => {
-    if (Boolean("1")) { return; }
-    const fory = new Fory();
+    const fory = new Fory({
+      mode: Mode.Compatible
+    });
 
     @Type.struct(101, {
-      f1: Type.int32(),
-      f2: Type.int32(),
-      f3: Type.int32(),
-      f4: Type.int32(),
-      f5: Type.int32(),
-      f6: Type.int32()
+      f1: Type.varInt32(),
+      f2: Type.varInt32(),
+      f3: Type.varInt32(),
+      f4: Type.varInt32(),
+      f5: Type.varInt32(),
+      f6: Type.varInt32()
     })
     class Item1 {
       f1: number = 0;
@@ -490,26 +484,24 @@ describe("bool", () => {
 
     fory.registerSerializer(Item1);
 
-    const reader = new BinaryReader({});
-    reader.reset(content);
 
     // Deserialize item and individual integers from Java
     const deserializedData = [];
+    let cursor = 0;
     for (let i = 0; i < 7; i++) { // 1 item + 6 integers
-      const deserializedItem = 
fory.deserialize(reader.buffer(reader.varUInt32()));
+      const deserializedItem = fory.deserialize(content.subarray(cursor));
+      cursor += fory.binaryReader.getCursor();
       deserializedData.push(deserializedItem);
     }
 
-    const writer = new BinaryWriter();
-    writer.reserve(256);
-
+    const bfs = []
     // Serialize each deserialized item back
     for (const item of deserializedData) {
       const serializedData = fory.serialize(item);
-      writer.buffer(serializedData);
+      bfs.push(serializedData);
     }
 
-    writeToFile(writer.dump() as Buffer);
+    writeToFile(Buffer.concat(bfs));
   });
 
   test("test_item", () => {


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to