{"version":3,"file":"get-field.mjs","names":[],"sources":["../src/get-field.ts"],"sourcesContent":["/* -------------------------------------------------------------------\n\n                       🗲 Storm Software - Stryke\n\n This code was released as part of the Stryke project. Stryke\n is maintained by Storm Software under the Apache-2.0 license, and is\n free for commercial and private use. For more information, please visit\n our licensing page at https://stormsoftware.com/licenses/projects/stryke.\n\n Website:                  https://stormsoftware.com\n Repository:               https://github.com/storm-software/stryke\n Documentation:            https://docs.stormsoftware.com/projects/stryke\n Contact:                  https://stormsoftware.com/contact\n\n SPDX-License-Identifier:  Apache-2.0\n\n ------------------------------------------------------------------- */\n\nimport { toStringKey } from \"@stryke/convert\";\nimport { isDeepKey, isNumber } from \"@stryke/type-checks\";\nimport { toPath } from \"./to-path\";\n\n/**\n * See the definition of `@types/lodash`.\n */\ntype GetIndexedField<T, K> = K extends keyof T\n  ? T[K]\n  : K extends `${number}`\n    ? \"length\" extends keyof T\n      ? number extends T[\"length\"]\n        ? number extends keyof T\n          ? T[number]\n          : undefined\n        : undefined\n      : undefined\n    : undefined;\n\ntype FieldWithPossiblyUndefined<T, Key> =\n  | GetField<Exclude<T, undefined>, Key>\n  | Extract<T, undefined>;\n\ntype IndexedFieldWithPossiblyUndefined<T, Key> =\n  | GetIndexedField<Exclude<T, undefined>, Key>\n  | Extract<T, undefined>;\n\nexport type GetField<T, P> = P extends `${infer Left}.${infer Right}`\n  ? Left extends keyof Exclude<T, undefined>\n    ?\n        | FieldWithPossiblyUndefined<Exclude<T, undefined>[Left], Right>\n        | Extract<T, undefined>\n    : Left extends `${infer FieldKey}[${infer IndexKey}]`\n      ? FieldKey extends keyof T\n        ? FieldWithPossiblyUndefined<\n            IndexedFieldWithPossiblyUndefined<T[FieldKey], IndexKey>,\n            Right\n          >\n        : undefined\n      : undefined\n  : P extends keyof T\n    ? T[P]\n    : P extends `${infer FieldKey}[${infer IndexKey}]`\n      ? FieldKey extends keyof T\n        ? IndexedFieldWithPossiblyUndefined<T[FieldKey], IndexKey>\n        : undefined\n      : IndexedFieldWithPossiblyUndefined<T, P>;\n\n/**\n * Retrieves the value at a given path from an object. If the resolved value is undefined, the defaultValue is returned instead.\n *\n * @typeParam T - The type of the object.\n * @typeParam K - The type of the key in the object.\n *\n * @param object - The object to query.\n * @param path - The path of the property to get.\n * @returns The resolved value.\n */\nexport function getField<T extends object, K extends keyof T>(\n  object: T,\n  path: K | readonly [K]\n): T[K];\n/**\n * Retrieves the value at a given path from an object. If the resolved value is undefined, the defaultValue is returned instead.\n *\n * @typeParam T - The type of the object.\n * @typeParam K - The type of the key in the object.\n *\n * @param object - The object to query.\n * @param path - The path of the property to get.\n * @returns The resolved value or undefined.\n */\nexport function getField<T extends object, K extends keyof T>(\n  object: T | null | undefined,\n  path: K | readonly [K]\n): T[K] | undefined;\n/**\n * Retrieves the value at a given path from an object. If the resolved value is undefined, the defaultValue is returned instead.\n *\n * @typeParam T - The type of the object.\n * @typeParam K - The type of the key in the object.\n * @typeParam D - The type of the default value.\n *\n * @param object - The object to query.\n * @param path - The path of the property to get.\n * @param defaultValue - The value returned if the resolved value is undefined.\n * @returns The resolved value or default value.\n */\nexport function getField<T extends object, K extends keyof T, D>(\n  object: T | null | undefined,\n  path: K | readonly [K],\n  defaultValue: D\n): Exclude<T[K], undefined> | D;\n/**\n * Retrieves the value at a given path from an object. If the resolved value is undefined, the defaultValue is returned instead.\n *\n * @typeParam T - The type of the object.\n * @typeParam K1 - The type of the first key in the object.\n * @typeParam K2 - The type of the second key in the object.\n *\n * @param object - The object to query.\n * @param path - The path of the property to get.\n * @returns The resolved value.\n */\nexport function getField<\n  T extends object,\n  K1 extends keyof T,\n  K2 extends keyof T[K1]\n>(object: T, path: readonly [K1, K2]): T[K1][K2];\n/**\n * Retrieves the value at a given path from an object. If the resolved value is undefined, the defaultValue is returned instead.\n *\n * @typeParam T - The type of the object.\n * @typeParam K1 - The type of the first key in the object.\n * @typeParam K2 - The type of the second key in the object.\n *\n * @param object - The object to query.\n * @param path - The path of the property to get.\n * @returns The resolved value or undefined.\n */\nexport function getField<\n  T extends object,\n  K1 extends keyof T,\n  K2 extends keyof T[K1]\n>(object: T | null | undefined, path: readonly [K1, K2]): T[K1][K2] | undefined;\n/**\n * Retrieves the value at a given path from an object. If the resolved value is undefined, the defaultValue is returned instead.\n *\n * @typeParam T - The type of the object.\n * @typeParam K1 - The type of the first key in the object.\n * @typeParam K2 - The type of the second key in the object.\n * @typeParam D - The type of the default value.\n *\n * @param object - The object to query.\n * @param path - The path of the property to get.\n * @param defaultValue - The value returned if the resolved value is undefined.\n * @returns The resolved value or default value.\n */\nexport function getField<\n  T extends object,\n  K1 extends keyof T,\n  K2 extends keyof T[K1],\n  D\n>(\n  object: T | null | undefined,\n  path: readonly [K1, K2],\n  defaultValue: D\n): Exclude<T[K1][K2], undefined> | D;\n/**\n * Retrieves the value at a given path from an object. If the resolved value is undefined, the defaultValue is returned instead.\n *\n * @typeParam T - The type of the object.\n * @typeParam K1 - The type of the first key in the object.\n * @typeParam K2 - The type of the second key in the object.\n * @typeParam K3 - The type of the third key in the object.\n *\n * @param object - The object to query.\n * @param path - The path of the property to get.\n * @returns The resolved value.\n */\nexport function getField<\n  T extends object,\n  K1 extends keyof T,\n  K2 extends keyof T[K1],\n  K3 extends keyof T[K1][K2]\n>(object: T, path: readonly [K1, K2, K3]): T[K1][K2][K3];\n/**\n * Retrieves the value at a given path from an object. If the resolved value is undefined, the defaultValue is returned instead.\n *\n * @typeParam T - The type of the object.\n * @typeParam K1 - The type of the first key in the object.\n * @typeParam K2 - The type of the second key in the object.\n * @typeParam K3 - The type of the third key in the object.\n *\n * @param object - The object to query.\n * @param path - The path of the property to get.\n * @returns The resolved value or undefined.\n */\nexport function getField<\n  T extends object,\n  K1 extends keyof T,\n  K2 extends keyof T[K1],\n  K3 extends keyof T[K1][K2]\n>(\n  object: T | null | undefined,\n  path: readonly [K1, K2, K3]\n): T[K1][K2][K3] | undefined;\n/**\n * Retrieves the value at a given path from an object. If the resolved value is undefined, the defaultValue is returned instead.\n *\n * @typeParam T - The type of the object.\n * @typeParam K1 - The type of the first key in the object.\n * @typeParam K2 - The type of the second key in the object.\n * @typeParam K3 - The type of the third key in the object.\n * @typeParam D - The type of the default value.\n *\n * @param object - The object to query.\n * @param path - The path of the property to get.\n * @param defaultValue - The value returned if the resolved value is undefined.\n * @returns The resolved value or default value.\n */\nexport function getField<\n  T extends object,\n  K1 extends keyof T,\n  K2 extends keyof T[K1],\n  K3 extends keyof T[K1][K2],\n  D\n>(\n  object: T | null | undefined,\n  path: readonly [K1, K2, K3],\n  defaultValue: D\n): Exclude<T[K1][K2][K3], undefined> | D;\n/**\n * Retrieves the value at a given path from an object. If the resolved value is undefined, the defaultValue is returned instead.\n *\n * @typeParam T - The type of the object.\n * @typeParam K1 - The type of the first key in the object.\n * @typeParam K2 - The type of the second key in the object.\n * @typeParam K3 - The type of the third key in the object.\n * @typeParam K4 - The type of the fourth key in the object.\n *\n * @param object - The object to query.\n * @param path - The path of the property to get.\n * @returns The resolved value.\n */\nexport function getField<\n  T extends object,\n  K1 extends keyof T,\n  K2 extends keyof T[K1],\n  K3 extends keyof T[K1][K2],\n  K4 extends keyof T[K1][K2][K3]\n>(object: T, path: readonly [K1, K2, K3, K4]): T[K1][K2][K3][K4];\n/**\n * Retrieves the value at a given path from an object. If the resolved value is undefined, the defaultValue is returned instead.\n *\n * @typeParam T - The type of the object.\n * @typeParam K1 - The type of the first key in the object.\n * @typeParam K2 - The type of the second key in the object.\n * @typeParam K3 - The type of the third key in the object.\n * @typeParam K4 - The type of the fourth key in the object.\n *\n * @param object - The object to query.\n * @param path - The path of the property to get.\n * @returns The resolved value or undefined.\n */\nexport function getField<\n  T extends object,\n  K1 extends keyof T,\n  K2 extends keyof T[K1],\n  K3 extends keyof T[K1][K2],\n  K4 extends keyof T[K1][K2][K3]\n>(\n  object: T | null | undefined,\n  path: readonly [K1, K2, K3, K4]\n): T[K1][K2][K3][K4] | undefined;\n/**\n * Retrieves the value at a given path from an object. If the resolved value is undefined, the defaultValue is returned instead.\n *\n * @typeParam T - The type of the object.\n * @typeParam K1 - The type of the first key in the object.\n * @typeParam K2 - The type of the second key in the object.\n * @typeParam K3 - The type of the third key in the object.\n * @typeParam K4 - The type of the fourth key in the object.\n * @typeParam D - The type of the default value.\n *\n * @param object - The object to query.\n * @param path - The path of the property to get.\n * @param defaultValue - The value returned if the resolved value is undefined.\n * @returns The resolved value or default value.\n */\nexport function getField<\n  T extends object,\n  K1 extends keyof T,\n  K2 extends keyof T[K1],\n  K3 extends keyof T[K1][K2],\n  K4 extends keyof T[K1][K2][K3],\n  D\n>(\n  object: T | null | undefined,\n  path: readonly [K1, K2, K3, K4],\n  defaultValue: D\n): Exclude<T[K1][K2][K3][K4], undefined> | D;\n/**\n * Retrieves the value at a given path from an object with numeric keys. If the resolved value is undefined, the defaultValue is returned instead.\n *\n * @typeParam T - The type of the value.\n *\n * @param object - The object to query.\n * @param path - The path of the property to get.\n * @returns The resolved value.\n */\nexport function getField<T>(object: Record<number, T>, path: number): T;\n/**\n * Retrieves the value at a given path from an object with numeric keys. If the resolved value is undefined, the defaultValue is returned instead.\n *\n * @typeParam T - The type of the value.\n *\n * @param object - The object to query.\n * @param path - The path of the property to get.\n * @returns The resolved value or undefined.\n */\nexport function getField<T>(\n  object: Record<number, T> | null | undefined,\n  path: number\n): T | undefined;\n/**\n * Retrieves the value at a given path from an object with numeric keys. If the resolved value is undefined, the defaultValue is returned instead.\n *\n * @typeParam T - The type of the value.\n * @typeParam D - The type of the default value.\n *\n * @param object - The object to query.\n * @param path - The path of the property to get.\n * @param defaultValue - The value returned if the resolved value is undefined.\n * @returns The resolved value or default value.\n */\nexport function getField<T, D>(\n  object: Record<number, T> | null | undefined,\n  path: number,\n  defaultValue: D\n): T | D;\n/**\n * Retrieves the value at a given path from a null or undefined object, returning the default value.\n *\n * @typeParam D - The type of the default value.\n *\n * @param object - The object to query.\n * @param path - The path of the property to get.\n * @param defaultValue - The value returned if the resolved value is undefined.\n * @returns The default value.\n */\nexport function getField<D>(\n  object: null | undefined,\n  path: PropertyKey,\n  defaultValue: D\n): D;\n\n/**\n * Retrieves the value at a given path from a null or undefined object, returning undefined.\n *\n * @param object - The object to query.\n * @param path - The path of the property to get.\n */\nexport function getField(\n  object: null | undefined,\n  path: PropertyKey\n): undefined;\n\n/**\n * Retrieves the value at a given path from a string-keyed object. If the resolved value is undefined, the defaultValue is returned instead.\n *\n * @typeParam T - The type of the object.\n * @typeParam P - The type of the path.\n *\n * @param data - The object to query.\n * @param path - The path of the property to get.\n * @returns The resolved value, or any if path is a general string.\n */\nexport function getField<T, P extends string>(\n  data: T,\n  path: P\n): string extends P ? any : GetField<T, P>;\n/**\n * Retrieves the value at a given path from a string-keyed object. If the resolved value is undefined, the defaultValue is returned instead.\n *\n * @typeParam T - The type of the object.\n * @typeParam P - The type of the path.\n * @typeParam D - The type of the default value.\n *\n * @param data - The object to query.\n * @param path - The path of the property to get.\n * @param defaultValue - The value returned if the resolved value is undefined.\n * @returns The resolved value or default value.\n */\nexport function getField<T, P extends string, D = GetField<T, P>>(\n  data: T,\n  path: P,\n  defaultValue: D\n): Exclude<GetField<T, P>, null | undefined> | D;\n/**\n * Retrieves the value at a given path from an object. If the resolved value is undefined, the defaultValue is returned instead.\n *\n * @param object - The object to query.\n * @param path - The path of the property to get.\n * @param defaultValue - The value returned if the resolved value is undefined.\n * @returns The resolved value.\n */\nexport function getField(\n  object: unknown,\n  path: PropertyKey | readonly PropertyKey[],\n  defaultValue?: unknown\n): any;\n/**\n * Retrieves the value at a given path from an object. If the resolved value is undefined, the defaultValue is returned instead.\n *\n * @param object - The object to query.\n * @param path - The path of the property to get.\n * @param defaultValue - The value returned if the resolved value is undefined.\n * @returns The resolved value.\n */\nexport function getField(\n  object: any,\n  path: PropertyKey | readonly PropertyKey[],\n  defaultValue?: any\n): any {\n  if (object === null) {\n    return defaultValue;\n  }\n\n  switch (typeof path) {\n    case \"string\": {\n      const result = object[path];\n\n      if (result === undefined) {\n        if (isDeepKey(path)) {\n          return getField(object, toPath(path), defaultValue);\n        }\n        return defaultValue;\n      }\n\n      return result;\n    }\n    case \"number\":\n    case \"symbol\": {\n      if (isNumber(path)) {\n        path = toStringKey(path);\n      }\n\n      const result = Array.isArray(path)\n        ? undefined\n        : object[path as PropertyKey];\n      if (result === undefined) {\n        return defaultValue;\n      }\n\n      return result;\n    }\n    case \"bigint\":\n    case \"boolean\":\n    case \"undefined\":\n    case \"object\":\n    case \"function\":\n    default: {\n      if (Array.isArray(path)) {\n        return getWithPath(object, path, defaultValue);\n      }\n\n      path = Object.is(path?.valueOf(), -0) ? \"-0\" : String(path);\n\n      const result = object[path];\n\n      if (result === undefined) {\n        return defaultValue;\n      }\n\n      return result;\n    }\n  }\n}\n\nfunction getWithPath(\n  object: any,\n  path: readonly PropertyKey[],\n  defaultValue?: any\n): any {\n  if (path.length === 0) {\n    return defaultValue;\n  }\n\n  let current = object;\n\n  for (const element of path) {\n    if (current === null) {\n      return defaultValue;\n    }\n\n    current = current[element];\n  }\n\n  if (current === undefined) {\n    return defaultValue;\n  }\n\n  return current;\n}\n"],"mappings":";;;;;;;;;;;;;AAkaA,SAAgB,SACd,QACA,MACA,cACK;AACL,KAAI,WAAW,KACb,QAAO;AAGT,SAAQ,OAAO,MAAf;EACE,KAAK,UAAU;GACb,MAAM,SAAS,OAAO;AAEtB,OAAI,WAAW,QAAW;AACxB,QAAI,UAAU,KAAK,CACjB,QAAO,SAAS,QAAQ,OAAO,KAAK,EAAE,aAAa;AAErD,WAAO;;AAGT,UAAO;;EAET,KAAK;EACL,KAAK,UAAU;AACb,OAAI,SAAS,KAAK,CAChB,QAAO,YAAY,KAAK;GAG1B,MAAM,SAAS,MAAM,QAAQ,KAAK,GAC9B,SACA,OAAO;AACX,OAAI,WAAW,OACb,QAAO;AAGT,UAAO;;EAOT,SAAS;AACP,OAAI,MAAM,QAAQ,KAAK,CACrB,QAAO,YAAY,QAAQ,MAAM,aAAa;AAGhD,UAAO,OAAO,GAAG,MAAM,SAAS,EAAE,GAAG,GAAG,OAAO,OAAO,KAAK;GAE3D,MAAM,SAAS,OAAO;AAEtB,OAAI,WAAW,OACb,QAAO;AAGT,UAAO;;;;AAKb,SAAS,YACP,QACA,MACA,cACK;AACL,KAAI,KAAK,WAAW,EAClB,QAAO;CAGT,IAAI,UAAU;AAEd,MAAK,MAAM,WAAW,MAAM;AAC1B,MAAI,YAAY,KACd,QAAO;AAGT,YAAU,QAAQ;;AAGpB,KAAI,YAAY,OACd,QAAO;AAGT,QAAO"}