{"version":3,"file":"paths.mjs","sources":["../src/paths.ts"],"sourcesContent":["import {\n  type IndexTuple,\n  isIndexSegment,\n  isIndexTuple,\n  isKeySegment,\n  type KeyedSegment,\n  type Path,\n  type PathSegment,\n} from '@sanity/types'\n\nconst rePropName =\n  /[^.[\\]]+|\\[(?:(-?\\d+(?:\\.\\d+)?)|([\"'])((?:(?!\\2)[^\\\\]|\\\\.)*?)\\2)\\]|(?=(?:\\.|\\[\\])(?:\\.|\\[\\]|$))/g\nconst reKeySegment = /_key\\s*==\\s*['\"](.*)['\"]/\nconst EMPTY_PATH: Path = []\n\nexport const FOCUS_TERMINATOR = '$'\n\n// Fields named as GROQ data types cannot be accessed using dot notation. These fields must instead\n// be serialized using square bracket notation.\nconst GROQ_DATA_TYPE_VALUES = ['true', 'false', 'null']\n\nexport function get<R>(obj: unknown, path: Path | string): R | undefined\nexport function get<R>(obj: unknown, path: Path | string, defaultValue: R): R\nexport function get(obj: unknown, path: Path | string, defaultVal?: unknown): unknown {\n  const select = typeof path === 'string' ? fromString(path) : path\n  if (!Array.isArray(select)) {\n    throw new Error('Path must be an array or a string')\n  }\n\n  let acc: unknown | undefined = obj\n  for (let i = 0; i < select.length; i++) {\n    const segment = select[i]\n    if (isIndexSegment(segment)) {\n      if (!Array.isArray(acc)) {\n        return defaultVal\n      }\n\n      acc = acc[segment]\n    }\n\n    if (isKeySegment(segment)) {\n      if (!Array.isArray(acc)) {\n        return defaultVal\n      }\n\n      acc = acc.find((item) => item._key === segment._key)\n    }\n\n    if (typeof segment === 'string') {\n      acc =\n        typeof acc === 'object' && acc !== null\n          ? ((acc as Record<string, unknown>)[segment] as Record<string, unknown>)\n          : undefined\n    }\n\n    if (typeof acc === 'undefined') {\n      return defaultVal\n    }\n  }\n\n  return acc\n}\n\nconst pathsMemo = new Map<string, Path>()\nexport function pathFor(path: Path): Path {\n  if (path.length === 0) {\n    return EMPTY_PATH\n  }\n  const asString = toString(path)\n  if (pathsMemo.has(asString)) {\n    return pathsMemo.get(asString)!\n  }\n  pathsMemo.set(asString, path)\n  Object.freeze(path)\n  return path\n}\n\nexport function isEqual(path: Path, otherPath: Path): boolean {\n  return (\n    path.length === otherPath.length &&\n    path.every((segment, i) => isSegmentEqual(segment, otherPath[i]))\n  )\n}\n\nexport function numEqualSegments(path: Path, otherPath: Path): number {\n  const length = Math.min(path.length, otherPath.length)\n  for (let i = 0; i < length; i++) {\n    if (!isSegmentEqual(path[i], otherPath[i])) {\n      return i\n    }\n  }\n  return length\n}\n\nexport function isSegmentEqual(segmentA: PathSegment, segmentB: PathSegment): boolean {\n  if (isKeySegment(segmentA) && isKeySegment(segmentB)) {\n    return segmentA._key === segmentB._key\n  }\n\n  if (isIndexSegment(segmentA)) {\n    return Number(segmentA) === Number(segmentB)\n  }\n\n  if (isIndexTuple(segmentA) && isIndexTuple(segmentB)) {\n    return segmentA[0] === segmentB[0] && segmentA[1] === segmentB[1]\n  }\n\n  return segmentA === segmentB\n}\n\nexport function hasFocus(focusPath: Path, path: Path): boolean {\n  const withoutTerminator =\n    focusPath[focusPath.length - 1] === FOCUS_TERMINATOR ? focusPath.slice(0, -1) : focusPath\n  return isEqual(withoutTerminator, path)\n}\n\nexport function hasItemFocus(focusPath: Path, item: PathSegment): boolean {\n  return focusPath.length === 1 && isSegmentEqual(focusPath[0], item)\n}\n\nexport function isExpanded(segment: PathSegment, focusPath: Path): boolean {\n  const [head, ...tail] = focusPath\n  return tail.length > 0 && isSegmentEqual(segment, head)\n}\n\nexport function startsWith(prefix: Path, path: Path): boolean {\n  return prefix.every((segment, i) => isSegmentEqual(segment, path[i]))\n}\n\nexport function trimLeft(prefix: Path, path: Path): Path {\n  if (prefix.length === 0 || path.length === 0) {\n    return path\n  }\n  const [prefixHead, ...prefixTail] = prefix\n  const [pathHead, ...pathTail] = path\n  if (!isSegmentEqual(prefixHead, pathHead)) {\n    return path\n  }\n  return pathFor(trimLeft(prefixTail, pathTail))\n}\n\nexport function trimRight(suffix: Path, path: Path): Path {\n  const sufLen = suffix.length\n  const pathLen = path.length\n  if (sufLen === 0 || pathLen === 0) {\n    return path\n  }\n\n  let i = 0\n  while (\n    i < sufLen &&\n    i < pathLen &&\n    isSegmentEqual(path[pathLen - i - 1], suffix[sufLen - i - 1])\n  ) {\n    i++\n  }\n\n  return pathFor(path.slice(0, pathLen - i))\n}\n\nexport function trimChildPath(path: Path, childPath: Path): Path {\n  return startsWith(path, childPath) ? trimLeft(path, childPath) : EMPTY_PATH\n}\n\nexport function toString(path: Path): string {\n  if (!Array.isArray(path)) {\n    throw new Error('Path is not an array')\n  }\n\n  return path.reduce<string>((target, segment, i) => {\n    const isHead = i === 0\n\n    if (typeof segment === 'number') {\n      return `${target}[${segment}]`\n    }\n\n    if (typeof segment === 'string') {\n      if (isHead) {\n        return segment\n      }\n\n      if (GROQ_DATA_TYPE_VALUES.includes(segment)) {\n        return `${target}[\"${segment}\"]`\n      }\n\n      return `${target}.${segment}`\n    }\n\n    if (isKeySegment(segment) && segment._key) {\n      return `${target}[_key==\"${segment._key}\"]`\n    }\n\n    if (Array.isArray(segment)) {\n      const [from, to] = segment\n      return `${target}[${from}:${to}]`\n    }\n\n    throw new Error(`Unsupported path segment \\`${JSON.stringify(segment)}\\``)\n  }, '')\n}\n\nexport function _resolveKeyedPath(value: unknown, path: Path): Path {\n  if (path.length === 0) {\n    return path\n  }\n  const [next, ...rest] = path\n  if (typeof next === 'number') {\n    if (!Array.isArray(value) || !(next in value)) {\n      return []\n    }\n    const item = value[next]\n    const key = item?._key\n    return [typeof key === 'string' ? {_key: item._key} : next, ..._resolveKeyedPath(item, rest)]\n  }\n  const nextVal = get(value, [next])\n  return [next, ..._resolveKeyedPath(nextVal, rest)]\n}\n\n/**\n * Takes a value and a path that may include numeric indices and attempts to replace numeric indices with keyed paths\n *\n * @param value - any json value\n * @param path - a Path that may include numeric indices\n * @returns a path where numeric indices has been replaced by keyed segments (e.g. `{_key: <key>}`)\n * Will do as good attempt as possible, but in case of missing array items, it will return the best possible match:\n * - `resolveKeyedPath([0, 'bar'], [])` will return [] since array has no value at index 0\n * - `resolveKeyedPath([0, 'foo'], [{_key: 'xyz', 'foo': 'bar'}, {_key: 'abc'}])` will return `[{_key: 'xyz'}, 'foo']` since array has no value at index 0\n * - `resolveKeyedPath([0, 'foo', 'bar'], [{_key: 'xyz'}])` will return `[{_key: 'xyz'}, 'foo', 'bar']` since array has no value at index 0\n * Object keys will be preserved as-is, e.g. `resolveKeyedPath(['foo', 'bar'], undefined)` will return `['foo', 'bar']`\n */\nexport function resolveKeyedPath(value: unknown, path: Path): Path {\n  if (!Array.isArray(path)) {\n    throw new Error('Path is not an array')\n  }\n  return pathFor(_resolveKeyedPath(value, path))\n}\n\nexport function fromString(path: string): Path {\n  if (typeof path !== 'string') {\n    throw new Error('Path is not a string')\n  }\n\n  const segments = path.match(rePropName)\n  if (!segments) {\n    throw new Error('Invalid path string')\n  }\n\n  return segments.map(normalizePathSegment)\n}\n\nfunction normalizePathSegment(segment: string): PathSegment {\n  if (isIndexSegment(segment)) {\n    return normalizeIndexSegment(segment)\n  }\n\n  if (isKeySegment(segment)) {\n    return normalizeKeySegment(segment)\n  }\n\n  if (isIndexTuple(segment)) {\n    return normalizeIndexTupleSegment(segment)\n  }\n\n  return segment\n}\n\nfunction normalizeIndexSegment(segment: string): PathSegment {\n  return Number(segment.replace(/[^\\d]/g, ''))\n}\n\nfunction normalizeKeySegment(segment: string): KeyedSegment {\n  const segments = segment.match(reKeySegment)\n  return {_key: segments![1]}\n}\n\nfunction normalizeIndexTupleSegment(segment: string): IndexTuple {\n  const [from, to] = segment.split(':').map((seg) => (seg === '' ? seg : Number(seg)))\n  return [from, to]\n}\n"],"names":[],"mappings":"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"}