From 1c8b13295a700ef21b5c9801a6b1b1f78fd287e5 Mon Sep 17 00:00:00 2001 From: Yarchik Date: Mon, 22 Jun 2026 20:13:50 +0100 Subject: [PATCH] fix: keep an empty-string key on unflatten instead of renaming it to 0 `getkey` coerces a key to a number when it is numeric, guarding only against NaN. But `Number('')` is `0` (not NaN), so a top-level empty-string key was turned into the index 0, breaking the documented round-trip: unflatten(flatten({ '': 1, x: 2 })) // { '0': 1, x: 2 }, expected { '': 1, x: 2 } unflatten(flatten({ a: { '': 1 } })) // { a: [1] } flatten preserves `''` losslessly, so only unflatten corrupted it. Return the empty string as-is before the numeric coercion. Added a round-trip test. --- index.js | 4 ++++ test/test.js | 6 ++++++ 2 files changed, 10 insertions(+) diff --git a/index.js b/index.js index 42e1ddc..d86a68f 100644 --- a/index.js +++ b/index.js @@ -63,6 +63,10 @@ export function unflatten (target, opts) { // safely ensure that the key is // an integer. function getkey (key) { + // `Number('')` is 0 (not NaN), so an empty-string key would be coerced to + // the numeric index 0 and renamed; keep it as-is. + if (key === '') return key + const parsedKey = Number(key) return ( diff --git a/test/test.js b/test/test.js index ef01c9b..6c74eaf 100644 --- a/test/test.js +++ b/test/test.js @@ -566,6 +566,12 @@ describe('Arrays', function () { })) }) + test('Should keep an empty-string key instead of renaming it to 0', function () { + assert.deepStrictEqual({ '': 1, x: 2 }, unflatten({ '': 1, x: 2 })) + assert.deepStrictEqual({ a: { '': 1 } }, unflatten({ 'a.': 1 })) + assert.deepStrictEqual({ '': 1, x: 2 }, unflatten(flatten({ '': 1, x: 2 }))) + }) + test('Array typed objects should be restored by unflatten', function () { assert.strictEqual( Object.prototype.toString.call(['foo', 'bar'])