Last active
February 25, 2020 12:53
-
-
Save nanxiaobei/a4936d2b5f946bd71c250f593ced2b04 to your computer and use it in GitHub Desktop.
Inspired by optional chaining
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const isObj = (val) => Object.prototype.toString.call(val) === '[object Object]'; | |
const isArr = (val) => Array.isArray(val); | |
const isNum = (val) => val === `${+val}`; | |
const strToNum = (str) => (isNum(str) ? +str : str); | |
/** | |
* Used to change undefined keys to object or array, similar effect to the 'optional chaining'. | |
* Received an object and an array of keys, returns a formatted object. | |
* | |
* e.g. | |
* list -> ['a', 'b.c'] -> a is object, b is object, b.c is object | |
* list -> ['a[]', 'b.c[]'] -> a is array | |
* list -> ['b[0].c'] -> b is array, b[0] is object, b[0].c is object | |
* list -> ['b[0][]'] -> b is array, b[0] is array | |
* | |
* Default, change last key to object | |
* chain({ a: 1 }, ['a', 'b.c', 'd']) -> { a: {}, b: { c: {} }, d: {} } // change not object to object, add missed object | |
* chain({ a: { b: 1 } }, ['a', 'd']) -> { a: { b: 1 } }, d: {} } // if object exists, not change | |
* | |
* chain({ a: 1 }, ['b[0]']) -> { a: 1, b: [{}] } // b -> array, b[0] -> object | |
* chain({ a: 1 }, ['b[0].c']) -> { a: 1, b: [{ c: {} }] } // b -> array, b[0] -> object, b[0].c -> object | |
* | |
* To change last key to array, not object, add '[]' behind. | |
* chain({ a: 1 }, ['b[]']) -> { a: 1, b: [] } // b -> array | |
* chain({ a: 1 }, ['b[0][]']) -> { a: 1, b: [[]] } // b -> array, b[0] -> array | |
* | |
* @param {object} obj - source object | |
* @param {array} list - needed keys for source object | |
* @returns {object} formatted object | |
*/ | |
const chain = (obj, list) => { | |
list.forEach((key) => { | |
// e.g. | |
// key: prop[0][0] -> chain({}, [key]) -> { prop: [ [ {} ] ] } | |
// key: prop[0][] -> chain({}, [key]) -> { prop: [ [] ] } | |
// key: prop -> chain({}, [key]) -> { prop: {} } | |
const newKey = key.replace(/\[(\d+)]/g, '[].$1'); | |
// prop[0][0] -> prop[].0[].0 (key -> newKey) | |
// prop[0][] -> prop[].0[] (key -> newKey) | |
// prop -> prop (key -> newKey) | |
const keyPieces = newKey.split('.'); | |
// prop[].0[].0 -> ['prop[]', '0[]', '0'] (newKey -> keyPieces) | |
// prop[].0[] -> ['prop[]', '0[]'] (newKey -> keyPieces) | |
// prop -> ['prop'] (newKey -> keyPieces) | |
keyPieces.reduce((data, oldPiece) => { | |
let newPiece = oldPiece; | |
if (newPiece.includes('[]')) { | |
// newPiece: 'prop[]' or '0[]' (data[newPiece] is array) | |
newPiece = newPiece.slice(0, -2); // 'prop[]' -> 'prop', '0[]' -> '0' | |
newPiece = strToNum(newPiece); // 'prop' -> 'prop', '0' -> 0 | |
if (!isArr(data[newPiece])) { | |
data[newPiece] = []; | |
} | |
} else { | |
// newPiece: 'prop' or '0' (data[newPiece] is object) | |
newPiece = strToNum(newPiece); // 'prop' -> 'prop', '0' -> 0 | |
if (!isObj(data[newPiece])) { | |
data[newPiece] = {}; | |
} | |
} | |
return data[newPiece]; | |
}, obj); | |
}); | |
return obj; | |
}; | |
export default chain; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment