expo-router
Version:
Expo Router is a file-based router for React Native and web applications.
247 lines (245 loc) • 9.64 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
0 && (module.exports = {
appendBaseUrl: null,
getPathDataFromState: null,
getPathFromState: null
});
function _export(target, all) {
for(var name in all)Object.defineProperty(target, name, {
enumerable: true,
get: Object.getOwnPropertyDescriptor(all, name).get
});
}
_export(exports, {
get appendBaseUrl () {
return appendBaseUrl;
},
get getPathDataFromState () {
return getPathDataFromState;
},
get getPathFromState () {
return getPathFromState;
}
});
const _navigationParams = require("../navigationParams");
const _queryParams = require("../utils/queryParams");
const _getPathFromStateforks = /*#__PURE__*/ _interop_require_wildcard(require("./getPathFromState-forks"));
const _validatePathConfig = require("./validatePathConfig");
function _getRequireWildcardCache(nodeInterop) {
if (typeof WeakMap !== "function") return null;
var cacheBabelInterop = new WeakMap();
var cacheNodeInterop = new WeakMap();
return (_getRequireWildcardCache = function(nodeInterop) {
return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
})(nodeInterop);
}
function _interop_require_wildcard(obj, nodeInterop) {
if (!nodeInterop && obj && obj.__esModule) {
return obj;
}
if (obj === null || typeof obj !== "object" && typeof obj !== "function") {
return {
default: obj
};
}
var cache = _getRequireWildcardCache(nodeInterop);
if (cache && cache.has(obj)) {
return cache.get(obj);
}
var newObj = {
__proto__: null
};
var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor;
for(var key in obj){
if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) {
var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null;
if (desc && (desc.get || desc.set)) {
Object.defineProperty(newObj, key, desc);
} else {
newObj[key] = obj[key];
}
}
}
newObj.default = obj;
if (cache) {
cache.set(obj, newObj);
}
return newObj;
}
const getActiveRoute = (state)=>{
const route = state.index != null ? state.routes[state.index] : state.routes[state.routes.length - 1];
if (route.state) {
return getActiveRoute(route.state);
}
return route;
};
let cachedNormalizedConfigs = [
undefined,
{}
];
function getPathFromState(state, options) {
return getPathDataFromState(state, options).path;
}
function getPathDataFromState(state, options) {
if (state == null) {
throw Error("Got 'undefined' for the navigation state. You must pass a valid state object.");
}
if (options) {
(0, _validatePathConfig.validatePathConfig)(options);
}
// Create a normalized configs object which will be easier to use
if (cachedNormalizedConfigs[0] !== options?.screens) {
cachedNormalizedConfigs = [
options?.screens,
options?.screens ? createNormalizedConfigs(options.screens) : {}
];
}
const configs = cachedNormalizedConfigs[1];
let path = '/';
let current = state;
const allParams = {};
while(current){
let index = typeof current.index === 'number' ? current.index : 0;
let route = current.routes[index];
let pattern;
let focusedParams;
const focusedRoute = getActiveRoute(state);
let currentOptions = configs;
// Keep all the route names that appeared during going deeper in config in case the pattern is resolved to undefined
const nestedRouteNames = [];
let hasNext = true;
while(route.name in currentOptions && hasNext){
pattern = currentOptions[route.name].pattern;
nestedRouteNames.push(route.name);
if (route.params) {
const stringify = currentOptions[route.name]?.stringify;
// This mutates allParams
const currentParams = _getPathFromStateforks.fixCurrentParams(allParams, route, stringify);
if (focusedRoute === route) {
// If this is the focused route, keep the params for later use
// We save it here since it's been stringified already
focusedParams = {
...currentParams
};
pattern?.split('/').filter((p)=>_getPathFromStateforks.isDynamicPart(p)).forEach((p)=>{
const name = _getPathFromStateforks.getParamName(p);
// Remove the params present in the pattern since we'll only use the rest for query string
if (focusedParams) {
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
delete focusedParams[name];
}
});
}
}
// If there is no `screens` property or no nested state, we return pattern
if (!currentOptions[route.name].screens || route.state === undefined) {
hasNext = false;
} else {
index = route.state.index != null ? route.state.index : route.state.routes.length - 1;
const nextRoute = route.state.routes[index];
const nestedConfig = currentOptions[route.name].screens;
// if there is config for next route name, we go deeper
if (nestedConfig && nextRoute.name in nestedConfig) {
route = nextRoute;
currentOptions = nestedConfig;
} else {
// If not, there is no sense in going deeper in config
hasNext = false;
}
}
}
if (pattern === undefined) {
pattern = nestedRouteNames.join('/');
}
if (currentOptions[route.name] !== undefined) {
path += _getPathFromStateforks.getPathWithConventionsCollapsed({
...options,
pattern,
route,
params: allParams,
initialRouteName: configs[route.name]?.initialRouteName
});
} else if (!route.name.startsWith('+')) {
path += encodeURIComponent(route.name);
}
if (!focusedParams) {
focusedParams = focusedRoute.params ? {
...focusedRoute.params
} : undefined;
}
if (route.state) {
path += '/';
} else if (focusedParams) {
for(const param in focusedParams){
if (focusedParams[param] === 'undefined') {
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
delete focusedParams[param];
}
}
delete focusedParams['#'];
focusedParams = (0, _navigationParams.removeInternalExpoRouterParams)(focusedParams);
const query = (0, _queryParams.stringifySearchParams)(focusedParams);
if (query) {
path += `?${query}`;
}
}
current = route.state;
}
// Remove multiple as well as trailing slashes
path = path.replace(/\/+/g, '/');
path = path.length > 1 ? path.replace(/\/$/, '') : path;
// Include the root path if specified
if (options?.path) {
path = joinPaths(options.path, path);
}
path = _getPathFromStateforks.appendBaseUrl(path);
if (allParams['#']) {
path += `#${allParams['#']}`;
}
return {
path,
params: allParams
};
}
const joinPaths = (...paths)=>[].concat(...paths.map((p)=>p.split('/'))).filter(Boolean).join('/');
const createConfigItem = (config, parentPattern)=>{
if (typeof config === 'string') {
// If a string is specified as the value of the key(e.g. Foo: '/path'), use it as the pattern
const pattern = parentPattern ? joinPaths(parentPattern, config) : config;
return {
pattern
};
}
if (config.exact && config.path === undefined) {
throw new Error("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: ''`.");
}
// If an object is specified as the value (e.g. Foo: { ... }),
// It can have `path` property and `screens` prop which has nested configs
const pattern = config.exact !== true ? joinPaths(parentPattern || '', config.path || '') : config.path || '';
const screens = config.screens ? createNormalizedConfigs(config.screens, pattern) : undefined;
return {
// Normalize pattern to remove any leading, trailing slashes, duplicate slashes etc.
pattern: pattern?.split('/').filter(Boolean).join('/'),
stringify: config.stringify,
screens
};
};
const createNormalizedConfigs = (options, pattern)=>Object.fromEntries(Object.entries(options).map(([name, c])=>{
const result = createConfigItem(c, pattern);
return [
name,
result
];
}));
function appendBaseUrl(path, baseUrl = process.env.EXPO_BASE_URL) {
if (process.env.NODE_ENV !== 'development') {
if (baseUrl) {
return `/${baseUrl.replace(/^\/+/, '').replace(/\/$/, '')}${path}`;
}
}
return path;
}
//# sourceMappingURL=getPathFromState.js.map