UNPKG

15.4 kBSource Map (JSON)View Raw
1{"version":3,"names":["queryString","fromEntries","validatePathConfig","getActiveRoute","state","route","index","routes","length","getPathFromState","options","Error","configs","screens","createNormalizedConfigs","path","current","allParams","pattern","focusedParams","focusedRoute","currentOptions","nestedRouteNames","hasNext","name","push","params","stringify","currentParams","Object","entries","map","key","value","String","assign","split","filter","p","startsWith","forEach","getParamName","undefined","nextRoute","nestedConfig","join","endsWith","encodeURIComponent","param","query","sort","replace","joinPaths","paths","concat","Boolean","createConfigItem","config","parentPattern","exact","c","result"],"sources":["getPathFromState.tsx"],"sourcesContent":["import type {\n NavigationState,\n PartialState,\n Route,\n} from '@react-navigation/routers';\nimport * as queryString from 'query-string';\n\nimport fromEntries from './fromEntries';\nimport type { PathConfig, PathConfigMap } from './types';\nimport validatePathConfig from './validatePathConfig';\n\ntype Options<ParamList> = {\n initialRouteName?: string;\n screens: PathConfigMap<ParamList>;\n};\n\ntype State = NavigationState | Omit<PartialState<NavigationState>, 'stale'>;\n\ntype StringifyConfig = Record<string, (value: any) => string>;\n\ntype ConfigItem = {\n pattern?: string;\n stringify?: StringifyConfig;\n screens?: Record<string, ConfigItem>;\n};\n\nconst getActiveRoute = (state: State): { name: string; params?: object } => {\n const route =\n typeof state.index === 'number'\n ? state.routes[state.index]\n : state.routes[state.routes.length - 1];\n\n if (route.state) {\n return getActiveRoute(route.state);\n }\n\n return route;\n};\n\n/**\n * Utility to serialize a navigation state object to a path string.\n *\n * @example\n * ```js\n * getPathFromState(\n * {\n * routes: [\n * {\n * name: 'Chat',\n * params: { author: 'Jane', id: 42 },\n * },\n * ],\n * },\n * {\n * screens: {\n * Chat: {\n * path: 'chat/:author/:id',\n * stringify: { author: author => author.toLowerCase() }\n * }\n * }\n * }\n * )\n * ```\n *\n * @param state Navigation state to serialize.\n * @param options Extra options to fine-tune how to serialize the path.\n * @returns Path representing the state, e.g. /foo/bar?count=42.\n */\nexport default function getPathFromState<ParamList extends {}>(\n state: State,\n options?: Options<ParamList>\n): string {\n if (state == null) {\n throw Error(\n \"Got 'undefined' for the navigation state. You must pass a valid state object.\"\n );\n }\n\n if (options) {\n validatePathConfig(options);\n }\n\n // Create a normalized configs object which will be easier to use\n const configs: Record<string, ConfigItem> = options?.screens\n ? createNormalizedConfigs(options?.screens)\n : {};\n\n let path = '/';\n let current: State | undefined = state;\n\n const allParams: Record<string, any> = {};\n\n while (current) {\n let index = typeof current.index === 'number' ? current.index : 0;\n let route = current.routes[index] as Route<string> & {\n state?: State;\n };\n\n let pattern: string | undefined;\n\n let focusedParams: Record<string, any> | undefined;\n let focusedRoute = getActiveRoute(state);\n let currentOptions = configs;\n\n // Keep all the route names that appeared during going deeper in config in case the pattern is resolved to undefined\n let nestedRouteNames = [];\n\n let hasNext = true;\n\n while (route.name in currentOptions && hasNext) {\n pattern = currentOptions[route.name].pattern;\n\n nestedRouteNames.push(route.name);\n\n if (route.params) {\n const stringify = currentOptions[route.name]?.stringify;\n\n const currentParams = fromEntries(\n Object.entries(route.params).map(([key, value]) => [\n key,\n stringify?.[key] ? stringify[key](value) : String(value),\n ])\n );\n\n if (pattern) {\n Object.assign(allParams, currentParams);\n }\n\n if (focusedRoute === route) {\n // If this is the focused route, keep the params for later use\n // We save it here since it's been stringified already\n focusedParams = { ...currentParams };\n\n pattern\n ?.split('/')\n .filter((p) => p.startsWith(':'))\n // eslint-disable-next-line no-loop-func\n .forEach((p) => {\n const name = getParamName(p);\n\n // Remove the params present in the pattern since we'll only use the rest for query string\n if (focusedParams) {\n // eslint-disable-next-line @typescript-eslint/no-dynamic-delete\n delete focusedParams[name];\n }\n });\n }\n }\n\n // If there is no `screens` property or no nested state, we return pattern\n if (!currentOptions[route.name].screens || route.state === undefined) {\n hasNext = false;\n } else {\n index =\n typeof route.state.index === 'number'\n ? route.state.index\n : route.state.routes.length - 1;\n\n const nextRoute = route.state.routes[index];\n const nestedConfig = currentOptions[route.name].screens;\n\n // if there is config for next route name, we go deeper\n if (nestedConfig && nextRoute.name in nestedConfig) {\n route = nextRoute as Route<string> & { state?: State };\n currentOptions = nestedConfig;\n } else {\n // If not, there is no sense in going deeper in config\n hasNext = false;\n }\n }\n }\n\n if (pattern === undefined) {\n pattern = nestedRouteNames.join('/');\n }\n\n if (currentOptions[route.name] !== undefined) {\n path += pattern\n .split('/')\n .map((p) => {\n const name = getParamName(p);\n\n // We don't know what to show for wildcard patterns\n // Showing the route name seems ok, though whatever we show here will be incorrect\n // Since the page doesn't actually exist\n if (p === '*') {\n return route.name;\n }\n\n // If the path has a pattern for a param, put the param in the path\n if (p.startsWith(':')) {\n const value = allParams[name];\n\n if (value === undefined && p.endsWith('?')) {\n // Optional params without value assigned in route.params should be ignored\n return '';\n }\n\n return encodeURIComponent(value);\n }\n\n return encodeURIComponent(p);\n })\n .join('/');\n } else {\n path += encodeURIComponent(route.name);\n }\n\n if (!focusedParams) {\n focusedParams = focusedRoute.params;\n }\n\n if (route.state) {\n path += '/';\n } else if (focusedParams) {\n for (let param in focusedParams) {\n if (focusedParams[param] === 'undefined') {\n // eslint-disable-next-line @typescript-eslint/no-dynamic-delete\n delete focusedParams[param];\n }\n }\n\n const query = queryString.stringify(focusedParams, { sort: false });\n\n if (query) {\n path += `?${query}`;\n }\n }\n\n current = route.state;\n }\n\n // Remove multiple as well as trailing slashes\n path = path.replace(/\\/+/g, '/');\n path = path.length > 1 ? path.replace(/\\/$/, '') : path;\n\n return path;\n}\n\nconst getParamName = (pattern: string) =>\n pattern.replace(/^:/, '').replace(/\\?$/, '');\n\nconst joinPaths = (...paths: string[]): string =>\n ([] as string[])\n .concat(...paths.map((p) => p.split('/')))\n .filter(Boolean)\n .join('/');\n\nconst createConfigItem = (\n config: PathConfig<object> | string,\n parentPattern?: string\n): ConfigItem => {\n if (typeof config === 'string') {\n // If a string is specified as the value of the key(e.g. Foo: '/path'), use it as the pattern\n const pattern = parentPattern ? joinPaths(parentPattern, config) : config;\n\n return { pattern };\n }\n\n // If an object is specified as the value (e.g. Foo: { ... }),\n // It can have `path` property and `screens` prop which has nested configs\n let pattern: string | undefined;\n\n if (config.exact && config.path === undefined) {\n throw new Error(\n \"A 'path' needs to be specified when specifying 'exact: true'. If you don't want this screen in the URL, specify it as empty string, e.g. `path: ''`.\"\n );\n }\n\n pattern =\n config.exact !== true\n ? joinPaths(parentPattern || '', config.path || '')\n : config.path || '';\n\n const screens = config.screens\n ? createNormalizedConfigs(config.screens, pattern)\n : undefined;\n\n return {\n // Normalize pattern to remove any leading, trailing slashes, duplicate slashes etc.\n pattern: pattern?.split('/').filter(Boolean).join('/'),\n stringify: config.stringify,\n screens,\n };\n};\n\nconst createNormalizedConfigs = (\n options: PathConfigMap<object>,\n pattern?: string\n): Record<string, ConfigItem> =>\n fromEntries(\n Object.entries(options).map(([name, c]) => {\n const result = createConfigItem(c, pattern);\n\n return [name, result];\n })\n );\n"],"mappings":"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"}
\No newline at end of file