Skip to content
This repository has been archived by the owner on Jul 5, 2024. It is now read-only.

Commit

Permalink
handle Map and Set
Browse files Browse the repository at this point in the history
  • Loading branch information
Sheraff committed Oct 8, 2023
1 parent 220d529 commit d83bc7e
Show file tree
Hide file tree
Showing 2 changed files with 153 additions and 6 deletions.
110 changes: 110 additions & 0 deletions src/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
createTsonAsync,
tsonDate,
tsonMap,
tsonSet,
} from "./index.js";
import { waitError } from "./internals/testUtils.js";

Expand Down Expand Up @@ -234,6 +235,115 @@ test("back-reference: self-referencing Map", () => {
const res = t.parse(str);

expect(res).toEqual(expected);
expect(res.get("a")).toBe(res);
});

test("back-reference: self-referencing Map deep", () => {
const t = createTson({
nonce: () => "__tson__",
types: [tsonMap],
});

const expected = new Map();
expected.set("a", {
foo: expected,
});

const str = t.stringify(expected, 2);

expect(str).toMatchInlineSnapshot(`
"{
\\"json\\": [
\\"Map\\",
[
[
\\"a\\",
{
\\"foo\\": [
\\"CIRCULAR\\",
\\"\\",
\\"__tson__\\"
]
}
]
],
\\"__tson__\\"
],
\\"nonce\\": \\"__tson__\\"
}"
`);
const res = t.parse(str);

expect(res).toEqual(expected);
expect(res.get("a").foo).toBe(res);
});

test("back-reference: self-referencing Set", () => {
const t = createTson({
nonce: () => "__tson__",
types: [tsonSet],
});

const expected = new Set();
expected.add(expected);

const str = t.stringify(expected, 2);

expect(str).toMatchInlineSnapshot(`
"{
\\"json\\": [
\\"Set\\",
[
[
\\"CIRCULAR\\",
\\"\\",
\\"__tson__\\"
]
],
\\"__tson__\\"
],
\\"nonce\\": \\"__tson__\\"
}"
`);
const res = t.parse(str);

expect(res).toEqual(expected);
expect(res.has(res)).toBe(true);
});

test("back-reference: self-referencing Set deep", () => {
const t = createTson({
nonce: () => "__tson__",
types: [tsonSet],
});

const expected = new Set();
expected.add({ foo: expected });

const str = t.stringify(expected, 2);

expect(str).toMatchInlineSnapshot(`
"{
\\"json\\": [
\\"Set\\",
[
{
\\"foo\\": [
\\"CIRCULAR\\",
\\"\\",
\\"__tson__\\"
]
}
],
\\"__tson__\\"
],
\\"nonce\\": \\"__tson__\\"
}"
`);
const res = t.parse(str);

expect(res).toEqual(expected);
expect(res.values().next().value.foo).toBe(res);
});
/**
* WILL NOT WORK: the async serialize/deserialize functions haven't
Expand Down
49 changes: 43 additions & 6 deletions src/sync/deserialize.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ export function createTsonDeserialize(opts: TsonOptions): TsonDeserializeFn {
const [type, serializedValue] = value;
if (type === "CIRCULAR") {
references.push([key, serializedValue as string]);
return;
return nonce;
}

// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
Expand Down Expand Up @@ -75,15 +75,52 @@ export function createTsonDeserialize(opts: TsonOptions): TsonDeserializeFn {
let insertAt = res;
try {
while (path.length > 1) {
//@ts-expect-error -- insertAt is unknown and not checked, but if it passed serialization, it should be an object
insertAt = insertAt[path.shift()];
if (insertAt instanceof Map) {
if (path.length <= 2) {
break;
}

// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-non-null-assertion -- if it passed serialization, path will have an index at this point
const key = Array.from(insertAt.keys())[Number(path.shift()!)];
insertAt = insertAt.get(key);
path.shift();
} else if (insertAt instanceof Set) {
//@ts-expect-error -- if it passed serialization, path will have an index at this point
insertAt = Array.from(insertAt)[path.shift()];
} else {
//@ts-expect-error -- insertAt is unknown and not checked, but if it passed serialization, it should be an object
insertAt = insertAt[path.shift()];
}
}

//@ts-expect-error -- see above, + if it passed serialization, path should be length 1 at this point
insertAt[path[0]] = prev;
if (insertAt instanceof Map) {
if (path.length !== 2) {
throw new Error(
`Invalid path to Map insertion ${copyKey
.split(nonce)
.join(".")}`,
);
}

Check warning on line 103 in src/sync/deserialize.ts

View check run for this annotation

Codecov / codecov/patch

src/sync/deserialize.ts#L98-L103

Added lines #L98 - L103 were not covered by tests

const mapKeys = Array.from(insertAt.keys());
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-non-null-assertion -- if it passed serialization, path will have an index at this point
const key = mapKeys[Number(path[0]!)];
insertAt.set(key, prev);
} else if (insertAt instanceof Set) {
/**
* WARNING: this doesn't preserve order in the Set
*/
insertAt.delete(nonce);
insertAt.add(prev);
} else {
//@ts-expect-error -- see above, + if it passed serialization, path should be length 1 at this point
insertAt[path[0]] = prev;
}
} catch (cause) {
throw new Error(
`Invalid path to reference insertion ${copyKey.split(nonce).join(".")}`,
`Invalid path to reference insertion ${copyKey
.split(nonce)
.join(".")}`,
{ cause },
);
}

Check warning on line 126 in src/sync/deserialize.ts

View check run for this annotation

Codecov / codecov/patch

src/sync/deserialize.ts#L120-L126

Added lines #L120 - L126 were not covered by tests
Expand Down

0 comments on commit d83bc7e

Please sign in to comment.