@rangojs/router 0.0.0-experimental.32 → 0.0.0-experimental.3232cd17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +4 -0
- package/README.md +198 -44
- package/dist/bin/rango.js +287 -105
- package/dist/testing/vitest.js +82 -0
- package/dist/vite/index.js +3248 -1117
- package/dist/vite/plugins/cloudflare-protocol-loader-hook.mjs +76 -0
- package/package.json +73 -21
- package/skills/api-client/SKILL.md +211 -0
- package/skills/breadcrumbs/SKILL.md +107 -1
- package/skills/bundle-analysis/SKILL.md +159 -0
- package/skills/cache-guide/SKILL.md +245 -21
- package/skills/caching/SKILL.md +302 -6
- package/skills/composability/SKILL.md +27 -2
- package/skills/css/SKILL.md +76 -0
- package/skills/document-cache/SKILL.md +78 -55
- package/skills/handler-use/SKILL.md +364 -0
- package/skills/hooks/SKILL.md +270 -30
- package/skills/host-router/SKILL.md +82 -22
- package/skills/i18n/SKILL.md +276 -0
- package/skills/intercept/SKILL.md +49 -5
- package/skills/layout/SKILL.md +35 -9
- package/skills/links/SKILL.md +249 -17
- package/skills/loader/SKILL.md +294 -30
- package/skills/middleware/SKILL.md +52 -13
- package/skills/migrate-nextjs/SKILL.md +584 -0
- package/skills/migrate-react-router/SKILL.md +769 -0
- package/skills/mime-routes/SKILL.md +27 -0
- package/skills/observability/SKILL.md +137 -0
- package/skills/parallel/SKILL.md +203 -7
- package/skills/prerender/SKILL.md +123 -100
- package/skills/rango/SKILL.md +250 -22
- package/skills/react-compiler/SKILL.md +168 -0
- package/skills/response-routes/SKILL.md +122 -47
- package/skills/route/SKILL.md +97 -5
- package/skills/router-setup/SKILL.md +90 -5
- package/skills/server-actions/SKILL.md +775 -0
- package/skills/streams-and-websockets/SKILL.md +283 -0
- package/skills/tailwind/SKILL.md +27 -3
- package/skills/testing/SKILL.md +129 -0
- package/skills/testing/bindings.md +89 -0
- package/skills/testing/cache-prerender.md +124 -0
- package/skills/testing/client-components.md +122 -0
- package/skills/testing/e2e-parity.md +125 -0
- package/skills/testing/flight.md +92 -0
- package/skills/testing/handles.md +129 -0
- package/skills/testing/loader.md +128 -0
- package/skills/testing/middleware.md +99 -0
- package/skills/testing/render-handler.md +121 -0
- package/skills/testing/response-routes.md +95 -0
- package/skills/testing/reverse-and-types.md +84 -0
- package/skills/testing/server-actions.md +107 -0
- package/skills/testing/server-tree.md +128 -0
- package/skills/testing/setup.md +120 -0
- package/skills/typesafety/SKILL.md +329 -27
- package/skills/use-cache/SKILL.md +36 -5
- package/skills/view-transitions/SKILL.md +294 -0
- package/src/__augment-tests__/augment.ts +81 -0
- package/src/__augment-tests__/augmented.check.ts +116 -0
- package/src/__internal.ts +67 -40
- package/src/browser/action-coordinator.ts +53 -36
- package/src/browser/action-fence.ts +47 -0
- package/src/browser/app-shell.ts +39 -0
- package/src/browser/app-version.ts +14 -0
- package/src/browser/cookie-name.ts +140 -0
- package/src/browser/event-controller.ts +86 -147
- package/src/browser/history-state.ts +21 -0
- package/src/browser/index.ts +3 -3
- package/src/browser/invalidate-client-cache.ts +52 -0
- package/src/browser/link-interceptor.ts +4 -0
- package/src/browser/navigation-bridge.ts +148 -19
- package/src/browser/navigation-client.ts +187 -67
- package/src/browser/navigation-store-handle.ts +38 -0
- package/src/browser/navigation-store.ts +76 -67
- package/src/browser/navigation-transaction.ts +18 -66
- package/src/browser/partial-update.ts +123 -94
- package/src/browser/prefetch/cache.ts +214 -36
- package/src/browser/prefetch/fetch.ts +260 -38
- package/src/browser/prefetch/policy.ts +6 -0
- package/src/browser/prefetch/queue.ts +126 -20
- package/src/browser/prefetch/resource-ready.ts +77 -0
- package/src/browser/rango-state.ts +158 -76
- package/src/browser/react/Link.tsx +93 -11
- package/src/browser/react/NavigationProvider.tsx +115 -34
- package/src/browser/react/ScrollRestoration.tsx +10 -6
- package/src/browser/react/context.ts +7 -2
- package/src/browser/react/filter-segment-order.ts +49 -7
- package/src/browser/react/index.ts +0 -48
- package/src/browser/react/location-state-shared.ts +166 -8
- package/src/browser/react/location-state.ts +39 -14
- package/src/browser/react/use-action.ts +6 -15
- package/src/browser/react/use-handle.ts +23 -69
- package/src/browser/react/use-link-status.ts +0 -4
- package/src/browser/react/use-navigation.ts +22 -5
- package/src/browser/react/use-params.ts +20 -10
- package/src/browser/react/use-reverse.ts +106 -0
- package/src/browser/react/use-router.ts +46 -11
- package/src/browser/react/use-search-params.ts +0 -5
- package/src/browser/react/use-segments.ts +11 -21
- package/src/browser/response-adapter.ts +52 -1
- package/src/browser/rsc-router.tsx +215 -76
- package/src/browser/scroll-restoration.ts +46 -39
- package/src/browser/segment-reconciler.ts +36 -9
- package/src/browser/segment-structure-assert.ts +2 -2
- package/src/browser/server-action-bridge.ts +176 -50
- package/src/browser/types.ts +95 -11
- package/src/browser/validate-redirect-origin.ts +43 -16
- package/src/build/collect-fallback-refs.ts +107 -0
- package/src/build/generate-manifest.ts +65 -40
- package/src/build/generate-route-types.ts +5 -0
- package/src/build/index.ts +8 -2
- package/src/build/prefix-tree-utils.ts +123 -0
- package/src/build/route-trie.ts +137 -32
- package/src/build/route-types/codegen.ts +4 -4
- package/src/build/route-types/include-resolution.ts +9 -2
- package/src/build/route-types/param-extraction.ts +6 -3
- package/src/build/route-types/per-module-writer.ts +7 -4
- package/src/build/route-types/router-processing.ts +278 -96
- package/src/build/route-types/scan-filter.ts +9 -2
- package/src/build/route-types/source-scan.ts +118 -0
- package/src/build/runtime-discovery.ts +9 -20
- package/src/cache/cache-error.ts +104 -0
- package/src/cache/cache-policy.ts +68 -28
- package/src/cache/cache-runtime.ts +149 -43
- package/src/cache/cache-scope.ts +148 -81
- package/src/cache/cache-tag.ts +98 -0
- package/src/cache/cf/cf-cache-store.ts +2550 -93
- package/src/cache/cf/index.ts +11 -17
- package/src/cache/document-cache.ts +78 -27
- package/src/cache/handle-snapshot.ts +63 -0
- package/src/cache/index.ts +23 -20
- package/src/cache/memory-segment-store.ts +136 -37
- package/src/cache/profile-registry.ts +6 -30
- package/src/cache/read-through-swr.ts +41 -11
- package/src/cache/segment-codec.ts +0 -16
- package/src/cache/tag-invalidation.ts +230 -0
- package/src/cache/taint.ts +55 -0
- package/src/cache/types.ts +33 -100
- package/src/cache/vercel/index.ts +11 -0
- package/src/cache/vercel/vercel-cache-store.ts +799 -0
- package/src/client.rsc.tsx +6 -21
- package/src/client.tsx +108 -290
- package/src/component-utils.ts +19 -0
- package/src/context-var.ts +84 -2
- package/src/debug.ts +2 -2
- package/src/decode-loader-results.ts +36 -0
- package/src/defer.ts +196 -0
- package/src/deps/ssr.ts +0 -1
- package/src/errors.ts +30 -4
- package/src/handle.ts +70 -22
- package/src/handles/MetaTags.tsx +0 -14
- package/src/handles/breadcrumbs.ts +16 -5
- package/src/handles/meta.ts +0 -39
- package/src/host/cookie-handler.ts +0 -36
- package/src/host/errors.ts +0 -24
- package/src/host/index.ts +8 -2
- package/src/host/pattern-matcher.ts +7 -50
- package/src/host/router.ts +107 -99
- package/src/host/testing.ts +40 -27
- package/src/host/types.ts +37 -4
- package/src/host/utils.ts +1 -1
- package/src/href-client.ts +137 -22
- package/src/index.rsc.ts +52 -26
- package/src/index.ts +100 -38
- package/src/internal-debug.ts +2 -4
- package/src/loader-store.ts +500 -0
- package/src/loader.rsc.ts +20 -13
- package/src/loader.ts +12 -11
- package/src/missing-id-error.ts +68 -0
- package/src/network-error-thrower.tsx +1 -6
- package/src/outlet-context.ts +1 -1
- package/src/outlet-provider.tsx +1 -5
- package/src/prerender/param-hash.ts +10 -11
- package/src/prerender/store.ts +37 -41
- package/src/prerender.ts +198 -82
- package/src/redirect-origin.ts +100 -0
- package/src/response-utils.ts +37 -0
- package/src/reverse.ts +65 -15
- package/src/root-error-boundary.tsx +1 -19
- package/src/route-content-wrapper.tsx +7 -72
- package/src/route-definition/dsl-helpers.ts +437 -274
- package/src/route-definition/helper-factories.ts +29 -139
- package/src/route-definition/helpers-types.ts +113 -37
- package/src/route-definition/index.ts +3 -0
- package/src/route-definition/redirect.ts +52 -10
- package/src/route-definition/resolve-handler-use.ts +161 -0
- package/src/route-definition/use-item-types.ts +32 -0
- package/src/route-map-builder.ts +7 -17
- package/src/route-types.ts +37 -41
- package/src/router/basename.ts +14 -0
- package/src/router/content-negotiation.ts +108 -9
- package/src/router/error-handling.ts +13 -17
- package/src/router/find-match.ts +45 -22
- package/src/router/handler-context.ts +83 -41
- package/src/router/intercept-resolution.ts +25 -23
- package/src/router/lazy-includes.ts +19 -53
- package/src/router/loader-resolution.ts +213 -30
- package/src/router/logging.ts +5 -8
- package/src/router/manifest.ts +49 -45
- package/src/router/match-api.ts +120 -204
- package/src/router/match-context.ts +0 -22
- package/src/router/match-handlers.ts +58 -58
- package/src/router/match-middleware/background-revalidation.ts +27 -6
- package/src/router/match-middleware/cache-lookup.ts +205 -249
- package/src/router/match-middleware/cache-store.ts +45 -32
- package/src/router/match-middleware/intercept-resolution.ts +8 -28
- package/src/router/match-middleware/segment-resolution.ts +52 -18
- package/src/router/match-pipelines.ts +1 -42
- package/src/router/match-result.ts +104 -40
- package/src/router/metrics.ts +5 -34
- package/src/router/middleware-types.ts +13 -142
- package/src/router/middleware.ts +173 -143
- package/src/router/navigation-snapshot.ts +131 -0
- package/src/router/params-util.ts +23 -0
- package/src/router/pattern-matching.ts +109 -63
- package/src/router/prerender-match.ts +190 -54
- package/src/router/preview-match.ts +32 -102
- package/src/router/request-classification.ts +276 -0
- package/src/router/revalidation.ts +63 -55
- package/src/router/route-snapshot.ts +244 -0
- package/src/router/router-context.ts +6 -28
- package/src/router/router-interfaces.ts +100 -35
- package/src/router/router-options.ts +91 -11
- package/src/router/router-registry.ts +2 -5
- package/src/router/segment-resolution/fresh.ts +242 -75
- package/src/router/segment-resolution/helpers.ts +63 -24
- package/src/router/segment-resolution/loader-cache.ts +41 -37
- package/src/router/segment-resolution/revalidation.ts +456 -372
- package/src/router/segment-resolution/static-store.ts +19 -5
- package/src/router/segment-resolution/streamed-handler-telemetry.ts +52 -0
- package/src/router/segment-resolution/view-transition-default.ts +36 -0
- package/src/router/segment-resolution.ts +4 -1
- package/src/router/segment-wrappers.ts +2 -3
- package/src/router/state-cookie-name.ts +33 -0
- package/src/router/substitute-pattern-params.ts +56 -0
- package/src/router/telemetry-otel.ts +0 -20
- package/src/router/telemetry.ts +96 -19
- package/src/router/timeout.ts +0 -20
- package/src/router/trie-matching.ts +91 -46
- package/src/router/types.ts +10 -63
- package/src/router/url-params.ts +44 -0
- package/src/router.ts +134 -43
- package/src/rsc/handler-context.ts +3 -2
- package/src/rsc/handler.ts +492 -383
- package/src/rsc/helpers.ts +162 -46
- package/src/rsc/index.ts +1 -1
- package/src/rsc/json-route-result.ts +38 -0
- package/src/rsc/loader-fetch.ts +23 -3
- package/src/rsc/manifest-init.ts +33 -42
- package/src/rsc/origin-guard.ts +39 -25
- package/src/rsc/progressive-enhancement.ts +30 -3
- package/src/rsc/redirect-guard.ts +99 -0
- package/src/rsc/response-error.ts +79 -12
- package/src/rsc/response-route-handler.ts +90 -63
- package/src/rsc/rsc-rendering.ts +56 -54
- package/src/rsc/runtime-warnings.ts +23 -10
- package/src/rsc/server-action.ts +74 -67
- package/src/rsc/ssr-setup.ts +18 -2
- package/src/rsc/types.ts +25 -6
- package/src/runtime-env.ts +18 -0
- package/src/search-params.ts +4 -20
- package/src/segment-content-promise.ts +67 -0
- package/src/segment-loader-promise.ts +134 -0
- package/src/segment-system.tsx +272 -129
- package/src/serialize.ts +243 -0
- package/src/server/context.ts +309 -61
- package/src/server/cookie-store.ts +80 -5
- package/src/server/handle-store.ts +26 -24
- package/src/server/loader-registry.ts +10 -28
- package/src/server/request-context.ts +338 -126
- package/src/ssr/index.tsx +23 -15
- package/src/static-handler.ts +27 -18
- package/src/testing/cache-status.ts +162 -0
- package/src/testing/collect-handle.ts +40 -0
- package/src/testing/dispatch.ts +618 -0
- package/src/testing/dom.entry.ts +22 -0
- package/src/testing/e2e/fixture.ts +188 -0
- package/src/testing/e2e/index.ts +128 -0
- package/src/testing/e2e/matchers.ts +35 -0
- package/src/testing/e2e/page-helpers.ts +272 -0
- package/src/testing/e2e/parity.ts +387 -0
- package/src/testing/e2e/server.ts +195 -0
- package/src/testing/flight-matchers.ts +97 -0
- package/src/testing/flight-normalize.ts +11 -0
- package/src/testing/flight-runtime.d.ts +57 -0
- package/src/testing/flight-tree.ts +682 -0
- package/src/testing/flight.entry.ts +52 -0
- package/src/testing/flight.ts +232 -0
- package/src/testing/generated-routes.ts +183 -0
- package/src/testing/index.ts +99 -0
- package/src/testing/internal/context.ts +348 -0
- package/src/testing/internal/flight-client-globals.ts +30 -0
- package/src/testing/internal/seed-vars.ts +54 -0
- package/src/testing/render-handler.ts +330 -0
- package/src/testing/render-route.tsx +566 -0
- package/src/testing/run-loader.ts +378 -0
- package/src/testing/run-middleware.ts +205 -0
- package/src/testing/vitest-stubs/cloudflare-email.ts +9 -0
- package/src/testing/vitest-stubs/cloudflare-workers.ts +21 -0
- package/src/testing/vitest-stubs/plugin-rsc.ts +16 -0
- package/src/testing/vitest-stubs/version.ts +5 -0
- package/src/testing/vitest.ts +305 -0
- package/src/theme/ThemeProvider.tsx +0 -52
- package/src/theme/ThemeScript.tsx +0 -6
- package/src/theme/constants.ts +0 -12
- package/src/theme/index.ts +0 -7
- package/src/theme/theme-context.ts +1 -5
- package/src/theme/theme-script.ts +0 -14
- package/src/theme/use-theme.ts +0 -3
- package/src/types/boundaries.ts +0 -35
- package/src/types/cache-types.ts +17 -8
- package/src/types/error-types.ts +30 -90
- package/src/types/global-namespace.ts +54 -41
- package/src/types/handler-context.ts +233 -81
- package/src/types/index.ts +1 -10
- package/src/types/loader-types.ts +44 -15
- package/src/types/request-scope.ts +107 -0
- package/src/types/route-config.ts +6 -50
- package/src/types/route-entry.ts +19 -7
- package/src/types/segments.ts +37 -14
- package/src/urls/include-helper.ts +33 -70
- package/src/urls/index.ts +1 -11
- package/src/urls/path-helper-types.ts +58 -11
- package/src/urls/path-helper.ts +57 -111
- package/src/urls/pattern-types.ts +48 -19
- package/src/urls/response-types.ts +25 -22
- package/src/urls/type-extraction.ts +58 -139
- package/src/urls/urls-function.ts +1 -18
- package/src/use-loader.tsx +346 -89
- package/src/vite/debug.ts +185 -0
- package/src/vite/discovery/bundle-postprocess.ts +36 -38
- package/src/vite/discovery/discover-routers.ts +130 -85
- package/src/vite/discovery/discovery-errors.ts +194 -0
- package/src/vite/discovery/gate-state.ts +171 -0
- package/src/vite/discovery/prerender-collection.ts +192 -99
- package/src/vite/discovery/route-types-writer.ts +40 -84
- package/src/vite/discovery/self-gen-tracking.ts +27 -1
- package/src/vite/discovery/state.ts +51 -6
- package/src/vite/discovery/virtual-module-codegen.ts +14 -34
- package/src/vite/index.ts +8 -0
- package/src/vite/plugin-types.ts +187 -69
- package/src/vite/plugins/cjs-to-esm.ts +8 -18
- package/src/vite/plugins/client-ref-dedup.ts +16 -11
- package/src/vite/plugins/client-ref-hashing.ts +28 -15
- package/src/vite/plugins/cloudflare-protocol-loader-hook.d.mts +23 -0
- package/src/vite/plugins/cloudflare-protocol-loader-hook.mjs +76 -0
- package/src/vite/plugins/cloudflare-protocol-stub.ts +194 -0
- package/src/vite/plugins/expose-action-id.ts +49 -98
- package/src/vite/plugins/expose-id-utils.ts +11 -50
- package/src/vite/plugins/expose-ids/export-analysis.ts +76 -34
- package/src/vite/plugins/expose-ids/handler-transform.ts +10 -48
- package/src/vite/plugins/expose-ids/loader-transform.ts +3 -20
- package/src/vite/plugins/expose-ids/router-transform.ts +20 -16
- package/src/vite/plugins/expose-internal-ids.ts +554 -317
- package/src/vite/plugins/performance-tracks.ts +89 -0
- package/src/vite/plugins/refresh-cmd.ts +89 -27
- package/src/vite/plugins/use-cache-transform.ts +73 -83
- package/src/vite/plugins/vercel-output.ts +258 -0
- package/src/vite/plugins/version-injector.ts +21 -25
- package/src/vite/plugins/version-plugin.ts +41 -20
- package/src/vite/plugins/virtual-entries.ts +2 -17
- package/src/vite/rango.ts +257 -289
- package/src/vite/router-discovery.ts +930 -140
- package/src/vite/utils/ast-handler-extract.ts +15 -31
- package/src/vite/utils/banner.ts +4 -4
- package/src/vite/utils/bundle-analysis.ts +10 -15
- package/src/vite/utils/client-chunks.ts +184 -0
- package/src/vite/utils/forward-user-plugins.ts +171 -0
- package/src/vite/utils/manifest-utils.ts +4 -59
- package/src/vite/utils/package-resolution.ts +20 -52
- package/src/vite/utils/prerender-utils.ts +27 -29
- package/src/vite/utils/shared-utils.ts +92 -42
- package/src/browser/action-response-classifier.ts +0 -99
- package/src/browser/react/use-client-cache.ts +0 -58
- package/src/browser/shallow.ts +0 -40
- package/src/handles/index.ts +0 -7
- package/src/router/middleware-cookies.ts +0 -55
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure prefix-tree walks shared by the build/discovery layer and the runtime
|
|
3
|
+
* trie builder. Kept in `build/` (not `vite/utils`) so runtime code
|
|
4
|
+
* (rsc/manifest-init via build/route-trie) can consume them without importing
|
|
5
|
+
* from the vite layer. `vite/utils/manifest-utils` re-exports them so existing
|
|
6
|
+
* vite-side imports stay unchanged.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Flatten prefix tree leaf nodes into precomputed route entries.
|
|
11
|
+
* Leaf nodes have no children (no nested includes), so their routes can be
|
|
12
|
+
* used directly by evaluateLazyEntry() without running the handler.
|
|
13
|
+
* Non-leaf nodes are skipped because they have nested lazy includes that
|
|
14
|
+
* require the handler to run for discovery.
|
|
15
|
+
*
|
|
16
|
+
* A leaf is also skipped when its staticPrefix collides with an ancestor
|
|
17
|
+
* include node's staticPrefix. That happens when a dynamic param collapses the
|
|
18
|
+
* staticPrefix of nested includes onto the parent's (e.g. `/m/:id/edit` -> sp
|
|
19
|
+
* `/m`): precomputing such a leaf under the collapsed prefix would let the
|
|
20
|
+
* ancestor's lazy entry claim a route it cannot register (the route is behind
|
|
21
|
+
* further nested lazy includes), producing a RouteNotFoundError at request time
|
|
22
|
+
* (issue #506). Those routes are resolved via the handler chain instead.
|
|
23
|
+
*/
|
|
24
|
+
export function flattenLeafEntries(
|
|
25
|
+
prefixTree: Record<string, any>,
|
|
26
|
+
routeManifest: Record<string, string>,
|
|
27
|
+
result: Array<{ staticPrefix: string; routes: Record<string, string> }>,
|
|
28
|
+
): void {
|
|
29
|
+
function visit(node: any, ancestorStaticPrefixes: Set<string>): void {
|
|
30
|
+
const children = node.children || {};
|
|
31
|
+
if (
|
|
32
|
+
Object.keys(children).length === 0 &&
|
|
33
|
+
node.routes &&
|
|
34
|
+
node.routes.length > 0
|
|
35
|
+
) {
|
|
36
|
+
// Leaf node. Skip if its staticPrefix collides with an ancestor include
|
|
37
|
+
// node's staticPrefix (dynamic-param collapse) — see doc comment above.
|
|
38
|
+
if (ancestorStaticPrefixes.has(node.staticPrefix)) {
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
// Collect its routes from the manifest
|
|
42
|
+
const routes: Record<string, string> = {};
|
|
43
|
+
for (const name of node.routes) {
|
|
44
|
+
if (name in routeManifest) {
|
|
45
|
+
routes[name] = routeManifest[name];
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
result.push({ staticPrefix: node.staticPrefix, routes });
|
|
49
|
+
} else {
|
|
50
|
+
// Non-leaf: recurse into children, tracking this node's staticPrefix as
|
|
51
|
+
// an ancestor so a collapsed nested leaf below it is not over-claimed.
|
|
52
|
+
const nextAncestors = new Set(ancestorStaticPrefixes);
|
|
53
|
+
nextAncestors.add(node.staticPrefix);
|
|
54
|
+
for (const child of Object.values(children)) {
|
|
55
|
+
visit(child, nextAncestors);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
for (const node of Object.values(prefixTree)) {
|
|
60
|
+
visit(node, new Set());
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Build the staticPrefix -> routes lookup the runtime shortcut consumes from a
|
|
66
|
+
* flat precomputed-entry array.
|
|
67
|
+
*
|
|
68
|
+
* A staticPrefix owned by MORE THAN ONE leaf include cannot be collapsed to a
|
|
69
|
+
* single routes object: `new Map(entries.map(e => [e.staticPrefix, e.routes]))`
|
|
70
|
+
* is last-wins, so one include's routes are silently dropped and mis-assigned
|
|
71
|
+
* to whichever entry evaluates first. Two distinct includes legitimately share a
|
|
72
|
+
* staticPrefix when a dynamic param collapses their literal prefixes onto the
|
|
73
|
+
* same value (e.g. `include("/shop/:cat", ...)` and a nested
|
|
74
|
+
* `include("/shop/:brand", ...)` both extract "/shop/"). Merging them is also
|
|
75
|
+
* wrong — assigning the merged set to the first matching entry makes findMatch
|
|
76
|
+
* pick the wrong handler for routes belonging to the other include, which then
|
|
77
|
+
* fails its `Store.manifest.has(routeKey)` invariant at render (500 on a valid
|
|
78
|
+
* route, dev/prod identical).
|
|
79
|
+
*
|
|
80
|
+
* So any shared staticPrefix is OMITTED from the shortcut entirely. Those
|
|
81
|
+
* includes fall through to the handler path in evaluateLazyEntry(), which is the
|
|
82
|
+
* ground truth (identical to pre-precomputed behavior). The shortcut is purely an
|
|
83
|
+
* optimization, so dropping a prefix can only cost a handler run, never change a
|
|
84
|
+
* result.
|
|
85
|
+
*/
|
|
86
|
+
export function buildPrecomputedByPrefix(
|
|
87
|
+
entries: Array<{ staticPrefix: string; routes: Record<string, string> }>,
|
|
88
|
+
): Map<string, Record<string, string>> {
|
|
89
|
+
const byPrefix = new Map<string, Record<string, string>>();
|
|
90
|
+
const shared = new Set<string>();
|
|
91
|
+
for (const e of entries) {
|
|
92
|
+
if (byPrefix.has(e.staticPrefix)) {
|
|
93
|
+
shared.add(e.staticPrefix);
|
|
94
|
+
} else {
|
|
95
|
+
byPrefix.set(e.staticPrefix, e.routes);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
for (const sp of shared) {
|
|
99
|
+
byPrefix.delete(sp);
|
|
100
|
+
}
|
|
101
|
+
return byPrefix;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Walk prefix tree to map each route name to its scope's staticPrefix.
|
|
106
|
+
*/
|
|
107
|
+
export function buildRouteToStaticPrefix(
|
|
108
|
+
prefixTree: Record<string, any>,
|
|
109
|
+
result: Record<string, string>,
|
|
110
|
+
): void {
|
|
111
|
+
function visit(node: any): void {
|
|
112
|
+
const sp = node.staticPrefix || "";
|
|
113
|
+
for (const name of node.routes || []) {
|
|
114
|
+
result[name] = sp;
|
|
115
|
+
}
|
|
116
|
+
for (const child of Object.values(node.children || {})) {
|
|
117
|
+
visit(child);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
for (const node of Object.values(prefixTree)) {
|
|
121
|
+
visit(node);
|
|
122
|
+
}
|
|
123
|
+
}
|
package/src/build/route-trie.ts
CHANGED
|
@@ -10,6 +10,8 @@ import {
|
|
|
10
10
|
parsePattern,
|
|
11
11
|
type ParsedSegment,
|
|
12
12
|
} from "../router/pattern-matching.js";
|
|
13
|
+
import { buildRouteToStaticPrefix } from "./prefix-tree-utils.js";
|
|
14
|
+
import type { FullManifest } from "./generate-manifest.js";
|
|
13
15
|
|
|
14
16
|
// -- Trie data structures (compact keys for JSON serialization) --
|
|
15
17
|
|
|
@@ -20,8 +22,6 @@ export interface TrieLeaf {
|
|
|
20
22
|
sp: string;
|
|
21
23
|
/** Ancestry shortCodes from root to route [M0L0, M0L0L0, M0L0L0R499] */
|
|
22
24
|
a: string[];
|
|
23
|
-
/** Optional param names (absent params get empty string value) */
|
|
24
|
-
op?: string[];
|
|
25
25
|
/** Constraint validation: paramName -> allowed values */
|
|
26
26
|
cv?: Record<string, string[]>;
|
|
27
27
|
/** Ordered param names for this route (positional) */
|
|
@@ -60,6 +60,9 @@ export interface TrieNode {
|
|
|
60
60
|
* @param routeAncestry - Map of route name to ancestry shortCodes
|
|
61
61
|
* @param routeToStaticPrefix - Map of route name to its entry's staticPrefix
|
|
62
62
|
* @param routeTrailingSlash - Optional map of route name to trailing slash mode
|
|
63
|
+
* @param prerenderRouteNames - Optional set of prerendered route names (sets leaf.pr)
|
|
64
|
+
* @param passthroughRouteNames - Optional set of passthrough route names (sets leaf.pt)
|
|
65
|
+
* @param responseTypeRoutes - Optional map of route name to response type (sets leaf.rt)
|
|
63
66
|
*/
|
|
64
67
|
export function buildRouteTrie(
|
|
65
68
|
routeManifest: Record<string, string>,
|
|
@@ -94,51 +97,126 @@ export function buildRouteTrie(
|
|
|
94
97
|
});
|
|
95
98
|
}
|
|
96
99
|
|
|
100
|
+
sortSuffixParams(root);
|
|
97
101
|
return root;
|
|
98
102
|
}
|
|
99
103
|
|
|
100
104
|
/**
|
|
101
|
-
*
|
|
102
|
-
* the
|
|
105
|
+
* Sort every node's suffix-param map (`node.xp`) by descending suffix length so
|
|
106
|
+
* the matcher tries the most specific suffix first. Overlapping suffixes like
|
|
107
|
+
* `.min.js` and `.js` must resolve by specificity, not route declaration order:
|
|
108
|
+
* a request for `/app.min.js` should match `:file.min.js`, not `:file.js`.
|
|
109
|
+
*
|
|
110
|
+
* This started as a bug — `walkTrie` iterates `node.xp` in object order and
|
|
111
|
+
* returns the first suffix the segment ends with, so the winner depended on
|
|
112
|
+
* which route was declared first. Sorting at build time fixes it allocation-free
|
|
113
|
+
* on the match hot path: the serialized production trie preserves this key order
|
|
114
|
+
* through JSON.parse, so dev (per-request rebuild) and production match
|
|
115
|
+
* identically. Array.prototype.sort is stable (ES2019+), so equal-length
|
|
116
|
+
* suffixes keep their declaration order — the router's existing tiebreak.
|
|
117
|
+
*/
|
|
118
|
+
function sortSuffixParams(node: TrieNode): void {
|
|
119
|
+
if (node.xp) {
|
|
120
|
+
const sorted: Record<string, { n: string; c: TrieNode }> = {};
|
|
121
|
+
for (const suffix of Object.keys(node.xp).sort(
|
|
122
|
+
(a, b) => b.length - a.length,
|
|
123
|
+
)) {
|
|
124
|
+
sorted[suffix] = node.xp[suffix];
|
|
125
|
+
}
|
|
126
|
+
node.xp = sorted;
|
|
127
|
+
}
|
|
128
|
+
if (node.s) {
|
|
129
|
+
for (const child of Object.values(node.s)) {
|
|
130
|
+
sortSuffixParams(child);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
if (node.p) {
|
|
134
|
+
sortSuffixParams(node.p.c);
|
|
135
|
+
}
|
|
136
|
+
if (node.xp) {
|
|
137
|
+
for (const child of Object.values(node.xp)) {
|
|
138
|
+
sortSuffixParams(child.c);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Build a per-router trie from a generated manifest. This is the single
|
|
145
|
+
* construction path shared by build/discovery (discover-routers.ts, serialized
|
|
146
|
+
* into the production chunk) and the dev/HMR runtime rebuild
|
|
147
|
+
* (rsc/manifest-init.ts). Keeping one code path is what guarantees the dev
|
|
148
|
+
* runtime trie and the production serialized trie are byte-for-byte identical
|
|
149
|
+
* (modulo `leaf.a` ancestry, which embeds the mount index and is debug-only).
|
|
150
|
+
*
|
|
151
|
+
* Returns null when the manifest has no route ancestry (no routes), matching
|
|
152
|
+
* the prior guard at both call sites.
|
|
153
|
+
*/
|
|
154
|
+
export function buildPerRouterTrie(manifest: FullManifest): TrieNode | null {
|
|
155
|
+
const ancestry = manifest._routeAncestry;
|
|
156
|
+
if (!ancestry || Object.keys(ancestry).length === 0) {
|
|
157
|
+
return null;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// Seed every route to the root static prefix (""), then override with each
|
|
161
|
+
// route's include() scope prefix from the prefix tree so the trie returns the
|
|
162
|
+
// correct `sp` for lazy-entry lookup in find-match.
|
|
163
|
+
const routeToStaticPrefix: Record<string, string> = {};
|
|
164
|
+
for (const name of Object.keys(manifest.routeManifest)) {
|
|
165
|
+
routeToStaticPrefix[name] = "";
|
|
166
|
+
}
|
|
167
|
+
if (manifest.prefixTree) {
|
|
168
|
+
buildRouteToStaticPrefix(manifest.prefixTree, routeToStaticPrefix);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
return buildRouteTrie(
|
|
172
|
+
manifest.routeManifest,
|
|
173
|
+
ancestry,
|
|
174
|
+
routeToStaticPrefix,
|
|
175
|
+
manifest.routeTrailingSlash,
|
|
176
|
+
manifest.prerenderRoutes ? new Set(manifest.prerenderRoutes) : undefined,
|
|
177
|
+
manifest.passthroughRoutes
|
|
178
|
+
? new Set(manifest.passthroughRoutes)
|
|
179
|
+
: undefined,
|
|
180
|
+
manifest.responseTypeRoutes,
|
|
181
|
+
);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Insert a route into the trie. Optional params expand into two branches at
|
|
186
|
+
* registration time (skip-first, then present), so each terminal lives at the
|
|
187
|
+
* correct depth for its number of bound params and carries a branch-local
|
|
188
|
+
* `pa` listing only those names. The trie's single-slot `node.p` is reused
|
|
189
|
+
* across branches because matching ignores `node.p.n` — the leaf's `pa` is
|
|
190
|
+
* the source of truth for naming. Skip-first ordering lets `mergeLeaf`'s
|
|
191
|
+
* last-wins rule produce greedy-leftmost semantics for free at any shared
|
|
192
|
+
* terminal depth.
|
|
103
193
|
*/
|
|
104
194
|
function insertRoute(
|
|
105
195
|
node: TrieNode,
|
|
106
196
|
segments: ParsedSegment[],
|
|
107
197
|
index: number,
|
|
108
|
-
leaf: Omit<TrieLeaf, "
|
|
198
|
+
leaf: Omit<TrieLeaf, "cv" | "pa">,
|
|
109
199
|
): void {
|
|
110
|
-
//
|
|
111
|
-
|
|
112
|
-
const optionalParams: string[] = [];
|
|
200
|
+
// cv (full constraint map) is route-level and identical on every terminal,
|
|
201
|
+
// so compute it once on the shared base.
|
|
113
202
|
const constraints: Record<string, string[]> = {};
|
|
114
203
|
|
|
115
204
|
for (const seg of segments) {
|
|
116
205
|
if (seg.type === "param") {
|
|
117
|
-
paramNames.push(seg.value);
|
|
118
|
-
if (seg.optional) {
|
|
119
|
-
optionalParams.push(seg.value);
|
|
120
|
-
}
|
|
121
206
|
if (seg.constraint) {
|
|
122
207
|
constraints[seg.value] = seg.constraint;
|
|
123
208
|
}
|
|
124
209
|
}
|
|
125
210
|
}
|
|
126
211
|
|
|
127
|
-
const
|
|
212
|
+
const leafBase: Omit<TrieLeaf, "pa"> = {
|
|
128
213
|
...leaf,
|
|
129
|
-
...(paramNames.length > 0 ? { pa: paramNames } : {}),
|
|
130
|
-
...(optionalParams.length > 0 ? { op: optionalParams } : {}),
|
|
131
214
|
...(Object.keys(constraints).length > 0 ? { cv: constraints } : {}),
|
|
132
215
|
};
|
|
133
216
|
|
|
134
|
-
insertSegments(node, segments, index,
|
|
217
|
+
insertSegments(node, segments, index, leafBase, []);
|
|
135
218
|
}
|
|
136
219
|
|
|
137
|
-
/**
|
|
138
|
-
* Recursively insert segments into the trie.
|
|
139
|
-
* For optional params, we add a terminal at the current node (param absent)
|
|
140
|
-
* AND continue inserting into the param child (param present).
|
|
141
|
-
*/
|
|
142
220
|
/**
|
|
143
221
|
* Extract ancestry map from a built trie by visiting all leaf nodes.
|
|
144
222
|
* Returns { routeName: ancestryShortCodes[] } for every route in the trie.
|
|
@@ -218,15 +296,25 @@ function mergeLeaf(node: TrieNode, leaf: TrieLeaf): void {
|
|
|
218
296
|
node.r = mergeLeaves(node.r, leaf);
|
|
219
297
|
}
|
|
220
298
|
|
|
299
|
+
function buildLeaf(
|
|
300
|
+
leafBase: Omit<TrieLeaf, "pa">,
|
|
301
|
+
paramNames: string[],
|
|
302
|
+
): TrieLeaf {
|
|
303
|
+
return paramNames.length > 0
|
|
304
|
+
? { ...leafBase, pa: [...paramNames] }
|
|
305
|
+
: { ...leafBase };
|
|
306
|
+
}
|
|
307
|
+
|
|
221
308
|
function insertSegments(
|
|
222
309
|
node: TrieNode,
|
|
223
310
|
segments: ParsedSegment[],
|
|
224
311
|
index: number,
|
|
225
|
-
|
|
312
|
+
leafBase: Omit<TrieLeaf, "pa">,
|
|
313
|
+
paramNames: string[],
|
|
226
314
|
): void {
|
|
227
|
-
// Base case: all segments consumed, add terminal
|
|
315
|
+
// Base case: all segments consumed, add terminal with branch-local pa
|
|
228
316
|
if (index >= segments.length) {
|
|
229
|
-
mergeLeaf(node,
|
|
317
|
+
mergeLeaf(node, buildLeaf(leafBase, paramNames));
|
|
230
318
|
return;
|
|
231
319
|
}
|
|
232
320
|
|
|
@@ -235,12 +323,19 @@ function insertSegments(
|
|
|
235
323
|
if (segment.type === "static") {
|
|
236
324
|
if (!node.s) node.s = {};
|
|
237
325
|
if (!node.s[segment.value]) node.s[segment.value] = {};
|
|
238
|
-
insertSegments(
|
|
326
|
+
insertSegments(
|
|
327
|
+
node.s[segment.value],
|
|
328
|
+
segments,
|
|
329
|
+
index + 1,
|
|
330
|
+
leafBase,
|
|
331
|
+
paramNames,
|
|
332
|
+
);
|
|
239
333
|
} else if (segment.type === "param") {
|
|
240
334
|
if (segment.optional) {
|
|
241
|
-
//
|
|
242
|
-
|
|
243
|
-
//
|
|
335
|
+
// SKIP first: continue at the same node without binding this name.
|
|
336
|
+
// Skip-first ordering means the present-branch's TAKE overwrites any
|
|
337
|
+
// shared terminal later, giving greedy-leftmost semantics.
|
|
338
|
+
insertSegments(node, segments, index + 1, leafBase, paramNames);
|
|
244
339
|
}
|
|
245
340
|
if (segment.suffix) {
|
|
246
341
|
// Suffix param: keyed by suffix string (e.g., ".html")
|
|
@@ -248,16 +343,26 @@ function insertSegments(
|
|
|
248
343
|
if (!node.xp[segment.suffix]) {
|
|
249
344
|
node.xp[segment.suffix] = { n: segment.value, c: {} };
|
|
250
345
|
}
|
|
251
|
-
insertSegments(node.xp[segment.suffix].c, segments, index + 1,
|
|
346
|
+
insertSegments(node.xp[segment.suffix].c, segments, index + 1, leafBase, [
|
|
347
|
+
...paramNames,
|
|
348
|
+
segment.value,
|
|
349
|
+
]);
|
|
252
350
|
} else {
|
|
253
351
|
if (!node.p) {
|
|
254
352
|
node.p = { n: segment.value, c: {} };
|
|
255
353
|
}
|
|
256
|
-
insertSegments(node.p.c, segments, index + 1,
|
|
354
|
+
insertSegments(node.p.c, segments, index + 1, leafBase, [
|
|
355
|
+
...paramNames,
|
|
356
|
+
segment.value,
|
|
357
|
+
]);
|
|
257
358
|
}
|
|
258
359
|
} else if (segment.type === "wildcard") {
|
|
259
|
-
// Wildcard consumes all remaining segments
|
|
260
|
-
|
|
360
|
+
// Wildcard consumes all remaining segments. Carry any params bound before
|
|
361
|
+
// the wildcard in pa so they zip correctly against paramValues at match.
|
|
362
|
+
const wildLeaf: TrieLeaf & { pn: string } = {
|
|
363
|
+
...buildLeaf(leafBase, paramNames),
|
|
364
|
+
pn: "*",
|
|
365
|
+
};
|
|
261
366
|
const existing = node.w ? ({ ...node.w } as TrieLeaf) : undefined;
|
|
262
367
|
const merged = mergeLeaves(existing, wildLeaf);
|
|
263
368
|
node.w = merged as TrieLeaf & { pn: string };
|
|
@@ -23,7 +23,7 @@ export function generatePerModuleTypesSource(
|
|
|
23
23
|
const valid = routes.filter(({ name }) => {
|
|
24
24
|
if (!name || /["'\\`\n\r]/.test(name)) {
|
|
25
25
|
console.warn(
|
|
26
|
-
`[
|
|
26
|
+
`[rango] Skipping route with invalid name: ${JSON.stringify(name)}`,
|
|
27
27
|
);
|
|
28
28
|
return false;
|
|
29
29
|
}
|
|
@@ -42,7 +42,7 @@ export function generatePerModuleTypesSource(
|
|
|
42
42
|
for (const { name, pattern, params, search } of valid) {
|
|
43
43
|
if (deduped.has(name)) {
|
|
44
44
|
console.warn(
|
|
45
|
-
`[
|
|
45
|
+
`[rango] Duplicate route name "${name}" — keeping first definition`,
|
|
46
46
|
);
|
|
47
47
|
continue;
|
|
48
48
|
}
|
|
@@ -59,7 +59,7 @@ export function generatePerModuleTypesSource(
|
|
|
59
59
|
}
|
|
60
60
|
|
|
61
61
|
/**
|
|
62
|
-
* Generates a .ts file that augments
|
|
62
|
+
* Generates a .ts file that augments Rango.GeneratedRouteMap
|
|
63
63
|
* with route name -> pattern mappings. This enables Handler<"routeName">
|
|
64
64
|
* without circular references since the file has no imports from the app.
|
|
65
65
|
*/
|
|
@@ -94,7 +94,7 @@ ${objectBody}
|
|
|
94
94
|
} as const;
|
|
95
95
|
|
|
96
96
|
declare global {
|
|
97
|
-
namespace
|
|
97
|
+
namespace Rango {
|
|
98
98
|
interface GeneratedRouteMap extends Readonly<typeof NamedRoutes> {}
|
|
99
99
|
}
|
|
100
100
|
}
|
|
@@ -357,12 +357,17 @@ function buildRouteMapFromBlock(
|
|
|
357
357
|
/**
|
|
358
358
|
* Build route map and search schemas together.
|
|
359
359
|
* Internal helper used by the include resolution path.
|
|
360
|
+
*
|
|
361
|
+
* @param inlineBlock - Optional pre-extracted code block (e.g. from an inline
|
|
362
|
+
* builder function). When provided, variableName is ignored and the block
|
|
363
|
+
* is parsed directly for path()/include() calls.
|
|
360
364
|
*/
|
|
361
365
|
export function buildCombinedRouteMapWithSearch(
|
|
362
366
|
filePath: string,
|
|
363
367
|
variableName?: string,
|
|
364
368
|
visited?: Set<string>,
|
|
365
369
|
diagnosticsOut?: UnresolvableInclude[],
|
|
370
|
+
inlineBlock?: string,
|
|
366
371
|
): {
|
|
367
372
|
routes: Record<string, string>;
|
|
368
373
|
searchSchemas: Record<string, Record<string, string>>;
|
|
@@ -371,7 +376,7 @@ export function buildCombinedRouteMapWithSearch(
|
|
|
371
376
|
const realPath = resolve(filePath);
|
|
372
377
|
const key = variableName ? `${realPath}:${variableName}` : realPath;
|
|
373
378
|
if (visited.has(key)) {
|
|
374
|
-
console.warn(`[
|
|
379
|
+
console.warn(`[rango] Circular include detected, skipping: ${key}`);
|
|
375
380
|
return { routes: {}, searchSchemas: {} };
|
|
376
381
|
}
|
|
377
382
|
visited.add(key);
|
|
@@ -384,7 +389,9 @@ export function buildCombinedRouteMapWithSearch(
|
|
|
384
389
|
}
|
|
385
390
|
|
|
386
391
|
let block: string;
|
|
387
|
-
if (
|
|
392
|
+
if (inlineBlock) {
|
|
393
|
+
block = inlineBlock;
|
|
394
|
+
} else if (variableName) {
|
|
388
395
|
const extracted = extractUrlsBlockForVariable(source, variableName);
|
|
389
396
|
if (!extracted) return { routes: {}, searchSchemas: {} };
|
|
390
397
|
block = extracted;
|
|
@@ -37,12 +37,15 @@ export function formatRouteEntry(
|
|
|
37
37
|
): string {
|
|
38
38
|
const hasSearch = search && Object.keys(search).length > 0;
|
|
39
39
|
|
|
40
|
+
// JSON.stringify the pattern and search values so backslashes and quotes in a
|
|
41
|
+
// route pattern (e.g. a custom regex constraint) survive interpolation into
|
|
42
|
+
// both the type-level string and the runtime NamedRoutes value.
|
|
40
43
|
if (!hasSearch) {
|
|
41
|
-
return ` ${key}:
|
|
44
|
+
return ` ${key}: ${JSON.stringify(pattern)},`;
|
|
42
45
|
}
|
|
43
46
|
|
|
44
47
|
const searchBody = Object.entries(search!)
|
|
45
|
-
.map(([k, v]) => `${k}:
|
|
48
|
+
.map(([k, v]) => `${k}: ${JSON.stringify(v)}`)
|
|
46
49
|
.join(", ");
|
|
47
|
-
return ` ${key}: { path:
|
|
50
|
+
return ` ${key}: { path: ${JSON.stringify(pattern)}, search: { ${searchBody} } },`;
|
|
48
51
|
}
|
|
@@ -97,7 +97,10 @@ export function writePerModuleRouteTypesForFile(filePath: string): void {
|
|
|
97
97
|
routes = extractRoutesFromSource(source);
|
|
98
98
|
}
|
|
99
99
|
|
|
100
|
-
|
|
100
|
+
// Match .ts/.tsx/.js/.jsx (same as router-processing.ts / router-transform.ts).
|
|
101
|
+
// Without the jsx? branch a .jsx/.js source produced genPath === filePath,
|
|
102
|
+
// overwriting the source file instead of writing a sibling .gen.ts.
|
|
103
|
+
const genPath = filePath.replace(/\.(tsx?|jsx?)$/, ".gen.ts");
|
|
101
104
|
|
|
102
105
|
// When a urls() variable was found but static resolution yields zero
|
|
103
106
|
// routes, write an empty placeholder so generated imports stay
|
|
@@ -106,7 +109,7 @@ export function writePerModuleRouteTypesForFile(filePath: string): void {
|
|
|
106
109
|
if (varNames.length > 0 && !existsSync(genPath)) {
|
|
107
110
|
writeFileSync(genPath, generatePerModuleTypesSource([]));
|
|
108
111
|
console.log(
|
|
109
|
-
`[
|
|
112
|
+
`[rango] Generated route types (placeholder) -> ${genPath}`,
|
|
110
113
|
);
|
|
111
114
|
}
|
|
112
115
|
return;
|
|
@@ -118,11 +121,11 @@ export function writePerModuleRouteTypesForFile(filePath: string): void {
|
|
|
118
121
|
: null;
|
|
119
122
|
if (existing !== genSource) {
|
|
120
123
|
writeFileSync(genPath, genSource);
|
|
121
|
-
console.log(`[
|
|
124
|
+
console.log(`[rango] Generated route types -> ${genPath}`);
|
|
122
125
|
}
|
|
123
126
|
} catch (err) {
|
|
124
127
|
console.warn(
|
|
125
|
-
`[
|
|
128
|
+
`[rango] Failed to generate route types for ${filePath}: ${(err as Error).message}`,
|
|
126
129
|
);
|
|
127
130
|
}
|
|
128
131
|
}
|