diff --git a/deno.json b/deno.json index ba967afdb0d..6b8eea39f24 100644 --- a/deno.json +++ b/deno.json @@ -65,7 +65,8 @@ "@marvinh-test/fresh-island": "jsr:@marvinh-test/fresh-island@^0.0.1", "linkedom": "npm:linkedom@^0.16.11", "@std/async": "jsr:@std/async@1", - "@std/expect": "jsr:@std/expect@1" + "@std/expect": "jsr:@std/expect@1", + "@std/testing": "jsr:@std/testing@1" }, "compilerOptions": { "lib": ["dom", "dom.asynciterable", "deno.ns", "deno.unstable"], diff --git a/deno.lock b/deno.lock index ce10da5aee3..127583e8364 100644 --- a/deno.lock +++ b/deno.lock @@ -4,14 +4,19 @@ "jsr:@astral/astral@~0.4.6": "0.4.9", "jsr:@deno-library/progress@^1.5.1": "1.5.1", "jsr:@deno/otel@*": "0.0.2", + "jsr:@fresh/core@^2.0.0-alpha.22": "2.0.0-alpha.26", + "jsr:@fresh/core@^2.0.0-alpha.26": "2.0.0-alpha.26", "jsr:@luca/esbuild-deno-loader@0.11": "0.11.1", "jsr:@marvinh-test/fresh-island@*": "0.0.1", "jsr:@marvinh-test/fresh-island@^0.0.1": "0.0.1", "jsr:@std/assert@^1.0.9": "1.0.9", "jsr:@std/async@1": "1.0.9", "jsr:@std/bytes@^1.0.2": "1.0.4", + "jsr:@std/bytes@^1.0.3": "1.0.4", + "jsr:@std/cli@1": "1.0.8", "jsr:@std/collections@^1.0.9": "1.0.9", "jsr:@std/crypto@1": "1.0.3", + "jsr:@std/datetime@0.225.0": "0.225.0", "jsr:@std/datetime@~0.225.2": "0.225.2", "jsr:@std/encoding@1": "1.0.5", "jsr:@std/encoding@^1.0.5": "1.0.5", @@ -20,6 +25,7 @@ "jsr:@std/fmt@1.0.3": "1.0.3", "jsr:@std/front-matter@^1.0.5": "1.0.5", "jsr:@std/fs@1": "1.0.6", + "jsr:@std/fs@^1.0.6": "1.0.6", "jsr:@std/html@1": "1.0.3", "jsr:@std/internal@^1.0.5": "1.0.5", "jsr:@std/io@0.225.0": "0.225.0", @@ -31,6 +37,7 @@ "jsr:@std/path@^1.0.8": "1.0.8", "jsr:@std/semver@1": "1.0.3", "jsr:@std/streams@1": "1.0.8", + "jsr:@std/testing@1": "1.0.6", "jsr:@std/toml@^1.0.1": "1.0.2", "jsr:@std/yaml@^1.0.5": "1.0.5", "jsr:@zip-js/zip-js@^2.7.52": "2.7.54", @@ -39,6 +46,7 @@ "npm:@opentelemetry/sdk-trace-base@1": "1.29.0_@opentelemetry+api@1.9.0", "npm:@preact/signals@^1.2.3": "1.3.1_preact@10.25.1", "npm:@preact/signals@^1.3.0": "1.3.1_preact@10.25.1", + "npm:@types/node@*": "22.5.4", "npm:autoprefixer@10.4.17": "10.4.17_postcss@8.4.35", "npm:cssnano@6.0.3": "6.0.3_postcss@8.4.35", "npm:esbuild-wasm@0.23.1": "0.23.1", @@ -62,7 +70,7 @@ "dependencies": [ "jsr:@deno-library/progress", "jsr:@std/async", - "jsr:@std/fs", + "jsr:@std/fs@1", "jsr:@std/path@1", "jsr:@zip-js/zip-js" ] @@ -81,10 +89,31 @@ "npm:@opentelemetry/sdk-trace-base" ] }, + "@fresh/core@2.0.0-alpha.26": { + "integrity": "db268b66b94086eabb3cf682d8d6270e1de57664899a54f1ce35aecd1a59691d", + "dependencies": [ + "jsr:@luca/esbuild-deno-loader", + "jsr:@std/crypto", + "jsr:@std/datetime@~0.225.2", + "jsr:@std/encoding@1", + "jsr:@std/fmt@1", + "jsr:@std/fs@1", + "jsr:@std/html", + "jsr:@std/jsonc", + "jsr:@std/media-types", + "jsr:@std/path@1", + "jsr:@std/semver", + "npm:@opentelemetry/api@^1.9.0", + "npm:esbuild", + "npm:esbuild-wasm", + "npm:preact-render-to-string", + "npm:preact@^10.25.1" + ] + }, "@luca/esbuild-deno-loader@0.11.1": { "integrity": "dc020d16d75b591f679f6b9288b10f38bdb4f24345edb2f5732affa1d9885267", "dependencies": [ - "jsr:@std/bytes", + "jsr:@std/bytes@^1.0.2", "jsr:@std/encoding@^1.0.5", "jsr:@std/path@^1.0.6" ] @@ -109,12 +138,18 @@ "@std/bytes@1.0.4": { "integrity": "11a0debe522707c95c7b7ef89b478c13fb1583a7cfb9a85674cd2cc2e3a28abc" }, + "@std/cli@1.0.8": { + "integrity": "3762d8dc9a373715c08d871c38d45e637b25266f013a1d0bbe560bca409de94e" + }, "@std/collections@1.0.9": { "integrity": "4f58104ead08a04a2199374247f07befe50ba01d9cca8cbb23ab9a0419921e71" }, "@std/crypto@1.0.3": { "integrity": "a2a32f51ddef632d299e3879cd027c630dcd4d1d9a5285d6e6788072f4e51e7f" }, + "@std/datetime@0.225.0": { + "integrity": "73ee4457218e06f50d3680fb0c430ba94006305e4104c84e783b3f5c0ec78900" + }, "@std/datetime@0.225.2": { "integrity": "45f0100554a912cd65f48089ef0a33aa1eb6ea21f08090840b539ab582827eaa" }, @@ -172,7 +207,19 @@ "integrity": "7c139c6076a080eeaa4252c78b95ca5302818d7eafab0470d34cafd9930c13c8" }, "@std/streams@1.0.8": { - "integrity": "b41332d93d2cf6a82fe4ac2153b930adf1a859392931e2a19d9fabfb6f154fb3" + "integrity": "b41332d93d2cf6a82fe4ac2153b930adf1a859392931e2a19d9fabfb6f154fb3", + "dependencies": [ + "jsr:@std/bytes@^1.0.3" + ] + }, + "@std/testing@1.0.6": { + "integrity": "9192ded2d34065f4c959fdc1921fe836770abb9194410c2cc8a0fff4eff5c893", + "dependencies": [ + "jsr:@std/assert", + "jsr:@std/fs@^1.0.6", + "jsr:@std/internal", + "jsr:@std/path@^1.0.8" + ] }, "@std/toml@1.0.2": { "integrity": "5892ba489c5b512265a384238a8fe8dddbbb9498b4b210ef1b9f0336a423a39b", @@ -370,6 +417,12 @@ "path-browserify" ] }, + "@types/node@22.5.4": { + "integrity": "sha512-FDuKUJQm/ju9fT/SeX/6+gBzoPzlVCzfzmGkwKvRHQVxi4BntVbyIwf6a4Xn62mrvndLiml6z/UBXIdEVjQLXg==", + "dependencies": [ + "undici-types" + ] + }, "ansi-regex@5.0.1": { "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" }, @@ -1358,6 +1411,9 @@ "uhyphen@0.2.0": { "integrity": "sha512-qz3o9CHXmJJPGBdqzab7qAYuW8kQGKNEuoHFYrBwV6hWIMcpAmxDLXojcHfFr9US1Pe6zUswEIJIbLI610fuqA==" }, + "undici-types@6.19.8": { + "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==" + }, "update-browserslist-db@1.1.1_browserslist@4.24.2": { "integrity": "sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==", "dependencies": [ @@ -1664,6 +1720,7 @@ "jsr:@std/path@1", "jsr:@std/semver@1", "jsr:@std/streams@1", + "jsr:@std/testing@1", "npm:@opentelemetry/api@^1.9.0", "npm:@preact/signals@^1.2.3", "npm:esbuild-wasm@0.23.1", diff --git a/src/jsonify/__snapshots__/round_trip_test.ts.snap b/src/jsonify/__snapshots__/round_trip_test.ts.snap new file mode 100644 index 00000000000..ccc2cab2ee5 --- /dev/null +++ b/src/jsonify/__snapshots__/round_trip_test.ts.snap @@ -0,0 +1,55 @@ +export const snapshot = {}; + +snapshot[`round trip - undefined 1`] = `"-1"`; + +snapshot[`round trip - null 1`] = `"-2"`; + +snapshot[`round trip - 1 1`] = `"[1]"`; + +snapshot[`round trip - 2 1`] = `"[2]"`; + +snapshot[`round trip - -2 1`] = `"[-2]"`; + +snapshot[`round trip - Infinity 1`] = `"-4"`; + +snapshot[`round trip - -Infinity 1`] = `"-5"`; + +snapshot[`round trip - 0 1`] = `"[0]"`; + +snapshot[`round trip - -0 1`] = `"-6"`; + +snapshot[`round trip - NaN 1`] = `"-3"`; + +snapshot[`round trip - 0 2`] = `"[0]"`; + +snapshot[`round trip - true 1`] = `"[true]"`; + +snapshot[`round trip - false 1`] = `"[false]"`; + +snapshot[`round trip - 'abc' 1`] = `'["abc"]'`; + +snapshot[`round trip - 1n 1`] = `'[["BigInt","1"]]'`; + +snapshot[`round trip - -1n 1`] = `'[["BigInt","-1"]]'`; + +snapshot[`round trip - [ 1, 2, 3 ] 1`] = `"[[1,2,3],1,2,3]"`; + +snapshot[`round trip - [ null, undefined, -2 ] 1`] = `"[[-2,-1,1],-2]"`; + +snapshot[`round trip - { a: 1, b: null, c: -2 } 1`] = `'[{"a":1,"b":-2,"c":2},1,-2]'`; + +snapshot[`round trip - Uint8Array(3) [ 1, 2, 3 ] 1`] = `'[["Uint8Array","AQID"]]'`; + +snapshot[`round trip - 1990-05-31T00:00:00.000Z 1`] = `'[["Date","1990-05-31T00:00:00.000Z"]]'`; + +snapshot[`round trip - Map(2) { 1 => null, undefined => -2 } 1`] = `'[["Map",[1,-2,-1,2]],1,-2]'`; + +snapshot[`round trip - Set(5) { 1, 2, null, -2, NaN } 1`] = `'[["Set",[1,2,-2,3,-3]],1,2,-2]'`; + +snapshot[`round trip - [ 1, <1 empty item>, 3 ] 1`] = `"[[1,-7,2],1,3]"`; + +snapshot[`round trip - /foo["]/ 1`] = `'[["RegExp","foo[\\\\"]", ""]]'`; + +snapshot[`round trip - { a: { foo: 123 }, b: [ { foo: 123 }, { foo: 123 } ] } 1`] = `'[{"a":1,"b":3},{"foo":2},123,[1,1]]'`; + +snapshot[`round trip - { a: 1, b: [Circular *1] } 1`] = `'[{"a":1,"b":0},1]'`; diff --git a/src/jsonify/parse.ts b/src/jsonify/parse.ts index 91c0fe0e527..03f41c6991d 100644 --- a/src/jsonify/parse.ts +++ b/src/jsonify/parse.ts @@ -16,10 +16,9 @@ export function parse( custom?: CustomParser | undefined, ): T { const data = JSON.parse(value); - + if (!Array.isArray(data)) return unpack([], [], data, custom); const hydrated = new Array(data.length); - // deno-lint-ignore no-explicit-any - unpack(data, hydrated, 0, custom) as any; + unpack(data, hydrated, 0, custom); return hydrated[0]; } @@ -28,181 +27,94 @@ function unpack( hydrated: unknown[], idx: number, custom: CustomParser | undefined, -): void { - if (idx in hydrated) return; +): any { + switch (idx) { + case UNDEFINED: + return undefined; + case NULL: + return null; + case NAN: + return NaN; + case INFINITY_POS: + return Infinity; + case INFINITY_NEG: + return -Infinity; + case ZERO_NEG: + return -0; + } + + if (idx in hydrated) return hydrated[idx]; const current = arr[idx]; if (typeof current === "number") { - switch (current) { - case UNDEFINED: - hydrated[idx] = undefined; - return; - case NULL: - hydrated[idx] = null; - return; - case NAN: - hydrated[idx] = NaN; - return; - case INFINITY_POS: - hydrated[idx] = Infinity; - return; - case INFINITY_NEG: - hydrated[idx] = -Infinity; - return; - case ZERO_NEG: - hydrated[idx] = -0; - return; - default: - hydrated[idx] = current; - return; - } + return hydrated[idx] = current; } else if ( typeof current === "string" || typeof current === "boolean" || current === null ) { - hydrated[idx] = current; - return; + return hydrated[idx] = current; } else if (Array.isArray(current)) { if (current.length > 0 && typeof current[0] === "string") { const name = current[0]; if (custom !== undefined && name in custom) { const fn = custom[name]; const ref = current[1]; - let value; - if (ref < 0) { - switch (ref) { - case UNDEFINED: - value = undefined; - break; - case NULL: - value = null; - break; - case NAN: - value = NaN; - break; - case INFINITY_POS: - value = Infinity; - break; - case INFINITY_NEG: - value = -Infinity; - break; - case ZERO_NEG: - value = -0; - break; - } - } else { - unpack(arr, hydrated, ref, custom); - value = hydrated[ref]; - } - hydrated[idx] = fn(value); - return; + const value = unpack(arr, hydrated, ref, custom); + return hydrated[idx] = fn(value); } switch (name) { case "BigInt": - hydrated[idx] = BigInt(current[1]); - return; + return hydrated[idx] = BigInt(current[1]); case "Date": - hydrated[idx] = new Date(current[1]); - return; + return hydrated[idx] = new Date(current[1]); case "RegExp": - hydrated[idx] = new RegExp(current[1], current[2]); - return; + return hydrated[idx] = new RegExp(current[1], current[2]); case "Set": { const set = new Set(); for (let i = 0; i < current[1].length; i++) { const ref = current[1][i]; - unpack(arr, hydrated, ref, custom); - set.add(hydrated[ref]); + set.add(unpack(arr, hydrated, ref, custom)); } - hydrated[idx] = set; - return; + return hydrated[idx] = set; } case "Map": { const set = new Map(); for (let i = 0; i < current[1].length; i++) { const refKey = current[1][i++]; - unpack(arr, hydrated, refKey, custom); + const key = unpack(arr, hydrated, refKey, custom); const refValue = current[1][i]; - unpack(arr, hydrated, refValue, custom); + const value = unpack(arr, hydrated, refValue, custom); - set.set(hydrated[refKey], hydrated[refValue]); + set.set(key, value); } - hydrated[idx] = set; - return; + return hydrated[idx] = set; } case "Uint8Array": - hydrated[idx] = b64decode(current[1]); - return; + return hydrated[idx] = b64decode(current[1]); } } else { const actual = new Array(current.length); hydrated[idx] = actual; for (let i = 0; i < current.length; i++) { const ref = current[i]; - if (ref < 0) { - switch (ref) { - case UNDEFINED: - actual[i] = undefined; - break; - case NULL: - actual[i] = null; - break; - case NAN: - actual[i] = NaN; - break; - case INFINITY_POS: - actual[i] = Infinity; - break; - case INFINITY_NEG: - actual[i] = -Infinity; - break; - case ZERO_NEG: - actual[i] = -0; - break; - case HOLE: - continue; - } + if (ref === HOLE) { + continue; } else { - unpack(arr, hydrated, ref, custom); - actual[i] = hydrated[ref]; + actual[i] = unpack(arr, hydrated, ref, custom); } } + return actual; } } else if (typeof current === "object") { const actual: Record = {}; hydrated[idx] = actual; - const keys = Object.keys(current); for (let i = 0; i < keys.length; i++) { const key = keys[i]; - // deno-lint-ignore no-explicit-any const ref = (current as any)[key]; - if (ref < 0) { - switch (ref) { - case UNDEFINED: - actual[key] = undefined; - break; - case NULL: - actual[key] = null; - break; - case NAN: - actual[key] = NaN; - break; - case INFINITY_POS: - actual[key] = Infinity; - break; - case INFINITY_NEG: - actual[key] = -Infinity; - break; - case ZERO_NEG: - actual[key] = -0; - break; - } - } else { - unpack(arr, hydrated, ref, custom); - actual[key] = hydrated[ref]; - } + actual[key] = unpack(arr, hydrated, ref, custom); } + return actual; } } diff --git a/src/jsonify/parse_test.ts b/src/jsonify/parse_test.ts deleted file mode 100644 index 8e5a1b88df1..00000000000 --- a/src/jsonify/parse_test.ts +++ /dev/null @@ -1,99 +0,0 @@ -import { expect } from "@std/expect"; -import { parse } from "./parse.ts"; - -Deno.test("parse - json", () => { - expect(parse("[2]")).toEqual(2); - expect(parse('["abc"]')).toEqual("abc"); - expect(parse("[true]")).toEqual(true); - expect(parse("[false]")).toEqual(false); - expect(parse("[[1,2,3],1,2,3]")).toEqual([1, 2, 3]); - expect(parse('[{"a":1,"b":-2,"c":2},1,[-2]]')).toEqual({ - a: 1, - b: null, - c: [null], - }); -}); - -Deno.test("parse - hole array", () => { - expect(parse("[[1,-7,2],1,3]")).toEqual([1, , 3]); -}); - -Deno.test("parse - undefined", () => { - expect(parse("[-1]")).toEqual(undefined); -}); - -Deno.test("parse - Infinity", () => { - expect(parse("[-4]")).toEqual(Infinity); - expect(parse("[-5]")).toEqual(-Infinity); -}); - -Deno.test("parse - NaN", () => { - expect(parse("[-3]")).toEqual(NaN); -}); - -Deno.test("parse - -0", () => { - expect(parse("[-6]")).toEqual(-0); -}); - -Deno.test("parse - bigint", () => { - const n = BigInt(9007199254740991); - expect(parse('[["BigInt","9007199254740991"]]')).toEqual( - n, - ); -}); - -Deno.test("parse - Set", () => { - const res = parse('[["Set",[1,2]],1,{"foo":1}]'); - expect(res).toEqual( - new Set([1, { foo: 1 }]), - ); -}); - -Deno.test("parse - Map", () => { - expect(parse('[["Map",[1,2,3,4]],1,{"foo":1},2,3]')) - .toEqual( - new Map([[1, { foo: 1 }], [2, 3]]), - ); -}); - -Deno.test("parse - Date", () => { - const date = new Date("1990-05-31"); - expect(parse('[["Date","1990-05-31T00:00:00.000Z"]]')).toEqual( - date, - ); -}); - -Deno.test("parse - RegExp", () => { - let reg = /foo["]/; - expect(parse('[["RegExp","foo[\\"]", ""]]')).toEqual(reg); - - reg = /foo["]/g; - expect(parse('[["RegExp","foo[\\"]", "g"]]')).toEqual(reg); -}); - -Deno.test("parse - Uint8Array", () => { - const value = new Uint8Array([1, 2, 3]); - expect(parse('[["Uint8Array","AQID"]]')).toEqual( - value, - ); -}); - -Deno.test("parse - references", () => { - const inner = { foo: 123 }; - const obj = { a: inner, b: [inner, inner] }; - const res = parse('[{"a":1,"b":3},{"foo":2},123,[1,1]]'); - expect(res).toEqual(obj); - expect(res.a).toEqual(res.b[0]); - expect(res.a).toEqual(res.b[1]); -}); - -Deno.test("parse - circular references", () => { - // deno-lint-ignore no-explicit-any - const foo = { foo: null as any }; - foo.foo = foo; - expect(parse('[{"foo":0}]')).toEqual(foo); -}); - -Deno.test("parse - object", () => { - expect(parse('[{"foo":1},42]')).toEqual({ foo: 42 }); -}); diff --git a/src/jsonify/round_trip_test.ts b/src/jsonify/round_trip_test.ts new file mode 100644 index 00000000000..aecaed1e635 --- /dev/null +++ b/src/jsonify/round_trip_test.ts @@ -0,0 +1,51 @@ +import { expect } from "@std/expect"; +import { parse } from "./parse.ts"; +import { assertSnapshot } from "@std/testing/snapshot"; +import { inspect } from "node:util"; +import { stringify } from "./stringify.ts"; + +const inner = { foo: 123 }; +const references = { a: inner, b: [inner, inner] }; + +const circular = { a: 1, b: null as unknown }; +circular.b = circular; + +const TESTS = [ + undefined, + null, + 1, + 2, + -2, + Infinity, + -Infinity, + 0, + -0, + NaN, + 1.2 - + 1.2, + true, + false, + "abc", + 1n, + -1n, + [1, 2, 3], + [null, undefined, -2], + { a: 1, b: null, c: -2 }, + new Uint8Array([1, 2, 3]), + new Date("1990-05-31"), + new Map([[1, null], [undefined, -2]]), + new Set([1, 2, null, -2, NaN]), + [1, , 3], + /foo["]/, + references, + circular, +]; + +for (const value of TESTS) { + Deno.test(`round trip - ${inspect(value)}`, async (t) => { + const str = stringify(value); + await assertSnapshot(t, str); + const parsed = parse(str); + expect(parsed).toEqual(value); + }); +} diff --git a/src/jsonify/stringify.ts b/src/jsonify/stringify.ts index eb55ca41a6c..b44f1b01222 100644 --- a/src/jsonify/stringify.ts +++ b/src/jsonify/stringify.ts @@ -39,7 +39,7 @@ export function stringify(data: unknown, custom?: Stringifiers): string { const indexes = new Map(); const res = serializeInner(out, indexes, data, custom); if (res < 0) { - out.push(String(res)); + return String(res) } return `[${out.join(",")}]`; } diff --git a/src/jsonify/stringify_test.ts b/src/jsonify/stringify_test.ts index 912dda67380..7f4cbf93ecb 100644 --- a/src/jsonify/stringify_test.ts +++ b/src/jsonify/stringify_test.ts @@ -1,101 +1,6 @@ import { expect } from "@std/expect"; import { stringify } from "./stringify.ts"; -Deno.test("stringify - json", () => { - expect(stringify(2)).toEqual("[2]"); - expect(stringify("abc")).toEqual('["abc"]'); - expect(stringify(true)).toEqual("[true]"); - expect(stringify(false)).toEqual("[false]"); - expect(stringify([1, 2, 3])).toEqual("[[1,2,3],1,2,3]"); - expect(stringify({ a: 1, b: null, c: [null] })).toEqual( - '[{"a":1,"b":-2,"c":2},1,[-2]]', - ); -}); - -Deno.test("stringify - hole array", () => { - expect(stringify([1, , 3])).toEqual("[[1,-7,2],1,3]"); -}); - -Deno.test("stringify - undefined", () => { - expect(stringify(undefined)).toEqual("[-1]"); -}); - -Deno.test("stringify - Infinity", () => { - expect(stringify(Infinity)).toEqual("[-4]"); - expect(stringify(-Infinity)).toEqual("[-5]"); -}); - -Deno.test("stringify - NaN", () => { - expect(stringify(NaN)).toEqual("[-3]"); -}); - -Deno.test("stringify - -0", () => { - expect(stringify(-0)).toEqual("[-6]"); -}); - -Deno.test("stringify - bigint", () => { - const n = BigInt(9007199254740991); - expect(stringify(n)).toEqual( - '[["BigInt","9007199254740991"]]', - ); -}); - -Deno.test("stringify - Date", () => { - const date = new Date("1990-05-31"); - expect(stringify(date)).toEqual( - '[["Date","1990-05-31T00:00:00.000Z"]]', - ); -}); - -Deno.test("stringify - RegExp", () => { - let reg = /foo["]/; - expect(stringify(reg)).toEqual( - '[["RegExp","foo[\\"]", ""]]', - ); - - reg = /foo["]/g; - expect(stringify(reg)).toEqual( - '[["RegExp","foo[\\"]", "g"]]', - ); -}); - -Deno.test("stringify - Set", () => { - expect(stringify(new Set([1, { foo: 1 }]))).toEqual( - '[["Set",[1,2]],1,{"foo":1}]', - ); -}); - -Deno.test("stringify - Map", () => { - expect(stringify(new Map([[1, { foo: 1 }], [2, 3]]))) - .toEqual( - '[["Map",[1,2,3,4]],1,{"foo":1},2,3]', - ); -}); - -Deno.test("stringify - Uint8Array", () => { - const value = new Uint8Array([1, 2, 3]); - expect(stringify(value)).toEqual( - '[["Uint8Array","AQID"]]', - ); -}); - -Deno.test("stringify - references", () => { - const inner = { foo: 123 }; - const obj = { a: inner, b: [inner, inner] }; - expect(stringify(obj)).toEqual( - '[{"a":1,"b":3},{"foo":2},123,[1,1]]', - ); -}); - -Deno.test("stringify - circular references", () => { - // deno-lint-ignore no-explicit-any - const foo = { foo: null as any }; - foo.foo = foo; - expect(stringify(foo)).toEqual( - '[{"foo":0}]', - ); -}); - Deno.test("stringify - object prototype", () => { const obj = { __proto__: 123, foo: 1 }; expect(stringify(obj)).toEqual(