+1
-2
| { | ||
| "name": "devalue", | ||
| "description": "Gets the job done when JSON.stringify can't", | ||
| "version": "5.8.1", | ||
| "version": "5.8.2", | ||
| "repository": "sveltejs/devalue", | ||
@@ -31,3 +31,2 @@ "sideEffects": false, | ||
| "type": "module", | ||
| "packageManager": "pnpm@8.15.9", | ||
| "scripts": { | ||
@@ -34,0 +33,0 @@ "changeset:version": "changeset version", |
+10
-0
@@ -81,2 +81,12 @@ import { decode64 } from './base64.js'; | ||
| // If the payload is already hydrated, its recursion has already | ||
| // terminated (e.g. a self-referential object cached itself before | ||
| // following its own back-reference), so revive it directly. Falling | ||
| // through to the `hydrating` guard here would wrongly reject a valid | ||
| // cycle. An actually infinite payload (e.g. `[["Custom", 0]]`) is never | ||
| // cached, so it still hits the guard below. | ||
| if (Object.hasOwn(hydrated, i)) { | ||
| return (hydrated[index] = reviver(hydrated[i])); | ||
| } | ||
| hydrating ??= new Set(); | ||
@@ -83,0 +93,0 @@ |
+14
-3
@@ -292,4 +292,3 @@ import { | ||
| case 'BigInt64Array': | ||
| case 'BigUint64Array': | ||
| case 'DataView': { | ||
| case 'BigUint64Array': { | ||
| /** @type {import("./types.js").TypedArray} */ | ||
@@ -301,3 +300,2 @@ const typedArray = thing; | ||
| if (typedArray.byteLength !== typedArray.buffer.byteLength) { | ||
| // to be used with `new TypedArray(buffer, byteOffset, length)` | ||
| str += `,${typedArray.byteOffset},${typedArray.length}`; | ||
@@ -310,2 +308,15 @@ } | ||
| case 'DataView': { | ||
| /** @type {DataView} */ | ||
| const view = thing; | ||
| str = '["' + type + '",' + flatten(view.buffer); | ||
| if (view.byteLength !== view.buffer.byteLength) { | ||
| str += `,${view.byteOffset},${view.byteLength}`; | ||
| } | ||
| str += ']'; | ||
| break; | ||
| } | ||
| case 'ArrayBuffer': { | ||
@@ -312,0 +323,0 @@ /** @type {ArrayBuffer} */ |
+51
-21
@@ -82,2 +82,3 @@ import { | ||
| keys.push(`.get(${is_primitive(key) ? stringify_primitive(key) : '...'})`); | ||
| walk(key); | ||
| walk(value); | ||
@@ -264,5 +265,3 @@ keys.pop(); | ||
| // Re-process this index as a hole in the array literal | ||
| has_holes = true; | ||
| i -= 1; | ||
| } | ||
@@ -296,4 +295,3 @@ // else: already decided on array literal, hole is just an empty slot | ||
| if (!names.has(thing.buffer)) { | ||
| const array = new thing.constructor(thing.buffer); | ||
| str += `([${array}])`; | ||
| str += `([${stringify_typed_array_elements(new thing.constructor(thing.buffer))}])`; | ||
| } else { | ||
@@ -324,3 +322,3 @@ str += `(${stringify(thing.buffer)})`; | ||
| if (thing.byteLength !== thing.buffer.byteLength) { | ||
| str += `,${thing.startOffset},${thing.byteLength}`; | ||
| str += `,${thing.byteOffset},${thing.byteLength}`; | ||
| } | ||
@@ -370,2 +368,9 @@ | ||
| // Reconstructions (e.g. `b = new Uint8Array(...)`) reassign a placeholder | ||
| // parameter. They must run before the `statements` that reference them, | ||
| // otherwise those statements capture the placeholder. They only depend on | ||
| // IIFE arguments (never on each other), so emitting them first is safe. | ||
| /** @type {string[]} */ | ||
| const reconstructions = []; | ||
| names.forEach((name, thing) => { | ||
@@ -421,19 +426,19 @@ params.push(name); | ||
| case 'Set': | ||
| case 'Set': { | ||
| values.push(`new Set`); | ||
| statements.push( | ||
| `${name}.${Array.from(thing) | ||
| .map((v) => `add(${stringify(v)})`) | ||
| .join('.')}` | ||
| ); | ||
| const adds = Array.from(thing).map((v) => `.add(${stringify(v)})`); | ||
| // An empty Set is fully built by `new Set`; a chained statement would | ||
| // otherwise be a dangling `name.`. | ||
| if (adds.length > 0) statements.push(name + adds.join('')); | ||
| break; | ||
| } | ||
| case 'Map': | ||
| case 'Map': { | ||
| values.push(`new Map`); | ||
| statements.push( | ||
| `${name}.${Array.from(thing) | ||
| .map(([k, v]) => `set(${stringify(k)}, ${stringify(v)})`) | ||
| .join('.')}` | ||
| const sets = Array.from(thing).map( | ||
| ([k, v]) => `.set(${stringify(k)}, ${stringify(v)})` | ||
| ); | ||
| if (sets.length > 0) statements.push(name + sets.join('')); | ||
| break; | ||
| } | ||
@@ -455,4 +460,3 @@ case 'Int8Array': | ||
| if (!names.has(thing.buffer)) { | ||
| const array = new thing.constructor(thing.buffer); | ||
| str += `([${array}])`; | ||
| str += `([${stringify_typed_array_elements(new thing.constructor(thing.buffer))}])`; | ||
| } else { | ||
@@ -470,3 +474,3 @@ str += `(${stringify(thing.buffer)})`; | ||
| values.push(`{}`); | ||
| statements.push(`${name}=${str}`); | ||
| reconstructions.push(`${name}=${str}`); | ||
| break; | ||
@@ -492,3 +496,3 @@ } | ||
| values.push(`{}`); | ||
| statements.push(`${name}=${str}`); | ||
| reconstructions.push(`${name}=${str}`); | ||
| break; | ||
@@ -501,2 +505,13 @@ } | ||
| case 'Temporal.Duration': | ||
| case 'Temporal.Instant': | ||
| case 'Temporal.PlainDate': | ||
| case 'Temporal.PlainTime': | ||
| case 'Temporal.PlainDateTime': | ||
| case 'Temporal.PlainMonthDay': | ||
| case 'Temporal.PlainYearMonth': | ||
| case 'Temporal.ZonedDateTime': | ||
| values.push(`${type}.from(${stringify_string(thing.toString())})`); | ||
| break; | ||
| default: | ||
@@ -512,3 +527,4 @@ values.push(Object.getPrototypeOf(thing) === null ? 'Object.create(null)' : '{}'); | ||
| return `(function(${params.join(',')}){${statements.join(';')}}(${values.join(',')}))`; | ||
| const body = [...reconstructions, ...statements].join(';'); | ||
| return `(function(${params.join(',')}){${body}}(${values.join(',')}))`; | ||
| } else { | ||
@@ -519,2 +535,16 @@ return str; | ||
| /** | ||
| * Serialize the elements of a typed array as a comma-separated list. | ||
| * `BigInt64Array`/`BigUint64Array` elements are bigints and must be written | ||
| * with an `n` suffix, otherwise the emitted `new BigInt64Array([...])` throws. | ||
| * @param {import('./types.js').TypedArray} array | ||
| */ | ||
| function stringify_typed_array_elements(array) { | ||
| if (array instanceof BigInt64Array || array instanceof BigUint64Array) { | ||
| return Array.from(array, (element) => `${element}n`).join(','); | ||
| } | ||
| return array.toString(); | ||
| } | ||
| /** @param {number} num */ | ||
@@ -521,0 +551,0 @@ function get_name(num) { |
54499
3.95%1423
3.12%