Legend:
- Unmodified
- Added
- Removed
-
imaps-frontend/node_modules/@remix-run/router/dist/router.cjs.js
rd565449 r0c6b92a 1 1 /** 2 * @remix-run/router v1. 19.02 * @remix-run/router v1.21.0 3 3 * 4 4 * Copyright (c) Remix Software Inc. … … 579 579 580 580 /** 581 * Result from a loader or action called via dataStrategy582 */583 584 /**585 581 * Users can specify either lowercase or uppercase form methods on `<Form>`, 586 582 * useSubmit(), `<fetcher.Form>`, etc. … … 646 642 * 647 643 * @deprecated Use `mapRouteProperties` instead 644 */ 645 /** 646 * Result from a loader or action called via dataStrategy 648 647 */ 649 648 /** … … 746 745 * Matches the given routes to a location and returns the match data. 747 746 * 748 * @see https://reactrouter.com/ utils/match-routes747 * @see https://reactrouter.com/v6/utils/match-routes 749 748 */ 750 749 function matchRoutes(routes, locationArg, basename) { … … 979 978 * Returns a path with params interpolated. 980 979 * 981 * @see https://reactrouter.com/ utils/generate-path980 * @see https://reactrouter.com/v6/utils/generate-path 982 981 */ 983 982 function generatePath(originalPath, params) { … … 1031 1030 * the match. 1032 1031 * 1033 * @see https://reactrouter.com/ utils/match-path1032 * @see https://reactrouter.com/v6/utils/match-path 1034 1033 */ 1035 1034 function matchPath(pattern, pathname) { … … 1146 1145 * Returns a resolved path object relative to the given pathname. 1147 1146 * 1148 * @see https://reactrouter.com/ utils/resolve-path1147 * @see https://reactrouter.com/v6/utils/resolve-path 1149 1148 */ 1150 1149 function resolvePath(to, fromPathname) { … … 1312 1311 * This is a shortcut for creating `application/json` responses. Converts `data` 1313 1312 * to JSON and sets the `Content-Type` header. 1313 * 1314 * @deprecated The `json` method is deprecated in favor of returning raw objects. 1315 * This method will be removed in v7. 1314 1316 */ 1315 1317 const json = function json(data, init) { … … 1485 1487 return value._data; 1486 1488 } 1489 /** 1490 * @deprecated The `defer` method is deprecated in favor of returning raw 1491 * objects. This method will be removed in v7. 1492 */ 1487 1493 const defer = function defer(data, init) { 1488 1494 if (init === void 0) { … … 1713 1719 let inFlightDataRoutes; 1714 1720 let basename = init.basename || "/"; 1715 let dataStrategyImpl = init. unstable_dataStrategy || defaultDataStrategy;1716 let patchRoutesOn MissImpl = init.unstable_patchRoutesOnMiss;1721 let dataStrategyImpl = init.dataStrategy || defaultDataStrategy; 1722 let patchRoutesOnNavigationImpl = init.patchRoutesOnNavigation; 1717 1723 1718 1724 // Config driven behavior flags … … 1744 1750 let initialMatches = matchRoutes(dataRoutes, init.history.location, basename); 1745 1751 let initialErrors = null; 1746 if (initialMatches == null && !patchRoutesOn MissImpl) {1752 if (initialMatches == null && !patchRoutesOnNavigationImpl) { 1747 1753 // If we do not match a user-provided-route, fall back to the root 1748 1754 // to allow the error boundary to take over … … 1760 1766 } 1761 1767 1762 // In SPA apps, if the user provided a patchRoutesOn Missimplementation and1768 // In SPA apps, if the user provided a patchRoutesOnNavigation implementation and 1763 1769 // our initial match is a splat route, clear them out so we run through lazy 1764 1770 // discovery on hydration in case there's a more accurate lazy route match. … … 1778 1784 1779 1785 // If partial hydration and fog of war is enabled, we will be running 1780 // `patchRoutesOn Miss` during hydration so include any partial matches as1786 // `patchRoutesOnNavigation` during hydration so include any partial matches as 1781 1787 // the initial matches so we can properly render `HydrateFallback`'s 1782 1788 if (future.v7_partialHydration) { … … 1799 1805 let loaderData = init.hydrationData ? init.hydrationData.loaderData : null; 1800 1806 let errors = init.hydrationData ? init.hydrationData.errors : null; 1801 let isRouteInitialized = m => {1802 // No loader, nothing to initialize1803 if (!m.route.loader) {1804 return true;1805 }1806 // Explicitly opting-in to running on hydration1807 if (typeof m.route.loader === "function" && m.route.loader.hydrate === true) {1808 return false;1809 }1810 // Otherwise, initialized if hydrated with data or an error1811 return loaderData && loaderData[m.route.id] !== undefined || errors && errors[m.route.id] !== undefined;1812 };1813 1814 1807 // If errors exist, don't consider routes below the boundary 1815 1808 if (errors) { 1816 1809 let idx = initialMatches.findIndex(m => errors[m.route.id] !== undefined); 1817 initialized = initialMatches.slice(0, idx + 1).every( isRouteInitialized);1810 initialized = initialMatches.slice(0, idx + 1).every(m => !shouldLoadRouteOnHydration(m.route, loaderData, errors)); 1818 1811 } else { 1819 initialized = initialMatches.every( isRouteInitialized);1812 initialized = initialMatches.every(m => !shouldLoadRouteOnHydration(m.route, loaderData, errors)); 1820 1813 } 1821 1814 } else { … … 1917 1910 let blockerFunctions = new Map(); 1918 1911 1919 // Map of pending patchRoutesOnMiss() promises (keyed by path/matches) so1920 // that we only kick them off once for a given combo1921 let pendingPatchRoutes = new Map();1922 1923 1912 // Flag to ignore the next history update, so we can revert the URL change on 1924 1913 // a POP navigation that was blocked by the user without touching router state 1925 let ignoreNextHistoryUpdate = false;1914 let unblockBlockerHistoryUpdate = undefined; 1926 1915 1927 1916 // Initialize the router, all side effects should be kicked off from here. … … 1939 1928 // Ignore this event if it was just us resetting the URL from a 1940 1929 // blocked POP navigation 1941 if (ignoreNextHistoryUpdate) { 1942 ignoreNextHistoryUpdate = false; 1930 if (unblockBlockerHistoryUpdate) { 1931 unblockBlockerHistoryUpdate(); 1932 unblockBlockerHistoryUpdate = undefined; 1943 1933 return; 1944 1934 } … … 1951 1941 if (blockerKey && delta != null) { 1952 1942 // Restore the URL to match the current UI, but don't update router state 1953 ignoreNextHistoryUpdate = true; 1943 let nextHistoryUpdatePromise = new Promise(resolve => { 1944 unblockBlockerHistoryUpdate = resolve; 1945 }); 1954 1946 init.history.go(delta * -1); 1955 1947 … … 1965 1957 location 1966 1958 }); 1967 // Re-do the same POP navigation we just blocked 1968 init.history.go(delta); 1959 // Re-do the same POP navigation we just blocked, after the url 1960 // restoration is also complete. See: 1961 // https://github.com/remix-run/react-router/issues/11613 1962 nextHistoryUpdatePromise.then(() => init.history.go(delta)); 1969 1963 }, 1970 1964 reset() { … … 2053 2047 [...subscribers].forEach(subscriber => subscriber(state, { 2054 2048 deletedFetchers: deletedFetchersKeys, 2055 unstable_viewTransitionOpts: opts.viewTransitionOpts,2056 unstable_flushSync: opts.flushSync === true2049 viewTransitionOpts: opts.viewTransitionOpts, 2050 flushSync: opts.flushSync === true 2057 2051 })); 2058 2052 … … 2214 2208 } 2215 2209 let preventScrollReset = opts && "preventScrollReset" in opts ? opts.preventScrollReset === true : undefined; 2216 let flushSync = (opts && opts. unstable_flushSync) === true;2210 let flushSync = (opts && opts.flushSync) === true; 2217 2211 let blockerKey = shouldBlockNavigation({ 2218 2212 currentLocation, … … 2252 2246 preventScrollReset, 2253 2247 replace: opts && opts.replace, 2254 enableViewTransition: opts && opts. unstable_viewTransition,2248 enableViewTransition: opts && opts.viewTransition, 2255 2249 flushSync 2256 2250 }); … … 2286 2280 // revalidation so that history correctly updates once the navigation completes 2287 2281 startNavigation(pendingAction || state.historyAction, state.navigation.location, { 2288 overrideNavigation: state.navigation 2282 overrideNavigation: state.navigation, 2283 // Proxy through any rending view transition 2284 enableViewTransition: pendingViewTransitionEnabled === true 2289 2285 }); 2290 2286 } … … 2338 2334 // mutation submission. 2339 2335 // 2340 // Ignore on initial page loads because since the initial loadwill always2336 // Ignore on initial page loads because since the initial hydration will always 2341 2337 // be "same hash". For example, on /page#hash and submit a <Form method="post"> 2342 2338 // which will default to a navigation to /page … … 2445 2441 }; 2446 2442 } else if (discoverResult.type === "error") { 2447 let { 2448 boundaryId, 2449 error 2450 } = handleDiscoverRouteError(location.pathname, discoverResult); 2443 let boundaryId = findNearestBoundary(discoverResult.partialMatches).route.id; 2451 2444 return { 2452 2445 matches: discoverResult.partialMatches, 2453 2446 pendingActionResult: [boundaryId, { 2454 2447 type: ResultType.error, 2455 error 2448 error: discoverResult.error 2456 2449 }] 2457 2450 }; … … 2487 2480 }; 2488 2481 } else { 2489 let results = await callDataStrategy("action", request, [actionMatch], matches);2490 result = results[ 0];2482 let results = await callDataStrategy("action", state, request, [actionMatch], matches, null); 2483 result = results[actionMatch.route.id]; 2491 2484 if (request.signal.aborted) { 2492 2485 return { … … 2506 2499 replace = location === state.location.pathname + state.location.search; 2507 2500 } 2508 await startRedirectNavigation(request, result, {2501 await startRedirectNavigation(request, result, true, { 2509 2502 submission, 2510 2503 replace … … 2583 2576 }; 2584 2577 } else if (discoverResult.type === "error") { 2585 let { 2586 boundaryId, 2587 error 2588 } = handleDiscoverRouteError(location.pathname, discoverResult); 2578 let boundaryId = findNearestBoundary(discoverResult.partialMatches).route.id; 2589 2579 return { 2590 2580 matches: discoverResult.partialMatches, 2591 2581 loaderData: {}, 2592 2582 errors: { 2593 [boundaryId]: error2583 [boundaryId]: discoverResult.error 2594 2584 } 2595 2585 }; … … 2657 2647 } 2658 2648 revalidatingFetchers.forEach(rf => { 2659 if (fetchControllers.has(rf.key)) { 2660 abortFetcher(rf.key); 2661 } 2649 abortFetcher(rf.key); 2662 2650 if (rf.controller) { 2663 2651 // Fetchers use an independent AbortController so that aborting a fetcher … … 2676 2664 loaderResults, 2677 2665 fetcherResults 2678 } = await callLoadersAndMaybeResolveData(state .matches, matches, matchesToLoad, revalidatingFetchers, request);2666 } = await callLoadersAndMaybeResolveData(state, matches, matchesToLoad, revalidatingFetchers, request); 2679 2667 if (request.signal.aborted) { 2680 2668 return { … … 2692 2680 2693 2681 // If any loaders returned a redirect Response, start a new REPLACE navigation 2694 let redirect = findRedirect( [...loaderResults, ...fetcherResults]);2682 let redirect = findRedirect(loaderResults); 2695 2683 if (redirect) { 2696 if (redirect.idx >= matchesToLoad.length) { 2697 // If this redirect came from a fetcher make sure we mark it in 2698 // fetchRedirectIds so it doesn't get revalidated on the next set of 2699 // loader executions 2700 let fetcherKey = revalidatingFetchers[redirect.idx - matchesToLoad.length].key; 2701 fetchRedirectIds.add(fetcherKey); 2702 } 2703 await startRedirectNavigation(request, redirect.result, { 2684 await startRedirectNavigation(request, redirect.result, true, { 2704 2685 replace 2705 2686 }); … … 2708 2689 }; 2709 2690 } 2691 redirect = findRedirect(fetcherResults); 2692 if (redirect) { 2693 // If this redirect came from a fetcher make sure we mark it in 2694 // fetchRedirectIds so it doesn't get revalidated on the next set of 2695 // loader executions 2696 fetchRedirectIds.add(redirect.key); 2697 await startRedirectNavigation(request, redirect.result, true, { 2698 replace 2699 }); 2700 return { 2701 shortCircuited: true 2702 }; 2703 } 2710 2704 2711 2705 // Process and commit output from loaders … … 2713 2707 loaderData, 2714 2708 errors 2715 } = processLoaderData(state, matches, matchesToLoad,loaderResults, pendingActionResult, revalidatingFetchers, fetcherResults, activeDeferreds);2709 } = processLoaderData(state, matches, loaderResults, pendingActionResult, revalidatingFetchers, fetcherResults, activeDeferreds); 2716 2710 2717 2711 // Wire up subscribers to update loaderData as promises settle … … 2727 2721 }); 2728 2722 2729 // During partial hydration, preserve SSR errors for routes that don't re-run2723 // Preserve SSR errors during partial hydration 2730 2724 if (future.v7_partialHydration && initialHydration && state.errors) { 2731 Object.entries(state.errors).filter(_ref2 => { 2732 let [id] = _ref2; 2733 return !matchesToLoad.some(m => m.route.id === id); 2734 }).forEach(_ref3 => { 2735 let [routeId, error] = _ref3; 2736 errors = Object.assign(errors || {}, { 2737 [routeId]: error 2738 }); 2739 }); 2725 errors = _extends({}, state.errors, errors); 2740 2726 } 2741 2727 let updatedFetchers = markFetchRedirectsDone(); … … 2780 2766 throw new Error("router.fetch() was called during the server render, but it shouldn't be. " + "You are likely calling a useFetcher() method in the body of your component. " + "Try moving it to a useEffect or a callback."); 2781 2767 } 2782 if (fetchControllers.has(key))abortFetcher(key);2783 let flushSync = (opts && opts. unstable_flushSync) === true;2768 abortFetcher(key); 2769 let flushSync = (opts && opts.flushSync) === true; 2784 2770 let routesToUse = inFlightDataRoutes || dataRoutes; 2785 2771 let normalizedPath = normalizeTo(state.location, state.matches, basename, future.v7_prependBasename, href, future.v7_relativeSplatPath, routeId, opts == null ? void 0 : opts.relative); … … 2809 2795 } 2810 2796 let match = getTargetMatch(matches, path); 2811 pendingPreventScrollReset = (opts && opts.preventScrollReset) === true;2797 let preventScrollReset = (opts && opts.preventScrollReset) === true; 2812 2798 if (submission && isMutationMethod(submission.formMethod)) { 2813 handleFetcherAction(key, routeId, path, match, matches, fogOfWar.active, flushSync, submission);2799 handleFetcherAction(key, routeId, path, match, matches, fogOfWar.active, flushSync, preventScrollReset, submission); 2814 2800 return; 2815 2801 } … … 2821 2807 path 2822 2808 }); 2823 handleFetcherLoader(key, routeId, path, match, matches, fogOfWar.active, flushSync, submission);2809 handleFetcherLoader(key, routeId, path, match, matches, fogOfWar.active, flushSync, preventScrollReset, submission); 2824 2810 } 2825 2811 2826 2812 // Call the action for the matched fetcher.submit(), and then handle redirects, 2827 2813 // errors, and revalidation 2828 async function handleFetcherAction(key, routeId, path, match, requestMatches, isFogOfWar, flushSync, submission) {2814 async function handleFetcherAction(key, routeId, path, match, requestMatches, isFogOfWar, flushSync, preventScrollReset, submission) { 2829 2815 interruptActiveLoads(); 2830 2816 fetchLoadMatches.delete(key); … … 2859 2845 return; 2860 2846 } else if (discoverResult.type === "error") { 2861 let { 2862 error 2863 } = handleDiscoverRouteError(path, discoverResult); 2864 setFetcherError(key, routeId, error, { 2847 setFetcherError(key, routeId, discoverResult.error, { 2865 2848 flushSync 2866 2849 }); … … 2885 2868 fetchControllers.set(key, abortController); 2886 2869 let originatingLoadId = incrementingLoadId; 2887 let actionResults = await callDataStrategy("action", fetchRequest, [match], requestMatches);2888 let actionResult = actionResults[ 0];2870 let actionResults = await callDataStrategy("action", state, fetchRequest, [match], requestMatches, key); 2871 let actionResult = actionResults[match.route.id]; 2889 2872 if (fetchRequest.signal.aborted) { 2890 2873 // We can delete this so long as we weren't aborted by our own fetcher … … 2918 2901 fetchRedirectIds.add(key); 2919 2902 updateFetcherState(key, getLoadingFetcher(submission)); 2920 return startRedirectNavigation(fetchRequest, actionResult, { 2921 fetcherSubmission: submission 2903 return startRedirectNavigation(fetchRequest, actionResult, false, { 2904 fetcherSubmission: submission, 2905 preventScrollReset 2922 2906 }); 2923 2907 } … … 2957 2941 let revalidatingFetcher = getLoadingFetcher(undefined, existingFetcher ? existingFetcher.data : undefined); 2958 2942 state.fetchers.set(staleKey, revalidatingFetcher); 2959 if (fetchControllers.has(staleKey)) { 2960 abortFetcher(staleKey); 2961 } 2943 abortFetcher(staleKey); 2962 2944 if (rf.controller) { 2963 2945 fetchControllers.set(staleKey, rf.controller); … … 2972 2954 loaderResults, 2973 2955 fetcherResults 2974 } = await callLoadersAndMaybeResolveData(state .matches, matches, matchesToLoad, revalidatingFetchers, revalidationRequest);2956 } = await callLoadersAndMaybeResolveData(state, matches, matchesToLoad, revalidatingFetchers, revalidationRequest); 2975 2957 if (abortController.signal.aborted) { 2976 2958 return; … … 2980 2962 fetchControllers.delete(key); 2981 2963 revalidatingFetchers.forEach(r => fetchControllers.delete(r.key)); 2982 let redirect = findRedirect( [...loaderResults, ...fetcherResults]);2964 let redirect = findRedirect(loaderResults); 2983 2965 if (redirect) { 2984 if (redirect.idx >= matchesToLoad.length) { 2985 // If this redirect came from a fetcher make sure we mark it in 2986 // fetchRedirectIds so it doesn't get revalidated on the next set of 2987 // loader executions 2988 let fetcherKey = revalidatingFetchers[redirect.idx - matchesToLoad.length].key; 2989 fetchRedirectIds.add(fetcherKey); 2990 } 2991 return startRedirectNavigation(revalidationRequest, redirect.result); 2966 return startRedirectNavigation(revalidationRequest, redirect.result, false, { 2967 preventScrollReset 2968 }); 2969 } 2970 redirect = findRedirect(fetcherResults); 2971 if (redirect) { 2972 // If this redirect came from a fetcher make sure we mark it in 2973 // fetchRedirectIds so it doesn't get revalidated on the next set of 2974 // loader executions 2975 fetchRedirectIds.add(redirect.key); 2976 return startRedirectNavigation(revalidationRequest, redirect.result, false, { 2977 preventScrollReset 2978 }); 2992 2979 } 2993 2980 … … 2996 2983 loaderData, 2997 2984 errors 2998 } = processLoaderData(state, state.matches, matchesToLoad, loaderResults, undefined, revalidatingFetchers, fetcherResults, activeDeferreds);2985 } = processLoaderData(state, matches, loaderResults, undefined, revalidatingFetchers, fetcherResults, activeDeferreds); 2999 2986 3000 2987 // Since we let revalidations complete even if the submitting fetcher was … … 3032 3019 3033 3020 // Call the matched loader for fetcher.load(), handling redirects, errors, etc. 3034 async function handleFetcherLoader(key, routeId, path, match, matches, isFogOfWar, flushSync, submission) {3021 async function handleFetcherLoader(key, routeId, path, match, matches, isFogOfWar, flushSync, preventScrollReset, submission) { 3035 3022 let existingFetcher = state.fetchers.get(key); 3036 3023 updateFetcherState(key, getLoadingFetcher(submission, existingFetcher ? existingFetcher.data : undefined), { … … 3044 3031 return; 3045 3032 } else if (discoverResult.type === "error") { 3046 let { 3047 error 3048 } = handleDiscoverRouteError(path, discoverResult); 3049 setFetcherError(key, routeId, error, { 3033 setFetcherError(key, routeId, discoverResult.error, { 3050 3034 flushSync 3051 3035 }); … … 3067 3051 fetchControllers.set(key, abortController); 3068 3052 let originatingLoadId = incrementingLoadId; 3069 let results = await callDataStrategy("loader", fetchRequest, [match], matches);3070 let result = results[ 0];3053 let results = await callDataStrategy("loader", state, fetchRequest, [match], matches, key); 3054 let result = results[match.route.id]; 3071 3055 3072 3056 // Deferred isn't supported for fetcher loads, await everything and treat it … … 3103 3087 } else { 3104 3088 fetchRedirectIds.add(key); 3105 await startRedirectNavigation(fetchRequest, result); 3089 await startRedirectNavigation(fetchRequest, result, false, { 3090 preventScrollReset 3091 }); 3106 3092 return; 3107 3093 } … … 3138 3124 * the history action from the original navigation (PUSH or REPLACE). 3139 3125 */ 3140 async function startRedirectNavigation(request, redirect, _temp2) {3126 async function startRedirectNavigation(request, redirect, isNavigation, _temp2) { 3141 3127 let { 3142 3128 submission, 3143 3129 fetcherSubmission, 3130 preventScrollReset, 3144 3131 replace 3145 3132 } = _temp2 === void 0 ? {} : _temp2; … … 3201 3188 formAction: location 3202 3189 }), 3203 // Preserve this flag across redirects 3204 preventScrollReset: pendingPreventScrollReset 3190 // Preserve these flags across redirects 3191 preventScrollReset: preventScrollReset || pendingPreventScrollReset, 3192 enableViewTransition: isNavigation ? pendingViewTransitionEnabled : undefined 3205 3193 }); 3206 3194 } else { … … 3212 3200 // Send fetcher submissions through for shouldRevalidate 3213 3201 fetcherSubmission, 3214 // Preserve this flag across redirects 3215 preventScrollReset: pendingPreventScrollReset 3202 // Preserve these flags across redirects 3203 preventScrollReset: preventScrollReset || pendingPreventScrollReset, 3204 enableViewTransition: isNavigation ? pendingViewTransitionEnabled : undefined 3216 3205 }); 3217 3206 } … … 3220 3209 // Utility wrapper for calling dataStrategy client-side without having to 3221 3210 // pass around the manifest, mapRouteProperties, etc. 3222 async function callDataStrategy(type, request, matchesToLoad, matches) { 3211 async function callDataStrategy(type, state, request, matchesToLoad, matches, fetcherKey) { 3212 let results; 3213 let dataResults = {}; 3223 3214 try { 3224 let results = await callDataStrategyImpl(dataStrategyImpl, type, request, matchesToLoad, matches, manifest, mapRouteProperties); 3225 return await Promise.all(results.map((result, i) => { 3226 if (isRedirectHandlerResult(result)) { 3227 let response = result.result; 3228 return { 3229 type: ResultType.redirect, 3230 response: normalizeRelativeRoutingRedirectResponse(response, request, matchesToLoad[i].route.id, matches, basename, future.v7_relativeSplatPath) 3231 }; 3232 } 3233 return convertHandlerResultToDataResult(result); 3234 })); 3215 results = await callDataStrategyImpl(dataStrategyImpl, type, state, request, matchesToLoad, matches, fetcherKey, manifest, mapRouteProperties); 3235 3216 } catch (e) { 3236 3217 // If the outer dataStrategy method throws, just return the error for all 3237 3218 // matches - and it'll naturally bubble to the root 3238 return matchesToLoad.map(() => ({ 3239 type: ResultType.error, 3240 error: e 3241 })); 3242 } 3243 } 3244 async function callLoadersAndMaybeResolveData(currentMatches, matches, matchesToLoad, fetchersToLoad, request) { 3245 let [loaderResults, ...fetcherResults] = await Promise.all([matchesToLoad.length ? callDataStrategy("loader", request, matchesToLoad, matches) : [], ...fetchersToLoad.map(f => { 3219 matchesToLoad.forEach(m => { 3220 dataResults[m.route.id] = { 3221 type: ResultType.error, 3222 error: e 3223 }; 3224 }); 3225 return dataResults; 3226 } 3227 for (let [routeId, result] of Object.entries(results)) { 3228 if (isRedirectDataStrategyResultResult(result)) { 3229 let response = result.result; 3230 dataResults[routeId] = { 3231 type: ResultType.redirect, 3232 response: normalizeRelativeRoutingRedirectResponse(response, request, routeId, matches, basename, future.v7_relativeSplatPath) 3233 }; 3234 } else { 3235 dataResults[routeId] = await convertDataStrategyResultToDataResult(result); 3236 } 3237 } 3238 return dataResults; 3239 } 3240 async function callLoadersAndMaybeResolveData(state, matches, matchesToLoad, fetchersToLoad, request) { 3241 let currentMatches = state.matches; 3242 3243 // Kick off loaders and fetchers in parallel 3244 let loaderResultsPromise = callDataStrategy("loader", state, request, matchesToLoad, matches, null); 3245 let fetcherResultsPromise = Promise.all(fetchersToLoad.map(async f => { 3246 3246 if (f.matches && f.match && f.controller) { 3247 let fetcherRequest = createClientSideRequest(init.history, f.path, f.controller.signal); 3248 return callDataStrategy("loader", fetcherRequest, [f.match], f.matches).then(r => r[0]); 3247 let results = await callDataStrategy("loader", state, createClientSideRequest(init.history, f.path, f.controller.signal), [f.match], f.matches, f.key); 3248 let result = results[f.match.route.id]; 3249 // Fetcher results are keyed by fetcher key from here on out, not routeId 3250 return { 3251 [f.key]: result 3252 }; 3249 3253 } else { 3250 3254 return Promise.resolve({ 3251 type: ResultType.error, 3252 error: getInternalRouterError(404, { 3253 pathname: f.path 3254 }) 3255 [f.key]: { 3256 type: ResultType.error, 3257 error: getInternalRouterError(404, { 3258 pathname: f.path 3259 }) 3260 } 3255 3261 }); 3256 3262 } 3257 })]); 3258 await Promise.all([resolveDeferredResults(currentMatches, matchesToLoad, loaderResults, loaderResults.map(() => request.signal), false, state.loaderData), resolveDeferredResults(currentMatches, fetchersToLoad.map(f => f.match), fetcherResults, fetchersToLoad.map(f => f.controller ? f.controller.signal : null), true)]); 3263 })); 3264 let loaderResults = await loaderResultsPromise; 3265 let fetcherResults = (await fetcherResultsPromise).reduce((acc, r) => Object.assign(acc, r), {}); 3266 await Promise.all([resolveNavigationDeferredResults(matches, loaderResults, request.signal, currentMatches, state.loaderData), resolveFetcherDeferredResults(matches, fetcherResults, fetchersToLoad)]); 3259 3267 return { 3260 3268 loaderResults, … … 3274 3282 if (fetchControllers.has(key)) { 3275 3283 cancelledFetcherLoads.add(key); 3276 abortFetcher(key);3277 }3284 } 3285 abortFetcher(key); 3278 3286 }); 3279 3287 } … … 3348 3356 function abortFetcher(key) { 3349 3357 let controller = fetchControllers.get(key); 3350 invariant(controller, "Expected fetch controller: " + key); 3351 controller.abort(); 3352 fetchControllers.delete(key); 3358 if (controller) { 3359 controller.abort(); 3360 fetchControllers.delete(key); 3361 } 3353 3362 } 3354 3363 function markFetchersDone(keys) { … … 3415 3424 }); 3416 3425 } 3417 function shouldBlockNavigation(_ref 4) {3426 function shouldBlockNavigation(_ref2) { 3418 3427 let { 3419 3428 currentLocation, 3420 3429 nextLocation, 3421 3430 historyAction 3422 } = _ref 4;3431 } = _ref2; 3423 3432 if (blockerFunctions.size === 0) { 3424 3433 return; … … 3465 3474 route, 3466 3475 error 3467 };3468 }3469 function handleDiscoverRouteError(pathname, discoverResult) {3470 return {3471 boundaryId: findNearestBoundary(discoverResult.partialMatches).route.id,3472 error: getInternalRouterError(400, {3473 type: "route-discovery",3474 pathname,3475 message: discoverResult.error != null && "message" in discoverResult.error ? discoverResult.error : String(discoverResult.error)3476 })3477 3476 }; 3478 3477 } … … 3541 3540 } 3542 3541 function checkFogOfWar(matches, routesToUse, pathname) { 3543 if (patchRoutesOn MissImpl) {3542 if (patchRoutesOnNavigationImpl) { 3544 3543 if (!matches) { 3545 3544 let fogMatches = matchRoutesImpl(routesToUse, pathname, basename, true); … … 3549 3548 }; 3550 3549 } else { 3551 let leafRoute = matches[matches.length - 1].route; 3552 if (leafRoute.path && (leafRoute.path === "*" || leafRoute.path.endsWith("/*"))) { 3553 // If we matched a splat, it might only be because we haven't yet fetched 3554 // the children that would match with a higher score, so let's fetch 3555 // around and find out 3550 if (Object.keys(matches[0].params).length > 0) { 3551 // If we matched a dynamic param or a splat, it might only be because 3552 // we haven't yet discovered other routes that would match with a 3553 // higher score. Call patchRoutesOnNavigation just to be sure 3556 3554 let partialMatches = matchRoutesImpl(routesToUse, pathname, basename, true); 3557 3555 return { … … 3568 3566 } 3569 3567 async function discoverRoutes(matches, pathname, signal) { 3568 if (!patchRoutesOnNavigationImpl) { 3569 return { 3570 type: "success", 3571 matches 3572 }; 3573 } 3570 3574 let partialMatches = matches; 3571 let route = partialMatches.length > 0 ? partialMatches[partialMatches.length - 1].route : null;3572 3575 while (true) { 3573 3576 let isNonHMR = inFlightDataRoutes == null; 3574 3577 let routesToUse = inFlightDataRoutes || dataRoutes; 3578 let localManifest = manifest; 3575 3579 try { 3576 await loadLazyRouteChildren(patchRoutesOnMissImpl, pathname, partialMatches, routesToUse, manifest, mapRouteProperties, pendingPatchRoutes, signal); 3580 await patchRoutesOnNavigationImpl({ 3581 path: pathname, 3582 matches: partialMatches, 3583 patch: (routeId, children) => { 3584 if (signal.aborted) return; 3585 patchRoutesImpl(routeId, children, routesToUse, localManifest, mapRouteProperties); 3586 } 3587 }); 3577 3588 } catch (e) { 3578 3589 return { … … 3588 3599 // HMR will already update the identity and reflow when it lands 3589 3600 // `inFlightDataRoutes` in `completeNavigation` 3590 if (isNonHMR ) {3601 if (isNonHMR && !signal.aborted) { 3591 3602 dataRoutes = [...dataRoutes]; 3592 3603 } … … 3598 3609 } 3599 3610 let newMatches = matchRoutes(routesToUse, pathname, basename); 3600 let matchedSplat = false;3601 3611 if (newMatches) { 3602 let leafRoute = newMatches[newMatches.length - 1].route;3603 if (leafRoute.index) {3604 // If we found an index route, we can stop3605 return {3606 type: "success",3607 matches: newMatches3608 };3609 }3610 if (leafRoute.path && leafRoute.path.length > 0) {3611 if (leafRoute.path === "*") {3612 // If we found a splat route, we can't be sure there's not a3613 // higher-scoring route down some partial matches trail so we need3614 // to check that out3615 matchedSplat = true;3616 } else {3617 // If we found a non-splat route, we can stop3618 return {3619 type: "success",3620 matches: newMatches3621 };3622 }3623 }3624 }3625 let newPartialMatches = matchRoutesImpl(routesToUse, pathname, basename, true);3626 3627 // If we are no longer partially matching anything, this was either a3628 // legit splat match above, or it's a 404. Also avoid loops if the3629 // second pass results in the same partial matches3630 if (!newPartialMatches || partialMatches.map(m => m.route.id).join("-") === newPartialMatches.map(m => m.route.id).join("-")) {3631 3612 return { 3632 3613 type: "success", 3633 matches: matchedSplat ? newMatches : null3614 matches: newMatches 3634 3615 }; 3635 3616 } 3636 partialMatches = newPartialMatches;3637 route = partialMatches[partialMatches.length - 1].route; 3638 if (route.path === "*") {3639 // The splat is still our most accurate partial, so run with it3617 let newPartialMatches = matchRoutesImpl(routesToUse, pathname, basename, true); 3618 3619 // Avoid loops if the second pass results in the same partial matches 3620 if (!newPartialMatches || partialMatches.length === newPartialMatches.length && partialMatches.every((m, i) => m.route.id === newPartialMatches[i].route.id)) { 3640 3621 return { 3641 3622 type: "success", 3642 matches: partialMatches3623 matches: null 3643 3624 }; 3644 3625 } 3626 partialMatches = newPartialMatches; 3645 3627 } 3646 3628 } … … 3769 3751 requestContext, 3770 3752 skipLoaderErrorBubbling, 3771 unstable_dataStrategy3753 dataStrategy 3772 3754 } = _temp3 === void 0 ? {} : _temp3; 3773 3755 let url = new URL(request.url); … … 3822 3804 }; 3823 3805 } 3824 let result = await queryImpl(request, location, matches, requestContext, unstable_dataStrategy || null, skipLoaderErrorBubbling === true, null);3806 let result = await queryImpl(request, location, matches, requestContext, dataStrategy || null, skipLoaderErrorBubbling === true, null); 3825 3807 if (isResponse(result)) { 3826 3808 return result; … … 3866 3848 routeId, 3867 3849 requestContext, 3868 unstable_dataStrategy3850 dataStrategy 3869 3851 } = _temp4 === void 0 ? {} : _temp4; 3870 3852 let url = new URL(request.url); … … 3895 3877 }); 3896 3878 } 3897 let result = await queryImpl(request, location, matches, requestContext, unstable_dataStrategy || null, false, match);3879 let result = await queryImpl(request, location, matches, requestContext, dataStrategy || null, false, match); 3898 3880 if (isResponse(result)) { 3899 3881 return result; … … 3922 3904 return undefined; 3923 3905 } 3924 async function queryImpl(request, location, matches, requestContext, unstable_dataStrategy, skipLoaderErrorBubbling, routeMatch) {3906 async function queryImpl(request, location, matches, requestContext, dataStrategy, skipLoaderErrorBubbling, routeMatch) { 3925 3907 invariant(request.signal, "query()/queryRoute() requests must contain an AbortController signal"); 3926 3908 try { 3927 3909 if (isMutationMethod(request.method.toLowerCase())) { 3928 let result = await submit(request, matches, routeMatch || getTargetMatch(matches, location), requestContext, unstable_dataStrategy, skipLoaderErrorBubbling, routeMatch != null);3910 let result = await submit(request, matches, routeMatch || getTargetMatch(matches, location), requestContext, dataStrategy, skipLoaderErrorBubbling, routeMatch != null); 3929 3911 return result; 3930 3912 } 3931 let result = await loadRouteData(request, matches, requestContext, unstable_dataStrategy, skipLoaderErrorBubbling, routeMatch);3913 let result = await loadRouteData(request, matches, requestContext, dataStrategy, skipLoaderErrorBubbling, routeMatch); 3932 3914 return isResponse(result) ? result : _extends({}, result, { 3933 3915 actionData: null, … … 3936 3918 } catch (e) { 3937 3919 // If the user threw/returned a Response in callLoaderOrAction for a 3938 // `queryRoute` call, we throw the ` HandlerResult` to bail out early3920 // `queryRoute` call, we throw the `DataStrategyResult` to bail out early 3939 3921 // and then return or throw the raw Response here accordingly 3940 if (is HandlerResult(e) && isResponse(e.result)) {3922 if (isDataStrategyResult(e) && isResponse(e.result)) { 3941 3923 if (e.type === ResultType.error) { 3942 3924 throw e.result; … … 3952 3934 } 3953 3935 } 3954 async function submit(request, matches, actionMatch, requestContext, unstable_dataStrategy, skipLoaderErrorBubbling, isRouteRequest) {3936 async function submit(request, matches, actionMatch, requestContext, dataStrategy, skipLoaderErrorBubbling, isRouteRequest) { 3955 3937 let result; 3956 3938 if (!actionMatch.route.action && !actionMatch.route.lazy) { … … 3968 3950 }; 3969 3951 } else { 3970 let results = await callDataStrategy("action", request, [actionMatch], matches, isRouteRequest, requestContext, unstable_dataStrategy);3971 result = results[ 0];3952 let results = await callDataStrategy("action", request, [actionMatch], matches, isRouteRequest, requestContext, dataStrategy); 3953 result = results[actionMatch.route.id]; 3972 3954 if (request.signal.aborted) { 3973 3955 throwStaticHandlerAbortedError(request, isRouteRequest, future); … … 4030 4012 // to call and will commit it when we complete the navigation 4031 4013 let boundaryMatch = skipLoaderErrorBubbling ? actionMatch : findNearestBoundary(matches, actionMatch.route.id); 4032 let context = await loadRouteData(loaderRequest, matches, requestContext, unstable_dataStrategy, skipLoaderErrorBubbling, null, [boundaryMatch.route.id, result]);4014 let context = await loadRouteData(loaderRequest, matches, requestContext, dataStrategy, skipLoaderErrorBubbling, null, [boundaryMatch.route.id, result]); 4033 4015 4034 4016 // action status codes take precedence over loader status codes … … 4041 4023 }); 4042 4024 } 4043 let context = await loadRouteData(loaderRequest, matches, requestContext, unstable_dataStrategy, skipLoaderErrorBubbling, null);4025 let context = await loadRouteData(loaderRequest, matches, requestContext, dataStrategy, skipLoaderErrorBubbling, null); 4044 4026 return _extends({}, context, { 4045 4027 actionData: { … … 4054 4036 }); 4055 4037 } 4056 async function loadRouteData(request, matches, requestContext, unstable_dataStrategy, skipLoaderErrorBubbling, routeMatch, pendingActionResult) {4038 async function loadRouteData(request, matches, requestContext, dataStrategy, skipLoaderErrorBubbling, routeMatch, pendingActionResult) { 4057 4039 let isRouteRequest = routeMatch != null; 4058 4040 … … 4084 4066 }; 4085 4067 } 4086 let results = await callDataStrategy("loader", request, matchesToLoad, matches, isRouteRequest, requestContext, unstable_dataStrategy);4068 let results = await callDataStrategy("loader", request, matchesToLoad, matches, isRouteRequest, requestContext, dataStrategy); 4087 4069 if (request.signal.aborted) { 4088 4070 throwStaticHandlerAbortedError(request, isRouteRequest, future); … … 4091 4073 // Process and commit output from loaders 4092 4074 let activeDeferreds = new Map(); 4093 let context = processRouteLoaderData(matches, matchesToLoad,results, pendingActionResult, activeDeferreds, skipLoaderErrorBubbling);4075 let context = processRouteLoaderData(matches, results, pendingActionResult, activeDeferreds, skipLoaderErrorBubbling); 4094 4076 4095 4077 // Add a null for any non-loader matches for proper revalidation on the client … … 4108 4090 // Utility wrapper for calling dataStrategy server-side without having to 4109 4091 // pass around the manifest, mapRouteProperties, etc. 4110 async function callDataStrategy(type, request, matchesToLoad, matches, isRouteRequest, requestContext, unstable_dataStrategy) { 4111 let results = await callDataStrategyImpl(unstable_dataStrategy || defaultDataStrategy, type, request, matchesToLoad, matches, manifest, mapRouteProperties, requestContext); 4112 return await Promise.all(results.map((result, i) => { 4113 if (isRedirectHandlerResult(result)) { 4092 async function callDataStrategy(type, request, matchesToLoad, matches, isRouteRequest, requestContext, dataStrategy) { 4093 let results = await callDataStrategyImpl(dataStrategy || defaultDataStrategy, type, null, request, matchesToLoad, matches, null, manifest, mapRouteProperties, requestContext); 4094 let dataResults = {}; 4095 await Promise.all(matches.map(async match => { 4096 if (!(match.route.id in results)) { 4097 return; 4098 } 4099 let result = results[match.route.id]; 4100 if (isRedirectDataStrategyResultResult(result)) { 4114 4101 let response = result.result; 4115 4102 // Throw redirects and let the server handle them with an HTTP redirect 4116 throw normalizeRelativeRoutingRedirectResponse(response, request, match esToLoad[i].route.id, matches, basename, future.v7_relativeSplatPath);4103 throw normalizeRelativeRoutingRedirectResponse(response, request, match.route.id, matches, basename, future.v7_relativeSplatPath); 4117 4104 } 4118 4105 if (isResponse(result.result) && isRouteRequest) { … … 4121 4108 throw result; 4122 4109 } 4123 return convertHandlerResultToDataResult(result);4110 dataResults[match.route.id] = await convertDataStrategyResultToDataResult(result); 4124 4111 })); 4112 return dataResults; 4125 4113 } 4126 4114 return { … … 4190 4178 } 4191 4179 4192 // Add an ?index param for matched index routes if we don't already have one 4193 if ((to == null || to === "" || to === ".") && activeRouteMatch && activeRouteMatch.route.index && !hasNakedIndexQuery(path.search)) { 4194 path.search = path.search ? path.search.replace(/^\?/, "?index&") : "?index"; 4180 // Account for `?index` params when routing to the current location 4181 if ((to == null || to === "" || to === ".") && activeRouteMatch) { 4182 let nakedIndex = hasNakedIndexQuery(path.search); 4183 if (activeRouteMatch.route.index && !nakedIndex) { 4184 // Add one when we're targeting an index route 4185 path.search = path.search ? path.search.replace(/^\?/, "?index&") : "?index"; 4186 } else if (!activeRouteMatch.route.index && nakedIndex) { 4187 // Remove existing ones when we're not 4188 let params = new URLSearchParams(path.search); 4189 let indexValues = params.getAll("index"); 4190 params.delete("index"); 4191 indexValues.filter(v => v).forEach(v => params.append("index", v)); 4192 let qs = params.toString(); 4193 path.search = qs ? "?" + qs : ""; 4194 } 4195 4195 } 4196 4196 … … 4241 4241 let text = typeof opts.body === "string" ? opts.body : opts.body instanceof FormData || opts.body instanceof URLSearchParams ? 4242 4242 // https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#plain-text-form-data 4243 Array.from(opts.body.entries()).reduce((acc, _ref 5) => {4244 let [name, value] = _ref 5;4243 Array.from(opts.body.entries()).reduce((acc, _ref3) => { 4244 let [name, value] = _ref3; 4245 4245 return "" + acc + name + "=" + value + "\n"; 4246 4246 }, "") : String(opts.body); … … 4332 4332 } 4333 4333 4334 // Filter out all routes below any caught error as they aren't going to4334 // Filter out all routes at/below any caught error as they aren't going to 4335 4335 // render so we don't need to load them 4336 function getLoaderMatchesUntilBoundary(matches, boundaryId ) {4337 let boundaryMatches = matches;4338 if (boundaryId) {4339 let index = matches.findIndex(m => m.route.id === boundaryId);4340 if (index >= 0) {4341 boundaryMatches = matches.slice(0, index);4342 }4343 } 4344 return boundaryMatches;4345 } 4346 function getMatchesToLoad(history, state, matches, submission, location, i sInitialLoad, skipActionErrorRevalidation, isRevalidationRequired, cancelledDeferredRoutes, cancelledFetcherLoads, deletedFetchers, fetchLoadMatches, fetchRedirectIds, routesToUse, basename, pendingActionResult) {4336 function getLoaderMatchesUntilBoundary(matches, boundaryId, includeBoundary) { 4337 if (includeBoundary === void 0) { 4338 includeBoundary = false; 4339 } 4340 let index = matches.findIndex(m => m.route.id === boundaryId); 4341 if (index >= 0) { 4342 return matches.slice(0, includeBoundary ? index + 1 : index); 4343 } 4344 return matches; 4345 } 4346 function getMatchesToLoad(history, state, matches, submission, location, initialHydration, skipActionErrorRevalidation, isRevalidationRequired, cancelledDeferredRoutes, cancelledFetcherLoads, deletedFetchers, fetchLoadMatches, fetchRedirectIds, routesToUse, basename, pendingActionResult) { 4347 4347 let actionResult = pendingActionResult ? isErrorResult(pendingActionResult[1]) ? pendingActionResult[1].error : pendingActionResult[1].data : undefined; 4348 4348 let currentUrl = history.createURL(state.location); … … 4350 4350 4351 4351 // Pick navigation matches that are net-new or qualify for revalidation 4352 let boundaryId = pendingActionResult && isErrorResult(pendingActionResult[1]) ? pendingActionResult[0] : undefined; 4353 let boundaryMatches = boundaryId ? getLoaderMatchesUntilBoundary(matches, boundaryId) : matches; 4352 let boundaryMatches = matches; 4353 if (initialHydration && state.errors) { 4354 // On initial hydration, only consider matches up to _and including_ the boundary. 4355 // This is inclusive to handle cases where a server loader ran successfully, 4356 // a child server loader bubbled up to this route, but this route has 4357 // `clientLoader.hydrate` so we want to still run the `clientLoader` so that 4358 // we have a complete version of `loaderData` 4359 boundaryMatches = getLoaderMatchesUntilBoundary(matches, Object.keys(state.errors)[0], true); 4360 } else if (pendingActionResult && isErrorResult(pendingActionResult[1])) { 4361 // If an action threw an error, we call loaders up to, but not including the 4362 // boundary 4363 boundaryMatches = getLoaderMatchesUntilBoundary(matches, pendingActionResult[0]); 4364 } 4354 4365 4355 4366 // Don't revalidate loaders by default after action 4xx/5xx responses … … 4369 4380 return false; 4370 4381 } 4371 if (isInitialLoad) { 4372 if (typeof route.loader !== "function" || route.loader.hydrate) { 4373 return true; 4374 } 4375 return state.loaderData[route.id] === undefined && ( 4376 // Don't re-run if the loader ran and threw an error 4377 !state.errors || state.errors[route.id] === undefined); 4382 if (initialHydration) { 4383 return shouldLoadRouteOnHydration(route, state.loaderData, state.errors); 4378 4384 } 4379 4385 … … 4409 4415 fetchLoadMatches.forEach((f, key) => { 4410 4416 // Don't revalidate: 4411 // - on initial load(shouldn't be any fetchers then anyway)4417 // - on initial hydration (shouldn't be any fetchers then anyway) 4412 4418 // - if fetcher won't be present in the subsequent render 4413 4419 // - no longer matches the URL (v7_fetcherPersist=false) 4414 4420 // - was unmounted but persisted due to v7_fetcherPersist=true 4415 if (i sInitialLoad|| !matches.some(m => m.route.id === f.routeId) || deletedFetchers.has(key)) {4421 if (initialHydration || !matches.some(m => m.route.id === f.routeId) || deletedFetchers.has(key)) { 4416 4422 return; 4417 4423 } … … 4479 4485 return [navigationMatches, revalidatingFetchers]; 4480 4486 } 4487 function shouldLoadRouteOnHydration(route, loaderData, errors) { 4488 // We dunno if we have a loader - gotta find out! 4489 if (route.lazy) { 4490 return true; 4491 } 4492 4493 // No loader, nothing to initialize 4494 if (!route.loader) { 4495 return false; 4496 } 4497 let hasData = loaderData != null && loaderData[route.id] !== undefined; 4498 let hasError = errors != null && errors[route.id] !== undefined; 4499 4500 // Don't run if we error'd during SSR 4501 if (!hasData && hasError) { 4502 return false; 4503 } 4504 4505 // Explicitly opting-in to running on hydration 4506 if (typeof route.loader === "function" && route.loader.hydrate === true) { 4507 return true; 4508 } 4509 4510 // Otherwise, run if we're not yet initialized with anything 4511 return !hasData && !hasError; 4512 } 4481 4513 function isNewLoader(currentLoaderData, currentMatch, match) { 4482 4514 let isNew = … … 4512 4544 return arg.defaultShouldRevalidate; 4513 4545 } 4514 4515 /**4516 * Idempotent utility to execute patchRoutesOnMiss() to lazily load route4517 * definitions and update the routes/routeManifest4518 */4519 async function loadLazyRouteChildren(patchRoutesOnMissImpl, path, matches, routes, manifest, mapRouteProperties, pendingRouteChildren, signal) {4520 let key = [path, ...matches.map(m => m.route.id)].join("-");4521 try {4522 let pending = pendingRouteChildren.get(key);4523 if (!pending) {4524 pending = patchRoutesOnMissImpl({4525 path,4526 matches,4527 patch: (routeId, children) => {4528 if (!signal.aborted) {4529 patchRoutesImpl(routeId, children, routes, manifest, mapRouteProperties);4530 }4531 }4532 });4533 pendingRouteChildren.set(key, pending);4534 }4535 if (pending && isPromise(pending)) {4536 await pending;4537 }4538 } finally {4539 pendingRouteChildren.delete(key);4540 }4541 }4542 4546 function patchRoutesImpl(routeId, children, routesToUse, manifest, mapRouteProperties) { 4547 var _childrenToPatch; 4548 let childrenToPatch; 4543 4549 if (routeId) { 4544 var _route$children;4545 4550 let route = manifest[routeId]; 4546 4551 invariant(route, "No route found to patch children into: routeId = " + routeId); 4547 let dataChildren = convertRoutesToDataRoutes(children, mapRouteProperties, [routeId, "patch", String(((_route$children = route.children) == null ? void 0 : _route$children.length) || "0")], manifest); 4548 if (route.children) { 4549 route.children.push(...dataChildren); 4550 } else { 4551 route.children = dataChildren; 4552 } 4552 if (!route.children) { 4553 route.children = []; 4554 } 4555 childrenToPatch = route.children; 4553 4556 } else { 4554 let dataChildren = convertRoutesToDataRoutes(children, mapRouteProperties, ["patch", String(routesToUse.length || "0")], manifest); 4555 routesToUse.push(...dataChildren); 4556 } 4557 childrenToPatch = routesToUse; 4558 } 4559 4560 // Don't patch in routes we already know about so that `patch` is idempotent 4561 // to simplify user-land code. This is useful because we re-call the 4562 // `patchRoutesOnNavigation` function for matched routes with params. 4563 let uniqueChildren = children.filter(newRoute => !childrenToPatch.some(existingRoute => isSameRoute(newRoute, existingRoute))); 4564 let newRoutes = convertRoutesToDataRoutes(uniqueChildren, mapRouteProperties, [routeId || "_", "patch", String(((_childrenToPatch = childrenToPatch) == null ? void 0 : _childrenToPatch.length) || "0")], manifest); 4565 childrenToPatch.push(...newRoutes); 4566 } 4567 function isSameRoute(newRoute, existingRoute) { 4568 // Most optimal check is by id 4569 if ("id" in newRoute && "id" in existingRoute && newRoute.id === existingRoute.id) { 4570 return true; 4571 } 4572 4573 // Second is by pathing differences 4574 if (!(newRoute.index === existingRoute.index && newRoute.path === existingRoute.path && newRoute.caseSensitive === existingRoute.caseSensitive)) { 4575 return false; 4576 } 4577 4578 // Pathless layout routes are trickier since we need to check children. 4579 // If they have no children then they're the same as far as we can tell 4580 if ((!newRoute.children || newRoute.children.length === 0) && (!existingRoute.children || existingRoute.children.length === 0)) { 4581 return true; 4582 } 4583 4584 // Otherwise, we look to see if every child in the new route is already 4585 // represented in the existing route's children 4586 return newRoute.children.every((aChild, i) => { 4587 var _existingRoute$childr; 4588 return (_existingRoute$childr = existingRoute.children) == null ? void 0 : _existingRoute$childr.some(bChild => isSameRoute(aChild, bChild)); 4589 }); 4557 4590 } 4558 4591 … … 4611 4644 4612 4645 // Default implementation of `dataStrategy` which fetches all loaders in parallel 4613 function defaultDataStrategy(opts) { 4614 return Promise.all(opts.matches.map(m => m.resolve())); 4615 } 4616 async function callDataStrategyImpl(dataStrategyImpl, type, request, matchesToLoad, matches, manifest, mapRouteProperties, requestContext) { 4617 let routeIdsToLoad = matchesToLoad.reduce((acc, m) => acc.add(m.route.id), new Set()); 4618 let loadedMatches = new Set(); 4646 async function defaultDataStrategy(_ref4) { 4647 let { 4648 matches 4649 } = _ref4; 4650 let matchesToLoad = matches.filter(m => m.shouldLoad); 4651 let results = await Promise.all(matchesToLoad.map(m => m.resolve())); 4652 return results.reduce((acc, result, i) => Object.assign(acc, { 4653 [matchesToLoad[i].route.id]: result 4654 }), {}); 4655 } 4656 async function callDataStrategyImpl(dataStrategyImpl, type, state, request, matchesToLoad, matches, fetcherKey, manifest, mapRouteProperties, requestContext) { 4657 let loadRouteDefinitionsPromises = matches.map(m => m.route.lazy ? loadLazyRouteModule(m.route, mapRouteProperties, manifest) : undefined); 4658 let dsMatches = matches.map((match, i) => { 4659 let loadRoutePromise = loadRouteDefinitionsPromises[i]; 4660 let shouldLoad = matchesToLoad.some(m => m.route.id === match.route.id); 4661 // `resolve` encapsulates route.lazy(), executing the loader/action, 4662 // and mapping return values/thrown errors to a `DataStrategyResult`. Users 4663 // can pass a callback to take fine-grained control over the execution 4664 // of the loader/action 4665 let resolve = async handlerOverride => { 4666 if (handlerOverride && request.method === "GET" && (match.route.lazy || match.route.loader)) { 4667 shouldLoad = true; 4668 } 4669 return shouldLoad ? callLoaderOrAction(type, request, match, loadRoutePromise, handlerOverride, requestContext) : Promise.resolve({ 4670 type: ResultType.data, 4671 result: undefined 4672 }); 4673 }; 4674 return _extends({}, match, { 4675 shouldLoad, 4676 resolve 4677 }); 4678 }); 4619 4679 4620 4680 // Send all matches here to allow for a middleware-type implementation. … … 4622 4682 // back out below. 4623 4683 let results = await dataStrategyImpl({ 4624 matches: matches.map(match => { 4625 let shouldLoad = routeIdsToLoad.has(match.route.id); 4626 // `resolve` encapsulates the route.lazy, executing the 4627 // loader/action, and mapping return values/thrown errors to a 4628 // HandlerResult. Users can pass a callback to take fine-grained control 4629 // over the execution of the loader/action 4630 let resolve = handlerOverride => { 4631 loadedMatches.add(match.route.id); 4632 return shouldLoad ? callLoaderOrAction(type, request, match, manifest, mapRouteProperties, handlerOverride, requestContext) : Promise.resolve({ 4633 type: ResultType.data, 4634 result: undefined 4635 }); 4636 }; 4637 return _extends({}, match, { 4638 shouldLoad, 4639 resolve 4640 }); 4641 }), 4684 matches: dsMatches, 4642 4685 request, 4643 4686 params: matches[0].params, 4687 fetcherKey, 4644 4688 context: requestContext 4645 4689 }); 4646 4690 4647 // Throw if any loadRoute implementations not called since they are what 4648 // ensures a route is fully loaded 4649 matches.forEach(m => invariant(loadedMatches.has(m.route.id), "`match.resolve()` was not called for route id \"" + m.route.id + "\". " + "You must call `match.resolve()` on every match passed to " + "`dataStrategy` to ensure all routes are properly loaded.")); 4650 4651 // Filter out any middleware-only matches for which we didn't need to run handlers 4652 return results.filter((_, i) => routeIdsToLoad.has(matches[i].route.id)); 4691 // Wait for all routes to load here but 'swallow the error since we want 4692 // it to bubble up from the `await loadRoutePromise` in `callLoaderOrAction` - 4693 // called from `match.resolve()` 4694 try { 4695 await Promise.all(loadRouteDefinitionsPromises); 4696 } catch (e) { 4697 // No-op 4698 } 4699 return results; 4653 4700 } 4654 4701 4655 4702 // Default logic for calling a loader/action is the user has no specified a dataStrategy 4656 async function callLoaderOrAction(type, request, match, manifest, mapRouteProperties, handlerOverride, staticContext) {4703 async function callLoaderOrAction(type, request, match, loadRoutePromise, handlerOverride, staticContext) { 4657 4704 let result; 4658 4705 let onReject; … … 4660 4707 // Setup a promise we can race against so that abort signals short circuit 4661 4708 let reject; 4662 // This will never resolve so safe to type it as Promise< HandlerResult> to4709 // This will never resolve so safe to type it as Promise<DataStrategyResult> to 4663 4710 // satisfy the function return value 4664 4711 let abortPromise = new Promise((_, r) => reject = r); … … 4675 4722 }, ...(ctx !== undefined ? [ctx] : [])); 4676 4723 }; 4677 let handlerPromise; 4678 if (handlerOverride) { 4679 handlerPromise = handlerOverride(ctx => actualHandler(ctx)); 4680 } else { 4681 handlerPromise = (async () => { 4682 try { 4683 let val = await actualHandler(); 4684 return { 4685 type: "data", 4686 result: val 4687 }; 4688 } catch (e) { 4689 return { 4690 type: "error", 4691 result: e 4692 }; 4693 } 4694 })(); 4695 } 4724 let handlerPromise = (async () => { 4725 try { 4726 let val = await (handlerOverride ? handlerOverride(ctx => actualHandler(ctx)) : actualHandler()); 4727 return { 4728 type: "data", 4729 result: val 4730 }; 4731 } catch (e) { 4732 return { 4733 type: "error", 4734 result: e 4735 }; 4736 } 4737 })(); 4696 4738 return Promise.race([handlerPromise, abortPromise]); 4697 4739 }; 4698 4740 try { 4699 4741 let handler = match.route[type]; 4700 if (match.route.lazy) { 4742 4743 // If we have a route.lazy promise, await that first 4744 if (loadRoutePromise) { 4701 4745 if (handler) { 4702 4746 // Run statically defined handler in parallel with lazy() … … 4708 4752 runHandler(handler).catch(e => { 4709 4753 handlerError = e; 4710 }), load LazyRouteModule(match.route, mapRouteProperties, manifest)]);4754 }), loadRoutePromise]); 4711 4755 if (handlerError !== undefined) { 4712 4756 throw handlerError; … … 4715 4759 } else { 4716 4760 // Load lazy route module, then run any returned handler 4717 await load LazyRouteModule(match.route, mapRouteProperties, manifest);4761 await loadRoutePromise; 4718 4762 handler = match.route[type]; 4719 4763 if (handler) { … … 4751 4795 } catch (e) { 4752 4796 // We should already be catching and converting normal handler executions to 4753 // HandlerResults and returning them, so anything that throws here is an4797 // DataStrategyResults and returning them, so anything that throws here is an 4754 4798 // unexpected error we still need to wrap 4755 4799 return { … … 4764 4808 return result; 4765 4809 } 4766 async function convert HandlerResultToDataResult(handlerResult) {4810 async function convertDataStrategyResultToDataResult(dataStrategyResult) { 4767 4811 let { 4768 4812 result, 4769 4813 type 4770 } = handlerResult;4814 } = dataStrategyResult; 4771 4815 if (isResponse(result)) { 4772 4816 let data; … … 4817 4861 } 4818 4862 4819 // Convert thrown unstable_data() to ErrorResponse instances4863 // Convert thrown data() to ErrorResponse instances 4820 4864 result = new ErrorResponseImpl(((_result$init2 = result.init) == null ? void 0 : _result$init2.status) || 500, undefined, result.data); 4821 4865 } … … 4924 4968 return formData; 4925 4969 } 4926 function processRouteLoaderData(matches, matchesToLoad,results, pendingActionResult, activeDeferreds, skipLoaderErrorBubbling) {4970 function processRouteLoaderData(matches, results, pendingActionResult, activeDeferreds, skipLoaderErrorBubbling) { 4927 4971 // Fill in loaderData/errors from our loaders 4928 4972 let loaderData = {}; … … 4934 4978 4935 4979 // Process loader results into state.loaderData/state.errors 4936 results.forEach((result, index) => { 4937 let id = matchesToLoad[index].route.id; 4980 matches.forEach(match => { 4981 if (!(match.route.id in results)) { 4982 return; 4983 } 4984 let id = match.route.id; 4985 let result = results[id]; 4938 4986 invariant(!isRedirectResult(result), "Cannot handle redirect results in processLoaderData"); 4939 4987 if (isErrorResult(result)) { … … 5013 5061 }; 5014 5062 } 5015 function processLoaderData(state, matches, matchesToLoad,results, pendingActionResult, revalidatingFetchers, fetcherResults, activeDeferreds) {5063 function processLoaderData(state, matches, results, pendingActionResult, revalidatingFetchers, fetcherResults, activeDeferreds) { 5016 5064 let { 5017 5065 loaderData, 5018 5066 errors 5019 } = processRouteLoaderData(matches, matchesToLoad,results, pendingActionResult, activeDeferreds, false // This method is only called client side so we always want to bubble5067 } = processRouteLoaderData(matches, results, pendingActionResult, activeDeferreds, false // This method is only called client side so we always want to bubble 5020 5068 ); 5021 5069 5022 5070 // Process results from our revalidating fetchers 5023 for (let index = 0; index < revalidatingFetchers.length; index++){5071 revalidatingFetchers.forEach(rf => { 5024 5072 let { 5025 5073 key, 5026 5074 match, 5027 5075 controller 5028 } = r evalidatingFetchers[index];5029 invariant(fetcherResults !== undefined && fetcherResults[index] !== undefined, "Did not find corresponding fetcher result");5030 let result = fetcherResults[index];5076 } = rf; 5077 let result = fetcherResults[key]; 5078 invariant(result, "Did not find corresponding fetcher result"); 5031 5079 5032 5080 // Process fetcher non-redirect errors 5033 5081 if (controller && controller.signal.aborted) { 5034 5082 // Nothing to do for aborted fetchers 5035 continue;5083 return; 5036 5084 } else if (isErrorResult(result)) { 5037 5085 let boundaryMatch = findNearestBoundary(state.matches, match == null ? void 0 : match.route.id); … … 5054 5102 state.fetchers.set(key, doneFetcher); 5055 5103 } 5056 } 5104 }); 5057 5105 return { 5058 5106 loaderData, … … 5128 5176 if (status === 400) { 5129 5177 statusText = "Bad Request"; 5130 if (type === "route-discovery") { 5131 errorMessage = "Unable to match URL \"" + pathname + "\" - the `unstable_patchRoutesOnMiss()` " + ("function threw the following error:\n" + message); 5132 } else if (method && pathname && routeId) { 5178 if (method && pathname && routeId) { 5133 5179 errorMessage = "You made a " + method + " request to \"" + pathname + "\" but " + ("did not provide a `loader` for route \"" + routeId + "\", ") + "so there is no way to handle the request."; 5134 5180 } else if (type === "defer-action") { … … 5156 5202 // Find any returned redirect errors, starting from the lowest match 5157 5203 function findRedirect(results) { 5158 for (let i = results.length - 1; i >= 0; i--) { 5159 let result = results[i]; 5204 let entries = Object.entries(results); 5205 for (let i = entries.length - 1; i >= 0; i--) { 5206 let [key, result] = entries[i]; 5160 5207 if (isRedirectResult(result)) { 5161 5208 return { 5162 result,5163 idx: i5209 key, 5210 result 5164 5211 }; 5165 5212 } … … 5191 5238 return false; 5192 5239 } 5193 function isPromise(val) { 5194 return typeof val === "object" && val != null && "then" in val; 5195 } 5196 function isHandlerResult(result) { 5240 function isDataStrategyResult(result) { 5197 5241 return result != null && typeof result === "object" && "type" in result && "result" in result && (result.type === ResultType.data || result.type === ResultType.error); 5198 5242 } 5199 function isRedirect HandlerResult(result) {5243 function isRedirectDataStrategyResultResult(result) { 5200 5244 return isResponse(result.result) && redirectStatusCodes.has(result.result.status); 5201 5245 } … … 5233 5277 return validMutationMethods.has(method.toLowerCase()); 5234 5278 } 5235 async function resolveDeferredResults(currentMatches, matchesToLoad, results, signals, isFetcher, currentLoaderData) { 5236 for (let index = 0; index < results.length; index++) { 5237 let result = results[index]; 5238 let match = matchesToLoad[index]; 5279 async function resolveNavigationDeferredResults(matches, results, signal, currentMatches, currentLoaderData) { 5280 let entries = Object.entries(results); 5281 for (let index = 0; index < entries.length; index++) { 5282 let [routeId, result] = entries[index]; 5283 let match = matches.find(m => (m == null ? void 0 : m.route.id) === routeId); 5239 5284 // If we don't have a match, then we can have a deferred result to do 5240 5285 // anything with. This is for revalidating fetchers where the route was … … 5245 5290 let currentMatch = currentMatches.find(m => m.route.id === match.route.id); 5246 5291 let isRevalidatingLoader = currentMatch != null && !isNewRouteInstance(currentMatch, match) && (currentLoaderData && currentLoaderData[match.route.id]) !== undefined; 5247 if (isDeferredResult(result) && (isFetcher || isRevalidatingLoader)) {5292 if (isDeferredResult(result) && isRevalidatingLoader) { 5248 5293 // Note: we do not have to touch activeDeferreds here since we race them 5249 5294 // against the signal in resolveDeferredData and they'll get aborted 5250 5295 // there if needed 5251 let signal = signals[index]; 5252 invariant(signal, "Expected an AbortSignal for revalidating fetcher deferred result"); 5253 await resolveDeferredData(result, signal, isFetcher).then(result => { 5296 await resolveDeferredData(result, signal, false).then(result => { 5254 5297 if (result) { 5255 results[index] = result || results[index]; 5298 results[routeId] = result; 5299 } 5300 }); 5301 } 5302 } 5303 } 5304 async function resolveFetcherDeferredResults(matches, results, revalidatingFetchers) { 5305 for (let index = 0; index < revalidatingFetchers.length; index++) { 5306 let { 5307 key, 5308 routeId, 5309 controller 5310 } = revalidatingFetchers[index]; 5311 let result = results[key]; 5312 let match = matches.find(m => (m == null ? void 0 : m.route.id) === routeId); 5313 // If we don't have a match, then we can have a deferred result to do 5314 // anything with. This is for revalidating fetchers where the route was 5315 // removed during HMR 5316 if (!match) { 5317 continue; 5318 } 5319 if (isDeferredResult(result)) { 5320 // Note: we do not have to touch activeDeferreds here since we race them 5321 // against the signal in resolveDeferredData and they'll get aborted 5322 // there if needed 5323 invariant(controller, "Expected an AbortController for revalidating fetcher deferred result"); 5324 await resolveDeferredData(result, controller.signal, true).then(result => { 5325 if (result) { 5326 results[key] = result; 5256 5327 } 5257 5328 }); … … 5484 5555 exports.createRouter = createRouter; 5485 5556 exports.createStaticHandler = createStaticHandler; 5557 exports.data = data; 5486 5558 exports.defer = defer; 5487 5559 exports.generatePath = generatePath; … … 5503 5575 exports.resolveTo = resolveTo; 5504 5576 exports.stripBasename = stripBasename; 5505 exports.unstable_data = data;5506 5577 //# sourceMappingURL=router.cjs.js.map
Note:
See TracChangeset
for help on using the changeset viewer.