Legend:
- Unmodified
- Added
- Removed
-
imaps-frontend/node_modules/@remix-run/router/dist/router.umd.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. … … 581 581 582 582 /** 583 * Result from a loader or action called via dataStrategy584 */585 586 /**587 583 * Users can specify either lowercase or uppercase form methods on `<Form>`, 588 584 * useSubmit(), `<fetcher.Form>`, etc. … … 648 644 * 649 645 * @deprecated Use `mapRouteProperties` instead 646 */ 647 /** 648 * Result from a loader or action called via dataStrategy 650 649 */ 651 650 /** … … 748 747 * Matches the given routes to a location and returns the match data. 749 748 * 750 * @see https://reactrouter.com/ utils/match-routes749 * @see https://reactrouter.com/v6/utils/match-routes 751 750 */ 752 751 function matchRoutes(routes, locationArg, basename) { … … 981 980 * Returns a path with params interpolated. 982 981 * 983 * @see https://reactrouter.com/ utils/generate-path982 * @see https://reactrouter.com/v6/utils/generate-path 984 983 */ 985 984 function generatePath(originalPath, params) { … … 1033 1032 * the match. 1034 1033 * 1035 * @see https://reactrouter.com/ utils/match-path1034 * @see https://reactrouter.com/v6/utils/match-path 1036 1035 */ 1037 1036 function matchPath(pattern, pathname) { … … 1148 1147 * Returns a resolved path object relative to the given pathname. 1149 1148 * 1150 * @see https://reactrouter.com/ utils/resolve-path1149 * @see https://reactrouter.com/v6/utils/resolve-path 1151 1150 */ 1152 1151 function resolvePath(to, fromPathname) { … … 1314 1313 * This is a shortcut for creating `application/json` responses. Converts `data` 1315 1314 * to JSON and sets the `Content-Type` header. 1315 * 1316 * @deprecated The `json` method is deprecated in favor of returning raw objects. 1317 * This method will be removed in v7. 1316 1318 */ 1317 1319 const json = function json(data, init) { … … 1487 1489 return value._data; 1488 1490 } 1491 /** 1492 * @deprecated The `defer` method is deprecated in favor of returning raw 1493 * objects. This method will be removed in v7. 1494 */ 1489 1495 const defer = function defer(data, init) { 1490 1496 if (init === void 0) { … … 1715 1721 let inFlightDataRoutes; 1716 1722 let basename = init.basename || "/"; 1717 let dataStrategyImpl = init. unstable_dataStrategy || defaultDataStrategy;1718 let patchRoutesOn MissImpl = init.unstable_patchRoutesOnMiss;1723 let dataStrategyImpl = init.dataStrategy || defaultDataStrategy; 1724 let patchRoutesOnNavigationImpl = init.patchRoutesOnNavigation; 1719 1725 1720 1726 // Config driven behavior flags … … 1746 1752 let initialMatches = matchRoutes(dataRoutes, init.history.location, basename); 1747 1753 let initialErrors = null; 1748 if (initialMatches == null && !patchRoutesOn MissImpl) {1754 if (initialMatches == null && !patchRoutesOnNavigationImpl) { 1749 1755 // If we do not match a user-provided-route, fall back to the root 1750 1756 // to allow the error boundary to take over … … 1762 1768 } 1763 1769 1764 // In SPA apps, if the user provided a patchRoutesOn Missimplementation and1770 // In SPA apps, if the user provided a patchRoutesOnNavigation implementation and 1765 1771 // our initial match is a splat route, clear them out so we run through lazy 1766 1772 // discovery on hydration in case there's a more accurate lazy route match. … … 1780 1786 1781 1787 // If partial hydration and fog of war is enabled, we will be running 1782 // `patchRoutesOn Miss` during hydration so include any partial matches as1788 // `patchRoutesOnNavigation` during hydration so include any partial matches as 1783 1789 // the initial matches so we can properly render `HydrateFallback`'s 1784 1790 if (future.v7_partialHydration) { … … 1801 1807 let loaderData = init.hydrationData ? init.hydrationData.loaderData : null; 1802 1808 let errors = init.hydrationData ? init.hydrationData.errors : null; 1803 let isRouteInitialized = m => {1804 // No loader, nothing to initialize1805 if (!m.route.loader) {1806 return true;1807 }1808 // Explicitly opting-in to running on hydration1809 if (typeof m.route.loader === "function" && m.route.loader.hydrate === true) {1810 return false;1811 }1812 // Otherwise, initialized if hydrated with data or an error1813 return loaderData && loaderData[m.route.id] !== undefined || errors && errors[m.route.id] !== undefined;1814 };1815 1816 1809 // If errors exist, don't consider routes below the boundary 1817 1810 if (errors) { 1818 1811 let idx = initialMatches.findIndex(m => errors[m.route.id] !== undefined); 1819 initialized = initialMatches.slice(0, idx + 1).every( isRouteInitialized);1812 initialized = initialMatches.slice(0, idx + 1).every(m => !shouldLoadRouteOnHydration(m.route, loaderData, errors)); 1820 1813 } else { 1821 initialized = initialMatches.every( isRouteInitialized);1814 initialized = initialMatches.every(m => !shouldLoadRouteOnHydration(m.route, loaderData, errors)); 1822 1815 } 1823 1816 } else { … … 1919 1912 let blockerFunctions = new Map(); 1920 1913 1921 // Map of pending patchRoutesOnMiss() promises (keyed by path/matches) so1922 // that we only kick them off once for a given combo1923 let pendingPatchRoutes = new Map();1924 1925 1914 // Flag to ignore the next history update, so we can revert the URL change on 1926 1915 // a POP navigation that was blocked by the user without touching router state 1927 let ignoreNextHistoryUpdate = false;1916 let unblockBlockerHistoryUpdate = undefined; 1928 1917 1929 1918 // Initialize the router, all side effects should be kicked off from here. … … 1941 1930 // Ignore this event if it was just us resetting the URL from a 1942 1931 // blocked POP navigation 1943 if (ignoreNextHistoryUpdate) { 1944 ignoreNextHistoryUpdate = false; 1932 if (unblockBlockerHistoryUpdate) { 1933 unblockBlockerHistoryUpdate(); 1934 unblockBlockerHistoryUpdate = undefined; 1945 1935 return; 1946 1936 } … … 1953 1943 if (blockerKey && delta != null) { 1954 1944 // Restore the URL to match the current UI, but don't update router state 1955 ignoreNextHistoryUpdate = true; 1945 let nextHistoryUpdatePromise = new Promise(resolve => { 1946 unblockBlockerHistoryUpdate = resolve; 1947 }); 1956 1948 init.history.go(delta * -1); 1957 1949 … … 1967 1959 location 1968 1960 }); 1969 // Re-do the same POP navigation we just blocked 1970 init.history.go(delta); 1961 // Re-do the same POP navigation we just blocked, after the url 1962 // restoration is also complete. See: 1963 // https://github.com/remix-run/react-router/issues/11613 1964 nextHistoryUpdatePromise.then(() => init.history.go(delta)); 1971 1965 }, 1972 1966 reset() { … … 2055 2049 [...subscribers].forEach(subscriber => subscriber(state, { 2056 2050 deletedFetchers: deletedFetchersKeys, 2057 unstable_viewTransitionOpts: opts.viewTransitionOpts,2058 unstable_flushSync: opts.flushSync === true2051 viewTransitionOpts: opts.viewTransitionOpts, 2052 flushSync: opts.flushSync === true 2059 2053 })); 2060 2054 … … 2216 2210 } 2217 2211 let preventScrollReset = opts && "preventScrollReset" in opts ? opts.preventScrollReset === true : undefined; 2218 let flushSync = (opts && opts. unstable_flushSync) === true;2212 let flushSync = (opts && opts.flushSync) === true; 2219 2213 let blockerKey = shouldBlockNavigation({ 2220 2214 currentLocation, … … 2254 2248 preventScrollReset, 2255 2249 replace: opts && opts.replace, 2256 enableViewTransition: opts && opts. unstable_viewTransition,2250 enableViewTransition: opts && opts.viewTransition, 2257 2251 flushSync 2258 2252 }); … … 2288 2282 // revalidation so that history correctly updates once the navigation completes 2289 2283 startNavigation(pendingAction || state.historyAction, state.navigation.location, { 2290 overrideNavigation: state.navigation 2284 overrideNavigation: state.navigation, 2285 // Proxy through any rending view transition 2286 enableViewTransition: pendingViewTransitionEnabled === true 2291 2287 }); 2292 2288 } … … 2340 2336 // mutation submission. 2341 2337 // 2342 // Ignore on initial page loads because since the initial loadwill always2338 // Ignore on initial page loads because since the initial hydration will always 2343 2339 // be "same hash". For example, on /page#hash and submit a <Form method="post"> 2344 2340 // which will default to a navigation to /page … … 2447 2443 }; 2448 2444 } else if (discoverResult.type === "error") { 2449 let { 2450 boundaryId, 2451 error 2452 } = handleDiscoverRouteError(location.pathname, discoverResult); 2445 let boundaryId = findNearestBoundary(discoverResult.partialMatches).route.id; 2453 2446 return { 2454 2447 matches: discoverResult.partialMatches, 2455 2448 pendingActionResult: [boundaryId, { 2456 2449 type: ResultType.error, 2457 error 2450 error: discoverResult.error 2458 2451 }] 2459 2452 }; … … 2489 2482 }; 2490 2483 } else { 2491 let results = await callDataStrategy("action", request, [actionMatch], matches);2492 result = results[ 0];2484 let results = await callDataStrategy("action", state, request, [actionMatch], matches, null); 2485 result = results[actionMatch.route.id]; 2493 2486 if (request.signal.aborted) { 2494 2487 return { … … 2508 2501 replace = location === state.location.pathname + state.location.search; 2509 2502 } 2510 await startRedirectNavigation(request, result, {2503 await startRedirectNavigation(request, result, true, { 2511 2504 submission, 2512 2505 replace … … 2585 2578 }; 2586 2579 } else if (discoverResult.type === "error") { 2587 let { 2588 boundaryId, 2589 error 2590 } = handleDiscoverRouteError(location.pathname, discoverResult); 2580 let boundaryId = findNearestBoundary(discoverResult.partialMatches).route.id; 2591 2581 return { 2592 2582 matches: discoverResult.partialMatches, 2593 2583 loaderData: {}, 2594 2584 errors: { 2595 [boundaryId]: error2585 [boundaryId]: discoverResult.error 2596 2586 } 2597 2587 }; … … 2659 2649 } 2660 2650 revalidatingFetchers.forEach(rf => { 2661 if (fetchControllers.has(rf.key)) { 2662 abortFetcher(rf.key); 2663 } 2651 abortFetcher(rf.key); 2664 2652 if (rf.controller) { 2665 2653 // Fetchers use an independent AbortController so that aborting a fetcher … … 2678 2666 loaderResults, 2679 2667 fetcherResults 2680 } = await callLoadersAndMaybeResolveData(state .matches, matches, matchesToLoad, revalidatingFetchers, request);2668 } = await callLoadersAndMaybeResolveData(state, matches, matchesToLoad, revalidatingFetchers, request); 2681 2669 if (request.signal.aborted) { 2682 2670 return { … … 2694 2682 2695 2683 // If any loaders returned a redirect Response, start a new REPLACE navigation 2696 let redirect = findRedirect( [...loaderResults, ...fetcherResults]);2684 let redirect = findRedirect(loaderResults); 2697 2685 if (redirect) { 2698 if (redirect.idx >= matchesToLoad.length) { 2699 // If this redirect came from a fetcher make sure we mark it in 2700 // fetchRedirectIds so it doesn't get revalidated on the next set of 2701 // loader executions 2702 let fetcherKey = revalidatingFetchers[redirect.idx - matchesToLoad.length].key; 2703 fetchRedirectIds.add(fetcherKey); 2704 } 2705 await startRedirectNavigation(request, redirect.result, { 2686 await startRedirectNavigation(request, redirect.result, true, { 2706 2687 replace 2707 2688 }); … … 2710 2691 }; 2711 2692 } 2693 redirect = findRedirect(fetcherResults); 2694 if (redirect) { 2695 // If this redirect came from a fetcher make sure we mark it in 2696 // fetchRedirectIds so it doesn't get revalidated on the next set of 2697 // loader executions 2698 fetchRedirectIds.add(redirect.key); 2699 await startRedirectNavigation(request, redirect.result, true, { 2700 replace 2701 }); 2702 return { 2703 shortCircuited: true 2704 }; 2705 } 2712 2706 2713 2707 // Process and commit output from loaders … … 2715 2709 loaderData, 2716 2710 errors 2717 } = processLoaderData(state, matches, matchesToLoad,loaderResults, pendingActionResult, revalidatingFetchers, fetcherResults, activeDeferreds);2711 } = processLoaderData(state, matches, loaderResults, pendingActionResult, revalidatingFetchers, fetcherResults, activeDeferreds); 2718 2712 2719 2713 // Wire up subscribers to update loaderData as promises settle … … 2729 2723 }); 2730 2724 2731 // During partial hydration, preserve SSR errors for routes that don't re-run2725 // Preserve SSR errors during partial hydration 2732 2726 if (future.v7_partialHydration && initialHydration && state.errors) { 2733 Object.entries(state.errors).filter(_ref2 => { 2734 let [id] = _ref2; 2735 return !matchesToLoad.some(m => m.route.id === id); 2736 }).forEach(_ref3 => { 2737 let [routeId, error] = _ref3; 2738 errors = Object.assign(errors || {}, { 2739 [routeId]: error 2740 }); 2741 }); 2727 errors = _extends({}, state.errors, errors); 2742 2728 } 2743 2729 let updatedFetchers = markFetchRedirectsDone(); … … 2782 2768 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."); 2783 2769 } 2784 if (fetchControllers.has(key))abortFetcher(key);2785 let flushSync = (opts && opts. unstable_flushSync) === true;2770 abortFetcher(key); 2771 let flushSync = (opts && opts.flushSync) === true; 2786 2772 let routesToUse = inFlightDataRoutes || dataRoutes; 2787 2773 let normalizedPath = normalizeTo(state.location, state.matches, basename, future.v7_prependBasename, href, future.v7_relativeSplatPath, routeId, opts == null ? void 0 : opts.relative); … … 2811 2797 } 2812 2798 let match = getTargetMatch(matches, path); 2813 pendingPreventScrollReset = (opts && opts.preventScrollReset) === true;2799 let preventScrollReset = (opts && opts.preventScrollReset) === true; 2814 2800 if (submission && isMutationMethod(submission.formMethod)) { 2815 handleFetcherAction(key, routeId, path, match, matches, fogOfWar.active, flushSync, submission);2801 handleFetcherAction(key, routeId, path, match, matches, fogOfWar.active, flushSync, preventScrollReset, submission); 2816 2802 return; 2817 2803 } … … 2823 2809 path 2824 2810 }); 2825 handleFetcherLoader(key, routeId, path, match, matches, fogOfWar.active, flushSync, submission);2811 handleFetcherLoader(key, routeId, path, match, matches, fogOfWar.active, flushSync, preventScrollReset, submission); 2826 2812 } 2827 2813 2828 2814 // Call the action for the matched fetcher.submit(), and then handle redirects, 2829 2815 // errors, and revalidation 2830 async function handleFetcherAction(key, routeId, path, match, requestMatches, isFogOfWar, flushSync, submission) {2816 async function handleFetcherAction(key, routeId, path, match, requestMatches, isFogOfWar, flushSync, preventScrollReset, submission) { 2831 2817 interruptActiveLoads(); 2832 2818 fetchLoadMatches.delete(key); … … 2861 2847 return; 2862 2848 } else if (discoverResult.type === "error") { 2863 let { 2864 error 2865 } = handleDiscoverRouteError(path, discoverResult); 2866 setFetcherError(key, routeId, error, { 2849 setFetcherError(key, routeId, discoverResult.error, { 2867 2850 flushSync 2868 2851 }); … … 2887 2870 fetchControllers.set(key, abortController); 2888 2871 let originatingLoadId = incrementingLoadId; 2889 let actionResults = await callDataStrategy("action", fetchRequest, [match], requestMatches);2890 let actionResult = actionResults[ 0];2872 let actionResults = await callDataStrategy("action", state, fetchRequest, [match], requestMatches, key); 2873 let actionResult = actionResults[match.route.id]; 2891 2874 if (fetchRequest.signal.aborted) { 2892 2875 // We can delete this so long as we weren't aborted by our own fetcher … … 2920 2903 fetchRedirectIds.add(key); 2921 2904 updateFetcherState(key, getLoadingFetcher(submission)); 2922 return startRedirectNavigation(fetchRequest, actionResult, { 2923 fetcherSubmission: submission 2905 return startRedirectNavigation(fetchRequest, actionResult, false, { 2906 fetcherSubmission: submission, 2907 preventScrollReset 2924 2908 }); 2925 2909 } … … 2959 2943 let revalidatingFetcher = getLoadingFetcher(undefined, existingFetcher ? existingFetcher.data : undefined); 2960 2944 state.fetchers.set(staleKey, revalidatingFetcher); 2961 if (fetchControllers.has(staleKey)) { 2962 abortFetcher(staleKey); 2963 } 2945 abortFetcher(staleKey); 2964 2946 if (rf.controller) { 2965 2947 fetchControllers.set(staleKey, rf.controller); … … 2974 2956 loaderResults, 2975 2957 fetcherResults 2976 } = await callLoadersAndMaybeResolveData(state .matches, matches, matchesToLoad, revalidatingFetchers, revalidationRequest);2958 } = await callLoadersAndMaybeResolveData(state, matches, matchesToLoad, revalidatingFetchers, revalidationRequest); 2977 2959 if (abortController.signal.aborted) { 2978 2960 return; … … 2982 2964 fetchControllers.delete(key); 2983 2965 revalidatingFetchers.forEach(r => fetchControllers.delete(r.key)); 2984 let redirect = findRedirect( [...loaderResults, ...fetcherResults]);2966 let redirect = findRedirect(loaderResults); 2985 2967 if (redirect) { 2986 if (redirect.idx >= matchesToLoad.length) { 2987 // If this redirect came from a fetcher make sure we mark it in 2988 // fetchRedirectIds so it doesn't get revalidated on the next set of 2989 // loader executions 2990 let fetcherKey = revalidatingFetchers[redirect.idx - matchesToLoad.length].key; 2991 fetchRedirectIds.add(fetcherKey); 2992 } 2993 return startRedirectNavigation(revalidationRequest, redirect.result); 2968 return startRedirectNavigation(revalidationRequest, redirect.result, false, { 2969 preventScrollReset 2970 }); 2971 } 2972 redirect = findRedirect(fetcherResults); 2973 if (redirect) { 2974 // If this redirect came from a fetcher make sure we mark it in 2975 // fetchRedirectIds so it doesn't get revalidated on the next set of 2976 // loader executions 2977 fetchRedirectIds.add(redirect.key); 2978 return startRedirectNavigation(revalidationRequest, redirect.result, false, { 2979 preventScrollReset 2980 }); 2994 2981 } 2995 2982 … … 2998 2985 loaderData, 2999 2986 errors 3000 } = processLoaderData(state, state.matches, matchesToLoad, loaderResults, undefined, revalidatingFetchers, fetcherResults, activeDeferreds);2987 } = processLoaderData(state, matches, loaderResults, undefined, revalidatingFetchers, fetcherResults, activeDeferreds); 3001 2988 3002 2989 // Since we let revalidations complete even if the submitting fetcher was … … 3034 3021 3035 3022 // Call the matched loader for fetcher.load(), handling redirects, errors, etc. 3036 async function handleFetcherLoader(key, routeId, path, match, matches, isFogOfWar, flushSync, submission) {3023 async function handleFetcherLoader(key, routeId, path, match, matches, isFogOfWar, flushSync, preventScrollReset, submission) { 3037 3024 let existingFetcher = state.fetchers.get(key); 3038 3025 updateFetcherState(key, getLoadingFetcher(submission, existingFetcher ? existingFetcher.data : undefined), { … … 3046 3033 return; 3047 3034 } else if (discoverResult.type === "error") { 3048 let { 3049 error 3050 } = handleDiscoverRouteError(path, discoverResult); 3051 setFetcherError(key, routeId, error, { 3035 setFetcherError(key, routeId, discoverResult.error, { 3052 3036 flushSync 3053 3037 }); … … 3069 3053 fetchControllers.set(key, abortController); 3070 3054 let originatingLoadId = incrementingLoadId; 3071 let results = await callDataStrategy("loader", fetchRequest, [match], matches);3072 let result = results[ 0];3055 let results = await callDataStrategy("loader", state, fetchRequest, [match], matches, key); 3056 let result = results[match.route.id]; 3073 3057 3074 3058 // Deferred isn't supported for fetcher loads, await everything and treat it … … 3105 3089 } else { 3106 3090 fetchRedirectIds.add(key); 3107 await startRedirectNavigation(fetchRequest, result); 3091 await startRedirectNavigation(fetchRequest, result, false, { 3092 preventScrollReset 3093 }); 3108 3094 return; 3109 3095 } … … 3140 3126 * the history action from the original navigation (PUSH or REPLACE). 3141 3127 */ 3142 async function startRedirectNavigation(request, redirect, _temp2) {3128 async function startRedirectNavigation(request, redirect, isNavigation, _temp2) { 3143 3129 let { 3144 3130 submission, 3145 3131 fetcherSubmission, 3132 preventScrollReset, 3146 3133 replace 3147 3134 } = _temp2 === void 0 ? {} : _temp2; … … 3203 3190 formAction: location 3204 3191 }), 3205 // Preserve this flag across redirects 3206 preventScrollReset: pendingPreventScrollReset 3192 // Preserve these flags across redirects 3193 preventScrollReset: preventScrollReset || pendingPreventScrollReset, 3194 enableViewTransition: isNavigation ? pendingViewTransitionEnabled : undefined 3207 3195 }); 3208 3196 } else { … … 3214 3202 // Send fetcher submissions through for shouldRevalidate 3215 3203 fetcherSubmission, 3216 // Preserve this flag across redirects 3217 preventScrollReset: pendingPreventScrollReset 3204 // Preserve these flags across redirects 3205 preventScrollReset: preventScrollReset || pendingPreventScrollReset, 3206 enableViewTransition: isNavigation ? pendingViewTransitionEnabled : undefined 3218 3207 }); 3219 3208 } … … 3222 3211 // Utility wrapper for calling dataStrategy client-side without having to 3223 3212 // pass around the manifest, mapRouteProperties, etc. 3224 async function callDataStrategy(type, request, matchesToLoad, matches) { 3213 async function callDataStrategy(type, state, request, matchesToLoad, matches, fetcherKey) { 3214 let results; 3215 let dataResults = {}; 3225 3216 try { 3226 let results = await callDataStrategyImpl(dataStrategyImpl, type, request, matchesToLoad, matches, manifest, mapRouteProperties); 3227 return await Promise.all(results.map((result, i) => { 3228 if (isRedirectHandlerResult(result)) { 3229 let response = result.result; 3230 return { 3231 type: ResultType.redirect, 3232 response: normalizeRelativeRoutingRedirectResponse(response, request, matchesToLoad[i].route.id, matches, basename, future.v7_relativeSplatPath) 3233 }; 3234 } 3235 return convertHandlerResultToDataResult(result); 3236 })); 3217 results = await callDataStrategyImpl(dataStrategyImpl, type, state, request, matchesToLoad, matches, fetcherKey, manifest, mapRouteProperties); 3237 3218 } catch (e) { 3238 3219 // If the outer dataStrategy method throws, just return the error for all 3239 3220 // matches - and it'll naturally bubble to the root 3240 return matchesToLoad.map(() => ({ 3241 type: ResultType.error, 3242 error: e 3243 })); 3244 } 3245 } 3246 async function callLoadersAndMaybeResolveData(currentMatches, matches, matchesToLoad, fetchersToLoad, request) { 3247 let [loaderResults, ...fetcherResults] = await Promise.all([matchesToLoad.length ? callDataStrategy("loader", request, matchesToLoad, matches) : [], ...fetchersToLoad.map(f => { 3221 matchesToLoad.forEach(m => { 3222 dataResults[m.route.id] = { 3223 type: ResultType.error, 3224 error: e 3225 }; 3226 }); 3227 return dataResults; 3228 } 3229 for (let [routeId, result] of Object.entries(results)) { 3230 if (isRedirectDataStrategyResultResult(result)) { 3231 let response = result.result; 3232 dataResults[routeId] = { 3233 type: ResultType.redirect, 3234 response: normalizeRelativeRoutingRedirectResponse(response, request, routeId, matches, basename, future.v7_relativeSplatPath) 3235 }; 3236 } else { 3237 dataResults[routeId] = await convertDataStrategyResultToDataResult(result); 3238 } 3239 } 3240 return dataResults; 3241 } 3242 async function callLoadersAndMaybeResolveData(state, matches, matchesToLoad, fetchersToLoad, request) { 3243 let currentMatches = state.matches; 3244 3245 // Kick off loaders and fetchers in parallel 3246 let loaderResultsPromise = callDataStrategy("loader", state, request, matchesToLoad, matches, null); 3247 let fetcherResultsPromise = Promise.all(fetchersToLoad.map(async f => { 3248 3248 if (f.matches && f.match && f.controller) { 3249 let fetcherRequest = createClientSideRequest(init.history, f.path, f.controller.signal); 3250 return callDataStrategy("loader", fetcherRequest, [f.match], f.matches).then(r => r[0]); 3249 let results = await callDataStrategy("loader", state, createClientSideRequest(init.history, f.path, f.controller.signal), [f.match], f.matches, f.key); 3250 let result = results[f.match.route.id]; 3251 // Fetcher results are keyed by fetcher key from here on out, not routeId 3252 return { 3253 [f.key]: result 3254 }; 3251 3255 } else { 3252 3256 return Promise.resolve({ 3253 type: ResultType.error, 3254 error: getInternalRouterError(404, { 3255 pathname: f.path 3256 }) 3257 [f.key]: { 3258 type: ResultType.error, 3259 error: getInternalRouterError(404, { 3260 pathname: f.path 3261 }) 3262 } 3257 3263 }); 3258 3264 } 3259 })]); 3260 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)]); 3265 })); 3266 let loaderResults = await loaderResultsPromise; 3267 let fetcherResults = (await fetcherResultsPromise).reduce((acc, r) => Object.assign(acc, r), {}); 3268 await Promise.all([resolveNavigationDeferredResults(matches, loaderResults, request.signal, currentMatches, state.loaderData), resolveFetcherDeferredResults(matches, fetcherResults, fetchersToLoad)]); 3261 3269 return { 3262 3270 loaderResults, … … 3276 3284 if (fetchControllers.has(key)) { 3277 3285 cancelledFetcherLoads.add(key); 3278 abortFetcher(key);3279 }3286 } 3287 abortFetcher(key); 3280 3288 }); 3281 3289 } … … 3350 3358 function abortFetcher(key) { 3351 3359 let controller = fetchControllers.get(key); 3352 invariant(controller, "Expected fetch controller: " + key); 3353 controller.abort(); 3354 fetchControllers.delete(key); 3360 if (controller) { 3361 controller.abort(); 3362 fetchControllers.delete(key); 3363 } 3355 3364 } 3356 3365 function markFetchersDone(keys) { … … 3417 3426 }); 3418 3427 } 3419 function shouldBlockNavigation(_ref 4) {3428 function shouldBlockNavigation(_ref2) { 3420 3429 let { 3421 3430 currentLocation, 3422 3431 nextLocation, 3423 3432 historyAction 3424 } = _ref 4;3433 } = _ref2; 3425 3434 if (blockerFunctions.size === 0) { 3426 3435 return; … … 3467 3476 route, 3468 3477 error 3469 };3470 }3471 function handleDiscoverRouteError(pathname, discoverResult) {3472 return {3473 boundaryId: findNearestBoundary(discoverResult.partialMatches).route.id,3474 error: getInternalRouterError(400, {3475 type: "route-discovery",3476 pathname,3477 message: discoverResult.error != null && "message" in discoverResult.error ? discoverResult.error : String(discoverResult.error)3478 })3479 3478 }; 3480 3479 } … … 3543 3542 } 3544 3543 function checkFogOfWar(matches, routesToUse, pathname) { 3545 if (patchRoutesOn MissImpl) {3544 if (patchRoutesOnNavigationImpl) { 3546 3545 if (!matches) { 3547 3546 let fogMatches = matchRoutesImpl(routesToUse, pathname, basename, true); … … 3551 3550 }; 3552 3551 } else { 3553 let leafRoute = matches[matches.length - 1].route; 3554 if (leafRoute.path && (leafRoute.path === "*" || leafRoute.path.endsWith("/*"))) { 3555 // If we matched a splat, it might only be because we haven't yet fetched 3556 // the children that would match with a higher score, so let's fetch 3557 // around and find out 3552 if (Object.keys(matches[0].params).length > 0) { 3553 // If we matched a dynamic param or a splat, it might only be because 3554 // we haven't yet discovered other routes that would match with a 3555 // higher score. Call patchRoutesOnNavigation just to be sure 3558 3556 let partialMatches = matchRoutesImpl(routesToUse, pathname, basename, true); 3559 3557 return { … … 3570 3568 } 3571 3569 async function discoverRoutes(matches, pathname, signal) { 3570 if (!patchRoutesOnNavigationImpl) { 3571 return { 3572 type: "success", 3573 matches 3574 }; 3575 } 3572 3576 let partialMatches = matches; 3573 let route = partialMatches.length > 0 ? partialMatches[partialMatches.length - 1].route : null;3574 3577 while (true) { 3575 3578 let isNonHMR = inFlightDataRoutes == null; 3576 3579 let routesToUse = inFlightDataRoutes || dataRoutes; 3580 let localManifest = manifest; 3577 3581 try { 3578 await loadLazyRouteChildren(patchRoutesOnMissImpl, pathname, partialMatches, routesToUse, manifest, mapRouteProperties, pendingPatchRoutes, signal); 3582 await patchRoutesOnNavigationImpl({ 3583 path: pathname, 3584 matches: partialMatches, 3585 patch: (routeId, children) => { 3586 if (signal.aborted) return; 3587 patchRoutesImpl(routeId, children, routesToUse, localManifest, mapRouteProperties); 3588 } 3589 }); 3579 3590 } catch (e) { 3580 3591 return { … … 3590 3601 // HMR will already update the identity and reflow when it lands 3591 3602 // `inFlightDataRoutes` in `completeNavigation` 3592 if (isNonHMR ) {3603 if (isNonHMR && !signal.aborted) { 3593 3604 dataRoutes = [...dataRoutes]; 3594 3605 } … … 3600 3611 } 3601 3612 let newMatches = matchRoutes(routesToUse, pathname, basename); 3602 let matchedSplat = false;3603 3613 if (newMatches) { 3604 let leafRoute = newMatches[newMatches.length - 1].route;3605 if (leafRoute.index) {3606 // If we found an index route, we can stop3607 return {3608 type: "success",3609 matches: newMatches3610 };3611 }3612 if (leafRoute.path && leafRoute.path.length > 0) {3613 if (leafRoute.path === "*") {3614 // If we found a splat route, we can't be sure there's not a3615 // higher-scoring route down some partial matches trail so we need3616 // to check that out3617 matchedSplat = true;3618 } else {3619 // If we found a non-splat route, we can stop3620 return {3621 type: "success",3622 matches: newMatches3623 };3624 }3625 }3626 }3627 let newPartialMatches = matchRoutesImpl(routesToUse, pathname, basename, true);3628 3629 // If we are no longer partially matching anything, this was either a3630 // legit splat match above, or it's a 404. Also avoid loops if the3631 // second pass results in the same partial matches3632 if (!newPartialMatches || partialMatches.map(m => m.route.id).join("-") === newPartialMatches.map(m => m.route.id).join("-")) {3633 3614 return { 3634 3615 type: "success", 3635 matches: matchedSplat ? newMatches : null3616 matches: newMatches 3636 3617 }; 3637 3618 } 3638 partialMatches = newPartialMatches;3639 route = partialMatches[partialMatches.length - 1].route; 3640 if (route.path === "*") {3641 // The splat is still our most accurate partial, so run with it3619 let newPartialMatches = matchRoutesImpl(routesToUse, pathname, basename, true); 3620 3621 // Avoid loops if the second pass results in the same partial matches 3622 if (!newPartialMatches || partialMatches.length === newPartialMatches.length && partialMatches.every((m, i) => m.route.id === newPartialMatches[i].route.id)) { 3642 3623 return { 3643 3624 type: "success", 3644 matches: partialMatches3625 matches: null 3645 3626 }; 3646 3627 } 3628 partialMatches = newPartialMatches; 3647 3629 } 3648 3630 } … … 3771 3753 requestContext, 3772 3754 skipLoaderErrorBubbling, 3773 unstable_dataStrategy3755 dataStrategy 3774 3756 } = _temp3 === void 0 ? {} : _temp3; 3775 3757 let url = new URL(request.url); … … 3824 3806 }; 3825 3807 } 3826 let result = await queryImpl(request, location, matches, requestContext, unstable_dataStrategy || null, skipLoaderErrorBubbling === true, null);3808 let result = await queryImpl(request, location, matches, requestContext, dataStrategy || null, skipLoaderErrorBubbling === true, null); 3827 3809 if (isResponse(result)) { 3828 3810 return result; … … 3868 3850 routeId, 3869 3851 requestContext, 3870 unstable_dataStrategy3852 dataStrategy 3871 3853 } = _temp4 === void 0 ? {} : _temp4; 3872 3854 let url = new URL(request.url); … … 3897 3879 }); 3898 3880 } 3899 let result = await queryImpl(request, location, matches, requestContext, unstable_dataStrategy || null, false, match);3881 let result = await queryImpl(request, location, matches, requestContext, dataStrategy || null, false, match); 3900 3882 if (isResponse(result)) { 3901 3883 return result; … … 3924 3906 return undefined; 3925 3907 } 3926 async function queryImpl(request, location, matches, requestContext, unstable_dataStrategy, skipLoaderErrorBubbling, routeMatch) {3908 async function queryImpl(request, location, matches, requestContext, dataStrategy, skipLoaderErrorBubbling, routeMatch) { 3927 3909 invariant(request.signal, "query()/queryRoute() requests must contain an AbortController signal"); 3928 3910 try { 3929 3911 if (isMutationMethod(request.method.toLowerCase())) { 3930 let result = await submit(request, matches, routeMatch || getTargetMatch(matches, location), requestContext, unstable_dataStrategy, skipLoaderErrorBubbling, routeMatch != null);3912 let result = await submit(request, matches, routeMatch || getTargetMatch(matches, location), requestContext, dataStrategy, skipLoaderErrorBubbling, routeMatch != null); 3931 3913 return result; 3932 3914 } 3933 let result = await loadRouteData(request, matches, requestContext, unstable_dataStrategy, skipLoaderErrorBubbling, routeMatch);3915 let result = await loadRouteData(request, matches, requestContext, dataStrategy, skipLoaderErrorBubbling, routeMatch); 3934 3916 return isResponse(result) ? result : _extends({}, result, { 3935 3917 actionData: null, … … 3938 3920 } catch (e) { 3939 3921 // If the user threw/returned a Response in callLoaderOrAction for a 3940 // `queryRoute` call, we throw the ` HandlerResult` to bail out early3922 // `queryRoute` call, we throw the `DataStrategyResult` to bail out early 3941 3923 // and then return or throw the raw Response here accordingly 3942 if (is HandlerResult(e) && isResponse(e.result)) {3924 if (isDataStrategyResult(e) && isResponse(e.result)) { 3943 3925 if (e.type === ResultType.error) { 3944 3926 throw e.result; … … 3954 3936 } 3955 3937 } 3956 async function submit(request, matches, actionMatch, requestContext, unstable_dataStrategy, skipLoaderErrorBubbling, isRouteRequest) {3938 async function submit(request, matches, actionMatch, requestContext, dataStrategy, skipLoaderErrorBubbling, isRouteRequest) { 3957 3939 let result; 3958 3940 if (!actionMatch.route.action && !actionMatch.route.lazy) { … … 3970 3952 }; 3971 3953 } else { 3972 let results = await callDataStrategy("action", request, [actionMatch], matches, isRouteRequest, requestContext, unstable_dataStrategy);3973 result = results[ 0];3954 let results = await callDataStrategy("action", request, [actionMatch], matches, isRouteRequest, requestContext, dataStrategy); 3955 result = results[actionMatch.route.id]; 3974 3956 if (request.signal.aborted) { 3975 3957 throwStaticHandlerAbortedError(request, isRouteRequest, future); … … 4032 4014 // to call and will commit it when we complete the navigation 4033 4015 let boundaryMatch = skipLoaderErrorBubbling ? actionMatch : findNearestBoundary(matches, actionMatch.route.id); 4034 let context = await loadRouteData(loaderRequest, matches, requestContext, unstable_dataStrategy, skipLoaderErrorBubbling, null, [boundaryMatch.route.id, result]);4016 let context = await loadRouteData(loaderRequest, matches, requestContext, dataStrategy, skipLoaderErrorBubbling, null, [boundaryMatch.route.id, result]); 4035 4017 4036 4018 // action status codes take precedence over loader status codes … … 4043 4025 }); 4044 4026 } 4045 let context = await loadRouteData(loaderRequest, matches, requestContext, unstable_dataStrategy, skipLoaderErrorBubbling, null);4027 let context = await loadRouteData(loaderRequest, matches, requestContext, dataStrategy, skipLoaderErrorBubbling, null); 4046 4028 return _extends({}, context, { 4047 4029 actionData: { … … 4056 4038 }); 4057 4039 } 4058 async function loadRouteData(request, matches, requestContext, unstable_dataStrategy, skipLoaderErrorBubbling, routeMatch, pendingActionResult) {4040 async function loadRouteData(request, matches, requestContext, dataStrategy, skipLoaderErrorBubbling, routeMatch, pendingActionResult) { 4059 4041 let isRouteRequest = routeMatch != null; 4060 4042 … … 4086 4068 }; 4087 4069 } 4088 let results = await callDataStrategy("loader", request, matchesToLoad, matches, isRouteRequest, requestContext, unstable_dataStrategy);4070 let results = await callDataStrategy("loader", request, matchesToLoad, matches, isRouteRequest, requestContext, dataStrategy); 4089 4071 if (request.signal.aborted) { 4090 4072 throwStaticHandlerAbortedError(request, isRouteRequest, future); … … 4093 4075 // Process and commit output from loaders 4094 4076 let activeDeferreds = new Map(); 4095 let context = processRouteLoaderData(matches, matchesToLoad,results, pendingActionResult, activeDeferreds, skipLoaderErrorBubbling);4077 let context = processRouteLoaderData(matches, results, pendingActionResult, activeDeferreds, skipLoaderErrorBubbling); 4096 4078 4097 4079 // Add a null for any non-loader matches for proper revalidation on the client … … 4110 4092 // Utility wrapper for calling dataStrategy server-side without having to 4111 4093 // pass around the manifest, mapRouteProperties, etc. 4112 async function callDataStrategy(type, request, matchesToLoad, matches, isRouteRequest, requestContext, unstable_dataStrategy) { 4113 let results = await callDataStrategyImpl(unstable_dataStrategy || defaultDataStrategy, type, request, matchesToLoad, matches, manifest, mapRouteProperties, requestContext); 4114 return await Promise.all(results.map((result, i) => { 4115 if (isRedirectHandlerResult(result)) { 4094 async function callDataStrategy(type, request, matchesToLoad, matches, isRouteRequest, requestContext, dataStrategy) { 4095 let results = await callDataStrategyImpl(dataStrategy || defaultDataStrategy, type, null, request, matchesToLoad, matches, null, manifest, mapRouteProperties, requestContext); 4096 let dataResults = {}; 4097 await Promise.all(matches.map(async match => { 4098 if (!(match.route.id in results)) { 4099 return; 4100 } 4101 let result = results[match.route.id]; 4102 if (isRedirectDataStrategyResultResult(result)) { 4116 4103 let response = result.result; 4117 4104 // Throw redirects and let the server handle them with an HTTP redirect 4118 throw normalizeRelativeRoutingRedirectResponse(response, request, match esToLoad[i].route.id, matches, basename, future.v7_relativeSplatPath);4105 throw normalizeRelativeRoutingRedirectResponse(response, request, match.route.id, matches, basename, future.v7_relativeSplatPath); 4119 4106 } 4120 4107 if (isResponse(result.result) && isRouteRequest) { … … 4123 4110 throw result; 4124 4111 } 4125 return convertHandlerResultToDataResult(result);4112 dataResults[match.route.id] = await convertDataStrategyResultToDataResult(result); 4126 4113 })); 4114 return dataResults; 4127 4115 } 4128 4116 return { … … 4192 4180 } 4193 4181 4194 // Add an ?index param for matched index routes if we don't already have one 4195 if ((to == null || to === "" || to === ".") && activeRouteMatch && activeRouteMatch.route.index && !hasNakedIndexQuery(path.search)) { 4196 path.search = path.search ? path.search.replace(/^\?/, "?index&") : "?index"; 4182 // Account for `?index` params when routing to the current location 4183 if ((to == null || to === "" || to === ".") && activeRouteMatch) { 4184 let nakedIndex = hasNakedIndexQuery(path.search); 4185 if (activeRouteMatch.route.index && !nakedIndex) { 4186 // Add one when we're targeting an index route 4187 path.search = path.search ? path.search.replace(/^\?/, "?index&") : "?index"; 4188 } else if (!activeRouteMatch.route.index && nakedIndex) { 4189 // Remove existing ones when we're not 4190 let params = new URLSearchParams(path.search); 4191 let indexValues = params.getAll("index"); 4192 params.delete("index"); 4193 indexValues.filter(v => v).forEach(v => params.append("index", v)); 4194 let qs = params.toString(); 4195 path.search = qs ? "?" + qs : ""; 4196 } 4197 4197 } 4198 4198 … … 4243 4243 let text = typeof opts.body === "string" ? opts.body : opts.body instanceof FormData || opts.body instanceof URLSearchParams ? 4244 4244 // https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#plain-text-form-data 4245 Array.from(opts.body.entries()).reduce((acc, _ref 5) => {4246 let [name, value] = _ref 5;4245 Array.from(opts.body.entries()).reduce((acc, _ref3) => { 4246 let [name, value] = _ref3; 4247 4247 return "" + acc + name + "=" + value + "\n"; 4248 4248 }, "") : String(opts.body); … … 4334 4334 } 4335 4335 4336 // Filter out all routes below any caught error as they aren't going to4336 // Filter out all routes at/below any caught error as they aren't going to 4337 4337 // render so we don't need to load them 4338 function getLoaderMatchesUntilBoundary(matches, boundaryId ) {4339 let boundaryMatches = matches;4340 if (boundaryId) {4341 let index = matches.findIndex(m => m.route.id === boundaryId);4342 if (index >= 0) {4343 boundaryMatches = matches.slice(0, index);4344 }4345 } 4346 return boundaryMatches;4347 } 4348 function getMatchesToLoad(history, state, matches, submission, location, i sInitialLoad, skipActionErrorRevalidation, isRevalidationRequired, cancelledDeferredRoutes, cancelledFetcherLoads, deletedFetchers, fetchLoadMatches, fetchRedirectIds, routesToUse, basename, pendingActionResult) {4338 function getLoaderMatchesUntilBoundary(matches, boundaryId, includeBoundary) { 4339 if (includeBoundary === void 0) { 4340 includeBoundary = false; 4341 } 4342 let index = matches.findIndex(m => m.route.id === boundaryId); 4343 if (index >= 0) { 4344 return matches.slice(0, includeBoundary ? index + 1 : index); 4345 } 4346 return matches; 4347 } 4348 function getMatchesToLoad(history, state, matches, submission, location, initialHydration, skipActionErrorRevalidation, isRevalidationRequired, cancelledDeferredRoutes, cancelledFetcherLoads, deletedFetchers, fetchLoadMatches, fetchRedirectIds, routesToUse, basename, pendingActionResult) { 4349 4349 let actionResult = pendingActionResult ? isErrorResult(pendingActionResult[1]) ? pendingActionResult[1].error : pendingActionResult[1].data : undefined; 4350 4350 let currentUrl = history.createURL(state.location); … … 4352 4352 4353 4353 // Pick navigation matches that are net-new or qualify for revalidation 4354 let boundaryId = pendingActionResult && isErrorResult(pendingActionResult[1]) ? pendingActionResult[0] : undefined; 4355 let boundaryMatches = boundaryId ? getLoaderMatchesUntilBoundary(matches, boundaryId) : matches; 4354 let boundaryMatches = matches; 4355 if (initialHydration && state.errors) { 4356 // On initial hydration, only consider matches up to _and including_ the boundary. 4357 // This is inclusive to handle cases where a server loader ran successfully, 4358 // a child server loader bubbled up to this route, but this route has 4359 // `clientLoader.hydrate` so we want to still run the `clientLoader` so that 4360 // we have a complete version of `loaderData` 4361 boundaryMatches = getLoaderMatchesUntilBoundary(matches, Object.keys(state.errors)[0], true); 4362 } else if (pendingActionResult && isErrorResult(pendingActionResult[1])) { 4363 // If an action threw an error, we call loaders up to, but not including the 4364 // boundary 4365 boundaryMatches = getLoaderMatchesUntilBoundary(matches, pendingActionResult[0]); 4366 } 4356 4367 4357 4368 // Don't revalidate loaders by default after action 4xx/5xx responses … … 4371 4382 return false; 4372 4383 } 4373 if (isInitialLoad) { 4374 if (typeof route.loader !== "function" || route.loader.hydrate) { 4375 return true; 4376 } 4377 return state.loaderData[route.id] === undefined && ( 4378 // Don't re-run if the loader ran and threw an error 4379 !state.errors || state.errors[route.id] === undefined); 4384 if (initialHydration) { 4385 return shouldLoadRouteOnHydration(route, state.loaderData, state.errors); 4380 4386 } 4381 4387 … … 4411 4417 fetchLoadMatches.forEach((f, key) => { 4412 4418 // Don't revalidate: 4413 // - on initial load(shouldn't be any fetchers then anyway)4419 // - on initial hydration (shouldn't be any fetchers then anyway) 4414 4420 // - if fetcher won't be present in the subsequent render 4415 4421 // - no longer matches the URL (v7_fetcherPersist=false) 4416 4422 // - was unmounted but persisted due to v7_fetcherPersist=true 4417 if (i sInitialLoad|| !matches.some(m => m.route.id === f.routeId) || deletedFetchers.has(key)) {4423 if (initialHydration || !matches.some(m => m.route.id === f.routeId) || deletedFetchers.has(key)) { 4418 4424 return; 4419 4425 } … … 4481 4487 return [navigationMatches, revalidatingFetchers]; 4482 4488 } 4489 function shouldLoadRouteOnHydration(route, loaderData, errors) { 4490 // We dunno if we have a loader - gotta find out! 4491 if (route.lazy) { 4492 return true; 4493 } 4494 4495 // No loader, nothing to initialize 4496 if (!route.loader) { 4497 return false; 4498 } 4499 let hasData = loaderData != null && loaderData[route.id] !== undefined; 4500 let hasError = errors != null && errors[route.id] !== undefined; 4501 4502 // Don't run if we error'd during SSR 4503 if (!hasData && hasError) { 4504 return false; 4505 } 4506 4507 // Explicitly opting-in to running on hydration 4508 if (typeof route.loader === "function" && route.loader.hydrate === true) { 4509 return true; 4510 } 4511 4512 // Otherwise, run if we're not yet initialized with anything 4513 return !hasData && !hasError; 4514 } 4483 4515 function isNewLoader(currentLoaderData, currentMatch, match) { 4484 4516 let isNew = … … 4514 4546 return arg.defaultShouldRevalidate; 4515 4547 } 4516 4517 /**4518 * Idempotent utility to execute patchRoutesOnMiss() to lazily load route4519 * definitions and update the routes/routeManifest4520 */4521 async function loadLazyRouteChildren(patchRoutesOnMissImpl, path, matches, routes, manifest, mapRouteProperties, pendingRouteChildren, signal) {4522 let key = [path, ...matches.map(m => m.route.id)].join("-");4523 try {4524 let pending = pendingRouteChildren.get(key);4525 if (!pending) {4526 pending = patchRoutesOnMissImpl({4527 path,4528 matches,4529 patch: (routeId, children) => {4530 if (!signal.aborted) {4531 patchRoutesImpl(routeId, children, routes, manifest, mapRouteProperties);4532 }4533 }4534 });4535 pendingRouteChildren.set(key, pending);4536 }4537 if (pending && isPromise(pending)) {4538 await pending;4539 }4540 } finally {4541 pendingRouteChildren.delete(key);4542 }4543 }4544 4548 function patchRoutesImpl(routeId, children, routesToUse, manifest, mapRouteProperties) { 4549 var _childrenToPatch; 4550 let childrenToPatch; 4545 4551 if (routeId) { 4546 var _route$children;4547 4552 let route = manifest[routeId]; 4548 4553 invariant(route, "No route found to patch children into: routeId = " + routeId); 4549 let dataChildren = convertRoutesToDataRoutes(children, mapRouteProperties, [routeId, "patch", String(((_route$children = route.children) == null ? void 0 : _route$children.length) || "0")], manifest); 4550 if (route.children) { 4551 route.children.push(...dataChildren); 4552 } else { 4553 route.children = dataChildren; 4554 } 4554 if (!route.children) { 4555 route.children = []; 4556 } 4557 childrenToPatch = route.children; 4555 4558 } else { 4556 let dataChildren = convertRoutesToDataRoutes(children, mapRouteProperties, ["patch", String(routesToUse.length || "0")], manifest); 4557 routesToUse.push(...dataChildren); 4558 } 4559 childrenToPatch = routesToUse; 4560 } 4561 4562 // Don't patch in routes we already know about so that `patch` is idempotent 4563 // to simplify user-land code. This is useful because we re-call the 4564 // `patchRoutesOnNavigation` function for matched routes with params. 4565 let uniqueChildren = children.filter(newRoute => !childrenToPatch.some(existingRoute => isSameRoute(newRoute, existingRoute))); 4566 let newRoutes = convertRoutesToDataRoutes(uniqueChildren, mapRouteProperties, [routeId || "_", "patch", String(((_childrenToPatch = childrenToPatch) == null ? void 0 : _childrenToPatch.length) || "0")], manifest); 4567 childrenToPatch.push(...newRoutes); 4568 } 4569 function isSameRoute(newRoute, existingRoute) { 4570 // Most optimal check is by id 4571 if ("id" in newRoute && "id" in existingRoute && newRoute.id === existingRoute.id) { 4572 return true; 4573 } 4574 4575 // Second is by pathing differences 4576 if (!(newRoute.index === existingRoute.index && newRoute.path === existingRoute.path && newRoute.caseSensitive === existingRoute.caseSensitive)) { 4577 return false; 4578 } 4579 4580 // Pathless layout routes are trickier since we need to check children. 4581 // If they have no children then they're the same as far as we can tell 4582 if ((!newRoute.children || newRoute.children.length === 0) && (!existingRoute.children || existingRoute.children.length === 0)) { 4583 return true; 4584 } 4585 4586 // Otherwise, we look to see if every child in the new route is already 4587 // represented in the existing route's children 4588 return newRoute.children.every((aChild, i) => { 4589 var _existingRoute$childr; 4590 return (_existingRoute$childr = existingRoute.children) == null ? void 0 : _existingRoute$childr.some(bChild => isSameRoute(aChild, bChild)); 4591 }); 4559 4592 } 4560 4593 … … 4613 4646 4614 4647 // Default implementation of `dataStrategy` which fetches all loaders in parallel 4615 function defaultDataStrategy(opts) { 4616 return Promise.all(opts.matches.map(m => m.resolve())); 4617 } 4618 async function callDataStrategyImpl(dataStrategyImpl, type, request, matchesToLoad, matches, manifest, mapRouteProperties, requestContext) { 4619 let routeIdsToLoad = matchesToLoad.reduce((acc, m) => acc.add(m.route.id), new Set()); 4620 let loadedMatches = new Set(); 4648 async function defaultDataStrategy(_ref4) { 4649 let { 4650 matches 4651 } = _ref4; 4652 let matchesToLoad = matches.filter(m => m.shouldLoad); 4653 let results = await Promise.all(matchesToLoad.map(m => m.resolve())); 4654 return results.reduce((acc, result, i) => Object.assign(acc, { 4655 [matchesToLoad[i].route.id]: result 4656 }), {}); 4657 } 4658 async function callDataStrategyImpl(dataStrategyImpl, type, state, request, matchesToLoad, matches, fetcherKey, manifest, mapRouteProperties, requestContext) { 4659 let loadRouteDefinitionsPromises = matches.map(m => m.route.lazy ? loadLazyRouteModule(m.route, mapRouteProperties, manifest) : undefined); 4660 let dsMatches = matches.map((match, i) => { 4661 let loadRoutePromise = loadRouteDefinitionsPromises[i]; 4662 let shouldLoad = matchesToLoad.some(m => m.route.id === match.route.id); 4663 // `resolve` encapsulates route.lazy(), executing the loader/action, 4664 // and mapping return values/thrown errors to a `DataStrategyResult`. Users 4665 // can pass a callback to take fine-grained control over the execution 4666 // of the loader/action 4667 let resolve = async handlerOverride => { 4668 if (handlerOverride && request.method === "GET" && (match.route.lazy || match.route.loader)) { 4669 shouldLoad = true; 4670 } 4671 return shouldLoad ? callLoaderOrAction(type, request, match, loadRoutePromise, handlerOverride, requestContext) : Promise.resolve({ 4672 type: ResultType.data, 4673 result: undefined 4674 }); 4675 }; 4676 return _extends({}, match, { 4677 shouldLoad, 4678 resolve 4679 }); 4680 }); 4621 4681 4622 4682 // Send all matches here to allow for a middleware-type implementation. … … 4624 4684 // back out below. 4625 4685 let results = await dataStrategyImpl({ 4626 matches: matches.map(match => { 4627 let shouldLoad = routeIdsToLoad.has(match.route.id); 4628 // `resolve` encapsulates the route.lazy, executing the 4629 // loader/action, and mapping return values/thrown errors to a 4630 // HandlerResult. Users can pass a callback to take fine-grained control 4631 // over the execution of the loader/action 4632 let resolve = handlerOverride => { 4633 loadedMatches.add(match.route.id); 4634 return shouldLoad ? callLoaderOrAction(type, request, match, manifest, mapRouteProperties, handlerOverride, requestContext) : Promise.resolve({ 4635 type: ResultType.data, 4636 result: undefined 4637 }); 4638 }; 4639 return _extends({}, match, { 4640 shouldLoad, 4641 resolve 4642 }); 4643 }), 4686 matches: dsMatches, 4644 4687 request, 4645 4688 params: matches[0].params, 4689 fetcherKey, 4646 4690 context: requestContext 4647 4691 }); 4648 4692 4649 // Throw if any loadRoute implementations not called since they are what 4650 // ensures a route is fully loaded 4651 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.")); 4652 4653 // Filter out any middleware-only matches for which we didn't need to run handlers 4654 return results.filter((_, i) => routeIdsToLoad.has(matches[i].route.id)); 4693 // Wait for all routes to load here but 'swallow the error since we want 4694 // it to bubble up from the `await loadRoutePromise` in `callLoaderOrAction` - 4695 // called from `match.resolve()` 4696 try { 4697 await Promise.all(loadRouteDefinitionsPromises); 4698 } catch (e) { 4699 // No-op 4700 } 4701 return results; 4655 4702 } 4656 4703 4657 4704 // Default logic for calling a loader/action is the user has no specified a dataStrategy 4658 async function callLoaderOrAction(type, request, match, manifest, mapRouteProperties, handlerOverride, staticContext) {4705 async function callLoaderOrAction(type, request, match, loadRoutePromise, handlerOverride, staticContext) { 4659 4706 let result; 4660 4707 let onReject; … … 4662 4709 // Setup a promise we can race against so that abort signals short circuit 4663 4710 let reject; 4664 // This will never resolve so safe to type it as Promise< HandlerResult> to4711 // This will never resolve so safe to type it as Promise<DataStrategyResult> to 4665 4712 // satisfy the function return value 4666 4713 let abortPromise = new Promise((_, r) => reject = r); … … 4677 4724 }, ...(ctx !== undefined ? [ctx] : [])); 4678 4725 }; 4679 let handlerPromise; 4680 if (handlerOverride) { 4681 handlerPromise = handlerOverride(ctx => actualHandler(ctx)); 4682 } else { 4683 handlerPromise = (async () => { 4684 try { 4685 let val = await actualHandler(); 4686 return { 4687 type: "data", 4688 result: val 4689 }; 4690 } catch (e) { 4691 return { 4692 type: "error", 4693 result: e 4694 }; 4695 } 4696 })(); 4697 } 4726 let handlerPromise = (async () => { 4727 try { 4728 let val = await (handlerOverride ? handlerOverride(ctx => actualHandler(ctx)) : actualHandler()); 4729 return { 4730 type: "data", 4731 result: val 4732 }; 4733 } catch (e) { 4734 return { 4735 type: "error", 4736 result: e 4737 }; 4738 } 4739 })(); 4698 4740 return Promise.race([handlerPromise, abortPromise]); 4699 4741 }; 4700 4742 try { 4701 4743 let handler = match.route[type]; 4702 if (match.route.lazy) { 4744 4745 // If we have a route.lazy promise, await that first 4746 if (loadRoutePromise) { 4703 4747 if (handler) { 4704 4748 // Run statically defined handler in parallel with lazy() … … 4710 4754 runHandler(handler).catch(e => { 4711 4755 handlerError = e; 4712 }), load LazyRouteModule(match.route, mapRouteProperties, manifest)]);4756 }), loadRoutePromise]); 4713 4757 if (handlerError !== undefined) { 4714 4758 throw handlerError; … … 4717 4761 } else { 4718 4762 // Load lazy route module, then run any returned handler 4719 await load LazyRouteModule(match.route, mapRouteProperties, manifest);4763 await loadRoutePromise; 4720 4764 handler = match.route[type]; 4721 4765 if (handler) { … … 4753 4797 } catch (e) { 4754 4798 // We should already be catching and converting normal handler executions to 4755 // HandlerResults and returning them, so anything that throws here is an4799 // DataStrategyResults and returning them, so anything that throws here is an 4756 4800 // unexpected error we still need to wrap 4757 4801 return { … … 4766 4810 return result; 4767 4811 } 4768 async function convert HandlerResultToDataResult(handlerResult) {4812 async function convertDataStrategyResultToDataResult(dataStrategyResult) { 4769 4813 let { 4770 4814 result, 4771 4815 type 4772 } = handlerResult;4816 } = dataStrategyResult; 4773 4817 if (isResponse(result)) { 4774 4818 let data; … … 4819 4863 } 4820 4864 4821 // Convert thrown unstable_data() to ErrorResponse instances4865 // Convert thrown data() to ErrorResponse instances 4822 4866 result = new ErrorResponseImpl(((_result$init2 = result.init) == null ? void 0 : _result$init2.status) || 500, undefined, result.data); 4823 4867 } … … 4926 4970 return formData; 4927 4971 } 4928 function processRouteLoaderData(matches, matchesToLoad,results, pendingActionResult, activeDeferreds, skipLoaderErrorBubbling) {4972 function processRouteLoaderData(matches, results, pendingActionResult, activeDeferreds, skipLoaderErrorBubbling) { 4929 4973 // Fill in loaderData/errors from our loaders 4930 4974 let loaderData = {}; … … 4936 4980 4937 4981 // Process loader results into state.loaderData/state.errors 4938 results.forEach((result, index) => { 4939 let id = matchesToLoad[index].route.id; 4982 matches.forEach(match => { 4983 if (!(match.route.id in results)) { 4984 return; 4985 } 4986 let id = match.route.id; 4987 let result = results[id]; 4940 4988 invariant(!isRedirectResult(result), "Cannot handle redirect results in processLoaderData"); 4941 4989 if (isErrorResult(result)) { … … 5015 5063 }; 5016 5064 } 5017 function processLoaderData(state, matches, matchesToLoad,results, pendingActionResult, revalidatingFetchers, fetcherResults, activeDeferreds) {5065 function processLoaderData(state, matches, results, pendingActionResult, revalidatingFetchers, fetcherResults, activeDeferreds) { 5018 5066 let { 5019 5067 loaderData, 5020 5068 errors 5021 } = processRouteLoaderData(matches, matchesToLoad,results, pendingActionResult, activeDeferreds, false // This method is only called client side so we always want to bubble5069 } = processRouteLoaderData(matches, results, pendingActionResult, activeDeferreds, false // This method is only called client side so we always want to bubble 5022 5070 ); 5023 5071 5024 5072 // Process results from our revalidating fetchers 5025 for (let index = 0; index < revalidatingFetchers.length; index++){5073 revalidatingFetchers.forEach(rf => { 5026 5074 let { 5027 5075 key, 5028 5076 match, 5029 5077 controller 5030 } = r evalidatingFetchers[index];5031 invariant(fetcherResults !== undefined && fetcherResults[index] !== undefined, "Did not find corresponding fetcher result");5032 let result = fetcherResults[index];5078 } = rf; 5079 let result = fetcherResults[key]; 5080 invariant(result, "Did not find corresponding fetcher result"); 5033 5081 5034 5082 // Process fetcher non-redirect errors 5035 5083 if (controller && controller.signal.aborted) { 5036 5084 // Nothing to do for aborted fetchers 5037 continue;5085 return; 5038 5086 } else if (isErrorResult(result)) { 5039 5087 let boundaryMatch = findNearestBoundary(state.matches, match == null ? void 0 : match.route.id); … … 5056 5104 state.fetchers.set(key, doneFetcher); 5057 5105 } 5058 } 5106 }); 5059 5107 return { 5060 5108 loaderData, … … 5130 5178 if (status === 400) { 5131 5179 statusText = "Bad Request"; 5132 if (type === "route-discovery") { 5133 errorMessage = "Unable to match URL \"" + pathname + "\" - the `unstable_patchRoutesOnMiss()` " + ("function threw the following error:\n" + message); 5134 } else if (method && pathname && routeId) { 5180 if (method && pathname && routeId) { 5135 5181 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."; 5136 5182 } else if (type === "defer-action") { … … 5158 5204 // Find any returned redirect errors, starting from the lowest match 5159 5205 function findRedirect(results) { 5160 for (let i = results.length - 1; i >= 0; i--) { 5161 let result = results[i]; 5206 let entries = Object.entries(results); 5207 for (let i = entries.length - 1; i >= 0; i--) { 5208 let [key, result] = entries[i]; 5162 5209 if (isRedirectResult(result)) { 5163 5210 return { 5164 result,5165 idx: i5211 key, 5212 result 5166 5213 }; 5167 5214 } … … 5193 5240 return false; 5194 5241 } 5195 function isPromise(val) { 5196 return typeof val === "object" && val != null && "then" in val; 5197 } 5198 function isHandlerResult(result) { 5242 function isDataStrategyResult(result) { 5199 5243 return result != null && typeof result === "object" && "type" in result && "result" in result && (result.type === ResultType.data || result.type === ResultType.error); 5200 5244 } 5201 function isRedirect HandlerResult(result) {5245 function isRedirectDataStrategyResultResult(result) { 5202 5246 return isResponse(result.result) && redirectStatusCodes.has(result.result.status); 5203 5247 } … … 5235 5279 return validMutationMethods.has(method.toLowerCase()); 5236 5280 } 5237 async function resolveDeferredResults(currentMatches, matchesToLoad, results, signals, isFetcher, currentLoaderData) { 5238 for (let index = 0; index < results.length; index++) { 5239 let result = results[index]; 5240 let match = matchesToLoad[index]; 5281 async function resolveNavigationDeferredResults(matches, results, signal, currentMatches, currentLoaderData) { 5282 let entries = Object.entries(results); 5283 for (let index = 0; index < entries.length; index++) { 5284 let [routeId, result] = entries[index]; 5285 let match = matches.find(m => (m == null ? void 0 : m.route.id) === routeId); 5241 5286 // If we don't have a match, then we can have a deferred result to do 5242 5287 // anything with. This is for revalidating fetchers where the route was … … 5247 5292 let currentMatch = currentMatches.find(m => m.route.id === match.route.id); 5248 5293 let isRevalidatingLoader = currentMatch != null && !isNewRouteInstance(currentMatch, match) && (currentLoaderData && currentLoaderData[match.route.id]) !== undefined; 5249 if (isDeferredResult(result) && (isFetcher || isRevalidatingLoader)) {5294 if (isDeferredResult(result) && isRevalidatingLoader) { 5250 5295 // Note: we do not have to touch activeDeferreds here since we race them 5251 5296 // against the signal in resolveDeferredData and they'll get aborted 5252 5297 // there if needed 5253 let signal = signals[index]; 5254 invariant(signal, "Expected an AbortSignal for revalidating fetcher deferred result"); 5255 await resolveDeferredData(result, signal, isFetcher).then(result => { 5298 await resolveDeferredData(result, signal, false).then(result => { 5256 5299 if (result) { 5257 results[index] = result || results[index]; 5300 results[routeId] = result; 5301 } 5302 }); 5303 } 5304 } 5305 } 5306 async function resolveFetcherDeferredResults(matches, results, revalidatingFetchers) { 5307 for (let index = 0; index < revalidatingFetchers.length; index++) { 5308 let { 5309 key, 5310 routeId, 5311 controller 5312 } = revalidatingFetchers[index]; 5313 let result = results[key]; 5314 let match = matches.find(m => (m == null ? void 0 : m.route.id) === routeId); 5315 // If we don't have a match, then we can have a deferred result to do 5316 // anything with. This is for revalidating fetchers where the route was 5317 // removed during HMR 5318 if (!match) { 5319 continue; 5320 } 5321 if (isDeferredResult(result)) { 5322 // Note: we do not have to touch activeDeferreds here since we race them 5323 // against the signal in resolveDeferredData and they'll get aborted 5324 // there if needed 5325 invariant(controller, "Expected an AbortController for revalidating fetcher deferred result"); 5326 await resolveDeferredData(result, controller.signal, true).then(result => { 5327 if (result) { 5328 results[key] = result; 5258 5329 } 5259 5330 }); … … 5486 5557 exports.createRouter = createRouter; 5487 5558 exports.createStaticHandler = createStaticHandler; 5559 exports.data = data; 5488 5560 exports.defer = defer; 5489 5561 exports.generatePath = generatePath; … … 5505 5577 exports.resolveTo = resolveTo; 5506 5578 exports.stripBasename = stripBasename; 5507 exports.unstable_data = data;5508 5579 5509 5580 Object.defineProperty(exports, '__esModule', { value: true });
Note:
See TracChangeset
for help on using the changeset viewer.