Created
October 7, 2019 13:33
-
-
Save Sleavely/e0b130658a0ce87939baf1b9dcf92e6c to your computer and use it in GitHub Desktop.
lodash.get alternative that covers _most_ cases.
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
// Graciously stolen from lodash's stringToPath | |
const charCodeOfDot = '.'.charCodeAt(0) | |
const reEscapeChar = /\\(\\)?/g | |
const rePropName = RegExp( | |
// Match anything that isn't a dot or bracket. | |
'[^.[\\]]+' + '|' + | |
// Or match property names within brackets. | |
'\\[(?:' + | |
// Match a non-string expression. | |
'([^"\'][^[]*)' + '|' + | |
// Or match strings (supports escaping characters). | |
'(["\'])((?:(?!\\2)[^\\\\]|\\\\.)*?)\\2' + | |
')\\]'+ '|' + | |
// Or match "" as the space between consecutive dots or empty brackets. | |
'(?=(?:\\.|\\[\\])(?:\\.|\\[\\]|$))' | |
, 'g') | |
/** | |
* Converts `string` to a property path array. | |
* | |
* @private | |
* @param {string} string The string to convert. | |
* @returns {Array} Returns the property path array. | |
*/ | |
const stringToPath = (string) => { | |
const result = [] | |
if (string.charCodeAt(0) === charCodeOfDot) { | |
result.push('') | |
} | |
string.replace(rePropName, (match, expression, quote, subString) => { | |
let key = match | |
if (quote) { | |
key = subString.replace(reEscapeChar, '$1') | |
} | |
else if (expression) { | |
key = expression.trim() | |
} | |
result.push(key) | |
}) | |
return result | |
} | |
/** | |
* Recursively iterates over an object or array to find a nested path. | |
* | |
* @param {object|array} input | |
* @param {string} path A dot-notation path | |
* @returns {any|undefined} If a truthy value is found at the path, it is returned | |
*/ | |
const get = (input, path) => { | |
const pathComponents = stringToPath(path) | |
const currentProp = pathComponents[0] | |
// end of the road? | |
if(pathComponents.length === 1) return input[currentProp] | |
// keep going | |
if(input[currentProp]) return get(input[currentProp], pathComponents.slice(1).join('.')) | |
// surrender to the endless void | |
return undefined | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment