Package Exports
- get-wild
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 (get-wild) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.
Readme
get-wild
- NAME
- FEATURES
- INSTALLATION
- SYNOPSIS
- DESCRIPTION
- TYPES
- EXPORTS
- OPTIONS
- DEVELOPMENT
- COMPATIBILITY
- SEE ALSO
- VERSION
- AUTHOR
- COPYRIGHT AND LICENSE
NAME
get-wild - pluck nested properties from an object with support for wildcards
FEATURES
- configurable wildcard support, e.g.
"foo.*.bar"
- support for negative array indices, e.g.
"foo[-1].bar"
- pluggable path parser
- no dependencies
- < 700 B minified + gzipped
- fully typed (TypeScript)
- CDN builds (UMD) - jsDelivr, unpkg
INSTALLATION
$ npm install get-wild
SYNOPSIS
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
Negative array indices
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
Wildcards
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.*.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]
Flatten results
get(data, 'users.*.hobbies')
// ["eating", "sleeping", undefined, "singing", "dancing"]
Remove missing results
get(data, 'users.*.hobbies', [])
// ["eating", "sleeping", "singing", "dancing"]
Raw results
get(data, 'users.**.hobbies')
// [["eating", "sleeping"], undefined, ["singing", "dancing"]]
DESCRIPTION
This module exports a function which can be used to pluck 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:
- wildcard support, e.g.
"foo.*.bar.*.baz"
- support for negative array indices, e.g.
"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.
Why?
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.
Why not?
If you don't need support for wildcards, negative array-indices, or other options, there are smaller implementations, e.g. just-safe-get.
TYPES
The following types are referenced in the descriptions below.
type Options = {
collect?: (value: {}) ⇒ Array<any>;
default?: any;
flatMap?: PropertyKey | false;
map?: PropertyKey | false;
parse?: (path: string) => Array<PropertyKey>;
};
type Path = PropertyKey | Array<PropertyKey>;
EXPORTS
get
- Type:
(obj: any, path: Path, $default?: any) ⇒ any
import { get } from 'get-wild'
get(obj, 'foo.*.bar', [])
get
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 steps (strings, symbols or numbers).
The syntax for 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.
getter
- Type:
(options?: Options) ⇒ typeof get
import { getter } from 'get-wild'
const parser = path => path.split('.')
const get = getter({ parser })
const obj = { '': { '': 42 } }
get(obj, '.') // 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: '**',
parser: 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 parser = path => path.split('/')
const get = getter({ parser })
get(obj, 'foo/bar/*/quux')
parser
- Type:
(path: string) ⇒ Array<PropertyKey>
import { getter, parser } from 'get-wild'
import memoize from '@example/memoizer'
const memoized = memoize(parser)
const get = getter({ parser: memoized })
get(obj, '...')
The default parser used by get
to turn a path expression into an
array of steps (strings, symbols and numbers).
The array of steps used inside the get
function is not mutated, so, e.g., the
parser can be memoized (or steps can be pre-parsed) to avoid re-parsing
long/frequently-used paths.
Syntax
The parser supports an extended version of JavaScript's native path syntax, e.g. the path:
a[-1].b[42]["c.d"].e['f g'].*.h["i \\"j\\" k"][""]
is parsed into the following steps:
["a", -1, "b", 42, "c.d", "e", "f g", "*", "h", 'i "j" k', ""]
Property names are either unquoted (strings), bracketed integers, or bracketed
single or double-quoted strings. Unquoted names can contain any characters
apart from spaces (\s
), "
, '
, `
, [
, ]
, .
and \
.
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.
OPTIONS
collect
- Type:
(value: {}) ⇒ Array<any>
- Default:
Object.values
import { getter } from 'get-wild'
const collect = value => {
if (value instanceof Map || value instanceof Set) {
return Array.from(value.values())
} else {
return 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.*.value')
// ["foo", "bar", "baz", "quux"]
The collect
function is used to convert a value under a wildcard token into
an array of values. If not supplied, it defaults to
Object.values
, which works with objects, arrays, and other
non-nullish values. Can be overridden to add support for traversable values
that aren't plain objects, e.g. 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
.
default
- Type:
any
- Default:
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.
flatMap
- Type:
PropertyKey | false
- Default:
"*"
import { getter } from 'get-wild'
const get = getter({ flatMap: '**', map: '*' })
get(obj, 'foo.**.bar.baz')
The token used to map values at the specified location and flatten the results.
If an empty array is supplied as the third argument to get
,
missing/undefined values are removed from the result.
If set to false, wildcard matching with flatMap
is disabled and the token is
treated as a regular property name.
Usage
Wildcard matching with flatMap
behaves in a similar way to basic
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 an account'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"]
Syntax
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 parser = path => path.split('.')
const get = getter({ flatMap: '[]', parser })
get(obj, 'foo.[].bar') // [1, 2]
map
- Type:
PropertyKey | false
- Default:
"**"
import { getter } from 'get-wild'
const get = getter({ map: '*', flatMap: '**' })
get(obj, 'foo.*.bar.baz')
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.
parser
- Type:
(path: string) ⇒ Array<PropertyKey>
import { getter } from 'get-wild'
const parser = path => path.split('.')
const get = getter({ parser })
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 is used which supports an extended version of JavaScript's native path syntax.
DEVELOPMENT
NPM Scripts
The following NPM scripts are available:
- build - compile the library for testing and save to the target directory
- build:release - compile the library for release and save to the target directory
- clean - remove the target directory and its contents
- doctoc - generate the README's TOC (table of contents)
- rebuild - clean the target directory and recompile the library
- repl - launch a node REPL with the library loaded
- test - recompile the library and run the test suite
- test:run - run the test suite
- typecheck - sanity check the library's type definitions
COMPATIBILITY
- Environments with support for ES6 and
Array#flat
/Array#flatMap
(polyfill)
SEE ALSO
VERSION
1.0.1
AUTHOR
COPYRIGHT AND LICENSE
Copyright © 2020 by chocolateboy.
This is free software; you can redistribute it and/or modify it under the terms of the Artistic License 2.0.