This is an automated email from the ASF dual-hosted git repository.
wangweipeng pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/fury.git
The following commit(s) were added to refs/heads/main by this push:
new 0fe042af feat(javascript): simplify the definition of object type
description (#2058)
0fe042af is described below
commit 0fe042af1fe59ab5e225ae8ecc15a6719ac3b2e8
Author: weipeng <[email protected]>
AuthorDate: Fri Feb 14 21:39:28 2025 +0800
feat(javascript): simplify the definition of object type description (#2058)
## What does this PR do?
It is hard to describe the type of a object, we should write some code
like this:
```JavaScript
Type.object("example.foo", {
a: Type.string()
})
```
The `Type.xxx` APIs are very flexible but not easy to use.
This PR add improve these APIS to help simplifing the type definition.
Now we can definition object type like this:
```JavaScript
@Type.object("example.foo")
class Foo {
@Type.int32()
a: number;
}
const fury = new Fury({ refTracking: true });
const { serialize, deserialize } = fury.registerSerializer(Foo);
const foo = new Foo();
foo.a = 123;
const input = serialize(foo);
const result = deserialize(
input
);
expect(result instanceof Foo);
expect(result).toEqual({ a: 123 })
```
The result of `Type.xxx()` serves both as a decorator function and as a
description object. It is totally compatible with
`Type.object("example.foo", {
a: Type.string()
})`
Note that decoration APIs can not detect the type of a anonymous object.
providing anonymous object like `{a: 123}` still will cause error.
---
javascript/jest.config.js | 3 +-
javascript/packages/fury/lib/classResolver.ts | 33 +++--
javascript/packages/fury/lib/description.ts | 178 ++++++++++++++++---------
javascript/packages/fury/lib/fury.ts | 37 ++++-
javascript/packages/fury/lib/gen/any.ts | 4 +-
javascript/packages/fury/lib/gen/builder.ts | 4 +
javascript/packages/fury/lib/gen/index.ts | 10 +-
javascript/packages/fury/lib/gen/object.ts | 19 ++-
javascript/packages/fury/lib/gen/router.ts | 8 +-
javascript/packages/fury/lib/gen/serializer.ts | 5 +-
javascript/packages/fury/lib/type.ts | 8 ++
javascript/packages/fury/tsconfig.json | 2 +-
javascript/test/object.test.ts | 37 +++++
13 files changed, 254 insertions(+), 94 deletions(-)
diff --git a/javascript/jest.config.js b/javascript/jest.config.js
index 363bdd2b..9db8b752 100644
--- a/javascript/jest.config.js
+++ b/javascript/jest.config.js
@@ -32,7 +32,8 @@ module.exports = {
transform: {
'\\.ts$': ['ts-jest', {
tsconfig: {
- target: "ES2021"
+ target: "ES2021",
+ experimentalDecorators: true
},
diagnostics: {
ignoreCodes: [151001]
diff --git a/javascript/packages/fury/lib/classResolver.ts
b/javascript/packages/fury/lib/classResolver.ts
index 27dbbc64..600f5eec 100644
--- a/javascript/packages/fury/lib/classResolver.ts
+++ b/javascript/packages/fury/lib/classResolver.ts
@@ -17,7 +17,7 @@
* under the License.
*/
-import { InternalSerializerType, Serializer } from "./type";
+import { FuryClsInfoSymbol, InternalSerializerType, ObjectFuryClsInfo,
Serializer } from "./type";
import { fromString } from "./platformBuffer";
import { x64hash128 } from "./murmurHash3";
import { BinaryWriter } from "./writer";
@@ -78,9 +78,7 @@ const uninitSerialize = {
export default class SerializerResolver {
private internalSerializer: Serializer[] = new Array(300);
- private customSerializer: { [key: string]: Serializer } = {
- };
-
+ private customSerializer: Map<string | (new () => any), Serializer> = new
Map();
private readStringPool: LazyString[] = [];
private writeStringCount = 0;
private writeStringIndex: number[] = [];
@@ -161,17 +159,25 @@ export default class SerializerResolver {
return this.internalSerializer[id];
}
- registerSerializerByTag(tag: string, serializer: Serializer =
uninitSerialize) {
- if (this.customSerializer[tag]) {
- Object.assign(this.customSerializer[tag], serializer);
+ private registerCustomSerializer(tagOrConstructor: string | (new () => any),
serializer: Serializer = uninitSerialize) {
+ if (this.customSerializer.has(tagOrConstructor)) {
+ Object.assign(this.customSerializer.get(tagOrConstructor)!, serializer);
} else {
- this.customSerializer[tag] = { ...serializer };
+ this.customSerializer.set(tagOrConstructor, { ...serializer });
}
- return this.customSerializer[tag];
+ return this.customSerializer.get(tagOrConstructor);
+ }
+
+ registerSerializerByTag(tag: string, serializer: Serializer =
uninitSerialize) {
+ this.registerCustomSerializer(tag, serializer);
+ }
+
+ registerSerializerByConstructor(constructor: new () => any, serializer:
Serializer = uninitSerialize) {
+ this.registerCustomSerializer(constructor, serializer);
}
getSerializerByTag(tag: string) {
- return this.customSerializer[tag];
+ return this.customSerializer.get(tag)!;
}
static tagBuffer(tag: string) {
@@ -232,6 +238,7 @@ export default class SerializerResolver {
}
getSerializerByData(v: any) {
+ // internal types
if (typeof v === "number") {
return this.numberSerializer;
}
@@ -263,6 +270,12 @@ export default class SerializerResolver {
if (v instanceof Set) {
return this.setSerializer;
}
+
+ // custome types
+ if (typeof v === "object" && v !== null && FuryClsInfoSymbol in v) {
+ return this.customSerializer.get((v[FuryClsInfoSymbol] as
ObjectFuryClsInfo).constructor)!;
+ }
+
throw new Error(`Failed to detect the Fury type from JavaScript type:
${typeof v}`);
}
diff --git a/javascript/packages/fury/lib/description.ts
b/javascript/packages/fury/lib/description.ts
index de837bad..78d0b276 100644
--- a/javascript/packages/fury/lib/description.ts
+++ b/javascript/packages/fury/lib/description.ts
@@ -17,7 +17,7 @@
* under the License.
*/
-import { InternalSerializerType } from "./type";
+import { FuryClsInfoSymbol, InternalSerializerType, ObjectFuryClsInfo } from
"./type";
export interface TypeDescription {
type: InternalSerializerType;
@@ -28,6 +28,7 @@ export interface ObjectTypeDescription extends
TypeDescription {
options: {
props: { [key: string]: TypeDescription };
tag: string;
+ withConstructor?: false;
};
}
@@ -274,181 +275,234 @@ export type ResultType<T> = T extends {
type: InternalSerializerType.ONEOF;
} ? OneofResult<T> : unknown;
+type DecorationWithDescription<T> = ((target: any, key?: string | { name?:
string }) => void) & T;
+
+const makeDescriptionWithDecoration = <T extends TypeDescription>(description:
T): DecorationWithDescription<T> => {
+ function decoration(target: any, key?: string | { name?: string }) {
+ if (key === undefined) {
+ initMeta(target, description as unknown as ObjectTypeDescription);
+ } else {
+ const keyString = typeof key === "string" ? key : key?.name;
+ if (!keyString) {
+ throw new Error("Decorators can only be placed on classes and fields");
+ }
+ addField(target.constructor, keyString, description);
+ }
+ }
+ decoration.toJSON = function () {
+ return JSON.stringify(description);
+ };
+ Object.entries(description).map(([key, value]: any) => {
+ Object.defineProperty(decoration, key, {
+ enumerable: true,
+ get() {
+ return value;
+ },
+ });
+ });
+ return decoration as unknown as DecorationWithDescription<T>;
+};
+
export const Type = {
any() {
- return {
+ return makeDescriptionWithDecoration({
type: InternalSerializerType.ANY as const,
- };
+ });
},
enum<T1 extends { [key: string]: any }>(t1: T1) {
- return {
+ return makeDescriptionWithDecoration({
type: InternalSerializerType.ENUM as const,
options: {
inner: t1,
},
- };
+ });
},
oneof<T extends { [key: string]: TypeDescription }>(inner?: T) {
- return {
+ return makeDescriptionWithDecoration({
type: InternalSerializerType.ONEOF as const,
options: {
inner,
},
- };
+ });
},
string() {
- return {
+ return makeDescriptionWithDecoration({
type: InternalSerializerType.STRING as const,
- };
+ });
},
array<T extends TypeDescription>(def: T) {
- return {
+ return makeDescriptionWithDecoration({
type: InternalSerializerType.ARRAY as const,
options: {
inner: def,
},
- };
+ });
},
tuple<T1 extends readonly [...readonly TypeDescription[]]>(t1: T1) {
- return {
+ return makeDescriptionWithDecoration({
type: InternalSerializerType.TUPLE as const,
options: {
inner: t1,
},
- };
+ });
},
map<T1 extends TypeDescription, T2 extends TypeDescription>(
key: T1,
value: T2
) {
- return {
+ return makeDescriptionWithDecoration({
type: InternalSerializerType.MAP as const,
options: {
key,
value,
},
- };
+ });
},
set<T extends TypeDescription>(key: T) {
- return {
+ return makeDescriptionWithDecoration({
type: InternalSerializerType.SET as const,
options: {
key,
},
- };
+ });
},
bool() {
- return {
+ return makeDescriptionWithDecoration({
type: InternalSerializerType.BOOL as const,
- };
+ });
},
- object<T extends { [key: string]: TypeDescription }>(tag: string, props?: T)
{
- return {
+ object<T extends { [key: string]: TypeDescription }>(tag: string, props?: T,
withConstructor = false) {
+ return makeDescriptionWithDecoration({
type: InternalSerializerType.OBJECT as const,
options: {
tag,
props,
+ withConstructor,
},
- };
+ });
},
int8() {
- return {
+ return makeDescriptionWithDecoration({
type: InternalSerializerType.INT8 as const,
- };
+ });
},
int16() {
- return {
+ return makeDescriptionWithDecoration({
type: InternalSerializerType.INT16 as const,
- };
+ });
},
int32() {
- return {
+ return makeDescriptionWithDecoration({
type: InternalSerializerType.INT32 as const,
- };
+ });
},
varInt32() {
- return {
+ return makeDescriptionWithDecoration({
type: InternalSerializerType.VAR_INT32 as const,
- };
+ });
},
int64() {
- return {
+ return makeDescriptionWithDecoration({
type: InternalSerializerType.INT64 as const,
- };
+ });
},
sliInt64() {
- return {
+ return makeDescriptionWithDecoration({
type: InternalSerializerType.SLI_INT64 as const,
- };
+ });
},
float16() {
- return {
+ return makeDescriptionWithDecoration({
type: InternalSerializerType.FLOAT16 as const,
- };
+ });
},
float32() {
- return {
+ return makeDescriptionWithDecoration({
type: InternalSerializerType.FLOAT32 as const,
- };
+ });
},
float64() {
- return {
+ return makeDescriptionWithDecoration({
type: InternalSerializerType.FLOAT64 as const,
- };
+ });
},
binary() {
- return {
+ return makeDescriptionWithDecoration({
type: InternalSerializerType.BINARY as const,
- };
+ });
},
duration() {
- return {
+ return makeDescriptionWithDecoration({
type: InternalSerializerType.DURATION as const,
- };
+ });
},
timestamp() {
- return {
+ return makeDescriptionWithDecoration({
type: InternalSerializerType.TIMESTAMP as const,
- };
+ });
},
boolArray() {
- return {
+ return makeDescriptionWithDecoration({
type: InternalSerializerType.BOOL_ARRAY as const,
- };
+ });
},
int8Array() {
- return {
+ return makeDescriptionWithDecoration({
type: InternalSerializerType.INT8_ARRAY as const,
- };
+ });
},
int16Array() {
- return {
+ return makeDescriptionWithDecoration({
type: InternalSerializerType.INT16_ARRAY as const,
- };
+ });
},
int32Array() {
- return {
+ return makeDescriptionWithDecoration({
type: InternalSerializerType.INT32_ARRAY as const,
- };
+ });
},
int64Array() {
- return {
+ return makeDescriptionWithDecoration({
type: InternalSerializerType.INT64_ARRAY as const,
- };
+ });
},
float16Array() {
- return {
+ return makeDescriptionWithDecoration({
type: InternalSerializerType.FLOAT16_ARRAY as const,
- };
+ });
},
float32Array() {
- return {
+ return makeDescriptionWithDecoration({
type: InternalSerializerType.FLOAT32_ARRAY as const,
- };
+ });
},
float64Array() {
- return {
+ return makeDescriptionWithDecoration({
type: InternalSerializerType.FLOAT64_ARRAY as const,
- };
+ });
},
};
+
+const initMeta = (target: new () => any, description: ObjectTypeDescription)
=> {
+ if (!target.prototype) {
+ target.prototype = {};
+ }
+ target.prototype[FuryClsInfoSymbol] = {
+ toObjectDescription() {
+ if (targetFields.has(target)) {
+ return Type.object(description.options.tag, targetFields.get(target),
true);
+ }
+ return Type.object(description.options.tag, {}, true);
+ },
+ constructor: target,
+ } as ObjectFuryClsInfo;
+};
+
+const targetFields = new WeakMap<new () => any, { [key: string]:
TypeDescription }>();
+
+const addField = (target: new () => any, key: string, des: TypeDescription) =>
{
+ if (!targetFields.has(target)) {
+ targetFields.set(target, {});
+ }
+ targetFields.get(target)![key] = des;
+};
diff --git a/javascript/packages/fury/lib/fury.ts
b/javascript/packages/fury/lib/fury.ts
index d4400f7f..910d8006 100644
--- a/javascript/packages/fury/lib/fury.ts
+++ b/javascript/packages/fury/lib/fury.ts
@@ -21,11 +21,12 @@ import ClassResolver from "./classResolver";
import { BinaryWriter } from "./writer";
import { BinaryReader } from "./reader";
import { ReferenceResolver } from "./referenceResolver";
-import { ConfigFlags, Serializer, Config, Language, MAGIC_NUMBER, Mode } from
"./type";
+import { ConfigFlags, Serializer, Config, Language, MAGIC_NUMBER, Mode,
FuryClsInfoSymbol } from "./type";
import { OwnershipError } from "./error";
import { InputType, ResultType, TypeDescription } from "./description";
import { generateSerializer, AnySerializer } from "./gen";
import { TypeMeta } from "./meta/TypeMeta";
+import { PlatformBuffer } from "./platformBuffer";
export default class {
binaryReader: BinaryReader;
@@ -49,18 +50,42 @@ export default class {
this.anySerializer = new AnySerializer(this);
}
- registerSerializer<T extends TypeDescription>(description: T) {
- const serializer = generateSerializer(this, description);
+ registerSerializer<T extends new () => any>(description: T): {
+ serializer: Serializer;
+ serialize(data: Partial<InstanceType<T>> | null): PlatformBuffer;
+ serializeVolatile(data: Partial<InstanceType<T>>): {
+ get: () => Uint8Array;
+ dispose: () => void;
+ };
+ deserialize(bytes: Uint8Array): InstanceType<T> | null;
+ };
+ registerSerializer<T extends TypeDescription>(description: T): {
+ serializer: Serializer;
+ serialize(data: InputType<T> | null): PlatformBuffer;
+ serializeVolatile(data: InputType<T>): {
+ get: () => Uint8Array;
+ dispose: () => void;
+ };
+ deserialize(bytes: Uint8Array): ResultType<T>;
+ };
+ registerSerializer(description: any) {
+ let serializer: Serializer;
+ if (description.prototype?.[FuryClsInfoSymbol]) {
+ serializer = generateSerializer(this,
description.prototype[FuryClsInfoSymbol].toObjectDescription(), { constructor:
description });
+ this.classResolver.registerSerializerByConstructor(description,
serializer);
+ } else {
+ serializer = generateSerializer(this, description);
+ }
return {
serializer,
- serialize: (data: InputType<T>) => {
+ serialize: (data: any) => {
return this.serialize(data, serializer);
},
- serializeVolatile: (data: InputType<T>) => {
+ serializeVolatile: (data: any) => {
return this.serializeVolatile(data, serializer);
},
deserialize: (bytes: Uint8Array) => {
- return this.deserialize(bytes, serializer) as ResultType<T>;
+ return this.deserialize(bytes, serializer);
},
};
}
diff --git a/javascript/packages/fury/lib/gen/any.ts
b/javascript/packages/fury/lib/gen/any.ts
index cc3900fb..16846720 100644
--- a/javascript/packages/fury/lib/gen/any.ts
+++ b/javascript/packages/fury/lib/gen/any.ts
@@ -44,7 +44,7 @@ export class AnySerializer {
detectSerializer() {
const typeId = this.fury.binaryReader.int16();
- let serializer: Serializer;
+ let serializer: Serializer | undefined;
if (typeId ===
SerializerResolver.getTypeIdByInternalSerializerType(InternalSerializerType.OBJECT))
{
const tag = this.fury.classResolver.readTag(this.fury.binaryReader)();
serializer = this.fury.classResolver.getSerializerByTag(tag);
@@ -138,7 +138,7 @@ class AnySerializerGenerator extends
BaseSerializerGenerator {
};
`;
return `
- return function (fury, external) {
+ return function (fury, external, options) {
${this.scope.generate()}
${declare}
return {
diff --git a/javascript/packages/fury/lib/gen/builder.ts
b/javascript/packages/fury/lib/gen/builder.ts
index f78d5a3a..d5e5b7a2 100644
--- a/javascript/packages/fury/lib/gen/builder.ts
+++ b/javascript/packages/fury/lib/gen/builder.ts
@@ -383,4 +383,8 @@ export class CodecBuilder {
getExternal(key: string) {
return `external.${key}`;
}
+
+ getOptions(key: string) {
+ return `options.${key}`;
+ }
}
diff --git a/javascript/packages/fury/lib/gen/index.ts
b/javascript/packages/fury/lib/gen/index.ts
index ee449b75..827d1872 100644
--- a/javascript/packages/fury/lib/gen/index.ts
+++ b/javascript/packages/fury/lib/gen/index.ts
@@ -59,7 +59,7 @@ export const generate = (fury: Fury, description:
TypeDescription) => {
return new Function(funcString);
};
-function regDependencies(fury: Fury, description: TypeDescription) {
+function regDependencies(fury: Fury, description: TypeDescription, regOptions:
{ [key: string]: any } = {}) {
if (description.type === InternalSerializerType.OBJECT) {
const options = (<ObjectTypeDescription>description).options;
if (options.props) {
@@ -68,7 +68,7 @@ function regDependencies(fury: Fury, description:
TypeDescription) {
regDependencies(fury, x);
});
const func = generate(fury, description);
- fury.classResolver.registerSerializerByTag(options.tag, func()(fury,
external));
+ fury.classResolver.registerSerializerByTag(options.tag, func()(fury,
external, regOptions));
}
}
if (description.type === InternalSerializerType.ARRAY) {
@@ -96,11 +96,11 @@ function regDependencies(fury: Fury, description:
TypeDescription) {
}
}
-export const generateSerializer = (fury: Fury, description: TypeDescription)
=> {
- regDependencies(fury, description);
+export const generateSerializer = (fury: Fury, description: TypeDescription,
options: { [key: string]: any } = {}) => {
+ regDependencies(fury, description, options);
if (description.type === InternalSerializerType.OBJECT) {
return
fury.classResolver.getSerializerByTag((<ObjectTypeDescription>description).options.tag);
}
const func = generate(fury, description);
- return func()(fury, external);
+ return func()(fury, external, options);
};
diff --git a/javascript/packages/fury/lib/gen/object.ts
b/javascript/packages/fury/lib/gen/object.ts
index 3602b6d6..19077e77 100644
--- a/javascript/packages/fury/lib/gen/object.ts
+++ b/javascript/packages/fury/lib/gen/object.ts
@@ -106,11 +106,20 @@ class ObjectSerializerGenerator extends
BaseSerializerGenerator {
if (${this.builder.reader.int32()} !== ${expectHash}) {
throw new Error("got ${this.builder.reader.int32()} validate hash
failed: ${this.safeTag()}. expect ${expectHash}");
}
- const ${result} = {
- ${Object.entries(options.props).sort().map(([key]) => {
- return `${CodecBuilder.safePropName(key)}: null`;
- }).join(",\n")}
- };
+ ${
+ this.description.options.withConstructor
+? `
+ const ${result} = new ${this.builder.getOptions("constructor")}();
+ `
+: `
+ const ${result} = {
+ ${Object.entries(options.props).sort().map(([key]) => {
+ return `${CodecBuilder.safePropName(key)}: null`;
+ }).join(",\n")}
+ };
+ `
+ }
+
${this.maybeReference(result, refState)}
${
diff --git a/javascript/packages/fury/lib/gen/router.ts
b/javascript/packages/fury/lib/gen/router.ts
index 0260767c..caee36f3 100644
--- a/javascript/packages/fury/lib/gen/router.ts
+++ b/javascript/packages/fury/lib/gen/router.ts
@@ -29,12 +29,18 @@ export class CodegenRegistry {
static map = new Map<string, SerializerGeneratorConstructor>();
static external = new Map<string, any>();
+ private static checkExists(name: string) {
+ if (this.external.has(name)) {
+ throw new Error(`${name} has been registered.`);
+ }
+ }
+
static register(type: InternalSerializerType, generator:
SerializerGeneratorConstructor) {
this.map.set(InternalSerializerType[type], generator);
- this.external.set(generator.name, generator);
}
static registerExternal(object: { name: string }) {
+ CodegenRegistry.checkExists(object.name);
this.external.set(object.name, object);
}
diff --git a/javascript/packages/fury/lib/gen/serializer.ts
b/javascript/packages/fury/lib/gen/serializer.ts
index 3d8a067b..25a4478d 100644
--- a/javascript/packages/fury/lib/gen/serializer.ts
+++ b/javascript/packages/fury/lib/gen/serializer.ts
@@ -212,6 +212,9 @@ export abstract class BaseSerializerGenerator implements
SerializerGenerator {
this.scope.assertNameNotDuplicate("readInner");
this.scope.assertNameNotDuplicate("write");
this.scope.assertNameNotDuplicate("writeInner");
+ this.scope.assertNameNotDuplicate("fury");
+ this.scope.assertNameNotDuplicate("external");
+ this.scope.assertNameNotDuplicate("options");
const declare = `
const readInner = (fromRef) => {
@@ -228,7 +231,7 @@ export abstract class BaseSerializerGenerator implements
SerializerGenerator {
};
`;
return `
- return function (fury, external) {
+ return function (fury, external, options) {
${this.scope.generate()}
${declare}
return {
diff --git a/javascript/packages/fury/lib/type.ts
b/javascript/packages/fury/lib/type.ts
index 6c76e9c0..89072f00 100644
--- a/javascript/packages/fury/lib/type.ts
+++ b/javascript/packages/fury/lib/type.ts
@@ -17,6 +17,7 @@
* under the License.
*/
+import { ObjectTypeDescription } from "./description";
import { Meta } from "./meta";
export enum InternalSerializerType {
@@ -125,3 +126,10 @@ export enum Language {
}
export const MAGIC_NUMBER = 0x62D4;
+
+export interface ObjectFuryClsInfo {
+ constructor: new () => any;
+ toObjectDescription(): ObjectTypeDescription;
+}
+
+export const FuryClsInfoSymbol = Symbol("furyClsInfo");
diff --git a/javascript/packages/fury/tsconfig.json
b/javascript/packages/fury/tsconfig.json
index 176ef55b..87cefde9 100644
--- a/javascript/packages/fury/tsconfig.json
+++ b/javascript/packages/fury/tsconfig.json
@@ -3,7 +3,7 @@
"target": "ES2021", /* Set the JavaScript
language version for emitted JavaScript and include compatible library
declarations. */
// "lib": [], /* Specify a set of
bundled library declaration files that describe the target runtime environment.
*/
// "jsx": "preserve", /* Specify what JSX
code is generated. */
- // "experimentalDecorators": true, /* Enable
experimental support for TC39 stage 2 draft decorators. */
+ "experimentalDecorators": true, /* Enable experimental
support for TC39 stage 2 draft decorators. */
// "emitDecoratorMetadata": true, /* Emit design-type
metadata for decorated declarations in source files. */
// "jsxFactory": "", /* Specify the JSX
factory function used when targeting React JSX emit, e.g. 'React.createElement'
or 'h'. */
// "jsxFragmentFactory": "", /* Specify the JSX
Fragment reference used for fragments when targeting React JSX emit e.g.
'React.Fragment' or 'Fragment'. */
diff --git a/javascript/test/object.test.ts b/javascript/test/object.test.ts
index 79e1f7dc..3c1b4df0 100644
--- a/javascript/test/object.test.ts
+++ b/javascript/test/object.test.ts
@@ -21,6 +21,43 @@ import Fury, { TypeDescription, InternalSerializerType, Type
} from '../packages
import { describe, expect, test } from '@jest/globals';
describe('object', () => {
+ test('should descoration work', () => {
+ @Type.object("example.foo")
+ class Foo {
+ @Type.int32()
+ a: number;
+ }
+ const fury = new Fury({ refTracking: true });
+ const { serialize, deserialize } = fury.registerSerializer(Foo);
+ const foo = new Foo();
+ foo.a = 123;
+ const input = serialize(foo);
+ const result = deserialize(
+ input
+ );
+
+ expect(result instanceof Foo);
+
+ expect(result).toEqual({ a: 123 })
+ });
+
+ test('should descoration work2', () => {
+ @Type.object("example.foo")
+ class Foo {
+ @Type.int32()
+ a: number;
+ }
+ const fury = new Fury({ refTracking: true });
+ fury.registerSerializer(Foo);
+
+ const foo = new Foo();
+ foo.a = 123;
+ const input = fury.serialize(foo)
+ const result = fury.deserialize(input);
+ expect(result instanceof Foo);
+ expect(result).toEqual({ a: 123 })
+ });
+
test('should object work', () => {
const description = {
type: InternalSerializerType.OBJECT as const,
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]