Skip to content

Commit c683916

Browse files
committed
add JavaScriptCodec to handle basic JavaScript objects
1 parent aed070f commit c683916

File tree

2 files changed

+87
-0
lines changed

2 files changed

+87
-0
lines changed

src/JavaScriptCodec.ts

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

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("Thu, 28 Apr 2016 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)