Big News: Socket raises $60M Series C at a $1B valuation to secure software supply chains for AI-driven development.Announcement
Sign In

devalue

Package Overview
Dependencies
Maintainers
2
Versions
45
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

devalue - npm Package Compare versions

Comparing version
5.6.4
to
5.7.0
+44
src/base64.test.js
import * as assert from 'uvu/assert';
import { suite } from 'uvu';
import * as base64 from './base64.js';
const strings = [
'',
'a',
'ab',
'abc',
'a\r\nb',
'\xFF\xFE',
'\x00',
'\x00\x00\x00',
'the quick brown fox etc',
'é',
'中文',
'+/',
'😎'
];
const test = suite('base64_encode_decode');
const encoder = new TextEncoder();
const decoder = new TextDecoder();
for (const string of strings) {
test(string, () => {
const data = encoder.encode(string);
const with_buffer = base64.encode_buffer(data);
const with_legacy = base64.encode_legacy(data);
assert.equal(with_buffer, with_legacy);
assert.equal(decoder.decode(base64.decode_buffer(with_buffer)), string);
assert.equal(decoder.decode(base64.decode_legacy(with_legacy)), string);
if (typeof Uint8Array.fromBase64 === 'function') {
const with_native = base64.encode_native(data);
assert.equal(decoder.decode(base64.decode_native(with_native)), string);
}
});
}
test.run();
+5
-2
{
"name": "devalue",
"description": "Gets the job done when JSON.stringify can't",
"version": "5.6.4",
"version": "5.7.0",
"repository": "sveltejs/devalue",

@@ -23,2 +23,3 @@ "sideEffects": false,

"@js-temporal/polyfill": "^0.5.1",
"@types/node": "^24.12.0",
"dts-buddy": "^0.6.2",

@@ -36,4 +37,6 @@ "publint": "^0.3.12",

"build": "dts-buddy",
"test": "uvu"
"test": "uvu",
"bench": "node --allow-natives-syntax ./benchmarking/run.js",
"bench:compare": "node --allow-natives-syntax ./benchmarking/compare/index.js"
}
}

@@ -1,110 +0,60 @@

/**
* Base64 Encodes an arraybuffer
* @param {ArrayBuffer} arraybuffer
* @returns {string}
*/
export function encode64(arraybuffer) {
const dv = new DataView(arraybuffer);
let binaryString = "";
/* Baseline 2025 runtimes */
for (let i = 0; i < arraybuffer.byteLength; i++) {
binaryString += String.fromCharCode(dv.getUint8(i));
}
/** @type {(array_buffer: ArrayBuffer) => string} */
export function encode_native(array_buffer) {
return new Uint8Array(array_buffer).toBase64();
}
return binaryToAscii(binaryString);
/** @type {(base64: string) => ArrayBuffer} */
export function decode_native(base64) {
return Uint8Array.fromBase64(base64).buffer;
}
/**
* Decodes a base64 string into an arraybuffer
* @param {string} string
* @returns {ArrayBuffer}
*/
export function decode64(string) {
const binaryString = asciiToBinary(string);
const arraybuffer = new ArrayBuffer(binaryString.length);
const dv = new DataView(arraybuffer);
/* Node-compatible runtimes */
for (let i = 0; i < arraybuffer.byteLength; i++) {
dv.setUint8(i, binaryString.charCodeAt(i));
}
/** @type {(array_buffer: ArrayBuffer) => string} */
export function encode_buffer(array_buffer) {
return Buffer.from(array_buffer).toString('base64');
}
return arraybuffer;
/** @type {(base64: string) => ArrayBuffer} */
export function decode_buffer(base64) {
return Uint8Array.from(Buffer.from(base64, 'base64')).buffer;
}
const KEY_STRING =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
/* Legacy runtimes */
/**
* Substitute for atob since it's deprecated in node.
* Does not do any input validation.
*
* @see https://github.com/jsdom/abab/blob/master/lib/atob.js
*
* @param {string} data
* @returns {string}
*/
function asciiToBinary(data) {
if (data.length % 4 === 0) {
data = data.replace(/==?$/, "");
}
/** @type {(array_buffer: ArrayBuffer) => string} */
export function encode_legacy(array_buffer) {
const array = new Uint8Array(array_buffer);
let binary = '';
let output = "";
let buffer = 0;
let accumulatedBits = 0;
// the maximum number of arguments to String.fromCharCode.apply
// should be around 0xFFFF in modern engines
const chunk_size = 0x8000;
for (let i = 0; i < array.length; i += chunk_size) {
const chunk = array.subarray(i, i + chunk_size);
binary += String.fromCharCode.apply(null, chunk);
}
for (let i = 0; i < data.length; i++) {
buffer <<= 6;
buffer |= KEY_STRING.indexOf(data[i]);
accumulatedBits += 6;
if (accumulatedBits === 24) {
output += String.fromCharCode((buffer & 0xff0000) >> 16);
output += String.fromCharCode((buffer & 0xff00) >> 8);
output += String.fromCharCode(buffer & 0xff);
buffer = accumulatedBits = 0;
}
}
if (accumulatedBits === 12) {
buffer >>= 4;
output += String.fromCharCode(buffer);
} else if (accumulatedBits === 18) {
buffer >>= 2;
output += String.fromCharCode((buffer & 0xff00) >> 8);
output += String.fromCharCode(buffer & 0xff);
}
return output;
return btoa(binary);
}
/**
* Substitute for btoa since it's deprecated in node.
* Does not do any input validation.
*
* @see https://github.com/jsdom/abab/blob/master/lib/btoa.js
*
* @param {string} str
* @returns {string}
*/
function binaryToAscii(str) {
let out = "";
for (let i = 0; i < str.length; i += 3) {
/** @type {[number, number, number, number]} */
const groupsOfSix = [undefined, undefined, undefined, undefined];
groupsOfSix[0] = str.charCodeAt(i) >> 2;
groupsOfSix[1] = (str.charCodeAt(i) & 0x03) << 4;
if (str.length > i + 1) {
groupsOfSix[1] |= str.charCodeAt(i + 1) >> 4;
groupsOfSix[2] = (str.charCodeAt(i + 1) & 0x0f) << 2;
}
if (str.length > i + 2) {
groupsOfSix[2] |= str.charCodeAt(i + 2) >> 6;
groupsOfSix[3] = str.charCodeAt(i + 2) & 0x3f;
}
for (let j = 0; j < groupsOfSix.length; j++) {
if (typeof groupsOfSix[j] === "undefined") {
out += "=";
} else {
out += KEY_STRING[groupsOfSix[j]];
}
}
}
return out;
/** @type {(base64: string) => ArrayBuffer} */
export function decode_legacy(base64) {
const binary_string = atob(base64);
const len = binary_string.length;
const array = new Uint8Array(len);
for (let i = 0; i < len; i++) {
array[i] = binary_string.charCodeAt(i);
}
return array.buffer;
}
const native = typeof Uint8Array.fromBase64 === 'function';
const buffer = typeof process === 'object' && process.versions?.node !== undefined;
export const encode64 = native ? encode_native : buffer ? encode_buffer : encode_legacy;
export const decode64 = native ? decode_native : buffer ? decode_buffer : decode_legacy;

@@ -69,6 +69,3 @@ import { decode64 } from './base64.js';

const reviver =
revivers && Object.hasOwn(revivers, type)
? revivers[type]
: undefined;
const reviver = revivers && Object.hasOwn(revivers, type) ? revivers[type] : undefined;

@@ -121,11 +118,16 @@ if (reviver) {

case 'Object':
const object = Object(value[1]);
case 'Object': {
const wrapped_index = value[1];
if (Object.hasOwn(object, '__proto__')) {
throw new Error('Cannot parse an object with a `__proto__` property');
if (
typeof values[wrapped_index] === 'object' &&
values[wrapped_index][0] !== 'BigInt'
) {
// avoid infinite recusion in case of malformed input
throw new Error('Invalid input');
}
hydrated[index] = object;
hydrated[index] = Object(hydrate(wrapped_index));
break;
}

@@ -153,2 +155,3 @@ case 'BigInt':

case 'Uint16Array':
case 'Float16Array':
case 'Int32Array':

@@ -159,3 +162,4 @@ case 'Uint32Array':

case 'BigInt64Array':
case 'BigUint64Array': {
case 'BigUint64Array':
case 'DataView': {
if (values[value[1]][0] !== 'ArrayBuffer') {

@@ -170,8 +174,7 @@ // without this, if we receive malformed input we could

const buffer = hydrate(value[1]);
const typedArray = new TypedArrayConstructor(buffer);
hydrated[index] =
value[2] !== undefined
? typedArray.subarray(value[2], value[3])
: typedArray;
? new TypedArrayConstructor(buffer, value[2], value[3])
: new TypedArrayConstructor(buffer);

@@ -178,0 +181,0 @@ break;

@@ -55,3 +55,3 @@ import {

if (indexes.has(thing)) return indexes.get(thing);
if (indexes.has(thing)) return /** @type {number} */ (indexes.get(thing));

@@ -71,2 +71,4 @@ const index = p++;

throw new DevalueError(`Cannot stringify a function`, keys, thing, value);
} else if (typeof thing === 'symbol') {
throw new DevalueError(`Cannot stringify a Symbol primitive`, keys, thing, value);
}

@@ -85,7 +87,4 @@

case 'Boolean':
str = `["Object",${stringify_primitive(thing)}]`;
break;
case 'BigInt':
str = `["BigInt",${thing}]`;
str = `["Object",${flatten(thing.valueOf())}]`;
break;

@@ -211,5 +210,3 @@

for (const [key, value] of thing) {
keys.push(
`.get(${is_primitive(key) ? stringify_primitive(key) : '...'})`
);
keys.push(`.get(${is_primitive(key) ? stringify_primitive(key) : '...'})`);
str += `,${flatten(key)},${flatten(value)}`;

@@ -227,2 +224,3 @@ keys.pop();

case 'Uint16Array':
case 'Float16Array':
case 'Int32Array':

@@ -233,3 +231,4 @@ case 'Uint32Array':

case 'BigInt64Array':
case 'BigUint64Array': {
case 'BigUint64Array':
case 'DataView': {
/** @type {import("./types.js").TypedArray} */

@@ -239,9 +238,6 @@ const typedArray = thing;

const a = thing.byteOffset;
const b = a + thing.byteLength;
// handle subarrays
if (a > 0 || b !== typedArray.buffer.byteLength) {
const m = +/(\d+)/.exec(type)[1] / 8;
str += `,${a / m},${b / m}`;
if (typedArray.byteLength !== typedArray.buffer.byteLength) {
// to be used with `new TypedArray(buffer, byteOffset, length)`
str += `,${typedArray.byteOffset},${typedArray.length}`;
}

@@ -275,17 +271,7 @@

if (!is_plain_object(thing)) {
throw new DevalueError(
`Cannot stringify arbitrary non-POJOs`,
keys,
thing,
value
);
throw new DevalueError(`Cannot stringify arbitrary non-POJOs`, keys, thing, value);
}
if (enumerable_symbols(thing).length > 0) {
throw new DevalueError(
`Cannot stringify POJOs with symbolic keys`,
keys,
thing,
value
);
throw new DevalueError(`Cannot stringify POJOs with symbolic keys`, keys, thing, value);
}

@@ -353,3 +339,2 @@

if (type === 'string') return stringify_string(thing);
if (thing instanceof String) return stringify_string(thing.toString());
if (thing === void 0) return UNDEFINED.toString();

@@ -356,0 +341,0 @@ if (thing === 0 && 1 / thing < 0) return NEGATIVE_ZERO.toString();

@@ -1,1 +0,13 @@

export type TypedArray = Int8Array | Uint8Array | Uint8ClampedArray | Int16Array | Uint16Array | Int32Array | Uint32Array | Float32Array | Float64Array | BigInt64Array | BigUint64Array;
export type TypedArray =
| Int8Array
| Uint8Array
| Uint8ClampedArray
| Int16Array
| Uint16Array
| Float16Array
| Int32Array
| Uint32Array
| Float32Array
| Float64Array
| BigInt64Array
| BigUint64Array;

@@ -81,5 +81,3 @@ import {

for (const [key, value] of thing) {
keys.push(
`.get(${is_primitive(key) ? stringify_primitive(key) : '...'})`
);
keys.push(`.get(${is_primitive(key) ? stringify_primitive(key) : '...'})`);
walk(value);

@@ -95,2 +93,3 @@ keys.pop();

case 'Uint16Array':
case 'Float16Array':
case 'Int32Array':

@@ -102,2 +101,3 @@ case 'Uint32Array':

case 'BigUint64Array':
case 'DataView':
walk(thing.buffer);

@@ -121,17 +121,7 @@ return;

if (!is_plain_object(thing)) {
throw new DevalueError(
`Cannot stringify arbitrary non-POJOs`,
keys,
thing,
value
);
throw new DevalueError(`Cannot stringify arbitrary non-POJOs`, keys, thing, value);
}
if (enumerable_symbols(thing).length > 0) {
throw new DevalueError(
`Cannot stringify POJOs with symbolic keys`,
keys,
thing,
value
);
throw new DevalueError(`Cannot stringify POJOs with symbolic keys`, keys, thing, value);
}

@@ -154,2 +144,4 @@

}
} else if (typeof thing === 'symbol') {
throw new DevalueError(`Cannot stringify a Symbol primitive`, keys, thing, value);
}

@@ -192,8 +184,7 @@ }

case 'Boolean':
case 'BigInt':
return `Object(${stringify(thing.valueOf())})`;
case 'RegExp':
return `new RegExp(${stringify_string(thing.source)}, "${
thing.flags
}")`;
return `new RegExp(${stringify_string(thing.source)}, "${thing.flags}")`;

@@ -268,8 +259,6 @@ case 'Date':

const hole_cost = thing.length + 2;
const sparse_cost = (25 + d) + population * (d + 2);
const sparse_cost = 25 + d + population * (d + 2);
if (hole_cost > sparse_cost) {
const entries = populated_keys
.map((k) => `${k}:${stringify(thing[k])}`)
.join(',');
const entries = populated_keys.map((k) => `${k}:${stringify(thing[k])}`).join(',');
return `Object.assign(Array(${thing.length}),{${entries}})`;

@@ -299,2 +288,3 @@ }

case 'Uint16Array':
case 'Float16Array':
case 'Int32Array':

@@ -308,16 +298,14 @@ case 'Uint32Array':

if (counts.get(thing.buffer) === 1) {
if (!names.has(thing.buffer)) {
const array = new thing.constructor(thing.buffer);
str += `([${array}])`;
} else {
str += `([${stringify(thing.buffer)}])`;
str += `(${stringify(thing.buffer)})`;
}
const a = thing.byteOffset;
const b = a + thing.byteLength;
// handle subarrays
if (a > 0 || b !== thing.buffer.byteLength) {
const m = +/(\d+)/.exec(type)[1] / 8;
str += `.subarray(${a / m},${b / m})`;
if (thing.byteLength !== thing.buffer.byteLength) {
const start = thing.byteOffset / thing.BYTES_PER_ELEMENT;
const end = start + thing.length;
str += `.subarray(${start},${end})`;
}

@@ -328,2 +316,19 @@

case 'DataView': {
let str = `new DataView`;
if (!names.has(thing.buffer)) {
str += `(new Uint8Array([${new Uint8Array(thing.buffer)}]).buffer`;
} else {
str += `(${stringify(thing.buffer)}`;
}
// handle subviews
if (thing.byteLength !== thing.buffer.byteLength) {
str += `,${thing.startOffset},${thing.byteLength}`;
}
return str + ')';
}
case 'ArrayBuffer': {

@@ -346,10 +351,6 @@ const ui8 = new Uint8Array(thing);

const keys = Object.keys(thing);
const obj = keys
.map((key) => `${safe_key(key)}:${stringify(thing[key])}`)
.join(',');
const obj = keys.map((key) => `${safe_key(key)}:${stringify(thing[key])}`).join(',');
const proto = Object.getPrototypeOf(thing);
if (proto === null) {
return keys.length > 0
? `{${obj},__proto__:null}`
: `{__proto__:null}`;
return keys.length > 0 ? `{${obj},__proto__:null}` : `{__proto__:null}`;
}

@@ -392,2 +393,3 @@

case 'Boolean':
case 'BigInt':
values.push(`Object(${stringify(thing.valueOf())})`);

@@ -404,2 +406,10 @@ break;

case 'URL':
values.push(`new URL(${stringify_string(thing.toString())})`);
break;
case 'URLSearchParams':
values.push(`new URLSearchParams(${stringify_string(thing.toString())})`);
break;
case 'Array':

@@ -430,16 +440,64 @@ values.push(`Array(${thing.length})`);

case 'Int8Array':
case 'Uint8Array':
case 'Uint8ClampedArray':
case 'Int16Array':
case 'Uint16Array':
case 'Float16Array':
case 'Int32Array':
case 'Uint32Array':
case 'Float32Array':
case 'Float64Array':
case 'BigInt64Array':
case 'BigUint64Array': {
let str = `new ${type}`;
if (!names.has(thing.buffer)) {
const array = new thing.constructor(thing.buffer);
str += `([${array}])`;
} else {
str += `(${stringify(thing.buffer)})`;
}
// handle subarrays
if (thing.byteLength !== thing.buffer.byteLength) {
const start = thing.byteOffset / thing.BYTES_PER_ELEMENT;
const end = start + thing.length;
str += `.subarray(${start},${end})`;
}
values.push(`{}`);
statements.push(`${name}=${str}`);
break;
}
case 'DataView': {
let str = `new DataView`;
if (!names.has(thing.buffer)) {
str += `(new Uint8Array([${new Uint8Array(thing.buffer)}]).buffer`;
} else {
str += `(${stringify(thing.buffer)}`;
}
// handle subviews
if (thing.byteLength !== thing.buffer.byteLength) {
str += `,${thing.byteOffset},${thing.byteLength}`;
}
str += ')';
values.push(`{}`);
statements.push(`${name}=${str}`);
break;
}
case 'ArrayBuffer':
values.push(
`new Uint8Array([${new Uint8Array(thing).join(',')}]).buffer`
);
values.push(`new Uint8Array([${new Uint8Array(thing)}]).buffer`);
break;
default:
values.push(
Object.getPrototypeOf(thing) === null ? 'Object.create(null)' : '{}'
);
values.push(Object.getPrototypeOf(thing) === null ? 'Object.create(null)' : '{}');
Object.keys(thing).forEach((key) => {
statements.push(
`${name}${safe_prop(key)}=${stringify(thing[key])}`
);
statements.push(`${name}${safe_prop(key)}=${stringify(thing[key])}`);
});

@@ -451,5 +509,3 @@ }

return `(function(${params.join(',')}){${statements.join(
';'
)}}(${values.join(',')}))`;
return `(function(${params.join(',')}){${statements.join(';')}}(${values.join(',')}))`;
} else {

@@ -484,5 +540,3 @@ return str;

function safe_key(key) {
return /^[_$a-zA-Z][_$a-zA-Z0-9]*$/.test(key)
? key
: escape_unsafe_chars(JSON.stringify(key));
return /^[_$a-zA-Z][_$a-zA-Z0-9]*$/.test(key) ? key : escape_unsafe_chars(JSON.stringify(key));
}

@@ -499,9 +553,10 @@

function stringify_primitive(thing) {
if (typeof thing === 'string') return stringify_string(thing);
const type = typeof thing;
if (type === 'string') return stringify_string(thing);
if (thing === void 0) return 'void 0';
if (thing === 0 && 1 / thing < 0) return '-0';
const str = String(thing);
if (typeof thing === 'number') return str.replace(/^(-)?0\./, '$1.');
if (typeof thing === 'bigint') return thing + 'n';
if (type === 'number') return str.replace(/^(-)?0\./, '$1.');
if (type === 'bigint') return thing + 'n';
return str;
}

@@ -32,8 +32,6 @@ /** @type {Record<string, string>} */

export function is_primitive(thing) {
return Object(thing) !== thing;
return thing === null || (typeof thing !== 'object' && typeof thing !== 'function');
}
const object_proto_names = /* @__PURE__ */ Object.getOwnPropertyNames(
Object.prototype
)
const object_proto_names = /* @__PURE__ */ Object.getOwnPropertyNames(Object.prototype)
.sort()

@@ -83,5 +81,3 @@ .join('\0');

default:
return char < ' '
? `\\u${char.charCodeAt(0).toString(16).padStart(4, '0')}`
: '';
return char < ' ' ? `\\u${char.charCodeAt(0).toString(16).padStart(4, '0')}` : '';
}

@@ -88,0 +84,0 @@ }

@@ -59,6 +59,6 @@ import * as assert from 'uvu/assert';

arr[-1] = 'negative index';
arr[2**32 - 1] = 'too large index';
arr[2 ** 32 - 1] = 'too large index';
assert.equal(valid_array_indices(arr), ['0', '1']);
})
});
test.run();