Skip to content

Instantly share code, notes, and snippets.

@rauljose
Created October 2, 2019 21:30
Show Gist options
  • Save rauljose/e03e582008ffb9c667003c92bde77522 to your computer and use it in GitHub Desktop.
Save rauljose/e03e582008ffb9c667003c92bde77522 to your computer and use it in GitHub Desktop.
Utilities for objects. Find key(s) within sub-objects, recursively. get/set deep keys by path
/**
* Utilities for object {}
*
* @usage
* iaObjectUtil.findKeyFirst('b', {a:1,b:2,c:{a:'ac', b:'bc'}})
* => [{ path: "b", value: 2 }] // key not found returns []
*
* iaObjectUtil.findKeyAll('b', {a:1,b:2,c:{a:'ac', b:'bc'}})
* => [{ path: "b", value: 2 },{ path: "c.b", value: "bc" }] // not found []
*
* iaObjectUtil.getPath('c.b',{a:1,b:2,c:{a:'ac', b:'bc'}})
* => 'bc' // not found throws error Key not found: key
* iaObjectUtil.getPath('c/b',{a:1,b:2,c:{a:'ac', b:'bc'}}, '/')
* => 'bc' // change path separator from default to /
*
* iaObjectUtil.setPath('c.d', 33, {a:1,b:2} )
* => {a:1,b:2, c:{d:33}}
*
* @author Raúl José Santos
* @author Informática Asociada
* @copyright 2019
* @license MIT
* @version 1.0.0
*/
var iaObjectUtil = {
/**
* Find first key in an object, searching within object's objects
*
* @param key string
* @param obj object
* @return array of objects, empty array on not found
* @example
* findKeyFirst('b', {a:1,b:2,c:{a:'ac', b:'bc'}})
* => [{ path: "b", value: 2 }] // key not found returns []
*/
findKeyFirst: function(key, obj) {
var found = [], visited = {};
/**
*
* @param searchKey string
* @param onObj object
* @param p string
* @private
*/
function _findFirstKey(searchKey, onObj, p) {
if(typeof onObj !== 'object' || onObj === null)
return;
if(onObj.hasOwnProperty(searchKey)) {
var f = (p + '.' + searchKey).substr(1);
found[found.length] = {path:f, value:onObj[searchKey]};
visited[f]=true;
return;
}
for(var c in onObj)
if(onObj.hasOwnProperty(c) && typeof onObj[c] === 'object') {
var f1 = p + '.' + c;
if(!visited.hasOwnProperty(f1)) {
visited[f1]=true;
_findFirstKey(searchKey, onObj[c],f1);
}
}
}
_findFirstKey(key, obj, '');
return found;
},
/**
* Find all key in object, searching within object's objects
*
* @param key string
* @param obj object {}
* @return array of objects, empty array on not found
* @example
* findKeyAll('b', {a:1,b:2,c:{a:'ac', b:'bc'}})
* => [{ path: "b", value: 2 },{ path: "c.b", value: "bc" }] // key not found returns []
*/
findKeyAll: function(key, obj) {
var found = [], visited = {};
function _findKeyAll(key, obj, p) {
if(typeof obj !== 'object' || obj === null)
return;
if(obj.hasOwnProperty(key)) {
found[found.length] = {path:(p + '.' + key).substr(1), value:obj[key]};
visited[p]=true;
}
for(var c in obj)
if(obj.hasOwnProperty(c) && typeof obj[c] === 'object' ) {
var f = p + '.' + c;
if(!visited.hasOwnProperty(f)) {
_findKeyAll(key, obj[c], f);
visited[f]=true;
}
}
}
_findKeyAll(key, obj, '');
return found;
},
/**
* Returns the value of an object's property with path keys
*
* @param path string the keys sperated by pathSeparator
* @param obj object {}
* @param pathSeparator string string to separate keys, default .
* @return mixed value at path or trhows error: Key not found: key
*
* @example
* getPath('c.b',{a:1,b:2,c:{a:'ac', b:'bc'}})
* => 'bc' // not found throws error
* getPath('c/b',{a:1,b:2,c:{a:'ac', b:'bc'}}, '/')
* => 'bc' // change path separator from default to /
*/
getPath: function(path, obj, pathSeparator) {
var o=obj, keys = path.split(typeof pathSeparator === 'undefined' ? '.' : pathSeparator), i=0;
for(var len=keys.length; i<len; ++i)
if(o.hasOwnProperty(keys[i]))
o = o[keys[i]];
else
throw "Key not found!: " + keys[i];
return o;
},
/**
* for path keys set the value, creating non existing keys, or replacing
*
*
* @param path string the keys sperated by pathSeparator
* @param value mixed the value to set to the last key in path
* @param obj object {}
* @param pathSeparator string string to separate keys, default .
* @return object the modified object obj with the new value
*
* @example
* setPath('c.d', 33, {a:1,b:2} )
* => {a:1,b:2, c:{d:33}}
*/
setPath: function(path, value, obj, pathSeparator) {
var o=obj, keys = path.split(typeof pathSeparator === 'undefined' ? '.' : pathSeparator), i=0;
for(var len=keys.length-1; i<len; ++i) {
if(!o.hasOwnProperty(keys[i]))
o[keys[i]] = {};
o = o[keys[i]];
}
o[keys[i]] = value;
return obj;
},
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment