@rangojs/router 0.0.0-experimental.b9cb8739 → 0.0.0-experimental.bdaf10aa
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 +8 -4
- package/README.md +303 -741
- package/dist/bin/rango.js +730 -184
- package/dist/testing/vitest.js +82 -0
- package/dist/vite/index.js +4344 -1335
- package/dist/vite/index.js.bak +5448 -0
- package/dist/vite/plugins/cloudflare-protocol-loader-hook.mjs +76 -0
- package/package.json +86 -15
- package/skills/api-client/SKILL.md +211 -0
- package/skills/breadcrumbs/SKILL.md +85 -6
- package/skills/bundle-analysis/SKILL.md +159 -0
- package/skills/cache-guide/SKILL.md +251 -24
- package/skills/caching/SKILL.md +375 -17
- package/skills/catalog.json +271 -0
- package/skills/comparison/SKILL.md +50 -0
- package/skills/comparison/agents/openai.yaml +4 -0
- package/skills/comparison/references/framework-comparison.md +837 -0
- package/skills/composability/SKILL.md +110 -4
- package/skills/css/SKILL.md +76 -0
- package/skills/debug-manifest/SKILL.md +5 -3
- package/skills/defer-hydration/SKILL.md +235 -0
- package/skills/document-cache/SKILL.md +87 -56
- package/skills/fonts/SKILL.md +1 -1
- package/skills/handler-use/SKILL.md +364 -0
- package/skills/hooks/SKILL.md +73 -691
- package/skills/hooks/data.md +273 -0
- package/skills/hooks/handle-and-actions.md +103 -0
- package/skills/hooks/navigation.md +110 -0
- package/skills/hooks/outlets.md +41 -0
- package/skills/hooks/state.md +228 -0
- package/skills/hooks/urls.md +135 -0
- package/skills/host-router/SKILL.md +129 -27
- package/skills/i18n/SKILL.md +276 -0
- package/skills/intercept/SKILL.md +94 -18
- package/skills/layout/SKILL.md +62 -19
- package/skills/links/SKILL.md +249 -17
- package/skills/loader/SKILL.md +302 -54
- package/skills/middleware/SKILL.md +59 -16
- package/skills/migrate-nextjs/SKILL.md +745 -0
- package/skills/migrate-react-router/SKILL.md +153 -0
- package/skills/migrate-react-router/cloudflare-workers.md +129 -0
- package/skills/migrate-react-router/component-migration.md +196 -0
- package/skills/migrate-react-router/data-and-actions.md +225 -0
- package/skills/migrate-react-router/route-mapping.md +271 -0
- package/skills/mime-routes/SKILL.md +29 -2
- package/skills/observability/SKILL.md +202 -0
- package/skills/parallel/SKILL.md +225 -10
- package/skills/ppr/SKILL.md +622 -0
- package/skills/prerender/SKILL.md +178 -124
- package/skills/rango/SKILL.md +318 -24
- package/skills/react-compiler/SKILL.md +168 -0
- package/skills/response-routes/SKILL.md +138 -49
- package/skills/route/SKILL.md +172 -9
- package/skills/router-setup/SKILL.md +131 -11
- package/skills/scripts/SKILL.md +179 -0
- package/skills/server-actions/SKILL.md +776 -0
- package/skills/shell-manifest/SKILL.md +185 -0
- package/skills/streams-and-websockets/SKILL.md +283 -0
- package/skills/tailwind/SKILL.md +28 -4
- package/skills/testing/SKILL.md +130 -0
- package/skills/testing/bindings.md +103 -0
- package/skills/testing/cache-prerender.md +127 -0
- package/skills/testing/client-components.md +124 -0
- package/skills/testing/e2e-parity.md +125 -0
- package/skills/testing/flight.md +91 -0
- package/skills/testing/handles.md +131 -0
- package/skills/testing/loader.md +128 -0
- package/skills/testing/middleware.md +99 -0
- package/skills/testing/render-handler.md +122 -0
- package/skills/testing/response-routes.md +95 -0
- package/skills/testing/reverse-and-types.md +85 -0
- package/skills/testing/server-actions.md +107 -0
- package/skills/testing/server-tree.md +128 -0
- package/skills/testing/setup.md +123 -0
- package/skills/theme/SKILL.md +1 -1
- package/skills/typesafety/SKILL.md +45 -616
- package/skills/typesafety/env-and-bindings.md +254 -0
- package/skills/typesafety/generated-files-and-cli.md +335 -0
- package/skills/typesafety/params-and-search.md +153 -0
- package/skills/typesafety/route-types.md +209 -0
- package/skills/use-cache/SKILL.md +74 -15
- package/skills/vercel/SKILL.md +128 -0
- package/skills/view-transitions/SKILL.md +337 -0
- package/src/__augment-tests__/augment.ts +81 -0
- package/src/__augment-tests__/augmented.check.ts +116 -0
- package/src/__internal.ts +1 -66
- 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/connection-warmup.ts +134 -0
- package/src/browser/cookie-name.ts +140 -0
- package/src/browser/event-controller.ts +257 -158
- 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/logging.ts +28 -0
- package/src/browser/merge-segment-loaders.ts +6 -4
- package/src/browser/navigation-bridge.ts +132 -33
- package/src/browser/navigation-client.ts +218 -68
- package/src/browser/navigation-store-handle.ts +38 -0
- package/src/browser/navigation-store.ts +203 -80
- package/src/browser/navigation-transaction.ts +18 -66
- package/src/browser/network-error-handler.ts +34 -7
- package/src/browser/partial-update.ts +241 -127
- package/src/browser/prefetch/cache.ts +271 -44
- package/src/browser/prefetch/fetch.ts +367 -40
- package/src/browser/prefetch/queue.ts +144 -23
- package/src/browser/prefetch/resource-ready.ts +77 -0
- package/src/browser/rango-state.ts +158 -76
- package/src/browser/react/Link.tsx +121 -16
- package/src/browser/react/NavigationProvider.tsx +240 -122
- package/src/browser/react/ScrollRestoration.tsx +10 -6
- package/src/browser/react/context.ts +7 -2
- package/src/browser/react/filter-segment-order.ts +66 -7
- package/src/browser/react/index.ts +0 -48
- package/src/browser/react/location-state-shared.ts +178 -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-href.tsx +8 -1
- package/src/browser/react/use-link-status.ts +33 -8
- package/src/browser/react/use-navigation.ts +32 -7
- 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 +99 -8
- package/src/browser/rsc-router.tsx +272 -80
- package/src/browser/scroll-restoration.ts +56 -22
- package/src/browser/segment-reconciler.ts +44 -7
- package/src/browser/segment-structure-assert.ts +2 -2
- package/src/browser/server-action-bridge.ts +244 -71
- package/src/browser/types.ts +136 -12
- package/src/browser/validate-redirect-origin.ts +43 -16
- package/src/build/collect-fallback-refs.ts +107 -0
- package/src/build/generate-manifest.ts +207 -158
- package/src/build/generate-route-types.ts +6 -1
- package/src/build/index.ts +11 -3
- package/src/build/prefix-tree-utils.ts +123 -0
- package/src/build/route-trie.ts +198 -41
- package/src/build/route-types/ast-route-extraction.ts +15 -8
- package/src/build/route-types/codegen.ts +16 -5
- package/src/build/route-types/include-resolution.ts +464 -63
- package/src/build/route-types/param-extraction.ts +6 -3
- package/src/build/route-types/per-module-writer.ts +22 -6
- package/src/build/route-types/router-processing.ts +336 -110
- package/src/build/route-types/scan-filter.ts +9 -2
- package/src/build/route-types/source-scan.ts +216 -0
- package/src/build/runtime-discovery.ts +13 -21
- package/src/cache/cache-error.ts +104 -0
- package/src/cache/cache-key-utils.ts +58 -13
- package/src/cache/cache-policy.ts +108 -34
- package/src/cache/cache-runtime.ts +454 -97
- package/src/cache/cache-scope.ts +235 -103
- package/src/cache/cache-tag.ts +149 -0
- package/src/cache/cf/cf-base64.ts +33 -0
- package/src/cache/cf/cf-cache-constants.ts +127 -0
- package/src/cache/cf/cf-cache-store.ts +2446 -170
- package/src/cache/cf/cf-cache-types.ts +349 -0
- package/src/cache/cf/cf-kv-utils.ts +46 -0
- package/src/cache/cf/cf-tag-marker-memo.ts +105 -0
- package/src/cache/cf/index.ts +11 -17
- package/src/cache/document-cache.ts +144 -49
- package/src/cache/handle-snapshot.ts +70 -0
- package/src/cache/index.ts +24 -20
- package/src/cache/memory-segment-store.ts +243 -37
- package/src/cache/profile-registry.ts +46 -31
- package/src/cache/read-through-swr.ts +56 -12
- package/src/cache/segment-codec.ts +13 -21
- package/src/cache/shell-snapshot.ts +417 -0
- package/src/cache/tag-invalidation.ts +230 -0
- package/src/cache/taint.ts +55 -0
- package/src/cache/types.ts +194 -99
- package/src/cache/vercel/index.ts +11 -0
- package/src/cache/vercel/vercel-cache-store.ts +1132 -0
- package/src/client.rsc.tsx +41 -21
- package/src/client.tsx +116 -290
- package/src/cloudflare/index.ts +11 -0
- package/src/cloudflare/tracing.ts +108 -0
- package/src/component-utils.ts +19 -0
- package/src/components/DefaultDocument.tsx +8 -2
- package/src/context-var.ts +84 -2
- package/src/debug.ts +2 -2
- package/src/decode-loader-results.ts +52 -0
- package/src/defer.ts +185 -0
- package/src/deps/ssr.ts +0 -1
- package/src/encode-kv.ts +49 -0
- package/src/errors.ts +30 -4
- package/src/escape-script.ts +52 -0
- package/src/handle.ts +104 -34
- package/src/handles/MetaTags.tsx +24 -53
- package/src/handles/Scripts.tsx +183 -0
- package/src/handles/breadcrumbs.ts +35 -8
- package/src/handles/deferred-resolution.ts +127 -0
- package/src/handles/is-thenable.ts +18 -0
- package/src/handles/meta.ts +14 -40
- package/src/handles/script.ts +244 -0
- package/src/host/cookie-handler.ts +9 -60
- package/src/host/errors.ts +13 -22
- package/src/host/index.ts +9 -2
- package/src/host/pattern-matcher.ts +23 -52
- 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 +100 -13
- package/src/index.ts +143 -19
- package/src/internal-debug.ts +11 -10
- 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/outlet-context.ts +1 -1
- package/src/outlet-provider.tsx +1 -5
- package/src/prerender/param-hash.ts +16 -16
- package/src/prerender/store.ts +37 -41
- package/src/prerender.ts +215 -86
- package/src/redirect-origin.ts +114 -0
- package/src/regex-escape.ts +8 -0
- package/src/render-error-thrower.tsx +20 -0
- package/src/response-utils.ts +62 -0
- package/src/reverse.ts +65 -15
- package/src/root-error-boundary.tsx +1 -19
- package/src/route-content-wrapper.tsx +19 -77
- package/src/route-definition/dsl-helpers.ts +485 -303
- package/src/route-definition/helper-factories.ts +28 -140
- package/src/route-definition/helpers-types.ts +153 -77
- package/src/route-definition/index.ts +4 -2
- package/src/route-definition/redirect.ts +53 -12
- package/src/route-definition/resolve-handler-use.ts +160 -0
- package/src/route-definition/use-item-types.ts +29 -0
- package/src/route-map-builder.ts +48 -21
- package/src/route-types.ts +37 -46
- package/src/router/basename.ts +14 -0
- package/src/router/content-negotiation.ts +164 -17
- package/src/router/error-handling.ts +45 -18
- package/src/router/find-match.ts +130 -29
- package/src/router/handler-context.ts +83 -39
- package/src/router/instrument.ts +355 -0
- package/src/router/intercept-resolution.ts +50 -24
- package/src/router/lazy-includes.ts +89 -63
- package/src/router/loader-resolution.ts +286 -56
- package/src/router/logging.ts +5 -8
- package/src/router/manifest.ts +105 -56
- package/src/router/match-api.ts +178 -218
- package/src/router/match-context.ts +0 -22
- package/src/router/match-handlers.ts +211 -165
- package/src/router/match-middleware/background-revalidation.ts +66 -22
- package/src/router/match-middleware/cache-lookup.ts +214 -263
- package/src/router/match-middleware/cache-store.ts +105 -50
- 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 +128 -44
- package/src/router/metrics.ts +5 -34
- package/src/router/middleware-types.ts +13 -142
- package/src/router/middleware.ts +301 -177
- package/src/router/navigation-snapshot.ts +133 -0
- package/src/router/params-util.ts +23 -0
- package/src/router/parse-pattern.ts +115 -0
- package/src/router/pattern-matching.ts +181 -150
- package/src/router/prefetch-cache-ttl.ts +51 -0
- package/src/router/prefetch-limits.ts +37 -0
- package/src/router/prerender-match.ts +203 -58
- package/src/router/preview-match.ts +35 -103
- package/src/router/request-classification.ts +291 -0
- package/src/router/revalidation.ts +123 -73
- package/src/router/route-snapshot.ts +256 -0
- package/src/router/router-context.ts +11 -29
- package/src/router/router-interfaces.ts +146 -35
- package/src/router/router-options.ts +202 -15
- package/src/router/router-registry.ts +2 -5
- package/src/router/segment-resolution/fresh.ts +301 -78
- package/src/router/segment-resolution/helpers.ts +115 -30
- package/src/router/segment-resolution/loader-cache.ts +156 -39
- package/src/router/segment-resolution/loader-mask.ts +60 -0
- package/src/router/segment-resolution/loader-snapshot.ts +259 -0
- package/src/router/segment-resolution/mask-nested.ts +83 -0
- package/src/router/segment-resolution/revalidation.ts +477 -385
- 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 +56 -0
- package/src/router/segment-resolution.ts +5 -1
- package/src/router/segment-wrappers.ts +8 -5
- package/src/router/state-cookie-name.ts +33 -0
- package/src/router/substitute-pattern-params.ts +75 -0
- package/src/router/telemetry-otel.ts +160 -200
- package/src/router/telemetry.ts +105 -20
- package/src/router/timeout.ts +0 -20
- package/src/router/tracing.ts +215 -0
- package/src/router/trie-matching.ts +171 -59
- package/src/router/types.ts +10 -63
- package/src/router/url-params.ts +57 -0
- package/src/router.ts +210 -71
- package/src/rsc/full-payload.ts +70 -0
- package/src/rsc/handler-context.ts +3 -2
- package/src/rsc/handler.ts +682 -508
- package/src/rsc/helpers.ts +168 -46
- package/src/rsc/index.ts +2 -5
- package/src/rsc/json-route-result.ts +38 -0
- package/src/rsc/loader-fetch.ts +127 -31
- package/src/rsc/manifest-init.ts +33 -42
- package/src/rsc/nonce.ts +10 -1
- package/src/rsc/origin-guard.ts +39 -25
- package/src/rsc/progressive-enhancement.ts +138 -15
- package/src/rsc/redirect-guard.ts +100 -0
- package/src/rsc/response-cache-serve.ts +238 -0
- package/src/rsc/response-error.ts +79 -12
- package/src/rsc/response-route-handler.ts +99 -189
- package/src/rsc/rsc-rendering.ts +509 -73
- package/src/rsc/runtime-warnings.ts +23 -10
- package/src/rsc/server-action.ts +287 -113
- package/src/rsc/shell-capture.ts +1190 -0
- package/src/rsc/shell-serve.ts +181 -0
- package/src/rsc/ssr-setup.ts +18 -2
- package/src/rsc/transition-gate.ts +89 -0
- package/src/rsc/types.ts +62 -6
- package/src/runtime-env.ts +18 -0
- package/src/search-params.ts +35 -30
- package/src/segment-content-promise.ts +67 -0
- package/src/segment-loader-promise.ts +167 -0
- package/src/segment-system.tsx +449 -132
- package/src/serialize.ts +243 -0
- package/src/server/context.ts +367 -61
- package/src/server/cookie-parse.ts +32 -0
- package/src/server/cookie-store.ts +152 -5
- package/src/server/handle-store.ts +40 -38
- package/src/server/loader-registry.ts +38 -46
- package/src/server/request-context.ts +558 -173
- package/src/ssr/index.tsx +491 -174
- package/src/ssr/inject-rsc-eager.ts +167 -0
- package/src/ssr/ssr-root.tsx +228 -0
- package/src/static-handler.ts +27 -18
- package/src/testing/cache-status.ts +162 -0
- package/src/testing/collect-handle.ts +46 -0
- package/src/testing/dispatch.ts +813 -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 +257 -0
- package/src/testing/generated-routes.ts +199 -0
- package/src/testing/index.ts +105 -0
- package/src/testing/internal/context.ts +371 -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 +357 -0
- package/src/testing/render-route.tsx +584 -0
- package/src/testing/run-loader.ts +385 -0
- package/src/testing/run-middleware.ts +205 -0
- package/src/testing/run-transition-when.ts +164 -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 +56 -84
- package/src/theme/ThemeScript.tsx +7 -9
- package/src/theme/constants.ts +52 -13
- package/src/theme/index.ts +0 -7
- package/src/theme/theme-context.ts +1 -5
- package/src/theme/theme-script.ts +22 -21
- 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 +234 -82
- package/src/types/index.ts +3 -10
- package/src/types/loader-types.ts +44 -15
- package/src/types/request-scope.ts +112 -0
- package/src/types/route-config.ts +20 -52
- package/src/types/route-entry.ts +19 -7
- package/src/types/segments.ts +137 -14
- package/src/urls/include-helper.ts +40 -75
- package/src/urls/include-provider.ts +71 -0
- package/src/urls/index.ts +2 -11
- package/src/urls/path-helper-types.ts +102 -23
- package/src/urls/path-helper.ts +62 -111
- package/src/urls/pattern-types.ts +84 -19
- package/src/urls/response-types.ts +25 -22
- package/src/urls/type-extraction.ts +98 -154
- package/src/urls/urls-function.ts +1 -19
- package/src/use-loader.tsx +346 -89
- package/src/vercel/index.ts +11 -0
- package/src/vercel/tracing.ts +88 -0
- package/src/vite/debug.ts +185 -0
- package/src/vite/discovery/bundle-postprocess.ts +36 -38
- package/src/vite/discovery/dev-prerender-cache.ts +117 -0
- package/src/vite/discovery/discover-routers.ts +130 -85
- package/src/vite/discovery/discovery-errors.ts +255 -0
- package/src/vite/discovery/gate-state.ts +171 -0
- package/src/vite/discovery/prerender-collection.ts +214 -132
- 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 +57 -6
- package/src/vite/discovery/virtual-module-codegen.ts +14 -34
- package/src/vite/index.ts +15 -0
- package/src/vite/inject-client-debug.ts +88 -0
- package/src/vite/plugin-types.ts +234 -62
- package/src/vite/plugins/cjs-to-esm.ts +16 -19
- 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 +96 -51
- package/src/vite/plugins/expose-ids/export-analysis.ts +101 -34
- package/src/vite/plugins/expose-ids/handler-transform.ts +15 -64
- package/src/vite/plugins/expose-ids/loader-transform.ts +14 -24
- package/src/vite/plugins/expose-ids/router-transform.ts +118 -29
- package/src/vite/plugins/expose-internal-ids.ts +553 -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 +384 -0
- package/src/vite/plugins/version-injector.ts +40 -29
- package/src/vite/plugins/version-plugin.ts +46 -37
- package/src/vite/plugins/virtual-entries.ts +138 -27
- package/src/vite/rango.ts +353 -303
- package/src/vite/router-discovery.ts +1090 -166
- package/src/vite/utils/ast-handler-extract.ts +26 -35
- 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/directive-prologue.ts +40 -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 +98 -38
- package/src/vite/utils/shared-utils.ts +144 -44
- 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/network-error-thrower.tsx +0 -23
- package/src/router/middleware-cookies.ts +0 -55
|
@@ -15,6 +15,7 @@ import {
|
|
|
15
15
|
import ts from "typescript";
|
|
16
16
|
import { generateRouteTypesSource } from "./codegen.js";
|
|
17
17
|
import type { ScanFilter } from "./scan-filter.js";
|
|
18
|
+
import { firstCodeMatchIndex } from "./source-scan.js";
|
|
18
19
|
import {
|
|
19
20
|
resolveImportedVariable,
|
|
20
21
|
resolveImportPath,
|
|
@@ -38,6 +39,8 @@ function countPublicRouteEntries(source: string): number {
|
|
|
38
39
|
}
|
|
39
40
|
|
|
40
41
|
const ROUTER_CALL_PATTERN = /\bcreateRouter\s*[<(]/;
|
|
42
|
+
// Global variant for the code-region scan (firstCodeMatchIndex sets lastIndex).
|
|
43
|
+
const ROUTER_CALL_PATTERN_G = /\bcreateRouter\s*[<(]/g;
|
|
41
44
|
|
|
42
45
|
function isRoutableSourceFile(name: string): boolean {
|
|
43
46
|
return (
|
|
@@ -45,12 +48,39 @@ function isRoutableSourceFile(name: string): boolean {
|
|
|
45
48
|
name.endsWith(".tsx") ||
|
|
46
49
|
name.endsWith(".js") ||
|
|
47
50
|
name.endsWith(".jsx")) &&
|
|
48
|
-
!name.includes(".gen.")
|
|
51
|
+
!name.includes(".gen.") &&
|
|
52
|
+
!name.includes(".test.") &&
|
|
53
|
+
!name.includes(".spec.")
|
|
49
54
|
);
|
|
50
55
|
}
|
|
51
56
|
|
|
52
|
-
function
|
|
57
|
+
function isExcludedScanDir(name: string): boolean {
|
|
58
|
+
return (
|
|
59
|
+
name === "node_modules" ||
|
|
60
|
+
name === "dist" ||
|
|
61
|
+
name === "coverage" ||
|
|
62
|
+
name === "__tests__" ||
|
|
63
|
+
name === "__mocks__" ||
|
|
64
|
+
name.startsWith(".")
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Recursively collect source files whose code contains `pattern` (a comment- or
|
|
70
|
+
* string-only mention is ignored via firstCodeMatchIndex). Shared by createRouter
|
|
71
|
+
* and createHostRouter discovery, which differ only in the call pattern and
|
|
72
|
+
* `stopAtMatchDir`: createRouter treats a directory containing a match as a router
|
|
73
|
+
* root and stops descending it; createHostRouter descends the whole tree (the host
|
|
74
|
+
* entry sits above the sub-app router roots).
|
|
75
|
+
*
|
|
76
|
+
* `pattern` is the non-global tester (no lastIndex state); `patternG` is its global
|
|
77
|
+
* twin for the code-region scan.
|
|
78
|
+
*/
|
|
79
|
+
function findCallSiteFilesRecursive(
|
|
53
80
|
dir: string,
|
|
81
|
+
pattern: RegExp,
|
|
82
|
+
patternG: RegExp,
|
|
83
|
+
stopAtMatchDir: boolean,
|
|
54
84
|
filter: ScanFilter | undefined,
|
|
55
85
|
results: string[],
|
|
56
86
|
): void {
|
|
@@ -59,19 +89,18 @@ function findRouterFilesRecursive(
|
|
|
59
89
|
entries = readdirSync(dir, { withFileTypes: true });
|
|
60
90
|
} catch (err) {
|
|
61
91
|
console.warn(
|
|
62
|
-
`[
|
|
92
|
+
`[rango] Failed to scan directory ${dir}: ${(err as Error).message}`,
|
|
63
93
|
);
|
|
64
94
|
return;
|
|
65
95
|
}
|
|
66
96
|
|
|
67
97
|
const childDirs: string[] = [];
|
|
68
|
-
const
|
|
98
|
+
const matchesInDir: string[] = [];
|
|
69
99
|
|
|
70
100
|
for (const entry of entries) {
|
|
71
101
|
const fullPath = join(dir, entry.name);
|
|
72
102
|
if (entry.isDirectory()) {
|
|
73
|
-
if (entry.name
|
|
74
|
-
childDirs.push(fullPath);
|
|
103
|
+
if (!isExcludedScanDir(entry.name)) childDirs.push(fullPath);
|
|
75
104
|
continue;
|
|
76
105
|
}
|
|
77
106
|
|
|
@@ -80,23 +109,36 @@ function findRouterFilesRecursive(
|
|
|
80
109
|
|
|
81
110
|
try {
|
|
82
111
|
const source = readFileSync(fullPath, "utf-8");
|
|
83
|
-
|
|
84
|
-
|
|
112
|
+
// Fast path: most files contain no `createRouter(` at all, so the cheap
|
|
113
|
+
// raw regex short-circuits before the code-region scan. Only a file that
|
|
114
|
+
// mentions the token (real call OR a comment/string mention) is rescanned
|
|
115
|
+
// over code regions — allocation-free, never building a stripped copy —
|
|
116
|
+
// so a mention inside a comment or string is not mistaken for a real
|
|
117
|
+
// router file (which previously triggered a spurious "Multiple routers
|
|
118
|
+
// found" error).
|
|
119
|
+
if (pattern.test(source) && firstCodeMatchIndex(source, patternG) >= 0) {
|
|
120
|
+
matchesInDir.push(fullPath);
|
|
85
121
|
}
|
|
86
122
|
} catch {
|
|
87
123
|
continue;
|
|
88
124
|
}
|
|
89
125
|
}
|
|
90
126
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
127
|
+
results.push(...matchesInDir);
|
|
128
|
+
|
|
129
|
+
// createRouter (stopAtMatchDir): a directory that contains a match is a router
|
|
130
|
+
// root, so deeper directories are skipped. createHostRouter: always descend.
|
|
131
|
+
if (!stopAtMatchDir || matchesInDir.length === 0) {
|
|
132
|
+
for (const childDir of childDirs) {
|
|
133
|
+
findCallSiteFilesRecursive(
|
|
134
|
+
childDir,
|
|
135
|
+
pattern,
|
|
136
|
+
patternG,
|
|
137
|
+
stopAtMatchDir,
|
|
138
|
+
filter,
|
|
139
|
+
results,
|
|
140
|
+
);
|
|
141
|
+
}
|
|
100
142
|
}
|
|
101
143
|
}
|
|
102
144
|
|
|
@@ -132,7 +174,7 @@ export function findNestedRouterConflict(
|
|
|
132
174
|
|
|
133
175
|
export function formatNestedRouterConflictError(
|
|
134
176
|
conflict: { ancestor: string; nested: string },
|
|
135
|
-
prefix = "[
|
|
177
|
+
prefix = "[rango]",
|
|
136
178
|
): string {
|
|
137
179
|
return (
|
|
138
180
|
`${prefix} Nested router roots are not supported.\n` +
|
|
@@ -147,13 +189,26 @@ export function formatNestedRouterConflictError(
|
|
|
147
189
|
// ---------------------------------------------------------------------------
|
|
148
190
|
|
|
149
191
|
/**
|
|
150
|
-
*
|
|
151
|
-
*
|
|
192
|
+
* Result of extracting URL patterns from a router file.
|
|
193
|
+
* - "variable": a named variable reference (e.g., `.routes(patterns)` or `urls: patterns`)
|
|
194
|
+
* - "inline": an inline builder function (e.g., `.routes(({ path }) => [...])` or `urls: ({ path }) => [...]`)
|
|
195
|
+
*/
|
|
196
|
+
export type UrlsExtractionResult =
|
|
197
|
+
| { kind: "variable"; name: string }
|
|
198
|
+
| { kind: "inline"; block: string };
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Extract the url patterns from a router file using AST.
|
|
202
|
+
* Detects four patterns:
|
|
152
203
|
* 1. createRouter(...).routes(variableName)
|
|
153
204
|
* 2. createRouter({ urls: variableName, ... })
|
|
154
|
-
*
|
|
205
|
+
* 3. createRouter(...).routes(({ path, ... }) => [...])
|
|
206
|
+
* 4. createRouter({ urls: ({ path, ... }) => [...], ... })
|
|
207
|
+
* Returns either a variable name or an inline code block.
|
|
155
208
|
*/
|
|
156
|
-
export function
|
|
209
|
+
export function extractUrlsFromRouter(
|
|
210
|
+
code: string,
|
|
211
|
+
): UrlsExtractionResult | null {
|
|
157
212
|
const sourceFile = ts.createSourceFile(
|
|
158
213
|
"router.tsx",
|
|
159
214
|
code,
|
|
@@ -161,7 +216,7 @@ export function extractUrlsVariableFromRouter(code: string): string | null {
|
|
|
161
216
|
true,
|
|
162
217
|
ts.ScriptKind.TSX,
|
|
163
218
|
);
|
|
164
|
-
let result:
|
|
219
|
+
let result: UrlsExtractionResult | null = null;
|
|
165
220
|
|
|
166
221
|
function isCreateRouterCall(node: ts.Node): boolean {
|
|
167
222
|
if (!ts.isCallExpression(node)) return false;
|
|
@@ -169,44 +224,108 @@ export function extractUrlsVariableFromRouter(code: string): string | null {
|
|
|
169
224
|
return ts.isIdentifier(callee) && callee.text === "createRouter";
|
|
170
225
|
}
|
|
171
226
|
|
|
227
|
+
/** Check if a node is an arrow/function expression (inline builder). */
|
|
228
|
+
function isInlineBuilder(node: ts.Node): boolean {
|
|
229
|
+
return ts.isArrowFunction(node) || ts.isFunctionExpression(node);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/** Check if a .routes() call chains from createRouter(). */
|
|
233
|
+
function isRoutesOnCreateRouter(node: ts.CallExpression): boolean {
|
|
234
|
+
if (
|
|
235
|
+
!ts.isPropertyAccessExpression(node.expression) ||
|
|
236
|
+
node.expression.name.text !== "routes"
|
|
237
|
+
)
|
|
238
|
+
return false;
|
|
239
|
+
let inner: ts.Expression = node.expression.expression;
|
|
240
|
+
while (
|
|
241
|
+
ts.isCallExpression(inner) &&
|
|
242
|
+
ts.isPropertyAccessExpression(inner.expression)
|
|
243
|
+
) {
|
|
244
|
+
inner = inner.expression.expression;
|
|
245
|
+
}
|
|
246
|
+
return isCreateRouterCall(inner);
|
|
247
|
+
}
|
|
248
|
+
|
|
172
249
|
function visit(node: ts.Node) {
|
|
173
250
|
if (result) return;
|
|
174
251
|
|
|
175
|
-
// Pattern 1: createRouter(...).routes(variableName)
|
|
176
|
-
// The AST shape is CallExpression(.routes) -> PropertyAccessExpression -> CallExpression(createRouter)
|
|
252
|
+
// Pattern 1 & 3: createRouter(...).routes(variableName | builder)
|
|
177
253
|
if (
|
|
178
254
|
ts.isCallExpression(node) &&
|
|
179
|
-
ts.isPropertyAccessExpression(node.expression) &&
|
|
180
|
-
node.expression.name.text === "routes" &&
|
|
181
255
|
node.arguments.length >= 1 &&
|
|
182
|
-
|
|
256
|
+
isRoutesOnCreateRouter(node)
|
|
183
257
|
) {
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
ts.isPropertyAccessExpression(inner.expression)
|
|
190
|
-
) {
|
|
191
|
-
inner = inner.expression.expression;
|
|
192
|
-
}
|
|
193
|
-
if (isCreateRouterCall(inner)) {
|
|
194
|
-
result = (node.arguments[0] as ts.Identifier).text;
|
|
195
|
-
return;
|
|
258
|
+
const arg = node.arguments[0];
|
|
259
|
+
if (ts.isIdentifier(arg)) {
|
|
260
|
+
result = { kind: "variable", name: arg.text };
|
|
261
|
+
} else if (isInlineBuilder(arg)) {
|
|
262
|
+
result = { kind: "inline", block: arg.getText(sourceFile) };
|
|
196
263
|
}
|
|
264
|
+
return;
|
|
197
265
|
}
|
|
198
266
|
|
|
199
|
-
// Pattern 2: createRouter({ urls: variableName, ... })
|
|
267
|
+
// Pattern 2 & 4: createRouter({ urls: variableName | builder, ... })
|
|
200
268
|
if (isCreateRouterCall(node)) {
|
|
201
269
|
const callExpr = node as ts.CallExpression;
|
|
202
|
-
for (const
|
|
270
|
+
for (const callArg of callExpr.arguments) {
|
|
271
|
+
if (ts.isObjectLiteralExpression(callArg)) {
|
|
272
|
+
for (const prop of callArg.properties) {
|
|
273
|
+
if (
|
|
274
|
+
ts.isPropertyAssignment(prop) &&
|
|
275
|
+
ts.isIdentifier(prop.name) &&
|
|
276
|
+
prop.name.text === "urls"
|
|
277
|
+
) {
|
|
278
|
+
if (ts.isIdentifier(prop.initializer)) {
|
|
279
|
+
result = { kind: "variable", name: prop.initializer.text };
|
|
280
|
+
} else if (isInlineBuilder(prop.initializer)) {
|
|
281
|
+
result = {
|
|
282
|
+
kind: "inline",
|
|
283
|
+
block: prop.initializer.getText(sourceFile),
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
return;
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
ts.forEachChild(node, visit);
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
visit(sourceFile);
|
|
297
|
+
return result;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
/**
|
|
301
|
+
* Extract the `basename` string literal from createRouter({ basename: "..." }).
|
|
302
|
+
* Returns the basename value or undefined if not present.
|
|
303
|
+
*/
|
|
304
|
+
export function extractBasenameFromRouter(code: string): string | undefined {
|
|
305
|
+
const sourceFile = ts.createSourceFile(
|
|
306
|
+
"router.tsx",
|
|
307
|
+
code,
|
|
308
|
+
ts.ScriptTarget.Latest,
|
|
309
|
+
true,
|
|
310
|
+
ts.ScriptKind.TSX,
|
|
311
|
+
);
|
|
312
|
+
let result: string | undefined;
|
|
313
|
+
|
|
314
|
+
function visit(node: ts.Node) {
|
|
315
|
+
if (result !== undefined) return;
|
|
316
|
+
if (
|
|
317
|
+
ts.isCallExpression(node) &&
|
|
318
|
+
ts.isIdentifier(node.expression) &&
|
|
319
|
+
node.expression.text === "createRouter"
|
|
320
|
+
) {
|
|
321
|
+
for (const arg of node.arguments) {
|
|
203
322
|
if (ts.isObjectLiteralExpression(arg)) {
|
|
204
323
|
for (const prop of arg.properties) {
|
|
205
324
|
if (
|
|
206
325
|
ts.isPropertyAssignment(prop) &&
|
|
207
326
|
ts.isIdentifier(prop.name) &&
|
|
208
|
-
prop.name.text === "
|
|
209
|
-
ts.
|
|
327
|
+
prop.name.text === "basename" &&
|
|
328
|
+
ts.isStringLiteral(prop.initializer)
|
|
210
329
|
) {
|
|
211
330
|
result = prop.initializer.text;
|
|
212
331
|
return;
|
|
@@ -215,7 +334,6 @@ export function extractUrlsVariableFromRouter(code: string): string | null {
|
|
|
215
334
|
}
|
|
216
335
|
}
|
|
217
336
|
}
|
|
218
|
-
|
|
219
337
|
ts.forEachChild(node, visit);
|
|
220
338
|
}
|
|
221
339
|
|
|
@@ -223,9 +341,64 @@ export function extractUrlsVariableFromRouter(code: string): string | null {
|
|
|
223
341
|
return result;
|
|
224
342
|
}
|
|
225
343
|
|
|
344
|
+
/** Apply a basename prefix to all route patterns in a result set. */
|
|
345
|
+
function applyBasenameToRoutes(
|
|
346
|
+
result: {
|
|
347
|
+
routes: Record<string, string>;
|
|
348
|
+
searchSchemas: Record<string, Record<string, string>>;
|
|
349
|
+
},
|
|
350
|
+
basename: string,
|
|
351
|
+
): {
|
|
352
|
+
routes: Record<string, string>;
|
|
353
|
+
searchSchemas: Record<string, Record<string, string>>;
|
|
354
|
+
} {
|
|
355
|
+
const prefixed: Record<string, string> = {};
|
|
356
|
+
for (const [name, pattern] of Object.entries(result.routes)) {
|
|
357
|
+
if (pattern === "/") {
|
|
358
|
+
prefixed[name] = basename;
|
|
359
|
+
} else if (basename.endsWith("/") && pattern.startsWith("/")) {
|
|
360
|
+
prefixed[name] = basename + pattern.slice(1);
|
|
361
|
+
} else {
|
|
362
|
+
prefixed[name] = basename + pattern;
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
return { routes: prefixed, searchSchemas: result.searchSchemas };
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
// Filesystem path of the generated route-types file for a router source file.
|
|
369
|
+
// Native separators — matches the self-gen-tracking Map key the watcher compares.
|
|
370
|
+
export function genFileTsPath(sourceFile: string): string {
|
|
371
|
+
const base = pathBasename(sourceFile).replace(/\.(tsx?|jsx?)$/, "");
|
|
372
|
+
return join(dirname(sourceFile), `${base}.named-routes.gen.ts`);
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
// Search schemas for the gen file: prefer the runtime manifest's; when it omits
|
|
376
|
+
// them (some module-runner flows) fall back to static parsing filtered to the
|
|
377
|
+
// public route-name set. Returns the runtime value unchanged otherwise.
|
|
378
|
+
export function resolveSearchSchemas(
|
|
379
|
+
publicRouteNames: string[],
|
|
380
|
+
runtimeSchemas: Record<string, Record<string, string>> | undefined,
|
|
381
|
+
sourceFile: string,
|
|
382
|
+
): Record<string, Record<string, string>> | undefined {
|
|
383
|
+
if (runtimeSchemas && Object.keys(runtimeSchemas).length > 0) {
|
|
384
|
+
return runtimeSchemas;
|
|
385
|
+
}
|
|
386
|
+
const staticParsed = buildCombinedRouteMapForRouterFile(sourceFile);
|
|
387
|
+
if (Object.keys(staticParsed.searchSchemas).length === 0) {
|
|
388
|
+
return runtimeSchemas;
|
|
389
|
+
}
|
|
390
|
+
const filtered: Record<string, Record<string, string>> = {};
|
|
391
|
+
for (const name of publicRouteNames) {
|
|
392
|
+
const schema = staticParsed.searchSchemas[name];
|
|
393
|
+
if (schema) filtered[name] = schema;
|
|
394
|
+
}
|
|
395
|
+
return Object.keys(filtered).length > 0 ? filtered : runtimeSchemas;
|
|
396
|
+
}
|
|
397
|
+
|
|
226
398
|
/**
|
|
227
399
|
* Resolve routes and search schemas from a router source file by following the
|
|
228
|
-
* variable passed to `.routes(...)` or `urls: ...` in createRouter options
|
|
400
|
+
* variable passed to `.routes(...)` or `urls: ...` in createRouter options,
|
|
401
|
+
* or by parsing an inline builder function directly.
|
|
229
402
|
*/
|
|
230
403
|
export function buildCombinedRouteMapForRouterFile(routerFilePath: string): {
|
|
231
404
|
routes: Record<string, string>;
|
|
@@ -238,21 +411,54 @@ export function buildCombinedRouteMapForRouterFile(routerFilePath: string): {
|
|
|
238
411
|
return { routes: {}, searchSchemas: {} };
|
|
239
412
|
}
|
|
240
413
|
|
|
241
|
-
const
|
|
242
|
-
if (!
|
|
414
|
+
const extraction = extractUrlsFromRouter(routerSource);
|
|
415
|
+
if (!extraction) {
|
|
243
416
|
return { routes: {}, searchSchemas: {} };
|
|
244
417
|
}
|
|
245
418
|
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
419
|
+
// Detect basename from createRouter({ basename: "..." })
|
|
420
|
+
const rawBasename = extractBasenameFromRouter(routerSource);
|
|
421
|
+
const basename = rawBasename
|
|
422
|
+
? ("/" + rawBasename.replace(/^\/+|\/+$/g, "")).replace(/^\/$/, "")
|
|
423
|
+
: undefined;
|
|
424
|
+
|
|
425
|
+
let result: {
|
|
426
|
+
routes: Record<string, string>;
|
|
427
|
+
searchSchemas: Record<string, Record<string, string>>;
|
|
428
|
+
};
|
|
429
|
+
|
|
430
|
+
// Inline builder: extract routes directly from the function body
|
|
431
|
+
if (extraction.kind === "inline") {
|
|
432
|
+
result = buildCombinedRouteMapWithSearch(
|
|
433
|
+
routerFilePath,
|
|
434
|
+
undefined,
|
|
435
|
+
undefined,
|
|
436
|
+
undefined,
|
|
437
|
+
extraction.block,
|
|
438
|
+
);
|
|
439
|
+
} else {
|
|
440
|
+
// Variable reference: follow imports or same-file declaration
|
|
441
|
+
const imported = resolveImportedVariable(routerSource, extraction.name);
|
|
442
|
+
if (imported) {
|
|
443
|
+
const targetFile = resolveImportPath(imported.specifier, routerFilePath);
|
|
444
|
+
if (!targetFile) {
|
|
445
|
+
return { routes: {}, searchSchemas: {} };
|
|
446
|
+
}
|
|
447
|
+
result = buildCombinedRouteMapWithSearch(
|
|
448
|
+
targetFile,
|
|
449
|
+
imported.exportedName,
|
|
450
|
+
);
|
|
451
|
+
} else {
|
|
452
|
+
result = buildCombinedRouteMapWithSearch(routerFilePath, extraction.name);
|
|
251
453
|
}
|
|
252
|
-
return buildCombinedRouteMapWithSearch(targetFile, imported.exportedName);
|
|
253
454
|
}
|
|
254
455
|
|
|
255
|
-
|
|
456
|
+
// Apply basename prefix to all extracted route patterns
|
|
457
|
+
if (basename) {
|
|
458
|
+
result = applyBasenameToRoutes(result, basename);
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
return result;
|
|
256
462
|
}
|
|
257
463
|
|
|
258
464
|
// ---------------------------------------------------------------------------
|
|
@@ -275,12 +481,26 @@ export function detectUnresolvableIncludes(
|
|
|
275
481
|
return [];
|
|
276
482
|
}
|
|
277
483
|
|
|
278
|
-
// Extract the urls
|
|
279
|
-
const
|
|
280
|
-
if (!
|
|
484
|
+
// Extract the urls source from the router file
|
|
485
|
+
const extraction = extractUrlsFromRouter(source);
|
|
486
|
+
if (!extraction) return [];
|
|
487
|
+
|
|
488
|
+
const diagnostics: UnresolvableInclude[] = [];
|
|
281
489
|
|
|
282
|
-
|
|
283
|
-
|
|
490
|
+
if (extraction.kind === "inline") {
|
|
491
|
+
// Inline builder: parse directly
|
|
492
|
+
buildCombinedRouteMapWithSearch(
|
|
493
|
+
realPath,
|
|
494
|
+
undefined,
|
|
495
|
+
new Set(),
|
|
496
|
+
diagnostics,
|
|
497
|
+
extraction.block,
|
|
498
|
+
);
|
|
499
|
+
return diagnostics;
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
// Variable reference: resolve where it comes from
|
|
503
|
+
const imported = resolveImportedVariable(source, extraction.name);
|
|
284
504
|
let targetFile: string;
|
|
285
505
|
let exportedName: string | undefined;
|
|
286
506
|
|
|
@@ -302,10 +522,9 @@ export function detectUnresolvableIncludes(
|
|
|
302
522
|
} else {
|
|
303
523
|
// Same-file urls() definition
|
|
304
524
|
targetFile = realPath;
|
|
305
|
-
exportedName =
|
|
525
|
+
exportedName = extraction.name;
|
|
306
526
|
}
|
|
307
527
|
|
|
308
|
-
const diagnostics: UnresolvableInclude[] = [];
|
|
309
528
|
buildCombinedRouteMapWithSearch(
|
|
310
529
|
targetFile,
|
|
311
530
|
exportedName,
|
|
@@ -352,7 +571,38 @@ export function detectUnresolvableIncludesForUrlsFile(
|
|
|
352
571
|
*/
|
|
353
572
|
export function findRouterFiles(root: string, filter?: ScanFilter): string[] {
|
|
354
573
|
const result: string[] = [];
|
|
355
|
-
|
|
574
|
+
findCallSiteFilesRecursive(
|
|
575
|
+
root,
|
|
576
|
+
ROUTER_CALL_PATTERN,
|
|
577
|
+
ROUTER_CALL_PATTERN_G,
|
|
578
|
+
true,
|
|
579
|
+
filter,
|
|
580
|
+
result,
|
|
581
|
+
);
|
|
582
|
+
return result;
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
const HOST_ROUTER_CALL_PATTERN = /\bcreateHostRouter\s*[<(]/;
|
|
586
|
+
const HOST_ROUTER_CALL_PATTERN_G = /\bcreateHostRouter\s*[<(]/g;
|
|
587
|
+
|
|
588
|
+
/**
|
|
589
|
+
* Scan for files containing createHostRouter() and return their paths. Unlike
|
|
590
|
+
* findRouterFiles, this does NOT stop at the first router-root directory -- a host
|
|
591
|
+
* entry typically sits above the sub-app router roots, so the whole tree is scanned.
|
|
592
|
+
*/
|
|
593
|
+
export function findHostRouterFiles(
|
|
594
|
+
root: string,
|
|
595
|
+
filter?: ScanFilter,
|
|
596
|
+
): string[] {
|
|
597
|
+
const result: string[] = [];
|
|
598
|
+
findCallSiteFilesRecursive(
|
|
599
|
+
root,
|
|
600
|
+
HOST_ROUTER_CALL_PATTERN,
|
|
601
|
+
HOST_ROUTER_CALL_PATTERN_G,
|
|
602
|
+
false,
|
|
603
|
+
filter,
|
|
604
|
+
result,
|
|
605
|
+
);
|
|
356
606
|
return result;
|
|
357
607
|
}
|
|
358
608
|
|
|
@@ -365,7 +615,10 @@ export function findRouterFiles(root: string, filter?: ScanFilter): string[] {
|
|
|
365
615
|
export function writeCombinedRouteTypes(
|
|
366
616
|
root: string,
|
|
367
617
|
knownRouterFiles?: string[],
|
|
368
|
-
opts?: {
|
|
618
|
+
opts?: {
|
|
619
|
+
preserveIfLarger?: boolean;
|
|
620
|
+
onWrite?: (outPath: string, content: string) => void;
|
|
621
|
+
},
|
|
369
622
|
): void {
|
|
370
623
|
// Delete old combined named-routes.gen.ts if it exists (stale from older versions)
|
|
371
624
|
try {
|
|
@@ -373,7 +626,7 @@ export function writeCombinedRouteTypes(
|
|
|
373
626
|
if (existsSync(oldCombinedPath)) {
|
|
374
627
|
unlinkSync(oldCombinedPath);
|
|
375
628
|
console.log(
|
|
376
|
-
`[
|
|
629
|
+
`[rango] Removed stale combined route types: ${oldCombinedPath}`,
|
|
377
630
|
);
|
|
378
631
|
}
|
|
379
632
|
} catch {}
|
|
@@ -387,54 +640,31 @@ export function writeCombinedRouteTypes(
|
|
|
387
640
|
}
|
|
388
641
|
|
|
389
642
|
for (const routerFilePath of routerFilePaths) {
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
};
|
|
405
|
-
|
|
406
|
-
const imported = resolveImportedVariable(routerSource, urlsVarName);
|
|
407
|
-
if (imported) {
|
|
408
|
-
// Variable is imported from another module
|
|
409
|
-
const targetFile = resolveImportPath(imported.specifier, routerFilePath);
|
|
410
|
-
if (!targetFile) continue;
|
|
411
|
-
result = buildCombinedRouteMapWithSearch(
|
|
412
|
-
targetFile,
|
|
413
|
-
imported.exportedName,
|
|
414
|
-
);
|
|
415
|
-
} else {
|
|
416
|
-
// Variable is defined in the same file
|
|
417
|
-
result = buildCombinedRouteMapWithSearch(routerFilePath, urlsVarName);
|
|
643
|
+
const result = buildCombinedRouteMapForRouterFile(routerFilePath);
|
|
644
|
+
if (
|
|
645
|
+
Object.keys(result.routes).length === 0 &&
|
|
646
|
+
Object.keys(result.searchSchemas).length === 0
|
|
647
|
+
) {
|
|
648
|
+
// Check if the file even has a createRouter call — if not, skip entirely.
|
|
649
|
+
// If it does, fall through to write an empty placeholder below.
|
|
650
|
+
let routerSource: string;
|
|
651
|
+
try {
|
|
652
|
+
routerSource = readFileSync(routerFilePath, "utf-8");
|
|
653
|
+
} catch {
|
|
654
|
+
continue;
|
|
655
|
+
}
|
|
656
|
+
if (!extractUrlsFromRouter(routerSource)) continue;
|
|
418
657
|
}
|
|
419
658
|
|
|
420
|
-
const
|
|
421
|
-
/\.(tsx?|jsx?)$/,
|
|
422
|
-
"",
|
|
423
|
-
);
|
|
424
|
-
const outPath = join(
|
|
425
|
-
dirname(routerFilePath),
|
|
426
|
-
`${routerBasename}.named-routes.gen.ts`,
|
|
427
|
-
);
|
|
659
|
+
const outPath = genFileTsPath(routerFilePath);
|
|
428
660
|
const existing = existsSync(outPath)
|
|
429
661
|
? readFileSync(outPath, "utf-8")
|
|
430
662
|
: null;
|
|
431
663
|
|
|
432
|
-
// When the static parser can't extract routes (e.g. callback-style urls()),
|
|
433
|
-
// write an empty placeholder so the build-time transform's injected import
|
|
434
|
-
// resolves. Runtime discovery will overwrite this with the real routes.
|
|
435
664
|
if (Object.keys(result.routes).length === 0) {
|
|
436
665
|
if (!existing) {
|
|
437
666
|
const emptySource = generateRouteTypesSource({});
|
|
667
|
+
opts?.onWrite?.(outPath, emptySource);
|
|
438
668
|
writeFileSync(outPath, emptySource);
|
|
439
669
|
}
|
|
440
670
|
continue;
|
|
@@ -446,11 +676,6 @@ export function writeCombinedRouteTypes(
|
|
|
446
676
|
hasSearchSchemas ? result.searchSchemas : undefined,
|
|
447
677
|
);
|
|
448
678
|
if (existing !== source) {
|
|
449
|
-
// On initial dev startup, don't overwrite a file from runtime discovery
|
|
450
|
-
// (which has all dynamic routes) with a smaller set from the static
|
|
451
|
-
// parser. The static parser can't see routes generated by Array.from()
|
|
452
|
-
// or other dynamic code. During HMR (file watcher), always write so
|
|
453
|
-
// newly added routes appear immediately.
|
|
454
679
|
if (opts?.preserveIfLarger && existing) {
|
|
455
680
|
const existingCount = countPublicRouteEntries(existing);
|
|
456
681
|
const newCount = Object.keys(result.routes).filter(
|
|
@@ -460,9 +685,10 @@ export function writeCombinedRouteTypes(
|
|
|
460
685
|
continue;
|
|
461
686
|
}
|
|
462
687
|
}
|
|
688
|
+
opts?.onWrite?.(outPath, source);
|
|
463
689
|
writeFileSync(outPath, source);
|
|
464
690
|
console.log(
|
|
465
|
-
`[
|
|
691
|
+
`[rango] Generated route types (${Object.keys(result.routes).length} routes) -> ${outPath}`,
|
|
466
692
|
);
|
|
467
693
|
}
|
|
468
694
|
}
|
|
@@ -54,14 +54,21 @@ export function findTsFiles(dir: string, filter?: ScanFilter): string[] {
|
|
|
54
54
|
entries = readdirSync(dir, { withFileTypes: true });
|
|
55
55
|
} catch (err) {
|
|
56
56
|
console.warn(
|
|
57
|
-
`[
|
|
57
|
+
`[rango] Failed to scan directory ${dir}: ${(err as Error).message}`,
|
|
58
58
|
);
|
|
59
59
|
return results;
|
|
60
60
|
}
|
|
61
61
|
for (const entry of entries) {
|
|
62
62
|
const fullPath = join(dir, entry.name);
|
|
63
63
|
if (entry.isDirectory()) {
|
|
64
|
-
if (
|
|
64
|
+
if (
|
|
65
|
+
entry.name === "node_modules" ||
|
|
66
|
+
entry.name.startsWith(".") ||
|
|
67
|
+
entry.name === "dist" ||
|
|
68
|
+
entry.name === "build" ||
|
|
69
|
+
entry.name === "coverage"
|
|
70
|
+
)
|
|
71
|
+
continue;
|
|
65
72
|
results.push(...findTsFiles(fullPath, filter));
|
|
66
73
|
} else if (
|
|
67
74
|
(entry.name.endsWith(".ts") ||
|