Nerds Publishing Monstrosities
Have ideas to improve npm?Join in the discussion! »

deep-entriesTypeScript icon, indicating that this package has built-in type declarations

4.0.2 • Public • Published

npm version build status coverage status

deep-entries

A utility that resolves deeply nested key-values as variadic tuples.

TL;DR: examples

install

Node

> npm install deep-entries
const { deepEntries } = require('deep-entries')

Deno

// "https://unpkg.com/deep-entries@VERSION/deno.js" VERSION >= 4.0.1
import { deepEntries } from 'https://unpkg.com/deep-entries/deno.js'

exposes

type DeepEntry = [unknown, unknown, ...unknown[]]

Instances of DeepEntry will vary in length from one iteration to the next but are essentially arrays of at least 2 elements.

core functions

Typically input types will be object | array though other built-in types should yield intuitive results. Object types such as Date and RegExp will be treated as if primitive, i.e. returned as whole values and not enumerated.

deepEntries

function deepEntries<T = DeepEntry>(
    input: unknown,
    mapFn?: (entry: DeepEntry) => T
): T[]

deepEntriesIterator

function deepEntriesIterator<T = DeepEntry>(
    input: unknown,
    mapFn?: (entry: DeepEntry) => T
): IterableIterator<T>

map functions

delimitEntryBy

function delimitEntryBy<T = unknown>(
    delimiter: string
): (entry: DeepEntry) => [string, T]

delimitEntry

delimitEntry is an alias and is equivalent to delimitEntryBy('.')

function delimitEntry<T = unknown>(entry: DeepEntry): [string, T]

rotateEntryBy

function rotateEntryBy(n: number): (entry: DeepEntry) => DeepEntry

rotateEntry

rotateEntry is an alias and is equivalent to rotateEntryBy(1)

function rotateEntry(entry: DeepEntry): DeepEntry

misc. observations

In most use-cases DeepEntry keys will be of type string | number, though instances of Map will yield Map.prototype.entries(), meaning keys can be of any arbitrary type. If undesirable such results can be filtered out via the mapFn.

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
        }
    ]
}

Nested entries are returned as tuples of keys and a trailing value.

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

An optional map function is accepted 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 ]
// ]

The rotate-functions are intended for convenience when destructuring an entry. Since JavaScript requires rest parameters only as the last parameter, rotating by 1 puts the value first instead.

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 can effectively filter out entries by not returning them, i.e. returning undefined instead.

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 ]
// ]

Install

npm i deep-entries

DownloadsWeekly Downloads

911

Version

4.0.2

License

ISC

Unpacked Size

19.9 kB

Total Files

8

Last publish

Collaborators

  • avatar