From 49e9082d0f1901152ee68bb5f9a5d87ca20eb143 Mon Sep 17 00:00:00 2001 From: Alex Kostyukov Date: Sat, 22 Apr 2023 09:25:49 +0300 Subject: [PATCH] Make `deepKeys` include empty arrays and objects (#105) --- index.d.ts | 6 +++++- index.js | 4 +++- readme.md | 6 +++++- test.js | 14 ++++++++++++++ 4 files changed, 27 insertions(+), 3 deletions(-) diff --git a/index.d.ts b/index.d.ts index 0eaa13a..8e22a07 100644 --- a/index.d.ts +++ b/index.d.ts @@ -133,7 +133,7 @@ console.log(getProperty(object, escapedPath)); export function escapePath(path: string): string; /** -Returns an array of every path. Plain objects are deeply recursed and are not themselves included. +Returns an array of every path. Non-empty plain objects and arrays are deeply recursed and are not themselves included. This can be useful to help flatten an object for an API that only accepts key-value pairs or for a tagged template literal. @@ -148,12 +148,16 @@ const user = { first: 'Richie', last: 'Bendall', }, + activeTasks: [], + currentProject: null }; for (const property of deepKeys(user)) { console.log(`${property}: ${getProperty(user, property)}`); //=> name.first: Richie //=> name.last: Bendall + //=> activeTasks: [] + //=> currentProject: null } ``` */ diff --git a/index.js b/index.js index c4abc95..e699982 100644 --- a/index.js +++ b/index.js @@ -3,6 +3,8 @@ const isObject = value => { return value !== null && (type === 'object' || type === 'function'); }; +const isEmptyObject = value => isObject(value) && Object.keys(value).length === 0; + const disallowedKeys = new Set([ '__proto__', 'prototype', @@ -316,7 +318,7 @@ function stringifyPath(pathSegments) { } function * deepKeysIterator(object, currentPath = []) { - if (!isObject(object)) { + if (!isObject(object) || isEmptyObject(object)) { if (currentPath.length > 0) { yield stringifyPath(currentPath); } diff --git a/readme.md b/readme.md index b0ed66e..a5d7baf 100644 --- a/readme.md +++ b/readme.md @@ -110,7 +110,7 @@ console.log(getProperty(object, escapedPath)); ### deepKeys(object) -Returns an array of every path. Plain objects are deeply recursed and are not themselves included. +Returns an array of every path. Non-empty plain objects and arrays are deeply recursed and are not themselves included. This can be useful to help flatten an object for an API that only accepts key-value pairs or for a tagged template literal. @@ -122,12 +122,16 @@ const user = { first: 'Richie', last: 'Bendall', }, + activeTasks: [], + currentProject: null }; for (const property of deepKeys(user)) { console.log(`${property}: ${getProperty(user, property)}`); //=> name.first: Richie //=> name.last: Bendall + //=> activeTasks: [] + //=> currentProject: null } ``` diff --git a/test.js b/test.js index 556d810..17cf1c7 100644 --- a/test.js +++ b/test.js @@ -413,6 +413,8 @@ test('escapePath', t => { test('deepKeys', t => { const object = { + eo: {}, + ea: [], 'a.b': { c: { d: [1, 2, { @@ -420,6 +422,11 @@ test('deepKeys', t => { }], e: '🦄', f: 0, + h: {}, + i: [], + nu: null, + na: Number.NaN, + un: undefined, }, '': { a: 0, @@ -432,11 +439,18 @@ test('deepKeys', t => { const keys = deepKeys(object); t.deepEqual(keys, [ + 'eo', + 'ea', 'a\\.b.c.d[0]', 'a\\.b.c.d[1]', 'a\\.b.c.d[2].g', 'a\\.b.c.e', 'a\\.b.c.f', + 'a\\.b.c.h', + 'a\\.b.c.i', + 'a\\.b.c.nu', + 'a\\.b.c.na', + 'a\\.b.c.un', 'a\\.b..a', '.a', ]);