UNPKG

expo-router

Version:

Expo Router is a file-based router for React Native and web applications.

163 lines (161 loc) • 7.67 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); 0 && (module.exports = { extendRouter: null, extendRouterActions: 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 extendRouter () { return extendRouter; }, get extendRouterActions () { return extendRouterActions; } }); const _ensureStateType = require("./ensureStateType"); const _stateKeys = require("./stateKeys"); const _types = require("./types"); const _utils = require("./utils"); function extendRouter(base, extension, { type: extendedType } = {}) { // Warns once per router factory, so a deprecated result does not log on every action. let warnedNull = false; return (options)=>{ // The extension owns the state and action types of the router it produces. The base router // is created for the base types and the extension decides which of its members still apply. const baseRouter = base(options); const type = extendedType ?? baseRouter.type; const ensureType = (state)=>type === undefined ? state : (0, _ensureStateType.ensureStateType)(state, type); // The call in progress. One counter is shared by `nextKey` and delegation to the base router, // so keys minted on either side never collide regardless of the order they are used in. let current = { key: '', routeKeySeq: 0 }; const start = (state, config)=>{ current = { key: state.key, routeKeySeq: state.routeKeySeq, config }; return state; }; const stamp = (state)=>state.routeKeySeq < current.routeKeySeq ? { ...state, routeKeySeq: current.routeKeySeq } : state; // Every returned state gets the shared sequence, the type of the state it was derived from // (an outer router in the chain may have stamped it before delegating), and the effective // `normalizeState` (the extension's, else the base router's). States routed through // `context.baseRouter` were already normalized by the base router. const finish = (state, stateType)=>{ const stamped = stamp(state); const typed = stateType === undefined ? stamped : (0, _ensureStateType.ensureStateType)(stamped, stateType); return normalizeState ? normalizeState(typed) : typed; }; const delegate = { ...baseRouter, getStateForAction (state, action, config = current.config) { if (config === undefined) { throw new Error('`baseRouter.getStateForAction` needs the `config` argument when it is called outside of `getStateForAction`, because only that method receives one from the navigator. Pass the config explicitly.'); } const result = baseRouter.getStateForAction(stamp(state), action, config); // A custom base router may still return the deprecated `null`. if (!(0, _utils.isActionHandled)(result)) { return _types.RouterActionHandling.Unhandled; } current.routeKeySeq = Math.max(current.routeKeySeq, result.state.routeKeySeq); return result; } }; const nextKey = (name)=>{ const minter = (0, _stateKeys.createRouteKeyMinter)(current); const key = minter.mint(name); current.routeKeySeq = minter.routeKeySeq; return key; }; const router = { ...delegate, ...extension({ baseRouter: delegate, options, nextKey }), type }; const { normalizeState } = router; return { ...router, getStateForDeclaredRoutes (state, routeNames) { // Render-phase fallback: the seeded state keeps its own `type` until an action stamps it. return finish(router.getStateForDeclaredRoutes(start(state), routeNames), state.type); }, getStateForRouteFocus (state, key) { const typedState = ensureType(start(state)); return finish(router.getStateForRouteFocus(typedState, key), typedState.type); }, getStateForAction (state, action, config) { const typedState = ensureType(start(state, config)); const result = router.getStateForAction(typedState, action, config); if (result === null && process.env.NODE_ENV !== 'production' && !warnedNull) { warnedNull = true; console.warn(`An \`extendRouter\` extension or \`extendRouterActions\` reducer returned \`null\` for the "${action.type}" action. Returning \`null\` is deprecated. Return \`RouterActionHandling.Unhandled\` to leave the action unhandled, and use \`isActionHandled\` to check whether a router handled an action.`); } const resolved = result === _types.RouterActionHandling.Delegate ? delegate.getStateForAction(typedState, action, config) : result; if (!(0, _utils.isActionHandled)(resolved)) { return _types.RouterActionHandling.Unhandled; } const finishedState = finish(resolved.state, typedState.type); if (router.getBrowserHistoryForAction) { const browserHistory = router.getBrowserHistoryForAction(typedState, finishedState, action); if (browserHistory !== resolved.browserHistory) { return { ...resolved, state: finishedState, browserHistory }; } } return finishedState === resolved.state ? resolved : { ...resolved, state: finishedState }; } }; }; } function extendRouterActions(base, reducer) { // Warns once per router factory, so a deprecated result does not log on every action. let warnedUndefined = false; return extendRouter(base, ({ baseRouter, options, nextKey })=>{ // `Router` requires `type` conditionally on `State`, which TypeScript cannot resolve for a // generic `State`; the override never sets `type`, so the shape is compatible. const overrides = { getStateForAction (state, action, config) { const result = reducer(state, action, { ...config, baseRouter, options, nextKey }); if (result !== undefined) { return result; } if (process.env.NODE_ENV !== 'production' && !warnedUndefined) { warnedUndefined = true; console.warn(`An \`extendRouterActions\` reducer returned \`undefined\` for the "${action.type}" action. Returning \`undefined\` is deprecated. Return \`RouterActionHandling.Delegate\` to let the base router handle the action.`); } return _types.RouterActionHandling.Delegate; } }; return overrides; }); } //# sourceMappingURL=extendRouter.js.map