Skip to content

Commit

Permalink
feat: add classNames
Browse files Browse the repository at this point in the history
  • Loading branch information
wan2land committed Apr 15, 2024
1 parent d0b8fb6 commit 0994f3e
Show file tree
Hide file tree
Showing 6 changed files with 101 additions and 10 deletions.
30 changes: 30 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,36 @@ const user = serializer.deserialize(serialized);
console.log(user); // TestUser { name: "wan2land", age: 20 }
```

#### Alias

If you want to serialize a class with a different name, you can use the
`classes` option.

```ts
class TestUser {
constructor(
public name?: string,
public age?: number,
) {
}
}

const serializer = new Serializer({
classes: {
AliasTestUser: TestUser,
},
});
```

```ts
const serialized = serializer.serialize(new TestUser("wan2land", 20));
console.log(serialized);
// AliasTestUser{"name":"wan2land","age":20} <--- AliasTestUser

const user = serializer.deserialize(serialized);
console.log(user); // TestUser { name: "wan2land", age: 20 }
```

#### toSerialize / toDeserialize

Private variables can be converted using two special symbols (`toSerialize`,
Expand Down
4 changes: 2 additions & 2 deletions deserialize.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { AstAny, AstRoot, parse } from "./parse.ts";
import { type AstAny, type AstRoot, parse } from "./parse.ts";
import { toDeserialize } from "./symbol.ts";
import { ConstructType } from "./types.ts";
import type { ConstructType } from "./types.ts";

export type ClassLoadHandler = (
name: string,
Expand Down
16 changes: 16 additions & 0 deletions serialize.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,22 @@ Deno.test("serialize class", () => {
);
});

Deno.test("serialize class with alias", () => {
class TestUser {
#_privateSomething = 1;
publicSomething = 2;
constructor(public name: string, public age: number) {
}
}

const user = new TestUser("wan2land", 20);

assertEquals(
serialize(user, { classNames: new Map([[TestUser, "AliasedTestUser"]]) }),
'AliasedTestUser{"name":"wan2land","age":20,"publicSomething":2}',
);
});

Deno.test("serialize class with private", () => {
class TestUser {
#_privateSomething = 1;
Expand Down
4 changes: 3 additions & 1 deletion serialize.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
// deno-lint-ignore-file no-explicit-any
import { toSerialize } from "./symbol.ts";
import type { ConstructType } from "./types.ts";

export interface SerializeOptions {
classNames?: Map<ConstructType<unknown>, string>;
prettify?: boolean;
}

Expand Down Expand Up @@ -127,7 +129,7 @@ export function serialize(value: any, options: SerializeOptions = {}): string {

const name = value.constructor && value.constructor !== Object &&
value.constructor !== Function
? value.constructor.name
? (options.classNames?.get(value.constructor) ?? value.constructor.name)
: "";

_stringifyListStart(prettify && name ? `${name} {` : `${name}{`);
Expand Down
25 changes: 25 additions & 0 deletions serializer.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,3 +54,28 @@ Deno.test("serializer, toSerialize, toDeserialize", () => {
assertEquals(user.getAge(), 20);
}
});

Deno.test("serializer, alias class names", () => {
class TestUser {
constructor(public name: string) {
}
}

const serializer = new Serializer({ classes: { AliasedTestUser: TestUser } });
{
const user = new TestUser("wan2land");

assertEquals(
serializer.serialize(user),
'AliasedTestUser{"name":"wan2land"}',
);
}
{
const user = serializer.deserialize<TestUser>(
'AliasedTestUser{"name":"wan2land"}',
);

assertInstanceOf(user, TestUser);
assertEquals(user.name, "wan2land");
}
});
32 changes: 25 additions & 7 deletions serializer.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,39 @@
import { serialize, SerializeOptions } from "./serialize.ts";
import { ClassLoadHandler, deserialize } from "./deserialize.ts";
import { ConstructType } from "./types.ts";
import {
type ClassLoadHandler,
deserialize,
type DeserializeOptions,
} from "./deserialize.ts";
import { serialize, type SerializeOptions } from "./serialize.ts";
import type { ConstructType } from "./types.ts";

export interface SerializerOptions {
classes?: { [className: string]: ConstructType<unknown> };
loadClass?: ClassLoadHandler;
}

export class Serializer {
#classNames?: Map<ConstructType<unknown>, string>;

constructor(public options?: SerializerOptions) {
}

serialize(value: unknown, options?: SerializeOptions): string {
return serialize(value, options);
serialize(value: unknown, options: SerializeOptions = {}): string {
return serialize(value, {
prettify: options.prettify,
classNames: options.classNames ?? (
this.#classNames ??= new Map(
Object.entries(this.options?.classes ?? {}).map((
[key, value],
) => [value, key]),
)
),
});
}

deserialize<T = unknown>(code: string): T {
return deserialize<T>(code, this.options);
deserialize<T = unknown>(code: string, options: DeserializeOptions = {}): T {
return deserialize<T>(code, {
classes: options?.classes ?? this.options?.classes,
loadClass: options?.loadClass ?? this.options?.loadClass,
});
}
}

0 comments on commit 0994f3e

Please sign in to comment.