Allow to serialize reference to a constructor in the namespace
This commit is contained in:
parent
9e0d1d623e
commit
95b3cf9fcc
10
README.md
10
README.md
|
@ -23,7 +23,15 @@ uncompressed.
|
|||
In deno:
|
||||
|
||||
```typescript
|
||||
import { Serializer } from "https://code.thunderk.net/typescript/serializer/raw/branch/master/mod.ts";
|
||||
import { Serializer } from "https://js.thunderk.net/serializer/mod.ts";
|
||||
```
|
||||
|
||||
In browser:
|
||||
|
||||
```html
|
||||
<script type="module">
|
||||
import { Serializer } from "https://js.thunderk.net/serializer/mod.js";
|
||||
</script>
|
||||
```
|
||||
|
||||
## Use
|
||||
|
|
10
doc/usage.md
10
doc/usage.md
|
@ -3,7 +3,15 @@
|
|||
In deno:
|
||||
|
||||
```typescript
|
||||
import { Serializer } from "https://code.thunderk.net/typescript/serializer/raw/branch/master/mod.ts";
|
||||
import { Serializer } from "https://js.thunderk.net/serializer/mod.ts";
|
||||
```
|
||||
|
||||
In browser:
|
||||
|
||||
```html
|
||||
<script type="module">
|
||||
import { Serializer } from "https://js.thunderk.net/serializer/mod.js";
|
||||
</script>
|
||||
```
|
||||
|
||||
## Use
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
import {
|
||||
describe,
|
||||
expect,
|
||||
it,
|
||||
mock,
|
||||
} from "https://code.thunderk.net/typescript/devtools/raw/1.2.2/testing.ts";
|
||||
} from "https://code.thunderk.net/typescript/devtools/raw/1.3.0/testing.ts";
|
||||
import { Serializer } from "./serializer.ts";
|
||||
|
||||
class TestSerializerObj1 {
|
||||
|
@ -62,6 +63,7 @@ function checkReversability(
|
|||
return loaded;
|
||||
}
|
||||
|
||||
describe(Serializer, () => {
|
||||
it("serializes simple objects", () => {
|
||||
var obj = {
|
||||
"a": 5,
|
||||
|
@ -97,6 +99,11 @@ it("restores objects constructed from class", () => {
|
|||
expect(loaded).toBeInstanceOf(TestSerializerObj1);
|
||||
});
|
||||
|
||||
it("serializes reference to class type", () => {
|
||||
let loaded = checkReversability(TestSerializerObj1);
|
||||
expect(loaded).toBe(TestSerializerObj1);
|
||||
});
|
||||
|
||||
it("stores one version of the same object", () => {
|
||||
var a = new TestSerializerObj1(8);
|
||||
var b = new TestSerializerObj1(8);
|
||||
|
@ -157,7 +164,7 @@ it("ignores functions", () => {
|
|||
let data = serializer.serialize({ obj: new TestSerializerObj2() });
|
||||
let loaded = serializer.unserialize(data);
|
||||
|
||||
let expected = <any> new TestSerializerObj2();
|
||||
let expected: any = new TestSerializerObj2();
|
||||
expected.a = undefined;
|
||||
expected.b[0] = undefined;
|
||||
expect(loaded).toEqual({ obj: expected });
|
||||
|
@ -204,3 +211,4 @@ it("uses namespace alias to protect from property mangling", () => {
|
|||
expect(serializer1.unserialize(dumped1)).toEqual(data);
|
||||
expect(serializer2.unserialize(dumped2)).toEqual(data);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -41,18 +41,32 @@ export class Serializer {
|
|||
// Collect objects
|
||||
var objects: Object[] = [];
|
||||
var stats: any = {};
|
||||
|
||||
function add(value: any): void {
|
||||
if (objects.indexOf(value) < 0) {
|
||||
objects.push(value);
|
||||
}
|
||||
}
|
||||
|
||||
crawl(obj, (value) => {
|
||||
if (isObject(value)) {
|
||||
var vtype = classname(value);
|
||||
if (vtype != "" && this.ignored.indexOf(vtype) < 0) {
|
||||
stats[vtype] = (stats[vtype] || 0) + 1;
|
||||
if (objects.indexOf(value) < 0) {
|
||||
objects.push(value);
|
||||
}
|
||||
add(value);
|
||||
return value;
|
||||
} else {
|
||||
return STOP_CRAWLING;
|
||||
}
|
||||
} else if (typeof value == "function") {
|
||||
const found = Object.entries(this.namespace).find(([_, cons]) =>
|
||||
cons === value
|
||||
);
|
||||
if (found && this.ignored.indexOf(found[0]) < 0) {
|
||||
// Keep references to constructors in the namespace
|
||||
add(value);
|
||||
}
|
||||
return STOP_CRAWLING;
|
||||
} else {
|
||||
return value;
|
||||
}
|
||||
|
@ -63,7 +77,8 @@ export class Serializer {
|
|||
var fobjects = objects.map((value) => this.encodeObject(value));
|
||||
return JSON.stringify(fobjects, (key, value) => {
|
||||
if (
|
||||
key != "$f" && isObject(value) && !value.hasOwnProperty("$c") &&
|
||||
key != "$f" && (isObject(value) || typeof value == "function") &&
|
||||
!value.hasOwnProperty("$c") &&
|
||||
!value.hasOwnProperty("$i")
|
||||
) {
|
||||
return { $i: objects.indexOf(value) };
|
||||
|
@ -132,6 +147,10 @@ export class Serializer {
|
|||
$c: ctype,
|
||||
$f: Array.from(obj),
|
||||
};
|
||||
} else if (typeof obj == "function") {
|
||||
return {
|
||||
$c: obj.name,
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
$c: this.namespace_rev[ctype] || ctype,
|
||||
|
@ -149,8 +168,10 @@ export class Serializer {
|
|||
return new Set(objdata.$f);
|
||||
} else if (ctype == "Map") {
|
||||
return new Map(objdata.$f);
|
||||
} else {
|
||||
} else if (objdata.$f) {
|
||||
return Object.assign(this.constructObject(ctype), objdata.$f);
|
||||
} else {
|
||||
return this.namespace[ctype];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -159,7 +180,8 @@ export class Serializer {
|
|||
* Check if the argument is an instance of a class
|
||||
*/
|
||||
function isObject(value: any): boolean {
|
||||
return value instanceof Object && !Array.isArray(value);
|
||||
return typeof value == "object" && value instanceof Object &&
|
||||
!Array.isArray(value);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -174,7 +196,7 @@ function crawl(
|
|||
callback: (item: any) => any,
|
||||
replace = false,
|
||||
memo: any[] = [],
|
||||
) {
|
||||
): any {
|
||||
if (isObject(obj)) {
|
||||
if (memo.indexOf(obj) >= 0) {
|
||||
return obj;
|
||||
|
@ -183,11 +205,11 @@ function crawl(
|
|||
}
|
||||
}
|
||||
|
||||
if (obj !== undefined && obj !== null && typeof obj != "function") {
|
||||
if (obj !== undefined && obj !== null) {
|
||||
const result = callback(obj);
|
||||
|
||||
if (result === STOP_CRAWLING) {
|
||||
return;
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (Array.isArray(obj)) {
|
||||
|
@ -244,5 +266,5 @@ function crawl(
|
|||
* Get the class name of an object.
|
||||
*/
|
||||
function classname(obj: Object): string {
|
||||
return (<any> obj.constructor).name;
|
||||
return obj.constructor.name;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue