Skip to content

Commit 3770846

Browse files
fix: emit valid JS for BigInt64Array and BigUint64Array in uneval (#171)
uneval rendered typed-array elements by interpolating the array directly, which calls Array#toString and produces bare numbers (e.g. new BigInt64Array([1,2,3])). BigInt64Array/BigUint64Array constructors require bigint elements, so the emitted code threw 'Cannot convert 1 to a BigInt' when evaluated. Emit bigint elements with an 'n' suffix. stringify/parse were unaffected (they encode the underlying buffer as base64).
1 parent b9ed985 commit 3770846

3 files changed

Lines changed: 41 additions & 4 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"devalue": patch
3+
---
4+
5+
fix: emit valid JS for `BigInt64Array` and `BigUint64Array` in `uneval`

‎src/uneval.js‎

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -290,8 +290,7 @@ export function uneval(value, replacer) {
290290
let str = `new ${type}`;
291291

292292
if (!names.has(thing.buffer)) {
293-
const array = new thing.constructor(thing.buffer);
294-
str += `([${array}])`;
293+
str += `([${stringify_typed_array_elements(new thing.constructor(thing.buffer))}])`;
295294
} else {
296295
str += `(${stringify(thing.buffer)})`;
297296
}
@@ -445,8 +444,7 @@ export function uneval(value, replacer) {
445444
let str = `new ${type}`;
446445

447446
if (!names.has(thing.buffer)) {
448-
const array = new thing.constructor(thing.buffer);
449-
str += `([${array}])`;
447+
str += `([${stringify_typed_array_elements(new thing.constructor(thing.buffer))}])`;
450448
} else {
451449
str += `(${stringify(thing.buffer)})`;
452450
}
@@ -515,6 +513,20 @@ export function uneval(value, replacer) {
515513
}
516514
}
517515

516+
/**
517+
* Serialize the elements of a typed array as a comma-separated list.
518+
* `BigInt64Array`/`BigUint64Array` elements are bigints and must be written
519+
* with an `n` suffix, otherwise the emitted `new BigInt64Array([...])` throws.
520+
* @param {import('./types.js').TypedArray} array
521+
*/
522+
function stringify_typed_array_elements(array) {
523+
if (array instanceof BigInt64Array || array instanceof BigUint64Array) {
524+
return Array.from(array, (element) => `${element}n`).join(',');
525+
}
526+
527+
return array.toString();
528+
}
529+
518530
/** @param {number} num */
519531
function get_name(num) {
520532
let name = '';

‎test/index.test.js‎

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,18 @@ const fixtures = {
299299
js: 'new Uint8Array([1,2,3])',
300300
json: '[["Uint8Array",1],["ArrayBuffer","AQID"]]'
301301
},
302+
{
303+
name: 'BigInt64Array',
304+
value: new BigInt64Array([1n, -2n, 3n]),
305+
js: 'new BigInt64Array([1n,-2n,3n])',
306+
json: '[["BigInt64Array",1],["ArrayBuffer","AQAAAAAAAAD+/////////wMAAAAAAAAA"]]'
307+
},
308+
{
309+
name: 'BigUint64Array',
310+
value: new BigUint64Array([1n, 2n, 3n]),
311+
js: 'new BigUint64Array([1n,2n,3n])',
312+
json: '[["BigUint64Array",1],["ArrayBuffer","AQAAAAAAAAACAAAAAAAAAAMAAAAAAAAA"]]'
313+
},
302314
{
303315
name: 'ArrayBuffer',
304316
value: new Uint8Array([1, 2, 3]).buffer,
@@ -739,6 +751,14 @@ const fixtures = {
739751
json: '[[1,1],["DataView",2,2,4],["ArrayBuffer","AAECAwQFBgcICQ=="]]'
740752
},
741753

754+
{
755+
name: 'BigInt64Array (repetition)',
756+
value: ((array) => [array, array])(new BigInt64Array([1n, 2n, 3n])),
757+
js: '(function(a){a=new BigInt64Array([1n,2n,3n]);return [a,a]}({}))',
758+
json: '[[1,1],["BigInt64Array",2],["ArrayBuffer","AQAAAAAAAAACAAAAAAAAAAMAAAAAAAAA"]]',
759+
validate: ([a, b]) => assert.is(a, b)
760+
},
761+
742762
{
743763
name: 'Temporal.Instant (repetition)',
744764
value: ((instant) => [instant, instant])(

0 commit comments

Comments
 (0)