
Security News
Crates.io Implements Trusted Publishing Support
Crates.io adds Trusted Publishing support, enabling secure GitHub Actions-based crate releases without long-lived API tokens.
get-wild - extract nested properties from an object with support for wildcards
"foo.*.bar"
"foo[-1].bar"
$ npm install get-wild
import { get } from 'get-wild'
const obj = { foo: { bar: { baz: 'quux' } } }
get(obj, 'foo.bar.baz') // "quux"
get(obj, 'foo.fizz.buzz') // undefined
get(obj, 'foo.fizz.buzz', 42) // 42
get(obj, ['foo', 'bar', 'baz']) // "quux"
get(obj, ['foo', 'fizz', 'buzz'], 42) // 42
const array = [
[{ value: 1 }, { value: 2 }, { value: 3 }],
[{ value: 4 }, { value: 5 }, { value: 6 }],
[{ value: 7 }, { value: 8 }, { value: 9 }],
]
get(array, '[1][-2].value') // 5
get(array, [-1, -1, 'value']) // 9
const data = {
users: {
'abc123': {
name: 'John Doe',
homepage: 'https://example.com/john-doe',
hobbies: ['eating', 'sleeping'],
},
'def345': {
name: 'Jane Doe',
homepage: 'https://example.com/jane-doe',
},
'ghi567': {
name: 'Nemo',
hobbies: ['singing', 'dancing'],
},
}
}
get(data, 'users[0].name') // "John Doe"
get(data, 'users[-1].name') // "Nemo"
get(data, 'users.*.name') // ["John Doe", "Jane Doe", "Nemo"]
get(data, 'users.*.homepage')
// ["https://example.com/john-doe", "https://example.com/jane-doe", undefined]
// also works with arrays
get(array, '[1].*.value') // [4, 5, 6]
get(array, '[-1].*.value') // [7, 8, 9]
get(data, 'users.*.hobbies')
// ["eating", "sleeping", undefined, "singing", "dancing"]
get(data, 'users.*.hobbies', [])
// ["eating", "sleeping", "singing", "dancing"]
get(data, 'users.**.hobbies')
// [["eating", "sleeping"], undefined, ["singing", "dancing"]]
This module exports a function which can be used to extract nested properties
from an object, including arrays and any other non-falsey values. This is
similar to the get
function provided by Lodash (and many other libraries),
but it adds the following features:
"foo.*.bar.*.baz"
"foo[-1][-2]"
In addition to the default get
implementation, get-wild exports a
builder function (getter
) which can be used to create a custom
get
with different options baked in, as well as curried
(data last) versions of get
and getter
to
facilitate functional composition and reuse.
I needed a small, dependency-free version of Lodash.get
with wildcard
support, and preferably with an option to filter out/exclude missing values.
Although there are a huge number of get
implementations on NPM, I could only
find one or two with wildcard support and none that are
standalone/dependency-free.
If you don't need support for wildcards, negative array-indices, or other options, there are smaller implementations, e.g. dlv.
The following types are referenced in the descriptions below.
type Options = {
collect?: Collect;
default?: any;
flatMap?: PropertyKey | false;
map?: PropertyKey | false;
parser?: string | Parser;
split?: Options['parser'];
}
interface Collect {
(value: {}) => Array<any>;
(value: {}, index: number) => ArrayLike<any>;
}
type Parser = (path: string) => Array<PropertyKey>;
type Path = PropertyKey | Array<PropertyKey>;
<T = any>(obj: any, path: Path, $default?: any) => T
import { get } from 'get-wild'
get(obj, 'foo.*.bar', [])
Takes an object, a path and an optional default value, and returns the value(s) found in the object at the specified path, or the default value (which is undefined by default) if the path doesn't exist or the value is undefined. The path can be supplied as a dotted expression (string), symbol or number, or an array of strings, symbols or numbers.
The syntax of dotted path expressions mostly matches that of regular JavaScript path expressions, with a few additions.
If there are no steps in the path, the object itself is returned (or the default value if the object is undefined).
Wildcard matching is performed by collect
ing an array of values
at the wildcard's location and recursively get
ting the remainder of
the path from each value. Wildcards can be used at any locations in a path to
turn a single lookup into an array of lookup results for values at that
location.
The values returned by wildcard matches can be customized. By default, *
flattens the results (using flatMap
), while **
uses
map
, which returns the results verbatim, though this mapping can be
configured (or disabled) via the map
and flatMap
options.
The get
export is generated by a builder function, getter
, which
can be used to create a custom get
function with different options.
(options?: Options) => <T = any>(obj: any, path: Path, $default?: any) => T
import { getter } from 'get-wild'
const get = getter({ split: '/' })
const obj = { foo: { bar: { baz: 42 } } }
get(obj, 'foo/bar/baz') // 42
getter
is a function which is used to build get
functions. The default
get
export is generated by calling getter
with no arguments, which uses the
following default options:
{
collect: Object.values,
default: undefined,
flatMap: '*',
map: '**',
split: defaultParser,
}
The behavior of get
can be configured by generating a custom version which
overrides these defaults, e.g.:
import { getter } from 'get-wild'
const split = path => path.split('/')
const get = getter({ split })
get(obj, 'foo/bar/*/quux')
Parser
import { getter, split } from 'get-wild'
import memoize from '@example/memoizer'
const memoized = memoize(split)
const get = getter({ split: memoized })
get(obj, '...')
The default function used by get
to turn a path expression (string)
into an array of steps (strings, symbols or numbers).
The array is not mutated, so, e.g., the function can be memoized to avoid re-parsing long/frequently-used paths. Alternatively, the path can be pre-parsed into an array (this is done automatically if the curried versions are used).
The parser supports an extended version of JavaScript's native path syntax, e.g. the path:
`a[-1].b[42].-1.42["c.d"].e['f g'].*.h["i \\"j\\" k"]['']`
is parsed into the following steps:
['a', -1, 'b', 42, '-1', '42', 'c.d', 'e', 'f g', '*', 'h', 'i "j" k', '']
Properties are either unquoted names (strings), bracketed integers, or
bracketed single or double-quoted strings. Integers can be signed (-1
, +42
)
or unsigned (42
). Unquoted names can contain any characters apart from spaces
(\s
), "
, '
, `
, [
, ]
, .
or \
.
Unquoted property names must be preceded by a dot unless the name is at the start of the path, in which case the dot must be omitted. Bracketed values must not be preceded by a dot.
If the path is an empty string, an empty array is returned.
<T = any>(path: Path, $default?: any) => <U = T>(obj: any) => U
import { get } from 'get-wild/fp'
const followers = get('followers.*.name', [])
followers(user) // get(user, ["followers", "*", "name"], [])
const allFollowers = users.flatMap(followers)
A curried version of get
which takes a path and an optional default
value and returns a function which takes an object and returns the value(s)
located at the path.
(options?: Options) => <T = any>(path: Path, $default?: any) => <U = T>(obj: any) => U
import { getter } from 'get-wild/fp'
const get = getter({ default: [], split: '.' })
const followers = get('followers.*.name')
followers(user) // get(user, ["followers", "*", "name"], [])
const allFollowers = users.flatMap(followers)
A variant of getter
which takes an optional Options
object and returns a curried version of get
with the options baked
in.
(value: {}) => Array<any>
(value: {}, index: number) => ArrayLike<any>
Object.values
import { getter } from 'get-wild'
const collect = value => {
return (value instanceof Map || value instanceof Set)
? Array.from(value.values())
: Object.values(value)
}
const map = new Map([
[1, { value: 'foo' }],
[2, { value: 'bar' }],
[3, { value: 'baz' }],
[4, { value: 'quux' }],
])
const obj = { map }
const get = getter({ collect })
get(obj, 'map[0].value') // "foo"
get(obj, 'map[-1].value') // "quux"
get(obj, 'map.*.value') // ["foo", "bar", "baz", "quux"]
The collect
function is used to convert a non-array value matched by a
wildcard or indexed by an integer into an array of values. If not supplied, it
defaults to Object.values
, which works with plain objects,
array-likes, and other non-nullish values. It can be overridden to add support
for traversable values which aren't plain objects or arrays, e.g. DOM elements
or ES6 Map and Set instances.
Note that the value passed to collect
is not falsey and not an array, as both
are handled without calling collect
.
For indexed access, the collect
function is passed the index as its second
argument and the return value can be an array-like rather than a full-blown
array. For wildcard matches, the index is omitted and the return value is an
an array. This distinction can be used to customize the result, e.g. to avoid
constructing a large array if only a single value is accessed, or to customize
the order of the values.
any
undefined
const get = getter({ default: [] })
get(data, 'users.*.hobbies')
// ["eating", "sleeping", "singing", "dancing"]
get(data, 'users.*.hobbies', [])
// ["eating", "sleeping", "singing", "dancing"]
get(data, 'users.*.hobbies', undefined)
// ["eating", "sleeping", undefined, "singing", "dancing"]
This option allows the default value to be baked into a get
function. If no
third argument is passed to the function, this value is returned for
missing/undefined properties. Otherwise, the supplied value is returned.
PropertyKey | false
"*"
import { getter } from 'get-wild'
const get = getter({ flatMap: '**', map: '*' })
get(data, 'users.**.hobbies', [])
// ["eating", "sleeping", "singing", "dancing"]
get(data, 'users.*.hobbies', [])
// [["eating", "sleeping"], [], ["singing", "dancing"]]
The token used to map values at the specified location and flatten the results.
If set to false, wildcard matching with flatMap
is disabled and the token is
treated as a regular property name.
Wildcard matching with flatMap
behaves in a similar way to directory/filename
matching with globs (minus the pattern matching). The selected properties
(at the end of the path) are returned as direct children of the resulting array
(wildcard matches always return an array), either as matched results or as
default values if there's no match.
For example, with the default mapping, a path such as
accounts.active.*.followers.*.name
, which extracts the names of all followers
of active accounts, would return an array of account names interspersed with
default values where an account doesn't have any followers (or if a follower's
name is undefined), e.g.:
get(data, 'accounts.active.*.followers.*.name')
// ["john", "paul", undefined, "george", undefined, "ringo"]
This can be reduced to just the names by setting the default value to an empty array, e.g.:
get(data, 'accounts.active.*.followers.*.name', [])
// ["john", "paul", "george", "ringo"]
Note that with the default parser, the token must be a syntactically-valid name, e.g. this doesn't work:
import { getter } from 'get-wild'
const obj = { foo: [{ bar: 1 }, { bar: 2 }] }
const get = getter({ flatMap: '[]' })
get(obj, 'foo.[].bar') // SyntaxError: Invalid step @ 3: "foo.[].bar"
If a custom parser is supplied, any token can be used:
const get = getter({ flatMap: '[]', split: '.' })
get(obj, 'foo.[].bar') // [1, 2]
PropertyKey | false
"**"
import { getter } from 'get-wild'
const get = getter({ map: '*', flatMap: '**' })
get(data, 'users.*.hobbies', [])
// [["eating", "sleeping"], [], ["singing", "dancing"]]
get(data, 'users.**.hobbies', [])
// ["eating", "sleeping", "singing", "dancing"]
The token used to map values at the specified location without flattening the results.
Matching with map
selects the same values as flatMap
, but they remain
nested inside arrays, with each enclosing map
in the path adding another
layer of wrapping.
If set to false, wildcard matching with map
is disabled and the token is
treated as a regular property name.
string | Parser
split
import { getter } from 'get-wild'
const split = path => path.split('.')
const get = getter({ split })
const obj = { '': { '': 42 } }
get(obj, '.') // 42
A function which takes a path expression (string) and parses it into an array of property names (strings, symbols or numbers). If not supplied, a default parser which supports an extended version of JavaScript's native path syntax is used.
As a shortcut, if the value is a string, a function which splits the path on that string is used, i.e. the following are equivalent:
const split = path => path.split('.')
const get = getter({ split })
const get = getter({ split: '.' })
The following NPM scripts are available:
3.0.2
Copyright © 2020-2022 by chocolateboy.
This is free software; you can redistribute it and/or modify it under the terms of the MIT license.
3.0.2 - 2022-04-30
Collect
exportFAQs
Pluck nested properties from an object with support for wildcards
We found that get-wild demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Crates.io adds Trusted Publishing support, enabling secure GitHub Actions-based crate releases without long-lived API tokens.
Research
/Security News
Undocumented protestware found in 28 npm packages disrupts UI for Russian-language users visiting Russian and Belarusian domains.
Research
/Security News
North Korean threat actors deploy 67 malicious npm packages using the newly discovered XORIndex malware loader.