Legend:
- Unmodified
- Added
- Removed
-
imaps-frontend/node_modules/@remix-run/router/dist/router.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. … … 513 513 * Matches the given routes to a location and returns the match data. 514 514 * 515 * @see https://reactrouter.com/ utils/match-routes515 * @see https://reactrouter.com/v6/utils/match-routes 516 516 */ 517 517 function matchRoutes(routes, locationArg, basename) { … … 738 738 * Returns a path with params interpolated. 739 739 * 740 * @see https://reactrouter.com/ utils/generate-path740 * @see https://reactrouter.com/v6/utils/generate-path 741 741 */ 742 742 function generatePath(originalPath, params) { … … 778 778 * the match. 779 779 * 780 * @see https://reactrouter.com/ utils/match-path780 * @see https://reactrouter.com/v6/utils/match-path 781 781 */ 782 782 function matchPath(pattern, pathname) { … … 890 890 * Returns a resolved path object relative to the given pathname. 891 891 * 892 * @see https://reactrouter.com/ utils/resolve-path892 * @see https://reactrouter.com/v6/utils/resolve-path 893 893 */ 894 894 function resolvePath(to, fromPathname) { … … 1044 1044 * This is a shortcut for creating `application/json` responses. Converts `data` 1045 1045 * to JSON and sets the `Content-Type` header. 1046 * 1047 * @deprecated The `json` method is deprecated in favor of returning raw objects. 1048 * This method will be removed in v7. 1046 1049 */ 1047 1050 const json = function json(data, init) { … … 1212 1215 return value._data; 1213 1216 } 1217 /** 1218 * @deprecated The `defer` method is deprecated in favor of returning raw 1219 * objects. This method will be removed in v7. 1220 */ 1214 1221 const defer = function defer(data, init) { 1215 1222 if (init === void 0) { … … 1363 1370 let inFlightDataRoutes; 1364 1371 let basename = init.basename || "/"; 1365 let dataStrategyImpl = init. unstable_dataStrategy || defaultDataStrategy;1366 let patchRoutesOn MissImpl = init.unstable_patchRoutesOnMiss;1372 let dataStrategyImpl = init.dataStrategy || defaultDataStrategy; 1373 let patchRoutesOnNavigationImpl = init.patchRoutesOnNavigation; 1367 1374 // Config driven behavior flags 1368 1375 let future = _extends({ … … 1393 1400 let initialMatches = matchRoutes(dataRoutes, init.history.location, basename); 1394 1401 let initialErrors = null; 1395 if (initialMatches == null && !patchRoutesOn MissImpl) {1402 if (initialMatches == null && !patchRoutesOnNavigationImpl) { 1396 1403 // If we do not match a user-provided-route, fall back to the root 1397 1404 // to allow the error boundary to take over … … 1408 1415 }; 1409 1416 } 1410 // In SPA apps, if the user provided a patchRoutesOn Missimplementation and1417 // In SPA apps, if the user provided a patchRoutesOnNavigation implementation and 1411 1418 // our initial match is a splat route, clear them out so we run through lazy 1412 1419 // discovery on hydration in case there's a more accurate lazy route match. … … 1425 1432 initialMatches = []; 1426 1433 // If partial hydration and fog of war is enabled, we will be running 1427 // `patchRoutesOn Miss` during hydration so include any partial matches as1434 // `patchRoutesOnNavigation` during hydration so include any partial matches as 1428 1435 // the initial matches so we can properly render `HydrateFallback`'s 1429 1436 if (future.v7_partialHydration) { … … 1446 1453 let loaderData = init.hydrationData ? init.hydrationData.loaderData : null; 1447 1454 let errors = init.hydrationData ? init.hydrationData.errors : null; 1448 let isRouteInitialized = m => {1449 // No loader, nothing to initialize1450 if (!m.route.loader) {1451 return true;1452 }1453 // Explicitly opting-in to running on hydration1454 if (typeof m.route.loader === "function" && m.route.loader.hydrate === true) {1455 return false;1456 }1457 // Otherwise, initialized if hydrated with data or an error1458 return loaderData && loaderData[m.route.id] !== undefined || errors && errors[m.route.id] !== undefined;1459 };1460 1455 // If errors exist, don't consider routes below the boundary 1461 1456 if (errors) { 1462 1457 let idx = initialMatches.findIndex(m => errors[m.route.id] !== undefined); 1463 initialized = initialMatches.slice(0, idx + 1).every( isRouteInitialized);1458 initialized = initialMatches.slice(0, idx + 1).every(m => !shouldLoadRouteOnHydration(m.route, loaderData, errors)); 1464 1459 } else { 1465 initialized = initialMatches.every( isRouteInitialized);1460 initialized = initialMatches.every(m => !shouldLoadRouteOnHydration(m.route, loaderData, errors)); 1466 1461 } 1467 1462 } else { … … 1542 1537 // we don't need to update UI state if they change 1543 1538 let blockerFunctions = new Map(); 1544 // Map of pending patchRoutesOnMiss() promises (keyed by path/matches) so1545 // that we only kick them off once for a given combo1546 let pendingPatchRoutes = new Map();1547 1539 // Flag to ignore the next history update, so we can revert the URL change on 1548 1540 // a POP navigation that was blocked by the user without touching router state 1549 let ignoreNextHistoryUpdate = false;1541 let unblockBlockerHistoryUpdate = undefined; 1550 1542 // Initialize the router, all side effects should be kicked off from here. 1551 1543 // Implemented as a Fluent API for ease of: … … 1562 1554 // Ignore this event if it was just us resetting the URL from a 1563 1555 // blocked POP navigation 1564 if (ignoreNextHistoryUpdate) { 1565 ignoreNextHistoryUpdate = false; 1556 if (unblockBlockerHistoryUpdate) { 1557 unblockBlockerHistoryUpdate(); 1558 unblockBlockerHistoryUpdate = undefined; 1566 1559 return; 1567 1560 } … … 1574 1567 if (blockerKey && delta != null) { 1575 1568 // Restore the URL to match the current UI, but don't update router state 1576 ignoreNextHistoryUpdate = true; 1569 let nextHistoryUpdatePromise = new Promise(resolve => { 1570 unblockBlockerHistoryUpdate = resolve; 1571 }); 1577 1572 init.history.go(delta * -1); 1578 1573 // Put the blocker into a blocked state … … 1587 1582 location 1588 1583 }); 1589 // Re-do the same POP navigation we just blocked 1590 init.history.go(delta); 1584 // Re-do the same POP navigation we just blocked, after the url 1585 // restoration is also complete. See: 1586 // https://github.com/remix-run/react-router/issues/11613 1587 nextHistoryUpdatePromise.then(() => init.history.go(delta)); 1591 1588 }, 1592 1589 reset() { … … 1669 1666 [...subscribers].forEach(subscriber => subscriber(state, { 1670 1667 deletedFetchers: deletedFetchersKeys, 1671 unstable_viewTransitionOpts: opts.viewTransitionOpts,1672 unstable_flushSync: opts.flushSync === true1668 viewTransitionOpts: opts.viewTransitionOpts, 1669 flushSync: opts.flushSync === true 1673 1670 })); 1674 1671 // Remove idle fetchers from state since we only care about in-flight fetchers. … … 1819 1816 } 1820 1817 let preventScrollReset = opts && "preventScrollReset" in opts ? opts.preventScrollReset === true : undefined; 1821 let flushSync = (opts && opts. unstable_flushSync) === true;1818 let flushSync = (opts && opts.flushSync) === true; 1822 1819 let blockerKey = shouldBlockNavigation({ 1823 1820 currentLocation, … … 1857 1854 preventScrollReset, 1858 1855 replace: opts && opts.replace, 1859 enableViewTransition: opts && opts. unstable_viewTransition,1856 enableViewTransition: opts && opts.viewTransition, 1860 1857 flushSync 1861 1858 }); … … 1887 1884 // revalidation so that history correctly updates once the navigation completes 1888 1885 startNavigation(pendingAction || state.historyAction, state.navigation.location, { 1889 overrideNavigation: state.navigation 1886 overrideNavigation: state.navigation, 1887 // Proxy through any rending view transition 1888 enableViewTransition: pendingViewTransitionEnabled === true 1890 1889 }); 1891 1890 } … … 1935 1934 // mutation submission. 1936 1935 // 1937 // Ignore on initial page loads because since the initial loadwill always1936 // Ignore on initial page loads because since the initial hydration will always 1938 1937 // be "same hash". For example, on /page#hash and submit a <Form method="post"> 1939 1938 // which will default to a navigation to /page … … 2035 2034 }; 2036 2035 } else if (discoverResult.type === "error") { 2037 let { 2038 boundaryId, 2039 error 2040 } = handleDiscoverRouteError(location.pathname, discoverResult); 2036 let boundaryId = findNearestBoundary(discoverResult.partialMatches).route.id; 2041 2037 return { 2042 2038 matches: discoverResult.partialMatches, 2043 2039 pendingActionResult: [boundaryId, { 2044 2040 type: ResultType.error, 2045 error 2041 error: discoverResult.error 2046 2042 }] 2047 2043 }; … … 2076 2072 }; 2077 2073 } else { 2078 let results = await callDataStrategy("action", request, [actionMatch], matches);2079 result = results[ 0];2074 let results = await callDataStrategy("action", state, request, [actionMatch], matches, null); 2075 result = results[actionMatch.route.id]; 2080 2076 if (request.signal.aborted) { 2081 2077 return { … … 2095 2091 replace = location === state.location.pathname + state.location.search; 2096 2092 } 2097 await startRedirectNavigation(request, result, {2093 await startRedirectNavigation(request, result, true, { 2098 2094 submission, 2099 2095 replace … … 2167 2163 }; 2168 2164 } else if (discoverResult.type === "error") { 2169 let { 2170 boundaryId, 2171 error 2172 } = handleDiscoverRouteError(location.pathname, discoverResult); 2165 let boundaryId = findNearestBoundary(discoverResult.partialMatches).route.id; 2173 2166 return { 2174 2167 matches: discoverResult.partialMatches, 2175 2168 loaderData: {}, 2176 2169 errors: { 2177 [boundaryId]: error2170 [boundaryId]: discoverResult.error 2178 2171 } 2179 2172 }; … … 2239 2232 } 2240 2233 revalidatingFetchers.forEach(rf => { 2241 if (fetchControllers.has(rf.key)) { 2242 abortFetcher(rf.key); 2243 } 2234 abortFetcher(rf.key); 2244 2235 if (rf.controller) { 2245 2236 // Fetchers use an independent AbortController so that aborting a fetcher … … 2257 2248 loaderResults, 2258 2249 fetcherResults 2259 } = await callLoadersAndMaybeResolveData(state .matches, matches, matchesToLoad, revalidatingFetchers, request);2250 } = await callLoadersAndMaybeResolveData(state, matches, matchesToLoad, revalidatingFetchers, request); 2260 2251 if (request.signal.aborted) { 2261 2252 return { … … 2271 2262 revalidatingFetchers.forEach(rf => fetchControllers.delete(rf.key)); 2272 2263 // If any loaders returned a redirect Response, start a new REPLACE navigation 2273 let redirect = findRedirect( [...loaderResults, ...fetcherResults]);2264 let redirect = findRedirect(loaderResults); 2274 2265 if (redirect) { 2275 if (redirect.idx >= matchesToLoad.length) { 2276 // If this redirect came from a fetcher make sure we mark it in 2277 // fetchRedirectIds so it doesn't get revalidated on the next set of 2278 // loader executions 2279 let fetcherKey = revalidatingFetchers[redirect.idx - matchesToLoad.length].key; 2280 fetchRedirectIds.add(fetcherKey); 2281 } 2282 await startRedirectNavigation(request, redirect.result, { 2266 await startRedirectNavigation(request, redirect.result, true, { 2267 replace 2268 }); 2269 return { 2270 shortCircuited: true 2271 }; 2272 } 2273 redirect = findRedirect(fetcherResults); 2274 if (redirect) { 2275 // If this redirect came from a fetcher make sure we mark it in 2276 // fetchRedirectIds so it doesn't get revalidated on the next set of 2277 // loader executions 2278 fetchRedirectIds.add(redirect.key); 2279 await startRedirectNavigation(request, redirect.result, true, { 2283 2280 replace 2284 2281 }); … … 2291 2288 loaderData, 2292 2289 errors 2293 } = processLoaderData(state, matches, matchesToLoad,loaderResults, pendingActionResult, revalidatingFetchers, fetcherResults, activeDeferreds);2290 } = processLoaderData(state, matches, loaderResults, pendingActionResult, revalidatingFetchers, fetcherResults, activeDeferreds); 2294 2291 // Wire up subscribers to update loaderData as promises settle 2295 2292 activeDeferreds.forEach((deferredData, routeId) => { … … 2303 2300 }); 2304 2301 }); 2305 // During partial hydration, preserve SSR errors for routes that don't re-run2302 // Preserve SSR errors during partial hydration 2306 2303 if (future.v7_partialHydration && initialHydration && state.errors) { 2307 Object.entries(state.errors).filter(_ref2 => { 2308 let [id] = _ref2; 2309 return !matchesToLoad.some(m => m.route.id === id); 2310 }).forEach(_ref3 => { 2311 let [routeId, error] = _ref3; 2312 errors = Object.assign(errors || {}, { 2313 [routeId]: error 2314 }); 2315 }); 2304 errors = _extends({}, state.errors, errors); 2316 2305 } 2317 2306 let updatedFetchers = markFetchRedirectsDone(); … … 2355 2344 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."); 2356 2345 } 2357 if (fetchControllers.has(key))abortFetcher(key);2358 let flushSync = (opts && opts. unstable_flushSync) === true;2346 abortFetcher(key); 2347 let flushSync = (opts && opts.flushSync) === true; 2359 2348 let routesToUse = inFlightDataRoutes || dataRoutes; 2360 2349 let normalizedPath = normalizeTo(state.location, state.matches, basename, future.v7_prependBasename, href, future.v7_relativeSplatPath, routeId, opts == null ? void 0 : opts.relative); … … 2384 2373 } 2385 2374 let match = getTargetMatch(matches, path); 2386 pendingPreventScrollReset = (opts && opts.preventScrollReset) === true;2375 let preventScrollReset = (opts && opts.preventScrollReset) === true; 2387 2376 if (submission && isMutationMethod(submission.formMethod)) { 2388 handleFetcherAction(key, routeId, path, match, matches, fogOfWar.active, flushSync, submission);2377 handleFetcherAction(key, routeId, path, match, matches, fogOfWar.active, flushSync, preventScrollReset, submission); 2389 2378 return; 2390 2379 } … … 2395 2384 path 2396 2385 }); 2397 handleFetcherLoader(key, routeId, path, match, matches, fogOfWar.active, flushSync, submission);2386 handleFetcherLoader(key, routeId, path, match, matches, fogOfWar.active, flushSync, preventScrollReset, submission); 2398 2387 } 2399 2388 // Call the action for the matched fetcher.submit(), and then handle redirects, 2400 2389 // errors, and revalidation 2401 async function handleFetcherAction(key, routeId, path, match, requestMatches, isFogOfWar, flushSync, submission) {2390 async function handleFetcherAction(key, routeId, path, match, requestMatches, isFogOfWar, flushSync, preventScrollReset, submission) { 2402 2391 interruptActiveLoads(); 2403 2392 fetchLoadMatches.delete(key); … … 2431 2420 return; 2432 2421 } else if (discoverResult.type === "error") { 2433 let { 2434 error 2435 } = handleDiscoverRouteError(path, discoverResult); 2436 setFetcherError(key, routeId, error, { 2422 setFetcherError(key, routeId, discoverResult.error, { 2437 2423 flushSync 2438 2424 }); … … 2456 2442 fetchControllers.set(key, abortController); 2457 2443 let originatingLoadId = incrementingLoadId; 2458 let actionResults = await callDataStrategy("action", fetchRequest, [match], requestMatches);2459 let actionResult = actionResults[ 0];2444 let actionResults = await callDataStrategy("action", state, fetchRequest, [match], requestMatches, key); 2445 let actionResult = actionResults[match.route.id]; 2460 2446 if (fetchRequest.signal.aborted) { 2461 2447 // We can delete this so long as we weren't aborted by our own fetcher … … 2488 2474 fetchRedirectIds.add(key); 2489 2475 updateFetcherState(key, getLoadingFetcher(submission)); 2490 return startRedirectNavigation(fetchRequest, actionResult, { 2491 fetcherSubmission: submission 2476 return startRedirectNavigation(fetchRequest, actionResult, false, { 2477 fetcherSubmission: submission, 2478 preventScrollReset 2492 2479 }); 2493 2480 } … … 2524 2511 let revalidatingFetcher = getLoadingFetcher(undefined, existingFetcher ? existingFetcher.data : undefined); 2525 2512 state.fetchers.set(staleKey, revalidatingFetcher); 2526 if (fetchControllers.has(staleKey)) { 2527 abortFetcher(staleKey); 2528 } 2513 abortFetcher(staleKey); 2529 2514 if (rf.controller) { 2530 2515 fetchControllers.set(staleKey, rf.controller); … … 2539 2524 loaderResults, 2540 2525 fetcherResults 2541 } = await callLoadersAndMaybeResolveData(state .matches, matches, matchesToLoad, revalidatingFetchers, revalidationRequest);2526 } = await callLoadersAndMaybeResolveData(state, matches, matchesToLoad, revalidatingFetchers, revalidationRequest); 2542 2527 if (abortController.signal.aborted) { 2543 2528 return; … … 2547 2532 fetchControllers.delete(key); 2548 2533 revalidatingFetchers.forEach(r => fetchControllers.delete(r.key)); 2549 let redirect = findRedirect( [...loaderResults, ...fetcherResults]);2534 let redirect = findRedirect(loaderResults); 2550 2535 if (redirect) { 2551 if (redirect.idx >= matchesToLoad.length) { 2552 // If this redirect came from a fetcher make sure we mark it in 2553 // fetchRedirectIds so it doesn't get revalidated on the next set of 2554 // loader executions 2555 let fetcherKey = revalidatingFetchers[redirect.idx - matchesToLoad.length].key; 2556 fetchRedirectIds.add(fetcherKey); 2557 } 2558 return startRedirectNavigation(revalidationRequest, redirect.result); 2536 return startRedirectNavigation(revalidationRequest, redirect.result, false, { 2537 preventScrollReset 2538 }); 2539 } 2540 redirect = findRedirect(fetcherResults); 2541 if (redirect) { 2542 // If this redirect came from a fetcher make sure we mark it in 2543 // fetchRedirectIds so it doesn't get revalidated on the next set of 2544 // loader executions 2545 fetchRedirectIds.add(redirect.key); 2546 return startRedirectNavigation(revalidationRequest, redirect.result, false, { 2547 preventScrollReset 2548 }); 2559 2549 } 2560 2550 // Process and commit output from loaders … … 2562 2552 loaderData, 2563 2553 errors 2564 } = processLoaderData(state, state.matches, matchesToLoad, loaderResults, undefined, revalidatingFetchers, fetcherResults, activeDeferreds);2554 } = processLoaderData(state, matches, loaderResults, undefined, revalidatingFetchers, fetcherResults, activeDeferreds); 2565 2555 // Since we let revalidations complete even if the submitting fetcher was 2566 2556 // deleted, only put it back to idle if it hasn't been deleted … … 2595 2585 } 2596 2586 // Call the matched loader for fetcher.load(), handling redirects, errors, etc. 2597 async function handleFetcherLoader(key, routeId, path, match, matches, isFogOfWar, flushSync, submission) {2587 async function handleFetcherLoader(key, routeId, path, match, matches, isFogOfWar, flushSync, preventScrollReset, submission) { 2598 2588 let existingFetcher = state.fetchers.get(key); 2599 2589 updateFetcherState(key, getLoadingFetcher(submission, existingFetcher ? existingFetcher.data : undefined), { … … 2607 2597 return; 2608 2598 } else if (discoverResult.type === "error") { 2609 let { 2610 error 2611 } = handleDiscoverRouteError(path, discoverResult); 2612 setFetcherError(key, routeId, error, { 2599 setFetcherError(key, routeId, discoverResult.error, { 2613 2600 flushSync 2614 2601 }); … … 2629 2616 fetchControllers.set(key, abortController); 2630 2617 let originatingLoadId = incrementingLoadId; 2631 let results = await callDataStrategy("loader", fetchRequest, [match], matches);2632 let result = results[ 0];2618 let results = await callDataStrategy("loader", state, fetchRequest, [match], matches, key); 2619 let result = results[match.route.id]; 2633 2620 // Deferred isn't supported for fetcher loads, await everything and treat it 2634 2621 // as a normal load. resolveDeferredData will return undefined if this … … 2661 2648 } else { 2662 2649 fetchRedirectIds.add(key); 2663 await startRedirectNavigation(fetchRequest, result); 2650 await startRedirectNavigation(fetchRequest, result, false, { 2651 preventScrollReset 2652 }); 2664 2653 return; 2665 2654 } … … 2693 2682 * the history action from the original navigation (PUSH or REPLACE). 2694 2683 */ 2695 async function startRedirectNavigation(request, redirect, _temp2) {2684 async function startRedirectNavigation(request, redirect, isNavigation, _temp2) { 2696 2685 let { 2697 2686 submission, 2698 2687 fetcherSubmission, 2688 preventScrollReset, 2699 2689 replace 2700 2690 } = _temp2 === void 0 ? {} : _temp2; … … 2753 2743 formAction: location 2754 2744 }), 2755 // Preserve this flag across redirects 2756 preventScrollReset: pendingPreventScrollReset 2745 // Preserve these flags across redirects 2746 preventScrollReset: preventScrollReset || pendingPreventScrollReset, 2747 enableViewTransition: isNavigation ? pendingViewTransitionEnabled : undefined 2757 2748 }); 2758 2749 } else { … … 2764 2755 // Send fetcher submissions through for shouldRevalidate 2765 2756 fetcherSubmission, 2766 // Preserve this flag across redirects 2767 preventScrollReset: pendingPreventScrollReset 2757 // Preserve these flags across redirects 2758 preventScrollReset: preventScrollReset || pendingPreventScrollReset, 2759 enableViewTransition: isNavigation ? pendingViewTransitionEnabled : undefined 2768 2760 }); 2769 2761 } … … 2771 2763 // Utility wrapper for calling dataStrategy client-side without having to 2772 2764 // pass around the manifest, mapRouteProperties, etc. 2773 async function callDataStrategy(type, request, matchesToLoad, matches) { 2765 async function callDataStrategy(type, state, request, matchesToLoad, matches, fetcherKey) { 2766 let results; 2767 let dataResults = {}; 2774 2768 try { 2775 let results = await callDataStrategyImpl(dataStrategyImpl, type, request, matchesToLoad, matches, manifest, mapRouteProperties); 2776 return await Promise.all(results.map((result, i) => { 2777 if (isRedirectHandlerResult(result)) { 2778 let response = result.result; 2779 return { 2780 type: ResultType.redirect, 2781 response: normalizeRelativeRoutingRedirectResponse(response, request, matchesToLoad[i].route.id, matches, basename, future.v7_relativeSplatPath) 2782 }; 2783 } 2784 return convertHandlerResultToDataResult(result); 2785 })); 2769 results = await callDataStrategyImpl(dataStrategyImpl, type, state, request, matchesToLoad, matches, fetcherKey, manifest, mapRouteProperties); 2786 2770 } catch (e) { 2787 2771 // If the outer dataStrategy method throws, just return the error for all 2788 2772 // matches - and it'll naturally bubble to the root 2789 return matchesToLoad.map(() => ({ 2790 type: ResultType.error, 2791 error: e 2792 })); 2793 } 2794 } 2795 async function callLoadersAndMaybeResolveData(currentMatches, matches, matchesToLoad, fetchersToLoad, request) { 2796 let [loaderResults, ...fetcherResults] = await Promise.all([matchesToLoad.length ? callDataStrategy("loader", request, matchesToLoad, matches) : [], ...fetchersToLoad.map(f => { 2773 matchesToLoad.forEach(m => { 2774 dataResults[m.route.id] = { 2775 type: ResultType.error, 2776 error: e 2777 }; 2778 }); 2779 return dataResults; 2780 } 2781 for (let [routeId, result] of Object.entries(results)) { 2782 if (isRedirectDataStrategyResultResult(result)) { 2783 let response = result.result; 2784 dataResults[routeId] = { 2785 type: ResultType.redirect, 2786 response: normalizeRelativeRoutingRedirectResponse(response, request, routeId, matches, basename, future.v7_relativeSplatPath) 2787 }; 2788 } else { 2789 dataResults[routeId] = await convertDataStrategyResultToDataResult(result); 2790 } 2791 } 2792 return dataResults; 2793 } 2794 async function callLoadersAndMaybeResolveData(state, matches, matchesToLoad, fetchersToLoad, request) { 2795 let currentMatches = state.matches; 2796 // Kick off loaders and fetchers in parallel 2797 let loaderResultsPromise = callDataStrategy("loader", state, request, matchesToLoad, matches, null); 2798 let fetcherResultsPromise = Promise.all(fetchersToLoad.map(async f => { 2797 2799 if (f.matches && f.match && f.controller) { 2798 let fetcherRequest = createClientSideRequest(init.history, f.path, f.controller.signal); 2799 return callDataStrategy("loader", fetcherRequest, [f.match], f.matches).then(r => r[0]); 2800 let results = await callDataStrategy("loader", state, createClientSideRequest(init.history, f.path, f.controller.signal), [f.match], f.matches, f.key); 2801 let result = results[f.match.route.id]; 2802 // Fetcher results are keyed by fetcher key from here on out, not routeId 2803 return { 2804 [f.key]: result 2805 }; 2800 2806 } else { 2801 2807 return Promise.resolve({ 2802 type: ResultType.error, 2803 error: getInternalRouterError(404, { 2804 pathname: f.path 2805 }) 2808 [f.key]: { 2809 type: ResultType.error, 2810 error: getInternalRouterError(404, { 2811 pathname: f.path 2812 }) 2813 } 2806 2814 }); 2807 2815 } 2808 })]); 2809 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)]); 2816 })); 2817 let loaderResults = await loaderResultsPromise; 2818 let fetcherResults = (await fetcherResultsPromise).reduce((acc, r) => Object.assign(acc, r), {}); 2819 await Promise.all([resolveNavigationDeferredResults(matches, loaderResults, request.signal, currentMatches, state.loaderData), resolveFetcherDeferredResults(matches, fetcherResults, fetchersToLoad)]); 2810 2820 return { 2811 2821 loaderResults, … … 2823 2833 if (fetchControllers.has(key)) { 2824 2834 cancelledFetcherLoads.add(key); 2825 abortFetcher(key);2826 }2835 } 2836 abortFetcher(key); 2827 2837 }); 2828 2838 } … … 2897 2907 function abortFetcher(key) { 2898 2908 let controller = fetchControllers.get(key); 2899 invariant(controller, "Expected fetch controller: " + key); 2900 controller.abort(); 2901 fetchControllers.delete(key); 2909 if (controller) { 2910 controller.abort(); 2911 fetchControllers.delete(key); 2912 } 2902 2913 } 2903 2914 function markFetchersDone(keys) { … … 2962 2973 }); 2963 2974 } 2964 function shouldBlockNavigation(_ref 4) {2975 function shouldBlockNavigation(_ref2) { 2965 2976 let { 2966 2977 currentLocation, 2967 2978 nextLocation, 2968 2979 historyAction 2969 } = _ref 4;2980 } = _ref2; 2970 2981 if (blockerFunctions.size === 0) { 2971 2982 return; … … 3011 3022 }; 3012 3023 } 3013 function handleDiscoverRouteError(pathname, discoverResult) {3014 return {3015 boundaryId: findNearestBoundary(discoverResult.partialMatches).route.id,3016 error: getInternalRouterError(400, {3017 type: "route-discovery",3018 pathname,3019 message: discoverResult.error != null && "message" in discoverResult.error ? discoverResult.error : String(discoverResult.error)3020 })3021 };3022 }3023 3024 function cancelActiveDeferreds(predicate) { 3024 3025 let cancelledRouteIds = []; … … 3083 3084 } 3084 3085 function checkFogOfWar(matches, routesToUse, pathname) { 3085 if (patchRoutesOn MissImpl) {3086 if (patchRoutesOnNavigationImpl) { 3086 3087 if (!matches) { 3087 3088 let fogMatches = matchRoutesImpl(routesToUse, pathname, basename, true); … … 3091 3092 }; 3092 3093 } else { 3093 let leafRoute = matches[matches.length - 1].route; 3094 if (leafRoute.path && (leafRoute.path === "*" || leafRoute.path.endsWith("/*"))) { 3095 // If we matched a splat, it might only be because we haven't yet fetched 3096 // the children that would match with a higher score, so let's fetch 3097 // around and find out 3094 if (Object.keys(matches[0].params).length > 0) { 3095 // If we matched a dynamic param or a splat, it might only be because 3096 // we haven't yet discovered other routes that would match with a 3097 // higher score. Call patchRoutesOnNavigation just to be sure 3098 3098 let partialMatches = matchRoutesImpl(routesToUse, pathname, basename, true); 3099 3099 return { … … 3110 3110 } 3111 3111 async function discoverRoutes(matches, pathname, signal) { 3112 if (!patchRoutesOnNavigationImpl) { 3113 return { 3114 type: "success", 3115 matches 3116 }; 3117 } 3112 3118 let partialMatches = matches; 3113 let route = partialMatches.length > 0 ? partialMatches[partialMatches.length - 1].route : null;3114 3119 while (true) { 3115 3120 let isNonHMR = inFlightDataRoutes == null; 3116 3121 let routesToUse = inFlightDataRoutes || dataRoutes; 3122 let localManifest = manifest; 3117 3123 try { 3118 await loadLazyRouteChildren(patchRoutesOnMissImpl, pathname, partialMatches, routesToUse, manifest, mapRouteProperties, pendingPatchRoutes, signal); 3124 await patchRoutesOnNavigationImpl({ 3125 path: pathname, 3126 matches: partialMatches, 3127 patch: (routeId, children) => { 3128 if (signal.aborted) return; 3129 patchRoutesImpl(routeId, children, routesToUse, localManifest, mapRouteProperties); 3130 } 3131 }); 3119 3132 } catch (e) { 3120 3133 return { … … 3130 3143 // HMR will already update the identity and reflow when it lands 3131 3144 // `inFlightDataRoutes` in `completeNavigation` 3132 if (isNonHMR ) {3145 if (isNonHMR && !signal.aborted) { 3133 3146 dataRoutes = [...dataRoutes]; 3134 3147 } … … 3140 3153 } 3141 3154 let newMatches = matchRoutes(routesToUse, pathname, basename); 3142 let matchedSplat = false;3143 3155 if (newMatches) { 3144 let leafRoute = newMatches[newMatches.length - 1].route;3145 if (leafRoute.index) {3146 // If we found an index route, we can stop3147 return {3148 type: "success",3149 matches: newMatches3150 };3151 }3152 if (leafRoute.path && leafRoute.path.length > 0) {3153 if (leafRoute.path === "*") {3154 // If we found a splat route, we can't be sure there's not a3155 // higher-scoring route down some partial matches trail so we need3156 // to check that out3157 matchedSplat = true;3158 } else {3159 // If we found a non-splat route, we can stop3160 return {3161 type: "success",3162 matches: newMatches3163 };3164 }3165 }3166 }3167 let newPartialMatches = matchRoutesImpl(routesToUse, pathname, basename, true);3168 // If we are no longer partially matching anything, this was either a3169 // legit splat match above, or it's a 404. Also avoid loops if the3170 // second pass results in the same partial matches3171 if (!newPartialMatches || partialMatches.map(m => m.route.id).join("-") === newPartialMatches.map(m => m.route.id).join("-")) {3172 3156 return { 3173 3157 type: "success", 3174 matches: matchedSplat ? newMatches : null3158 matches: newMatches 3175 3159 }; 3176 3160 } 3177 partialMatches = newPartialMatches; 3178 route = partialMatches[partialMatches.length - 1].route; 3179 if (route.path === "*") { 3180 // The splat is still our most accurate partial, so run with it 3161 let newPartialMatches = matchRoutesImpl(routesToUse, pathname, basename, true); 3162 // Avoid loops if the second pass results in the same partial matches 3163 if (!newPartialMatches || partialMatches.length === newPartialMatches.length && partialMatches.every((m, i) => m.route.id === newPartialMatches[i].route.id)) { 3181 3164 return { 3182 3165 type: "success", 3183 matches: partialMatches3166 matches: null 3184 3167 }; 3185 3168 } 3169 partialMatches = newPartialMatches; 3186 3170 } 3187 3171 } … … 3301 3285 requestContext, 3302 3286 skipLoaderErrorBubbling, 3303 unstable_dataStrategy3287 dataStrategy 3304 3288 } = _temp3 === void 0 ? {} : _temp3; 3305 3289 let url = new URL(request.url); … … 3353 3337 }; 3354 3338 } 3355 let result = await queryImpl(request, location, matches, requestContext, unstable_dataStrategy || null, skipLoaderErrorBubbling === true, null);3339 let result = await queryImpl(request, location, matches, requestContext, dataStrategy || null, skipLoaderErrorBubbling === true, null); 3356 3340 if (isResponse(result)) { 3357 3341 return result; … … 3395 3379 routeId, 3396 3380 requestContext, 3397 unstable_dataStrategy3381 dataStrategy 3398 3382 } = _temp4 === void 0 ? {} : _temp4; 3399 3383 let url = new URL(request.url); … … 3423 3407 }); 3424 3408 } 3425 let result = await queryImpl(request, location, matches, requestContext, unstable_dataStrategy || null, false, match);3409 let result = await queryImpl(request, location, matches, requestContext, dataStrategy || null, false, match); 3426 3410 if (isResponse(result)) { 3427 3411 return result; … … 3449 3433 return undefined; 3450 3434 } 3451 async function queryImpl(request, location, matches, requestContext, unstable_dataStrategy, skipLoaderErrorBubbling, routeMatch) {3435 async function queryImpl(request, location, matches, requestContext, dataStrategy, skipLoaderErrorBubbling, routeMatch) { 3452 3436 invariant(request.signal, "query()/queryRoute() requests must contain an AbortController signal"); 3453 3437 try { 3454 3438 if (isMutationMethod(request.method.toLowerCase())) { 3455 let result = await submit(request, matches, routeMatch || getTargetMatch(matches, location), requestContext, unstable_dataStrategy, skipLoaderErrorBubbling, routeMatch != null);3439 let result = await submit(request, matches, routeMatch || getTargetMatch(matches, location), requestContext, dataStrategy, skipLoaderErrorBubbling, routeMatch != null); 3456 3440 return result; 3457 3441 } 3458 let result = await loadRouteData(request, matches, requestContext, unstable_dataStrategy, skipLoaderErrorBubbling, routeMatch);3442 let result = await loadRouteData(request, matches, requestContext, dataStrategy, skipLoaderErrorBubbling, routeMatch); 3459 3443 return isResponse(result) ? result : _extends({}, result, { 3460 3444 actionData: null, … … 3463 3447 } catch (e) { 3464 3448 // If the user threw/returned a Response in callLoaderOrAction for a 3465 // `queryRoute` call, we throw the ` HandlerResult` to bail out early3449 // `queryRoute` call, we throw the `DataStrategyResult` to bail out early 3466 3450 // and then return or throw the raw Response here accordingly 3467 if (is HandlerResult(e) && isResponse(e.result)) {3451 if (isDataStrategyResult(e) && isResponse(e.result)) { 3468 3452 if (e.type === ResultType.error) { 3469 3453 throw e.result; … … 3479 3463 } 3480 3464 } 3481 async function submit(request, matches, actionMatch, requestContext, unstable_dataStrategy, skipLoaderErrorBubbling, isRouteRequest) {3465 async function submit(request, matches, actionMatch, requestContext, dataStrategy, skipLoaderErrorBubbling, isRouteRequest) { 3482 3466 let result; 3483 3467 if (!actionMatch.route.action && !actionMatch.route.lazy) { … … 3495 3479 }; 3496 3480 } else { 3497 let results = await callDataStrategy("action", request, [actionMatch], matches, isRouteRequest, requestContext, unstable_dataStrategy);3498 result = results[ 0];3481 let results = await callDataStrategy("action", request, [actionMatch], matches, isRouteRequest, requestContext, dataStrategy); 3482 result = results[actionMatch.route.id]; 3499 3483 if (request.signal.aborted) { 3500 3484 throwStaticHandlerAbortedError(request, isRouteRequest, future); … … 3556 3540 // to call and will commit it when we complete the navigation 3557 3541 let boundaryMatch = skipLoaderErrorBubbling ? actionMatch : findNearestBoundary(matches, actionMatch.route.id); 3558 let context = await loadRouteData(loaderRequest, matches, requestContext, unstable_dataStrategy, skipLoaderErrorBubbling, null, [boundaryMatch.route.id, result]);3542 let context = await loadRouteData(loaderRequest, matches, requestContext, dataStrategy, skipLoaderErrorBubbling, null, [boundaryMatch.route.id, result]); 3559 3543 // action status codes take precedence over loader status codes 3560 3544 return _extends({}, context, { … … 3566 3550 }); 3567 3551 } 3568 let context = await loadRouteData(loaderRequest, matches, requestContext, unstable_dataStrategy, skipLoaderErrorBubbling, null);3552 let context = await loadRouteData(loaderRequest, matches, requestContext, dataStrategy, skipLoaderErrorBubbling, null); 3569 3553 return _extends({}, context, { 3570 3554 actionData: { … … 3579 3563 }); 3580 3564 } 3581 async function loadRouteData(request, matches, requestContext, unstable_dataStrategy, skipLoaderErrorBubbling, routeMatch, pendingActionResult) {3565 async function loadRouteData(request, matches, requestContext, dataStrategy, skipLoaderErrorBubbling, routeMatch, pendingActionResult) { 3582 3566 let isRouteRequest = routeMatch != null; 3583 3567 // Short circuit if we have no loaders to run (queryRoute()) … … 3607 3591 }; 3608 3592 } 3609 let results = await callDataStrategy("loader", request, matchesToLoad, matches, isRouteRequest, requestContext, unstable_dataStrategy);3593 let results = await callDataStrategy("loader", request, matchesToLoad, matches, isRouteRequest, requestContext, dataStrategy); 3610 3594 if (request.signal.aborted) { 3611 3595 throwStaticHandlerAbortedError(request, isRouteRequest, future); … … 3613 3597 // Process and commit output from loaders 3614 3598 let activeDeferreds = new Map(); 3615 let context = processRouteLoaderData(matches, matchesToLoad,results, pendingActionResult, activeDeferreds, skipLoaderErrorBubbling);3599 let context = processRouteLoaderData(matches, results, pendingActionResult, activeDeferreds, skipLoaderErrorBubbling); 3616 3600 // Add a null for any non-loader matches for proper revalidation on the client 3617 3601 let executedLoaders = new Set(matchesToLoad.map(match => match.route.id)); … … 3628 3612 // Utility wrapper for calling dataStrategy server-side without having to 3629 3613 // pass around the manifest, mapRouteProperties, etc. 3630 async function callDataStrategy(type, request, matchesToLoad, matches, isRouteRequest, requestContext, unstable_dataStrategy) { 3631 let results = await callDataStrategyImpl(unstable_dataStrategy || defaultDataStrategy, type, request, matchesToLoad, matches, manifest, mapRouteProperties, requestContext); 3632 return await Promise.all(results.map((result, i) => { 3633 if (isRedirectHandlerResult(result)) { 3614 async function callDataStrategy(type, request, matchesToLoad, matches, isRouteRequest, requestContext, dataStrategy) { 3615 let results = await callDataStrategyImpl(dataStrategy || defaultDataStrategy, type, null, request, matchesToLoad, matches, null, manifest, mapRouteProperties, requestContext); 3616 let dataResults = {}; 3617 await Promise.all(matches.map(async match => { 3618 if (!(match.route.id in results)) { 3619 return; 3620 } 3621 let result = results[match.route.id]; 3622 if (isRedirectDataStrategyResultResult(result)) { 3634 3623 let response = result.result; 3635 3624 // Throw redirects and let the server handle them with an HTTP redirect 3636 throw normalizeRelativeRoutingRedirectResponse(response, request, match esToLoad[i].route.id, matches, basename, future.v7_relativeSplatPath);3625 throw normalizeRelativeRoutingRedirectResponse(response, request, match.route.id, matches, basename, future.v7_relativeSplatPath); 3637 3626 } 3638 3627 if (isResponse(result.result) && isRouteRequest) { … … 3641 3630 throw result; 3642 3631 } 3643 return convertHandlerResultToDataResult(result);3632 dataResults[match.route.id] = await convertDataStrategyResultToDataResult(result); 3644 3633 })); 3634 return dataResults; 3645 3635 } 3646 3636 return { … … 3704 3694 path.hash = location.hash; 3705 3695 } 3706 // Add an ?index param for matched index routes if we don't already have one 3707 if ((to == null || to === "" || to === ".") && activeRouteMatch && activeRouteMatch.route.index && !hasNakedIndexQuery(path.search)) { 3708 path.search = path.search ? path.search.replace(/^\?/, "?index&") : "?index"; 3696 // Account for `?index` params when routing to the current location 3697 if ((to == null || to === "" || to === ".") && activeRouteMatch) { 3698 let nakedIndex = hasNakedIndexQuery(path.search); 3699 if (activeRouteMatch.route.index && !nakedIndex) { 3700 // Add one when we're targeting an index route 3701 path.search = path.search ? path.search.replace(/^\?/, "?index&") : "?index"; 3702 } else if (!activeRouteMatch.route.index && nakedIndex) { 3703 // Remove existing ones when we're not 3704 let params = new URLSearchParams(path.search); 3705 let indexValues = params.getAll("index"); 3706 params.delete("index"); 3707 indexValues.filter(v => v).forEach(v => params.append("index", v)); 3708 let qs = params.toString(); 3709 path.search = qs ? "?" + qs : ""; 3710 } 3709 3711 } 3710 3712 // If we're operating within a basename, prepend it to the pathname. If … … 3752 3754 let text = typeof opts.body === "string" ? opts.body : opts.body instanceof FormData || opts.body instanceof URLSearchParams ? 3753 3755 // https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#plain-text-form-data 3754 Array.from(opts.body.entries()).reduce((acc, _ref 5) => {3755 let [name, value] = _ref 5;3756 Array.from(opts.body.entries()).reduce((acc, _ref3) => { 3757 let [name, value] = _ref3; 3756 3758 return "" + acc + name + "=" + value + "\n"; 3757 3759 }, "") : String(opts.body); … … 3841 3843 }; 3842 3844 } 3843 // Filter out all routes below any caught error as they aren't going to3845 // Filter out all routes at/below any caught error as they aren't going to 3844 3846 // render so we don't need to load them 3845 function getLoaderMatchesUntilBoundary(matches, boundaryId ) {3846 let boundaryMatches = matches;3847 if (boundaryId) {3848 let index = matches.findIndex(m => m.route.id === boundaryId);3849 if (index >= 0) {3850 boundaryMatches = matches.slice(0, index);3851 }3852 } 3853 return boundaryMatches;3854 } 3855 function getMatchesToLoad(history, state, matches, submission, location, i sInitialLoad, skipActionErrorRevalidation, isRevalidationRequired, cancelledDeferredRoutes, cancelledFetcherLoads, deletedFetchers, fetchLoadMatches, fetchRedirectIds, routesToUse, basename, pendingActionResult) {3847 function getLoaderMatchesUntilBoundary(matches, boundaryId, includeBoundary) { 3848 if (includeBoundary === void 0) { 3849 includeBoundary = false; 3850 } 3851 let index = matches.findIndex(m => m.route.id === boundaryId); 3852 if (index >= 0) { 3853 return matches.slice(0, includeBoundary ? index + 1 : index); 3854 } 3855 return matches; 3856 } 3857 function getMatchesToLoad(history, state, matches, submission, location, initialHydration, skipActionErrorRevalidation, isRevalidationRequired, cancelledDeferredRoutes, cancelledFetcherLoads, deletedFetchers, fetchLoadMatches, fetchRedirectIds, routesToUse, basename, pendingActionResult) { 3856 3858 let actionResult = pendingActionResult ? isErrorResult(pendingActionResult[1]) ? pendingActionResult[1].error : pendingActionResult[1].data : undefined; 3857 3859 let currentUrl = history.createURL(state.location); 3858 3860 let nextUrl = history.createURL(location); 3859 3861 // Pick navigation matches that are net-new or qualify for revalidation 3860 let boundaryId = pendingActionResult && isErrorResult(pendingActionResult[1]) ? pendingActionResult[0] : undefined; 3861 let boundaryMatches = boundaryId ? getLoaderMatchesUntilBoundary(matches, boundaryId) : matches; 3862 let boundaryMatches = matches; 3863 if (initialHydration && state.errors) { 3864 // On initial hydration, only consider matches up to _and including_ the boundary. 3865 // This is inclusive to handle cases where a server loader ran successfully, 3866 // a child server loader bubbled up to this route, but this route has 3867 // `clientLoader.hydrate` so we want to still run the `clientLoader` so that 3868 // we have a complete version of `loaderData` 3869 boundaryMatches = getLoaderMatchesUntilBoundary(matches, Object.keys(state.errors)[0], true); 3870 } else if (pendingActionResult && isErrorResult(pendingActionResult[1])) { 3871 // If an action threw an error, we call loaders up to, but not including the 3872 // boundary 3873 boundaryMatches = getLoaderMatchesUntilBoundary(matches, pendingActionResult[0]); 3874 } 3862 3875 // Don't revalidate loaders by default after action 4xx/5xx responses 3863 3876 // when the flag is enabled. They can still opt-into revalidation via … … 3876 3889 return false; 3877 3890 } 3878 if (isInitialLoad) { 3879 if (typeof route.loader !== "function" || route.loader.hydrate) { 3880 return true; 3881 } 3882 return state.loaderData[route.id] === undefined && ( 3883 // Don't re-run if the loader ran and threw an error 3884 !state.errors || state.errors[route.id] === undefined); 3891 if (initialHydration) { 3892 return shouldLoadRouteOnHydration(route, state.loaderData, state.errors); 3885 3893 } 3886 3894 // Always call the loader on new route instances and pending defer cancellations … … 3913 3921 fetchLoadMatches.forEach((f, key) => { 3914 3922 // Don't revalidate: 3915 // - on initial load(shouldn't be any fetchers then anyway)3923 // - on initial hydration (shouldn't be any fetchers then anyway) 3916 3924 // - if fetcher won't be present in the subsequent render 3917 3925 // - no longer matches the URL (v7_fetcherPersist=false) 3918 3926 // - was unmounted but persisted due to v7_fetcherPersist=true 3919 if (i sInitialLoad|| !matches.some(m => m.route.id === f.routeId) || deletedFetchers.has(key)) {3927 if (initialHydration || !matches.some(m => m.route.id === f.routeId) || deletedFetchers.has(key)) { 3920 3928 return; 3921 3929 } … … 3981 3989 return [navigationMatches, revalidatingFetchers]; 3982 3990 } 3991 function shouldLoadRouteOnHydration(route, loaderData, errors) { 3992 // We dunno if we have a loader - gotta find out! 3993 if (route.lazy) { 3994 return true; 3995 } 3996 // No loader, nothing to initialize 3997 if (!route.loader) { 3998 return false; 3999 } 4000 let hasData = loaderData != null && loaderData[route.id] !== undefined; 4001 let hasError = errors != null && errors[route.id] !== undefined; 4002 // Don't run if we error'd during SSR 4003 if (!hasData && hasError) { 4004 return false; 4005 } 4006 // Explicitly opting-in to running on hydration 4007 if (typeof route.loader === "function" && route.loader.hydrate === true) { 4008 return true; 4009 } 4010 // Otherwise, run if we're not yet initialized with anything 4011 return !hasData && !hasError; 4012 } 3983 4013 function isNewLoader(currentLoaderData, currentMatch, match) { 3984 4014 let isNew = … … 4012 4042 return arg.defaultShouldRevalidate; 4013 4043 } 4014 /**4015 * Idempotent utility to execute patchRoutesOnMiss() to lazily load route4016 * definitions and update the routes/routeManifest4017 */4018 async function loadLazyRouteChildren(patchRoutesOnMissImpl, path, matches, routes, manifest, mapRouteProperties, pendingRouteChildren, signal) {4019 let key = [path, ...matches.map(m => m.route.id)].join("-");4020 try {4021 let pending = pendingRouteChildren.get(key);4022 if (!pending) {4023 pending = patchRoutesOnMissImpl({4024 path,4025 matches,4026 patch: (routeId, children) => {4027 if (!signal.aborted) {4028 patchRoutesImpl(routeId, children, routes, manifest, mapRouteProperties);4029 }4030 }4031 });4032 pendingRouteChildren.set(key, pending);4033 }4034 if (pending && isPromise(pending)) {4035 await pending;4036 }4037 } finally {4038 pendingRouteChildren.delete(key);4039 }4040 }4041 4044 function patchRoutesImpl(routeId, children, routesToUse, manifest, mapRouteProperties) { 4045 var _childrenToPatch; 4046 let childrenToPatch; 4042 4047 if (routeId) { 4043 var _route$children;4044 4048 let route = manifest[routeId]; 4045 4049 invariant(route, "No route found to patch children into: routeId = " + routeId); 4046 let dataChildren = convertRoutesToDataRoutes(children, mapRouteProperties, [routeId, "patch", String(((_route$children = route.children) == null ? void 0 : _route$children.length) || "0")], manifest); 4047 if (route.children) { 4048 route.children.push(...dataChildren); 4049 } else { 4050 route.children = dataChildren; 4051 } 4050 if (!route.children) { 4051 route.children = []; 4052 } 4053 childrenToPatch = route.children; 4052 4054 } else { 4053 let dataChildren = convertRoutesToDataRoutes(children, mapRouteProperties, ["patch", String(routesToUse.length || "0")], manifest); 4054 routesToUse.push(...dataChildren); 4055 } 4055 childrenToPatch = routesToUse; 4056 } 4057 // Don't patch in routes we already know about so that `patch` is idempotent 4058 // to simplify user-land code. This is useful because we re-call the 4059 // `patchRoutesOnNavigation` function for matched routes with params. 4060 let uniqueChildren = children.filter(newRoute => !childrenToPatch.some(existingRoute => isSameRoute(newRoute, existingRoute))); 4061 let newRoutes = convertRoutesToDataRoutes(uniqueChildren, mapRouteProperties, [routeId || "_", "patch", String(((_childrenToPatch = childrenToPatch) == null ? void 0 : _childrenToPatch.length) || "0")], manifest); 4062 childrenToPatch.push(...newRoutes); 4063 } 4064 function isSameRoute(newRoute, existingRoute) { 4065 // Most optimal check is by id 4066 if ("id" in newRoute && "id" in existingRoute && newRoute.id === existingRoute.id) { 4067 return true; 4068 } 4069 // Second is by pathing differences 4070 if (!(newRoute.index === existingRoute.index && newRoute.path === existingRoute.path && newRoute.caseSensitive === existingRoute.caseSensitive)) { 4071 return false; 4072 } 4073 // Pathless layout routes are trickier since we need to check children. 4074 // If they have no children then they're the same as far as we can tell 4075 if ((!newRoute.children || newRoute.children.length === 0) && (!existingRoute.children || existingRoute.children.length === 0)) { 4076 return true; 4077 } 4078 // Otherwise, we look to see if every child in the new route is already 4079 // represented in the existing route's children 4080 return newRoute.children.every((aChild, i) => { 4081 var _existingRoute$childr; 4082 return (_existingRoute$childr = existingRoute.children) == null ? void 0 : _existingRoute$childr.some(bChild => isSameRoute(aChild, bChild)); 4083 }); 4056 4084 } 4057 4085 /** … … 4104 4132 } 4105 4133 // Default implementation of `dataStrategy` which fetches all loaders in parallel 4106 function defaultDataStrategy(opts) { 4107 return Promise.all(opts.matches.map(m => m.resolve())); 4108 } 4109 async function callDataStrategyImpl(dataStrategyImpl, type, request, matchesToLoad, matches, manifest, mapRouteProperties, requestContext) { 4110 let routeIdsToLoad = matchesToLoad.reduce((acc, m) => acc.add(m.route.id), new Set()); 4111 let loadedMatches = new Set(); 4134 async function defaultDataStrategy(_ref4) { 4135 let { 4136 matches 4137 } = _ref4; 4138 let matchesToLoad = matches.filter(m => m.shouldLoad); 4139 let results = await Promise.all(matchesToLoad.map(m => m.resolve())); 4140 return results.reduce((acc, result, i) => Object.assign(acc, { 4141 [matchesToLoad[i].route.id]: result 4142 }), {}); 4143 } 4144 async function callDataStrategyImpl(dataStrategyImpl, type, state, request, matchesToLoad, matches, fetcherKey, manifest, mapRouteProperties, requestContext) { 4145 let loadRouteDefinitionsPromises = matches.map(m => m.route.lazy ? loadLazyRouteModule(m.route, mapRouteProperties, manifest) : undefined); 4146 let dsMatches = matches.map((match, i) => { 4147 let loadRoutePromise = loadRouteDefinitionsPromises[i]; 4148 let shouldLoad = matchesToLoad.some(m => m.route.id === match.route.id); 4149 // `resolve` encapsulates route.lazy(), executing the loader/action, 4150 // and mapping return values/thrown errors to a `DataStrategyResult`. Users 4151 // can pass a callback to take fine-grained control over the execution 4152 // of the loader/action 4153 let resolve = async handlerOverride => { 4154 if (handlerOverride && request.method === "GET" && (match.route.lazy || match.route.loader)) { 4155 shouldLoad = true; 4156 } 4157 return shouldLoad ? callLoaderOrAction(type, request, match, loadRoutePromise, handlerOverride, requestContext) : Promise.resolve({ 4158 type: ResultType.data, 4159 result: undefined 4160 }); 4161 }; 4162 return _extends({}, match, { 4163 shouldLoad, 4164 resolve 4165 }); 4166 }); 4112 4167 // Send all matches here to allow for a middleware-type implementation. 4113 4168 // handler will be a no-op for unneeded routes and we filter those results 4114 4169 // back out below. 4115 4170 let results = await dataStrategyImpl({ 4116 matches: matches.map(match => { 4117 let shouldLoad = routeIdsToLoad.has(match.route.id); 4118 // `resolve` encapsulates the route.lazy, executing the 4119 // loader/action, and mapping return values/thrown errors to a 4120 // HandlerResult. Users can pass a callback to take fine-grained control 4121 // over the execution of the loader/action 4122 let resolve = handlerOverride => { 4123 loadedMatches.add(match.route.id); 4124 return shouldLoad ? callLoaderOrAction(type, request, match, manifest, mapRouteProperties, handlerOverride, requestContext) : Promise.resolve({ 4125 type: ResultType.data, 4126 result: undefined 4127 }); 4128 }; 4129 return _extends({}, match, { 4130 shouldLoad, 4131 resolve 4132 }); 4133 }), 4171 matches: dsMatches, 4134 4172 request, 4135 4173 params: matches[0].params, 4174 fetcherKey, 4136 4175 context: requestContext 4137 4176 }); 4138 // Throw if any loadRoute implementations not called since they are what 4139 // ensures a route is fully loaded 4140 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.")); 4141 // Filter out any middleware-only matches for which we didn't need to run handlers 4142 return results.filter((_, i) => routeIdsToLoad.has(matches[i].route.id)); 4177 // Wait for all routes to load here but 'swallow the error since we want 4178 // it to bubble up from the `await loadRoutePromise` in `callLoaderOrAction` - 4179 // called from `match.resolve()` 4180 try { 4181 await Promise.all(loadRouteDefinitionsPromises); 4182 } catch (e) { 4183 // No-op 4184 } 4185 return results; 4143 4186 } 4144 4187 // Default logic for calling a loader/action is the user has no specified a dataStrategy 4145 async function callLoaderOrAction(type, request, match, manifest, mapRouteProperties, handlerOverride, staticContext) {4188 async function callLoaderOrAction(type, request, match, loadRoutePromise, handlerOverride, staticContext) { 4146 4189 let result; 4147 4190 let onReject; … … 4149 4192 // Setup a promise we can race against so that abort signals short circuit 4150 4193 let reject; 4151 // This will never resolve so safe to type it as Promise< HandlerResult> to4194 // This will never resolve so safe to type it as Promise<DataStrategyResult> to 4152 4195 // satisfy the function return value 4153 4196 let abortPromise = new Promise((_, r) => reject = r); … … 4164 4207 }, ...(ctx !== undefined ? [ctx] : [])); 4165 4208 }; 4166 let handlerPromise; 4167 if (handlerOverride) { 4168 handlerPromise = handlerOverride(ctx => actualHandler(ctx)); 4169 } else { 4170 handlerPromise = (async () => { 4171 try { 4172 let val = await actualHandler(); 4173 return { 4174 type: "data", 4175 result: val 4176 }; 4177 } catch (e) { 4178 return { 4179 type: "error", 4180 result: e 4181 }; 4182 } 4183 })(); 4184 } 4209 let handlerPromise = (async () => { 4210 try { 4211 let val = await (handlerOverride ? handlerOverride(ctx => actualHandler(ctx)) : actualHandler()); 4212 return { 4213 type: "data", 4214 result: val 4215 }; 4216 } catch (e) { 4217 return { 4218 type: "error", 4219 result: e 4220 }; 4221 } 4222 })(); 4185 4223 return Promise.race([handlerPromise, abortPromise]); 4186 4224 }; 4187 4225 try { 4188 4226 let handler = match.route[type]; 4189 if (match.route.lazy) { 4227 // If we have a route.lazy promise, await that first 4228 if (loadRoutePromise) { 4190 4229 if (handler) { 4191 4230 // Run statically defined handler in parallel with lazy() … … 4197 4236 runHandler(handler).catch(e => { 4198 4237 handlerError = e; 4199 }), load LazyRouteModule(match.route, mapRouteProperties, manifest)]);4238 }), loadRoutePromise]); 4200 4239 if (handlerError !== undefined) { 4201 4240 throw handlerError; … … 4204 4243 } else { 4205 4244 // Load lazy route module, then run any returned handler 4206 await load LazyRouteModule(match.route, mapRouteProperties, manifest);4245 await loadRoutePromise; 4207 4246 handler = match.route[type]; 4208 4247 if (handler) { … … 4240 4279 } catch (e) { 4241 4280 // We should already be catching and converting normal handler executions to 4242 // HandlerResults and returning them, so anything that throws here is an4281 // DataStrategyResults and returning them, so anything that throws here is an 4243 4282 // unexpected error we still need to wrap 4244 4283 return { … … 4253 4292 return result; 4254 4293 } 4255 async function convert HandlerResultToDataResult(handlerResult) {4294 async function convertDataStrategyResultToDataResult(dataStrategyResult) { 4256 4295 let { 4257 4296 result, 4258 4297 type 4259 } = handlerResult;4298 } = dataStrategyResult; 4260 4299 if (isResponse(result)) { 4261 4300 let data; … … 4305 4344 }; 4306 4345 } 4307 // Convert thrown unstable_data() to ErrorResponse instances4346 // Convert thrown data() to ErrorResponse instances 4308 4347 result = new ErrorResponseImpl(((_result$init2 = result.init) == null ? void 0 : _result$init2.status) || 500, undefined, result.data); 4309 4348 } … … 4410 4449 return formData; 4411 4450 } 4412 function processRouteLoaderData(matches, matchesToLoad,results, pendingActionResult, activeDeferreds, skipLoaderErrorBubbling) {4451 function processRouteLoaderData(matches, results, pendingActionResult, activeDeferreds, skipLoaderErrorBubbling) { 4413 4452 // Fill in loaderData/errors from our loaders 4414 4453 let loaderData = {}; … … 4419 4458 let pendingError = pendingActionResult && isErrorResult(pendingActionResult[1]) ? pendingActionResult[1].error : undefined; 4420 4459 // Process loader results into state.loaderData/state.errors 4421 results.forEach((result, index) => { 4422 let id = matchesToLoad[index].route.id; 4460 matches.forEach(match => { 4461 if (!(match.route.id in results)) { 4462 return; 4463 } 4464 let id = match.route.id; 4465 let result = results[id]; 4423 4466 invariant(!isRedirectResult(result), "Cannot handle redirect results in processLoaderData"); 4424 4467 if (isErrorResult(result)) { … … 4495 4538 }; 4496 4539 } 4497 function processLoaderData(state, matches, matchesToLoad,results, pendingActionResult, revalidatingFetchers, fetcherResults, activeDeferreds) {4540 function processLoaderData(state, matches, results, pendingActionResult, revalidatingFetchers, fetcherResults, activeDeferreds) { 4498 4541 let { 4499 4542 loaderData, 4500 4543 errors 4501 } = processRouteLoaderData(matches, matchesToLoad,results, pendingActionResult, activeDeferreds, false // This method is only called client side so we always want to bubble4544 } = processRouteLoaderData(matches, results, pendingActionResult, activeDeferreds, false // This method is only called client side so we always want to bubble 4502 4545 ); 4503 4546 // Process results from our revalidating fetchers 4504 for (let index = 0; index < revalidatingFetchers.length; index++){4547 revalidatingFetchers.forEach(rf => { 4505 4548 let { 4506 4549 key, 4507 4550 match, 4508 4551 controller 4509 } = r evalidatingFetchers[index];4510 invariant(fetcherResults !== undefined && fetcherResults[index] !== undefined, "Did not find corresponding fetcher result");4511 let result = fetcherResults[index];4552 } = rf; 4553 let result = fetcherResults[key]; 4554 invariant(result, "Did not find corresponding fetcher result"); 4512 4555 // Process fetcher non-redirect errors 4513 4556 if (controller && controller.signal.aborted) { 4514 4557 // Nothing to do for aborted fetchers 4515 continue;4558 return; 4516 4559 } else if (isErrorResult(result)) { 4517 4560 let boundaryMatch = findNearestBoundary(state.matches, match == null ? void 0 : match.route.id); … … 4534 4577 state.fetchers.set(key, doneFetcher); 4535 4578 } 4536 } 4579 }); 4537 4580 return { 4538 4581 loaderData, … … 4607 4650 if (status === 400) { 4608 4651 statusText = "Bad Request"; 4609 if (type === "route-discovery") { 4610 errorMessage = "Unable to match URL \"" + pathname + "\" - the `unstable_patchRoutesOnMiss()` " + ("function threw the following error:\n" + message); 4611 } else if (method && pathname && routeId) { 4652 if (method && pathname && routeId) { 4612 4653 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."; 4613 4654 } else if (type === "defer-action") { … … 4634 4675 // Find any returned redirect errors, starting from the lowest match 4635 4676 function findRedirect(results) { 4636 for (let i = results.length - 1; i >= 0; i--) { 4637 let result = results[i]; 4677 let entries = Object.entries(results); 4678 for (let i = entries.length - 1; i >= 0; i--) { 4679 let [key, result] = entries[i]; 4638 4680 if (isRedirectResult(result)) { 4639 4681 return { 4640 result,4641 idx: i4682 key, 4683 result 4642 4684 }; 4643 4685 } … … 4668 4710 return false; 4669 4711 } 4670 function isPromise(val) { 4671 return typeof val === "object" && val != null && "then" in val; 4672 } 4673 function isHandlerResult(result) { 4712 function isDataStrategyResult(result) { 4674 4713 return result != null && typeof result === "object" && "type" in result && "result" in result && (result.type === ResultType.data || result.type === ResultType.error); 4675 4714 } 4676 function isRedirect HandlerResult(result) {4715 function isRedirectDataStrategyResultResult(result) { 4677 4716 return isResponse(result.result) && redirectStatusCodes.has(result.result.status); 4678 4717 } … … 4710 4749 return validMutationMethods.has(method.toLowerCase()); 4711 4750 } 4712 async function resolveDeferredResults(currentMatches, matchesToLoad, results, signals, isFetcher, currentLoaderData) { 4713 for (let index = 0; index < results.length; index++) { 4714 let result = results[index]; 4715 let match = matchesToLoad[index]; 4751 async function resolveNavigationDeferredResults(matches, results, signal, currentMatches, currentLoaderData) { 4752 let entries = Object.entries(results); 4753 for (let index = 0; index < entries.length; index++) { 4754 let [routeId, result] = entries[index]; 4755 let match = matches.find(m => (m == null ? void 0 : m.route.id) === routeId); 4716 4756 // If we don't have a match, then we can have a deferred result to do 4717 4757 // anything with. This is for revalidating fetchers where the route was … … 4722 4762 let currentMatch = currentMatches.find(m => m.route.id === match.route.id); 4723 4763 let isRevalidatingLoader = currentMatch != null && !isNewRouteInstance(currentMatch, match) && (currentLoaderData && currentLoaderData[match.route.id]) !== undefined; 4724 if (isDeferredResult(result) && (isFetcher || isRevalidatingLoader)) {4764 if (isDeferredResult(result) && isRevalidatingLoader) { 4725 4765 // Note: we do not have to touch activeDeferreds here since we race them 4726 4766 // against the signal in resolveDeferredData and they'll get aborted 4727 4767 // there if needed 4728 let signal = signals[index]; 4729 invariant(signal, "Expected an AbortSignal for revalidating fetcher deferred result"); 4730 await resolveDeferredData(result, signal, isFetcher).then(result => { 4768 await resolveDeferredData(result, signal, false).then(result => { 4731 4769 if (result) { 4732 results[index] = result || results[index]; 4770 results[routeId] = result; 4771 } 4772 }); 4773 } 4774 } 4775 } 4776 async function resolveFetcherDeferredResults(matches, results, revalidatingFetchers) { 4777 for (let index = 0; index < revalidatingFetchers.length; index++) { 4778 let { 4779 key, 4780 routeId, 4781 controller 4782 } = revalidatingFetchers[index]; 4783 let result = results[key]; 4784 let match = matches.find(m => (m == null ? void 0 : m.route.id) === routeId); 4785 // If we don't have a match, then we can have a deferred result to do 4786 // anything with. This is for revalidating fetchers where the route was 4787 // removed during HMR 4788 if (!match) { 4789 continue; 4790 } 4791 if (isDeferredResult(result)) { 4792 // Note: we do not have to touch activeDeferreds here since we race them 4793 // against the signal in resolveDeferredData and they'll get aborted 4794 // there if needed 4795 invariant(controller, "Expected an AbortController for revalidating fetcher deferred result"); 4796 await resolveDeferredData(result, controller.signal, true).then(result => { 4797 if (result) { 4798 results[key] = result; 4733 4799 } 4734 4800 }); … … 4941 5007 //#endregion 4942 5008 4943 export { AbortedDeferredError, Action, IDLE_BLOCKER, IDLE_FETCHER, IDLE_NAVIGATION, UNSAFE_DEFERRED_SYMBOL, DeferredData as UNSAFE_DeferredData, ErrorResponseImpl as UNSAFE_ErrorResponseImpl, convertRouteMatchToUiMatch as UNSAFE_convertRouteMatchToUiMatch, convertRoutesToDataRoutes as UNSAFE_convertRoutesToDataRoutes, decodePath as UNSAFE_decodePath, getResolveToMatches as UNSAFE_getResolveToMatches, invariant as UNSAFE_invariant, warning as UNSAFE_warning, createBrowserHistory, createHashHistory, createMemoryHistory, createPath, createRouter, createStaticHandler, d efer, generatePath, getStaticContextFromError, getToPathname, isDataWithResponseInit, isDeferredData, isRouteErrorResponse, joinPaths, json, matchPath, matchRoutes, normalizePathname, parsePath, redirect, redirectDocument, replace, resolvePath, resolveTo, stripBasename, data as unstable_data};5009 export { AbortedDeferredError, Action, IDLE_BLOCKER, IDLE_FETCHER, IDLE_NAVIGATION, UNSAFE_DEFERRED_SYMBOL, DeferredData as UNSAFE_DeferredData, ErrorResponseImpl as UNSAFE_ErrorResponseImpl, convertRouteMatchToUiMatch as UNSAFE_convertRouteMatchToUiMatch, convertRoutesToDataRoutes as UNSAFE_convertRoutesToDataRoutes, decodePath as UNSAFE_decodePath, getResolveToMatches as UNSAFE_getResolveToMatches, invariant as UNSAFE_invariant, warning as UNSAFE_warning, createBrowserHistory, createHashHistory, createMemoryHistory, createPath, createRouter, createStaticHandler, data, defer, generatePath, getStaticContextFromError, getToPathname, isDataWithResponseInit, isDeferredData, isRouteErrorResponse, joinPaths, json, matchPath, matchRoutes, normalizePathname, parsePath, redirect, redirectDocument, replace, resolvePath, resolveTo, stripBasename }; 4944 5010 //# sourceMappingURL=router.js.map
Note:
See TracChangeset
for help on using the changeset viewer.