@tanstack/query-core
Version:
The framework agnostic core that powers TanStack Query
1 lines • 28.9 kB
Source Map (JSON)
{"version":3,"file":"utils.cjs","names":[],"sources":["../../src/utils.ts"],"sourcesContent":["import { timeoutManager } from './timeoutManager'\nimport type {\n DefaultError,\n FetchStatus,\n MutationKey,\n MutationStatus,\n QueryFunction,\n QueryKey,\n QueryOptions,\n} from './types'\nimport type { Mutation } from './mutation'\nimport type { FetchOptions, Query } from './query'\n\n// TYPES\n\ntype DropLast<T extends ReadonlyArray<unknown>> = T extends readonly [\n ...infer R,\n unknown,\n]\n ? readonly [...R]\n : never\n\ntype TuplePrefixes<T extends ReadonlyArray<unknown>> = T extends readonly []\n ? readonly []\n : TuplePrefixes<DropLast<T>> | T\n\n/**\n * Filters used to select queries, for example in `queryClient.getQueriesData` or `queryClient.invalidateQueries`.\n * All provided filters must match; filters that are left unspecified are ignored.\n */\nexport interface QueryFilters<TQueryKey extends QueryKey = QueryKey> {\n /**\n * Filter to active queries, inactive queries or all queries\n * @defaultValue 'all'\n */\n type?: QueryTypeFilter\n /**\n * Match query key exactly\n */\n exact?: boolean\n /**\n * Include queries matching this predicate function\n */\n predicate?: (query: Query) => boolean\n /**\n * Include queries matching this query key\n */\n queryKey?: TQueryKey | TuplePrefixes<TQueryKey>\n /**\n * Include or exclude stale queries\n */\n stale?: boolean\n /**\n * Include queries matching their fetchStatus\n */\n fetchStatus?: FetchStatus\n}\n\n/**\n * Filters used to select mutations, for example in `mutationCache.findAll` or `queryClient.isMutating`.\n * All provided filters must match; filters that are left unspecified are ignored.\n */\nexport interface MutationFilters<\n TData = unknown,\n TError = DefaultError,\n TVariables = unknown,\n TOnMutateResult = unknown,\n> {\n /**\n * Match mutation key exactly\n */\n exact?: boolean\n /**\n * Include mutations matching this predicate function\n */\n predicate?: (\n mutation: Mutation<TData, TError, TVariables, TOnMutateResult>,\n ) => boolean\n /**\n * Include mutations matching this mutation key\n */\n mutationKey?: TuplePrefixes<MutationKey>\n /**\n * Filter by mutation status\n */\n status?: MutationStatus\n}\n\n/**\n * Either a plain value of type `TOutput`, or a function that receives `TInput` and returns `TOutput`.\n * Used for example by `setQueryData`-style updaters, which accept either the new data directly or a\n * function that computes it from the previous data. See {@link functionalUpdate}.\n * @example\n * ```ts\n * queryClient.setQueryData(['posts'], newPosts)\n *\n * // Or, using an updater function that receives the current data:\n * queryClient.setQueryData(['posts'], (oldPosts) =>\n * oldPosts ? [...oldPosts, newPost] : oldPosts,\n * )\n * ```\n */\nexport type Updater<TInput, TOutput> = TOutput | ((input: TInput) => TOutput)\n\n/**\n * Which queries a filter matches: all of them, only active ones (with enabled observers), or only\n * inactive ones.\n */\nexport type QueryTypeFilter = 'all' | 'active' | 'inactive'\n\n// UTILS\n\n/**\n * @deprecated use `environmentManager.isServer()` instead.\n */\nexport const isServer = typeof window === 'undefined' || 'Deno' in globalThis\n\n/**\n * A function that does nothing.\n */\nexport function noop(): void\nexport function noop(): undefined\nexport function noop() {}\n\n/**\n * Resolves an {@link Updater}: calls it with `input` if it is a function, otherwise returns it as\n * is.\n * @param updater - The new value, or a function that receives `input` and returns the new value.\n * @param input - The current value, passed to `updater` if it is a function.\n * @returns The new value.\n */\nexport function functionalUpdate<TInput, TOutput>(\n updater: Updater<TInput, TOutput>,\n input: TInput,\n): TOutput {\n return typeof updater === 'function'\n ? (updater as (_: TInput) => TOutput)(input)\n : updater\n}\n\n/**\n * Checks whether a value can be used as a timeout: a non-negative, finite number.\n * @param value - The value to check.\n * @returns `true` if `value` is a number that is `>= 0` and not `Infinity`.\n */\nexport function isValidTimeout(value: unknown): value is number {\n return typeof value === 'number' && value >= 0 && value !== Infinity\n}\n\n/**\n * Calculates how long until data updated at `updatedAt` becomes stale.\n * @param updatedAt - The timestamp, in milliseconds, at which the data was last updated.\n * @param staleTime - The time, in milliseconds, after which data is considered stale. Defaults to\n * `0`.\n * @returns The remaining time in milliseconds, or `0` if the data is already stale.\n */\nexport function timeUntilStale(updatedAt: number, staleTime?: number): number {\n return Math.max(updatedAt + (staleTime || 0) - Date.now(), 0)\n}\n\n/**\n * Resolves an option that can be given either as a value or as a function of the query, such as\n * `staleTime`.\n * @param value - The option value, or a function that receives `query` and returns the value.\n * @param query - The query passed to `value` if it is a function.\n * @returns The resolved value, or `undefined` if `value` is `undefined`.\n */\nexport function resolveQueryValue<\n TValue,\n TQueryFnData = unknown,\n TError = DefaultError,\n TData = TQueryFnData,\n TQueryKey extends QueryKey = QueryKey,\n>(\n value:\n | undefined\n | TValue\n | ((query: Query<TQueryFnData, TError, TData, TQueryKey>) => TValue),\n query: Query<TQueryFnData, TError, TData, TQueryKey>,\n): TValue | undefined {\n return typeof value === 'function'\n ? (\n value as (\n query: Query<TQueryFnData, TError, TData, TQueryKey>,\n ) => TValue\n )(query)\n : value\n}\n\n/**\n * Checks whether a query matches the given {@link QueryFilters}.\n * Every filter that is specified must match; filters that are left unspecified are ignored.\n * @param filters - The filters to check the query against.\n * @param query - The query to check.\n * @returns `true` if the query matches every specified filter.\n * @example\n * ```ts\n * const queryCache = queryClient.getQueryCache()\n *\n * const matchingQueries = queryCache\n * .getAll()\n * .filter((query) => matchQuery({ queryKey: ['posts'] }, query))\n * ```\n */\nexport function matchQuery(\n filters: QueryFilters,\n query: Query<any, any, any, any>,\n): boolean {\n const {\n type = 'all',\n exact,\n fetchStatus,\n predicate,\n queryKey,\n stale,\n } = filters\n\n if (queryKey) {\n if (exact) {\n if (query.queryHash !== hashQueryKeyByOptions(queryKey, query.options)) {\n return false\n }\n } else if (!partialMatchKey(query.queryKey, queryKey)) {\n return false\n }\n }\n\n if (type !== 'all') {\n const isActive = query.isActive()\n if (type === 'active' && !isActive) {\n return false\n }\n if (type === 'inactive' && isActive) {\n return false\n }\n }\n\n if (typeof stale === 'boolean' && query.isStale() !== stale) {\n return false\n }\n\n if (fetchStatus && fetchStatus !== query.state.fetchStatus) {\n return false\n }\n\n if (predicate && !predicate(query)) {\n return false\n }\n\n return true\n}\n\n/**\n * Checks whether a mutation matches the given {@link MutationFilters}.\n * Every filter that is specified must match; filters that are left unspecified are ignored.\n * If a `mutationKey` filter is provided but the mutation has no `mutationKey` of its own, it does not match.\n * @param filters - The filters to check the mutation against.\n * @param mutation - The mutation to check.\n * @returns `true` if the mutation matches every specified filter.\n * @example\n * ```ts\n * const mutationCache = queryClient.getMutationCache()\n *\n * const matchingMutations = mutationCache\n * .getAll()\n * .filter((mutation) => matchMutation({ mutationKey: ['addPost'] }, mutation))\n * ```\n */\nexport function matchMutation(\n filters: MutationFilters,\n mutation: Mutation<any, any>,\n): boolean {\n const { exact, status, predicate, mutationKey } = filters\n if (mutationKey) {\n if (!mutation.options.mutationKey) {\n return false\n }\n if (exact) {\n if (hashKey(mutation.options.mutationKey) !== hashKey(mutationKey)) {\n return false\n }\n } else if (!partialMatchKey(mutation.options.mutationKey, mutationKey)) {\n return false\n }\n }\n\n if (status && mutation.state.status !== status) {\n return false\n }\n\n if (predicate && !predicate(mutation)) {\n return false\n }\n\n return true\n}\n\n/**\n * Hashes a query key with the query's `queryKeyHashFn` option, falling back to {@link hashKey}.\n * @param queryKey - The query key to hash.\n * @param options - The query options that may provide a custom `queryKeyHashFn`.\n * @returns The query hash, a string that identifies the query in the cache.\n */\nexport function hashQueryKeyByOptions<TQueryKey extends QueryKey = QueryKey>(\n queryKey: TQueryKey,\n options?: Pick<QueryOptions<any, any, any, any>, 'queryKeyHashFn'>,\n): string {\n const hashFn = options?.queryKeyHashFn || hashKey\n return hashFn(queryKey)\n}\n\n/**\n * Default query & mutation keys hash function.\n * Hashes the value into a stable hash.\n * @param queryKey - The query or mutation key to hash.\n * @returns The stable hash of the key, as a JSON string.\n * @example\n * ```ts\n * // Object keys are sorted, so key order doesn't affect the hash:\n * hashKey(['todos', { page: 1, filter: 'done' }]) // === '[\"todos\",{\"filter\":\"done\",\"page\":1}]'\n * ```\n */\nexport function hashKey(queryKey: QueryKey | MutationKey): string {\n return JSON.stringify(queryKey, (_, val) =>\n isPlainObject(val)\n ? Object.keys(val)\n .sort()\n .reduce((result, key) => {\n result[key] = val[key]\n return result\n }, {} as any)\n : val,\n )\n}\n\n/**\n * Checks if key `b` partially matches with key `a`.\n * @param a - The key to check, e.g. a query's own key.\n * @param b - The (partial) key to match against `a`.\n * @returns `true` if every array element or object property in `b` matches the one at the same\n * position in `a`.\n */\nexport function partialMatchKey(a: QueryKey, b: QueryKey): boolean\nexport function partialMatchKey(a: any, b: any): boolean {\n if (a === b) {\n return true\n }\n\n if (typeof a !== typeof b) {\n return false\n }\n\n if (a && b && typeof a === 'object' && typeof b === 'object') {\n if (Array.isArray(a) && Array.isArray(b)) {\n if (b.length > a.length) return false\n for (let i = 0; i < b.length; i++) {\n if (!partialMatchKey(a[i], b[i])) {\n return false\n }\n }\n return true\n }\n\n const bKeys = Object.keys(b)\n for (const key of bKeys) {\n if (!partialMatchKey(a[key], b[key])) {\n return false\n }\n }\n return true\n }\n\n return false\n}\n\nconst hasOwn = Object.prototype.hasOwnProperty\n\n/**\n * This function returns `a` if `b` is deeply equal.\n * If not, it will replace any deeply equal children of `b` with those of `a`.\n * This can be used for structural sharing between JSON values for example.\n * @param a - The previous value, whose deeply equal parts are reused.\n * @param b - The new value.\n * @param depth - The current recursion depth. Past a depth of `500`, `b` is returned as is.\n * @returns `a` if `b` is deeply equal to it, otherwise `b` with its deeply equal parts replaced by\n * those of `a`.\n */\nexport function replaceEqualDeep<T>(a: unknown, b: T, depth?: number): T\nexport function replaceEqualDeep(a: any, b: any, depth = 0): any {\n if (a === b) {\n return a\n }\n\n if (depth > 500) return b\n\n const array = isPlainArray(a) && isPlainArray(b)\n\n if (!array && !(isPlainObject(a) && isPlainObject(b))) return b\n\n const aItems = array ? a : Object.keys(a)\n const aSize = aItems.length\n const bItems = array ? b : Object.keys(b)\n const bSize = bItems.length\n const copy: any = array ? new Array(bSize) : {}\n\n let equalItems = 0\n\n for (let i = 0; i < bSize; i++) {\n const key: any = array ? i : bItems[i]\n const aItem = a[key]\n const bItem = b[key]\n\n if (aItem === bItem) {\n copy[key] = aItem\n if (array ? i < aSize : hasOwn.call(a, key)) equalItems++\n continue\n }\n\n if (\n aItem === null ||\n bItem === null ||\n typeof aItem !== 'object' ||\n typeof bItem !== 'object'\n ) {\n copy[key] = bItem\n continue\n }\n\n const v = replaceEqualDeep(aItem, bItem, depth + 1)\n copy[key] = v\n if (v === aItem) equalItems++\n }\n\n return aSize === bSize && equalItems === aSize ? a : copy\n}\n\n/**\n * Shallow compare objects.\n * @param a - The first object.\n * @param b - The second object, or `undefined`.\n * @returns `true` if both objects have the same keys, with strictly equal values for each key.\n */\nexport function shallowEqualObjects<T extends Record<string, any>>(\n a: T,\n b: T | undefined,\n): boolean {\n if (!b || Object.keys(a).length !== Object.keys(b).length) {\n return false\n }\n\n for (const key in a) {\n if (a[key] !== b[key]) {\n return false\n }\n }\n\n return true\n}\n\n/**\n * Checks whether a value is an array with no holes and no extra properties.\n * @param value - The value to check.\n * @returns `true` if `value` is an array whose number of own keys equals its `length`.\n */\nexport function isPlainArray(value: unknown): value is Array<unknown> {\n return Array.isArray(value) && value.length === Object.keys(value).length\n}\n\n// Copied from: https://github.com/jonschlinkert/is-plain-object\n/**\n * Checks whether a value is a plain object, e.g. created with an object literal or\n * `Object.create(null)`.\n * @param o - The value to check.\n * @returns `true` if `o` is a plain object.\n */\nexport function isPlainObject(o: any): o is Record<PropertyKey, unknown> {\n if (!hasObjectPrototype(o)) {\n return false\n }\n\n // If has no constructor\n const objectPrototype = Object.getPrototypeOf(o)\n const ctor = objectPrototype?.constructor\n if (ctor === undefined) {\n return true\n }\n\n if (typeof ctor !== 'function') {\n return false\n }\n\n // If has modified prototype\n const prot = ctor.prototype\n if (!hasObjectPrototype(prot)) {\n return false\n }\n\n // If constructor does not have an Object-specific method\n if (!prot.hasOwnProperty('isPrototypeOf')) {\n return false\n }\n\n // Handles Objects created by Object.create(<arbitrary prototype>)\n if (objectPrototype !== Object.prototype) {\n return false\n }\n\n // Most likely a plain Object\n return true\n}\n\n/**\n * Checks whether a value's `Object.prototype.toString` tag is `[object Object]`.\n * @param o - The value to check.\n * @returns `true` if the tag is `[object Object]`.\n */\nfunction hasObjectPrototype(o: any): boolean {\n return Object.prototype.toString.call(o) === '[object Object]'\n}\n\n/**\n * Waits for the given time, using the configured {@link timeoutManager}.\n * @param timeout - The time to wait, in milliseconds.\n * @returns A promise that resolves after `timeout` milliseconds.\n */\nexport function sleep(timeout: number): Promise<void> {\n return new Promise((resolve) => {\n timeoutManager.setTimeout(resolve, timeout)\n })\n}\n\n/**\n * Applies a query's `structuralSharing` option when writing new data.\n * @param prevData - The previously cached data.\n * @param data - The new data.\n * @param options - The query options, whose `structuralSharing` decides how the data is merged.\n * @returns The result of a custom `structuralSharing` function, `data` with its unchanged parts\n * replaced by those of `prevData` by default, or `data` as is if `structuralSharing` is `false`.\n * @throws {Error} The error from the default structural sharing, e.g. when the data is not JSON serializable.\n * Outside production, it is also logged to the console.\n */\nexport function replaceData<\n TData,\n TOptions extends QueryOptions<any, any, any, any>,\n>(prevData: TData | undefined, data: TData, options: TOptions): TData {\n if (typeof options.structuralSharing === 'function') {\n return options.structuralSharing(prevData, data) as TData\n } else if (options.structuralSharing !== false) {\n if (process.env.NODE_ENV !== 'production') {\n try {\n return replaceEqualDeep(prevData, data)\n } catch (error) {\n console.error(\n `Structural sharing requires data to be JSON serializable. To fix this, turn off structuralSharing or return JSON-serializable data from your queryFn. [${options.queryHash}]: ${error}`,\n )\n\n // Prevent the replaceEqualDeep from being called again down below.\n throw error\n }\n }\n // Structurally share data between prev and new data if needed\n return replaceEqualDeep(prevData, data)\n }\n return data\n}\n\n/**\n * Intended to be passed as a query's `placeholderData` option, for example\n * `placeholderData: keepPreviousData`. Instead of resetting the query's data to `undefined` while a new\n * query key is fetching, it keeps displaying the previously fetched data until the new data arrives.\n * @param previousData - The data of the previous query key, passed by the observer.\n * @returns The previous data, unchanged.\n * @example\n * ```ts\n * new QueryObserver(queryClient, {\n * queryKey: ['posts', page],\n * queryFn: () => fetchPosts(page),\n * placeholderData: keepPreviousData,\n * })\n * ```\n */\nexport function keepPreviousData<T>(\n previousData: T | undefined,\n): T | undefined {\n return previousData\n}\n\n/**\n * Returns a new array with `item` added at the end. If that makes the array longer than `max`,\n * the first item is dropped. Only one item is dropped, so the result can still exceed `max` if\n * `items` already did.\n * @param items - The current items.\n * @param item - The value to append.\n * @param max - The length above which an item is dropped. `0` (the default) means no limit.\n * @returns A new array with `item` added.\n */\nexport function addToEnd<T>(items: Array<T>, item: T, max = 0): Array<T> {\n const newItems = [...items, item]\n return max && newItems.length > max ? newItems.slice(1) : newItems\n}\n\n/**\n * Returns a new array with `item` added at the start. If that makes the array longer than `max`,\n * the last item is dropped. Only one item is dropped, so the result can still exceed `max` if\n * `items` already did.\n * @param items - The current items.\n * @param item - The value to prepend.\n * @param max - The length above which an item is dropped. `0` (the default) means no limit.\n * @returns A new array with `item` added.\n */\nexport function addToStart<T>(items: Array<T>, item: T, max = 0): Array<T> {\n const newItems = [item, ...items]\n return max && newItems.length > max ? newItems.slice(0, -1) : newItems\n}\n\n/**\n * Sentinel value that can be passed as a query's `queryFn` to conditionally disable the query (equivalent\n * to `enabled: false`) while preserving full type inference for the query's data. Unlike `enabled: false`,\n * a query disabled via `skipToken` cannot be triggered with `refetch`.\n * @example\n * ```ts\n * new QueryObserver(queryClient, {\n * queryKey: ['post', postId],\n * queryFn: postId != null ? () => fetchPost(postId) : skipToken,\n * })\n * ```\n */\nexport const skipToken = Symbol()\n/**\n * The type of the {@link skipToken} sentinel value.\n */\nexport type SkipToken = typeof skipToken\n\n/**\n * Returns the function to call for a fetch. If there is no `queryFn` but the fetch was started from\n * an `initialPromise`, that promise is returned instead. If there is no usable `queryFn` (missing or\n * {@link skipToken}), the returned function rejects with a `Missing queryFn` error.\n * @param options - The query options with the `queryFn`, and the `queryHash` used in error messages.\n * @param fetchOptions - The fetch options, which may carry an `initialPromise`.\n * @returns The function to call for the fetch.\n */\nexport function ensureQueryFn<\n TQueryFnData = unknown,\n TQueryKey extends QueryKey = QueryKey,\n>(\n options: {\n queryFn?: QueryFunction<TQueryFnData, TQueryKey> | SkipToken\n queryHash?: string\n },\n fetchOptions?: FetchOptions<TQueryFnData>,\n): QueryFunction<TQueryFnData, TQueryKey> {\n if (process.env.NODE_ENV !== 'production') {\n if (options.queryFn === skipToken) {\n console.error(\n `Attempted to invoke queryFn when set to skipToken. This is likely a configuration error. Query hash: '${options.queryHash}'`,\n )\n }\n }\n\n // if we attempt to retry a fetch that was triggered from an initialPromise\n // when we don't have a queryFn yet, we can't retry, so we just return the already rejected initialPromise\n // if an observer has already mounted, we will be able to retry with that queryFn\n if (!options.queryFn && fetchOptions?.initialPromise) {\n return () => fetchOptions.initialPromise!\n }\n\n if (!options.queryFn || options.queryFn === skipToken) {\n return () =>\n Promise.reject(new Error(`Missing queryFn: '${options.queryHash}'`))\n }\n\n return options.queryFn\n}\n\n/**\n * Resolves a `throwOnError` option to a boolean.\n * If `throwOnError` is a function, it is called with `params` (e.g. the error and, depending on the caller,\n * additional context such as the query or mutation) and its result is returned, allowing the throwing\n * behavior to be decided per error. Otherwise, `throwOnError` itself is coerced to a boolean (`undefined`\n * resolves to `false`).\n * @param throwOnError - The `throwOnError` option: a boolean, a function that decides per error, or\n * `undefined`.\n * @param params - The arguments passed to `throwOnError` if it is a function.\n * @returns Whether the error should be thrown.\n * @example\n * ```ts\n * const throwOnError =\n * query.state.error && typeof options.throwOnError === 'function'\n * ? shouldThrowError(options.throwOnError, [query.state.error, query])\n * : options.throwOnError\n * ```\n */\nexport function shouldThrowError<T extends (...args: Array<any>) => boolean>(\n throwOnError: boolean | T | undefined,\n params: Parameters<T>,\n): boolean {\n // Allow throwOnError function to override throwing behavior on a per-error basis\n if (typeof throwOnError === 'function') {\n return throwOnError(...params)\n }\n\n return !!throwOnError\n}\n\n/**\n * Adds a lazy `signal` getter to an object, such as a query function context. The first time\n * `signal` is read, `onCancelled` is registered for the signal's `abort` event (or called right\n * away if it is already aborted), so cancellation is only tracked when the signal is actually used.\n * @param object - The object to add the `signal` property to.\n * @param getSignal - Returns the `AbortSignal`. Called once, when `signal` is first read.\n * @param onCancelled - Called when the signal is aborted, if `signal` was read.\n * @returns The same object, with the `signal` property added.\n */\nexport function addConsumeAwareSignal<T>(\n object: T,\n getSignal: () => AbortSignal,\n onCancelled: VoidFunction,\n): T & { signal: AbortSignal } {\n let consumed = false\n let signal: AbortSignal | undefined\n\n Object.defineProperty(object, 'signal', {\n enumerable: true,\n get: () => {\n signal ??= getSignal()\n if (consumed) {\n return signal\n }\n\n consumed = true\n if (signal.aborted) {\n onCancelled()\n } else {\n signal.addEventListener('abort', onCancelled, { once: true })\n }\n\n return signal\n },\n })\n\n return object as T & { signal: AbortSignal }\n}\n"],"mappings":"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"}