JSPM

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

return a flat array of key-values from a deep nested structure

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

github npm version deno version coverage status

deep-entries

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

TL;DR: examples

install

Node

> npm install deep-entries
import { deepEntries } = from 'deep-entries'

Deno

Either / or:

import { deepEntries } from 'npm:deep-entries'
import { deepEntries } from 'https://deno.land/x/deepentries@v5/src/index.mjs'

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. Objects resulting in a circular reference will be ignored.

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

» StackBlitz examples

usage

import {
    deepEntries,
    deepEntriesIterator,
    delimitEntryBy,
    rotateEntryBy,
    delimitEntry,
    rotateEntry,
} from '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

filtering

The map-functions can also filter out entries by not returning them, i.e. explicitly returning undefined instead.

const getValue = (entry) => entry[entry.length - 1]
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 early if passed undefined, such that they may be composed with filters and not throw errors.

const pipe =
    (...fns) =>
    (input) =>
        fns.reduce((acc, fn) => fn(acc), input)

const atDepth = (n) => (entry) => {
    if (entry.length === 2 + n) return entry
}

deepEntries(input, pipe(atDepth(1), delimitEntry))
// [
//     [ 'baz.0', 3 ]
// ]