npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

deep-entries

v5.0.2

Published

wrangle deep nested object entries

Downloads

854

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