UNPKG

@roxi/routify

Version:

93 lines (82 loc) 2.6 kB
export const spreadsLast = node => (node.name.match(/\[\.\.\.(.+)\]/) ? 1 : -1) /** * * @param {RouteFragment[]} routeFragments * @returns {RNodeRuntime} */ export const getNearestAncestorNodeWithSpreadParam = routeFragments => { for (const fragment of [...routeFragments].reverse()) { for (const node of fragment.node.parent?.navigableChildren || []) { const match = node.name.match(/\[\.\.\.(.+)\]/) if (match) return node } } } export const getUrlFragments = url => url .replace(/[?#].+/, '') // strip the search and hash query .replace(/\/$/, '') // strip trailing slash .split('/') .slice(1) // skip the first fragment since it will always be empty export const indexOfNode = (fragments, node) => fragments.findIndex(fragment => fragment.node === node) /** * @template {string|string[]} T * @param {T} strOrArr * @returns {T} */ const uriDecodeStringOrArray = strOrArr => strOrArr instanceof Array ? /** @type {T} */ (strOrArr.map(decodeURI)) : /** @type {T} */ (decodeURI(strOrArr)) /** * @template {Object<string, string|string[]>} T * @param {T} obj * @returns {T} */ export const URIDecodeObject = obj => Object.entries(obj).reduce( (_return, [key, value]) => ({ ..._return, [key]: uriDecodeStringOrArray(value), }), /** @type {T} */ ({}), ) /** * @template P * @typedef {Object} LoadCacheFetchOptions * @prop {(() => Promise<P>) |( ()=> P)} hydrate * @prop {(res:P) => Boolean|Number} [clear] **/ /** * @template P * LoadCache is a simple class implementation for caching Route.load */ export class LoadCache { constructor() { /** @type {Map<string, Promise<P>|P >} */ this.map = new Map() } /** * Fetches data for the given ID and caches it. * @param {any} id * @param {LoadCacheFetchOptions<P>} options * @returns {Promise<P>} */ async fetch(id, options) { if (!this.map.has(id)) this.map.set(id, options.hydrate()) this._handlePromise(id, options) return this.map.get(id) } /** * Handles the Promise resolution, cache expiration, and cache clearing. * @param {any} id * @param {LoadCacheFetchOptions<P>} options */ async _handlePromise(id, options) { const value = await this.map.get(id) const clear = options.clear?.(value) if (typeof clear === 'number') setTimeout(() => this.map.delete(id), clear) else if (clear) this.map.delete(id) } }