JSPM

  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 920
  • Score
    100M100P100Q101590F
  • License ISC

flatten nested object entries

Package Exports

  • deep-entries

This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (deep-entries) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.

Readme

npm version build status coverage status conventional commits

deep-entries

A utility for returning deeply nested key-values as tuples of varying length.

exposes

core functions

  • deepEntries
    => ( input: Object | Array, map?: function ): Array[]
  • deepEntriesIterator
    => ( input: Object | Array, map?: function ): Iterator

map functions

  • delimitEntryBy
    => ( input: string ): function
  • delimitEntry
    => ( input: Array ): Array
  • rotateEntryBy
    => ( input: integer ): function
  • rotateEntry
    => ( input: Array ): Array

observations

  • instances of Set will be converted to arrays
  • instances of Map will yield Map.prototype.entries()
    (limited support / usefulness TBD)
  • delimitEntry is an alias and is equivalent to delimitEntryBy('.')
  • rotateEntry is an alias and is equivalent to rotateEntryBy(1)

examples

» RunKit

usage

const {
    deepEntries,
    deepEntriesIterator,
    delimitEntryBy,
    rotateEntryBy,
    delimitEntry,
    rotateEntry
} = require('deep-entries')

A shape made up of both Objects or Arrays can be described in terms of deep entries. Only enumerable own-members will be returned and iteration will honour index and / or insertion order. The following examples will consume this input:

const input = {
    foo: 1,
    bar: {
        deep: {
            key: 2
        }
    },
    baz: [
        3,
        [4, 5],
        {
            key: 6
        }
    ]
}

deepEntries() will return nested entries as arrays of varying length, with the value always trailing.

deepEntries(input)
// [
//     [ 'foo', 1 ],
//     [ 'bar', 'deep', 'key', 2 ],
//     [ 'baz', 0, 3 ],
//     [ 'baz', 1, 0, 4 ],
//     [ 'baz', 1, 1, 5 ],
//     [ 'baz', 2, 'key', 6 ]
// ]

deepEntries() will accept an optional map function as a second parameter.

deepEntries(input, delimitEntry)
// [
//     [ 'foo', 1 ],
//     [ 'bar.deep.key', 2 ],
//     [ 'baz.0', 3 ],
//     [ 'baz.1.0', 4 ],
//     [ 'baz.1.1', 5 ],
//     [ 'baz.2.key', 6 ]
// ]

deepEntries() is an alias that collects all entries from a deepEntriesIterator(), which is also exposed to aid in performant iteration of larger structures. The rotateEntry map function rotates the entry array by 1 (i.e. putting the value first), allowing for more convenient destructuring of an entry.

for (let [value, ...keys] of deepEntriesIterator(input, rotateEntry)) {
    console.log(keys, value)
}
// [ 'foo' ] 1
// [ 'bar', 'deep', 'key' ] 2
// [ 'baz', 0 ] 3
// [ 'baz', 1, 0 ] 4
// [ 'baz', 1, 1 ] 5
// [ 'baz', 2, 'key' ] 6

It's worth noting that objects can have assigned iterators too.

const { withIterator } = require('with-iterator')
const withDeepEntriesIterator = withIterator(function*() {
    yield* deepEntriesIterator(this, delimitEntryBy(':'))
})
withDeepEntriesIterator(input)
Array.from(input)
// [
//     [ 'foo', 1 ],
//     [ 'bar:deep:key', 2 ],
//     [ 'baz:0', 3 ],
//     [ 'baz:1:0', 4 ],
//     [ 'baz:1:1', 5 ],
//     [ 'baz:2:key', 6 ]
// ]

filtering

The map functions passed to deepEntries() and deepEntriesIterator() can effectively filter out entries by not returning them - i.e. returning undefined.

const { last: getValue } = require('ramda')
deepEntries(input, entry => (getValue(entry) > 3 ? entry : undefined))
// [
//     [ 'baz', 1, 0, 4 ],
//     [ 'baz', 1, 1, 5 ],
//     [ 'baz', 2, 'key', 6 ]
// ]

The map functions follow a pattern of returning undefined if passed undefined such that they may be composed with filters, without throwing errors.

const { pipe } = require('ramda')
const atDepth = n => entry => {
    if (entry.length === 2 + n) return entry
}
deepEntries(
    input,
    pipe(
        atDepth(1),
        delimitEntry
    )
)
// [
//     [ 'baz.0', 3 ]
// ]