@wular/pnext 0.1.5 → 0.1.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/bin/pnext +9 -2
- package/dist/server/_chunks/aliases-j47a10ce.js +44 -0
- package/dist/server/_chunks/analyze-arswqe6s.js +445 -0
- package/dist/server/_chunks/boot-af0mv3dy.js +36 -0
- package/dist/server/_chunks/build-spy3dxp4.js +84 -0
- package/dist/server/_chunks/build-t9h0hec3.js +3550 -0
- package/dist/server/_chunks/build-tier-m7yvqz61.js +2472 -0
- package/dist/server/_chunks/compile-53j02j27.js +22 -0
- package/dist/server/_chunks/config-1yzwexq6.js +27 -0
- package/dist/server/_chunks/config-n2z7yxps.js +22 -0
- package/dist/server/_chunks/create-meec9hs6.js +134 -0
- package/dist/server/_chunks/dev-fjmqg6en.js +220 -0
- package/dist/server/_chunks/esbuild-yyktfrtt.js +15 -0
- package/dist/server/_chunks/generate-n9sh6hzt.js +21 -0
- package/dist/server/_chunks/index-0374j2b9.js +66 -0
- package/dist/server/_chunks/index-06nyqntx.js +213 -0
- package/dist/server/_chunks/index-1011cscr.js +5263 -0
- package/dist/server/_chunks/index-11sfk4hb.js +170 -0
- package/dist/server/_chunks/index-20ppawv7.js +297 -0
- package/dist/server/_chunks/index-2dv4y4wd.js +1065 -0
- package/dist/server/_chunks/index-2vz0wzdn.js +59 -0
- package/dist/server/_chunks/index-2wfv4kvx.js +182 -0
- package/dist/server/_chunks/index-357na4a8.js +109 -0
- package/dist/server/_chunks/index-3b3at80h.js +109 -0
- package/dist/server/_chunks/index-3tf1xjsp.js +6166 -0
- package/dist/server/_chunks/index-3xbr4eyv.js +105 -0
- package/dist/server/_chunks/index-4399bvd2.js +18 -0
- package/dist/server/_chunks/index-4hgjrqh7.js +851 -0
- package/dist/server/_chunks/index-4q2gbfwk.js +2530 -0
- package/dist/server/_chunks/index-4t92hdxd.js +172 -0
- package/dist/server/_chunks/index-4zzebszd.js +10 -0
- package/dist/server/_chunks/index-5gyr4emz.js +107 -0
- package/dist/server/_chunks/index-5hr4062s.js +70 -0
- package/dist/server/_chunks/index-68m3mwbd.js +84 -0
- package/dist/server/_chunks/index-6b009mt0.js +56 -0
- package/dist/server/_chunks/index-6e4fqv30.js +588 -0
- package/dist/server/_chunks/index-6gex3pfa.js +15 -0
- package/dist/server/_chunks/index-6kp9r0d9.js +11 -0
- package/dist/server/_chunks/index-6q7zvrap.js +134 -0
- package/dist/server/_chunks/index-73z4esab.js +38 -0
- package/dist/server/_chunks/index-79ngvam8.js +60 -0
- package/dist/server/_chunks/index-7wc9n8be.js +25 -0
- package/dist/server/_chunks/index-8k7pfejn.js +1599 -0
- package/dist/server/_chunks/index-8kcxdfya.js +206 -0
- package/dist/server/_chunks/index-91x12ykq.js +274 -0
- package/dist/server/_chunks/index-9ch50vtq.js +18 -0
- package/dist/server/_chunks/index-9hx2641q.js +28 -0
- package/dist/server/_chunks/index-9n2914ww.js +535 -0
- package/dist/server/_chunks/index-9ych9ma8.js +207 -0
- package/dist/server/_chunks/index-b6wtkdp4.js +24 -0
- package/dist/server/_chunks/index-bcws5eh2.js +35 -0
- package/dist/server/_chunks/index-c0g2wf3z.js +92 -0
- package/dist/server/_chunks/index-cf4rvxv6.js +95 -0
- package/dist/server/_chunks/index-cjgqs13g.js +65 -0
- package/dist/server/_chunks/index-ckkdpht5.js +41 -0
- package/dist/server/_chunks/index-cyfednwb.js +87 -0
- package/dist/server/_chunks/index-danncfhy.js +311 -0
- package/dist/server/_chunks/index-dg0f05zs.js +199 -0
- package/dist/server/_chunks/index-e3a6yx84.js +18 -0
- package/dist/server/_chunks/index-e88tyv35.js +45 -0
- package/dist/server/_chunks/index-eajaspjk.js +1253 -0
- package/dist/server/_chunks/index-eeaanp2e.js +483 -0
- package/dist/server/_chunks/index-egykcqg3.js +101 -0
- package/dist/server/_chunks/index-en7n9f7m.js +22 -0
- package/dist/server/_chunks/index-ezgj0tr1.js +88 -0
- package/dist/server/_chunks/index-fkp000p1.js +590 -0
- package/dist/server/_chunks/index-fn1chkkd.js +214 -0
- package/dist/server/_chunks/index-fp8r0sqs.js +64 -0
- package/dist/server/_chunks/index-ggk2j965.js +9432 -0
- package/dist/server/_chunks/index-grta8ap3.js +238 -0
- package/dist/server/_chunks/index-h2a70tg4.js +7 -0
- package/dist/server/_chunks/index-h4xy648y.js +51 -0
- package/dist/server/_chunks/index-hkdfj58q.js +92 -0
- package/dist/server/_chunks/index-j2zrcp1k.js +66 -0
- package/dist/server/_chunks/index-jcsjq3d1.js +20 -0
- package/dist/server/_chunks/index-jepjvcrf.js +198 -0
- package/dist/server/_chunks/index-jks0x0a1.js +14 -0
- package/dist/server/_chunks/index-jx7bqvw1.js +57 -0
- package/dist/server/_chunks/index-k1g3epw0.js +1299 -0
- package/dist/server/_chunks/index-knp0s912.js +7 -0
- package/dist/server/_chunks/index-kq8kpzye.js +472 -0
- package/dist/server/_chunks/index-kqyy1d4f.js +50 -0
- package/dist/server/_chunks/index-kresp2n8.js +445 -0
- package/dist/server/_chunks/index-ms9v9tnx.js +31 -0
- package/dist/server/_chunks/index-n4hxpng2.js +11 -0
- package/dist/server/_chunks/index-ncnes8c6.js +17 -0
- package/dist/server/_chunks/index-nqh3xhdc.js +57 -0
- package/dist/server/_chunks/index-nyrba2kr.js +4130 -0
- package/dist/server/_chunks/index-p77b4kcx.js +296 -0
- package/dist/server/_chunks/index-pym1cezq.js +39 -0
- package/dist/server/_chunks/index-q738kkhj.js +100 -0
- package/dist/server/_chunks/index-qjj6gddn.js +54 -0
- package/dist/server/_chunks/index-qm6kmhqs.js +110 -0
- package/dist/server/_chunks/index-qn4z5s3c.js +819 -0
- package/dist/server/_chunks/index-qpwsgt3a.js +158 -0
- package/dist/server/_chunks/index-r97ptz1q.js +97 -0
- package/dist/server/_chunks/index-ras0sdab.js +26 -0
- package/dist/server/_chunks/index-rcs322t1.js +19 -0
- package/dist/server/_chunks/index-rn8dyr1f.js +126 -0
- package/dist/server/_chunks/index-rt9qq1va.js +4 -0
- package/dist/server/_chunks/index-rthrsed5.js +356 -0
- package/dist/server/_chunks/index-sctcgyvv.js +185 -0
- package/dist/server/_chunks/index-sjpckxqn.js +213 -0
- package/dist/server/_chunks/index-sq3kvz3g.js +200 -0
- package/dist/server/_chunks/index-stbk3jhn.js +31 -0
- package/dist/server/_chunks/index-sv8m6789.js +266 -0
- package/dist/server/_chunks/index-tgcakdxc.js +125 -0
- package/dist/server/_chunks/index-tgsfjmep.js +74 -0
- package/dist/server/_chunks/index-tq0pc7eg.js +154 -0
- package/dist/server/_chunks/index-tq1f96v7.js +51 -0
- package/dist/server/_chunks/index-tqn2qnnn.js +241 -0
- package/dist/server/_chunks/index-tvqkq6e6.js +128 -0
- package/dist/server/_chunks/index-v1ags1na.js +132 -0
- package/dist/server/_chunks/index-vvmmknm1.js +1431 -0
- package/dist/server/_chunks/index-vvq7rqtn.js +329 -0
- package/dist/server/_chunks/index-vz0km5qk.js +33 -0
- package/dist/server/_chunks/index-w6h8m6vp.js +138 -0
- package/dist/server/_chunks/index-web361b8.js +138 -0
- package/dist/server/_chunks/index-wpfhfbs4.js +194 -0
- package/dist/server/_chunks/index-x0y005nh.js +283 -0
- package/dist/server/_chunks/index-x3yn4ywm.js +22 -0
- package/dist/server/_chunks/index-x93hv0sc.js +271 -0
- package/dist/server/_chunks/index-xvj80c3a.js +30 -0
- package/dist/server/_chunks/index-xywjg2vc.js +100 -0
- package/dist/server/_chunks/index-y2jr2n72.js +152 -0
- package/dist/server/_chunks/index-y36a0ybw.js +57 -0
- package/dist/server/_chunks/index-ye9hmsvf.js +47 -0
- package/dist/server/_chunks/index-yhxkxghe.js +56 -0
- package/dist/server/_chunks/index-ym67zqxp.js +130 -0
- package/dist/server/_chunks/index-ytjvpbm2.js +736 -0
- package/dist/server/_chunks/index-yz54pxrh.js +960 -0
- package/dist/server/_chunks/index-z4z9zv3b.js +733 -0
- package/dist/server/_chunks/index-z84ab1w0.js +1270 -0
- package/dist/server/_chunks/index-z88qv16t.js +11 -0
- package/dist/server/_chunks/index-zqpqyg8p.js +666 -0
- package/dist/server/_chunks/loader-7yw0j98z.js +78 -0
- package/dist/server/_chunks/modules-jn8bmbn8.js +74 -0
- package/dist/server/_chunks/pipeline-yy9jhydf.js +832 -0
- package/dist/server/_chunks/production-jar9ztm3.js +44 -0
- package/dist/server/_chunks/proxy-config-j84dgksn.js +21 -0
- package/dist/server/_chunks/proxy-w1d0wmsn.js +33 -0
- package/dist/server/_chunks/router-k1reahfn.js +498 -0
- package/dist/server/_chunks/routes-2s277fc6.js +64 -0
- package/dist/server/_chunks/run-pvd8bs1t.js +696 -0
- package/dist/server/_chunks/server-mt4a994c.js +1835 -0
- package/dist/server/_chunks/tsconfig-defaults-1nb3308g.js +20 -0
- package/dist/server/_chunks/typegen-0qr0459b.js +35 -0
- package/dist/server/api/client-cache.js +14 -0
- package/dist/server/cli/index.js +378 -0
- package/dist/server/cli/start.js +137 -0
- package/dist/server/client/reference.js +16 -0
- package/dist/server/compat/next/cache.js +56 -0
- package/dist/server/compat/next/canonical-url.js +13 -0
- package/dist/server/compat/next/client-cache.js +57 -0
- package/dist/server/compat/next/client-navigation.js +232 -0
- package/dist/server/compat/next/client-only.js +1 -0
- package/dist/server/compat/next/client-script.js +178 -0
- package/dist/server/compat/next/client-server.js +34 -0
- package/dist/server/compat/next/config-headers.js +32 -0
- package/dist/server/compat/next/config-loader.js +25 -0
- package/dist/server/compat/next/config.js +10 -0
- package/dist/server/compat/next/constants.js +18 -0
- package/dist/server/compat/next/custom-server.js +10 -0
- package/dist/server/compat/next/dist/client/components/app-router-headers.js +48 -0
- package/dist/server/compat/next/dist/server/web/spec-extension/revalidate.js +27 -0
- package/dist/server/compat/next/dist/server/web/spec-extension/unstable-cache.js +25 -0
- package/dist/server/compat/next/dist/server/web/spec-extension/unstable-no-store.js +25 -0
- package/dist/server/compat/next/dynamic.js +32 -0
- package/dist/server/compat/next/error.js +112 -0
- package/dist/server/compat/next/font/cache.js +14 -0
- package/dist/server/compat/next/font/google.js +3 -0
- package/dist/server/compat/next/font/index.js +1 -0
- package/dist/server/compat/next/font/local.js +22 -0
- package/dist/server/compat/next/font/runtime-client.js +33 -0
- package/dist/server/compat/next/font/runtime.js +41 -0
- package/dist/server/compat/next/font/shared.js +22 -0
- package/dist/server/compat/next/form.js +129 -0
- package/dist/server/compat/next/head.js +10 -0
- package/dist/server/compat/next/headers.js +30 -0
- package/dist/server/compat/next/image/client.js +11 -0
- package/dist/server/compat/next/image/config.js +18 -0
- package/dist/server/compat/next/image/optimizer.js +25 -0
- package/dist/server/compat/next/image/patterns.js +12 -0
- package/dist/server/compat/next/image/props.js +16 -0
- package/dist/server/compat/next/image/shared.js +86 -0
- package/dist/server/compat/next/image/static-metadata.js +32 -0
- package/dist/server/compat/next/image/validate.js +8 -0
- package/dist/server/compat/next/image.js +59 -0
- package/dist/server/compat/next/index.js +1 -0
- package/dist/server/compat/next/legacy-image.js +78 -0
- package/dist/server/compat/next/legacy-request-apis.js +24 -0
- package/dist/server/compat/next/link-transform.js +14 -0
- package/dist/server/compat/next/link.js +14 -0
- package/dist/server/compat/next/navigation.js +190 -0
- package/dist/server/compat/next/offline.js +45 -0
- package/dist/server/compat/next/og.js +8 -0
- package/dist/server/compat/next/preferred-region.js +8 -0
- package/dist/server/compat/next/redirects.js +30 -0
- package/dist/server/compat/next/resource-hints.js +30 -0
- package/dist/server/compat/next/rewrites.js +41 -0
- package/dist/server/compat/next/root-params.js +121 -0
- package/dist/server/compat/next/route-state.js +23 -0
- package/dist/server/compat/next/router.js +103 -0
- package/dist/server/compat/next/script.js +37 -0
- package/dist/server/compat/next/server-only.js +1 -0
- package/dist/server/compat/next/server.js +131 -0
- package/dist/server/compat/next/svgr.js +14 -0
- package/dist/server/compat/next/telemetry.js +10 -0
- package/dist/server/compat/next/usage.js +13 -0
- package/dist/server/compat/next/user-agent.js +12 -0
- package/dist/server/compat/next/web-vitals.js +35 -0
- package/dist/server/compat/react/action-state.js +11 -0
- package/dist/server/compat/react/client-lite.js +83 -0
- package/dist/server/compat/react/client.js +131 -0
- package/dist/server/compat/react/compiler-runtime.js +42 -0
- package/dist/server/compat/react/dom-client.js +106 -0
- package/dist/server/compat/react/dom-react-server.js +37 -0
- package/dist/server/compat/react/dom-server.js +40 -0
- package/dist/server/compat/react/dom.js +52 -0
- package/dist/server/compat/react/hooks-extra.js +12 -0
- package/dist/server/compat/react/internals.js +14 -0
- package/dist/server/compat/react/parity.js +11 -0
- package/dist/server/compat/react/preact.js +113 -0
- package/dist/server/compat/react/react-server.js +133 -0
- package/dist/server/compat/react/router-shim.js +8 -0
- package/dist/server/compat/react/server-component-use.js +14 -0
- package/dist/server/compat/react/server-inserted-html.js +14 -0
- package/dist/server/compat/react/server.js +194 -0
- package/dist/server/compat/react/style-values.js +10 -0
- package/dist/server/compat/react/use.js +10 -0
- package/dist/server/compat/react/view-transition.js +12 -0
- package/dist/server/generation.json +1 -0
- package/package.json +4 -1
- package/src/api/dynamic.tsx +2 -0
- package/src/api/server.ts +24 -6
- package/src/cli/adapters/vercel-warm.ts +315 -61
- package/src/cli/adapters/vercel.ts +348 -71
- package/src/cli/build.ts +58 -33
- package/src/cli/index.ts +23 -10
- package/src/cli/serve/entry.ts +21 -159
- package/src/cli/serve/immutable.ts +31 -0
- package/src/cli/serve/pipeline.ts +82 -84
- package/src/cli/start.ts +3 -1
- package/src/client/chunk-fold.ts +19 -6
- package/src/client/react-tier.ts +3 -2
- package/src/client/reference-stub.ts +21 -2
- package/src/compat/actions/client-plugin.ts +4 -2
- package/src/compat/actions/config.ts +6 -5
- package/src/compat/actions/extensions.ts +2 -3
- package/src/compat/aliases.ts +8 -1
- package/src/compat/bundler/config.ts +88 -0
- package/src/compat/bundler/optimize-package-imports.ts +86 -26
- package/src/compat/bundler/relay-transform.ts +15 -3
- package/src/compat/cache-control.ts +16 -8
- package/src/compat/css/modules.ts +18 -5
- package/src/compat/lifecycle/error-funnel.ts +1 -1
- package/src/compat/lifecycle/instrumentation.ts +117 -24
- package/src/compat/lifecycle/testmode.ts +3 -2
- package/src/compat/next/config-loader.ts +137 -13
- package/src/compat/next/font/runtime.ts +22 -2
- package/src/compat/next/og.ts +3 -3
- package/src/compat/next/usage.ts +3 -2
- package/src/compat/pages/api.ts +83 -14
- package/src/compat/pages/router.ts +30 -14
- package/src/compat/register/bundler.ts +3 -1
- package/src/compat/register/middleware.ts +1 -1
- package/src/compat/register/otel.ts +5 -9
- package/src/compat/register/render.ts +3 -1
- package/src/compat/register/use-cache.ts +3 -1
- package/src/compat/release.ts +46 -0
- package/src/compat/segment/serve.ts +1 -1
- package/src/compat/validation/validate.ts +10 -7
- package/src/config.ts +51 -7
- package/src/css/assets.ts +213 -0
- package/src/css/build.ts +174 -238
- package/src/dev/server.ts +27 -8
- package/src/extensions.ts +4 -0
- package/src/render/hooks.ts +13 -0
- package/src/render/renderer.ts +52 -32
- package/src/request/context.ts +9 -0
- package/src/resolve/dynamic.ts +3 -1
- package/src/resolve/imports.ts +12 -52
- package/src/resolve/package-json.ts +56 -0
- package/src/resolve/scan-facts.ts +65 -0
- package/src/routing/href.ts +10 -3
- package/src/routing/match.ts +287 -0
- package/src/routing/metadata-files.ts +19 -5
- package/src/routing/proxy-config.ts +137 -0
- package/src/routing/proxy.ts +35 -134
- package/src/routing/routes.ts +22 -281
- package/src/runtime/fingerprint.ts +23 -8
- package/src/runtime/load.ts +170 -0
- package/src/runtime/loader.ts +215 -43
- package/src/runtime/module-cache.ts +13 -0
- package/src/runtime/modules.ts +370 -81
- package/src/runtime/prebundle.ts +81 -0
- package/src/runtime/production.ts +391 -0
- package/src/runtime/release-graph.ts +334 -0
- package/src/runtime/vendor-build.ts +724 -13
- package/src/runtime/vendor.ts +16 -3
- package/src/types.ts +2 -0
- package/src/utils/fs.ts +89 -3
|
@@ -0,0 +1,1599 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
import {
|
|
3
|
+
dynamicCallsFromSource,
|
|
4
|
+
pnextDynamicImportNames,
|
|
5
|
+
rewriteLiteralDynamicCalls
|
|
6
|
+
} from "./index-91x12ykq.js";
|
|
7
|
+
import {
|
|
8
|
+
conventionFileName,
|
|
9
|
+
findConventionFiles,
|
|
10
|
+
findLayouts,
|
|
11
|
+
pageExtensions,
|
|
12
|
+
serverActionsUnsupportedMessage
|
|
13
|
+
} from "./index-jepjvcrf.js";
|
|
14
|
+
import {
|
|
15
|
+
globalCssSourcesForPaths
|
|
16
|
+
} from "./index-2dv4y4wd.js";
|
|
17
|
+
import {
|
|
18
|
+
readSourceSync
|
|
19
|
+
} from "./index-fp8r0sqs.js";
|
|
20
|
+
import {
|
|
21
|
+
childrenDefaultFile,
|
|
22
|
+
interceptionMarkerLevels,
|
|
23
|
+
interceptionMarkerOf,
|
|
24
|
+
isGroupSegment,
|
|
25
|
+
isSlotSegment,
|
|
26
|
+
slotConventionFile,
|
|
27
|
+
slotDirectoriesIn
|
|
28
|
+
} from "./index-p77b4kcx.js";
|
|
29
|
+
import {
|
|
30
|
+
listFiles,
|
|
31
|
+
listFilesSync,
|
|
32
|
+
toPosixPath,
|
|
33
|
+
withDirCache
|
|
34
|
+
} from "./index-20ppawv7.js";
|
|
35
|
+
import {
|
|
36
|
+
clientReferenceId,
|
|
37
|
+
ssrClientReference
|
|
38
|
+
} from "./index-ras0sdab.js";
|
|
39
|
+
import {
|
|
40
|
+
dynamicCallFacts,
|
|
41
|
+
scanFacts
|
|
42
|
+
} from "./index-z4z9zv3b.js";
|
|
43
|
+
import {
|
|
44
|
+
resolveImport,
|
|
45
|
+
resolveModuleAlias,
|
|
46
|
+
resolvePackageSpecifier
|
|
47
|
+
} from "./index-yz54pxrh.js";
|
|
48
|
+
import {
|
|
49
|
+
alwaysClientEntryReasons,
|
|
50
|
+
classifyRouteDependencies,
|
|
51
|
+
extraBoundaryConventionNames,
|
|
52
|
+
extraPageExtensions,
|
|
53
|
+
getBundlerExtensions,
|
|
54
|
+
getCssExtensions,
|
|
55
|
+
sourceClientEntryReasons,
|
|
56
|
+
sourceUsesRegisteredRequestApi
|
|
57
|
+
} from "./index-zqpqyg8p.js";
|
|
58
|
+
|
|
59
|
+
// src/routing/routes.ts
|
|
60
|
+
import path from "path";
|
|
61
|
+
import { existsSync } from "fs";
|
|
62
|
+
var BASE_ROUTE_HANDLER_EXTENSIONS = ["ts", "tsx", "js", "mjs"];
|
|
63
|
+
function routeHandlerExtensions() {
|
|
64
|
+
return BASE_ROUTE_HANDLER_EXTENSIONS;
|
|
65
|
+
}
|
|
66
|
+
function allFileExtensions() {
|
|
67
|
+
return [...new Set([...pageExtensions(), ...routeHandlerExtensions()])];
|
|
68
|
+
}
|
|
69
|
+
var componentConventions = ["loading", "error", "not-found"];
|
|
70
|
+
function boundaryConventions() {
|
|
71
|
+
return [...componentConventions, ...extraBoundaryConventionNames()];
|
|
72
|
+
}
|
|
73
|
+
var memoPageFile;
|
|
74
|
+
var memoRouteFilePattern;
|
|
75
|
+
var memoDefaultConventionPattern;
|
|
76
|
+
var memoMetadataCodeFilePattern;
|
|
77
|
+
var memoPageOrRouteTrailing;
|
|
78
|
+
var memoSlotConventionPattern;
|
|
79
|
+
var memoExtensionsKey;
|
|
80
|
+
function freshMemos() {
|
|
81
|
+
const key = extraPageExtensions().join(",");
|
|
82
|
+
if (key === memoExtensionsKey)
|
|
83
|
+
return;
|
|
84
|
+
memoExtensionsKey = key;
|
|
85
|
+
memoPageFile = undefined;
|
|
86
|
+
memoRouteFilePattern = undefined;
|
|
87
|
+
memoDefaultConventionPattern = undefined;
|
|
88
|
+
memoMetadataCodeFilePattern = undefined;
|
|
89
|
+
memoPageOrRouteTrailing = undefined;
|
|
90
|
+
memoSlotConventionPattern = undefined;
|
|
91
|
+
}
|
|
92
|
+
function pageFile() {
|
|
93
|
+
freshMemos();
|
|
94
|
+
return memoPageFile ??= extensionRegex("page", pageExtensions());
|
|
95
|
+
}
|
|
96
|
+
function routeFilePattern() {
|
|
97
|
+
freshMemos();
|
|
98
|
+
return memoRouteFilePattern ??= extensionRegex("route", routeHandlerExtensions());
|
|
99
|
+
}
|
|
100
|
+
function defaultConventionPattern() {
|
|
101
|
+
freshMemos();
|
|
102
|
+
return memoDefaultConventionPattern ??= extensionRegex("default", pageExtensions());
|
|
103
|
+
}
|
|
104
|
+
function metadataCodeFilePattern() {
|
|
105
|
+
freshMemos();
|
|
106
|
+
return memoMetadataCodeFilePattern ??= new RegExp(`(^|/)(robots|sitemap|manifest|icon\\d*|apple-icon\\d*|opengraph-image\\d*|twitter-image\\d*)\\.(${allFileExtensions().join("|")})$`);
|
|
107
|
+
}
|
|
108
|
+
function pageOrRouteTrailing() {
|
|
109
|
+
freshMemos();
|
|
110
|
+
return memoPageOrRouteTrailing ??= new RegExp(`/?(page|route|layout|template|loading|error|not-found|forbidden|unauthorized|default|global-error)\\.(${allFileExtensions().join("|")})$`);
|
|
111
|
+
}
|
|
112
|
+
function slotConventionPattern() {
|
|
113
|
+
freshMemos();
|
|
114
|
+
return memoSlotConventionPattern ??= new RegExp(`(^|/)(page|layout|template|loading|error|default|not-found)\\.(${pageExtensions().join("|")})$`);
|
|
115
|
+
}
|
|
116
|
+
function extensionRegex(base, extensions) {
|
|
117
|
+
return new RegExp(`(^|/)${escapeRegex(base)}\\.(${extensions.join("|")})$`);
|
|
118
|
+
}
|
|
119
|
+
function createScanContext(appPath, globalCss, workspaceRoot) {
|
|
120
|
+
const root = rootFromAppPath(appPath);
|
|
121
|
+
let memo;
|
|
122
|
+
return {
|
|
123
|
+
root,
|
|
124
|
+
workspaceRoot,
|
|
125
|
+
appPath,
|
|
126
|
+
sources: new Map,
|
|
127
|
+
edges: new Map,
|
|
128
|
+
requestImportUsage: new Map,
|
|
129
|
+
exists: new Map,
|
|
130
|
+
useClient: new Map,
|
|
131
|
+
usesLink: new Map,
|
|
132
|
+
usesNavigation: new Map,
|
|
133
|
+
entryReasons: new Map,
|
|
134
|
+
globalCssImports: globalCss ?? (() => memo ??= new Set(globalCssSourcesForPaths(root, appPath, workspaceRoot)))
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
function fileExists(context, file) {
|
|
138
|
+
let hit = context.exists.get(file);
|
|
139
|
+
if (hit === undefined) {
|
|
140
|
+
hit = existsSync(file);
|
|
141
|
+
context.exists.set(file, hit);
|
|
142
|
+
}
|
|
143
|
+
return hit;
|
|
144
|
+
}
|
|
145
|
+
var routeHandlerMethods = ["GET", "HEAD", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"];
|
|
146
|
+
var deferredFields = [
|
|
147
|
+
"mode",
|
|
148
|
+
"hasStaticParams",
|
|
149
|
+
"usesRequest",
|
|
150
|
+
"handlerUsesRevalidationApi",
|
|
151
|
+
"dynamicErrorApi",
|
|
152
|
+
"client",
|
|
153
|
+
"clientReferences",
|
|
154
|
+
"cssImports",
|
|
155
|
+
"sourceFiles",
|
|
156
|
+
"serverActionFile",
|
|
157
|
+
"stream",
|
|
158
|
+
"maxDuration",
|
|
159
|
+
"ppr",
|
|
160
|
+
"segmentConfig",
|
|
161
|
+
"needsRouterEntry",
|
|
162
|
+
"clientEntryReasons"
|
|
163
|
+
];
|
|
164
|
+
var resolvedRoutes = new WeakSet;
|
|
165
|
+
var factsVersion = 0;
|
|
166
|
+
function routeFactsVersion() {
|
|
167
|
+
return factsVersion;
|
|
168
|
+
}
|
|
169
|
+
function routeFactsResolved(route) {
|
|
170
|
+
return resolvedRoutes.has(route);
|
|
171
|
+
}
|
|
172
|
+
function materializeRouteFacts(routes, onRoute) {
|
|
173
|
+
for (const route of routes) {
|
|
174
|
+
route.sourceFiles;
|
|
175
|
+
onRoute?.(route);
|
|
176
|
+
}
|
|
177
|
+
return routes;
|
|
178
|
+
}
|
|
179
|
+
async function materializeRouteFactsPaced(routes, pause) {
|
|
180
|
+
for (const route of routes) {
|
|
181
|
+
await pause();
|
|
182
|
+
route.sourceFiles;
|
|
183
|
+
}
|
|
184
|
+
return routes;
|
|
185
|
+
}
|
|
186
|
+
var factsStore;
|
|
187
|
+
function setRouteFactsStore(store) {
|
|
188
|
+
factsStore = store;
|
|
189
|
+
}
|
|
190
|
+
function withDeferredFacts(appPath, base, compute) {
|
|
191
|
+
const entry = base;
|
|
192
|
+
let facts;
|
|
193
|
+
const overrides = new Map;
|
|
194
|
+
for (const field of deferredFields) {
|
|
195
|
+
Object.defineProperty(entry, field, {
|
|
196
|
+
enumerable: true,
|
|
197
|
+
configurable: true,
|
|
198
|
+
get() {
|
|
199
|
+
if (overrides.has(field))
|
|
200
|
+
return overrides.get(field);
|
|
201
|
+
if (!facts) {
|
|
202
|
+
const key = `${appPath}\x00${base.kind}:${base.id}`;
|
|
203
|
+
const stored = factsStore?.load(key);
|
|
204
|
+
facts = stored ?? withDirCache(compute);
|
|
205
|
+
if (!stored)
|
|
206
|
+
factsStore?.save(key, facts);
|
|
207
|
+
resolvedRoutes.add(entry);
|
|
208
|
+
factsVersion += 1;
|
|
209
|
+
}
|
|
210
|
+
return facts[field];
|
|
211
|
+
},
|
|
212
|
+
set(value) {
|
|
213
|
+
overrides.set(field, value);
|
|
214
|
+
}
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
return entry;
|
|
218
|
+
}
|
|
219
|
+
async function scanRoutes(appPath, workspaceRoot) {
|
|
220
|
+
const files = await listFiles(appPath);
|
|
221
|
+
return withDirCache(() => buildRouteTable(appPath, files, workspaceRoot));
|
|
222
|
+
}
|
|
223
|
+
function buildRouteTable(appPath, files, workspaceRoot) {
|
|
224
|
+
const context = createScanContext(appPath, undefined, workspaceRoot);
|
|
225
|
+
const routes = [];
|
|
226
|
+
const slotPageFiles = [];
|
|
227
|
+
const defaultPageFiles = [];
|
|
228
|
+
const table = { parallelRoutes: false };
|
|
229
|
+
for (const file of files) {
|
|
230
|
+
const relative = toPosixPath(path.relative(appPath, file));
|
|
231
|
+
const routeFile = path.join(appPath, relative);
|
|
232
|
+
if (defaultConventionPattern().test(relative) && !relative.split("/").some((segment) => segment.startsWith("@"))) {
|
|
233
|
+
defaultPageFiles.push({ file, relative });
|
|
234
|
+
}
|
|
235
|
+
if (isPrivateAppPath(relative))
|
|
236
|
+
continue;
|
|
237
|
+
if (!pageFile().test(relative) && !routeFilePattern().test(relative)) {
|
|
238
|
+
if (!metadataCodeFilePattern().test(relative))
|
|
239
|
+
continue;
|
|
240
|
+
const source = readSource(context, file);
|
|
241
|
+
const metadataParts = dynamicMetadataRouteParts(relative, source);
|
|
242
|
+
if (!metadataParts)
|
|
243
|
+
continue;
|
|
244
|
+
routes.push(withDeferredFacts(appPath, {
|
|
245
|
+
id: `metadata-${routeId(metadataParts.route)}`,
|
|
246
|
+
kind: "handler",
|
|
247
|
+
route: metadataParts.route,
|
|
248
|
+
pattern: metadataParts.pattern,
|
|
249
|
+
file,
|
|
250
|
+
params: metadataParts.params,
|
|
251
|
+
catchAll: metadataParts.catchAll,
|
|
252
|
+
...metadataParts.catchAllOptional ? { catchAllOptional: true } : {},
|
|
253
|
+
metadataRoute: metadataParts.metadataRoute
|
|
254
|
+
}, () => metadataRouteFacts(context, routeFile, metadataParts)));
|
|
255
|
+
continue;
|
|
256
|
+
}
|
|
257
|
+
if (relative.split("/").some((segment) => segment.startsWith("@"))) {
|
|
258
|
+
if (pageFile().test(relative))
|
|
259
|
+
slotPageFiles.push({ file, relative });
|
|
260
|
+
continue;
|
|
261
|
+
}
|
|
262
|
+
const kind = pageFile().test(relative) ? "page" : "handler";
|
|
263
|
+
const routeDir = relative.replace(pageOrRouteTrailing(), "");
|
|
264
|
+
const parts = routeParts(routeDir);
|
|
265
|
+
const conventions = conventionPaths(appPath, routeFile, kind);
|
|
266
|
+
const templatePaths = conventions.templateFiles.filter((item) => existsSync(item));
|
|
267
|
+
const extraBoundaries = new Set(extraBoundaryConventionNames());
|
|
268
|
+
const forbiddenPaths = kind === "page" && extraBoundaries.has("forbidden") ? findConventionFiles(appPath, routeFile, "forbidden").filter((item) => existsSync(item)) : [];
|
|
269
|
+
const unauthorizedPaths = kind === "page" && extraBoundaries.has("unauthorized") ? findConventionFiles(appPath, routeFile, "unauthorized").filter((item) => existsSync(item)) : [];
|
|
270
|
+
const interception = parts.interception;
|
|
271
|
+
routes.push(withDeferredFacts(appPath, {
|
|
272
|
+
id: interception ? `intercept-${sanitizeIdPart(routeDir)}` : routeId(parts.route || "/"),
|
|
273
|
+
kind,
|
|
274
|
+
route: parts.route,
|
|
275
|
+
pattern: parts.pattern,
|
|
276
|
+
file,
|
|
277
|
+
params: parts.params,
|
|
278
|
+
catchAll: parts.catchAll,
|
|
279
|
+
...parts.catchAllOptional ? { catchAllOptional: true } : {},
|
|
280
|
+
...templatePaths.length > 0 ? { templateFiles: templatePaths } : {},
|
|
281
|
+
...forbiddenPaths.length > 0 ? { forbiddenFiles: forbiddenPaths } : {},
|
|
282
|
+
...unauthorizedPaths.length > 0 ? { unauthorizedFiles: unauthorizedPaths } : {},
|
|
283
|
+
...conventions.slotDirs.length > 0 ? { slotDirs: conventions.slotDirs } : {},
|
|
284
|
+
...interception ? { interception } : {}
|
|
285
|
+
}, () => pageOrHandlerFacts(context, { kind, routeFile, parts, conventions, table })));
|
|
286
|
+
}
|
|
287
|
+
appendSlotDerivedRoutes(context, routes, slotPageFiles, table);
|
|
288
|
+
appendDefaultDerivedRoutes(context, routes, defaultPageFiles, table);
|
|
289
|
+
table.parallelRoutes = routes.some((route) => route.slotDirs?.length || route.interception);
|
|
290
|
+
return routes.sort((a, b) => routeRank(a).localeCompare(routeRank(b)));
|
|
291
|
+
}
|
|
292
|
+
function conventionPaths(appPath, routeFile, kind) {
|
|
293
|
+
if (kind !== "page") {
|
|
294
|
+
return { layoutFiles: [], templateFiles: [], specialFiles: [], slotDirs: [], slotFiles: [] };
|
|
295
|
+
}
|
|
296
|
+
const slotDirs = chainSlotDirs(appPath, routeFile);
|
|
297
|
+
return {
|
|
298
|
+
layoutFiles: findLayouts(appPath, routeFile),
|
|
299
|
+
templateFiles: findConventionFiles(appPath, routeFile, "template"),
|
|
300
|
+
specialFiles: boundaryConventions().flatMap((name) => findConventionFiles(appPath, routeFile, name)),
|
|
301
|
+
slotDirs,
|
|
302
|
+
slotFiles: slotTreeFiles(slotDirs)
|
|
303
|
+
};
|
|
304
|
+
}
|
|
305
|
+
function metadataRouteFacts(context, routeFile, parts) {
|
|
306
|
+
const source = readSource(context, routeFile);
|
|
307
|
+
const sourceFiles = collectSourceFiles(context, [routeFile]);
|
|
308
|
+
const dependency = routeDependencyClassification(context, "handler", sourceFiles);
|
|
309
|
+
const usesRequest = metadataRouteUsesRequest(source) || usesRevalidationApis(source) || dependency.usesRequest === true || usesRequestImportDataForFiles(context, sourceFiles.filter((file) => !isAssetFile(file)));
|
|
310
|
+
const segmentConfig = segmentConfigFromEntries(context.appPath, [{ file: routeFile, source }], parts);
|
|
311
|
+
return {
|
|
312
|
+
mode: inferRouteMode(parts, usesRequest, segmentConfig),
|
|
313
|
+
hasStaticParams: Boolean(parts.metadataRoute.generatedParam),
|
|
314
|
+
usesRequest,
|
|
315
|
+
client: false,
|
|
316
|
+
clientReferences: [],
|
|
317
|
+
cssImports: [],
|
|
318
|
+
sourceFiles,
|
|
319
|
+
maxDuration: maxDurationFromSources([source]),
|
|
320
|
+
...segmentConfig ? { segmentConfig } : {}
|
|
321
|
+
};
|
|
322
|
+
}
|
|
323
|
+
function pageOrHandlerFacts(context, options) {
|
|
324
|
+
const { appPath } = context;
|
|
325
|
+
const { kind, routeFile, parts, conventions, table } = options;
|
|
326
|
+
const { layoutFiles, templateFiles, specialFiles, slotFiles } = conventions;
|
|
327
|
+
const source = readScanSource(context, routeFile);
|
|
328
|
+
const layoutSources = [...layoutFiles, ...templateFiles, ...specialFiles].filter((item) => existsSync(item)).map((item) => readScanSource(context, item));
|
|
329
|
+
const entryFiles = [routeFile, ...layoutFiles, ...templateFiles, ...specialFiles, ...slotFiles];
|
|
330
|
+
const sourceFiles = collectSourceFiles(context, entryFiles);
|
|
331
|
+
const dependency = routeDependencyClassification(context, kind, sourceFiles);
|
|
332
|
+
const handlerUsesRevalidationApi = kind === "handler" && usesRevalidationApis(source);
|
|
333
|
+
const usesRequest = kind === "handler" ? routeHandlerUsesRequest(source) || handlerUsesRevalidationApi || dependency.usesRequest === true : [source, ...layoutSources].some(usesRequestData) || dependency.usesRequest === true;
|
|
334
|
+
const existingLayoutFiles = layoutFiles.filter((item) => existsSync(item));
|
|
335
|
+
const configEntries = [
|
|
336
|
+
{ file: routeFile, source },
|
|
337
|
+
...[...existingLayoutFiles].reverse().map((item) => ({
|
|
338
|
+
file: item,
|
|
339
|
+
source: readScanSource(context, item)
|
|
340
|
+
}))
|
|
341
|
+
];
|
|
342
|
+
const segmentConfig = segmentConfigFromEntries(appPath, configEntries, parts);
|
|
343
|
+
if (segmentConfig?.dynamicParamsFalse?.length) {
|
|
344
|
+
const allDynamicParams = [...parts.params, ...parts.catchAll ? [parts.catchAll] : []];
|
|
345
|
+
const coveredParams = new Set;
|
|
346
|
+
for (const entry of configEntries) {
|
|
347
|
+
if (!hasStaticParamsExport(entry.source))
|
|
348
|
+
continue;
|
|
349
|
+
const covered = paramOfOwnSegment(appPath, entry.file, allDynamicParams);
|
|
350
|
+
if (covered)
|
|
351
|
+
coveredParams.add(covered);
|
|
352
|
+
}
|
|
353
|
+
if (allDynamicParams.some((param) => !coveredParams.has(param))) {
|
|
354
|
+
delete segmentConfig.dynamicParamsFalse;
|
|
355
|
+
} else if (hasStaticParamsExport(source)) {
|
|
356
|
+
segmentConfig.strictDynamicParams = true;
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
const hasStaticParams = hasStaticParamsExport(source) || kind === "page" && existingLayoutFiles.map((item) => readScanSource(context, item)).some(hasStaticParamsExport);
|
|
360
|
+
const dynamicErrorApi = segmentConfig?.dynamic === "error" && parts.params.length === 0 && !parts.catchAll && !hasStaticParams ? dynamicApiLabel(kind === "handler" ? [source] : [source, ...layoutSources], kind) : undefined;
|
|
361
|
+
const ppr = kind === "page" && usesRequest && parts.params.length === 0 && !parts.catchAll && exportsExperimentalPpr([source, ...layoutSources]);
|
|
362
|
+
const directClient = kind === "page" && hasUseClientDirective(routeFile, source);
|
|
363
|
+
const clientReferences = kind === "page" ? collectClientReferences(context, directClient ? [...layoutFiles, ...templateFiles, ...specialFiles, ...slotFiles] : entryFiles) : [];
|
|
364
|
+
const client = directClient || clientReferences.some((reference) => reference.file === routeFile && reference.exportName === "default");
|
|
365
|
+
const stream = kind === "page" ? routeStreamMetadata({ context, layoutFiles, templateFiles, specialFiles }) : undefined;
|
|
366
|
+
const cssImports = kind === "page" ? collectCssImports(context, cssEntryOrder({ routeFile, layoutFiles, templateFiles, specialFiles, slotFiles }), { route: true }) : [];
|
|
367
|
+
if (kind === "page")
|
|
368
|
+
attachLazyReferenceCss(context, clientReferences);
|
|
369
|
+
const interception = parts.interception;
|
|
370
|
+
return {
|
|
371
|
+
mode: interception ? "dynamic" : inferRouteMode(parts, usesRequest, segmentConfig),
|
|
372
|
+
hasStaticParams: interception ? false : hasStaticParams,
|
|
373
|
+
usesRequest,
|
|
374
|
+
...handlerUsesRevalidationApi ? { handlerUsesRevalidationApi: true } : {},
|
|
375
|
+
...dynamicErrorApi ? { dynamicErrorApi } : {},
|
|
376
|
+
client,
|
|
377
|
+
clientReferences,
|
|
378
|
+
cssImports,
|
|
379
|
+
sourceFiles,
|
|
380
|
+
...kind === "page" ? serverActionFileFact(context, sourceFiles) : {},
|
|
381
|
+
...stream ? { stream } : {},
|
|
382
|
+
maxDuration: maxDurationFromSources([source, ...layoutSources]),
|
|
383
|
+
ppr: interception ? false : ppr,
|
|
384
|
+
...segmentConfig ? { segmentConfig } : {},
|
|
385
|
+
...routerEntryFact(context, {
|
|
386
|
+
kind,
|
|
387
|
+
client,
|
|
388
|
+
clientReferences,
|
|
389
|
+
sourceFiles,
|
|
390
|
+
slotInterceptor: false,
|
|
391
|
+
table
|
|
392
|
+
})
|
|
393
|
+
};
|
|
394
|
+
}
|
|
395
|
+
function routerEntryFact(context, options) {
|
|
396
|
+
if (options.kind !== "page")
|
|
397
|
+
return {};
|
|
398
|
+
const reasons = [];
|
|
399
|
+
if (options.table.parallelRoutes && !options.slotInterceptor)
|
|
400
|
+
reasons.push("parallel-routes");
|
|
401
|
+
reasons.push(...alwaysClientEntryReasons());
|
|
402
|
+
if (!options.client && options.clientReferences.length === 0) {
|
|
403
|
+
if (routeUsesLinkComponent(context, options.sourceFiles))
|
|
404
|
+
reasons.push("link");
|
|
405
|
+
} else if (routeUsesNavigation(context, options.sourceFiles)) {
|
|
406
|
+
reasons.push("router-api");
|
|
407
|
+
}
|
|
408
|
+
reasons.push(...routeClientEntryReasons(context, options.sourceFiles));
|
|
409
|
+
if (reasons.length === 0)
|
|
410
|
+
return {};
|
|
411
|
+
return { needsRouterEntry: true, clientEntryReasons: [...new Set(reasons)] };
|
|
412
|
+
}
|
|
413
|
+
function addClientEntryReason(route, reason) {
|
|
414
|
+
const reasons = route.clientEntryReasons ?? [];
|
|
415
|
+
if (!reasons.includes(reason))
|
|
416
|
+
route.clientEntryReasons = [...reasons, reason];
|
|
417
|
+
route.needsRouterEntry = true;
|
|
418
|
+
}
|
|
419
|
+
function routeStreamMetadata(options) {
|
|
420
|
+
const existingSpecialFiles = options.specialFiles.filter((item) => existsSync(item));
|
|
421
|
+
const hasLoadingBoundary = existingSpecialFiles.some((file) => /(^|[/\\])loading\.[^.]+$/.test(file));
|
|
422
|
+
const ancestorClientReferences = collectClientReferences(options.context, [
|
|
423
|
+
...options.layoutFiles,
|
|
424
|
+
...options.templateFiles
|
|
425
|
+
]);
|
|
426
|
+
return {
|
|
427
|
+
...hasLoadingBoundary ? { hasLoadingBoundary } : {},
|
|
428
|
+
...ancestorClientReferences.length > 0 ? { ancestorClientReferences: ancestorClientReferences.map((reference) => reference.id) } : {}
|
|
429
|
+
};
|
|
430
|
+
}
|
|
431
|
+
function hasStaticParamsExport(source) {
|
|
432
|
+
const searchable = stripCommentsAndStrings(source);
|
|
433
|
+
return /\bexport\s+(?:async\s+)?function\s+(?:params|generateStaticParams)\b/.test(searchable) || /\bexport\s+const\s+(?:params|generateStaticParams)\b/.test(searchable);
|
|
434
|
+
}
|
|
435
|
+
function chainSlotDirs(appPath, routeFilePath) {
|
|
436
|
+
const dirs = [];
|
|
437
|
+
let dir = path.dirname(routeFilePath);
|
|
438
|
+
while (dir.startsWith(appPath)) {
|
|
439
|
+
dirs.push(...slotDirectoriesIn(dir));
|
|
440
|
+
if (dir === appPath)
|
|
441
|
+
break;
|
|
442
|
+
dir = path.dirname(dir);
|
|
443
|
+
}
|
|
444
|
+
return dirs.reverse();
|
|
445
|
+
}
|
|
446
|
+
function slotTreeFiles(slotDirs) {
|
|
447
|
+
const files = [];
|
|
448
|
+
const pattern = slotConventionPattern();
|
|
449
|
+
for (const dir of slotDirs) {
|
|
450
|
+
for (const file of listFilesSync(dir)) {
|
|
451
|
+
if (pattern.test(toPosixPath(file)))
|
|
452
|
+
files.push(file);
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
return files;
|
|
456
|
+
}
|
|
457
|
+
function appendSlotDerivedRoutes(context, routes, slotPages, table) {
|
|
458
|
+
const appPath = context.appPath;
|
|
459
|
+
const patterns = new Set(routes.filter((route) => !route.interception).map((route) => route.pattern));
|
|
460
|
+
const interceptionKeys = new Set(routes.filter((route) => route.interception).map((route) => `${route.pattern}#${route.interception.base}`));
|
|
461
|
+
const candidates = slotPages.map(({ file, relative }) => {
|
|
462
|
+
const segments = relative.split("/");
|
|
463
|
+
const slotIndex = segments.findIndex(isSlotSegment);
|
|
464
|
+
const slotDir = path.join(appPath, ...segments.slice(0, slotIndex + 1));
|
|
465
|
+
return {
|
|
466
|
+
file,
|
|
467
|
+
relative,
|
|
468
|
+
slotDir,
|
|
469
|
+
ownerDir: path.dirname(slotDir),
|
|
470
|
+
parts: routeParts(relative.replace(pageOrRouteTrailing(), "")),
|
|
471
|
+
innerNames: segments.slice(slotIndex + 1, -1).filter((name) => !isSlotSegment(name) && !isGroupSegment(name))
|
|
472
|
+
};
|
|
473
|
+
}).sort((a, b) => b.ownerDir.length - a.ownerDir.length);
|
|
474
|
+
for (const candidate of candidates) {
|
|
475
|
+
const { parts } = candidate;
|
|
476
|
+
if (parts.interception) {
|
|
477
|
+
const key = `${parts.pattern}#${parts.interception.base}`;
|
|
478
|
+
if (interceptionKeys.has(key))
|
|
479
|
+
continue;
|
|
480
|
+
interceptionKeys.add(key);
|
|
481
|
+
routes.push(withDeferredFacts(appPath, {
|
|
482
|
+
id: `intercept-${sanitizeIdPart(candidate.relative.replace(pageOrRouteTrailing(), ""))}`,
|
|
483
|
+
kind: "page",
|
|
484
|
+
route: parts.route,
|
|
485
|
+
pattern: parts.pattern,
|
|
486
|
+
file: candidate.file,
|
|
487
|
+
params: parts.params,
|
|
488
|
+
catchAll: parts.catchAll,
|
|
489
|
+
...parts.catchAllOptional ? { catchAllOptional: true } : {},
|
|
490
|
+
interception: { ...parts.interception, slotDir: candidate.slotDir }
|
|
491
|
+
}, () => ({
|
|
492
|
+
...emptyDerivedFacts,
|
|
493
|
+
...routerEntryFact(context, {
|
|
494
|
+
kind: "page",
|
|
495
|
+
client: false,
|
|
496
|
+
clientReferences: [],
|
|
497
|
+
sourceFiles: [],
|
|
498
|
+
slotInterceptor: true,
|
|
499
|
+
table
|
|
500
|
+
})
|
|
501
|
+
})));
|
|
502
|
+
continue;
|
|
503
|
+
}
|
|
504
|
+
if (patterns.has(parts.pattern))
|
|
505
|
+
continue;
|
|
506
|
+
patterns.add(parts.pattern);
|
|
507
|
+
const childrenDefault = childrenDefaultFile(candidate.ownerDir, candidate.innerNames);
|
|
508
|
+
const anchor = childrenDefault ?? slotConventionFile(path.join(candidate.ownerDir, "@children"), "page") ?? slotConventionFile(candidate.ownerDir, "page") ?? candidate.file;
|
|
509
|
+
const layoutFiles = findLayouts(appPath, anchor);
|
|
510
|
+
const templateFiles = findConventionFiles(appPath, anchor, "template");
|
|
511
|
+
const specialFiles = boundaryConventions().flatMap((name) => findConventionFiles(appPath, anchor, name));
|
|
512
|
+
const slotDirs = chainSlotDirs(appPath, anchor);
|
|
513
|
+
const slotFiles = slotTreeFiles(slotDirs);
|
|
514
|
+
const extraBoundaries = new Set(extraBoundaryConventionNames());
|
|
515
|
+
const forbiddenPaths = extraBoundaries.has("forbidden") ? findConventionFiles(appPath, anchor, "forbidden").filter((item) => existsSync(item)) : [];
|
|
516
|
+
const unauthorizedPaths = extraBoundaries.has("unauthorized") ? findConventionFiles(appPath, anchor, "unauthorized").filter((item) => existsSync(item)) : [];
|
|
517
|
+
const templatePaths = templateFiles.filter((item) => existsSync(item));
|
|
518
|
+
routes.push(withDeferredFacts(appPath, {
|
|
519
|
+
id: `slot-${routeId(parts.route || "/")}`,
|
|
520
|
+
kind: "page",
|
|
521
|
+
route: parts.route,
|
|
522
|
+
pattern: parts.pattern,
|
|
523
|
+
file: anchor,
|
|
524
|
+
params: parts.params,
|
|
525
|
+
catchAll: parts.catchAll,
|
|
526
|
+
...parts.catchAllOptional ? { catchAllOptional: true } : {},
|
|
527
|
+
...templatePaths.length > 0 ? { templateFiles: templatePaths } : {},
|
|
528
|
+
...slotDirs.length > 0 ? { slotDirs } : {},
|
|
529
|
+
synthetic: true,
|
|
530
|
+
syntheticSlotDir: candidate.slotDir,
|
|
531
|
+
...childrenDefault ? { childrenDefault } : {},
|
|
532
|
+
...forbiddenPaths.length > 0 ? { forbiddenFiles: forbiddenPaths } : {},
|
|
533
|
+
...unauthorizedPaths.length > 0 ? { unauthorizedFiles: unauthorizedPaths } : {}
|
|
534
|
+
}, () => derivedRouteFacts(context, {
|
|
535
|
+
leadFiles: childrenDefault ? [childrenDefault] : [],
|
|
536
|
+
layoutFiles,
|
|
537
|
+
templateFiles,
|
|
538
|
+
specialFiles,
|
|
539
|
+
slotFiles,
|
|
540
|
+
clientFile: childrenDefault,
|
|
541
|
+
table
|
|
542
|
+
})));
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
var emptyDerivedFacts = {
|
|
546
|
+
mode: "dynamic",
|
|
547
|
+
hasStaticParams: false,
|
|
548
|
+
usesRequest: true,
|
|
549
|
+
client: false,
|
|
550
|
+
clientReferences: [],
|
|
551
|
+
cssImports: [],
|
|
552
|
+
sourceFiles: []
|
|
553
|
+
};
|
|
554
|
+
function derivedRouteFacts(context, options) {
|
|
555
|
+
const { leadFiles, layoutFiles, templateFiles, specialFiles, slotFiles } = options;
|
|
556
|
+
const entryFiles = [...leadFiles, ...layoutFiles, ...templateFiles, ...specialFiles, ...slotFiles];
|
|
557
|
+
const sourceFiles = collectSourceFiles(context, entryFiles);
|
|
558
|
+
const clientReferences = collectClientReferences(context, entryFiles);
|
|
559
|
+
const cssImports = collectCssImports(context, cssEntryOrder({
|
|
560
|
+
...options.leadIsRouteFile ? { routeFile: leadFiles[0] } : { leadFiles },
|
|
561
|
+
layoutFiles,
|
|
562
|
+
templateFiles,
|
|
563
|
+
specialFiles,
|
|
564
|
+
slotFiles
|
|
565
|
+
}), { route: true });
|
|
566
|
+
attachLazyReferenceCss(context, clientReferences);
|
|
567
|
+
const client = options.clientFile ? isClientModule(context, options.clientFile) : false;
|
|
568
|
+
return {
|
|
569
|
+
...emptyDerivedFacts,
|
|
570
|
+
client,
|
|
571
|
+
clientReferences,
|
|
572
|
+
cssImports,
|
|
573
|
+
sourceFiles,
|
|
574
|
+
...routerEntryFact(context, {
|
|
575
|
+
kind: "page",
|
|
576
|
+
client,
|
|
577
|
+
clientReferences,
|
|
578
|
+
sourceFiles,
|
|
579
|
+
slotInterceptor: false,
|
|
580
|
+
table: options.table
|
|
581
|
+
})
|
|
582
|
+
};
|
|
583
|
+
}
|
|
584
|
+
function appendDefaultDerivedRoutes(context, routes, defaultPages, table) {
|
|
585
|
+
const appPath = context.appPath;
|
|
586
|
+
const patterns = new Set(routes.filter((route) => !route.interception).map((route) => route.pattern));
|
|
587
|
+
for (const { file, relative } of defaultPages) {
|
|
588
|
+
const dir = path.dirname(file);
|
|
589
|
+
if (conventionFileName(dir, "page"))
|
|
590
|
+
continue;
|
|
591
|
+
const parts = routeParts(relative.replace(pageOrRouteTrailing(), ""));
|
|
592
|
+
if (parts.interception)
|
|
593
|
+
continue;
|
|
594
|
+
if (patterns.has(parts.pattern))
|
|
595
|
+
continue;
|
|
596
|
+
patterns.add(parts.pattern);
|
|
597
|
+
const layoutFiles = findLayouts(appPath, file);
|
|
598
|
+
const templateFiles = findConventionFiles(appPath, file, "template");
|
|
599
|
+
const specialFiles = boundaryConventions().flatMap((name) => findConventionFiles(appPath, file, name));
|
|
600
|
+
const slotDirs = chainSlotDirs(appPath, file);
|
|
601
|
+
const slotFiles = slotTreeFiles(slotDirs);
|
|
602
|
+
const extraBoundaries = new Set(extraBoundaryConventionNames());
|
|
603
|
+
const forbiddenPaths = extraBoundaries.has("forbidden") ? findConventionFiles(appPath, file, "forbidden").filter((item) => existsSync(item)) : [];
|
|
604
|
+
const unauthorizedPaths = extraBoundaries.has("unauthorized") ? findConventionFiles(appPath, file, "unauthorized").filter((item) => existsSync(item)) : [];
|
|
605
|
+
const templatePaths = templateFiles.filter((item) => existsSync(item));
|
|
606
|
+
routes.push(withDeferredFacts(appPath, {
|
|
607
|
+
id: `default-${routeId(parts.route || "/")}`,
|
|
608
|
+
kind: "page",
|
|
609
|
+
route: parts.route,
|
|
610
|
+
pattern: parts.pattern,
|
|
611
|
+
file,
|
|
612
|
+
params: parts.params,
|
|
613
|
+
catchAll: parts.catchAll,
|
|
614
|
+
...parts.catchAllOptional ? { catchAllOptional: true } : {},
|
|
615
|
+
...templatePaths.length > 0 ? { templateFiles: templatePaths } : {},
|
|
616
|
+
...slotDirs.length > 0 ? { slotDirs } : {},
|
|
617
|
+
...forbiddenPaths.length > 0 ? { forbiddenFiles: forbiddenPaths } : {},
|
|
618
|
+
...unauthorizedPaths.length > 0 ? { unauthorizedFiles: unauthorizedPaths } : {}
|
|
619
|
+
}, () => derivedRouteFacts(context, {
|
|
620
|
+
leadFiles: [file],
|
|
621
|
+
leadIsRouteFile: true,
|
|
622
|
+
layoutFiles,
|
|
623
|
+
templateFiles,
|
|
624
|
+
specialFiles,
|
|
625
|
+
slotFiles,
|
|
626
|
+
clientFile: file,
|
|
627
|
+
table
|
|
628
|
+
})));
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
async function collectNotFoundCss(appPath) {
|
|
632
|
+
const notFoundFile = conventionFileName(appPath, "not-found");
|
|
633
|
+
if (!notFoundFile)
|
|
634
|
+
return [];
|
|
635
|
+
return collectFileCss(appPath, [notFoundFile]);
|
|
636
|
+
}
|
|
637
|
+
async function collectFileCss(appPath, files, options = {}) {
|
|
638
|
+
const existing = files.filter((file) => existsSync(file));
|
|
639
|
+
if (existing.length === 0)
|
|
640
|
+
return [];
|
|
641
|
+
const context = createScanContext(appPath, options.includeGlobalCss ? () => new Set : undefined);
|
|
642
|
+
return collectCssImports(context, existing);
|
|
643
|
+
}
|
|
644
|
+
function segmentTokenOf(bare) {
|
|
645
|
+
const optionalCatchAllMatch = /^\[\[\.\.\.([^\]]+)\]\]$/.exec(bare);
|
|
646
|
+
if (optionalCatchAllMatch?.[1]) {
|
|
647
|
+
const name = optionalCatchAllMatch[1];
|
|
648
|
+
return { route: `:${name}*`, catchAll: name, catchAllOptional: true };
|
|
649
|
+
}
|
|
650
|
+
const catchAllMatch = /^\[\.\.\.([^\]]+)\]$/.exec(bare);
|
|
651
|
+
if (catchAllMatch?.[1]) {
|
|
652
|
+
return { route: `:${catchAllMatch[1]}*`, pattern: "(.*)", catchAll: catchAllMatch[1] };
|
|
653
|
+
}
|
|
654
|
+
const paramMatch = /^\[([^\]]+)\]$/.exec(bare);
|
|
655
|
+
if (paramMatch?.[1]) {
|
|
656
|
+
return { route: `:${paramMatch[1]}`, pattern: "([^/]+)", param: paramMatch[1] };
|
|
657
|
+
}
|
|
658
|
+
const literal = decodeLiteralSegment(bare);
|
|
659
|
+
return { route: literal, pattern: escapeRegex(literal) };
|
|
660
|
+
}
|
|
661
|
+
function isPrivateAppPath(relative) {
|
|
662
|
+
const segments = relative.split("/");
|
|
663
|
+
return segments.slice(0, -1).some((segment) => segment.startsWith("_") && !isGroupSegment(segment) && !isSlotSegment(segment));
|
|
664
|
+
}
|
|
665
|
+
function decodeLiteralSegment(segment) {
|
|
666
|
+
return segment.replace(/%5[Ff]/g, "_");
|
|
667
|
+
}
|
|
668
|
+
function routeParts(routeDir) {
|
|
669
|
+
const segments = routeDir.split("/").filter(Boolean);
|
|
670
|
+
let tokens = [];
|
|
671
|
+
let interception;
|
|
672
|
+
for (const segment of segments) {
|
|
673
|
+
if (isGroupSegment(segment) || isSlotSegment(segment))
|
|
674
|
+
continue;
|
|
675
|
+
const marker = interceptionMarkerOf(segment);
|
|
676
|
+
let bare = segment;
|
|
677
|
+
if (marker) {
|
|
678
|
+
bare = segment.slice(marker.length);
|
|
679
|
+
const base = tokens.slice();
|
|
680
|
+
const levels = interceptionMarkerLevels(marker);
|
|
681
|
+
tokens = levels === Number.POSITIVE_INFINITY ? [] : tokens.slice(0, Math.max(0, tokens.length - levels));
|
|
682
|
+
interception = {
|
|
683
|
+
marker,
|
|
684
|
+
base: `/${base.map((token) => token.route).join("/")}`.replace(/\/$/, "") || "/",
|
|
685
|
+
basePattern: base.map((token) => token.pattern ?? "(.*)").join("/")
|
|
686
|
+
};
|
|
687
|
+
}
|
|
688
|
+
tokens.push(segmentTokenOf(bare));
|
|
689
|
+
}
|
|
690
|
+
const params = tokens.filter((token) => token.param).map((token) => token.param);
|
|
691
|
+
const catchAllToken = tokens.find((token) => token.catchAll);
|
|
692
|
+
const routeSegments = tokens.map((token) => token.route);
|
|
693
|
+
const patternSegments = tokens.filter((token) => !token.catchAllOptional).map((token) => token.pattern);
|
|
694
|
+
const route = `/${routeSegments.join("/")}`.replace(/\/$/, "") || "/";
|
|
695
|
+
let pattern;
|
|
696
|
+
if (catchAllToken?.catchAllOptional) {
|
|
697
|
+
const prefix = patternSegments.length > 0 ? `/${patternSegments.join("/")}` : "";
|
|
698
|
+
pattern = `${prefix}(?:/(.*))?`;
|
|
699
|
+
if (pattern === "(?:/(.*))?")
|
|
700
|
+
pattern = "/?(?:(.*))?";
|
|
701
|
+
} else {
|
|
702
|
+
pattern = route === "/" ? "/" : `/${patternSegments.join("/")}`;
|
|
703
|
+
}
|
|
704
|
+
return {
|
|
705
|
+
route,
|
|
706
|
+
pattern,
|
|
707
|
+
params,
|
|
708
|
+
catchAll: catchAllToken?.catchAll,
|
|
709
|
+
catchAllOptional: Boolean(catchAllToken?.catchAllOptional),
|
|
710
|
+
interception
|
|
711
|
+
};
|
|
712
|
+
}
|
|
713
|
+
function dynamicMetadataRouteParts(relative, source) {
|
|
714
|
+
const name = path.basename(relative);
|
|
715
|
+
const dir = path.dirname(relative) === "." ? "" : path.dirname(relative);
|
|
716
|
+
const root = dir === "";
|
|
717
|
+
const extension = path.extname(name);
|
|
718
|
+
const base = name.slice(0, -extension.length);
|
|
719
|
+
const kind = dynamicMetadataKind(base, root);
|
|
720
|
+
if (!kind)
|
|
721
|
+
return;
|
|
722
|
+
const prefix = routeParts(dir);
|
|
723
|
+
const generatedParam = metadataGeneratedParam(kind, source);
|
|
724
|
+
const final = dynamicMetadataFinalSegment(kind, base, dir, Boolean(generatedParam));
|
|
725
|
+
return {
|
|
726
|
+
...appendRouteParts(prefix, final.route, final.pattern, generatedParam ? [generatedParam] : []),
|
|
727
|
+
metadataRoute: {
|
|
728
|
+
kind,
|
|
729
|
+
...generatedParam ? { generatedParam } : {}
|
|
730
|
+
}
|
|
731
|
+
};
|
|
732
|
+
}
|
|
733
|
+
function dynamicMetadataKind(base, root) {
|
|
734
|
+
if (base === "robots")
|
|
735
|
+
return root ? "robots" : undefined;
|
|
736
|
+
if (base === "sitemap")
|
|
737
|
+
return "sitemap";
|
|
738
|
+
if (base === "manifest")
|
|
739
|
+
return root ? "manifest" : undefined;
|
|
740
|
+
if (/^icon\d*$/.test(base))
|
|
741
|
+
return "icon";
|
|
742
|
+
if (/^apple-icon\d*$/.test(base))
|
|
743
|
+
return "apple-icon";
|
|
744
|
+
if (/^opengraph-image\d*$/.test(base))
|
|
745
|
+
return "opengraph-image";
|
|
746
|
+
if (/^twitter-image\d*$/.test(base))
|
|
747
|
+
return "twitter-image";
|
|
748
|
+
return;
|
|
749
|
+
}
|
|
750
|
+
function metadataGeneratedParam(kind, source) {
|
|
751
|
+
if (kind === "sitemap" && /\bexport\s+(?:async\s+)?function\s+generateSitemaps\b/.test(source)) {
|
|
752
|
+
return "__metadata_id__";
|
|
753
|
+
}
|
|
754
|
+
if (metadataImageKind(kind) && /\bexport\s+(?:async\s+)?function\s+generateImageMetadata\b/.test(source)) {
|
|
755
|
+
return "__metadata_id__";
|
|
756
|
+
}
|
|
757
|
+
return;
|
|
758
|
+
}
|
|
759
|
+
function dynamicMetadataFinalSegment(kind, base, relativeDir, generated) {
|
|
760
|
+
if (kind === "robots")
|
|
761
|
+
return { route: "robots.txt", pattern: "robots\\.txt" };
|
|
762
|
+
if (kind === "manifest")
|
|
763
|
+
return { route: "manifest.webmanifest", pattern: "manifest\\.webmanifest" };
|
|
764
|
+
if (kind === "sitemap") {
|
|
765
|
+
return generated ? { route: "sitemap/:id.xml", pattern: "sitemap/([^/]+)\\.xml" } : { route: "sitemap.xml", pattern: "sitemap\\.xml" };
|
|
766
|
+
}
|
|
767
|
+
const suffix = metadataRouteSuffix(relativeDir);
|
|
768
|
+
const imageBase = suffix ? `${base}-${suffix}` : base;
|
|
769
|
+
return generated ? { route: `${imageBase}/:id`, pattern: `${escapeRegex(imageBase)}/([^/]+)` } : { route: imageBase, pattern: escapeRegex(imageBase) };
|
|
770
|
+
}
|
|
771
|
+
function appendRouteParts(parts, route, pattern, params) {
|
|
772
|
+
const prefixRoute = parts.route === "/" ? "" : parts.route;
|
|
773
|
+
const prefixPattern = parts.pattern === "/" ? "" : parts.pattern;
|
|
774
|
+
return {
|
|
775
|
+
...parts,
|
|
776
|
+
route: `${prefixRoute}/${route}`.replace(/\/$/, "") || "/",
|
|
777
|
+
pattern: `${prefixPattern}/${pattern}`,
|
|
778
|
+
params: [...parts.params, ...params]
|
|
779
|
+
};
|
|
780
|
+
}
|
|
781
|
+
function metadataImageKind(kind) {
|
|
782
|
+
return kind === "icon" || kind === "apple-icon" || kind === "opengraph-image" || kind === "twitter-image";
|
|
783
|
+
}
|
|
784
|
+
function metadataRouteUsesRequest(source) {
|
|
785
|
+
return routeHandlerUsesRequest(source);
|
|
786
|
+
}
|
|
787
|
+
function metadataRouteSuffix(relativeDir) {
|
|
788
|
+
if (!relativeDir)
|
|
789
|
+
return "";
|
|
790
|
+
const segments = relativeDir.split("/").filter(Boolean);
|
|
791
|
+
if (!segments.some((segment) => isGroupSegment(segment) || isSlotSegment(segment)))
|
|
792
|
+
return "";
|
|
793
|
+
return djb2Hash(`/${relativeDir}`).toString(36).slice(0, 6);
|
|
794
|
+
}
|
|
795
|
+
function djb2Hash(value) {
|
|
796
|
+
let hash = 5381;
|
|
797
|
+
for (let i = 0;i < value.length; i++) {
|
|
798
|
+
hash = (hash << 5) + hash + value.charCodeAt(i) & 4294967295;
|
|
799
|
+
}
|
|
800
|
+
return hash >>> 0;
|
|
801
|
+
}
|
|
802
|
+
function inferRouteMode(parts, usesRequest, config) {
|
|
803
|
+
if (config?.dynamic === "force-dynamic")
|
|
804
|
+
return "dynamic";
|
|
805
|
+
if (config?.revalidate === 0)
|
|
806
|
+
return "dynamic";
|
|
807
|
+
if (config?.fetchCache === "force-no-store")
|
|
808
|
+
return "dynamic";
|
|
809
|
+
if (config?.dynamic === "force-static")
|
|
810
|
+
return "static";
|
|
811
|
+
if (config?.dynamic === "error")
|
|
812
|
+
return "static";
|
|
813
|
+
if (usesRequest)
|
|
814
|
+
return "dynamic";
|
|
815
|
+
if (parts.params.length > 0 || parts.catchAll)
|
|
816
|
+
return "dynamic";
|
|
817
|
+
return "static";
|
|
818
|
+
}
|
|
819
|
+
function parseSegmentConfig(source) {
|
|
820
|
+
const searchable = stripComments(source);
|
|
821
|
+
const parsed = {};
|
|
822
|
+
const dynamicMatch = /^\s*export\s+const\s+dynamic\s*=\s*['"](auto|force-dynamic|error|force-static)['"]/m.exec(searchable);
|
|
823
|
+
if (dynamicMatch)
|
|
824
|
+
parsed.dynamic = dynamicMatch[1];
|
|
825
|
+
const revalidateMatch = /^\s*export\s+const\s+revalidate\s*=\s*(\d+|false)\s*;?\s*$/m.exec(searchable);
|
|
826
|
+
if (revalidateMatch) {
|
|
827
|
+
parsed.revalidate = revalidateMatch[1] === "false" ? false : Number(revalidateMatch[1]);
|
|
828
|
+
} else {
|
|
829
|
+
const invalid = /^\s*export\s+const\s+revalidate\s*=\s*(['"]([^'"]*)['"]|-\d+)/m.exec(searchable);
|
|
830
|
+
if (invalid)
|
|
831
|
+
parsed.invalidRevalidate = invalid[2] ?? invalid[1];
|
|
832
|
+
}
|
|
833
|
+
const fetchCacheMatch = /^\s*export\s+const\s+fetchCache\s*=\s*['"](auto|default-cache|only-cache|force-cache|force-no-store|default-no-store|only-no-store)['"]/m.exec(searchable);
|
|
834
|
+
if (fetchCacheMatch)
|
|
835
|
+
parsed.fetchCache = fetchCacheMatch[1];
|
|
836
|
+
const dynamicParamsMatch = /^\s*export\s+const\s+dynamicParams\s*=\s*(true|false)/m.exec(searchable);
|
|
837
|
+
if (dynamicParamsMatch)
|
|
838
|
+
parsed.dynamicParams = dynamicParamsMatch[1] === "true";
|
|
839
|
+
const runtimeMatch = /^\s*export\s+const\s+runtime\s*=\s*['"](edge|nodejs)['"]/m.exec(searchable);
|
|
840
|
+
if (runtimeMatch)
|
|
841
|
+
parsed.runtime = runtimeMatch[1];
|
|
842
|
+
const prefetchMatch = /^\s*export\s+const\s+prefetch\s*=\s*['"](allow-runtime|partial|unstable_eager)['"]/m.exec(searchable);
|
|
843
|
+
if (prefetchMatch)
|
|
844
|
+
parsed.prefetch = prefetchMatch[1];
|
|
845
|
+
const instantMatch = /^\s*export\s+const\s+unstable_instant\s*=\s*(true|false|\{)/m.exec(searchable);
|
|
846
|
+
if (instantMatch)
|
|
847
|
+
parsed.unstableInstant = instantMatch[1] !== "false";
|
|
848
|
+
return parsed;
|
|
849
|
+
}
|
|
850
|
+
function segmentConfigFromEntries(appPath, entries, parts) {
|
|
851
|
+
const config = {};
|
|
852
|
+
let lowestRevalidate;
|
|
853
|
+
let sawRevalidateFalse = false;
|
|
854
|
+
const dynamicParamsByName = new Map;
|
|
855
|
+
const allParams = [...parts.params, ...parts.catchAll ? [parts.catchAll] : []];
|
|
856
|
+
for (const entry of entries) {
|
|
857
|
+
const parsed = parseSegmentConfig(entry.source);
|
|
858
|
+
if (parsed.invalidRevalidate !== undefined) {
|
|
859
|
+
throw new Error(`Invalid revalidate value "${parsed.invalidRevalidate}" on "${parts.route || "/"}", must be a non-negative number or false`);
|
|
860
|
+
}
|
|
861
|
+
if (parsed.dynamic) {
|
|
862
|
+
if (parsed.dynamic === "force-dynamic")
|
|
863
|
+
config.dynamic = "force-dynamic";
|
|
864
|
+
else if (!config.dynamic)
|
|
865
|
+
config.dynamic = parsed.dynamic;
|
|
866
|
+
}
|
|
867
|
+
if (parsed.revalidate !== undefined) {
|
|
868
|
+
if (parsed.revalidate === false)
|
|
869
|
+
sawRevalidateFalse = true;
|
|
870
|
+
else {
|
|
871
|
+
lowestRevalidate = lowestRevalidate === undefined ? parsed.revalidate : Math.min(lowestRevalidate, parsed.revalidate);
|
|
872
|
+
}
|
|
873
|
+
}
|
|
874
|
+
if (parsed.fetchCache && !config.fetchCache)
|
|
875
|
+
config.fetchCache = parsed.fetchCache;
|
|
876
|
+
if (parsed.runtime && !config.runtime)
|
|
877
|
+
config.runtime = parsed.runtime;
|
|
878
|
+
if (parsed.prefetch && !config.prefetch)
|
|
879
|
+
config.prefetch = parsed.prefetch;
|
|
880
|
+
if (parsed.unstableInstant !== undefined && config.unstableInstant === undefined) {
|
|
881
|
+
config.unstableInstant = parsed.unstableInstant;
|
|
882
|
+
}
|
|
883
|
+
if (parsed.dynamicParams !== undefined) {
|
|
884
|
+
const param = paramOfOwnSegment(appPath, entry.file, allParams);
|
|
885
|
+
if (param !== undefined && !dynamicParamsByName.has(param)) {
|
|
886
|
+
dynamicParamsByName.set(param, parsed.dynamicParams);
|
|
887
|
+
}
|
|
888
|
+
}
|
|
889
|
+
}
|
|
890
|
+
if (lowestRevalidate !== undefined)
|
|
891
|
+
config.revalidate = lowestRevalidate;
|
|
892
|
+
else if (sawRevalidateFalse)
|
|
893
|
+
config.revalidate = false;
|
|
894
|
+
const governed = allParams.filter((param) => dynamicParamsByName.get(param) === false);
|
|
895
|
+
if (governed.length > 0)
|
|
896
|
+
config.dynamicParamsFalse = governed;
|
|
897
|
+
return Object.keys(config).length > 0 ? config : undefined;
|
|
898
|
+
}
|
|
899
|
+
function paramOfOwnSegment(appPath, file, params) {
|
|
900
|
+
const segments = toPosixPath(path.relative(appPath, path.dirname(file))).split("/");
|
|
901
|
+
const own = segments[segments.length - 1];
|
|
902
|
+
return params.find((param) => own === `[${param}]` || own === `[...${param}]` || own === `[[...${param}]]`);
|
|
903
|
+
}
|
|
904
|
+
function hasUseClientDirective(file, source) {
|
|
905
|
+
return scanFacts(file, source).useClient;
|
|
906
|
+
}
|
|
907
|
+
function serverActionFileFact(context, sourceFiles) {
|
|
908
|
+
for (const file of sourceFiles) {
|
|
909
|
+
if (!fileExists(context, file) || isAssetFile(file))
|
|
910
|
+
continue;
|
|
911
|
+
if (scanFacts(file, readSource(context, file)).useServer)
|
|
912
|
+
return { serverActionFile: file };
|
|
913
|
+
}
|
|
914
|
+
return {};
|
|
915
|
+
}
|
|
916
|
+
function assertNoServerActionsWithoutCompat(routes, compatEnabled, root) {
|
|
917
|
+
if (compatEnabled)
|
|
918
|
+
return;
|
|
919
|
+
const offender = routes.find((route) => route.serverActionFile);
|
|
920
|
+
if (!offender)
|
|
921
|
+
return;
|
|
922
|
+
throw new Error(serverActionsUnsupportedMessage({
|
|
923
|
+
file: offender.serverActionFile,
|
|
924
|
+
route: offender.route,
|
|
925
|
+
root
|
|
926
|
+
}));
|
|
927
|
+
}
|
|
928
|
+
function isClientModule(context, file) {
|
|
929
|
+
const key = path.resolve(file);
|
|
930
|
+
let client = context.useClient.get(key);
|
|
931
|
+
if (client === undefined) {
|
|
932
|
+
client = hasUseClientDirective(file, readSource(context, file));
|
|
933
|
+
context.useClient.set(key, client);
|
|
934
|
+
}
|
|
935
|
+
return client;
|
|
936
|
+
}
|
|
937
|
+
function collectClientReferences(context, entryFiles) {
|
|
938
|
+
const references = new Map;
|
|
939
|
+
const visited = new Set;
|
|
940
|
+
for (const file of entryFiles) {
|
|
941
|
+
if (fileExists(context, file)) {
|
|
942
|
+
if (!isClientModule(context, file) && defaultReexportsClientModule(context, file)) {
|
|
943
|
+
addClientReference(references, clientReference(file, "default"));
|
|
944
|
+
}
|
|
945
|
+
}
|
|
946
|
+
collectFromFile(context, file, references, visited);
|
|
947
|
+
}
|
|
948
|
+
const collected = [...references.values()];
|
|
949
|
+
const hasRenderedReference = collected.some((reference) => !reference.sideEffect);
|
|
950
|
+
const filtered = hasRenderedReference ? collected : collected.filter((reference) => !reference.sideEffect);
|
|
951
|
+
return filtered.sort((a, b) => a.id.localeCompare(b.id));
|
|
952
|
+
}
|
|
953
|
+
function defaultReexportsClientModule(context, file, visited = new Set) {
|
|
954
|
+
const key = path.resolve(file);
|
|
955
|
+
if (visited.has(key))
|
|
956
|
+
return false;
|
|
957
|
+
visited.add(key);
|
|
958
|
+
const source = readSource(context, file);
|
|
959
|
+
const specifiers = [];
|
|
960
|
+
for (const edge of scanFacts(file, source).imports) {
|
|
961
|
+
if (edge.reexport && edge.exports.includes("default"))
|
|
962
|
+
specifiers.push(edge.specifier);
|
|
963
|
+
}
|
|
964
|
+
const defaultExpr = /export\s+default\s+([A-Za-z_$][\w$]*)(\s*\.\s*default)?\s*;?/.exec(source);
|
|
965
|
+
if (defaultExpr) {
|
|
966
|
+
const binding = defaultExpr[1];
|
|
967
|
+
const namespaced = Boolean(defaultExpr[2]);
|
|
968
|
+
const importBinding = namespaced ? new RegExp(`import\\s*\\*\\s*as\\s+${binding}\\s+from\\s+['"]([^'"]+)['"]`).exec(source) : new RegExp(`import\\s+${binding}\\s+from\\s+['"]([^'"]+)['"]`).exec(source);
|
|
969
|
+
if (importBinding?.[1])
|
|
970
|
+
specifiers.push(importBinding[1]);
|
|
971
|
+
}
|
|
972
|
+
for (const specifier of specifiers) {
|
|
973
|
+
const resolved = resolveModuleEdge(context, file, specifier);
|
|
974
|
+
if (!resolved || !fileExists(context, resolved))
|
|
975
|
+
continue;
|
|
976
|
+
if (isClientModule(context, resolved))
|
|
977
|
+
return true;
|
|
978
|
+
if (defaultReexportsClientModule(context, resolved, visited))
|
|
979
|
+
return true;
|
|
980
|
+
}
|
|
981
|
+
return false;
|
|
982
|
+
}
|
|
983
|
+
function collectFromFile(context, file, references, visited, withinClientBoundary = false) {
|
|
984
|
+
const visitKey = `${file}\x00${withinClientBoundary ? "client" : "server"}`;
|
|
985
|
+
if (visited.has(visitKey) || !fileExists(context, file))
|
|
986
|
+
return;
|
|
987
|
+
visited.add(visitKey);
|
|
988
|
+
const clientFile = isClientModule(context, file);
|
|
989
|
+
if (clientFile) {
|
|
990
|
+
addClientReference(references, clientReference(file, "default"));
|
|
991
|
+
}
|
|
992
|
+
const nestedClientBoundary = withinClientBoundary || clientFile;
|
|
993
|
+
const imports = [...moduleEdges(context, file)];
|
|
994
|
+
if (!nestedClientBoundary)
|
|
995
|
+
imports.push(...publishedClientImports(context, file));
|
|
996
|
+
for (const imported of imports) {
|
|
997
|
+
if (isClientModule(context, imported.file)) {
|
|
998
|
+
if (imported.star) {
|
|
999
|
+
const importedSource = readSource(context, imported.file);
|
|
1000
|
+
for (const exportName of scanFacts(imported.file, importedSource).exportNames) {
|
|
1001
|
+
if (exportName !== "default") {
|
|
1002
|
+
addClientReference(references, clientReference(imported.file, exportName));
|
|
1003
|
+
}
|
|
1004
|
+
}
|
|
1005
|
+
continue;
|
|
1006
|
+
}
|
|
1007
|
+
if (imported.exports.includes("*")) {
|
|
1008
|
+
throw new Error(`${file} namespace-imports Client Component module ${imported.file}. Import the client component by default or named export instead.`);
|
|
1009
|
+
}
|
|
1010
|
+
if (imported.exports.length === 0) {
|
|
1011
|
+
addClientReference(references, {
|
|
1012
|
+
...clientReference(imported.file, "*side-effect*"),
|
|
1013
|
+
sideEffect: true
|
|
1014
|
+
});
|
|
1015
|
+
continue;
|
|
1016
|
+
}
|
|
1017
|
+
for (const exportName of imported.exports) {
|
|
1018
|
+
addClientReference(references, {
|
|
1019
|
+
...clientReference(imported.file, exportName),
|
|
1020
|
+
dynamic: imported.dynamic
|
|
1021
|
+
});
|
|
1022
|
+
}
|
|
1023
|
+
continue;
|
|
1024
|
+
}
|
|
1025
|
+
if (imported.dynamic?.load === "visible") {
|
|
1026
|
+
console.warn(`${file} uses dynamic({ load: 'visible' }) for ${imported.file}, but the target is a Server Component. It will render on the server instead of loading on visibility.`);
|
|
1027
|
+
}
|
|
1028
|
+
collectFromFile(context, imported.file, references, visited, nestedClientBoundary);
|
|
1029
|
+
}
|
|
1030
|
+
}
|
|
1031
|
+
function addClientReference(references, reference) {
|
|
1032
|
+
const existing = references.get(reference.id);
|
|
1033
|
+
if (!existing) {
|
|
1034
|
+
references.set(reference.id, reference);
|
|
1035
|
+
return;
|
|
1036
|
+
}
|
|
1037
|
+
if (!reference.dynamic)
|
|
1038
|
+
references.set(reference.id, reference);
|
|
1039
|
+
}
|
|
1040
|
+
function cssEntryOrder(options) {
|
|
1041
|
+
return [
|
|
1042
|
+
...options.leadFiles ?? [],
|
|
1043
|
+
...options.layoutFiles,
|
|
1044
|
+
...options.templateFiles,
|
|
1045
|
+
...options.routeFile ? [options.routeFile] : [],
|
|
1046
|
+
...options.specialFiles,
|
|
1047
|
+
...options.slotFiles
|
|
1048
|
+
];
|
|
1049
|
+
}
|
|
1050
|
+
function collectCssImports(context, entryFiles, options = {}) {
|
|
1051
|
+
const imports = new Set;
|
|
1052
|
+
const visited = new Set;
|
|
1053
|
+
for (const file of entryFiles) {
|
|
1054
|
+
collectCssFromFile(context, file, imports, visited);
|
|
1055
|
+
}
|
|
1056
|
+
if (!options.route || !getCssExtensions().deferRootNotFoundCss())
|
|
1057
|
+
return [...imports];
|
|
1058
|
+
const rootNotFound = entryFiles.find((file) => path.dirname(file) === context.appPath && /^not-found\.[^.]+$/.test(path.basename(file)));
|
|
1059
|
+
if (!rootNotFound)
|
|
1060
|
+
return [...imports];
|
|
1061
|
+
const rootNotFoundImports = new Set;
|
|
1062
|
+
collectCssFromFile(context, rootNotFound, rootNotFoundImports, new Set);
|
|
1063
|
+
if (rootNotFoundImports.size === 0)
|
|
1064
|
+
return [...imports];
|
|
1065
|
+
const matchedImports = new Set;
|
|
1066
|
+
for (const file of entryFiles) {
|
|
1067
|
+
if (file === rootNotFound)
|
|
1068
|
+
continue;
|
|
1069
|
+
collectCssFromFile(context, file, matchedImports, new Set);
|
|
1070
|
+
}
|
|
1071
|
+
return [...imports].filter((file) => !rootNotFoundImports.has(file) || matchedImports.has(file));
|
|
1072
|
+
}
|
|
1073
|
+
function collectSourceFiles(context, entryFiles) {
|
|
1074
|
+
const files = new Set;
|
|
1075
|
+
const visited = new Set;
|
|
1076
|
+
for (const file of entryFiles) {
|
|
1077
|
+
collectSourceFile(context, file, files, visited);
|
|
1078
|
+
}
|
|
1079
|
+
return [...files].sort();
|
|
1080
|
+
}
|
|
1081
|
+
function collectSourceFile(context, file, files, visited) {
|
|
1082
|
+
if (visited.has(file) || !fileExists(context, file))
|
|
1083
|
+
return;
|
|
1084
|
+
visited.add(file);
|
|
1085
|
+
files.add(file);
|
|
1086
|
+
if (isAssetFile(file))
|
|
1087
|
+
return;
|
|
1088
|
+
for (const imported of moduleEdges(context, file)) {
|
|
1089
|
+
collectSourceFile(context, imported.file, files, visited);
|
|
1090
|
+
}
|
|
1091
|
+
}
|
|
1092
|
+
function collectCssFromFile(context, file, imports, visited) {
|
|
1093
|
+
if (visited.has(file) || !fileExists(context, file))
|
|
1094
|
+
return;
|
|
1095
|
+
visited.add(file);
|
|
1096
|
+
if (isCssFile(file)) {
|
|
1097
|
+
if (!context.globalCssImports().has(path.resolve(file)))
|
|
1098
|
+
imports.add(file);
|
|
1099
|
+
return;
|
|
1100
|
+
}
|
|
1101
|
+
const clientFile = isClientModule(context, file);
|
|
1102
|
+
for (const imported of moduleEdges(context, file)) {
|
|
1103
|
+
if (isCssFile(imported.file)) {
|
|
1104
|
+
if (!context.globalCssImports().has(path.resolve(imported.file)))
|
|
1105
|
+
imports.add(imported.file);
|
|
1106
|
+
continue;
|
|
1107
|
+
}
|
|
1108
|
+
if (!clientFile && isLazyClientEdge(context, imported))
|
|
1109
|
+
continue;
|
|
1110
|
+
collectCssFromFile(context, imported.file, imports, visited);
|
|
1111
|
+
}
|
|
1112
|
+
}
|
|
1113
|
+
function isLazyClientEdge(context, edge) {
|
|
1114
|
+
if (!edge.dynamic || ssrClientReference({ dynamic: edge.dynamic }))
|
|
1115
|
+
return false;
|
|
1116
|
+
return isClientModule(context, edge.file);
|
|
1117
|
+
}
|
|
1118
|
+
function attachLazyReferenceCss(context, references) {
|
|
1119
|
+
for (const reference of references) {
|
|
1120
|
+
if (ssrClientReference(reference))
|
|
1121
|
+
continue;
|
|
1122
|
+
const css = collectCssImports(context, [reference.file]);
|
|
1123
|
+
if (css.length > 0)
|
|
1124
|
+
reference.cssImports = css;
|
|
1125
|
+
}
|
|
1126
|
+
}
|
|
1127
|
+
function readScanSource(context, file, visited = new Set) {
|
|
1128
|
+
const key = path.resolve(file);
|
|
1129
|
+
if (visited.has(key))
|
|
1130
|
+
return "";
|
|
1131
|
+
visited.add(key);
|
|
1132
|
+
const source = readSource(context, file);
|
|
1133
|
+
const parts = [source];
|
|
1134
|
+
for (const edge of scanFacts(file, source).imports) {
|
|
1135
|
+
if (!edge.reexport || !edge.specifier.startsWith("."))
|
|
1136
|
+
continue;
|
|
1137
|
+
const resolved = resolveModuleEdge(context, file, edge.specifier);
|
|
1138
|
+
if (!resolved || !existsSync(resolved))
|
|
1139
|
+
continue;
|
|
1140
|
+
parts.push(readScanSource(context, resolved, visited));
|
|
1141
|
+
}
|
|
1142
|
+
return parts.join(`
|
|
1143
|
+
`);
|
|
1144
|
+
}
|
|
1145
|
+
function readSource(context, file) {
|
|
1146
|
+
const key = path.resolve(file);
|
|
1147
|
+
let source = context.sources.get(key);
|
|
1148
|
+
if (source === undefined) {
|
|
1149
|
+
source = rewriteLiteralDynamicCalls(readSourceSync(key), file);
|
|
1150
|
+
context.sources.set(key, source);
|
|
1151
|
+
}
|
|
1152
|
+
return source;
|
|
1153
|
+
}
|
|
1154
|
+
var linkSpecifiers = new Set(["next/link", "@wular/pnext/link"]);
|
|
1155
|
+
var navigationSpecifiers = new Set([
|
|
1156
|
+
...linkSpecifiers,
|
|
1157
|
+
"next/form",
|
|
1158
|
+
"next/navigation",
|
|
1159
|
+
"next/router",
|
|
1160
|
+
"@wular/pnext/navigation",
|
|
1161
|
+
"@wular/pnext/navigation/client"
|
|
1162
|
+
]);
|
|
1163
|
+
var rootNavigationExports = new Set([
|
|
1164
|
+
"*",
|
|
1165
|
+
"default",
|
|
1166
|
+
"Link",
|
|
1167
|
+
"permanentRedirect",
|
|
1168
|
+
"redirect",
|
|
1169
|
+
"useLinkStatus",
|
|
1170
|
+
"useParams",
|
|
1171
|
+
"usePathname",
|
|
1172
|
+
"useRoute",
|
|
1173
|
+
"useRouter",
|
|
1174
|
+
"useSearchParams"
|
|
1175
|
+
]);
|
|
1176
|
+
function importReachesNavigation(edge) {
|
|
1177
|
+
if (navigationSpecifiers.has(edge.specifier))
|
|
1178
|
+
return true;
|
|
1179
|
+
if (edge.specifier !== "@wular/pnext")
|
|
1180
|
+
return false;
|
|
1181
|
+
return edge.exports.length === 0 || edge.exports.some((name) => rootNavigationExports.has(name));
|
|
1182
|
+
}
|
|
1183
|
+
function routeUsesLinkComponent(context, files) {
|
|
1184
|
+
for (const file of files) {
|
|
1185
|
+
if (!fileExists(context, file) || isAssetFile(file))
|
|
1186
|
+
continue;
|
|
1187
|
+
const key = path.resolve(file);
|
|
1188
|
+
let uses = context.usesLink.get(key);
|
|
1189
|
+
if (uses === undefined) {
|
|
1190
|
+
const facts = scanFacts(file, readSource(context, file));
|
|
1191
|
+
uses = facts.imports.some((edge) => linkSpecifiers.has(edge.specifier));
|
|
1192
|
+
context.usesLink.set(key, uses);
|
|
1193
|
+
}
|
|
1194
|
+
if (uses)
|
|
1195
|
+
return true;
|
|
1196
|
+
}
|
|
1197
|
+
return false;
|
|
1198
|
+
}
|
|
1199
|
+
function routeUsesNavigation(context, files) {
|
|
1200
|
+
for (const file of files) {
|
|
1201
|
+
if (!fileExists(context, file) || isAssetFile(file))
|
|
1202
|
+
continue;
|
|
1203
|
+
const key = path.resolve(file);
|
|
1204
|
+
let uses = context.usesNavigation.get(key);
|
|
1205
|
+
if (uses === undefined) {
|
|
1206
|
+
const facts = scanFacts(file, readSource(context, file));
|
|
1207
|
+
uses = facts.imports.some(importReachesNavigation);
|
|
1208
|
+
context.usesNavigation.set(key, uses);
|
|
1209
|
+
}
|
|
1210
|
+
if (uses)
|
|
1211
|
+
return true;
|
|
1212
|
+
}
|
|
1213
|
+
return false;
|
|
1214
|
+
}
|
|
1215
|
+
function routeClientEntryReasons(context, files) {
|
|
1216
|
+
const reasons = [];
|
|
1217
|
+
for (const file of files) {
|
|
1218
|
+
if (!fileExists(context, file) || isAssetFile(file))
|
|
1219
|
+
continue;
|
|
1220
|
+
const key = path.resolve(file);
|
|
1221
|
+
let fileReasons = context.entryReasons.get(key);
|
|
1222
|
+
if (fileReasons === undefined) {
|
|
1223
|
+
fileReasons = sourceClientEntryReasons(readSource(context, file));
|
|
1224
|
+
context.entryReasons.set(key, fileReasons);
|
|
1225
|
+
}
|
|
1226
|
+
reasons.push(...fileReasons);
|
|
1227
|
+
}
|
|
1228
|
+
return reasons;
|
|
1229
|
+
}
|
|
1230
|
+
function usesRequestImportDataForFiles(context, files) {
|
|
1231
|
+
for (const file of files) {
|
|
1232
|
+
const key = path.resolve(file);
|
|
1233
|
+
let usesRequestImport = context.requestImportUsage.get(key);
|
|
1234
|
+
if (usesRequestImport === undefined) {
|
|
1235
|
+
usesRequestImport = sourceUsesRegisteredRequestApi(readSource(context, file));
|
|
1236
|
+
context.requestImportUsage.set(key, usesRequestImport);
|
|
1237
|
+
}
|
|
1238
|
+
if (usesRequestImport)
|
|
1239
|
+
return true;
|
|
1240
|
+
}
|
|
1241
|
+
return false;
|
|
1242
|
+
}
|
|
1243
|
+
function routeDependencyClassification(context, kind, files) {
|
|
1244
|
+
const sources = files.filter((file) => !isAssetFile(file)).map((file) => ({ file, source: readSource(context, file) }));
|
|
1245
|
+
return classifyRouteDependencies({ kind, files: sources });
|
|
1246
|
+
}
|
|
1247
|
+
function moduleEdges(context, file) {
|
|
1248
|
+
const key = path.resolve(file);
|
|
1249
|
+
let edges = context.edges.get(key);
|
|
1250
|
+
if (!edges) {
|
|
1251
|
+
edges = moduleEdgesFromSource(context, file, readSource(context, file));
|
|
1252
|
+
context.edges.set(key, edges);
|
|
1253
|
+
}
|
|
1254
|
+
return edges;
|
|
1255
|
+
}
|
|
1256
|
+
function resolveModuleEdge(context, file, specifier) {
|
|
1257
|
+
return resolveModuleAlias(specifier) ?? resolveImport(context.root, file, specifier, context.workspaceRoot) ?? getBundlerExtensions().resolveRouteDependency(context.root, file, specifier) ?? getCssExtensions().resolveCssDependency(context.root, file, specifier);
|
|
1258
|
+
}
|
|
1259
|
+
function publishedClientImports(context, file) {
|
|
1260
|
+
const source = readSource(context, file);
|
|
1261
|
+
const found = [];
|
|
1262
|
+
for (const edge of scanFacts(file, source).imports) {
|
|
1263
|
+
if (resolveModuleEdge(context, file, edge.specifier))
|
|
1264
|
+
continue;
|
|
1265
|
+
found.push(...publishedClientEdges(context, file, edge.specifier, edge.exports));
|
|
1266
|
+
}
|
|
1267
|
+
return found;
|
|
1268
|
+
}
|
|
1269
|
+
function publishedClientEdges(context, file, specifier, requested) {
|
|
1270
|
+
const cacheKey = `${file}\x00${specifier}\x00${requested.join(",")}`;
|
|
1271
|
+
const cached = context.edges.get(cacheKey);
|
|
1272
|
+
if (cached)
|
|
1273
|
+
return cached;
|
|
1274
|
+
const entry = resolvePublishedEdge(context, file, specifier, "import");
|
|
1275
|
+
const edges = entry ? publishedClientExports(context, entry, requested, new Set) : [];
|
|
1276
|
+
context.edges.set(cacheKey, edges);
|
|
1277
|
+
return edges;
|
|
1278
|
+
}
|
|
1279
|
+
function resolvePublishedEdge(context, file, specifier, kind) {
|
|
1280
|
+
return resolveModuleEdge(context, file, specifier) ?? resolvePackageSpecifier(context.root, file, specifier, [kind, "default"]);
|
|
1281
|
+
}
|
|
1282
|
+
function publishedClientExports(context, file, requested, visiting) {
|
|
1283
|
+
const key = path.resolve(file);
|
|
1284
|
+
if (visiting.has(key) || !fileExists(context, key))
|
|
1285
|
+
return [];
|
|
1286
|
+
visiting.add(key);
|
|
1287
|
+
const source = readSource(context, key);
|
|
1288
|
+
if (hasUseClientDirective(key, source)) {
|
|
1289
|
+
visiting.delete(key);
|
|
1290
|
+
const names = [...scanFacts(key, source).exportNames, ...commonJsRouteExportNames(source)];
|
|
1291
|
+
const exports = requested.filter((name) => names.includes(name));
|
|
1292
|
+
return exports.length > 0 ? [{ file: key, exports }] : [];
|
|
1293
|
+
}
|
|
1294
|
+
const facts = scanFacts(key, source);
|
|
1295
|
+
const found = [];
|
|
1296
|
+
for (const edge of facts.imports) {
|
|
1297
|
+
if (!edge.reexport)
|
|
1298
|
+
continue;
|
|
1299
|
+
const map = { ...esmReexportMap(source, edge.specifier), ...edge.exportMap };
|
|
1300
|
+
const next = edge.star ? requested.filter((name) => name !== "default") : requested.map((name) => map[name]).filter((name) => Boolean(name));
|
|
1301
|
+
const target = resolvePublishedEdge(context, key, edge.specifier, "import");
|
|
1302
|
+
if (target && next.length > 0) {
|
|
1303
|
+
found.push(...publishedClientExports(context, target, next, visiting));
|
|
1304
|
+
}
|
|
1305
|
+
}
|
|
1306
|
+
for (const edge of facts.requires) {
|
|
1307
|
+
const map = commonJsRequireReexportMap(source, edge.specifier);
|
|
1308
|
+
const next = map.star ? requested : requested.map((name) => map.names[name]).filter((name) => Boolean(name));
|
|
1309
|
+
const target = resolvePublishedEdge(context, key, edge.specifier, "require");
|
|
1310
|
+
if (target && next.length > 0) {
|
|
1311
|
+
found.push(...publishedClientExports(context, target, next, visiting));
|
|
1312
|
+
}
|
|
1313
|
+
}
|
|
1314
|
+
visiting.delete(key);
|
|
1315
|
+
return found;
|
|
1316
|
+
}
|
|
1317
|
+
function moduleEdgesFromSource(context, file, source) {
|
|
1318
|
+
const dynamicNames = pnextDynamicImportNames(source, file);
|
|
1319
|
+
assertSupportedDynamicCalls(file, source, dynamicNames);
|
|
1320
|
+
const ordered = [];
|
|
1321
|
+
const facts = scanFacts(file, source);
|
|
1322
|
+
for (const edge of facts.imports) {
|
|
1323
|
+
const resolved = resolveModuleEdge(context, file, edge.specifier);
|
|
1324
|
+
if (!resolved)
|
|
1325
|
+
continue;
|
|
1326
|
+
ordered.push({
|
|
1327
|
+
file: resolved,
|
|
1328
|
+
exports: [...edge.exports],
|
|
1329
|
+
index: edge.index,
|
|
1330
|
+
...edge.star ? { star: true } : {}
|
|
1331
|
+
});
|
|
1332
|
+
}
|
|
1333
|
+
ordered.sort((a, b) => a.index - b.index);
|
|
1334
|
+
const imports = ordered.map(({ index: _index, ...edge }) => edge);
|
|
1335
|
+
for (const imported of dynamicImportEdgesFromSource(context, file, source, dynamicNames))
|
|
1336
|
+
imports.push(imported);
|
|
1337
|
+
return imports;
|
|
1338
|
+
}
|
|
1339
|
+
function esmReexportMap(source, specifier) {
|
|
1340
|
+
const escaped = escapeRegex(specifier);
|
|
1341
|
+
const names = {};
|
|
1342
|
+
const pattern = new RegExp(`\\bexport\\s*\\{([^}]*)\\}\\s*from\\s*["']${escaped}["']`, "g");
|
|
1343
|
+
for (const clause of source.matchAll(pattern)) {
|
|
1344
|
+
for (const item of (clause[1] ?? "").split(",")) {
|
|
1345
|
+
const parts = item.trim().split(/\s+as\s+/);
|
|
1346
|
+
const imported = parts[0]?.trim();
|
|
1347
|
+
const exported = (parts[1] ?? parts[0])?.trim();
|
|
1348
|
+
if (imported && exported && /^[$\w]+$/.test(imported) && /^[$\w]+$/.test(exported)) {
|
|
1349
|
+
names[exported] = imported;
|
|
1350
|
+
}
|
|
1351
|
+
}
|
|
1352
|
+
}
|
|
1353
|
+
return names;
|
|
1354
|
+
}
|
|
1355
|
+
function commonJsRequireReexportMap(source, specifier) {
|
|
1356
|
+
const escaped = escapeRegex(specifier);
|
|
1357
|
+
const names = {};
|
|
1358
|
+
const direct = new RegExp(`exports\\.([A-Za-z_$][\\w$]*)\\s*=\\s*require\\(\\s*["']${escaped}["']\\s*\\)\\.([A-Za-z_$][\\w$]*)`, "g");
|
|
1359
|
+
for (const match of source.matchAll(direct)) {
|
|
1360
|
+
names[match[1]] = match[2];
|
|
1361
|
+
}
|
|
1362
|
+
const binding = new RegExp(`(?:const|let|var)\\s+([A-Za-z_$][\\w$]*)\\s*=\\s*require\\(\\s*["']${escaped}["']\\s*\\)`).exec(source)?.[1];
|
|
1363
|
+
if (binding) {
|
|
1364
|
+
const local = escapeRegex(binding);
|
|
1365
|
+
const assignment = new RegExp(`exports\\.([A-Za-z_$][\\w$]*)\\s*=\\s*${local}\\.([A-Za-z_$][\\w$]*)`, "g");
|
|
1366
|
+
for (const match of source.matchAll(assignment)) {
|
|
1367
|
+
names[match[1]] = match[2];
|
|
1368
|
+
}
|
|
1369
|
+
const getter = new RegExp(`Object\\.defineProperty\\(\\s*exports\\s*,\\s*["']([A-Za-z_$][\\w$]*)["'](?:(?!Object\\.defineProperty)[\\s\\S]){0,300}?return\\s+${local}\\.([A-Za-z_$][\\w$]*)`, "g");
|
|
1370
|
+
for (const match of source.matchAll(getter)) {
|
|
1371
|
+
names[match[1]] = match[2];
|
|
1372
|
+
}
|
|
1373
|
+
const helper = new RegExp(`(?:^|[,\\{])\\s*([A-Za-z_$][\\w$]*)\\s*:\\s*\\(\\s*\\)\\s*=>\\s*${local}\\.([A-Za-z_$][\\w$]*)`, "g");
|
|
1374
|
+
for (const match of source.matchAll(helper)) {
|
|
1375
|
+
names[match[1]] = match[2];
|
|
1376
|
+
}
|
|
1377
|
+
}
|
|
1378
|
+
const star = new RegExp(`module\\.exports\\s*=\\s*(?:require\\(\\s*["']${escaped}["']\\s*\\)|${binding ?? "(?!)"})(?=\\s*(?:;|$))`, "m").test(source);
|
|
1379
|
+
return { names, star };
|
|
1380
|
+
}
|
|
1381
|
+
function commonJsRouteExportNames(source) {
|
|
1382
|
+
return [
|
|
1383
|
+
...new Set([
|
|
1384
|
+
...[...source.matchAll(/\bexports\.([A-Za-z_$][\w$]*)\s*=/g)].map((match) => match[1]),
|
|
1385
|
+
...[
|
|
1386
|
+
...source.matchAll(/\bObject\.defineProperty\(\s*exports\s*,\s*["']([A-Za-z_$][\w$]*)["']/g)
|
|
1387
|
+
].map((match) => match[1])
|
|
1388
|
+
])
|
|
1389
|
+
].filter((name) => name !== "__esModule");
|
|
1390
|
+
}
|
|
1391
|
+
function assertSupportedDynamicCalls(file, source, dynamicNames) {
|
|
1392
|
+
for (const call of dynamicCallsFromSource(source, dynamicNames)) {
|
|
1393
|
+
if (!/\bimport\s*\(/.test(call.source)) {
|
|
1394
|
+
throw new Error(`${file} uses dynamic() without a literal import. PNext supports dynamic('./module') or dynamic(() => import('./module')).`);
|
|
1395
|
+
}
|
|
1396
|
+
if (!/\bimport\s*\(\s*['"][^'"]+['"]\s*\)/.test(call.source)) {
|
|
1397
|
+
throw new Error(`${file} uses a non-literal dynamic import. PNext supports dynamic('./module') or dynamic(() => import('./module')).`);
|
|
1398
|
+
}
|
|
1399
|
+
}
|
|
1400
|
+
}
|
|
1401
|
+
function dynamicImportEdgesFromSource(context, file, source, dynamicNames) {
|
|
1402
|
+
const imports = [];
|
|
1403
|
+
if (dynamicNames.size === 0)
|
|
1404
|
+
return imports;
|
|
1405
|
+
const optionObjects = dynamicOptionObjects(source);
|
|
1406
|
+
for (const fact of dynamicCallFacts(source, file)) {
|
|
1407
|
+
if (!dynamicNames.has(fact.name))
|
|
1408
|
+
continue;
|
|
1409
|
+
const resolved = resolveModuleEdge(context, file, fact.specifier);
|
|
1410
|
+
if (!resolved)
|
|
1411
|
+
continue;
|
|
1412
|
+
imports.push({
|
|
1413
|
+
file: resolved,
|
|
1414
|
+
exports: [fact.exportName],
|
|
1415
|
+
dynamic: dynamicOptionsForFact(source, fact, optionObjects)
|
|
1416
|
+
});
|
|
1417
|
+
}
|
|
1418
|
+
return imports;
|
|
1419
|
+
}
|
|
1420
|
+
function dynamicOptionObjects(source) {
|
|
1421
|
+
const options = new Map;
|
|
1422
|
+
const pattern = /const\s+([A-Za-z_$][\w$]*)\s*=\s*({[\s\S]*?})\s*(?:as\s+const\s*)?;/g;
|
|
1423
|
+
let match;
|
|
1424
|
+
while (match = pattern.exec(source)) {
|
|
1425
|
+
const [, name, objectSource] = match;
|
|
1426
|
+
if (name && objectSource)
|
|
1427
|
+
options.set(name, dynamicOptionsFromSource(objectSource));
|
|
1428
|
+
}
|
|
1429
|
+
return options;
|
|
1430
|
+
}
|
|
1431
|
+
function dynamicOptionsForFact(source, fact, optionObjects) {
|
|
1432
|
+
if (fact.optionsStart === undefined || fact.optionsEnd === undefined)
|
|
1433
|
+
return {};
|
|
1434
|
+
const options = source.slice(fact.optionsStart, fact.optionsEnd);
|
|
1435
|
+
if (/^[A-Za-z_$][\w$]*$/.test(options))
|
|
1436
|
+
return optionObjects.get(options) ?? {};
|
|
1437
|
+
return dynamicOptionsFromSource(options);
|
|
1438
|
+
}
|
|
1439
|
+
function dynamicOptionsFromSource(source) {
|
|
1440
|
+
if (!source)
|
|
1441
|
+
return {};
|
|
1442
|
+
return {
|
|
1443
|
+
...dynamicLoadFromSource(source),
|
|
1444
|
+
...dynamicRootMarginFromSource(source),
|
|
1445
|
+
...dynamicSsrFromSource(source),
|
|
1446
|
+
...dynamicThresholdFromSource(source)
|
|
1447
|
+
};
|
|
1448
|
+
}
|
|
1449
|
+
function dynamicLoadFromSource(source) {
|
|
1450
|
+
const match = /\bload\s*:\s*['"](render|visible)['"]/.exec(source);
|
|
1451
|
+
return match?.[1] === "render" || match?.[1] === "visible" ? { load: match[1] } : {};
|
|
1452
|
+
}
|
|
1453
|
+
function dynamicRootMarginFromSource(source) {
|
|
1454
|
+
const match = /\brootMargin\s*:\s*['"]([^'"]+)['"]/.exec(source);
|
|
1455
|
+
return match?.[1] ? { rootMargin: match[1] } : {};
|
|
1456
|
+
}
|
|
1457
|
+
function dynamicSsrFromSource(source) {
|
|
1458
|
+
const match = /\bssr\s*:\s*(true|false)\b/.exec(source);
|
|
1459
|
+
return match?.[1] ? { ssr: match[1] === "true" } : {};
|
|
1460
|
+
}
|
|
1461
|
+
function dynamicThresholdFromSource(source) {
|
|
1462
|
+
const numberMatch = /\bthreshold\s*:\s*(-?\d+(?:\.\d+)?)/.exec(source);
|
|
1463
|
+
if (numberMatch?.[1])
|
|
1464
|
+
return { threshold: Number(numberMatch[1]) };
|
|
1465
|
+
const arrayMatch = /\bthreshold\s*:\s*\[([^\]]*)\]/.exec(source);
|
|
1466
|
+
if (!arrayMatch?.[1])
|
|
1467
|
+
return {};
|
|
1468
|
+
const threshold = arrayMatch[1].split(",").map((value) => Number(value.trim())).filter(Number.isFinite);
|
|
1469
|
+
return threshold.length > 0 ? { threshold } : {};
|
|
1470
|
+
}
|
|
1471
|
+
function isCssFile(file) {
|
|
1472
|
+
return file.endsWith(".css") || getCssExtensions().extraCssExtensions().some((ext) => file.endsWith(ext));
|
|
1473
|
+
}
|
|
1474
|
+
function isAssetFile(file) {
|
|
1475
|
+
return /\.(css|svg|png|jpe?g|gif|webp|ico|woff2?)$/.test(file) || getCssExtensions().extraCssExtensions().some((ext) => file.endsWith(ext));
|
|
1476
|
+
}
|
|
1477
|
+
function exportsExperimentalPpr(sources) {
|
|
1478
|
+
return sources.some((source) => /\bexport\s+const\s+experimental_ppr\s*=\s*true\b/.test(stripComments(source)));
|
|
1479
|
+
}
|
|
1480
|
+
function usesRequestData(source) {
|
|
1481
|
+
const searchable = stripJsxText(stripCommentsAndStrings(source));
|
|
1482
|
+
return /\b(?:request|searchParams)\b/.test(searchable) || sourceUsesRegisteredRequestApi(source);
|
|
1483
|
+
}
|
|
1484
|
+
function stripJsxText(source) {
|
|
1485
|
+
return source.replace(/>([^<>(){}=;\n]*)</g, (_match, text) => `>${" ".repeat(text.length)}<`);
|
|
1486
|
+
}
|
|
1487
|
+
function dynamicApiLabel(sources, kind) {
|
|
1488
|
+
const joined = sources.map(stripCommentsAndStrings).join(`
|
|
1489
|
+
`);
|
|
1490
|
+
if (/\bconnection\s*\(/.test(joined))
|
|
1491
|
+
return "`connection()`";
|
|
1492
|
+
if (/\bcookies\s*\(/.test(joined))
|
|
1493
|
+
return "`cookies()`";
|
|
1494
|
+
if (/\bheaders\s*\(/.test(joined))
|
|
1495
|
+
return "`headers()`";
|
|
1496
|
+
if (/\bdraftMode\s*\(/.test(joined))
|
|
1497
|
+
return "`draftMode()`";
|
|
1498
|
+
if (kind === "handler") {
|
|
1499
|
+
if (/\.formData\b/.test(joined))
|
|
1500
|
+
return "`request.formData`";
|
|
1501
|
+
if (/\bnextUrl\b/.test(joined))
|
|
1502
|
+
return "`nextUrl.toString`";
|
|
1503
|
+
if (/\brequest\.url\b|\breq\.url\b/.test(joined))
|
|
1504
|
+
return "`request.url`";
|
|
1505
|
+
} else if (/\bsearchParams\b/.test(joined)) {
|
|
1506
|
+
return "`await searchParams`, `searchParams.then`, or similar";
|
|
1507
|
+
}
|
|
1508
|
+
return;
|
|
1509
|
+
}
|
|
1510
|
+
function maxDurationFromSources(sources) {
|
|
1511
|
+
const durations = sources.map((source) => /\bexport\s+const\s+maxDuration\s*=\s*(\d+)\b/.exec(source)?.[1]).filter((value) => Boolean(value)).map((value) => Number(value));
|
|
1512
|
+
return durations.length > 0 ? Math.max(...durations) : undefined;
|
|
1513
|
+
}
|
|
1514
|
+
function usesRevalidationApis(source) {
|
|
1515
|
+
return /\b(?:revalidatePath|revalidateTag|updateTag|expirePath|expireTag|unstable_expirePath|unstable_expireTag)\s*\(/.test(stripCommentsAndStrings(source));
|
|
1516
|
+
}
|
|
1517
|
+
var DESTRUCTURED_PARAM = "<destructured>";
|
|
1518
|
+
function routeHandlerUsesRequest(source) {
|
|
1519
|
+
const withoutComments = stripComments(source);
|
|
1520
|
+
const searchable = stripCommentsAndStrings(source);
|
|
1521
|
+
if (sourceUsesRegisteredRequestApi(source))
|
|
1522
|
+
return true;
|
|
1523
|
+
for (const method of routeHandlerMethods) {
|
|
1524
|
+
for (const params of exportedFunctionParams(withoutComments, method)) {
|
|
1525
|
+
const name = firstParameterName(params);
|
|
1526
|
+
if (name === DESTRUCTURED_PARAM)
|
|
1527
|
+
return true;
|
|
1528
|
+
if (name && referencesName(searchable, name) > 1)
|
|
1529
|
+
return true;
|
|
1530
|
+
}
|
|
1531
|
+
}
|
|
1532
|
+
return false;
|
|
1533
|
+
}
|
|
1534
|
+
function exportedFunctionParams(source, method) {
|
|
1535
|
+
const params = [];
|
|
1536
|
+
const functionPattern = new RegExp(`\\bexport\\s+(?:async\\s+)?function\\s+${method}\\s*\\(([^)]*)\\)`, "g");
|
|
1537
|
+
let match;
|
|
1538
|
+
while (match = functionPattern.exec(source)) {
|
|
1539
|
+
params.push(match[1] ?? "");
|
|
1540
|
+
}
|
|
1541
|
+
const arrowPattern = new RegExp(`\\bexport\\s+const\\s+${method}\\s*(?::[^=]+)?=\\s*(?:async\\s*)?(?:\\(([^)]*)\\)|([A-Za-z_$][\\w$]*))\\s*=>`, "g");
|
|
1542
|
+
while (match = arrowPattern.exec(source)) {
|
|
1543
|
+
params.push(match[1] ?? match[2] ?? "");
|
|
1544
|
+
}
|
|
1545
|
+
return params;
|
|
1546
|
+
}
|
|
1547
|
+
function firstParameterName(params) {
|
|
1548
|
+
const first = params.split(",")[0]?.trim();
|
|
1549
|
+
if (!first)
|
|
1550
|
+
return;
|
|
1551
|
+
if (first.startsWith("{") || first.startsWith("["))
|
|
1552
|
+
return DESTRUCTURED_PARAM;
|
|
1553
|
+
const name = /^\.{3}\s*([A-Za-z_$][\w$]*)/.exec(first)?.[1] ?? /^([A-Za-z_$][\w$]*)/.exec(first)?.[1];
|
|
1554
|
+
return name;
|
|
1555
|
+
}
|
|
1556
|
+
function referencesName(source, name) {
|
|
1557
|
+
const pattern = new RegExp(`\\b${escapeRegex(name)}\\b`, "g");
|
|
1558
|
+
return [...source.matchAll(pattern)].length;
|
|
1559
|
+
}
|
|
1560
|
+
function stripCommentsAndStrings(source) {
|
|
1561
|
+
return stripComments(source).replace(/(['"`])(?:\\[\s\S]|(?!\1)[^\\])*\1/g, "");
|
|
1562
|
+
}
|
|
1563
|
+
function stripComments(source) {
|
|
1564
|
+
return source.replace(/\/\*[\s\S]*?\*\//g, "").replace(/(^|[^:])\/\/.*$/gm, "$1");
|
|
1565
|
+
}
|
|
1566
|
+
function rootFromAppPath(appPath) {
|
|
1567
|
+
const normalized = toPosixPath(appPath);
|
|
1568
|
+
return normalized.endsWith("/src/app") ? path.dirname(path.dirname(appPath)) : path.dirname(appPath);
|
|
1569
|
+
}
|
|
1570
|
+
function clientReference(file, exportName) {
|
|
1571
|
+
return {
|
|
1572
|
+
id: `c-${clientReferenceId(file, exportName)}`,
|
|
1573
|
+
file,
|
|
1574
|
+
exportName
|
|
1575
|
+
};
|
|
1576
|
+
}
|
|
1577
|
+
function routeId(route) {
|
|
1578
|
+
if (route === "/")
|
|
1579
|
+
return "index";
|
|
1580
|
+
return route.split("/").filter(Boolean).map((segment) => {
|
|
1581
|
+
if (segment.startsWith(":") && segment.endsWith("*"))
|
|
1582
|
+
return `catchall-${sanitizeIdPart(segment.slice(1, -1))}`;
|
|
1583
|
+
if (segment.startsWith(":"))
|
|
1584
|
+
return `param-${sanitizeIdPart(segment.slice(1))}`;
|
|
1585
|
+
return sanitizeIdPart(segment);
|
|
1586
|
+
}).join("-");
|
|
1587
|
+
}
|
|
1588
|
+
function sanitizeIdPart(value) {
|
|
1589
|
+
return value.replace(/[^a-zA-Z0-9_-]+/g, "-").replace(/^-+|-+$/g, "") || "route";
|
|
1590
|
+
}
|
|
1591
|
+
function routeRank(route) {
|
|
1592
|
+
const spec = route.route.split("/").filter(Boolean).map((segment) => segment.startsWith(":") ? segment.endsWith("*") ? "2" : "1" : "0").join("");
|
|
1593
|
+
return `${spec}:${route.synthetic ? 1 : 0}:${route.route}`;
|
|
1594
|
+
}
|
|
1595
|
+
function escapeRegex(value) {
|
|
1596
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
1597
|
+
}
|
|
1598
|
+
|
|
1599
|
+
export { routeFactsVersion, routeFactsResolved, materializeRouteFacts, materializeRouteFactsPaced, setRouteFactsStore, scanRoutes, addClientEntryReason, collectNotFoundCss, collectFileCss, assertNoServerActionsWithoutCompat };
|