@wular/pnext 0.0.4 → 0.0.7
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/README.md +22 -16
- package/bin/pnext +6 -1
- package/config/lint/base.js +7 -7
- package/config/ts/base.json +2 -4
- package/config/ts/react.json +2 -6
- package/package.json +23 -2
- package/reference/compat.md +87 -22
- package/reference/config.md +40 -93
- package/reference/css.md +42 -33
- package/reference/dev.md +26 -33
- package/reference/env.md +18 -20
- package/reference/getting-started.md +132 -0
- package/reference/metadata.md +31 -46
- package/reference/navigation.md +65 -105
- package/reference/performance.md +21 -142
- package/reference/rendering.md +78 -75
- package/reference/routing.md +97 -107
- package/reference/typegen.md +27 -29
- package/src/api/cache.ts +36 -37
- package/src/api/client-cache.ts +2 -2
- package/src/api/client-navigation.ts +121 -114
- package/src/api/dynamic.tsx +58 -55
- package/src/api/link.tsx +52 -53
- package/src/api/navigation.ts +59 -58
- package/src/api/server.ts +152 -144
- package/src/api/suspense.ts +4 -4
- package/src/cli/adapters/vercel-warm.ts +126 -121
- package/src/cli/adapters/vercel.ts +437 -443
- package/src/cli/analyze.ts +333 -144
- package/src/cli/{named-bin.ts → boot/named-bin.ts} +37 -37
- package/src/cli/{boot-trace.ts → boot/trace.ts} +10 -10
- package/src/cli/build.ts +976 -978
- package/src/cli/create.ts +72 -64
- package/src/cli/dev.ts +116 -116
- package/src/cli/index.ts +94 -85
- package/src/cli/migrate/package-json.ts +73 -71
- package/src/cli/migrate/report.ts +32 -33
- package/src/cli/migrate/{index.ts → run.ts} +48 -49
- package/src/cli/migrate/scan.ts +46 -46
- package/src/cli/migrate/spinner.ts +9 -9
- package/src/cli/migrate/tsconfig.ts +35 -35
- package/src/cli/{server-entry.ts → serve/entry.ts} +57 -57
- package/src/cli/{request-pipeline.ts → serve/pipeline.ts} +386 -394
- package/src/cli/{serve-ui.ts → serve/ui.ts} +47 -47
- package/src/cli/start.ts +65 -66
- package/src/{typegen.ts → cli/typegen.ts} +59 -59
- package/src/client/build.ts +802 -768
- package/src/client/chunk-fold.ts +245 -240
- package/src/client/{paths.ts → chunk-name.ts} +6 -6
- package/src/client/entry.ts +162 -147
- package/src/client/prebuilt.ts +231 -223
- package/src/client/profile.ts +29 -29
- package/src/client/react-compiler.ts +20 -15
- package/src/client/{compat-surface.ts → react-tier.ts} +64 -64
- package/src/client/reference-stub.ts +51 -51
- package/src/client/reference.ts +19 -19
- package/src/{api → client}/router/events.ts +32 -17
- package/src/{api → client}/router/history.ts +16 -16
- package/src/{api → client}/router/hub.ts +52 -53
- package/src/{api/router.ts → client/router/index.ts} +61 -60
- package/src/{api → client}/router/policies.ts +24 -24
- package/src/{api → client}/router/runtime.ts +2022 -1995
- package/src/{api → client}/router/types.ts +98 -98
- package/src/compat/actions/client-plugin.ts +42 -43
- package/src/compat/actions/client-stub.ts +14 -14
- package/src/compat/actions/{action-client.ts → client.ts} +194 -193
- package/src/compat/actions/config.ts +63 -64
- package/src/compat/actions/detect.ts +68 -68
- package/src/compat/actions/discovery.ts +105 -105
- package/src/compat/actions/{action-dispatch.ts → dispatch.ts} +277 -274
- package/src/compat/actions/early-submit.ts +1 -1
- package/src/compat/actions/endpoint.ts +198 -198
- package/src/compat/actions/extensions.ts +811 -0
- package/src/compat/actions/flight.ts +23 -23
- package/src/compat/actions/form-state.ts +34 -34
- package/src/compat/actions/hoist.ts +382 -236
- package/src/compat/actions/ids.ts +7 -12
- package/src/compat/actions/index.ts +8 -8
- package/src/compat/actions/instances.ts +46 -46
- package/src/compat/actions/origin.ts +47 -48
- package/src/compat/actions/protocol.ts +22 -22
- package/src/compat/actions/registry.ts +19 -19
- package/src/compat/{misc/action-return.ts → actions/return.ts} +60 -57
- package/src/compat/actions/rewrite.ts +125 -125
- package/src/compat/actions/{action-router.ts → router.ts} +10 -10
- package/src/compat/actions/serve.ts +132 -136
- package/src/compat/actions/server-tag.ts +4 -4
- package/src/compat/actions/{action-shared.ts → shared.ts} +34 -34
- package/src/compat/actions/unrecognized-error.ts +4 -4
- package/src/compat/{index.ts → aliases.ts} +112 -109
- package/src/compat/bundler/bun-externals.ts +18 -18
- package/src/compat/bundler/cjs-exports.ts +271 -223
- package/src/compat/bundler/config.ts +116 -111
- package/src/compat/bundler/externals.ts +12 -12
- package/src/compat/bundler/import-meta-url.ts +19 -19
- package/src/compat/bundler/modularize-imports.ts +36 -33
- package/src/compat/bundler/new-url-asset.ts +22 -24
- package/src/compat/bundler/optimize-package-imports.ts +111 -107
- package/src/compat/bundler/polyfill.ts +28 -28
- package/src/compat/bundler/react-compiler.ts +35 -29
- package/src/compat/bundler/react-profiler.tsx +11 -11
- package/src/compat/bundler/relay-transform.ts +48 -47
- package/src/compat/bundler/require-context.ts +119 -113
- package/src/compat/bundler/resolve-extensions.ts +19 -19
- package/src/compat/bundler/source-cache.ts +25 -25
- package/src/compat/bundler/static-imports.ts +7 -7
- package/src/compat/bundler/symlink-imports.ts +46 -46
- package/src/compat/bundler/tsconfig-paths.ts +13 -15
- package/src/compat/bundler/wasm.ts +58 -60
- package/src/compat/bundler/webpack-loaders.ts +254 -241
- package/src/compat/bundler/worker.ts +101 -104
- package/src/compat/cache/build-flags.ts +29 -29
- package/src/compat/cache/build-prerender-errors.ts +40 -44
- package/src/compat/cache/custom-handler.ts +60 -53
- package/src/compat/cache/fetch-patch.ts +240 -240
- package/src/compat/cache/handler.ts +27 -31
- package/src/compat/cache/modern-handler.ts +148 -126
- package/src/compat/cache/resume-data-cache.ts +47 -45
- package/src/compat/cache/revalidate.ts +233 -232
- package/src/compat/cache/runtime-error.ts +35 -35
- package/src/compat/cache/use-cache-transform.ts +442 -417
- package/src/compat/cache/use-cache.ts +650 -614
- package/src/compat/cache-control.ts +140 -142
- package/src/compat/client/base-path.ts +21 -20
- package/src/compat/client/css-order.ts +18 -18
- package/src/compat/client/errors/bare-boundary.ts +11 -11
- package/src/compat/client/errors/control-flow.ts +23 -23
- package/src/compat/client/errors/error-boundary.ts +61 -61
- package/src/compat/client/errors/global-error.ts +101 -91
- package/src/compat/client/errors/install.ts +71 -72
- package/src/compat/client/errors/lazy.ts +23 -23
- package/src/compat/client/errors/primitive-throw.ts +47 -45
- package/src/compat/client/errors/soft-refresh.ts +4 -4
- package/src/compat/client/link-status.ts +33 -33
- package/src/compat/client/{nav-compat-runtime.ts → nav-runtime.ts} +20 -20
- package/src/compat/client/{nav-compat.ts → nav.ts} +12 -13
- package/src/compat/client/navigation-scroll.ts +63 -63
- package/src/compat/client/optimistic-routing.ts +93 -88
- package/src/compat/client/prefetch-cache.ts +23 -24
- package/src/compat/client/route-announcer.ts +35 -35
- package/src/compat/client/segment-cache-policy.ts +20 -20
- package/src/compat/client/segment-cache.ts +309 -315
- package/src/compat/client/segment-prefetch.ts +127 -132
- package/src/compat/client/trailing-slash.ts +5 -4
- package/src/compat/css/chunking.ts +113 -116
- package/src/compat/css/inline-css.ts +21 -21
- package/src/compat/css/lightningcss.ts +37 -38
- package/src/compat/css/modules.ts +161 -175
- package/src/compat/css/nonce.ts +7 -7
- package/src/compat/css/sass-plugin.ts +18 -21
- package/src/compat/css/sass.ts +150 -152
- package/src/compat/css/styled-jsx-runtime.ts +27 -27
- package/src/compat/css/styled-jsx.ts +21 -21
- package/src/compat/edge-runtime.ts +27 -27
- package/src/compat/{adapter → export}/build-complete.ts +72 -75
- package/src/compat/export/client.ts +29 -31
- package/src/compat/export/{index.ts → emit.ts} +111 -110
- package/src/compat/export/standalone.ts +62 -54
- package/src/compat/image-optimizer/cache.ts +51 -49
- package/src/compat/image-optimizer/detect.ts +52 -52
- package/src/compat/image-optimizer/{index.ts → optimize.ts} +189 -194
- package/src/compat/image-optimizer/source.ts +77 -80
- package/src/compat/lifecycle/after-scope.ts +26 -26
- package/src/compat/lifecycle/after.ts +48 -45
- package/src/compat/lifecycle/error-funnel.ts +98 -102
- package/src/compat/lifecycle/error-serialize.ts +30 -26
- package/src/compat/lifecycle/error-ui.ts +67 -32
- package/src/compat/lifecycle/instrumentation-client.ts +36 -38
- package/src/compat/lifecycle/instrumentation.ts +85 -85
- package/src/compat/lifecycle/node-console.ts +11 -11
- package/src/compat/lifecycle/testmode.ts +160 -132
- package/src/compat/mdx/compile.ts +60 -57
- package/src/compat/mdx/plugin.ts +11 -11
- package/src/compat/mdx/{next-mdx-stub.ts → stub.ts} +5 -5
- package/src/compat/{metadata-route-artifacts.ts → metadata-artifacts.ts} +195 -191
- package/src/compat/metadata.ts +75 -81
- package/src/compat/next/cache.ts +68 -69
- package/src/compat/next/canonical-url.ts +9 -9
- package/src/compat/next/client-cache.ts +19 -19
- package/src/compat/next/client-navigation.ts +112 -116
- package/src/compat/next/client-only.ts +1 -1
- package/src/compat/next/client-script.tsx +99 -93
- package/src/compat/next/client-server.ts +10 -10
- package/src/compat/next/config-loader.ts +176 -173
- package/src/compat/next/config.ts +7 -7
- package/src/compat/next/constants.cjs +6 -6
- package/src/compat/next/constants.ts +6 -6
- package/src/compat/next/custom-server.ts +26 -24
- package/src/compat/next/dist/client/components/app-router-headers.ts +21 -21
- package/src/compat/next/dist/server/app-render/work-unit-async-storage.external.cjs +3 -4
- package/src/compat/next/dist/server/web/spec-extension/revalidate.ts +1 -1
- package/src/compat/next/dist/server/web/spec-extension/unstable-cache.ts +1 -1
- package/src/compat/next/dist/server/web/spec-extension/unstable-no-store.ts +1 -1
- package/src/compat/next/dynamic.tsx +21 -18
- package/src/compat/next/error.tsx +52 -52
- package/src/compat/next/font/cache.ts +74 -74
- package/src/compat/next/font/google.ts +2 -2
- package/src/compat/next/font/index.ts +1 -1
- package/src/compat/next/font/local.ts +3 -3
- package/src/compat/next/font/runtime-client.ts +17 -15
- package/src/compat/next/font/runtime.ts +443 -408
- package/src/compat/next/font/shared.ts +120 -108
- package/src/compat/next/form.tsx +63 -63
- package/src/compat/next/head.tsx +2 -2
- package/src/compat/next/headers.ts +103 -95
- package/src/compat/next/image/client.tsx +220 -0
- package/src/compat/next/image/config.ts +56 -58
- package/src/compat/next/image/optimizer.ts +40 -36
- package/src/compat/next/image/patterns.ts +37 -40
- package/src/compat/next/{image-props.ts → image/props.ts} +208 -202
- package/src/compat/next/image/shared.ts +65 -57
- package/src/compat/next/image/static-metadata.ts +98 -107
- package/src/compat/next/image/validate.ts +79 -88
- package/src/compat/next/image.tsx +19 -23
- package/src/compat/next/index.ts +1 -1
- package/src/compat/next/legacy-image.tsx +59 -60
- package/src/compat/next/{link-validation-transform.ts → link-transform.ts} +95 -96
- package/src/compat/next/link.tsx +158 -158
- package/src/compat/next/navigation.cjs +12 -3
- package/src/compat/next/navigation.ts +48 -50
- package/src/compat/next/offline.ts +27 -27
- package/src/compat/next/og.ts +121 -124
- package/src/compat/next/preferred-region.ts +13 -14
- package/src/compat/next/redirects.ts +58 -56
- package/src/compat/next/resource-hints.ts +73 -76
- package/src/compat/next/rewrites.ts +130 -133
- package/src/compat/next/root-params.ts +45 -45
- package/src/compat/next/{optimistic-route-state.ts → route-state.ts} +52 -52
- package/src/compat/next/router.cjs +4 -2
- package/src/compat/next/router.ts +58 -61
- package/src/compat/next/script.tsx +108 -108
- package/src/compat/next/server-only.ts +1 -1
- package/src/compat/next/server.ts +19 -19
- package/src/compat/next/svgr.ts +18 -17
- package/src/compat/next/telemetry.ts +24 -24
- package/src/compat/next/{image-usage.ts → usage.ts} +70 -39
- package/src/compat/next/user-agent.ts +53 -49
- package/src/compat/next/web-vitals.ts +22 -24
- package/src/compat/otel/api.ts +41 -41
- package/src/compat/otel/client-trace-metadata.ts +25 -27
- package/src/compat/otel/fetch-span.ts +29 -29
- package/src/compat/otel/tracer.ts +331 -331
- package/src/compat/pages/api.ts +456 -0
- package/src/compat/pages/client-plugin.ts +36 -36
- package/src/compat/pages/router-state.ts +34 -34
- package/src/compat/pages/{index.ts → router.ts} +130 -135
- package/src/compat/ppr/io.ts +12 -12
- package/src/compat/ppr/missing-root-params.ts +34 -38
- package/src/compat/ppr/root-params-scan.ts +66 -66
- package/src/compat/ppr/root-params-transform.ts +24 -26
- package/src/compat/ppr/root-params.ts +30 -30
- package/src/compat/ppr/segment-config-incompat.ts +6 -7
- package/src/compat/protocol.ts +71 -70
- package/src/compat/react/action-state.ts +47 -48
- package/src/compat/react/client-lite.ts +15 -15
- package/src/compat/react/client.ts +4 -4
- package/src/compat/react/compiler-runtime.ts +11 -11
- package/src/compat/react/dom-client.ts +44 -44
- package/src/compat/react/dom-react-server.ts +10 -16
- package/src/compat/react/dom-server.ts +10 -10
- package/src/compat/react/dom.ts +52 -52
- package/src/compat/react/hooks-extra.ts +34 -35
- package/src/compat/react/parity.ts +64 -61
- package/src/compat/react/preact.ts +81 -82
- package/src/compat/react/react-server.ts +28 -28
- package/src/compat/react/router-shim.ts +1 -1
- package/src/compat/react/server-component-use.ts +8 -8
- package/src/compat/react/server-inserted-html.ts +30 -31
- package/src/compat/react/server.ts +53 -55
- package/src/compat/react/use.ts +32 -32
- package/src/compat/react/view-transition.ts +20 -20
- package/src/compat/register/actions.ts +35 -824
- package/src/compat/register/boot.ts +41 -41
- package/src/compat/register/build-tier.ts +5 -5
- package/src/compat/register/build.ts +74 -70
- package/src/compat/register/bundler.ts +161 -156
- package/src/compat/register/cache.ts +20 -20
- package/src/compat/register/client-errors.ts +3 -3
- package/src/compat/register/config.ts +6 -6
- package/src/compat/register/css-extras.ts +30 -34
- package/src/compat/register/edge-runtime.ts +3 -3
- package/src/compat/register/errors.ts +10 -12
- package/src/compat/register/export.ts +16 -16
- package/src/compat/register/font.ts +11 -11
- package/src/compat/register/hooks.ts +2 -2
- package/src/compat/register/image.ts +40 -40
- package/src/compat/register/index.ts +59 -62
- package/src/compat/register/instrumentation-client.ts +10 -10
- package/src/compat/register/lifecycle.ts +25 -28
- package/src/compat/register/mdx.ts +10 -10
- package/src/compat/register/middleware.ts +226 -16
- package/src/compat/register/otel.ts +80 -88
- package/src/compat/register/pages-api.ts +10 -463
- package/src/compat/register/ppr.ts +16 -16
- package/src/compat/register/protocol.ts +17 -18
- package/src/compat/register/proxy.ts +49 -51
- package/src/compat/register/render.ts +79 -76
- package/src/compat/register/routing.ts +162 -159
- package/src/compat/register/segment.ts +24 -1897
- package/src/compat/register/static-image.ts +3 -3
- package/src/compat/register/{misc.ts → taint.ts} +9 -9
- package/src/compat/register/typed-routes.ts +14 -14
- package/src/compat/register/{usecache.ts → use-cache.ts} +39 -39
- package/src/compat/register/validation.ts +18 -18
- package/src/compat/segment/loading-boundary.ts +43 -45
- package/src/compat/segment/page-slot.ts +69 -69
- package/src/compat/segment/serve.ts +1884 -0
- package/src/compat/segment/tree.ts +113 -112
- package/src/compat/segment/vary-key.ts +38 -38
- package/src/compat/segment/vary-params.ts +138 -142
- package/src/compat/static-params.ts +14 -12
- package/src/compat/tsconfig-defaults.ts +87 -91
- package/src/compat/typecheck/{index.ts → check.ts} +234 -212
- package/src/compat/typecheck/worker.ts +15 -12
- package/src/compat/typed-routes/{index.ts → generate.ts} +36 -36
- package/src/compat/typed-routes/manifest.ts +174 -170
- package/src/compat/typed-routes/typegen.ts +127 -110
- package/src/compat/validation/errors.ts +16 -19
- package/src/compat/validation/prerender-diagnostics.ts +521 -504
- package/src/compat/validation/{index.ts → validate.ts} +647 -648
- package/src/compat-bootstrap.ts +16 -16
- package/src/config.ts +86 -69
- package/src/css/build.ts +230 -227
- package/src/css/postcss.ts +79 -80
- package/src/css/worker.ts +14 -15
- package/src/dev/client-actions.ts +10 -10
- package/src/dev/client-chunk-store.ts +27 -27
- package/src/dev/{client-key-cache.ts → restart/client-key.ts} +76 -76
- package/src/dev/{restart-cache.ts → restart/enabled.ts} +1 -1
- package/src/dev/{global-css-cache.ts → restart/global-css.ts} +91 -83
- package/src/dev/{node-module-bundle-cache.ts → restart/node-modules.ts} +24 -24
- package/src/dev/{route-bundle-key-cache.ts → restart/route-bundle-key.ts} +53 -53
- package/src/dev/{route-facts-cache.ts → restart/route-facts.ts} +82 -82
- package/src/dev/server.ts +804 -820
- package/src/env.ts +46 -43
- package/src/extensions.ts +491 -478
- package/src/index.ts +8 -8
- package/src/internal.ts +20 -23
- package/src/{islands → render}/boundary-error.ts +3 -3
- package/src/render/hooks.ts +71 -71
- package/src/render/island-context.ts +14 -14
- package/src/render/metadata.ts +310 -310
- package/src/{ppr-postpone.ts → render/postpone.ts} +5 -5
- package/src/{ppr.ts → render/ppr.ts} +244 -245
- package/src/render/renderer.ts +2087 -2082
- package/src/render/resource-hints.ts +16 -17
- package/src/render/slots.tsx +224 -235
- package/src/{islands → render}/static-children.ts +9 -12
- package/src/{islands → render}/static-slots.ts +37 -37
- package/src/{cache/context.ts → request/cache.ts} +20 -20
- package/src/request/context.ts +107 -107
- package/src/{dynamic/source.ts → resolve/dynamic.ts} +139 -139
- package/src/resolve/engine.ts +90 -77
- package/src/resolve/imports.ts +475 -463
- package/src/resolve/scan-facts.ts +318 -296
- package/src/resolve/source-text.ts +37 -37
- package/src/{dynamic → resolve}/tree-shake.ts +132 -128
- package/src/routing/forwarded.ts +19 -19
- package/src/routing/handler.ts +84 -91
- package/src/routing/href.ts +87 -70
- package/src/routing/{metadata.ts → metadata-files.ts} +403 -401
- package/src/{proxy.ts → routing/proxy.ts} +306 -312
- package/src/routing/{request-runtime.ts → request-environment.ts} +10 -10
- package/src/routing/routes.ts +827 -815
- package/src/routing/slots.ts +164 -160
- package/src/runtime/loader.ts +954 -0
- package/src/{dev → runtime}/module-cache.ts +309 -287
- package/src/{dev → runtime}/module-generations.ts +9 -9
- package/src/{dev → runtime}/module-transform.ts +81 -72
- package/src/{dev/imports.ts → runtime/modules.ts} +934 -847
- package/src/runtime/{server.ts → vendor-build.ts} +848 -1696
- package/src/runtime/vendor.ts +428 -406
- package/src/styles.d.ts +9 -0
- package/src/types.ts +324 -335
- package/src/utils/ansi.ts +5 -5
- package/src/utils/{source.ts → code.ts} +15 -12
- package/src/utils/content-type.ts +3 -3
- package/src/utils/decode.ts +2 -2
- package/src/utils/dev-profile.ts +13 -13
- package/src/utils/error-log.ts +6 -6
- package/src/utils/esbuild.ts +18 -18
- package/src/utils/fs-cache.ts +13 -13
- package/src/utils/fs.ts +57 -49
- package/src/utils/html.ts +20 -24
- package/src/utils/native-require.ts +8 -8
- package/src/utils/serialize.ts +139 -146
- package/src/utils/verbose.ts +18 -18
- package/reference/overview.md +0 -35
- package/src/cli/analyze-print.ts +0 -181
- package/src/compat/middleware/manifest.ts +0 -210
- package/src/compat/next/image-client.tsx +0 -215
- package/src/compat/next/link-usage.ts +0 -29
- package/src/css/index.ts +0 -2
- package/src/render/index.ts +0 -1
- package/src/style-modules.d.ts +0 -9
package/src/routing/slots.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import path from 'node:path'
|
|
2
|
-
import { safeDecode } from '../utils/decode'
|
|
3
|
-
import { readDirListing, toPosixPath } from '../utils/fs'
|
|
4
|
-
import type { InterceptionMarker, RouteParamValue } from '../types'
|
|
1
|
+
import path from 'node:path'
|
|
2
|
+
import { safeDecode } from '../utils/decode'
|
|
3
|
+
import { readDirListing, toPosixPath } from '../utils/fs'
|
|
4
|
+
import type { InterceptionMarker, RouteParamValue } from '../types'
|
|
5
5
|
|
|
6
6
|
// Parallel-route (@slot) and intercepting-route ((.)segment) tree matching.
|
|
7
7
|
// Slot content resolves at request time against the filesystem: the app source
|
|
@@ -9,52 +9,52 @@ import type { InterceptionMarker, RouteParamValue } from '../types';
|
|
|
9
9
|
// so matching walks directories directly instead of precomputing every slot
|
|
10
10
|
// combination into the manifest.
|
|
11
11
|
|
|
12
|
-
const pageExtensions = ['tsx', 'ts', 'jsx', 'js', 'mjs'] as const
|
|
12
|
+
const pageExtensions = ['tsx', 'ts', 'jsx', 'js', 'mjs'] as const
|
|
13
13
|
|
|
14
|
-
const interceptionMarkers: InterceptionMarker[] = ['(..)(..)', '(...)', '(..)', '(.)']
|
|
14
|
+
const interceptionMarkers: InterceptionMarker[] = ['(..)(..)', '(...)', '(..)', '(.)']
|
|
15
15
|
const interceptionLevels: Record<InterceptionMarker, number> = {
|
|
16
16
|
'(.)': 0,
|
|
17
17
|
'(..)': 1,
|
|
18
18
|
'(..)(..)': 2,
|
|
19
19
|
'(...)': Number.POSITIVE_INFINITY,
|
|
20
|
-
}
|
|
20
|
+
}
|
|
21
21
|
|
|
22
22
|
export function interceptionMarkerOf(segment: string): InterceptionMarker | undefined {
|
|
23
23
|
return interceptionMarkers.find(
|
|
24
24
|
marker => segment.startsWith(marker) && segment.length > marker.length,
|
|
25
|
-
)
|
|
25
|
+
)
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
export function interceptionMarkerLevels(marker: InterceptionMarker) {
|
|
29
|
-
return interceptionLevels[marker]
|
|
29
|
+
return interceptionLevels[marker]
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
export function isSlotSegment(name: string) {
|
|
33
|
-
return name.startsWith('@')
|
|
33
|
+
return name.startsWith('@')
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
export function isGroupSegment(name: string) {
|
|
37
|
-
return name.startsWith('(') && name.endsWith(')') && !interceptionMarkerOf(name)
|
|
37
|
+
return name.startsWith('(') && name.endsWith(')') && !interceptionMarkerOf(name)
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
/** Nearest existing `<base>.<ext>` convention file in `dir`. */
|
|
41
41
|
export function slotConventionFile(dir: string, base: string) {
|
|
42
|
-
const { files } = readDirListing(dir)
|
|
42
|
+
const { files } = readDirListing(dir)
|
|
43
43
|
for (const extension of pageExtensions) {
|
|
44
|
-
if (files.has(`${base}.${extension}`)) return path.join(dir, `${base}.${extension}`)
|
|
44
|
+
if (files.has(`${base}.${extension}`)) return path.join(dir, `${base}.${extension}`)
|
|
45
45
|
}
|
|
46
|
-
return undefined
|
|
46
|
+
return undefined
|
|
47
47
|
}
|
|
48
48
|
|
|
49
49
|
function childDirectories(dir: string) {
|
|
50
|
-
return readDirListing(dir).dirs
|
|
50
|
+
return readDirListing(dir).dirs
|
|
51
51
|
}
|
|
52
52
|
|
|
53
53
|
/** `@slot` directories directly inside `dir`. */
|
|
54
54
|
export function slotDirectoriesIn(dir: string) {
|
|
55
55
|
return childDirectories(dir)
|
|
56
56
|
.filter(isSlotSegment)
|
|
57
|
-
.map(name => path.join(dir, name))
|
|
57
|
+
.map(name => path.join(dir, name))
|
|
58
58
|
}
|
|
59
59
|
|
|
60
60
|
/**
|
|
@@ -65,17 +65,17 @@ export function slotDirectoriesIn(dir: string) {
|
|
|
65
65
|
* shift the mapping and are not supported for slot resolution below them).
|
|
66
66
|
*/
|
|
67
67
|
export function consumedSegments(appPath: string, dir: string) {
|
|
68
|
-
const relative = path.relative(appPath, dir)
|
|
69
|
-
if (relative.startsWith('..')) return 0
|
|
70
|
-
let consumed = 0
|
|
68
|
+
const relative = path.relative(appPath, dir)
|
|
69
|
+
if (relative.startsWith('..')) return 0
|
|
70
|
+
let consumed = 0
|
|
71
71
|
for (const name of relative.split(path.sep).filter(Boolean)) {
|
|
72
|
-
if (isGroupSegment(name) || isSlotSegment(name)) continue
|
|
73
|
-
const marker = interceptionMarkerOf(name)
|
|
74
|
-
const bare = marker ? name.slice(marker.length) : name
|
|
75
|
-
if (/^\[\[?\.\.\./.test(bare)) return Number.POSITIVE_INFINITY
|
|
76
|
-
consumed += 1
|
|
72
|
+
if (isGroupSegment(name) || isSlotSegment(name)) continue
|
|
73
|
+
const marker = interceptionMarkerOf(name)
|
|
74
|
+
const bare = marker ? name.slice(marker.length) : name
|
|
75
|
+
if (/^\[\[?\.\.\./.test(bare)) return Number.POSITIVE_INFINITY
|
|
76
|
+
consumed += 1
|
|
77
77
|
}
|
|
78
|
-
return consumed
|
|
78
|
+
return consumed
|
|
79
79
|
}
|
|
80
80
|
|
|
81
81
|
export interface SegmentMatch {
|
|
@@ -83,16 +83,16 @@ export interface SegmentMatch {
|
|
|
83
83
|
* The matched page file. Absent for a pageless match - a fully-consumed path that still has a layout or
|
|
84
84
|
* parallel slots to render, Next's implicit null children inside intercepted units.
|
|
85
85
|
*/
|
|
86
|
-
file?: string
|
|
86
|
+
file?: string
|
|
87
87
|
/** Directories entered from (excluding) the start dir to the page's dir. */
|
|
88
|
-
dirs: string[]
|
|
88
|
+
dirs: string[]
|
|
89
89
|
/** Params captured while matching (decoded). */
|
|
90
|
-
params: Record<string, RouteParamValue
|
|
90
|
+
params: Record<string, RouteParamValue>
|
|
91
91
|
}
|
|
92
92
|
|
|
93
93
|
interface MatchOptions {
|
|
94
94
|
/** Enter interception marker dirs as if they were their bare segment. */
|
|
95
|
-
markersAsSegments?: boolean
|
|
95
|
+
markersAsSegments?: boolean
|
|
96
96
|
}
|
|
97
97
|
|
|
98
98
|
/**
|
|
@@ -107,24 +107,24 @@ export function matchSegments(
|
|
|
107
107
|
params: Record<string, RouteParamValue> = {},
|
|
108
108
|
dirs: string[] = [],
|
|
109
109
|
): SegmentMatch | null {
|
|
110
|
-
const children = childDirectories(dir)
|
|
111
|
-
const groups = children.filter(isGroupSegment)
|
|
110
|
+
const children = childDirectories(dir)
|
|
111
|
+
const groups = children.filter(isGroupSegment)
|
|
112
112
|
|
|
113
113
|
if (segments.length === 0) {
|
|
114
|
-
const page = slotConventionFile(dir, 'page')
|
|
115
|
-
if (page) return { file: page, dirs, params }
|
|
114
|
+
const page = slotConventionFile(dir, 'page')
|
|
115
|
+
if (page) return { file: page, dirs, params }
|
|
116
116
|
for (const group of groups) {
|
|
117
|
-
const match = matchSegments(path.join(dir, group), [], options, params, [...dirs, group])
|
|
118
|
-
if (match) return match
|
|
117
|
+
const match = matchSegments(path.join(dir, group), [], options, params, [...dirs, group])
|
|
118
|
+
if (match) return match
|
|
119
119
|
}
|
|
120
120
|
for (const name of children) {
|
|
121
|
-
const param = optionalCatchAllName(bareName(name, options))
|
|
122
|
-
if (!param) continue
|
|
121
|
+
const param = optionalCatchAllName(bareName(name, options))
|
|
122
|
+
if (!param) continue
|
|
123
123
|
const match = matchSegments(path.join(dir, name), [], options, { ...params, [param]: [] }, [
|
|
124
124
|
...dirs,
|
|
125
125
|
name,
|
|
126
|
-
])
|
|
127
|
-
if (match) return match
|
|
126
|
+
])
|
|
127
|
+
if (match) return match
|
|
128
128
|
}
|
|
129
129
|
// Inside an intercepted unit a fully-consumed path may have no page yet
|
|
130
130
|
// still render: a layout (or parallel slots) with implicit null children.
|
|
@@ -132,78 +132,78 @@ export function matchSegments(
|
|
|
132
132
|
options.markersAsSegments &&
|
|
133
133
|
(slotConventionFile(dir, 'layout') || children.some(isSlotSegment))
|
|
134
134
|
) {
|
|
135
|
-
return { dirs, params }
|
|
135
|
+
return { dirs, params }
|
|
136
136
|
}
|
|
137
|
-
return null
|
|
137
|
+
return null
|
|
138
138
|
}
|
|
139
139
|
|
|
140
|
-
const [head, ...rest] = segments as [string, ...string[]]
|
|
140
|
+
const [head, ...rest] = segments as [string, ...string[]]
|
|
141
141
|
|
|
142
142
|
// Literal segment.
|
|
143
143
|
for (const name of children) {
|
|
144
|
-
if (bareName(name, options) !== head) continue
|
|
145
|
-
const match = matchSegments(path.join(dir, name), rest, options, params, [...dirs, name])
|
|
146
|
-
if (match) return match
|
|
144
|
+
if (bareName(name, options) !== head) continue
|
|
145
|
+
const match = matchSegments(path.join(dir, name), rest, options, params, [...dirs, name])
|
|
146
|
+
if (match) return match
|
|
147
147
|
}
|
|
148
148
|
|
|
149
149
|
// Route groups are transparent at this level.
|
|
150
150
|
for (const group of groups) {
|
|
151
|
-
const match = matchSegments(path.join(dir, group), segments, options, params, [...dirs, group])
|
|
152
|
-
if (match) return match
|
|
151
|
+
const match = matchSegments(path.join(dir, group), segments, options, params, [...dirs, group])
|
|
152
|
+
if (match) return match
|
|
153
153
|
}
|
|
154
154
|
|
|
155
155
|
// Dynamic `[param]`.
|
|
156
156
|
for (const name of children) {
|
|
157
|
-
const param = dynamicParamName(bareName(name, options))
|
|
158
|
-
if (!param) continue
|
|
157
|
+
const param = dynamicParamName(bareName(name, options))
|
|
158
|
+
if (!param) continue
|
|
159
159
|
const match = matchSegments(
|
|
160
160
|
path.join(dir, name),
|
|
161
161
|
rest,
|
|
162
162
|
options,
|
|
163
163
|
{ ...params, [param]: safeDecode(head) },
|
|
164
164
|
[...dirs, name],
|
|
165
|
-
)
|
|
166
|
-
if (match) return match
|
|
165
|
+
)
|
|
166
|
+
if (match) return match
|
|
167
167
|
}
|
|
168
168
|
|
|
169
169
|
// `[...catchAll]` and `[[...opt]]` consume everything remaining.
|
|
170
170
|
for (const name of children) {
|
|
171
|
-
const bare = bareName(name, options)
|
|
172
|
-
const param = catchAllName(bare) ?? optionalCatchAllName(bare)
|
|
173
|
-
if (!param) continue
|
|
171
|
+
const bare = bareName(name, options)
|
|
172
|
+
const param = catchAllName(bare) ?? optionalCatchAllName(bare)
|
|
173
|
+
if (!param) continue
|
|
174
174
|
const match = matchSegments(
|
|
175
175
|
path.join(dir, name),
|
|
176
176
|
[],
|
|
177
177
|
options,
|
|
178
178
|
{ ...params, [param]: segments.map(safeDecode) },
|
|
179
179
|
[...dirs, name],
|
|
180
|
-
)
|
|
181
|
-
if (match) return match
|
|
180
|
+
)
|
|
181
|
+
if (match) return match
|
|
182
182
|
}
|
|
183
183
|
|
|
184
|
-
return null
|
|
184
|
+
return null
|
|
185
185
|
}
|
|
186
186
|
|
|
187
187
|
function bareName(name: string, options: MatchOptions) {
|
|
188
|
-
if (isSlotSegment(name)) return '\0'
|
|
189
|
-
const marker = interceptionMarkerOf(name)
|
|
190
|
-
if (!marker) return name
|
|
191
|
-
return options.markersAsSegments ? name.slice(marker.length) : '\0'
|
|
188
|
+
if (isSlotSegment(name)) return '\0'
|
|
189
|
+
const marker = interceptionMarkerOf(name)
|
|
190
|
+
if (!marker) return name
|
|
191
|
+
return options.markersAsSegments ? name.slice(marker.length) : '\0'
|
|
192
192
|
}
|
|
193
193
|
|
|
194
194
|
function dynamicParamName(name: string) {
|
|
195
|
-
const match = /^\[([^\].]+)\]$/.exec(name)
|
|
196
|
-
return match?.[1]
|
|
195
|
+
const match = /^\[([^\].]+)\]$/.exec(name)
|
|
196
|
+
return match?.[1]
|
|
197
197
|
}
|
|
198
198
|
|
|
199
199
|
function catchAllName(name: string) {
|
|
200
|
-
const match = /^\[\.\.\.([^\]]+)\]$/.exec(name)
|
|
201
|
-
return match?.[1]
|
|
200
|
+
const match = /^\[\.\.\.([^\]]+)\]$/.exec(name)
|
|
201
|
+
return match?.[1]
|
|
202
202
|
}
|
|
203
203
|
|
|
204
204
|
function optionalCatchAllName(name: string) {
|
|
205
|
-
const match = /^\[\[\.\.\.([^\]]+)\]\]$/.exec(name)
|
|
206
|
-
return match?.[1]
|
|
205
|
+
const match = /^\[\[\.\.\.([^\]]+)\]\]$/.exec(name)
|
|
206
|
+
return match?.[1]
|
|
207
207
|
}
|
|
208
208
|
|
|
209
209
|
/**
|
|
@@ -213,40 +213,40 @@ function optionalCatchAllName(name: string) {
|
|
|
213
213
|
* renders nothing (Next's implicit null default).
|
|
214
214
|
*/
|
|
215
215
|
export function childrenDefaultFile(dir: string, segments: string[]): string | undefined {
|
|
216
|
-
let current = dir
|
|
217
|
-
let best = slotConventionFile(current, 'default')
|
|
216
|
+
let current = dir
|
|
217
|
+
let best = slotConventionFile(current, 'default')
|
|
218
218
|
for (const segment of segments) {
|
|
219
|
-
const next = childSegmentDir(current, segment)
|
|
220
|
-
if (!next) break
|
|
221
|
-
current = next
|
|
222
|
-
best = slotConventionFile(current, 'default') ?? best
|
|
219
|
+
const next = childSegmentDir(current, segment)
|
|
220
|
+
if (!next) break
|
|
221
|
+
current = next
|
|
222
|
+
best = slotConventionFile(current, 'default') ?? best
|
|
223
223
|
}
|
|
224
|
-
return best
|
|
224
|
+
return best
|
|
225
225
|
}
|
|
226
226
|
|
|
227
227
|
function childSegmentDir(dir: string, segment: string): string | undefined {
|
|
228
|
-
const children = childDirectories(dir)
|
|
229
|
-
if (children.includes(segment)) return path.join(dir, segment)
|
|
228
|
+
const children = childDirectories(dir)
|
|
229
|
+
if (children.includes(segment)) return path.join(dir, segment)
|
|
230
230
|
for (const group of children.filter(isGroupSegment)) {
|
|
231
|
-
const nested = childSegmentDir(path.join(dir, group), segment)
|
|
232
|
-
if (nested) return nested
|
|
231
|
+
const nested = childSegmentDir(path.join(dir, group), segment)
|
|
232
|
+
if (nested) return nested
|
|
233
233
|
}
|
|
234
|
-
const dynamic = children.find(name => dynamicParamName(name))
|
|
235
|
-
if (dynamic) return path.join(dir, dynamic)
|
|
236
|
-
return undefined
|
|
234
|
+
const dynamic = children.find(name => dynamicParamName(name))
|
|
235
|
+
if (dynamic) return path.join(dir, dynamic)
|
|
236
|
+
return undefined
|
|
237
237
|
}
|
|
238
238
|
|
|
239
239
|
export interface InterceptorUnit {
|
|
240
240
|
/** The marker directory (absolute). Content below renders when intercepted. */
|
|
241
|
-
dir: string
|
|
241
|
+
dir: string
|
|
242
242
|
/** Route-style target prefix segments from the app root (e.g. `['groups', ':id', 'new']`). */
|
|
243
|
-
targetSegments: string[]
|
|
243
|
+
targetSegments: string[]
|
|
244
244
|
/** Regex source matching the target prefix (no anchors). */
|
|
245
|
-
targetPattern: string
|
|
245
|
+
targetPattern: string
|
|
246
246
|
/** Params captured by targetPattern, in group order. */
|
|
247
|
-
params: { name: string; catchAll: boolean }[]
|
|
247
|
+
params: { name: string; catchAll: boolean }[]
|
|
248
248
|
/** The final target token is a catch-all (consumes every remaining segment). */
|
|
249
|
-
catchAllTail: boolean
|
|
249
|
+
catchAllTail: boolean
|
|
250
250
|
}
|
|
251
251
|
|
|
252
252
|
/**
|
|
@@ -256,18 +256,18 @@ export interface InterceptorUnit {
|
|
|
256
256
|
* plain segments during `matchSegments({ markersAsSegments: true })`.
|
|
257
257
|
*/
|
|
258
258
|
export function slotInterceptorUnits(appPath: string, slotDir: string): InterceptorUnit[] {
|
|
259
|
-
const owner = routeTokensForDir(appPath, path.dirname(slotDir))
|
|
260
|
-
if (!owner) return []
|
|
261
|
-
const units: InterceptorUnit[] = []
|
|
262
|
-
collectInterceptorUnits(slotDir, owner, [], units)
|
|
263
|
-
return units
|
|
259
|
+
const owner = routeTokensForDir(appPath, path.dirname(slotDir))
|
|
260
|
+
if (!owner) return []
|
|
261
|
+
const units: InterceptorUnit[] = []
|
|
262
|
+
collectInterceptorUnits(slotDir, owner, [], units)
|
|
263
|
+
return units
|
|
264
264
|
}
|
|
265
265
|
|
|
266
266
|
interface RouteToken {
|
|
267
|
-
route: string
|
|
268
|
-
pattern: string
|
|
269
|
-
param?: string
|
|
270
|
-
catchAll?: boolean
|
|
267
|
+
route: string
|
|
268
|
+
pattern: string
|
|
269
|
+
param?: string
|
|
270
|
+
catchAll?: boolean
|
|
271
271
|
}
|
|
272
272
|
|
|
273
273
|
function collectInterceptorUnits(
|
|
@@ -277,19 +277,21 @@ function collectInterceptorUnits(
|
|
|
277
277
|
units: InterceptorUnit[],
|
|
278
278
|
) {
|
|
279
279
|
for (const name of childDirectories(dir)) {
|
|
280
|
-
const child = path.join(dir, name)
|
|
280
|
+
const child = path.join(dir, name)
|
|
281
281
|
if (isSlotSegment(name) || isGroupSegment(name)) {
|
|
282
|
-
collectInterceptorUnits(child, owner, inner, units)
|
|
283
|
-
continue
|
|
282
|
+
collectInterceptorUnits(child, owner, inner, units)
|
|
283
|
+
continue
|
|
284
284
|
}
|
|
285
|
-
const marker = interceptionMarkerOf(name)
|
|
285
|
+
const marker = interceptionMarkerOf(name)
|
|
286
286
|
if (marker) {
|
|
287
|
-
const bare = name.slice(marker.length)
|
|
288
|
-
const levels = interceptionLevels[marker]
|
|
289
|
-
const context = [...owner, ...inner]
|
|
287
|
+
const bare = name.slice(marker.length)
|
|
288
|
+
const levels = interceptionLevels[marker]
|
|
289
|
+
const context = [...owner, ...inner]
|
|
290
290
|
const kept =
|
|
291
|
-
levels === Number.POSITIVE_INFINITY
|
|
292
|
-
|
|
291
|
+
levels === Number.POSITIVE_INFINITY
|
|
292
|
+
? []
|
|
293
|
+
: context.slice(0, Math.max(0, context.length - levels))
|
|
294
|
+
const target = [...kept, segmentToken(bare)]
|
|
293
295
|
units.push({
|
|
294
296
|
dir: child,
|
|
295
297
|
targetSegments: target.map(token => token.route),
|
|
@@ -298,10 +300,10 @@ function collectInterceptorUnits(
|
|
|
298
300
|
.filter(token => token.param)
|
|
299
301
|
.map(token => ({ name: token.param!, catchAll: Boolean(token.catchAll) })),
|
|
300
302
|
catchAllTail: Boolean(target[target.length - 1]?.catchAll),
|
|
301
|
-
})
|
|
302
|
-
continue
|
|
303
|
+
})
|
|
304
|
+
continue
|
|
303
305
|
}
|
|
304
|
-
collectInterceptorUnits(child, owner, [...inner, segmentToken(name)], units)
|
|
306
|
+
collectInterceptorUnits(child, owner, [...inner, segmentToken(name)], units)
|
|
305
307
|
}
|
|
306
308
|
}
|
|
307
309
|
|
|
@@ -311,34 +313,34 @@ function collectInterceptorUnits(
|
|
|
311
313
|
* Returns undefined when the dir is outside the app root.
|
|
312
314
|
*/
|
|
313
315
|
export function routeTokensForDir(appPath: string, dir: string): RouteToken[] | undefined {
|
|
314
|
-
const relative = path.relative(appPath, dir)
|
|
315
|
-
if (relative.startsWith('..')) return undefined
|
|
316
|
-
let tokens: RouteToken[] = []
|
|
316
|
+
const relative = path.relative(appPath, dir)
|
|
317
|
+
if (relative.startsWith('..')) return undefined
|
|
318
|
+
let tokens: RouteToken[] = []
|
|
317
319
|
for (const name of toPosixPath(relative).split('/').filter(Boolean)) {
|
|
318
|
-
if (isGroupSegment(name) || isSlotSegment(name)) continue
|
|
319
|
-
const marker = interceptionMarkerOf(name)
|
|
320
|
+
if (isGroupSegment(name) || isSlotSegment(name)) continue
|
|
321
|
+
const marker = interceptionMarkerOf(name)
|
|
320
322
|
if (marker) {
|
|
321
|
-
const levels = interceptionLevels[marker]
|
|
323
|
+
const levels = interceptionLevels[marker]
|
|
322
324
|
tokens =
|
|
323
325
|
levels === Number.POSITIVE_INFINITY
|
|
324
326
|
? []
|
|
325
|
-
: tokens.slice(0, Math.max(0, tokens.length - levels))
|
|
326
|
-
tokens.push(segmentToken(name.slice(marker.length)))
|
|
327
|
-
continue
|
|
327
|
+
: tokens.slice(0, Math.max(0, tokens.length - levels))
|
|
328
|
+
tokens.push(segmentToken(name.slice(marker.length)))
|
|
329
|
+
continue
|
|
328
330
|
}
|
|
329
|
-
tokens.push(segmentToken(name))
|
|
331
|
+
tokens.push(segmentToken(name))
|
|
330
332
|
}
|
|
331
|
-
return tokens
|
|
333
|
+
return tokens
|
|
332
334
|
}
|
|
333
335
|
|
|
334
336
|
function segmentToken(name: string): RouteToken {
|
|
335
|
-
const optional = optionalCatchAllName(name)
|
|
336
|
-
if (optional) return { route: `:${optional}*`, pattern: '(.*)', param: optional, catchAll: true }
|
|
337
|
-
const catchAll = catchAllName(name)
|
|
338
|
-
if (catchAll) return { route: `:${catchAll}*`, pattern: '(.*)', param: catchAll, catchAll: true }
|
|
339
|
-
const param = dynamicParamName(name)
|
|
340
|
-
if (param) return { route: `:${param}`, pattern: '([^/]+)', param }
|
|
341
|
-
return { route: name, pattern: escapeRegex(name) }
|
|
337
|
+
const optional = optionalCatchAllName(name)
|
|
338
|
+
if (optional) return { route: `:${optional}*`, pattern: '(.*)', param: optional, catchAll: true }
|
|
339
|
+
const catchAll = catchAllName(name)
|
|
340
|
+
if (catchAll) return { route: `:${catchAll}*`, pattern: '(.*)', param: catchAll, catchAll: true }
|
|
341
|
+
const param = dynamicParamName(name)
|
|
342
|
+
if (param) return { route: `:${param}`, pattern: '([^/]+)', param }
|
|
343
|
+
return { route: name, pattern: escapeRegex(name) }
|
|
342
344
|
}
|
|
343
345
|
|
|
344
346
|
/**
|
|
@@ -352,14 +354,14 @@ export function matchSlotInterceptor(
|
|
|
352
354
|
slotDir: string,
|
|
353
355
|
pathname: string,
|
|
354
356
|
): SegmentMatch | null {
|
|
355
|
-
const segments = pathnameSegments(pathname)
|
|
356
|
-
const markerOwner = markerOwnerTokens(appPath, slotDir)
|
|
357
|
+
const segments = pathnameSegments(pathname)
|
|
358
|
+
const markerOwner = markerOwnerTokens(appPath, slotDir)
|
|
357
359
|
if (markerOwner) {
|
|
358
|
-
const params = matchTargetTokens(markerOwner, pathname)
|
|
360
|
+
const params = matchTargetTokens(markerOwner, pathname)
|
|
359
361
|
if (params) {
|
|
360
|
-
const rest = markerOwner.at(-1)?.catchAll ? [] : segments.slice(markerOwner.length)
|
|
361
|
-
const inner = matchSegments(slotDir, rest, { markersAsSegments: true }, params, [])
|
|
362
|
-
if (inner) return inner
|
|
362
|
+
const rest = markerOwner.at(-1)?.catchAll ? [] : segments.slice(markerOwner.length)
|
|
363
|
+
const inner = matchSegments(slotDir, rest, { markersAsSegments: true }, params, [])
|
|
364
|
+
if (inner) return inner
|
|
363
365
|
}
|
|
364
366
|
}
|
|
365
367
|
// Specificity: non-catch-all first, deeper targets first, fewer dynamic
|
|
@@ -369,64 +371,66 @@ export function matchSlotInterceptor(
|
|
|
369
371
|
Number(a.catchAllTail) - Number(b.catchAllTail) ||
|
|
370
372
|
b.targetSegments.length - a.targetSegments.length ||
|
|
371
373
|
a.params.length - b.params.length,
|
|
372
|
-
)
|
|
374
|
+
)
|
|
373
375
|
for (const unit of units) {
|
|
374
|
-
const regex = new RegExp(`^/${unit.targetPattern}(?:/(.*))?$`)
|
|
375
|
-
const match = regex.exec(pathname.replace(/\/+$/, '') || '/')
|
|
376
|
-
if (!match) continue
|
|
377
|
-
const params: Record<string, RouteParamValue> = {}
|
|
376
|
+
const regex = new RegExp(`^/${unit.targetPattern}(?:/(.*))?$`)
|
|
377
|
+
const match = regex.exec(pathname.replace(/\/+$/, '') || '/')
|
|
378
|
+
if (!match) continue
|
|
379
|
+
const params: Record<string, RouteParamValue> = {}
|
|
378
380
|
unit.params.forEach((param, index) => {
|
|
379
|
-
const value = match[index + 1] ?? ''
|
|
381
|
+
const value = match[index + 1] ?? ''
|
|
380
382
|
params[param.name] = param.catchAll
|
|
381
383
|
? value.split('/').filter(Boolean).map(safeDecode)
|
|
382
|
-
: safeDecode(value)
|
|
383
|
-
})
|
|
384
|
-
const rest = unit.catchAllTail ? [] : segments.slice(unit.targetSegments.length)
|
|
385
|
-
const inner = matchSegments(unit.dir, rest, { markersAsSegments: true }, params, [])
|
|
384
|
+
: safeDecode(value)
|
|
385
|
+
})
|
|
386
|
+
const rest = unit.catchAllTail ? [] : segments.slice(unit.targetSegments.length)
|
|
387
|
+
const inner = matchSegments(unit.dir, rest, { markersAsSegments: true }, params, [])
|
|
386
388
|
if (inner) {
|
|
387
389
|
return {
|
|
388
390
|
file: inner.file,
|
|
389
391
|
dirs: [path.basename(unit.dir), ...inner.dirs],
|
|
390
392
|
params: inner.params,
|
|
391
|
-
}
|
|
393
|
+
}
|
|
392
394
|
}
|
|
393
395
|
}
|
|
394
|
-
return null
|
|
396
|
+
return null
|
|
395
397
|
}
|
|
396
398
|
|
|
397
399
|
function markerOwnerTokens(appPath: string, slotDir: string): RouteToken[] | null {
|
|
398
|
-
const relative = path.relative(appPath, slotDir)
|
|
399
|
-
if (relative.startsWith('..')) return null
|
|
400
|
-
const segments = toPosixPath(relative).split('/').filter(Boolean)
|
|
401
|
-
const markerIndex = segments.findIndex(segment => Boolean(interceptionMarkerOf(segment)))
|
|
402
|
-
if (markerIndex === -1) return null
|
|
403
|
-
return
|
|
400
|
+
const relative = path.relative(appPath, slotDir)
|
|
401
|
+
if (relative.startsWith('..')) return null
|
|
402
|
+
const segments = toPosixPath(relative).split('/').filter(Boolean)
|
|
403
|
+
const markerIndex = segments.findIndex(segment => Boolean(interceptionMarkerOf(segment)))
|
|
404
|
+
if (markerIndex === -1) return null
|
|
405
|
+
return (
|
|
406
|
+
routeTokensForDir(appPath, path.join(appPath, ...segments.slice(0, markerIndex + 1))) ?? null
|
|
407
|
+
)
|
|
404
408
|
}
|
|
405
409
|
|
|
406
410
|
function matchTargetTokens(
|
|
407
411
|
tokens: RouteToken[],
|
|
408
412
|
pathname: string,
|
|
409
413
|
): Record<string, RouteParamValue> | null {
|
|
410
|
-
const pattern = tokens.map(token => token.pattern).join('/')
|
|
411
|
-
const regex = new RegExp(`^/${pattern}(?:/.*)?$`)
|
|
412
|
-
const match = regex.exec(pathname.replace(/\/+$/, '') || '/')
|
|
413
|
-
if (!match) return null
|
|
414
|
-
const params: Record<string, RouteParamValue> = {}
|
|
414
|
+
const pattern = tokens.map(token => token.pattern).join('/')
|
|
415
|
+
const regex = new RegExp(`^/${pattern}(?:/.*)?$`)
|
|
416
|
+
const match = regex.exec(pathname.replace(/\/+$/, '') || '/')
|
|
417
|
+
if (!match) return null
|
|
418
|
+
const params: Record<string, RouteParamValue> = {}
|
|
415
419
|
tokens
|
|
416
420
|
.filter(token => token.param)
|
|
417
421
|
.forEach((token, index) => {
|
|
418
|
-
const value = match[index + 1] ?? ''
|
|
422
|
+
const value = match[index + 1] ?? ''
|
|
419
423
|
params[token.param!] = token.catchAll
|
|
420
424
|
? value.split('/').filter(Boolean).map(safeDecode)
|
|
421
|
-
: safeDecode(value)
|
|
422
|
-
})
|
|
423
|
-
return params
|
|
425
|
+
: safeDecode(value)
|
|
426
|
+
})
|
|
427
|
+
return params
|
|
424
428
|
}
|
|
425
429
|
|
|
426
430
|
export function pathnameSegments(pathname: string) {
|
|
427
|
-
return pathname.split('?')[0]!.split('/').filter(Boolean)
|
|
431
|
+
return pathname.split('?')[0]!.split('/').filter(Boolean)
|
|
428
432
|
}
|
|
429
433
|
|
|
430
434
|
function escapeRegex(value: string) {
|
|
431
|
-
return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
|
|
435
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
|
|
432
436
|
}
|