
Product
Introducing Socket Firewall Enterprise: Flexible, Configurable Protection for Modern Package Ecosystems
Socket Firewall Enterprise is now available with flexible deployment, configurable policies, and expanded language support.
Get or set a deep value using a keypath string. Supports bracket and dot notation

Get, set, or delete a deep value using a keypath string.
A collection of keypath utilities: get, set, delete, in, has, flatten, expand, and immutable set/delete.
Lightweight and parses keypaths using vanilla JS - No eval or new Function hacks!
npm install keypather
// modular imports, so you can keep your bundle lean
const get = require('keypather/get')
const set = require('keypather/set')
const del = require('keypather/del')
const immutableSet = require('keypather/immutable-set')
const immutableDel = require('keypather/immutable-del')
const keypathIn = require('keypather/in')
const hasKeypath = require('keypather/has')
const expand = require('keypather/expand')
const flatten = require('keypather/flatten')
const get = require('keypather/get')
const set = require('keypather/set')
const del = require('keypather/del')
let obj
// Objects
obj = { foo: { bar: 100 } }
get(obj, 'foo.bar') // returns 100
del(obj, '["foo"]["bar"]') // returns true, obj becomes { foo: {} }
set(obj, 'foo.bar.qux', 200) // returns 200, obj becomes { foo: { bar: { qux: 200 } } }
get(obj, 'foo["bar"].qux') // returns 200
// Arrays
obj = {}
set(obj, 'foo[0]', 100) // obj is { foo: [ 100 ] }
const set = require('keypather/immutable-set')
const del = require('keypather/immutable-del')
let obj
let out
// Objects
obj = { foo: { bar: 100 } }
out = set(obj, 'foo.bar', 100) // returns obj
// out === obj,
// since it was not modified
out = set(obj, 'foo.bar.qux', 200) // returns { foo: { bar: { qux: 200 } } }
// out !== obj,
// obj is still { foo: { bar: 100 } }
out = del(obj, 'one.two.three') // returns obj
// out === obj,
// since it was not modified
out = del(obj, 'foo.bar.qux') // returns { foo: { bar: {} } }
// out !== obj,
// obj is still { foo: { bar: { qux: 200 } } }
// Arrays
obj = {}
out = set(obj, 'foo[0]', 100) // returns { foo: [ 100 ] } (new)
// out !== obj, obj is still { foo: { bar: 100 } }
const hasKeypath = require('keypather/has')
const keypathIn = require('keypather/in')
const obj = { foo: Object.create({ bar: 100 }) }
hasKeypath(obj, 'foo.bar') // returns false (bar is on proto)
keypathIn(obj, 'foo.bar') // returns true
hasKeypath(obj, 'foo') // returns true
const expand = require('keypather/expand')
const flatten = require('keypather/flatten')
const obj = expand({
'foo.bar': 1,
'foo.qux[0]': 100,
'foo["qux"][1]': 200,
'foo.qux.wut': 'val'
})
// obj is { foo { bar: 1, qux: [ 100, 200, wut: 'val' ] } }
const flat = flatten(obj)
// flat is { 'foo.bar': 1, 'foo.qux': 2 } }
/* Missing deep values w/ "force: false" */
get({}, 'foo.bar', { force: false })
set({}, 'foo.bar', 100, { force: false })
del({}, 'foo.bar', { force: false })
immutableSet({}, 'foo.bar', 100, { force: false })
immutableDel({}, 'foo.bar', { force: false })
// TypeError: Cannot read property 'bar' of undefined (at keypath 'foo' of 'foo.bar')
get({ foo: {} }, 'foo.bar', { force: false })
set({ foo: {} }, 'foo.bar', 100, { force: false })
del({ foo: {} }, 'foo.bar', { force: false })
immutableSet({ foo: {} }, 'foo.bar', 100, { force: false })
immutableDel({ foo: {} }, 'foo.bar', { force: false })
// TypeError: Cannot read property 'bar' of undefined (at keypath 'foo.bar' of 'foo.bar.qux')
hasKeypath({}, 'foo.bar', { force: false })
// TypeError: Cannot read property 'hasOwnProperty' of undefined (hasOwnProperty('bar') errored at keypath 'foo' of 'foo.bar')
keypathIn({}, 'foo.bar', { force: false })
// TypeError: Cannot use 'in' operator to search for 'bar' in undefined (at 'foo' of 'foo.bar')
keypathIn({}, 'foo.bar.qux', { force: false })
hasKeypath({}, 'foo.bar.qux', { force: false })
// TypeError: Cannot read property 'bar' of undefined (at keypath 'foo' of 'foo.bar.qux')
/* Warnings for set and immutable-set */
// by default, set will overwrite primitives (string, number or regexp) to an object or array.
// when overwritePrimitives is set to false, sets will warn when settings a key on a primitive
// to disable all warnings use the option { warn: false }
set({}, '[0]', 'val', { overwritePrimitives: false })
// log: Setting number key (0) on object at keypath '' of '[0]')
set([], 'key', 'val', { overwritePrimitives: false })
// log: Setting string key 'foo' on array at keypath '' of 'foo')
set({ foo: 1 }, 'foo.qux', 'val', { overwritePrimitives: false })
// log: Setting key 'qux' on number 1 at keypath 'foo' of 'foo.qux')
set({ foo: 1 }, 'foo[0]', 'val', { overwritePrimitives: false })
// log: Setting number key (0) on number 1 at keypath 'foo' of 'foo[0]')
set({ foo: 'str' }, 'foo.bar', 'val', { overwritePrimitives: false })
// log: Setting key 'bar' on string 'str' at keypath 'foo' of 'foo.bar')
set({ foo: {} }, 'foo[0]', 'val', { overwritePrimitives: false })
// log: Setting number key (0) on object at keypath 'foo' of 'foo[0]')
/* Invalid keypaths */
get({}, 'foo.1bar')
// Error: Unexpected token '1' in keypath 'foo.1bar' at position 4 (invalid dot key)
get({}, 'foo[]')
// Error: Unexpected token ']' in keypath 'foo[]' at position 4 (invalid bracket key)
get({}, 'foo["]')
// Error: Unexpected token ']' in keypath 'foo[]' at position 5 (invalid bracket string key)
get({}, 'foo.')
// Error: Unexpected end of keypath 'foo.' (invalid dot key)
get({}, 'foo[')
// Error: Unexpected end of keypath 'foo[' (invalid bracket key)
get({}, "foo['")
// Error: Unexpected end of keypath 'foo['' (invalid bracket string key)
Returns value at keypath in obj
if false, `get` will error when reading a key on a non-existant keypath.
const get = require('keypather/get');
const obj = {
foo: {
bar: {
baz: 'val'
}
}
};
get(obj, "foo.bar.baz"); // returns 'val'
get(obj, "foo['bar'].baz"); // returns 'val'
get(obj, "['foo']['bar']['baz']"); // returns 'val'
get({}, 'foo.two.three', { force: false }) // throws error
// TypeError: Cannot read property 'three' of undefined (at keypath 'foo.two' of 'foo.two.three')
Sets a value in obj at keypath. If force=true, set will create objects at non-existant keys in the keypath. If the non-existant key is a number, its value will be initialized as an array.
if false, `set` will error when reading a key on a non-existant keypath.
setting a key on a primitive will convert it to an object or array (if key is string or number).
if false, `set` will log a warning when setting keys on primitives.
const set = require('keypather/set');
let obj = {
foo: {
bar: {
baz: 'val'
}
}
};
set(obj, "foo['bar'].baz", 'val'); // returns 'val'
set(obj, "foo.bar.baz", 'val'); // returns 'val'
set(obj, "['foo']['bar']['baz']", 'val'); // returns 'val'
/* By default, set forces creation of non-existant keys */
obj = {}
set(obj, "foo.bar.baz", 'val'); // returns 'val'
// obj becomes:
// {
// foo: {
// bar: {
// baz: 'val'
// }
// }
// };
/* By default, overwrites primitives when setting a key on one */
obj = { foo: 1 }
set(obj, "foo.bar.baz", 'val'); // returns 'val'
// obj becomes:
// {
// foo: {
// bar: {
// baz: 'val'
// }
// }
// };
obj = { foo: 1 }
set(obj, "foo[0].baz", 'val'); // returns 'val'
// obj becomes:
// {
// foo: [{
// baz: 'val'
// }]
// };
/* Errors, force=false */
set({}, "foo.bar.baz", 'val', { force: false }); // throw's an error
// TypeError: Cannot read property 'bar' of undefined (at keypath 'foo' of 'foo.bar.baz')
// see more errors above in the 'Errors' section
/* Warnings, overwritePrimitives=false */
set({ foo: 'str' }, 'foo.bar', 'val', { overwritePrimitives: false })
// log: Setting key 'bar' on string 'str' at keypath 'foo' of 'foo.bar')
// see more warnings above in the 'Errors' section
Deletes value a keypath in obj. Similar to delete obj.key.
if false, `del` will error when reading a key on a non-existant keypath.
const del = require('keypather/del');
const obj = {
foo: {
bar: {
baz: 'val'
}
}
};
del(obj, "foo['bar'].baz"); // true
del(obj, "foo.bar.baz"); // true
del(obj, "['foo']['bar']['baz']"); // true
// obj becomes:
// {
// foo: {
// bar: {}
// }
// }
/* Errors, force=false */
del(obj, "one.two.three", 'val', { force: false }); // throw's an error
// TypeError: Cannot read property 'two' of undefined (at keypath 'one' of 'one.two.three')
// see more errors above in the 'Errors' section
Sets a value in obj at keypath. If force=true, set will create objects at non-existant keys in the keypath. If the non-existant key is a number, its value will be initialized as an array.
if false, `immutable-set` will error when reading a key on a non-existant keypath.
setting a key on a primitive will convert it to an object or array (if key is string or number).
if false, `immutable-set` will log a warning when setting keys on primitives.
const set = require('keypather/immutable-set');
let obj = {
foo: {
bar: {
baz: 'val'
}
}
};
let out
out = set(obj, "foo['bar'].baz", 'val'); // returns SAME object, since the value was unchanged
// out === obj
out = set(obj, "foo.bar.baz", 'val2'); // returns { foo: { bar: { baz: 'val2' } } } (new object)
// out !== obj
out = set(obj, "['foo']['bar']['baz']", 'val3'); // returns { foo: { bar: { baz: 'val3' } } } (new object)
// out !== obj
/* By default, overwrites primitives when setting a key on one */
obj = { foo: 1 }
out = set(obj, "foo.bar.baz", 'val'); // returns new object
// out !== obj
// out is:
// {
// foo: {
// bar: {
// baz: 'val'
// }
// }
// };
obj = { foo: 1 }
out = set(obj, "foo[0].baz", 'val'); // returns new object
// out !== obj
// out is:
// {
// foo: [{
// baz: 'val'
// }]
// };
/* Errors, force=false */
obj = {}
set(obj, "foo.bar.baz", 'val', { force: false }); // throws error
// Error: Cannot read property 'bar' of undefined (at keypath 'foo' of 'foo.bar.baz')
/* Warnings, force=false */
obj = { foo: 'str' }
out = set(obj, 'foo.bar', 'val', { overwritePrimitives: false })
// out === obj, since keys cannot be set on strings or numbers
// log: Setting key 'bar' on string 'str' at keypath 'foo' of 'foo.bar')
Deletes value a keypath in obj. Similar to delete obj.key.
if false, `del` will error when reading a key on a non-existant keypath.
const del = require('keypather/immutable-del');
const obj = {
foo: {
bar: {
baz: 'val'
}
}
};
let out
out = del(obj, "foo['bar'].baz"); // true
out = del(obj, "foo.bar.baz"); // true
out = del(obj, "['foo']['bar']['baz']"); // true
// obj becomes:
// {
// foo: {
// bar: {}
// }
// }
/* Errors, force=false */
del(obj, "one.two.three", 'val', { force: false }); // throw's an error
// Error: Cannot read property 'two' of undefined (at keypath 'one' of 'one.two.three')
Returns true if keypath is "in" the obj at the keypath. Similar to "in" operator.
const keypathIn = require('keypather/in');
const obj = {
foo: {
bar: {
baz: 'val'
__proto__: {
qux: 'val'
}
}
}
};
keypathIn(obj, "foo.bar.baz"); // true
keypathIn(obj, "foo.bar.qux"); // true
keypathIn(obj, "foo.bar.bing"); // false
keypathIn(obj, "foo['bar'].baz"); // true
keypathIn(obj, "one.two.three"); // false
// Errors, force=false
keypathIn(obj, "one.two.three", { force: false });
// Error: Cannot read property 'two' of undefined (at keypath 'two' of 'one.two.three')
keypathIn(obj, "foo.two.three", { force: false });
// TypeError: Cannot use 'in' operator to search for 'three' in undefined (at 'foo.two' of 'foo.two.three')
Returns true if the obj has the keypath. Similar to obj.hasOwnProperty.
const hasKeypath = require('keypather/has');
const obj = {
foo: {
bar: {
baz: 'val'
__proto__: {
qux: 'val'
}
}
}
};
hasKeypath(obj, "foo.bar.baz"); // true
hasKeypath(obj, "foo.bar.qux"); // false
hasKeypath(obj, "['foo']['bar']['baz']"); // true
hasKeypath(obj, "one.two.three"); // false
// Errors, force=false
hasKeypath(obj, "one.two.three", { force: false }); // throw's an error
// Error: Cannot read property 'two' of undefined (at keypath 'two' of 'one.two.three
hasKeypath(obj, "foo.two.three", { force: false });
// Error: Cannot read property 'hasOwnProperty' of undefined (hasOwnProperty('three') errored at keypath 'foo.two' of 'foo.two.three')
Flatten an object or array into a keypath object
const flatten = require('keypather/flatten');
flatten({
foo: {
qux: 'hello'
},
bar: [
1,
{
yolo: [1]
}
]
});
// returns:
// {
// 'foo.qux': 'hello',
// 'bar[0]': 1,
// 'bar[1].yolo[0]': 1
// }
/* accepts a delimiter other than '.' as second arg */
flatten({
foo: {
qux: 'hello'
}
}, '_');
// returns:
// {
// 'foo_qux': 'hello',
// }
Expand a flattened object back into an object or array
const expand = require('keypather/expand');
expand({
'foo.qux': 'hello',
'bar[0]': 1,
'bar[1].yolo[0]': 1
});
// returns:
// {
// foo: {
// qux: 'hello'
// },
// bar: [
// 1,
// {
// yolo: [1]
// }
// ]
// }
/* expand will assume an object is an array if any of the keys are numbers */
expand({
'[0]': 1,
'[1].yolo[0]': 1
});
// returns:
// [
// 1,
// {
// yolo: [1]
// }
// ]
/* accepts a delimiter other than '.' as second arg */
expand({
'foo_qux': 'hello'
}, '_');
// returns:
// {
// foo: {
// qux: 'hello'
// }
// }
3.1.0
FAQs
Get or set a deep value using a keypath string. Supports bracket and dot notation
We found that keypather demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 3 open source maintainers 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.

Product
Socket Firewall Enterprise is now available with flexible deployment, configurable policies, and expanded language support.

Security News
Open source dashboard CNAPulse tracks CVE Numbering Authorities’ publishing activity, highlighting trends and transparency across the CVE ecosystem.

Product
Detect malware, unsafe data flows, and license issues in GitHub Actions with Socket’s new workflow scanning support.