@rangojs/router 0.0.0-experimental.9c9afef3 → 0.0.0-experimental.a014d2b7
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 -0
- package/README.md +245 -49
- package/dist/bin/rango.js +440 -133
- package/dist/testing/vitest.js +82 -0
- package/dist/vite/index.js +3373 -1176
- package/dist/vite/index.js.bak +5448 -0
- package/dist/vite/plugins/cloudflare-protocol-loader-hook.mjs +76 -0
- package/package.json +68 -14
- package/skills/api-client/SKILL.md +211 -0
- package/skills/breadcrumbs/SKILL.md +64 -2
- package/skills/bundle-analysis/SKILL.md +159 -0
- package/skills/cache-guide/SKILL.md +224 -32
- package/skills/caching/SKILL.md +279 -17
- package/skills/composability/SKILL.md +27 -3
- package/skills/css/SKILL.md +76 -0
- package/skills/debug-manifest/SKILL.md +4 -2
- package/skills/document-cache/SKILL.md +78 -55
- package/skills/handler-use/SKILL.md +364 -0
- package/skills/hooks/SKILL.md +250 -30
- package/skills/host-router/SKILL.md +83 -23
- package/skills/i18n/SKILL.md +276 -0
- package/skills/intercept/SKILL.md +87 -18
- package/skills/layout/SKILL.md +35 -9
- package/skills/links/SKILL.md +249 -17
- package/skills/loader/SKILL.md +235 -9
- package/skills/middleware/SKILL.md +52 -13
- package/skills/migrate-nextjs/SKILL.md +584 -0
- package/skills/migrate-react-router/SKILL.md +771 -0
- package/skills/mime-routes/SKILL.md +28 -1
- package/skills/observability/SKILL.md +172 -0
- package/skills/parallel/SKILL.md +77 -7
- package/skills/prerender/SKILL.md +172 -125
- package/skills/rango/SKILL.md +251 -22
- package/skills/react-compiler/SKILL.md +168 -0
- package/skills/response-routes/SKILL.md +123 -48
- package/skills/route/SKILL.md +70 -5
- package/skills/router-setup/SKILL.md +65 -8
- package/skills/scripts/SKILL.md +179 -0
- 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 +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 +129 -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 +84 -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/typesafety/SKILL.md +322 -29
- package/skills/use-cache/SKILL.md +57 -14
- 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 +192 -150
- 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/navigation-bridge.ts +131 -30
- package/src/browser/navigation-client.ts +186 -100
- package/src/browser/navigation-store-handle.ts +38 -0
- package/src/browser/navigation-store.ts +157 -74
- package/src/browser/navigation-transaction.ts +9 -59
- package/src/browser/network-error-handler.ts +34 -7
- package/src/browser/partial-update.ts +165 -112
- package/src/browser/prefetch/cache.ts +205 -62
- package/src/browser/prefetch/fetch.ts +347 -39
- package/src/browser/prefetch/queue.ts +42 -8
- package/src/browser/rango-state.ts +158 -76
- package/src/browser/react/Link.tsx +102 -15
- package/src/browser/react/NavigationProvider.tsx +295 -119
- package/src/browser/react/ScrollRestoration.tsx +10 -6
- package/src/browser/react/context.ts +7 -2
- package/src/browser/react/deferred-handle-resolution.ts +75 -0
- 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 +114 -24
- package/src/browser/scroll-restoration.ts +37 -22
- package/src/browser/segment-reconciler.ts +36 -14
- package/src/browser/segment-structure-assert.ts +2 -2
- package/src/browser/server-action-bridge.ts +222 -72
- package/src/browser/types.ts +102 -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 +65 -40
- package/src/build/generate-route-types.ts +5 -1
- package/src/build/index.ts +8 -2
- package/src/build/prefix-tree-utils.ts +123 -0
- package/src/build/route-trie.ts +165 -36
- 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 +125 -24
- 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 +260 -94
- 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 +9 -20
- package/src/cache/cache-error.ts +104 -0
- package/src/cache/cache-key-utils.ts +29 -13
- package/src/cache/cache-policy.ts +108 -34
- package/src/cache/cache-runtime.ts +224 -41
- package/src/cache/cache-scope.ts +188 -82
- package/src/cache/cache-tag.ts +103 -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 +1989 -378
- 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 +6 -16
- package/src/cache/document-cache.ts +89 -21
- package/src/cache/handle-snapshot.ts +70 -0
- package/src/cache/index.ts +10 -20
- package/src/cache/memory-segment-store.ts +136 -37
- package/src/cache/profile-registry.ts +46 -31
- package/src/cache/read-through-swr.ts +56 -12
- package/src/cache/segment-codec.ts +9 -17
- package/src/cache/tag-invalidation.ts +230 -0
- package/src/cache/types.ts +37 -100
- package/src/client.rsc.tsx +44 -21
- package/src/client.tsx +119 -290
- package/src/cloudflare/index.ts +11 -0
- package/src/cloudflare/tracing.ts +109 -0
- package/src/component-utils.ts +19 -0
- package/src/components/DefaultDocument.tsx +8 -2
- package/src/context-var.ts +18 -6
- package/src/decode-loader-results.ts +52 -0
- package/src/defer.ts +196 -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 +70 -22
- package/src/handles/MetaTags.tsx +62 -19
- package/src/handles/Scripts.tsx +183 -0
- package/src/handles/breadcrumbs.ts +37 -8
- package/src/handles/is-thenable.ts +19 -0
- package/src/handles/meta.ts +51 -40
- package/src/handles/script.ts +244 -0
- package/src/host/cookie-handler.ts +9 -60
- package/src/host/errors.ts +0 -24
- package/src/host/index.ts +8 -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 +99 -13
- package/src/index.ts +139 -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 +198 -82
- package/src/redirect-origin.ts +100 -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 +461 -304
- package/src/route-definition/helper-factories.ts +28 -140
- package/src/route-definition/helpers-types.ts +143 -69
- package/src/route-definition/index.ts +4 -2
- package/src/route-definition/redirect.ts +51 -10
- 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 +0 -16
- 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 +44 -23
- package/src/router/handler-context.ts +52 -31
- package/src/router/instrument.ts +350 -0
- package/src/router/intercept-resolution.ts +48 -24
- package/src/router/lazy-includes.ts +15 -52
- package/src/router/loader-resolution.ts +268 -56
- package/src/router/logging.ts +0 -6
- package/src/router/manifest.ts +40 -42
- package/src/router/match-api.ts +124 -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 +40 -24
- package/src/router/match-middleware/cache-lookup.ts +170 -276
- package/src/router/match-middleware/cache-store.ts +64 -52
- package/src/router/match-middleware/intercept-resolution.ts +0 -22
- package/src/router/match-middleware/segment-resolution.ts +45 -14
- package/src/router/match-pipelines.ts +1 -42
- package/src/router/match-result.ts +87 -39
- package/src/router/metrics.ts +0 -34
- package/src/router/middleware-types.ts +7 -140
- package/src/router/middleware.ts +266 -169
- package/src/router/navigation-snapshot.ts +131 -0
- package/src/router/params-util.ts +23 -0
- package/src/router/pattern-matching.ts +132 -90
- package/src/router/prefetch-cache-ttl.ts +51 -0
- package/src/router/prerender-match.ts +195 -56
- package/src/router/preview-match.ts +32 -102
- package/src/router/request-classification.ts +276 -0
- package/src/router/revalidation.ts +123 -73
- package/src/router/route-snapshot.ts +244 -0
- package/src/router/router-context.ts +3 -28
- package/src/router/router-interfaces.ts +115 -35
- package/src/router/router-options.ts +172 -15
- package/src/router/router-registry.ts +2 -5
- package/src/router/segment-resolution/fresh.ts +162 -84
- package/src/router/segment-resolution/helpers.ts +86 -6
- package/src/router/segment-resolution/loader-cache.ts +76 -39
- package/src/router/segment-resolution/revalidation.ts +351 -321
- 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 +6 -5
- package/src/router/state-cookie-name.ts +33 -0
- package/src/router/substitute-pattern-params.ts +56 -0
- package/src/router/telemetry-otel.ts +161 -199
- package/src/router/telemetry.ts +96 -19
- package/src/router/timeout.ts +0 -20
- package/src/router/tracing.ts +206 -0
- package/src/router/trie-matching.ts +163 -59
- package/src/router/types.ts +9 -63
- package/src/router/url-params.ts +44 -0
- package/src/router.ts +157 -54
- package/src/rsc/handler-context.ts +3 -2
- package/src/rsc/handler.ts +655 -529
- 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 +122 -31
- package/src/rsc/manifest-init.ts +33 -42
- package/src/rsc/origin-guard.ts +39 -25
- package/src/rsc/progressive-enhancement.ts +131 -14
- package/src/rsc/redirect-guard.ts +99 -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 +109 -74
- package/src/rsc/runtime-warnings.ts +23 -10
- package/src/rsc/server-action.ts +287 -115
- package/src/rsc/ssr-setup.ts +18 -2
- package/src/rsc/transition-gate.ts +89 -0
- package/src/rsc/types.ts +29 -9
- 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 +149 -0
- package/src/segment-system.tsx +236 -202
- package/src/serialize.ts +243 -0
- package/src/server/context.ts +224 -52
- package/src/server/cookie-parse.ts +32 -0
- package/src/server/cookie-store.ts +80 -5
- package/src/server/handle-store.ts +40 -38
- package/src/server/loader-registry.ts +38 -46
- package/src/server/request-context.ts +401 -173
- package/src/ssr/index.tsx +24 -16
- 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 +701 -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 +183 -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 +581 -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 +20 -58
- 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 +125 -71
- package/src/types/index.ts +3 -10
- package/src/types/loader-types.ts +40 -11
- package/src/types/request-scope.ts +112 -0
- package/src/types/route-config.ts +6 -50
- package/src/types/route-entry.ts +12 -7
- package/src/types/segments.ts +136 -15
- package/src/urls/include-helper.ts +33 -70
- package/src/urls/index.ts +1 -11
- package/src/urls/path-helper-types.ts +68 -18
- 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 -19
- 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 +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 -4
- package/src/vite/discovery/virtual-module-codegen.ts +14 -34
- package/src/vite/index.ts +6 -0
- package/src/vite/inject-client-debug.ts +36 -0
- package/src/vite/plugin-types.ts +178 -5
- 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 +48 -95
- 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 +64 -170
- package/src/vite/plugins/refresh-cmd.ts +89 -27
- package/src/vite/plugins/use-cache-transform.ts +73 -83
- package/src/vite/plugins/version-injector.ts +40 -29
- package/src/vite/plugins/version-plugin.ts +37 -40
- package/src/vite/plugins/virtual-entries.ts +39 -25
- package/src/vite/rango.ts +118 -114
- package/src/vite/router-discovery.ts +941 -142
- package/src/vite/utils/ast-handler-extract.ts +26 -35
- package/src/vite/utils/banner.ts +1 -1
- 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 +81 -34
- package/src/vite/utils/shared-utils.ts +92 -42
- package/src/browser/action-response-classifier.ts +0 -99
- package/src/browser/debug-channel.ts +0 -93
- 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
|
@@ -22,6 +22,61 @@ export interface UnresolvableInclude {
|
|
|
22
22
|
detail: string;
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
+
// ---------------------------------------------------------------------------
|
|
26
|
+
// Per-scan memo
|
|
27
|
+
// ---------------------------------------------------------------------------
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Per-scan memo shared across the include-resolution recursion. Keys are
|
|
31
|
+
* absolute file paths; values cache the readFileSync result and the
|
|
32
|
+
* ts.SourceFile parsed from the FULL file source. A separate blockSources map
|
|
33
|
+
* caches parses of extracted sub-blocks (urls() call text), keyed by the exact
|
|
34
|
+
* block string, so the two extractors (routes + includes) for the same block
|
|
35
|
+
* share a single parse.
|
|
36
|
+
*
|
|
37
|
+
* The memo is purely a performance accelerator: same input -> same parse, so
|
|
38
|
+
* generated output is identical to the un-memoized path. A fresh memo is
|
|
39
|
+
* created per top-level scan entry, so stale file edits between scans are never
|
|
40
|
+
* served.
|
|
41
|
+
*/
|
|
42
|
+
export interface ScanMemo {
|
|
43
|
+
files: Map<string, string>;
|
|
44
|
+
blockSourceFiles: Map<string, ts.SourceFile>;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export function createScanMemo(): ScanMemo {
|
|
48
|
+
return { files: new Map(), blockSourceFiles: new Map() };
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function parseBlock(memo: ScanMemo | undefined, block: string): ts.SourceFile {
|
|
52
|
+
if (memo) {
|
|
53
|
+
const cached = memo.blockSourceFiles.get(block);
|
|
54
|
+
if (cached) return cached;
|
|
55
|
+
}
|
|
56
|
+
const sf = ts.createSourceFile(
|
|
57
|
+
"input.tsx",
|
|
58
|
+
block,
|
|
59
|
+
ts.ScriptTarget.Latest,
|
|
60
|
+
true,
|
|
61
|
+
ts.ScriptKind.TSX,
|
|
62
|
+
);
|
|
63
|
+
if (memo) memo.blockSourceFiles.set(block, sf);
|
|
64
|
+
return sf;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function readSourceMemoized(
|
|
68
|
+
memo: ScanMemo | undefined,
|
|
69
|
+
realPath: string,
|
|
70
|
+
): string {
|
|
71
|
+
if (memo) {
|
|
72
|
+
const cached = memo.files.get(realPath);
|
|
73
|
+
if (cached !== undefined) return cached;
|
|
74
|
+
}
|
|
75
|
+
const source = readFileSync(realPath, "utf-8");
|
|
76
|
+
if (memo) memo.files.set(realPath, source);
|
|
77
|
+
return source;
|
|
78
|
+
}
|
|
79
|
+
|
|
25
80
|
// ---------------------------------------------------------------------------
|
|
26
81
|
// AST-based include() parsing
|
|
27
82
|
// ---------------------------------------------------------------------------
|
|
@@ -47,7 +102,10 @@ function extractNamePrefixFromInclude(node: ts.CallExpression): string | null {
|
|
|
47
102
|
* Returns both resolved includes (identifier second args) and unresolvable
|
|
48
103
|
* includes (factory calls, etc.) with reasons.
|
|
49
104
|
*/
|
|
50
|
-
export function extractIncludesWithDiagnostics(
|
|
105
|
+
export function extractIncludesWithDiagnostics(
|
|
106
|
+
code: string,
|
|
107
|
+
sourceFileArg?: ts.SourceFile,
|
|
108
|
+
): {
|
|
51
109
|
resolved: Array<{
|
|
52
110
|
pathPrefix: string;
|
|
53
111
|
variableName: string;
|
|
@@ -60,13 +118,16 @@ export function extractIncludesWithDiagnostics(code: string): {
|
|
|
60
118
|
detail: string;
|
|
61
119
|
}>;
|
|
62
120
|
} {
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
ts.
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
121
|
+
// Reuse a caller-provided SourceFile (parsed once per scan) when given.
|
|
122
|
+
const sourceFile =
|
|
123
|
+
sourceFileArg ??
|
|
124
|
+
ts.createSourceFile(
|
|
125
|
+
"input.tsx",
|
|
126
|
+
code,
|
|
127
|
+
ts.ScriptTarget.Latest,
|
|
128
|
+
true,
|
|
129
|
+
ts.ScriptKind.TSX,
|
|
130
|
+
);
|
|
70
131
|
const resolved: Array<{
|
|
71
132
|
pathPrefix: string;
|
|
72
133
|
variableName: string;
|
|
@@ -140,7 +201,13 @@ export function resolveImportedVariable(
|
|
|
140
201
|
code: string,
|
|
141
202
|
localName: string,
|
|
142
203
|
): { specifier: string; exportedName: string } | null {
|
|
143
|
-
|
|
204
|
+
// Allow an optional leading default binding before the named-import brace so
|
|
205
|
+
// a combined `import Foo, { bar } from "..."` is matched (the named members
|
|
206
|
+
// are the only part we resolve; the default binding is skipped). Without the
|
|
207
|
+
// optional `(?:[\w$]+\s*,\s*)?` segment, the `Foo, ` prefix breaks the match
|
|
208
|
+
// and a legitimate static named import surfaces as `unresolvable-import`.
|
|
209
|
+
const importRegex =
|
|
210
|
+
/import\s*(?:[\w$]+\s*,\s*)?\{([^}]+)\}\s*from\s*["']([^"']+)["']/g;
|
|
144
211
|
let match;
|
|
145
212
|
|
|
146
213
|
while ((match = importRegex.exec(code)) !== null) {
|
|
@@ -206,14 +273,18 @@ export function resolveImportPath(
|
|
|
206
273
|
function extractUrlsBlockForVariable(
|
|
207
274
|
code: string,
|
|
208
275
|
varName: string,
|
|
276
|
+
sourceFileArg?: ts.SourceFile,
|
|
209
277
|
): string | null {
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
ts.
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
278
|
+
// Reuse a caller-provided full-source SourceFile (parsed once per scan).
|
|
279
|
+
const sourceFile =
|
|
280
|
+
sourceFileArg ??
|
|
281
|
+
ts.createSourceFile(
|
|
282
|
+
"input.tsx",
|
|
283
|
+
code,
|
|
284
|
+
ts.ScriptTarget.Latest,
|
|
285
|
+
true,
|
|
286
|
+
ts.ScriptKind.TSX,
|
|
287
|
+
);
|
|
217
288
|
let result: string | null = null;
|
|
218
289
|
|
|
219
290
|
function visit(node: ts.Node) {
|
|
@@ -249,11 +320,15 @@ function buildRouteMapFromBlock(
|
|
|
249
320
|
visited: Set<string>,
|
|
250
321
|
searchSchemasOut?: Record<string, Record<string, string>>,
|
|
251
322
|
diagnosticsOut?: UnresolvableInclude[],
|
|
323
|
+
memo?: ScanMemo,
|
|
252
324
|
): Record<string, string> {
|
|
253
325
|
const routeMap: Record<string, string> = {};
|
|
254
326
|
|
|
327
|
+
// Parse the block once and share the SourceFile between both extractors.
|
|
328
|
+
const blockSourceFile = parseBlock(memo, block);
|
|
329
|
+
|
|
255
330
|
// Extract local path() routes
|
|
256
|
-
const localRoutes = extractRoutesFromSource(block);
|
|
331
|
+
const localRoutes = extractRoutesFromSource(block, blockSourceFile);
|
|
257
332
|
for (const { name, pattern, search } of localRoutes) {
|
|
258
333
|
routeMap[name] = pattern;
|
|
259
334
|
if (search && searchSchemasOut) {
|
|
@@ -262,8 +337,10 @@ function buildRouteMapFromBlock(
|
|
|
262
337
|
}
|
|
263
338
|
|
|
264
339
|
// Extract include() calls with diagnostics for unresolvable ones
|
|
265
|
-
const { resolved: includes, unresolvable } =
|
|
266
|
-
|
|
340
|
+
const { resolved: includes, unresolvable } = extractIncludesWithDiagnostics(
|
|
341
|
+
block,
|
|
342
|
+
blockSourceFile,
|
|
343
|
+
);
|
|
267
344
|
|
|
268
345
|
if (diagnosticsOut) {
|
|
269
346
|
for (const entry of unresolvable) {
|
|
@@ -298,12 +375,17 @@ function buildRouteMapFromBlock(
|
|
|
298
375
|
imported.exportedName,
|
|
299
376
|
visited,
|
|
300
377
|
diagnosticsOut,
|
|
378
|
+
undefined,
|
|
379
|
+
memo,
|
|
301
380
|
);
|
|
302
381
|
} else {
|
|
303
|
-
// Check if variable exists as a same-file urls() definition
|
|
382
|
+
// Check if variable exists as a same-file urls() definition. Share the
|
|
383
|
+
// full-source SourceFile parse via the memo (block === fullSource hits the
|
|
384
|
+
// same cache entry already used above).
|
|
304
385
|
const sameFileBlock = extractUrlsBlockForVariable(
|
|
305
386
|
fullSource,
|
|
306
387
|
variableName,
|
|
388
|
+
parseBlock(memo, fullSource),
|
|
307
389
|
);
|
|
308
390
|
if (!sameFileBlock) {
|
|
309
391
|
if (diagnosticsOut) {
|
|
@@ -322,6 +404,8 @@ function buildRouteMapFromBlock(
|
|
|
322
404
|
variableName,
|
|
323
405
|
visited,
|
|
324
406
|
diagnosticsOut,
|
|
407
|
+
undefined,
|
|
408
|
+
memo,
|
|
325
409
|
);
|
|
326
410
|
}
|
|
327
411
|
|
|
@@ -357,35 +441,51 @@ function buildRouteMapFromBlock(
|
|
|
357
441
|
/**
|
|
358
442
|
* Build route map and search schemas together.
|
|
359
443
|
* Internal helper used by the include resolution path.
|
|
444
|
+
*
|
|
445
|
+
* @param inlineBlock - Optional pre-extracted code block (e.g. from an inline
|
|
446
|
+
* builder function). When provided, variableName is ignored and the block
|
|
447
|
+
* is parsed directly for path()/include() calls.
|
|
448
|
+
* @param memo - Per-scan readFileSync/parse memo. A fresh one is created at the
|
|
449
|
+
* top-level entry and threaded through the recursion so each file is read and
|
|
450
|
+
* parsed once per scan. Behavior-preserving (same input -> same output).
|
|
360
451
|
*/
|
|
361
452
|
export function buildCombinedRouteMapWithSearch(
|
|
362
453
|
filePath: string,
|
|
363
454
|
variableName?: string,
|
|
364
455
|
visited?: Set<string>,
|
|
365
456
|
diagnosticsOut?: UnresolvableInclude[],
|
|
457
|
+
inlineBlock?: string,
|
|
458
|
+
memo?: ScanMemo,
|
|
366
459
|
): {
|
|
367
460
|
routes: Record<string, string>;
|
|
368
461
|
searchSchemas: Record<string, Record<string, string>>;
|
|
369
462
|
} {
|
|
370
463
|
visited = visited ?? new Set();
|
|
464
|
+
memo = memo ?? createScanMemo();
|
|
371
465
|
const realPath = resolve(filePath);
|
|
372
466
|
const key = variableName ? `${realPath}:${variableName}` : realPath;
|
|
373
467
|
if (visited.has(key)) {
|
|
374
|
-
console.warn(`[
|
|
468
|
+
console.warn(`[rango] Circular include detected, skipping: ${key}`);
|
|
375
469
|
return { routes: {}, searchSchemas: {} };
|
|
376
470
|
}
|
|
377
471
|
visited.add(key);
|
|
378
472
|
|
|
379
473
|
let source: string;
|
|
380
474
|
try {
|
|
381
|
-
source =
|
|
475
|
+
source = readSourceMemoized(memo, realPath);
|
|
382
476
|
} catch {
|
|
383
477
|
return { routes: {}, searchSchemas: {} };
|
|
384
478
|
}
|
|
385
479
|
|
|
386
480
|
let block: string;
|
|
387
|
-
if (
|
|
388
|
-
|
|
481
|
+
if (inlineBlock) {
|
|
482
|
+
block = inlineBlock;
|
|
483
|
+
} else if (variableName) {
|
|
484
|
+
const extracted = extractUrlsBlockForVariable(
|
|
485
|
+
source,
|
|
486
|
+
variableName,
|
|
487
|
+
parseBlock(memo, source),
|
|
488
|
+
);
|
|
389
489
|
if (!extracted) return { routes: {}, searchSchemas: {} };
|
|
390
490
|
block = extracted;
|
|
391
491
|
} else {
|
|
@@ -400,6 +500,7 @@ export function buildCombinedRouteMapWithSearch(
|
|
|
400
500
|
visited,
|
|
401
501
|
searchSchemas,
|
|
402
502
|
diagnosticsOut,
|
|
503
|
+
memo,
|
|
403
504
|
);
|
|
404
505
|
|
|
405
506
|
// Remove from visited so sibling branches can include the same variable
|
|
@@ -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
|
}
|
|
@@ -3,7 +3,10 @@ import ts from "typescript";
|
|
|
3
3
|
import { extractParamsFromPattern } from "./param-extraction.js";
|
|
4
4
|
import { extractRoutesFromSource } from "./ast-route-extraction.js";
|
|
5
5
|
import { generatePerModuleTypesSource } from "./codegen.js";
|
|
6
|
-
import {
|
|
6
|
+
import {
|
|
7
|
+
buildCombinedRouteMapWithSearch,
|
|
8
|
+
createScanMemo,
|
|
9
|
+
} from "./include-resolution.js";
|
|
7
10
|
import type { ScanFilter } from "./scan-filter.js";
|
|
8
11
|
import { findTsFiles } from "./scan-filter.js";
|
|
9
12
|
|
|
@@ -78,10 +81,20 @@ export function writePerModuleRouteTypesForFile(filePath: string): void {
|
|
|
78
81
|
if (varNames.length > 0) {
|
|
79
82
|
// Follow includes recursively via the combined route map builder.
|
|
80
83
|
// The visited set in buildCombinedRouteMapWithSearch prevents infinite loops.
|
|
84
|
+
// Share one per-file scan memo across all urls() variables so a shared
|
|
85
|
+
// include target is read+parsed once for this file, not once per variable.
|
|
81
86
|
routes = [];
|
|
87
|
+
const memo = createScanMemo();
|
|
82
88
|
for (const varName of varNames) {
|
|
83
89
|
const { routes: routeMap, searchSchemas } =
|
|
84
|
-
buildCombinedRouteMapWithSearch(
|
|
90
|
+
buildCombinedRouteMapWithSearch(
|
|
91
|
+
filePath,
|
|
92
|
+
varName,
|
|
93
|
+
undefined,
|
|
94
|
+
undefined,
|
|
95
|
+
undefined,
|
|
96
|
+
memo,
|
|
97
|
+
);
|
|
85
98
|
for (const [name, pattern] of Object.entries(routeMap)) {
|
|
86
99
|
const params = extractParamsFromPattern(pattern);
|
|
87
100
|
routes.push({
|
|
@@ -97,7 +110,10 @@ export function writePerModuleRouteTypesForFile(filePath: string): void {
|
|
|
97
110
|
routes = extractRoutesFromSource(source);
|
|
98
111
|
}
|
|
99
112
|
|
|
100
|
-
|
|
113
|
+
// Match .ts/.tsx/.js/.jsx (same as router-processing.ts / router-transform.ts).
|
|
114
|
+
// Without the jsx? branch a .jsx/.js source produced genPath === filePath,
|
|
115
|
+
// overwriting the source file instead of writing a sibling .gen.ts.
|
|
116
|
+
const genPath = filePath.replace(/\.(tsx?|jsx?)$/, ".gen.ts");
|
|
101
117
|
|
|
102
118
|
// When a urls() variable was found but static resolution yields zero
|
|
103
119
|
// routes, write an empty placeholder so generated imports stay
|
|
@@ -106,7 +122,7 @@ export function writePerModuleRouteTypesForFile(filePath: string): void {
|
|
|
106
122
|
if (varNames.length > 0 && !existsSync(genPath)) {
|
|
107
123
|
writeFileSync(genPath, generatePerModuleTypesSource([]));
|
|
108
124
|
console.log(
|
|
109
|
-
`[
|
|
125
|
+
`[rango] Generated route types (placeholder) -> ${genPath}`,
|
|
110
126
|
);
|
|
111
127
|
}
|
|
112
128
|
return;
|
|
@@ -118,11 +134,11 @@ export function writePerModuleRouteTypesForFile(filePath: string): void {
|
|
|
118
134
|
: null;
|
|
119
135
|
if (existing !== genSource) {
|
|
120
136
|
writeFileSync(genPath, genSource);
|
|
121
|
-
console.log(`[
|
|
137
|
+
console.log(`[rango] Generated route types -> ${genPath}`);
|
|
122
138
|
}
|
|
123
139
|
} catch (err) {
|
|
124
140
|
console.warn(
|
|
125
|
-
`[
|
|
141
|
+
`[rango] Failed to generate route types for ${filePath}: ${(err as Error).message}`,
|
|
126
142
|
);
|
|
127
143
|
}
|
|
128
144
|
}
|