@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
|
@@ -7,67 +7,67 @@
|
|
|
7
7
|
//
|
|
8
8
|
// A pure-core app registers none of these, so its route scan discovers only the generic conventions.
|
|
9
9
|
|
|
10
|
-
import type { ResolvedConfig } from '../../config'
|
|
10
|
+
import type { ResolvedConfig } from '../../config'
|
|
11
11
|
import {
|
|
12
12
|
registerAlwaysClientEntryReason,
|
|
13
13
|
registerClientEntryDetectors,
|
|
14
14
|
registerRouteDependencyClassifiers,
|
|
15
15
|
registerRouteConventions,
|
|
16
16
|
registerUsageDetectors,
|
|
17
|
-
} from '../../extensions'
|
|
18
|
-
import { nextCompatEnabled } from '../../compat'
|
|
19
|
-
import { escapeRegex } from '../../utils/
|
|
17
|
+
} from '../../extensions'
|
|
18
|
+
import { nextCompatEnabled } from '../../compat/aliases'
|
|
19
|
+
import { escapeRegex } from '../../utils/code'
|
|
20
20
|
|
|
21
21
|
export function registerRoutingExtensions(config: ResolvedConfig): void {
|
|
22
|
-
if (!nextCompatEnabled(config)) return
|
|
22
|
+
if (!nextCompatEnabled(config)) return
|
|
23
23
|
// Next's experimental authInterrupts boundaries mirror error/not-found.
|
|
24
24
|
registerRouteConventions(
|
|
25
25
|
{ name: 'forbidden', boundary: true },
|
|
26
26
|
{ name: 'unauthorized', boundary: true },
|
|
27
|
-
)
|
|
28
|
-
registerUsageDetectors(usesNextRequestImport, usesNextServerConnection)
|
|
29
|
-
registerRouteDependencyClassifiers(classifyNextRouteDependencies)
|
|
27
|
+
)
|
|
28
|
+
registerUsageDetectors(usesNextRequestImport, usesNextServerConnection)
|
|
29
|
+
registerRouteDependencyClassifiers(classifyNextRouteDependencies)
|
|
30
30
|
registerClientEntryDetectors(
|
|
31
31
|
{ reason: 'actions', detect: usesServerActionForm },
|
|
32
32
|
{ reason: 'form', detect: usesNextForm },
|
|
33
33
|
{ reason: 'control-flow', detect: usesClientControlFlowThrow },
|
|
34
|
-
)
|
|
34
|
+
)
|
|
35
35
|
// Next emits its app-router bootstrap for every app page, so every document
|
|
36
36
|
// hydrates — instrumentation-client runs before hydration and the hydration
|
|
37
37
|
// timestamp exists even on a page with no client components at all
|
|
38
38
|
// (instrumentation-client-hook asserts both). Core keeps its leaner default.
|
|
39
|
-
registerAlwaysClientEntryReason('compat-parity')
|
|
39
|
+
registerAlwaysClientEntryReason('compat-parity')
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
// A route's layout chain is re-classified for every route below it, and the answer depends only on
|
|
43
43
|
// the source and the route kind - memoize on exactly that.
|
|
44
|
-
const classificationCache = new Map<string, boolean>()
|
|
44
|
+
const classificationCache = new Map<string, boolean>()
|
|
45
45
|
|
|
46
46
|
function classifyNextRouteDependencies({
|
|
47
47
|
kind,
|
|
48
48
|
files,
|
|
49
49
|
}: import('../../extensions').RouteDependencyContext) {
|
|
50
50
|
for (const { source } of files) {
|
|
51
|
-
const key = `${kind}\0${source.length}\0${Bun.hash(source).toString()}
|
|
52
|
-
let usesRequest = classificationCache.get(key)
|
|
51
|
+
const key = `${kind}\0${source.length}\0${Bun.hash(source).toString()}`
|
|
52
|
+
let usesRequest = classificationCache.get(key)
|
|
53
53
|
if (usesRequest === undefined) {
|
|
54
|
-
usesRequest = sourceUsesRequest(kind, source)
|
|
55
|
-
classificationCache.set(key, usesRequest)
|
|
54
|
+
usesRequest = sourceUsesRequest(kind, source)
|
|
55
|
+
classificationCache.set(key, usesRequest)
|
|
56
56
|
}
|
|
57
|
-
if (usesRequest) return { usesRequest: true }
|
|
57
|
+
if (usesRequest) return { usesRequest: true }
|
|
58
58
|
}
|
|
59
|
-
return undefined
|
|
59
|
+
return undefined
|
|
60
60
|
}
|
|
61
61
|
|
|
62
62
|
function sourceUsesRequest(kind: 'page' | 'handler', source: string): boolean {
|
|
63
|
-
const requestUse = usesNextRequestImport(source) || usesNextServerConnection(source)
|
|
64
|
-
const afterOnly = hasAfterCallbacks(source) && !hasRequestApiOutsideAfter(source)
|
|
65
|
-
const handlerAfterDraftMode = kind === 'handler' && hasAfterDraftMode(source)
|
|
63
|
+
const requestUse = usesNextRequestImport(source) || usesNextServerConnection(source)
|
|
64
|
+
const afterOnly = hasAfterCallbacks(source) && !hasRequestApiOutsideAfter(source)
|
|
65
|
+
const handlerAfterDraftMode = kind === 'handler' && hasAfterDraftMode(source)
|
|
66
66
|
|
|
67
67
|
// Page after() callbacks run after their render scope has detached, so an
|
|
68
68
|
// API used only there does not make the page dynamic. Handler callbacks
|
|
69
69
|
// retain the request scope and must render per request instead.
|
|
70
|
-
if ((requestUse && (kind === 'handler' || !afterOnly)) || handlerAfterDraftMode) return true
|
|
70
|
+
if ((requestUse && (kind === 'handler' || !afterOnly)) || handlerAfterDraftMode) return true
|
|
71
71
|
// An automatic page that schedules after() work needs a request lifecycle to flush it after the
|
|
72
72
|
// response. Explicit static segment config still wins in core's mode inference: the page is statically
|
|
73
73
|
// prerendered and its after() runs during the build prerender, so it must NOT be forced dynamic here.
|
|
@@ -80,72 +80,74 @@ function sourceUsesRequest(kind: 'page' | 'handler', source: string): boolean {
|
|
|
80
80
|
!hasRequestApiUse(source) &&
|
|
81
81
|
!hasAfterDraftMode(source) &&
|
|
82
82
|
!hasExplicitStaticDynamic(source)
|
|
83
|
-
)
|
|
83
|
+
)
|
|
84
84
|
}
|
|
85
85
|
|
|
86
86
|
function hasAfterDraftMode(source: string): boolean {
|
|
87
|
-
return hasAfterCallbacks(source) && nextHeadersBindings(source).draftMode.length > 0
|
|
87
|
+
return hasAfterCallbacks(source) && nextHeadersBindings(source).draftMode.length > 0
|
|
88
88
|
}
|
|
89
89
|
|
|
90
90
|
function hasRequestApiOutsideAfter(source: string): boolean {
|
|
91
|
-
return hasRequestApiUse(withoutAfterCallbacks(source))
|
|
91
|
+
return hasRequestApiUse(withoutAfterCallbacks(source))
|
|
92
92
|
}
|
|
93
93
|
|
|
94
94
|
function hasRequestApiUse(source: string): boolean {
|
|
95
|
-
const outside = stripCommentsAndStrings(source)
|
|
96
|
-
const headers = nextHeadersBindings(source)
|
|
95
|
+
const outside = stripCommentsAndStrings(source)
|
|
96
|
+
const headers = nextHeadersBindings(source)
|
|
97
97
|
return (
|
|
98
98
|
headers.headers.some(name => new RegExp(`\\b${escapeRegex(name)}\\s*\\(`).test(outside)) ||
|
|
99
99
|
headers.cookies.some(name => new RegExp(`\\b${escapeRegex(name)}\\s*\\(`).test(outside)) ||
|
|
100
|
-
connectionBindings(source).some(name =>
|
|
101
|
-
|
|
100
|
+
connectionBindings(source).some(name =>
|
|
101
|
+
new RegExp(`\\b${escapeRegex(name)}\\s*\\(`).test(outside),
|
|
102
|
+
)
|
|
103
|
+
)
|
|
102
104
|
}
|
|
103
105
|
|
|
104
106
|
function nextHeadersBindings(source: string) {
|
|
105
|
-
const headers: string[] = []
|
|
106
|
-
const cookies: string[] = []
|
|
107
|
-
const draftMode: string[] = []
|
|
108
|
-
const pattern = /\bimport\s+\{([^}]*)\}\s+from\s*['"]next\/headers(?:\.js)?['"]/g
|
|
109
|
-
let match: RegExpExecArray | null
|
|
107
|
+
const headers: string[] = []
|
|
108
|
+
const cookies: string[] = []
|
|
109
|
+
const draftMode: string[] = []
|
|
110
|
+
const pattern = /\bimport\s+\{([^}]*)\}\s+from\s*['"]next\/headers(?:\.js)?['"]/g
|
|
111
|
+
let match: RegExpExecArray | null
|
|
110
112
|
while ((match = pattern.exec(stripComments(source)))) {
|
|
111
113
|
for (const item of match[1]!.split(',')) {
|
|
112
|
-
const [imported, local] = item.trim().split(/\s+as\s+/)
|
|
113
|
-
const name = (local ?? imported)?.trim()
|
|
114
|
-
if (!name) continue
|
|
115
|
-
if (imported?.trim() === 'headers') headers.push(name)
|
|
116
|
-
if (imported?.trim() === 'cookies') cookies.push(name)
|
|
117
|
-
if (imported?.trim() === 'draftMode') draftMode.push(name)
|
|
114
|
+
const [imported, local] = item.trim().split(/\s+as\s+/)
|
|
115
|
+
const name = (local ?? imported)?.trim()
|
|
116
|
+
if (!name) continue
|
|
117
|
+
if (imported?.trim() === 'headers') headers.push(name)
|
|
118
|
+
if (imported?.trim() === 'cookies') cookies.push(name)
|
|
119
|
+
if (imported?.trim() === 'draftMode') draftMode.push(name)
|
|
118
120
|
}
|
|
119
121
|
}
|
|
120
|
-
return { headers, cookies, draftMode }
|
|
122
|
+
return { headers, cookies, draftMode }
|
|
121
123
|
}
|
|
122
124
|
|
|
123
125
|
function connectionBindings(source: string): string[] {
|
|
124
|
-
const names: string[] = []
|
|
125
|
-
const pattern = /\bimport\s+[^'";]+?\s+from\s*['"]next\/server(?:\.js)?['"]/g
|
|
126
|
-
let match: RegExpExecArray | null
|
|
126
|
+
const names: string[] = []
|
|
127
|
+
const pattern = /\bimport\s+[^'";]+?\s+from\s*['"]next\/server(?:\.js)?['"]/g
|
|
128
|
+
let match: RegExpExecArray | null
|
|
127
129
|
while ((match = pattern.exec(stripComments(source)))) {
|
|
128
|
-
const named = /\{([^}]*)\}/.exec(match[0])?.[1]
|
|
129
|
-
if (!named) continue
|
|
130
|
+
const named = /\{([^}]*)\}/.exec(match[0])?.[1]
|
|
131
|
+
if (!named) continue
|
|
130
132
|
for (const item of named.split(',')) {
|
|
131
|
-
const [imported, local] = item.trim().split(/\s+as\s+/)
|
|
132
|
-
if (imported?.trim() === 'connection') names.push((local ?? imported).trim())
|
|
133
|
+
const [imported, local] = item.trim().split(/\s+as\s+/)
|
|
134
|
+
if (imported?.trim() === 'connection') names.push((local ?? imported).trim())
|
|
133
135
|
}
|
|
134
136
|
}
|
|
135
|
-
return names
|
|
137
|
+
return names
|
|
136
138
|
}
|
|
137
139
|
|
|
138
140
|
// Masking only blanks comment/string characters, so a source with no `after`
|
|
139
141
|
// token at all cannot grow one — the gate skips the whole-source mask (the
|
|
140
142
|
// common case) without changing a single answer.
|
|
141
|
-
const AFTER_TOKEN = /\bafter\b
|
|
143
|
+
const AFTER_TOKEN = /\bafter\b/
|
|
142
144
|
|
|
143
145
|
function mentionsAfter(source: string): boolean {
|
|
144
|
-
return source.includes('after') && AFTER_TOKEN.test(source)
|
|
146
|
+
return source.includes('after') && AFTER_TOKEN.test(source)
|
|
145
147
|
}
|
|
146
148
|
|
|
147
149
|
function hasAfterCallbacks(source: string): boolean {
|
|
148
|
-
return mentionsAfter(source) && /\bafter\s*\(/.test(maskCommentsAndStrings(source))
|
|
150
|
+
return mentionsAfter(source) && /\bafter\s*\(/.test(maskCommentsAndStrings(source))
|
|
149
151
|
}
|
|
150
152
|
|
|
151
153
|
// Explicit static segment config that keeps a page statically prerenderable
|
|
@@ -154,81 +156,81 @@ function hasAfterCallbacks(source: string): boolean {
|
|
|
154
156
|
function hasExplicitStaticDynamic(source: string): boolean {
|
|
155
157
|
return /\bexport\s+const\s+dynamic\s*=\s*['"](?:error|force-static)['"]/.test(
|
|
156
158
|
stripComments(source),
|
|
157
|
-
)
|
|
159
|
+
)
|
|
158
160
|
}
|
|
159
161
|
|
|
160
162
|
function withoutAfterCallbacks(source: string): string {
|
|
161
|
-
if (!mentionsAfter(source)) return source
|
|
162
|
-
const chars = [...source]
|
|
163
|
-
const searchable = maskCommentsAndStrings(source)
|
|
164
|
-
const pattern = /\bafter\s*\(/g
|
|
165
|
-
let match: RegExpExecArray | null
|
|
163
|
+
if (!mentionsAfter(source)) return source
|
|
164
|
+
const chars = [...source]
|
|
165
|
+
const searchable = maskCommentsAndStrings(source)
|
|
166
|
+
const pattern = /\bafter\s*\(/g
|
|
167
|
+
let match: RegExpExecArray | null
|
|
166
168
|
while ((match = pattern.exec(searchable))) {
|
|
167
|
-
let depth = 1
|
|
168
|
-
let index = match.index + match[0].length
|
|
169
|
+
let depth = 1
|
|
170
|
+
let index = match.index + match[0].length
|
|
169
171
|
for (; index < searchable.length && depth > 0; index++) {
|
|
170
|
-
if (searchable[index] === '(') depth
|
|
171
|
-
else if (searchable[index] === ')') depth
|
|
172
|
+
if (searchable[index] === '(') depth++
|
|
173
|
+
else if (searchable[index] === ')') depth--
|
|
172
174
|
}
|
|
173
|
-
if (depth !== 0) continue
|
|
174
|
-
for (let cursor = match.index; cursor < index; cursor++) chars[cursor] = ' '
|
|
175
|
-
pattern.lastIndex = index
|
|
175
|
+
if (depth !== 0) continue
|
|
176
|
+
for (let cursor = match.index; cursor < index; cursor++) chars[cursor] = ' '
|
|
177
|
+
pattern.lastIndex = index
|
|
176
178
|
}
|
|
177
|
-
return chars.join('')
|
|
179
|
+
return chars.join('')
|
|
178
180
|
}
|
|
179
181
|
|
|
180
|
-
const maskCommentsAndStrings = memoizeBySource(maskSource)
|
|
182
|
+
const maskCommentsAndStrings = memoizeBySource(maskSource)
|
|
181
183
|
|
|
182
184
|
function maskSource(source: string): string {
|
|
183
|
-
const chars = [...source]
|
|
184
|
-
let quote: string | undefined
|
|
185
|
-
let lineComment = false
|
|
186
|
-
let blockComment = false
|
|
185
|
+
const chars = [...source]
|
|
186
|
+
let quote: string | undefined
|
|
187
|
+
let lineComment = false
|
|
188
|
+
let blockComment = false
|
|
187
189
|
for (let index = 0; index < chars.length; index++) {
|
|
188
|
-
const char = chars[index]
|
|
189
|
-
const next = chars[index + 1]
|
|
190
|
+
const char = chars[index]!
|
|
191
|
+
const next = chars[index + 1]
|
|
190
192
|
if (lineComment) {
|
|
191
|
-
if (char === '\n') lineComment = false
|
|
192
|
-
else chars[index] = ' '
|
|
193
|
-
continue
|
|
193
|
+
if (char === '\n') lineComment = false
|
|
194
|
+
else chars[index] = ' '
|
|
195
|
+
continue
|
|
194
196
|
}
|
|
195
197
|
if (blockComment) {
|
|
196
|
-
chars[index] = char === '\n' ? '\n' : ' '
|
|
198
|
+
chars[index] = char === '\n' ? '\n' : ' '
|
|
197
199
|
if (char === '*' && next === '/') {
|
|
198
|
-
chars[index + 1] = ' '
|
|
199
|
-
blockComment = false
|
|
200
|
-
index
|
|
200
|
+
chars[index + 1] = ' '
|
|
201
|
+
blockComment = false
|
|
202
|
+
index++
|
|
201
203
|
}
|
|
202
|
-
continue
|
|
204
|
+
continue
|
|
203
205
|
}
|
|
204
206
|
if (quote) {
|
|
205
|
-
chars[index] = char === '\n' ? '\n' : ' '
|
|
207
|
+
chars[index] = char === '\n' ? '\n' : ' '
|
|
206
208
|
if (char === '\\') {
|
|
207
|
-
if (next && next !== '\n') chars[index + 1] = ' '
|
|
208
|
-
index
|
|
209
|
+
if (next && next !== '\n') chars[index + 1] = ' '
|
|
210
|
+
index++
|
|
209
211
|
} else if (char === quote) {
|
|
210
|
-
quote = undefined
|
|
212
|
+
quote = undefined
|
|
211
213
|
}
|
|
212
|
-
continue
|
|
214
|
+
continue
|
|
213
215
|
}
|
|
214
216
|
if (char === '/' && next === '/') {
|
|
215
|
-
chars[index] = chars[index + 1] = ' '
|
|
216
|
-
lineComment = true
|
|
217
|
-
index
|
|
218
|
-
continue
|
|
217
|
+
chars[index] = chars[index + 1] = ' '
|
|
218
|
+
lineComment = true
|
|
219
|
+
index++
|
|
220
|
+
continue
|
|
219
221
|
}
|
|
220
222
|
if (char === '/' && next === '*') {
|
|
221
|
-
chars[index] = chars[index + 1] = ' '
|
|
222
|
-
blockComment = true
|
|
223
|
-
index
|
|
224
|
-
continue
|
|
223
|
+
chars[index] = chars[index + 1] = ' '
|
|
224
|
+
blockComment = true
|
|
225
|
+
index++
|
|
226
|
+
continue
|
|
225
227
|
}
|
|
226
228
|
if (char === '"' || char === "'" || char === '`') {
|
|
227
|
-
chars[index] = ' '
|
|
228
|
-
quote = char
|
|
229
|
+
chars[index] = ' '
|
|
230
|
+
quote = char
|
|
229
231
|
}
|
|
230
232
|
}
|
|
231
|
-
return chars.join('')
|
|
233
|
+
return chars.join('')
|
|
232
234
|
}
|
|
233
235
|
|
|
234
236
|
// A source that declares a server action needs the client action runtime, even
|
|
@@ -236,8 +238,8 @@ function maskSource(source: string): string {
|
|
|
236
238
|
// to. Matched on the RAW source: stripComments also blanks string literals,
|
|
237
239
|
// which would erase the directive being looked for.
|
|
238
240
|
function usesServerActionForm(source: string): boolean {
|
|
239
|
-
if (source.includes('use server') && /(['"])use server\1/.test(source)) return true
|
|
240
|
-
return usesClientFunctionFormAction(source)
|
|
241
|
+
if (source.includes('use server') && /(['"])use server\1/.test(source)) return true
|
|
242
|
+
return usesClientFunctionFormAction(source)
|
|
241
243
|
}
|
|
242
244
|
|
|
243
245
|
// React runs a FUNCTION passed to `<form action>` / `<button formAction>` on the client with the form's
|
|
@@ -245,131 +247,132 @@ function usesServerActionForm(source: string): boolean {
|
|
|
245
247
|
// with no `'use server'` anywhere. Restricted to `'use client'` sources (a server component passing a
|
|
246
248
|
// function needs the directive) and to non-string expressions, so `<form action={url}>` keeps the lean
|
|
247
249
|
// entry.
|
|
248
|
-
const CLIENT_FUNCTION_ACTION_PATTERN = /\b(?:action|formAction)\s*=\s*\{\s*(?!['"`])
|
|
250
|
+
const CLIENT_FUNCTION_ACTION_PATTERN = /\b(?:action|formAction)\s*=\s*\{\s*(?!['"`])/
|
|
249
251
|
|
|
250
252
|
function usesClientFunctionFormAction(source: string): boolean {
|
|
251
|
-
if (!hasUseClientDirective(source)) return false
|
|
252
|
-
return CLIENT_FUNCTION_ACTION_PATTERN.test(stripComments(source))
|
|
253
|
+
if (!hasUseClientDirective(source)) return false
|
|
254
|
+
return CLIENT_FUNCTION_ACTION_PATTERN.test(stripComments(source))
|
|
253
255
|
}
|
|
254
256
|
|
|
255
|
-
const USE_CLIENT_DIRECTIVE =
|
|
257
|
+
const USE_CLIENT_DIRECTIVE =
|
|
258
|
+
/^\s*(?:\/\/[^\n]*\n|\/\*[\s\S]*?\*\/\s*|#![^\n]*\n|\s)*(['"])use client\1/
|
|
256
259
|
|
|
257
260
|
// The prologue regex scans every leading comment; the literal it ends in has to
|
|
258
261
|
// be somewhere in the source for it to match at all.
|
|
259
262
|
function hasUseClientDirective(source: string): boolean {
|
|
260
|
-
return source.includes('use client') && USE_CLIENT_DIRECTIVE.test(source)
|
|
263
|
+
return source.includes('use client') && USE_CLIENT_DIRECTIVE.test(source)
|
|
261
264
|
}
|
|
262
265
|
const CONTROL_FLOW_IMPORT_PATTERN =
|
|
263
|
-
/import\s*\{[^}]*\b(?:notFound|forbidden|unauthorized)\b[^}]*\}\s*from\s*['"]next\/navigation(?:\.js)?['"]
|
|
266
|
+
/import\s*\{[^}]*\b(?:notFound|forbidden|unauthorized)\b[^}]*\}\s*from\s*['"]next\/navigation(?:\.js)?['"]/
|
|
264
267
|
|
|
265
268
|
// A `'use client'` module that throws notFound()/forbidden()/unauthorized() does it during HYDRATION,
|
|
266
269
|
// where only the in-tree ClientErrorBoundary can render the outcome - the deferred window last resort
|
|
267
270
|
// lands at idle, long after the throw has unmounted the SSR tree. Server components keep the lean entry:
|
|
268
271
|
// their throw is resolved by the server render.
|
|
269
272
|
function usesClientControlFlowThrow(source: string): boolean {
|
|
270
|
-
return hasUseClientDirective(source) && CONTROL_FLOW_IMPORT_PATTERN.test(source)
|
|
273
|
+
return hasUseClientDirective(source) && CONTROL_FLOW_IMPORT_PATTERN.test(source)
|
|
271
274
|
}
|
|
272
275
|
|
|
273
|
-
const NEXT_FORM_IMPORT_PATTERN = /import\s+[^'";]*\s+from\s+['"]next\/form(?:\.js)?['"]
|
|
276
|
+
const NEXT_FORM_IMPORT_PATTERN = /import\s+[^'";]*\s+from\s+['"]next\/form(?:\.js)?['"]/
|
|
274
277
|
|
|
275
278
|
function usesNextForm(source: string): boolean {
|
|
276
|
-
if (!source.includes('next/form')) return false
|
|
277
|
-
const searchable = stripComments(source)
|
|
278
|
-
if (!NEXT_FORM_IMPORT_PATTERN.test(searchable)) return false
|
|
279
|
+
if (!source.includes('next/form')) return false
|
|
280
|
+
const searchable = stripComments(source)
|
|
281
|
+
if (!NEXT_FORM_IMPORT_PATTERN.test(searchable)) return false
|
|
279
282
|
return (
|
|
280
283
|
/\b<form\b[^>]*\b(?:action|formAction)\s*=/.test(searchable) ||
|
|
281
284
|
/\bformAction\s*:\s*/.test(searchable) ||
|
|
282
285
|
/<\s*[A-Za-z_$][\w$]*\b[^>]*\b(?:action|formAction)\s*=/.test(searchable)
|
|
283
|
-
)
|
|
286
|
+
)
|
|
284
287
|
}
|
|
285
288
|
|
|
286
289
|
// A next/headers or next/navigation request-hook import makes a route dynamic.
|
|
287
290
|
function usesNextRequestImport(source: string): boolean {
|
|
288
|
-
const withoutComments = stripComments(source)
|
|
291
|
+
const withoutComments = stripComments(source)
|
|
289
292
|
// A `draftMode`-only import of next/headers is not request-bound: Next still
|
|
290
293
|
// fully prerenders such pages (isEnabled is false at build time); only a
|
|
291
294
|
// __prerender_bypass cookie opts into a fresh dynamic render at request time.
|
|
292
295
|
const draftModeOnlyImport =
|
|
293
|
-
/\bimport\s+\{\s*draftMode\s*(?:as\s+[\w$]+\s*)?,?\s*\}\s*from\s*['"]next\/headers(?:\.js)?['"]/g
|
|
296
|
+
/\bimport\s+\{\s*draftMode\s*(?:as\s+[\w$]+\s*)?,?\s*\}\s*from\s*['"]next\/headers(?:\.js)?['"]/g
|
|
294
297
|
return (
|
|
295
298
|
nextHeadersImportPattern().test(withoutComments.replace(draftModeOnlyImport, '')) ||
|
|
296
299
|
importsNextNavigationRequestHook(withoutComments)
|
|
297
|
-
)
|
|
300
|
+
)
|
|
298
301
|
}
|
|
299
302
|
|
|
300
303
|
function nextHeadersImportPattern() {
|
|
301
|
-
return /(?:from\s+|import\s*\()\s*['"]next\/headers(?:\.js)?['"]
|
|
304
|
+
return /(?:from\s+|import\s*\()\s*['"]next\/headers(?:\.js)?['"]/
|
|
302
305
|
}
|
|
303
306
|
|
|
304
307
|
function importsNextNavigationRequestHook(source: string): boolean {
|
|
305
|
-
const importPattern = /\bimport\s+(type\s+)?([^'";]+?)\s+from\s+['"]next\/navigation['"]/g
|
|
306
|
-
let match: RegExpExecArray | null
|
|
308
|
+
const importPattern = /\bimport\s+(type\s+)?([^'";]+?)\s+from\s+['"]next\/navigation['"]/g
|
|
309
|
+
let match: RegExpExecArray | null
|
|
307
310
|
while ((match = importPattern.exec(source))) {
|
|
308
|
-
const [, typeKeyword, clause] = match
|
|
311
|
+
const [, typeKeyword, clause] = match
|
|
309
312
|
if (!typeKeyword && clause && includesRequestNavigationHook(importedExports(clause)))
|
|
310
|
-
return true
|
|
313
|
+
return true
|
|
311
314
|
}
|
|
312
315
|
|
|
313
|
-
const exportPattern = /\bexport\s+(type\s+)?\{([^}]*)\}\s+from\s+['"]next\/navigation['"]/g
|
|
316
|
+
const exportPattern = /\bexport\s+(type\s+)?\{([^}]*)\}\s+from\s+['"]next\/navigation['"]/g
|
|
314
317
|
while ((match = exportPattern.exec(source))) {
|
|
315
|
-
const [, typeKeyword, clause] = match
|
|
316
|
-
if (!typeKeyword && clause && includesRequestNavigationHook(exportedNames(clause))) return true
|
|
318
|
+
const [, typeKeyword, clause] = match
|
|
319
|
+
if (!typeKeyword && clause && includesRequestNavigationHook(exportedNames(clause))) return true
|
|
317
320
|
}
|
|
318
|
-
return false
|
|
321
|
+
return false
|
|
319
322
|
}
|
|
320
323
|
|
|
321
324
|
function usesNextServerConnection(source: string): boolean {
|
|
322
|
-
const withoutComments = stripComments(source)
|
|
323
|
-
const searchable = stripCommentsAndStrings(source)
|
|
324
|
-
const importPattern = /\bimport\s+(type\s+)?([^'";]+?)\s+from\s+['"]next\/server(?:\.js)?['"]/g
|
|
325
|
-
let match: RegExpExecArray | null
|
|
325
|
+
const withoutComments = stripComments(source)
|
|
326
|
+
const searchable = stripCommentsAndStrings(source)
|
|
327
|
+
const importPattern = /\bimport\s+(type\s+)?([^'";]+?)\s+from\s+['"]next\/server(?:\.js)?['"]/g
|
|
328
|
+
let match: RegExpExecArray | null
|
|
326
329
|
while ((match = importPattern.exec(withoutComments))) {
|
|
327
|
-
const [, typeKeyword, clause] = match
|
|
328
|
-
if (typeKeyword || !clause) continue
|
|
330
|
+
const [, typeKeyword, clause] = match
|
|
331
|
+
if (typeKeyword || !clause) continue
|
|
329
332
|
for (const pattern of importedConnectionCallPatterns(clause)) {
|
|
330
|
-
if (pattern.test(searchable)) return true
|
|
333
|
+
if (pattern.test(searchable)) return true
|
|
331
334
|
}
|
|
332
335
|
}
|
|
333
|
-
return false
|
|
336
|
+
return false
|
|
334
337
|
}
|
|
335
338
|
|
|
336
339
|
function importedConnectionCallPatterns(clause: string): RegExp[] {
|
|
337
|
-
const patterns: RegExp[] = []
|
|
338
|
-
const namespace = /\*\s+as\s+([A-Za-z_$][\w$]*)/.exec(clause)?.[1]
|
|
339
|
-
if (namespace) patterns.push(new RegExp(`\\b${escapeRegex(namespace)}\\.connection\\s*\\(`))
|
|
340
|
-
const named = /\{([^}]*)\}/.exec(clause)?.[1]
|
|
340
|
+
const patterns: RegExp[] = []
|
|
341
|
+
const namespace = /\*\s+as\s+([A-Za-z_$][\w$]*)/.exec(clause)?.[1]
|
|
342
|
+
if (namespace) patterns.push(new RegExp(`\\b${escapeRegex(namespace)}\\.connection\\s*\\(`))
|
|
343
|
+
const named = /\{([^}]*)\}/.exec(clause)?.[1]
|
|
341
344
|
if (named) {
|
|
342
345
|
for (const item of named.split(',')) {
|
|
343
|
-
const [imported, local] = item.trim().split(/\s+as\s+/)
|
|
346
|
+
const [imported, local] = item.trim().split(/\s+as\s+/)
|
|
344
347
|
if (imported?.trim() === 'connection') {
|
|
345
|
-
patterns.push(new RegExp(`\\b${escapeRegex((local ?? imported).trim())}\\s*\\(`))
|
|
348
|
+
patterns.push(new RegExp(`\\b${escapeRegex((local ?? imported).trim())}\\s*\\(`))
|
|
346
349
|
}
|
|
347
350
|
}
|
|
348
351
|
}
|
|
349
|
-
return patterns
|
|
352
|
+
return patterns
|
|
350
353
|
}
|
|
351
354
|
|
|
352
355
|
function includesRequestNavigationHook(exports: string[]): boolean {
|
|
353
356
|
return (
|
|
354
357
|
exports.includes('*') || exports.includes('useSearchParams') || exports.includes('useRoute')
|
|
355
|
-
)
|
|
358
|
+
)
|
|
356
359
|
}
|
|
357
360
|
|
|
358
361
|
function importedExports(clause: string): string[] {
|
|
359
|
-
const value = clause.trim()
|
|
360
|
-
if (!value) return []
|
|
361
|
-
const exports = new Set<string>()
|
|
362
|
-
if (value.startsWith('*')) exports.add('*')
|
|
363
|
-
const defaultImport = /^[A-Za-z_$][\w$]*/.exec(value)
|
|
364
|
-
if (defaultImport && !value.startsWith('{') && !value.startsWith('*')) exports.add('default')
|
|
365
|
-
const named = /\{([^}]*)\}/.exec(value)
|
|
362
|
+
const value = clause.trim()
|
|
363
|
+
if (!value) return []
|
|
364
|
+
const exports = new Set<string>()
|
|
365
|
+
if (value.startsWith('*')) exports.add('*')
|
|
366
|
+
const defaultImport = /^[A-Za-z_$][\w$]*/.exec(value)
|
|
367
|
+
if (defaultImport && !value.startsWith('{') && !value.startsWith('*')) exports.add('default')
|
|
368
|
+
const named = /\{([^}]*)\}/.exec(value)
|
|
366
369
|
if (named?.[1]) {
|
|
367
370
|
for (const item of named[1].split(',')) {
|
|
368
|
-
const [name] = item.trim().split(/\s+as\s+/)
|
|
369
|
-
if (name) exports.add(name.trim())
|
|
371
|
+
const [name] = item.trim().split(/\s+as\s+/)
|
|
372
|
+
if (name) exports.add(name.trim())
|
|
370
373
|
}
|
|
371
374
|
}
|
|
372
|
-
return [...exports]
|
|
375
|
+
return [...exports]
|
|
373
376
|
}
|
|
374
377
|
|
|
375
378
|
function exportedNames(clause: string): string[] {
|
|
@@ -381,7 +384,7 @@ function exportedNames(clause: string): string[] {
|
|
|
381
384
|
.split(/\s+as\s+/)[0]
|
|
382
385
|
?.trim(),
|
|
383
386
|
)
|
|
384
|
-
.filter((name): name is string => Boolean(name) && name !== 'type')
|
|
387
|
+
.filter((name): name is string => Boolean(name) && name !== 'type')
|
|
385
388
|
}
|
|
386
389
|
|
|
387
390
|
/**
|
|
@@ -390,21 +393,21 @@ function exportedNames(clause: string): string[] {
|
|
|
390
393
|
* each; the key is the source itself, so it never stales.
|
|
391
394
|
*/
|
|
392
395
|
function memoizeBySource(derive: (source: string) => string) {
|
|
393
|
-
const cache = new Map<string, string>()
|
|
396
|
+
const cache = new Map<string, string>()
|
|
394
397
|
return (source: string): string => {
|
|
395
|
-
const hit = cache.get(source)
|
|
396
|
-
if (hit !== undefined) return hit
|
|
397
|
-
const value = derive(source)
|
|
398
|
-
if (cache.size >= 4) cache.delete(cache.keys().next().value!)
|
|
399
|
-
cache.set(source, value)
|
|
400
|
-
return value
|
|
401
|
-
}
|
|
398
|
+
const hit = cache.get(source)
|
|
399
|
+
if (hit !== undefined) return hit
|
|
400
|
+
const value = derive(source)
|
|
401
|
+
if (cache.size >= 4) cache.delete(cache.keys().next().value!)
|
|
402
|
+
cache.set(source, value)
|
|
403
|
+
return value
|
|
404
|
+
}
|
|
402
405
|
}
|
|
403
406
|
|
|
404
407
|
const stripCommentsAndStrings = memoizeBySource(source =>
|
|
405
408
|
stripComments(source).replace(/(['"`])(?:\\[\s\S]|(?!\1)[^\\])*\1/g, ''),
|
|
406
|
-
)
|
|
409
|
+
)
|
|
407
410
|
|
|
408
411
|
const stripComments = memoizeBySource(source =>
|
|
409
412
|
source.replace(/\/\*[\s\S]*?\*\//g, '').replace(/(^|[^:])\/\/.*$/gm, '$1'),
|
|
410
|
-
)
|
|
413
|
+
)
|