Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 94a75e2

Browse files
committed
add JavaScriptCodec to serialize JavaScript data structure
1 parent 6e0069d commit 94a75e2

File tree

3 files changed

+100
-5
lines changed

3 files changed

+100
-5
lines changed

‎src/Encoder.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,16 +24,14 @@ export class Encoder {
2424
throw new Error(`Too deep objects in depth ${depth}`);
2525
}
2626

27-
if (object == null) {
28-
this.encodeNil();
29-
} else if (typeof object === "boolean") {
27+
if (typeof object === "boolean") {
3028
this.encodeBoolean(object);
3129
} else if (typeof object === "number") {
3230
this.encodeNumber(object);
3331
} else if (typeof object === "string") {
3432
this.encodeString(object);
3533
} else {
36-
this.encodeObject(object, depth);
34+
this.encodeObjectOrNil(object, depth);
3735
}
3836
}
3937

@@ -164,11 +162,14 @@ export class Encoder {
164162
}
165163
}
166164

167-
encodeObject(object: unknown, depth: number) {
165+
encodeObjectOrNil(object: unknown, depth: number) {
168166
// try to encode objects with custom codec first of non-primitives
169167
const ext = this.extensionCodec.tryToEncode(object);
170168
if (ext != null) {
171169
this.encodeExtension(ext);
170+
} else if (object == null) {
171+
// `encodeNil()` must be here for extentionCodec to handle null / undefined.
172+
this.encodeNil();
172173
} else if (Array.isArray(object)) {
173174
this.encodeArray(object, depth);
174175
} else if (ArrayBuffer.isView(object)) {

‎src/JavaScriptCodec.ts

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import { ExtensionCodec, ExtensionCodecType } from "./ExtensionCodec";
2+
import { encode } from "./encode";
3+
import { decode } from "./decode";
4+
5+
export const JavaScriptCodecType = 0;
6+
7+
export function encodeJavaScriptData(input: unknown): Uint8Array | null {
8+
if (input == null) {
9+
// to distinguish undefined from null
10+
if (input === undefined) {
11+
return encode(["undefined"]);
12+
} else {
13+
return null; // fallback to MessagePack nil
14+
}
15+
} else if (input instanceof Map) {
16+
return encode(["Map", [...input]]);
17+
} else if (input instanceof Set) {
18+
return encode(["Set", [...input]]);
19+
} else if (input instanceof Date) {
20+
// Not a MessagePack timestamp because
21+
// it may be overrided by users
22+
return encode(["Date", input.getTime()]);
23+
} else if (input instanceof RegExp) {
24+
return encode(["RegExp", [input.source, input.flags]]);
25+
} else {
26+
return null;
27+
}
28+
}
29+
30+
export function decodeJavaScriptData(data: Uint8Array) {
31+
const [constructor, source] = decode(data) as [string, any];
32+
33+
switch (constructor) {
34+
case "undefined": {
35+
return undefined;
36+
}
37+
case "Map": {
38+
return new Map<unknown, unknown>(source);
39+
}
40+
case "Set": {
41+
return new Set<unknown>(source);
42+
}
43+
case "Date": {
44+
return new Date(source);
45+
}
46+
case "RegExp": {
47+
const [pattern, flags] = source;
48+
return new RegExp(pattern, flags);
49+
}
50+
default: {
51+
throw new Error(`Unknown constructor: ${constructor}`);
52+
}
53+
}
54+
}
55+
56+
export const JavaScriptCodec: ExtensionCodecType = (() => {
57+
const ext = new ExtensionCodec();
58+
59+
ext.register({
60+
type: JavaScriptCodecType,
61+
encode: encodeJavaScriptData,
62+
decode: decodeJavaScriptData,
63+
});
64+
65+
return ext;
66+
})();

‎test/javascript-codec.test.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import assert from "assert";
2+
import { encode, decode } from "@msgpack/msgpack";
3+
import { JavaScriptCodec } from "src/JavaScriptCodec";
4+
5+
describe("JavaScriptCodec", () => {
6+
context("mixed", () => {
7+
// this data comes from https://github.com/yahoo/serialize-javascript
8+
9+
it("encodes and decodes the object", () => {
10+
const object = {
11+
str: "string",
12+
num: 0,
13+
obj: { foo: "foo", bar: "bar" },
14+
arr: [1, 2, 3],
15+
bool: true,
16+
nil: null,
17+
undef: undefined,
18+
date: new Date("2016年4月28日 22:02:17 GMT"),
19+
map: new Map([["foo", 10], ["bar", 20]]),
20+
set: new Set([123, 456]),
21+
regexp: /foo\n/i,
22+
};
23+
const encoded = encode(object, { extensionCodec: JavaScriptCodec });
24+
25+
assert.deepStrictEqual(decode(encoded, { extensionCodec: JavaScriptCodec }), object);
26+
});
27+
});
28+
});

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /