wild-wild-path alternatives and similar libraries
Based on the "Functional Programming" category.
Alternatively, view wild-wild-path alternatives based on common mentions on social networks and blogs.
-
scramjet
Public tracker for Scramjet Cloud Platform, a platform that bring data from many environments together.
CodeRabbit: AI Code Reviews for Developers
* Code Quality Rankings and insights are calculated and provided by Lumnify.
They vary from L1 to L5 with "L5" being the highest.
Do you think we are missing an alternative of wild-wild-path or a related project?
README
π€ Object property paths with wildcards and regexps. π΅
Get/set object properties using:
- βοΈ [Dot-delimited paths](#%EF%B8%8F-deep-properties):
foo.bar.0.baz
- β [Wildcards](#-wildcards):
foo.*
,**.bar
- πΊοΈ [Regexps](#%EF%B8%8F-regexps):
foo./ba?/
- ποΈ [Slices](#%EF%B8%8F-array-slices):
foo.0:2
- π [Unions](#-unions):
foo bar baz
Install
npm install wild-wild-path
This package is an ES module and must be loaded using
an import
or import()
statement,
not require()
.
API
Methods
get(target, query, options?)
target
: Target
\
query
: Query
\
options
: Options?
\
Return value: any | undefined
Return the first property matching the query
.
const target = { settings: { colors: ['red', 'blue'] } }
get(target, 'settings.colors.0') // 'red'
get(target, ['settings', 'colors', 0]) // 'red'
has(target, query, options?)
target
: Target
\
query
: Query
\
options
: Options?
\
Return value: boolean
Return whether the query
matches any property.
const target = { settings: { lastName: undefined, colors: ['red', 'blue'] } }
has(target, 'settings.firstName') // false
has(target, ['settings', 'firstName']) // false
has(target, 'settings.lastName') // true
list(target, query, options?)
target
: Target
\
query
: Query
\
options
: Options?
\
Return value: any[]
Return all properties matching the query
, as an array.
<!-- eslint-disable require-unicode-regexp -->
const target = {
userOne: { firstName: 'John', lastName: 'Doe', age: 72 },
userTwo: { firstName: 'Alice', colors: ['red', 'blue', 'yellow'] },
}
list(target, 'userOne.firstName userTwo.colors.0') // ['John', 'red']
list(target, [
['userOne', 'firstName'],
['userTwo', 'colors', 0],
]) // ['John', 'red']
list(target, 'userOne./Name/') // ['John', 'Doe']
list(target, ['userOne', /Name/]) // ['John', 'Doe']
list(target, 'userTwo.colors.*') // ['red', 'blue', 'yellow']
list(target, 'userTwo.colors.0:2') // ['red', 'blue']
list(target, '**.firstName') // ['John', 'Alice']
list(target, 'userOne.*', { entries: true })
// [
// { value: 'John', path: ['userOne', 'firstName'], missing: false },
// { value: 'Doe', path: ['userOne', 'lastName'], missing: false },
// { value: 72, path: ['userOne', 'age'], missing: false },
// ]
iterate(target, query, options?)
target
: Target
\
query
: Query
\
options
: Options?
\
Return value: Iterable<any>
Return all properties matching the query
, as an
iterable.
This is slower than list()
but uses less memory.
<!-- eslint-disable fp/no-loops -->
const target = { settings: { colors: ['red', 'blue'] } }
for (const color of iterate(target, 'settings.colors.*')) {
console.log(color) // 'red', 'blue'
}
set(target, query, value, options?)
target
: Target
\
query
: Query
\
value
: any
\
options
: Options?
\
Return value: Target
Sets all properties matching the query
. The return value is a deep clone
unless the mutate
option is true
.
const target = { colors: ['red', 'blue'] }
set(target, 'colors.0', 'yellow') // ['yellow', 'blue']
set(target, ['colors', 0], 'yellow') // ['yellow', 'blue']
set(target, 'colors.-1', 'yellow') // ['red', 'yellow']
set(target, 'colors.-0', 'yellow') // ['red', 'blue', 'yellow']
set(target, 'colors.*', 'yellow') // ['yellow', 'yellow']
set({}, 'user.0.color', 'red') // { user: [{ color: 'red' }] }
set({}, 'user.0.color', 'red', { missing: false }) // {}
remove(target, query, options?)
target
: Target
\
query
: Query
\
options
: Options?
\
Return value: Target
Delete all properties matching the query
. The return value is a deep clone
unless the mutate
option is true
.
<!-- eslint-disable require-unicode-regexp -->
const target = { user: { firstName: 'John', lastName: 'Doe', age: 72 } }
remove(target, 'user.lastName') // { user: { firstName: 'John', age: 72 } }
remove(target, 'user./Name/') // { user: { age: 72 } }
remove(target, ['user', /Name/]) // { user: { age: 72 } }
Functional utilities
wild-wild-utils
is a separate
library which provides with additional, higher-level methods:
map()
,
merge()
,
push()
,
unshift()
,
find()
,
pick()
,
include()
,
exclude()
,
flatten()
.
Target
The target value must be an object or an array.
Queries
There are two equivalent formats for queries: strings and arrays.
- Query strings are friendlier to CLI usage, more expressive, and easier to serialize.
- Query arrays are friendlier to programmatic usage, and faster. Also, they do not require escaping, so they should be used when the input is dynamic or user-provided to prevent injection attacks.
Query strings
βοΈ Deep properties
# Deep properties of objects or arrays.
# Dots are used for array indices, not brackets.
# Symbol properties are always ignored.
user.colors.0
π Unions
# Unions ("or") of queries are space-delimited.
# The string must not be empty.
colors name age
β Wildcards
# Shallow wildcards target all properties/items of a single object/array
user.*
# Deep wildcards target all properties/items of 0, 1 or many objects/arrays
user.**
**.colors
πΊοΈ Regexps
# Regexps match property names
user./name/
# Flags can be used, e.g. to make it case-insensitive
user./name/i
# ^ $ must be used to match from the beginning or until the end
user./^name$/i
π΅ Arrays indices
# Array indices are integers
user.colors.0
# Array indices can be negative.
# -1 is the last item.
# -0 is the item after it, which can be used to append.
user.colors.-1
ποΈ Array slices
# Array slices. Goes from the start (included) to the end index (excluded).
user.colors.0:2
# The start index defaults to 0, i.e. the beginning
user.colors.:2
# The end index defaults to -0, i.e. the end
user.colors.0:
user.colors.:
πͺ¨ Escaping
# Dots, spaces and backslashes in property names must be escaped
name\\ with\\ spaces
name\\.with\\.dots
name\\\\with\\\\backslashes
# Ambiguous property names must be escaped with a backslash at the beginning.
# This includes properties that:
# - Are integers but are not array elements
# - Have multiple slashes and start with one
name.\\0
name.\\/not_a_regexp/
π¨ Root and empty strings
# A leading dot can optionally be used. It is ignored.
user.colors
.user.colors
# Root value
.
# Empty string properties
user..colors
Query arrays
βοΈ Deep properties
<!-- prettier-ignore -->
// Deep properties of objects or arrays.
// Symbol properties are always ignored.
['user', 'colors', 0]
π Unions
<!-- prettier-ignore -->
// Unions ("or") of queries are arrays of arrays.
// There must be at least one item.
[['colors'], ['name'], ['age']]
β Wildcards
<!-- prettier-ignore -->
// Shallow wildcards target all properties/items of a single object/array
['user', { type: 'any' }]
// Deep wildcards target all properties/items of 0, 1 or many objects/arrays
['user', { type: 'anyDeep' }]
[{ type: 'anyDeep' }, 'colors']
π€ Regexps
<!-- prettier-ignore -->
// Regexps match property names
['user', /name/]
// Flags can be used, e.g. to make it case-insensitive
['user', /name/i]
// ^ $ must be used to match from the beginning or until the end
['user', /^name$/i]
π΅ Arrays indices
<!-- prettier-ignore -->
// Array indices are integers, not strings
['user', 'colors', 0]
// Array indices can be negative.
// -1 is the last item.
// -0 is the item after it, which can be used to append.
['user', 'colors', -1]
ποΈ Array slices
<!-- prettier-ignore -->
// Array slices. Goes from the start (included) to the end index (excluded).
['user', 'colors', { type: 'slice', from: 0, to: 2 }]
// The start index defaults to 0, i.e. the beginning
['user', 'colors', { type: 'slice', to: 2 }]
// The end index defaults to -0, i.e. the end
['user', 'colors', { type: 'slice', from: 0 }]
['user', 'colors', { type: 'slice' }]
πͺ¨ Escaping
<!-- prettier-ignore -->
// Escaping is not necessary with query arrays
['name with spaces']
['name.with.dots']
['name\\with\\backslashes']
['name', '0']
['name', '/not_a_regexp/']
π¨ Root and empty strings
<!-- prettier-ignore -->
// Root value
[]
// Empty string properties
['user', '', 'colors']
Paths
A "path" is any query using only [property names](#%EF%B8%8F-deep-properties) and positive [array indices](#-arrays-indices). This excludes [negative indices](#-arrays-indices), [slices](#%EF%B8%8F-array-slices), [wildcards](#-wildcards), [regexps](#%EF%B8%8F-regexps) and [unions](#-unions).
Paths are returned by the entries
option.
# Path string
user.colors.0
<!-- prettier-ignore -->
// Path array
['user', 'colors', 0]
Conversions and comparisons
wild-wild-parser
can be used to
convert between both formats, or to compare queries.
Undefined values
Object properties with a defined key but an undefined
value are not ignored.
However, object properties without any defined key are ignored. The
has()
method, missing
option and
entries
option can be used to distinguish those.
const target = { name: undefined }
has(target, 'name') // true
has(target, 'colors') // false
get(target, 'name') // undefined
get(target, 'colors') // undefined
get(target, 'name', { entries: true, missing: true })
// { value: undefined, path: ['name'], missing: false }
get(target, 'colors', { entries: true, missing: true })
// { value: undefined, path: ['colors'], missing: true }
list(target, '*') // [undefined]
list(target, '*', { entries: true })
// [{ value: undefined, path: ['name'], missing: false }]
Options
Options are optional plain objects.
mutate
Methods: set()
,
remove()
\
Type: boolean
\
Default: false
By default, the target is deeply cloned.\
When true
, it is directly mutated instead, which is faster but has side effects.
const target = {}
console.log(set(target, 'name', 'Alice')) // { name: 'Alice' }
console.log(target) // {}
console.log(set(target, 'name', 'Alice', { mutate: true })) // { name: 'Alice' }
console.log(target) // { name: 'Alice' }
entries
Methods: get()
,
list()
,
iterate()
\
Type: boolean
\
Default: false
By default, properties' values are returned.\
When true
, objects with the following shape are returned instead:
value
any
: property's valuepath
Path
: property's full pathmissing
boolean
: whether the property is missing from the target
const target = { firstName: 'Alice', lastName: 'Smith' }
list(target, '*') // ['Alice', 'Smith']
list(target, '*', { entries: true })
// [
// { value: 'Alice', path: ['firstName'], missing: false },
// { value: 'Smith', path: ['lastName'], missing: false },
// ]
missing
Methods: all except has()
and
remove()
\
Type: boolean
\
Default: false
with list|iterate()
, true
with set()
When false
, properties not defined in the target are
ignored.
const target = {}
set(target, 'name', 'Alice') // { name: 'Alice' }
set(target, 'name', 'Alice', { missing: false }) // {}
list(target, 'name') // []
list(target, 'name', { missing: true, entries: true })
// [{ value: undefined, path: ['name'], missing: true }]
sort
Methods: get()
,
list()
,
iterate()
\
Type: boolean
\
Default: false
When returning sibling object properties, sort them by the lexigographic order of their names (not values).
const target = { lastName: 'Doe', firstName: 'John' }
list(target, '*') // ['Doe', 'John']
list(target, '*', { sort: true }) // ['John', 'Doe']
childFirst
Methods: get()
,
list()
,
iterate()
\
Type: boolean
\
Default: false
When using [unions](#-unions) or [deep wildcards](#-wildcards), a query might match both a property and some of its children.
This option decides whether the returned properties should be sorted from children to parents, or the reverse.
const target = { user: { name: 'Alice' } }
list(target, 'user.**') // [{ name: 'Alice' }, 'Alice']
list(target, 'user.**', { childFirst: true }) // ['Alice', { name: 'Alice' }]
leaves
Methods: all except has()
\
Type: boolean
\
Default: false
When using [unions](#-unions) or [deep wildcards](#-wildcards), a query might match both a property and some of its children.
When true
, only leaves are matched. In other words, a matching property is
ignored if one of its children also matches.
const target = { user: { name: 'Alice' } }
list(target, 'user.**') // [{ name: 'Alice' }, 'Alice']
list(target, 'user.**', { leaves: true }) // ['Alice']
roots
Methods: get()
,
list()
,
iterate()
\
Type: boolean
\
Default: false
When using [unions](#-unions) or [deep wildcards](#-wildcards), a query might match both a property and some of its children.
When true
, only roots are matched. In other words, a matching property is
ignored if one of its parents also matches.
const target = { user: { name: 'Alice' } }
list(target, 'user.**') // [{ name: 'Alice' }, 'Alice']
list(target, 'user.**', { roots: true }) // [{ name: 'Alice' }]
shallowArrays
Methods: all\
Type: boolean
\
Default: false
If true
, [wildcards](#-wildcards) do not recurse on arrays. Array items can
still be matched by using [indices](#-arrays-indices) or
[slices](#%EF%B8%8F-array-slices).
const target = [{ name: 'Alice' }, { name: 'Bob' }]
list(target, '**')
// [
// [{ name: 'Alice' }, { name: 'Bob' }],
// { name: 'Alice' },
// 'Alice',
// { name: 'Bob' },
// 'Bob',
// ]
list(target, '**', { shallowArrays: true })
// [
// [{ name: 'Alice' }, { name: 'Bob' }],
// ]
classes
Methods: all\
Type: boolean
\
Default: false
Unless true
, [wildcards](#-wildcards) and [regexps](#%EF%B8%8F-regexps) ignore
properties of objects that are not plain objects (like class instances, errors
or functions). Those can still be matched by using their
[property name](#%EF%B8%8F-deep-properties).
const target = { user: new User({ name: 'Alice' }) }
list(target, 'user.*') // []
list(target, 'user.*', { classes: true }) // ['Alice']
inherited
Methods: all\
Type: boolean
\
Default: false
By default, [wildcards](#-wildcards) and [regexps](#%EF%B8%8F-regexps) ignore properties that are either inherited or not enumerable. Those can still be matched by using their [property name](#%EF%B8%8F-deep-properties).
When true
, inherited properties are not ignored, but not enumerable ones still
are.
Related projects
wild-wild-utils
: functional utilities usingwild-wild-path
's object property pathswild-wild-parser
: parser forwild-wild-path
's object property paths
Support
For any question, don't hesitate to [submit an issue on GitHub](../../issues).
Everyone is welcome regardless of personal background. We enforce a [Code of conduct](CODE_OF_CONDUCT.md) in order to promote a positive and inclusive environment.
Contributing
This project was made with β€οΈ. The simplest way to give back is by starring and sharing it online.
If the documentation is unclear or has a typo, please click on the page's Edit
button (pencil icon) and suggest a correction.
If you would like to help us fix a bug or add a new feature, please check our [guidelines](CONTRIBUTING.md). Pull requests are welcome!
<!-- Thanks go to our wonderful contributors: -->
<!-- ALL-CONTRIBUTORS-LIST:START --> <!-- prettier-ignore-start --> <!-- markdownlint-disable --> ehmickyπ» π¨ π€ π Sylvainπ€
<!-- markdownlint-restore --> <!-- prettier-ignore-end -->
<!-- ALL-CONTRIBUTORS-LIST:END -->