All files / utils string-path.js

100% Statements 53/53
95.23% Branches 20/21
100% Functions 2/2
100% Lines 53/53

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 542x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2152x 2152x 2135x 2135x 91x 2x 2116x 2135x 105x 105x 2135x 2135x 2135x 2135x 2135x 2135x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2133x 2133x 2133x 2133x 2131x 2131x 2131x 2132x 2132x  
/** Used to match property names within property paths. */
const rePropName = /[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g
 
/** Used to match backslashes in property paths. */
const reEscapeChar = /\\(\\)?/g
 
/**
 * Used to memoize `stringToPath()` results.
 * @type {{[stringPath: string]: ReturnType<typeof stringToPath>}}
 */
const stringToPathCache = {}
 
/**
 * Converts `string` to a property path array.
 *
 * @param {string} string The string to convert.
 * @returns {readonly string[]} Returns the property path array.
 */
export function stringToPath (string) {
  const cachedResult = stringToPathCache[string]
  if (cachedResult) { return cachedResult }
 
  const result = []
  if (string.at(0) === '.') {
    result.push('')
  }
  string.replace(rePropName, function (match, number, quote, subString) {
    result.push(quote ? subString.replace(reEscapeChar, '$1') : (number || match))
    return ''
  })
 
  const finalResult = Object.freeze(result)
  stringToPathCache[string] = finalResult
  return finalResult
}
 
/**
 * Get object data from a string path
 *
 * @param {unknown} obj - target object
 * @param {string} stringPath - string path
 * @returns {unknown} result from string path
 */
export function getFromStringPath (obj, stringPath) {
  if (obj == null) { return obj }
  const pathArray = stringToPath(stringPath)
  let current = obj
  for (const section of pathArray) {
    current = current[/** @type {never} */(section)]
    if (current == null) { return current }
  }
  return current
}