Skip to content

Commit 9600b30

Browse files
committed
Merge branch 'javascript_codec' into structure_cloneable
2 parents ac10a3d + a5a5d1b commit 9600b30

File tree

4 files changed

+108
-8
lines changed

4 files changed

+108
-8
lines changed

src/ExtensionCodec.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -61,25 +61,25 @@ export class ExtensionCodec<ContextType = undefined> implements ExtensionCodecTy
6161
}
6262

6363
public tryToEncode(object: unknown, context: ContextType): ExtData | null {
64-
// built-in extensions
65-
for (let i = 0; i < this.builtInEncoders.length; i++) {
66-
const encoder = this.builtInEncoders[i];
64+
// custom extensions
65+
for (let i = 0; i < this.encoders.length; i++) {
66+
const encoder = this.encoders[i];
6767
if (encoder != null) {
6868
const data = encoder(object, context);
6969
if (data != null) {
70-
const type = -1 - i;
70+
const type = i;
7171
return new ExtData(type, data);
7272
}
7373
}
7474
}
7575

76-
// custom extensions
77-
for (let i = 0; i < this.encoders.length; i++) {
78-
const encoder = this.encoders[i];
76+
// built-in extensions
77+
for (let i = 0; i < this.builtInEncoders.length; i++) {
78+
const encoder = this.builtInEncoders[i];
7979
if (encoder != null) {
8080
const data = encoder(object, context);
8181
if (data != null) {
82-
const type = i;
82+
const type = -1 - i;
8383
return new ExtData(type, data);
8484
}
8585
}

src/JavaScriptCodec.ts

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

src/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,3 +44,6 @@ export {
4444
encodeTimestampExtension,
4545
decodeTimestampExtension,
4646
};
47+
48+
export { JavaScriptCodec, EXT_JAVASCRIPT, encodeJavaScriptData, decodeJavaScriptData } from "./JavaScriptCodec";
49+

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, JavaScriptCodec } from "@msgpack/msgpack";
3+
4+
describe("JavaScriptCodec", () => {
5+
context("mixed", () => {
6+
// this data comes from https://github.com/yahoo/serialize-javascript
7+
8+
it("encodes and decodes the object", () => {
9+
const object = {
10+
str: "string",
11+
num: 0,
12+
obj: { foo: "foo", bar: "bar" },
13+
arr: [1, 2, 3],
14+
bool: true,
15+
nil: null,
16+
// undef: undefined, // not supported
17+
date: new Date("Thu, 28 Apr 2016 22:02:17 GMT"),
18+
map: new Map([["foo", 10], ["bar", 20]]),
19+
set: new Set([123, 456]),
20+
regexp: /foo\n/i,
21+
bigint: typeof(BigInt) !== "undefined" ? BigInt(Number.MAX_SAFE_INTEGER) + BigInt(1) : null,
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)