Skip to content

Instantly share code, notes, and snippets.

@joepuzzo
Last active November 18, 2020 12:00
Show Gist options
  • Save joepuzzo/e777519f079c954277995e706299f590 to your computer and use it in GitHub Desktop.
Save joepuzzo/e777519f079c954277995e706299f590 to your computer and use it in GitHub Desktop.
/* -------------------- toPath -------------------- */
const toPath = (path = '') => {
return String.prototype.replace
.call(path, /\['(.+?)'\]/g, '.$1')
.split(/[,[\].]+?/)
.filter(Boolean);
}
/* --------------------- get --------------------- */
const get = (obj, path = '', defaultValue) => {
const result = String.prototype.replace
.call(path, /\['(.+?)'\]/g, '.$1')
.split(/[,[\].]+?/)
.filter(Boolean)
.reduce(
(res, key) => (res !== null && res !== undefined ? res[key] : res),
obj
);
return result === undefined || result === obj ? defaultValue : result;
};
/* --------------------- has --------------------- */
// NOTE: two helper functions for has
// foo -->
// foo.bar --> foo
// foo.bar[3] --> foo.bar
// foo.bar.baz[2].raz.taz[5].laz --> foo.bar.baz[2].raz.taz[5]
const parentPath = (path) => {
return `.${path}`.replace(/(.*)[.[].*/, '$1').replace(/\./, '');
}
// foo --> foo
// foo.bar --> bar
// foo.bar[3] --> [3]
// foo.bar.baz[2].raz.taz[5].laz --> laz
const pathKey = (path) => {
return path.replace(parentPath(path), '').replace(/\./, '');
}
const has = (obj, path) => {
const pPath = parentPath(path);
const key = pathKey(path);
// If we have parent path then get the object at that location
// .. otherwise its the root object
const parentObj = pPath ? get(obj, pPath) : obj;
// If its [3] turn key into 3
return !!(parentObj && Object.hasOwnProperty.call(parentObj, key.replace(/\[(.*)\]/, '$1')));
}
/* --------------------- set --------------------- */
const set = (obj, path = '', val) => {
const result = String.prototype.replace
.call(path, /\['(.+?)'\]/g, '.$1')
.split(/[,[\].]+?/)
.filter(Boolean)
.reduce(
(res, key, i, arr) => {
//console.log('RES', res, 'Key', key, 'I', i, 'Arr', arr, 'OBJ', obj);
// At the leaf set the value
if( i === arr.length - 1){
res[key] = val;
return res[key];
}
// Initialize to new array or object if needed
if( res[key] === undefined ){
if(Number.isInteger(+(arr[i+1]))) {
res[key] = [];
} else {
res[key] = {};
}
return res[key];
}
// Exception for if the value is changeing to an array
if (Number.isInteger(+arr[i + 1]) && !Array.isArray(res[key])) {
res[key] = [];
}
// Otherwise keep whats there
return res[key];
},
obj
);
};
/* --------------------- unset --------------------- */
const unset = (obj, path = '') => {
let found = false;
String.prototype.replace
.call(path, /\['(.+?)'\]/g, '.$1')
.split(/[,[\].]+?/)
.filter(Boolean)
.reduce(
(res, key, i, arr) => {
// Base case res is undefined
if(res === undefined){
return res;
}
// At the leaf delete the value
if( i === arr.length - 1){
delete res[key];
found = true;
return res[key];
}
// Otherwise keep going
return res[key];
},
obj
);
return found;
};
/* --------------------- values --------------------- */
const values = (obj = {}) => {
const props = Object.keys(obj);
return props.map((key) => obj[key])
}
/* --------------------- pullAt --------------------- */
const pullAt = (obj, path = '') => {
let pulled;
String.prototype.replace
.call(path, /\['(.+?)'\]/g, '.$1')
.split(/[,[\].]+?/)
.filter(Boolean)
.reduce(
(res, key, i, arr) => {
// Base case res is undefined
if(res === undefined){
return res;
}
// At the leaf delete the value
if( i === arr.length - 1 && Array.isArray(res)){
// Pull out one value at index ( key )
pulled = res.splice(key, 1);
return res[key];
}
// Otherwise keep going
return res[key];
},
obj
);
return pulled;
};
/* --------------------- test logs --------------------- */
const testObj = {
foo: {
bar: [
{ baz: 'hello' }
]
}
};
console.log('--------- TEST TOPATH --------');
console.log('undefined ---->', toPath());
console.log('foo ---->', toPath('foo'));
console.log('foo.bar[0] ---->', toPath('foo.bar[0]'));
console.log('foo.bar[0].baz ---->', toPath('foo.bar[0].baz'));
console.log('foo.bar[3].baz ---->', toPath('foo.bar[3].baz'));
console.log('foo.bar.baz[0].taz.bar[10][3].bar.0.5 ---->', toPath('foo.bar.baz[0].taz.bar[10][3].bar.0.5'));
console.log("foo['bar'].baz[0].taz.bar[10][3].bar['0'].5 ----> ", toPath("foo['bar'].baz[0].taz.bar[10][3].bar['0'].5"));
console.log('\n');
console.log('-------- TEST VALUES --------');
console.log(JSON.stringify(testObj), '---->', values(testObj));
console.log(JSON.stringify({}), '---->', values({}));
console.log(JSON.stringify({ foo: 1, bar: 'baz' }), '---->', values({ foo: 1, bar: 'baz' }));
console.log(JSON.stringify(), '---->', values());
console.log('\n');
console.log('---------- TEST HAS ----------');
console.log(JSON.stringify(testObj));
console.log('foo ---->', has(testObj, 'foo'));
console.log('foo.bar[0] ---->', has(testObj, 'foo.bar[0]'));
console.log('foo.bar[0].baz ---->', has(testObj, 'foo.bar[0].baz'));
console.log('foo.bar[3].baz ---->', has(testObj, 'foo.bar[3].baz'));
console.log('\n');
console.log('---------- TEST GET ----------');;
console.log(JSON.stringify(testObj));
console.log('undefined ---->', get(testObj));
console.log('foo ---->', get(testObj, 'foo'));
console.log('foo.bar[0] ---->', get(testObj, 'foo.bar[0]'));
console.log('foo.bar[0].baz ---->', get(testObj, 'foo.bar[0].baz'));
console.log('foo.bar[3].baz ---->', get(testObj, 'foo.bar[3].baz'));
console.log('\n');
console.log('---------- TEST SET ----------');
let testSetObj = {};
console.log(JSON.stringify(testSetObj));
console.log('foo ----> {}', set(testSetObj, 'foo', {}));
console.log(JSON.stringify(testSetObj));
console.log('foo.bar[0] ----> { baz: "hello" }', set(testSetObj, 'foo.bar[0]', { baz: 'hello' }));
console.log(JSON.stringify(testSetObj));
console.log('\n');
testSetObj = {};
console.log('foo.bar[0].baz ----> "hello"', set(testSetObj, 'foo.bar[0].baz', 'hello'));
console.log(JSON.stringify(testSetObj));
console.log('foo.bar[3].baz ----> "world"', set(testSetObj, 'foo.bar[3].baz', 'world'));
console.log(JSON.stringify(testSetObj));
console.log('foo.bar[3].baz ----> "change"', set(testSetObj, 'foo.bar[3].baz', 'change'));
console.log(JSON.stringify(testSetObj));
console.log('foo.laz ----> "world"', set(testSetObj, 'foo.laz', 'world'));
console.log(JSON.stringify(testSetObj));
console.log('\n');
testSetObj = {};
console.log('foo ----> "hello"', set(testSetObj, 'foo', 'hello'));
console.log(JSON.stringify(testSetObj));
console.log('\n');
testSetObj = {};
console.log('foo.bar.baz[0].taz.bar[10][3].bar.0.5 ----> 3', set(testSetObj, 'foo.bar.baz[0].taz.bar[10][3].bar.0.5', 3));
console.log(JSON.stringify(testSetObj));
console.log('\n');
console.log('---------- TEST UNSET ----------');
let testUnsetObj = {};
console.log(JSON.stringify(testUnsetObj));
console.log('foo ---->', unset(testUnsetObj, 'foo'));
console.log(JSON.stringify(testUnsetObj));
console.log('foo.bar[0] ---->', unset(testUnsetObj, 'foo.bar[0]'));
console.log(JSON.stringify(testUnsetObj));
console.log('\n');
testUnsetObj = { foo: { bar: [{ baz: 'hello' }, { raz: 'world'}] } };
console.log(JSON.stringify(testUnsetObj));
console.log('foo.bar[0] ---->', unset(testUnsetObj, 'foo.bar[0]'));
console.log(JSON.stringify(testUnsetObj));
console.log('foo.bar[1].raz ---->', unset(testUnsetObj, 'foo.bar[1].raz'));
console.log(JSON.stringify(testUnsetObj));
console.log('foo ---->', unset(testUnsetObj, 'foo'));
console.log(JSON.stringify(testUnsetObj));
console.log('---------- TEST PULLAT ----------');
testUnsetObj = {};
console.log(JSON.stringify(testUnsetObj));
console.log('foo ---->', pullAt(testUnsetObj, 'foo'));
console.log(JSON.stringify(testUnsetObj));
console.log('\n');
console.log('foo.bar[0] ---->', pullAt(testUnsetObj, 'foo.bar[0]'));
console.log(JSON.stringify(testUnsetObj));
console.log('\n');
testUnsetObj = { foo: { bar: [{ baz: 'hello' }, { raz: 'world'}] } };
console.log(JSON.stringify(testUnsetObj));
console.log('foo.bar[0] ---->', pullAt(testUnsetObj, 'foo.bar[0]'));
console.log(JSON.stringify(testUnsetObj));
console.log('\n');
console.log('foo.bar[1].raz ---->', pullAt(testUnsetObj, 'foo.bar[1].raz'));
console.log(JSON.stringify(testUnsetObj));
console.log('foo ---->', pullAt(testUnsetObj, 'foo'));
console.log(JSON.stringify(testUnsetObj));
console.log('\n');
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment