@wular/pnext 0.0.4 → 0.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +22 -16
- package/bin/pnext +6 -1
- package/config/lint/base.js +7 -7
- package/config/ts/base.json +2 -4
- package/config/ts/react.json +2 -6
- package/package.json +23 -2
- package/reference/compat.md +87 -22
- package/reference/config.md +40 -93
- package/reference/css.md +42 -33
- package/reference/dev.md +26 -33
- package/reference/env.md +18 -20
- package/reference/getting-started.md +132 -0
- package/reference/metadata.md +31 -46
- package/reference/navigation.md +65 -105
- package/reference/performance.md +21 -142
- package/reference/rendering.md +78 -75
- package/reference/routing.md +97 -107
- package/reference/typegen.md +27 -29
- package/src/api/cache.ts +36 -37
- package/src/api/client-cache.ts +2 -2
- package/src/api/client-navigation.ts +121 -114
- package/src/api/dynamic.tsx +58 -55
- package/src/api/link.tsx +52 -53
- package/src/api/navigation.ts +59 -58
- package/src/api/server.ts +152 -144
- package/src/api/suspense.ts +4 -4
- package/src/cli/adapters/vercel-warm.ts +126 -121
- package/src/cli/adapters/vercel.ts +437 -443
- package/src/cli/analyze.ts +333 -144
- package/src/cli/{named-bin.ts → boot/named-bin.ts} +37 -37
- package/src/cli/{boot-trace.ts → boot/trace.ts} +10 -10
- package/src/cli/build.ts +976 -978
- package/src/cli/create.ts +72 -64
- package/src/cli/dev.ts +116 -116
- package/src/cli/index.ts +94 -85
- package/src/cli/migrate/package-json.ts +73 -71
- package/src/cli/migrate/report.ts +32 -33
- package/src/cli/migrate/{index.ts → run.ts} +48 -49
- package/src/cli/migrate/scan.ts +46 -46
- package/src/cli/migrate/spinner.ts +9 -9
- package/src/cli/migrate/tsconfig.ts +35 -35
- package/src/cli/{server-entry.ts → serve/entry.ts} +57 -57
- package/src/cli/{request-pipeline.ts → serve/pipeline.ts} +386 -394
- package/src/cli/{serve-ui.ts → serve/ui.ts} +47 -47
- package/src/cli/start.ts +65 -66
- package/src/{typegen.ts → cli/typegen.ts} +59 -59
- package/src/client/build.ts +802 -768
- package/src/client/chunk-fold.ts +245 -240
- package/src/client/{paths.ts → chunk-name.ts} +6 -6
- package/src/client/entry.ts +162 -147
- package/src/client/prebuilt.ts +231 -223
- package/src/client/profile.ts +29 -29
- package/src/client/react-compiler.ts +20 -15
- package/src/client/{compat-surface.ts → react-tier.ts} +64 -64
- package/src/client/reference-stub.ts +51 -51
- package/src/client/reference.ts +19 -19
- package/src/{api → client}/router/events.ts +32 -17
- package/src/{api → client}/router/history.ts +16 -16
- package/src/{api → client}/router/hub.ts +52 -53
- package/src/{api/router.ts → client/router/index.ts} +61 -60
- package/src/{api → client}/router/policies.ts +24 -24
- package/src/{api → client}/router/runtime.ts +2022 -1995
- package/src/{api → client}/router/types.ts +98 -98
- package/src/compat/actions/client-plugin.ts +42 -43
- package/src/compat/actions/client-stub.ts +14 -14
- package/src/compat/actions/{action-client.ts → client.ts} +194 -193
- package/src/compat/actions/config.ts +63 -64
- package/src/compat/actions/detect.ts +68 -68
- package/src/compat/actions/discovery.ts +105 -105
- package/src/compat/actions/{action-dispatch.ts → dispatch.ts} +277 -274
- package/src/compat/actions/early-submit.ts +1 -1
- package/src/compat/actions/endpoint.ts +198 -198
- package/src/compat/actions/extensions.ts +811 -0
- package/src/compat/actions/flight.ts +23 -23
- package/src/compat/actions/form-state.ts +34 -34
- package/src/compat/actions/hoist.ts +382 -236
- package/src/compat/actions/ids.ts +7 -12
- package/src/compat/actions/index.ts +8 -8
- package/src/compat/actions/instances.ts +46 -46
- package/src/compat/actions/origin.ts +47 -48
- package/src/compat/actions/protocol.ts +22 -22
- package/src/compat/actions/registry.ts +19 -19
- package/src/compat/{misc/action-return.ts → actions/return.ts} +60 -57
- package/src/compat/actions/rewrite.ts +125 -125
- package/src/compat/actions/{action-router.ts → router.ts} +10 -10
- package/src/compat/actions/serve.ts +132 -136
- package/src/compat/actions/server-tag.ts +4 -4
- package/src/compat/actions/{action-shared.ts → shared.ts} +34 -34
- package/src/compat/actions/unrecognized-error.ts +4 -4
- package/src/compat/{index.ts → aliases.ts} +112 -109
- package/src/compat/bundler/bun-externals.ts +18 -18
- package/src/compat/bundler/cjs-exports.ts +271 -223
- package/src/compat/bundler/config.ts +116 -111
- package/src/compat/bundler/externals.ts +12 -12
- package/src/compat/bundler/import-meta-url.ts +19 -19
- package/src/compat/bundler/modularize-imports.ts +36 -33
- package/src/compat/bundler/new-url-asset.ts +22 -24
- package/src/compat/bundler/optimize-package-imports.ts +111 -107
- package/src/compat/bundler/polyfill.ts +28 -28
- package/src/compat/bundler/react-compiler.ts +35 -29
- package/src/compat/bundler/react-profiler.tsx +11 -11
- package/src/compat/bundler/relay-transform.ts +48 -47
- package/src/compat/bundler/require-context.ts +119 -113
- package/src/compat/bundler/resolve-extensions.ts +19 -19
- package/src/compat/bundler/source-cache.ts +25 -25
- package/src/compat/bundler/static-imports.ts +7 -7
- package/src/compat/bundler/symlink-imports.ts +46 -46
- package/src/compat/bundler/tsconfig-paths.ts +13 -15
- package/src/compat/bundler/wasm.ts +58 -60
- package/src/compat/bundler/webpack-loaders.ts +254 -241
- package/src/compat/bundler/worker.ts +101 -104
- package/src/compat/cache/build-flags.ts +29 -29
- package/src/compat/cache/build-prerender-errors.ts +40 -44
- package/src/compat/cache/custom-handler.ts +60 -53
- package/src/compat/cache/fetch-patch.ts +240 -240
- package/src/compat/cache/handler.ts +27 -31
- package/src/compat/cache/modern-handler.ts +148 -126
- package/src/compat/cache/resume-data-cache.ts +47 -45
- package/src/compat/cache/revalidate.ts +233 -232
- package/src/compat/cache/runtime-error.ts +35 -35
- package/src/compat/cache/use-cache-transform.ts +442 -417
- package/src/compat/cache/use-cache.ts +650 -614
- package/src/compat/cache-control.ts +140 -142
- package/src/compat/client/base-path.ts +21 -20
- package/src/compat/client/css-order.ts +18 -18
- package/src/compat/client/errors/bare-boundary.ts +11 -11
- package/src/compat/client/errors/control-flow.ts +23 -23
- package/src/compat/client/errors/error-boundary.ts +61 -61
- package/src/compat/client/errors/global-error.ts +101 -91
- package/src/compat/client/errors/install.ts +71 -72
- package/src/compat/client/errors/lazy.ts +23 -23
- package/src/compat/client/errors/primitive-throw.ts +47 -45
- package/src/compat/client/errors/soft-refresh.ts +4 -4
- package/src/compat/client/link-status.ts +33 -33
- package/src/compat/client/{nav-compat-runtime.ts → nav-runtime.ts} +20 -20
- package/src/compat/client/{nav-compat.ts → nav.ts} +12 -13
- package/src/compat/client/navigation-scroll.ts +63 -63
- package/src/compat/client/optimistic-routing.ts +93 -88
- package/src/compat/client/prefetch-cache.ts +23 -24
- package/src/compat/client/route-announcer.ts +35 -35
- package/src/compat/client/segment-cache-policy.ts +20 -20
- package/src/compat/client/segment-cache.ts +309 -315
- package/src/compat/client/segment-prefetch.ts +127 -132
- package/src/compat/client/trailing-slash.ts +5 -4
- package/src/compat/css/chunking.ts +113 -116
- package/src/compat/css/inline-css.ts +21 -21
- package/src/compat/css/lightningcss.ts +37 -38
- package/src/compat/css/modules.ts +161 -175
- package/src/compat/css/nonce.ts +7 -7
- package/src/compat/css/sass-plugin.ts +18 -21
- package/src/compat/css/sass.ts +150 -152
- package/src/compat/css/styled-jsx-runtime.ts +27 -27
- package/src/compat/css/styled-jsx.ts +21 -21
- package/src/compat/edge-runtime.ts +27 -27
- package/src/compat/{adapter → export}/build-complete.ts +72 -75
- package/src/compat/export/client.ts +29 -31
- package/src/compat/export/{index.ts → emit.ts} +111 -110
- package/src/compat/export/standalone.ts +62 -54
- package/src/compat/image-optimizer/cache.ts +51 -49
- package/src/compat/image-optimizer/detect.ts +52 -52
- package/src/compat/image-optimizer/{index.ts → optimize.ts} +189 -194
- package/src/compat/image-optimizer/source.ts +77 -80
- package/src/compat/lifecycle/after-scope.ts +26 -26
- package/src/compat/lifecycle/after.ts +48 -45
- package/src/compat/lifecycle/error-funnel.ts +98 -102
- package/src/compat/lifecycle/error-serialize.ts +30 -26
- package/src/compat/lifecycle/error-ui.ts +67 -32
- package/src/compat/lifecycle/instrumentation-client.ts +36 -38
- package/src/compat/lifecycle/instrumentation.ts +85 -85
- package/src/compat/lifecycle/node-console.ts +11 -11
- package/src/compat/lifecycle/testmode.ts +160 -132
- package/src/compat/mdx/compile.ts +60 -57
- package/src/compat/mdx/plugin.ts +11 -11
- package/src/compat/mdx/{next-mdx-stub.ts → stub.ts} +5 -5
- package/src/compat/{metadata-route-artifacts.ts → metadata-artifacts.ts} +195 -191
- package/src/compat/metadata.ts +75 -81
- package/src/compat/next/cache.ts +68 -69
- package/src/compat/next/canonical-url.ts +9 -9
- package/src/compat/next/client-cache.ts +19 -19
- package/src/compat/next/client-navigation.ts +112 -116
- package/src/compat/next/client-only.ts +1 -1
- package/src/compat/next/client-script.tsx +99 -93
- package/src/compat/next/client-server.ts +10 -10
- package/src/compat/next/config-loader.ts +176 -173
- package/src/compat/next/config.ts +7 -7
- package/src/compat/next/constants.cjs +6 -6
- package/src/compat/next/constants.ts +6 -6
- package/src/compat/next/custom-server.ts +26 -24
- package/src/compat/next/dist/client/components/app-router-headers.ts +21 -21
- package/src/compat/next/dist/server/app-render/work-unit-async-storage.external.cjs +3 -4
- package/src/compat/next/dist/server/web/spec-extension/revalidate.ts +1 -1
- package/src/compat/next/dist/server/web/spec-extension/unstable-cache.ts +1 -1
- package/src/compat/next/dist/server/web/spec-extension/unstable-no-store.ts +1 -1
- package/src/compat/next/dynamic.tsx +21 -18
- package/src/compat/next/error.tsx +52 -52
- package/src/compat/next/font/cache.ts +74 -74
- package/src/compat/next/font/google.ts +2 -2
- package/src/compat/next/font/index.ts +1 -1
- package/src/compat/next/font/local.ts +3 -3
- package/src/compat/next/font/runtime-client.ts +17 -15
- package/src/compat/next/font/runtime.ts +443 -408
- package/src/compat/next/font/shared.ts +120 -108
- package/src/compat/next/form.tsx +63 -63
- package/src/compat/next/head.tsx +2 -2
- package/src/compat/next/headers.ts +103 -95
- package/src/compat/next/image/client.tsx +220 -0
- package/src/compat/next/image/config.ts +56 -58
- package/src/compat/next/image/optimizer.ts +40 -36
- package/src/compat/next/image/patterns.ts +37 -40
- package/src/compat/next/{image-props.ts → image/props.ts} +208 -202
- package/src/compat/next/image/shared.ts +65 -57
- package/src/compat/next/image/static-metadata.ts +98 -107
- package/src/compat/next/image/validate.ts +79 -88
- package/src/compat/next/image.tsx +19 -23
- package/src/compat/next/index.ts +1 -1
- package/src/compat/next/legacy-image.tsx +59 -60
- package/src/compat/next/{link-validation-transform.ts → link-transform.ts} +95 -96
- package/src/compat/next/link.tsx +158 -158
- package/src/compat/next/navigation.cjs +12 -3
- package/src/compat/next/navigation.ts +48 -50
- package/src/compat/next/offline.ts +27 -27
- package/src/compat/next/og.ts +121 -124
- package/src/compat/next/preferred-region.ts +13 -14
- package/src/compat/next/redirects.ts +58 -56
- package/src/compat/next/resource-hints.ts +73 -76
- package/src/compat/next/rewrites.ts +130 -133
- package/src/compat/next/root-params.ts +45 -45
- package/src/compat/next/{optimistic-route-state.ts → route-state.ts} +52 -52
- package/src/compat/next/router.cjs +4 -2
- package/src/compat/next/router.ts +58 -61
- package/src/compat/next/script.tsx +108 -108
- package/src/compat/next/server-only.ts +1 -1
- package/src/compat/next/server.ts +19 -19
- package/src/compat/next/svgr.ts +18 -17
- package/src/compat/next/telemetry.ts +24 -24
- package/src/compat/next/{image-usage.ts → usage.ts} +70 -39
- package/src/compat/next/user-agent.ts +53 -49
- package/src/compat/next/web-vitals.ts +22 -24
- package/src/compat/otel/api.ts +41 -41
- package/src/compat/otel/client-trace-metadata.ts +25 -27
- package/src/compat/otel/fetch-span.ts +29 -29
- package/src/compat/otel/tracer.ts +331 -331
- package/src/compat/pages/api.ts +456 -0
- package/src/compat/pages/client-plugin.ts +36 -36
- package/src/compat/pages/router-state.ts +34 -34
- package/src/compat/pages/{index.ts → router.ts} +130 -135
- package/src/compat/ppr/io.ts +12 -12
- package/src/compat/ppr/missing-root-params.ts +34 -38
- package/src/compat/ppr/root-params-scan.ts +66 -66
- package/src/compat/ppr/root-params-transform.ts +24 -26
- package/src/compat/ppr/root-params.ts +30 -30
- package/src/compat/ppr/segment-config-incompat.ts +6 -7
- package/src/compat/protocol.ts +71 -70
- package/src/compat/react/action-state.ts +47 -48
- package/src/compat/react/client-lite.ts +15 -15
- package/src/compat/react/client.ts +4 -4
- package/src/compat/react/compiler-runtime.ts +11 -11
- package/src/compat/react/dom-client.ts +44 -44
- package/src/compat/react/dom-react-server.ts +10 -16
- package/src/compat/react/dom-server.ts +10 -10
- package/src/compat/react/dom.ts +52 -52
- package/src/compat/react/hooks-extra.ts +34 -35
- package/src/compat/react/parity.ts +64 -61
- package/src/compat/react/preact.ts +81 -82
- package/src/compat/react/react-server.ts +28 -28
- package/src/compat/react/router-shim.ts +1 -1
- package/src/compat/react/server-component-use.ts +8 -8
- package/src/compat/react/server-inserted-html.ts +30 -31
- package/src/compat/react/server.ts +53 -55
- package/src/compat/react/use.ts +32 -32
- package/src/compat/react/view-transition.ts +20 -20
- package/src/compat/register/actions.ts +35 -824
- package/src/compat/register/boot.ts +41 -41
- package/src/compat/register/build-tier.ts +5 -5
- package/src/compat/register/build.ts +74 -70
- package/src/compat/register/bundler.ts +161 -156
- package/src/compat/register/cache.ts +20 -20
- package/src/compat/register/client-errors.ts +3 -3
- package/src/compat/register/config.ts +6 -6
- package/src/compat/register/css-extras.ts +30 -34
- package/src/compat/register/edge-runtime.ts +3 -3
- package/src/compat/register/errors.ts +10 -12
- package/src/compat/register/export.ts +16 -16
- package/src/compat/register/font.ts +11 -11
- package/src/compat/register/hooks.ts +2 -2
- package/src/compat/register/image.ts +40 -40
- package/src/compat/register/index.ts +59 -62
- package/src/compat/register/instrumentation-client.ts +10 -10
- package/src/compat/register/lifecycle.ts +25 -28
- package/src/compat/register/mdx.ts +10 -10
- package/src/compat/register/middleware.ts +226 -16
- package/src/compat/register/otel.ts +80 -88
- package/src/compat/register/pages-api.ts +10 -463
- package/src/compat/register/ppr.ts +16 -16
- package/src/compat/register/protocol.ts +17 -18
- package/src/compat/register/proxy.ts +49 -51
- package/src/compat/register/render.ts +79 -76
- package/src/compat/register/routing.ts +162 -159
- package/src/compat/register/segment.ts +24 -1897
- package/src/compat/register/static-image.ts +3 -3
- package/src/compat/register/{misc.ts → taint.ts} +9 -9
- package/src/compat/register/typed-routes.ts +14 -14
- package/src/compat/register/{usecache.ts → use-cache.ts} +39 -39
- package/src/compat/register/validation.ts +18 -18
- package/src/compat/segment/loading-boundary.ts +43 -45
- package/src/compat/segment/page-slot.ts +69 -69
- package/src/compat/segment/serve.ts +1884 -0
- package/src/compat/segment/tree.ts +113 -112
- package/src/compat/segment/vary-key.ts +38 -38
- package/src/compat/segment/vary-params.ts +138 -142
- package/src/compat/static-params.ts +14 -12
- package/src/compat/tsconfig-defaults.ts +87 -91
- package/src/compat/typecheck/{index.ts → check.ts} +234 -212
- package/src/compat/typecheck/worker.ts +15 -12
- package/src/compat/typed-routes/{index.ts → generate.ts} +36 -36
- package/src/compat/typed-routes/manifest.ts +174 -170
- package/src/compat/typed-routes/typegen.ts +127 -110
- package/src/compat/validation/errors.ts +16 -19
- package/src/compat/validation/prerender-diagnostics.ts +521 -504
- package/src/compat/validation/{index.ts → validate.ts} +647 -648
- package/src/compat-bootstrap.ts +16 -16
- package/src/config.ts +86 -69
- package/src/css/build.ts +230 -227
- package/src/css/postcss.ts +79 -80
- package/src/css/worker.ts +14 -15
- package/src/dev/client-actions.ts +10 -10
- package/src/dev/client-chunk-store.ts +27 -27
- package/src/dev/{client-key-cache.ts → restart/client-key.ts} +76 -76
- package/src/dev/{restart-cache.ts → restart/enabled.ts} +1 -1
- package/src/dev/{global-css-cache.ts → restart/global-css.ts} +91 -83
- package/src/dev/{node-module-bundle-cache.ts → restart/node-modules.ts} +24 -24
- package/src/dev/{route-bundle-key-cache.ts → restart/route-bundle-key.ts} +53 -53
- package/src/dev/{route-facts-cache.ts → restart/route-facts.ts} +82 -82
- package/src/dev/server.ts +804 -820
- package/src/env.ts +46 -43
- package/src/extensions.ts +491 -478
- package/src/index.ts +8 -8
- package/src/internal.ts +20 -23
- package/src/{islands → render}/boundary-error.ts +3 -3
- package/src/render/hooks.ts +71 -71
- package/src/render/island-context.ts +14 -14
- package/src/render/metadata.ts +310 -310
- package/src/{ppr-postpone.ts → render/postpone.ts} +5 -5
- package/src/{ppr.ts → render/ppr.ts} +244 -245
- package/src/render/renderer.ts +2087 -2082
- package/src/render/resource-hints.ts +16 -17
- package/src/render/slots.tsx +224 -235
- package/src/{islands → render}/static-children.ts +9 -12
- package/src/{islands → render}/static-slots.ts +37 -37
- package/src/{cache/context.ts → request/cache.ts} +20 -20
- package/src/request/context.ts +107 -107
- package/src/{dynamic/source.ts → resolve/dynamic.ts} +139 -139
- package/src/resolve/engine.ts +90 -77
- package/src/resolve/imports.ts +475 -463
- package/src/resolve/scan-facts.ts +318 -296
- package/src/resolve/source-text.ts +37 -37
- package/src/{dynamic → resolve}/tree-shake.ts +132 -128
- package/src/routing/forwarded.ts +19 -19
- package/src/routing/handler.ts +84 -91
- package/src/routing/href.ts +87 -70
- package/src/routing/{metadata.ts → metadata-files.ts} +403 -401
- package/src/{proxy.ts → routing/proxy.ts} +306 -312
- package/src/routing/{request-runtime.ts → request-environment.ts} +10 -10
- package/src/routing/routes.ts +827 -815
- package/src/routing/slots.ts +164 -160
- package/src/runtime/loader.ts +954 -0
- package/src/{dev → runtime}/module-cache.ts +309 -287
- package/src/{dev → runtime}/module-generations.ts +9 -9
- package/src/{dev → runtime}/module-transform.ts +81 -72
- package/src/{dev/imports.ts → runtime/modules.ts} +934 -847
- package/src/runtime/{server.ts → vendor-build.ts} +848 -1696
- package/src/runtime/vendor.ts +428 -406
- package/src/styles.d.ts +9 -0
- package/src/types.ts +324 -335
- package/src/utils/ansi.ts +5 -5
- package/src/utils/{source.ts → code.ts} +15 -12
- package/src/utils/content-type.ts +3 -3
- package/src/utils/decode.ts +2 -2
- package/src/utils/dev-profile.ts +13 -13
- package/src/utils/error-log.ts +6 -6
- package/src/utils/esbuild.ts +18 -18
- package/src/utils/fs-cache.ts +13 -13
- package/src/utils/fs.ts +57 -49
- package/src/utils/html.ts +20 -24
- package/src/utils/native-require.ts +8 -8
- package/src/utils/serialize.ts +139 -146
- package/src/utils/verbose.ts +18 -18
- package/reference/overview.md +0 -35
- package/src/cli/analyze-print.ts +0 -181
- package/src/compat/middleware/manifest.ts +0 -210
- package/src/compat/next/image-client.tsx +0 -215
- package/src/compat/next/link-usage.ts +0 -29
- package/src/css/index.ts +0 -2
- package/src/render/index.ts +0 -1
- package/src/style-modules.d.ts +0 -9
|
@@ -1,31 +1,31 @@
|
|
|
1
|
-
import { existsSync, statSync } from 'node:fs'
|
|
2
|
-
import { mkdir, writeFile } from 'node:fs/promises'
|
|
3
|
-
import { createRequire } from 'node:module'
|
|
4
|
-
import path from 'node:path'
|
|
5
|
-
import { Worker } from 'node:worker_threads'
|
|
6
|
-
import type * as TS from 'typescript'
|
|
7
|
-
import type { ResolvedConfig } from '../../config'
|
|
8
|
-
import { getNextConfig, type NextConfigObject } from '../next/config-loader'
|
|
9
|
-
import { turbopackLoaderRules } from '../bundler/config'
|
|
10
|
-
import { scanRootParamTypes, type RootParamValueType } from '../ppr/root-params-scan'
|
|
1
|
+
import { existsSync, statSync } from 'node:fs'
|
|
2
|
+
import { mkdir, writeFile } from 'node:fs/promises'
|
|
3
|
+
import { createRequire } from 'node:module'
|
|
4
|
+
import path from 'node:path'
|
|
5
|
+
import { Worker } from 'node:worker_threads'
|
|
6
|
+
import type * as TS from 'typescript'
|
|
7
|
+
import type { ResolvedConfig } from '../../config'
|
|
8
|
+
import { getNextConfig, type NextConfigObject } from '../next/config-loader'
|
|
9
|
+
import { turbopackLoaderRules } from '../bundler/config'
|
|
10
|
+
import { scanRootParamTypes, type RootParamValueType } from '../ppr/root-params-scan'
|
|
11
11
|
|
|
12
12
|
export class PnextTypecheckError extends Error {
|
|
13
13
|
/** The individual diagnostics, kept so the worker can ship them across intact. */
|
|
14
|
-
readonly messages: string[]
|
|
14
|
+
readonly messages: string[]
|
|
15
15
|
constructor(messages: string[]) {
|
|
16
|
-
super(messages.join('\n'))
|
|
17
|
-
this.name = 'PnextTypecheckError'
|
|
18
|
-
this.messages = messages
|
|
16
|
+
super(messages.join('\n'))
|
|
17
|
+
this.name = 'PnextTypecheckError'
|
|
18
|
+
this.messages = messages
|
|
19
19
|
}
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
// `typescript` is 8 MB of JS and is needed ONLY to read the app's tsconfig
|
|
23
23
|
// (extends chains, ambient file lists) and as the fallback checker. Loading it
|
|
24
24
|
// lazily keeps it out of every build that never reaches this step.
|
|
25
|
-
let typescriptModule: typeof TS | undefined
|
|
25
|
+
let typescriptModule: typeof TS | undefined
|
|
26
26
|
async function loadTypescript(): Promise<typeof TS> {
|
|
27
|
-
typescriptModule ??= (await import('typescript')) as unknown as typeof TS
|
|
28
|
-
return typescriptModule
|
|
27
|
+
typescriptModule ??= (await import('typescript')) as unknown as typeof TS
|
|
28
|
+
return typescriptModule
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
/**
|
|
@@ -34,20 +34,19 @@ async function loadTypescript(): Promise<typeof TS> {
|
|
|
34
34
|
* the test asserts - rely on the build completing so the app can start and surface it.
|
|
35
35
|
*/
|
|
36
36
|
export function typecheckDisabled(): boolean {
|
|
37
|
-
const typescript = getNextConfig().typescript as { ignoreBuildErrors?: unknown } | undefined
|
|
38
|
-
return typescript?.ignoreBuildErrors === true
|
|
37
|
+
const typescript = getNextConfig().typescript as { ignoreBuildErrors?: unknown } | undefined
|
|
38
|
+
return typescript?.ignoreBuildErrors === true
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
/** What ./worker.ts needs to run the check without re-loading the app config. */
|
|
42
42
|
export interface TypecheckWorkerInput {
|
|
43
|
-
root: string
|
|
44
|
-
outPath: string
|
|
45
|
-
nextConfig: NextConfigObject
|
|
43
|
+
root: string
|
|
44
|
+
outPath: string
|
|
45
|
+
nextConfig: NextConfigObject
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
export type TypecheckWorkerResult =
|
|
49
|
-
| { ok:
|
|
50
|
-
| { ok: false; messages?: string[]; failure?: string };
|
|
49
|
+
{ ok: true } | { ok: false; messages?: string[]; failure?: string }
|
|
51
50
|
|
|
52
51
|
/**
|
|
53
52
|
* Run the check on a worker thread, so `typescript`'s large import and the diagnostics pass land
|
|
@@ -59,8 +58,8 @@ export type TypecheckWorkerResult =
|
|
|
59
58
|
* A worker that cannot start at all falls back to the in-process path rather than failing the build.
|
|
60
59
|
*/
|
|
61
60
|
export async function validateTypesOffThread(config: ResolvedConfig): Promise<void> {
|
|
62
|
-
if (typecheckDisabled()) return
|
|
63
|
-
const next = getNextConfig()
|
|
61
|
+
if (typecheckDisabled()) return
|
|
62
|
+
const next = getNextConfig()
|
|
64
63
|
const input: TypecheckWorkerInput = {
|
|
65
64
|
root: config.root,
|
|
66
65
|
outPath: config.outPath,
|
|
@@ -69,31 +68,31 @@ export async function validateTypesOffThread(config: ResolvedConfig): Promise<vo
|
|
|
69
68
|
typedRoutes: next.typedRoutes,
|
|
70
69
|
turbopack: next.turbopack,
|
|
71
70
|
}),
|
|
72
|
-
}
|
|
73
|
-
let worker: Worker
|
|
71
|
+
}
|
|
72
|
+
let worker: Worker
|
|
74
73
|
try {
|
|
75
|
-
worker = new Worker(new URL('./worker.ts', import.meta.url), { workerData: input })
|
|
74
|
+
worker = new Worker(new URL('./worker.ts', import.meta.url), { workerData: input })
|
|
76
75
|
} catch {
|
|
77
|
-
return validateTypes(config)
|
|
76
|
+
return validateTypes(config)
|
|
78
77
|
}
|
|
79
78
|
const result = await new Promise<TypecheckWorkerResult>((resolve, reject) => {
|
|
80
|
-
worker.on('message', resolve)
|
|
81
|
-
worker.on('error', reject)
|
|
79
|
+
worker.on('message', resolve)
|
|
80
|
+
worker.on('error', reject)
|
|
82
81
|
// A worker that exits without a message crashed in a way `error` missed;
|
|
83
82
|
// treat it as a clean check rather than failing a build over the harness.
|
|
84
|
-
worker.on('exit', () => resolve({ ok: true }))
|
|
85
|
-
}).finally(() => void worker.terminate())
|
|
86
|
-
if (result.ok) return
|
|
87
|
-
if (result.messages) throw new PnextTypecheckError(result.messages)
|
|
88
|
-
throw new Error(result.failure ?? 'typecheck worker failed')
|
|
83
|
+
worker.on('exit', () => resolve({ ok: true }))
|
|
84
|
+
}).finally(() => void worker.terminate())
|
|
85
|
+
if (result.ok) return
|
|
86
|
+
if (result.messages) throw new PnextTypecheckError(result.messages)
|
|
87
|
+
throw new Error(result.failure ?? 'typecheck worker failed')
|
|
89
88
|
}
|
|
90
89
|
|
|
91
90
|
/** Drop anything structured-clone would reject (a `turbopack.rules` function). */
|
|
92
91
|
function cloneable(value: NextConfigObject): NextConfigObject {
|
|
93
92
|
try {
|
|
94
|
-
return JSON.parse(JSON.stringify(value)) as NextConfigObject
|
|
93
|
+
return JSON.parse(JSON.stringify(value)) as NextConfigObject
|
|
95
94
|
} catch {
|
|
96
|
-
return {}
|
|
95
|
+
return {}
|
|
97
96
|
}
|
|
98
97
|
}
|
|
99
98
|
|
|
@@ -108,23 +107,23 @@ function cloneable(value: NextConfigObject): NextConfigObject {
|
|
|
108
107
|
* suites match. That second pass only ever runs on a build that is already failing.
|
|
109
108
|
*/
|
|
110
109
|
export async function validateTypes(config: ResolvedConfig): Promise<void> {
|
|
111
|
-
if (typecheckDisabled()) return
|
|
112
|
-
const native = await nativeCheckerBin(config.root)
|
|
113
|
-
const project = await writeTypecheckProject(config, native)
|
|
114
|
-
if (native && (await checkWithNative(native, project, config)).length === 0) return
|
|
115
|
-
const messages = await checkInProcess(project, config)
|
|
116
|
-
if (messages.length === 0) return
|
|
117
|
-
throw new PnextTypecheckError(messages)
|
|
110
|
+
if (typecheckDisabled()) return
|
|
111
|
+
const native = await nativeCheckerBin(config.root)
|
|
112
|
+
const project = await writeTypecheckProject(config, native)
|
|
113
|
+
if (native && (await checkWithNative(native, project, config)).length === 0) return
|
|
114
|
+
const messages = await checkInProcess(project, config)
|
|
115
|
+
if (messages.length === 0) return
|
|
116
|
+
throw new PnextTypecheckError(messages)
|
|
118
117
|
}
|
|
119
118
|
|
|
120
119
|
async function checkInProcess(project: string, config: ResolvedConfig): Promise<string[]> {
|
|
121
|
-
const ts = await loadTypescript()
|
|
122
|
-
const parsed = readProject(ts, project)
|
|
123
|
-
const program = ts.createProgram(parsed.fileNames, parsed.options)
|
|
120
|
+
const ts = await loadTypescript()
|
|
121
|
+
const parsed = readProject(ts, project)
|
|
122
|
+
const program = ts.createProgram(parsed.fileNames, parsed.options)
|
|
124
123
|
const diagnostics = ts
|
|
125
124
|
.getPreEmitDiagnostics(program)
|
|
126
|
-
.filter(diagnostic => appDiagnostic(diagnostic.file?.fileName, config))
|
|
127
|
-
return formatDiagnostics(ts, diagnostics)
|
|
125
|
+
.filter(diagnostic => appDiagnostic(diagnostic.file?.fileName, config))
|
|
126
|
+
return formatDiagnostics(ts, diagnostics)
|
|
128
127
|
}
|
|
129
128
|
|
|
130
129
|
/**
|
|
@@ -133,23 +132,23 @@ async function checkInProcess(project: string, config: ResolvedConfig): Promise<
|
|
|
133
132
|
*/
|
|
134
133
|
async function nativeCheckerBin(root: string): Promise<string | undefined> {
|
|
135
134
|
// eslint-disable-next-line turbo/no-undeclared-env-vars
|
|
136
|
-
if (process.env.PNEXT_TYPECHECK === 'classic') return undefined
|
|
135
|
+
if (process.env.PNEXT_TYPECHECK === 'classic') return undefined
|
|
137
136
|
for (const base of [root, import.meta.dirname]) {
|
|
138
137
|
try {
|
|
139
|
-
const require = createRequire(path.join(base, 'noop.js'))
|
|
140
|
-
const pkg = require.resolve('@typescript/native-preview/package.json')
|
|
138
|
+
const require = createRequire(path.join(base, 'noop.js'))
|
|
139
|
+
const pkg = require.resolve('@typescript/native-preview/package.json')
|
|
141
140
|
// The package exposes the platform binary only through its own resolver
|
|
142
141
|
// (the published `.` export is just a version stub).
|
|
143
142
|
const { default: getExePath } = (await import(
|
|
144
143
|
path.join(path.dirname(pkg), 'lib', 'getExePath.js')
|
|
145
|
-
)) as { default: () => string }
|
|
146
|
-
const bin = getExePath()
|
|
147
|
-
if (bin && existsSync(bin)) return bin
|
|
144
|
+
)) as { default: () => string }
|
|
145
|
+
const bin = getExePath()
|
|
146
|
+
if (bin && existsSync(bin)) return bin
|
|
148
147
|
} catch {
|
|
149
148
|
// keep looking
|
|
150
149
|
}
|
|
151
150
|
}
|
|
152
|
-
return undefined
|
|
151
|
+
return undefined
|
|
153
152
|
}
|
|
154
153
|
|
|
155
154
|
async function checkWithNative(
|
|
@@ -161,13 +160,13 @@ async function checkWithNative(
|
|
|
161
160
|
cwd: config.root,
|
|
162
161
|
stdout: 'pipe',
|
|
163
162
|
stderr: 'pipe',
|
|
164
|
-
})
|
|
163
|
+
})
|
|
165
164
|
const [stdout, stderr] = await Promise.all([
|
|
166
165
|
new Response(proc.stdout).text(),
|
|
167
166
|
new Response(proc.stderr).text(),
|
|
168
|
-
])
|
|
169
|
-
await proc.exited
|
|
170
|
-
return nativeDiagnostics(`${stdout}${stderr}`, config)
|
|
167
|
+
])
|
|
168
|
+
await proc.exited
|
|
169
|
+
return nativeDiagnostics(`${stdout}${stderr}`, config)
|
|
171
170
|
}
|
|
172
171
|
|
|
173
172
|
/**
|
|
@@ -177,44 +176,44 @@ async function checkWithNative(
|
|
|
177
176
|
* a message chain.
|
|
178
177
|
*/
|
|
179
178
|
function nativeDiagnostics(output: string, config: ResolvedConfig): string[] {
|
|
180
|
-
const header = /^(?:(.+)\((\d+),(\d+)\): )?error TS\d+: (.*)
|
|
181
|
-
const messages = new Set<string>()
|
|
182
|
-
const lines = output.split('\n')
|
|
179
|
+
const header = /^(?:(.+)\((\d+),(\d+)\): )?error TS\d+: (.*)$/
|
|
180
|
+
const messages = new Set<string>()
|
|
181
|
+
const lines = output.split('\n')
|
|
183
182
|
for (let index = 0; index < lines.length; index += 1) {
|
|
184
|
-
const match = header.exec(lines[index]!)
|
|
185
|
-
if (!match) continue
|
|
186
|
-
const [, file, line, column, text] = match
|
|
187
|
-
const elaborations: string[] = []
|
|
183
|
+
const match = header.exec(lines[index]!)
|
|
184
|
+
if (!match) continue
|
|
185
|
+
const [, file, line, column, text] = match
|
|
186
|
+
const elaborations: string[] = []
|
|
188
187
|
while (index + 1 < lines.length && /^\s+\S/.test(lines[index + 1]!)) {
|
|
189
|
-
elaborations.push(lines[index + 1]!)
|
|
190
|
-
index += 1
|
|
188
|
+
elaborations.push(lines[index + 1]!)
|
|
189
|
+
index += 1
|
|
191
190
|
}
|
|
192
|
-
const resolved = file ? path.resolve(config.root, file) : undefined
|
|
193
|
-
if (!appDiagnostic(resolved, config)) continue
|
|
194
|
-
const raw = [text, ...elaborations].join('\n')
|
|
195
|
-
const location = resolved ? `${resolved}:${line}:${column}\n` : ''
|
|
196
|
-
messages.add(`${location}Type error: ${typedRouteMessage(raw) ?? raw}`)
|
|
191
|
+
const resolved = file ? path.resolve(config.root, file) : undefined
|
|
192
|
+
if (!appDiagnostic(resolved, config)) continue
|
|
193
|
+
const raw = [text, ...elaborations].join('\n')
|
|
194
|
+
const location = resolved ? `${resolved}:${line}:${column}\n` : ''
|
|
195
|
+
messages.add(`${location}Type error: ${typedRouteMessage(raw) ?? raw}`)
|
|
197
196
|
}
|
|
198
|
-
return [...messages]
|
|
197
|
+
return [...messages]
|
|
199
198
|
}
|
|
200
199
|
|
|
201
200
|
// Only diagnostics originating in the app's own sources may fail the build;
|
|
202
201
|
// errors inside node_modules, pnext shims, or generated files are never the
|
|
203
202
|
// app author's fault (Next.js typechecks with the same scoping).
|
|
204
203
|
function appDiagnostic(file: string | undefined, config: ResolvedConfig): boolean {
|
|
205
|
-
if (!file) return true
|
|
206
|
-
const resolved = path.resolve(file)
|
|
204
|
+
if (!file) return true
|
|
205
|
+
const resolved = path.resolve(file)
|
|
207
206
|
// The generated project is pnext's own; an option error in it (TS5102 and
|
|
208
207
|
// friends) is a framework bug and must never be silently swallowed.
|
|
209
|
-
if (resolved === generatedProjectPath(config)) return true
|
|
210
|
-
if (!resolved.startsWith(config.root + path.sep)) return false
|
|
211
|
-
if (resolved.includes(`${path.sep}node_modules${path.sep}`)) return false
|
|
212
|
-
if (resolved.startsWith(path.resolve(config.outPath) + path.sep)) return false
|
|
213
|
-
return true
|
|
208
|
+
if (resolved === generatedProjectPath(config)) return true
|
|
209
|
+
if (!resolved.startsWith(config.root + path.sep)) return false
|
|
210
|
+
if (resolved.includes(`${path.sep}node_modules${path.sep}`)) return false
|
|
211
|
+
if (resolved.startsWith(path.resolve(config.outPath) + path.sep)) return false
|
|
212
|
+
return true
|
|
214
213
|
}
|
|
215
214
|
|
|
216
215
|
function generatedProjectPath(config: ResolvedConfig): string {
|
|
217
|
-
return path.resolve(config.outPath, 'typecheck', 'tsconfig.json')
|
|
216
|
+
return path.resolve(config.outPath, 'typecheck', 'tsconfig.json')
|
|
218
217
|
}
|
|
219
218
|
|
|
220
219
|
/**
|
|
@@ -231,33 +230,33 @@ function reactTypePaths(
|
|
|
231
230
|
basePaths: Record<string, string[]> | undefined,
|
|
232
231
|
compatPreact?: string,
|
|
233
232
|
): Record<string, string[]> | undefined {
|
|
234
|
-
const react = resolveTypesDir('react', root)
|
|
235
|
-
if (!react) return basePaths
|
|
236
|
-
const reactDom = resolveTypesDir('react-dom', root)
|
|
237
|
-
const paths: Record<string, string[]> = { ...basePaths }
|
|
233
|
+
const react = resolveTypesDir('react', root)
|
|
234
|
+
if (!react) return basePaths
|
|
235
|
+
const reactDom = resolveTypesDir('react-dom', root)
|
|
236
|
+
const paths: Record<string, string[]> = { ...basePaths }
|
|
238
237
|
const mappings: Record<string, string | undefined> = {
|
|
239
238
|
react: path.join(react, 'index.d.ts'),
|
|
240
239
|
'react/*': path.join(react, '*'),
|
|
241
240
|
'react-dom': reactDom && path.join(reactDom, 'index.d.ts'),
|
|
242
241
|
'react-dom/*': reactDom && path.join(reactDom, '*'),
|
|
243
242
|
preact: compatPreact,
|
|
244
|
-
}
|
|
243
|
+
}
|
|
245
244
|
for (const [key, value] of Object.entries(mappings)) {
|
|
246
|
-
if (value) paths[key] = [value]
|
|
245
|
+
if (value) paths[key] = [value]
|
|
247
246
|
}
|
|
248
|
-
return paths
|
|
247
|
+
return paths
|
|
249
248
|
}
|
|
250
249
|
|
|
251
250
|
function resolveTypesDir(name: string, root: string): string | undefined {
|
|
252
251
|
for (const base of [root, import.meta.dirname]) {
|
|
253
252
|
try {
|
|
254
|
-
const require = createRequire(path.join(base, 'noop.js'))
|
|
255
|
-
return path.dirname(require.resolve(`@types/${name}/package.json`))
|
|
253
|
+
const require = createRequire(path.join(base, 'noop.js'))
|
|
254
|
+
return path.dirname(require.resolve(`@types/${name}/package.json`))
|
|
256
255
|
} catch {
|
|
257
256
|
// keep looking
|
|
258
257
|
}
|
|
259
258
|
}
|
|
260
|
-
return undefined
|
|
259
|
+
return undefined
|
|
261
260
|
}
|
|
262
261
|
|
|
263
262
|
// Rebase an app's `paths` onto absolute targets so the generated project (which
|
|
@@ -266,55 +265,55 @@ function absolutePaths(
|
|
|
266
265
|
paths: TS.MapLike<string[]> | undefined,
|
|
267
266
|
basePath: string,
|
|
268
267
|
): Record<string, string[]> | undefined {
|
|
269
|
-
if (!paths) return undefined
|
|
268
|
+
if (!paths) return undefined
|
|
270
269
|
return Object.fromEntries(
|
|
271
270
|
Object.entries(paths).map(([key, targets]) => [
|
|
272
271
|
key,
|
|
273
272
|
targets.map(target => (path.isAbsolute(target) ? target : path.resolve(basePath, target))),
|
|
274
273
|
]),
|
|
275
|
-
)
|
|
274
|
+
)
|
|
276
275
|
}
|
|
277
276
|
|
|
278
277
|
function resolvePackageDir(name: string, root: string): string | undefined {
|
|
279
278
|
for (const base of [root, import.meta.dirname]) {
|
|
280
279
|
try {
|
|
281
|
-
const require = createRequire(path.join(base, 'noop.js'))
|
|
282
|
-
return path.dirname(require.resolve(`${name}/package.json`))
|
|
280
|
+
const require = createRequire(path.join(base, 'noop.js'))
|
|
281
|
+
return path.dirname(require.resolve(`${name}/package.json`))
|
|
283
282
|
} catch {
|
|
284
283
|
// keep looking
|
|
285
284
|
}
|
|
286
285
|
}
|
|
287
|
-
return undefined
|
|
286
|
+
return undefined
|
|
288
287
|
}
|
|
289
288
|
|
|
290
289
|
async function writeTypecheckProject(
|
|
291
290
|
config: ResolvedConfig,
|
|
292
291
|
native: string | undefined,
|
|
293
292
|
): Promise<string> {
|
|
294
|
-
const dir = path.join(config.outPath, 'typecheck')
|
|
295
|
-
await mkdir(dir, { recursive: true })
|
|
296
|
-
const reactTypes = resolveTypesDir('react', config.root)
|
|
297
|
-
const hasReactTypes = reactTypes !== undefined
|
|
298
|
-
const rootParams = scanRootParamTypes(path.join(config.root, 'app'))
|
|
293
|
+
const dir = path.join(config.outPath, 'typecheck')
|
|
294
|
+
await mkdir(dir, { recursive: true })
|
|
295
|
+
const reactTypes = resolveTypesDir('react', config.root)
|
|
296
|
+
const hasReactTypes = reactTypes !== undefined
|
|
297
|
+
const rootParams = scanRootParamTypes(path.join(config.root, 'app'))
|
|
299
298
|
// With `typedRoutes` on, the build generates `.next/types/link.d.ts`, whose next/link, next/navigation
|
|
300
299
|
// and next augmentations layer the RouteImpl type onto the *real* next package. pnext's own permissive
|
|
301
300
|
// `next/*` shims would shadow those and mask the typed-route errors the suite asserts. When the real next
|
|
302
301
|
// package is resolvable from the app, drop the next-module shims and let real next plus the generated
|
|
303
302
|
// files drive the check - exactly what `next build` does.
|
|
304
|
-
const omitNextModuleShims = typedRoutesEnabled() && realNextResolvable(config.root)
|
|
303
|
+
const omitNextModuleShims = typedRoutesEnabled() && realNextResolvable(config.root)
|
|
305
304
|
await writeFile(
|
|
306
305
|
path.join(dir, 'next-shims.d.ts'),
|
|
307
306
|
nextShims(hasReactTypes, rootParams, omitNextModuleShims),
|
|
308
|
-
)
|
|
309
|
-
const preact = resolvePackageDir('preact', config.root)
|
|
307
|
+
)
|
|
308
|
+
const preact = resolvePackageDir('preact', config.root)
|
|
310
309
|
if (reactTypes && preact) {
|
|
311
|
-
await writeFile(preactTypeShimPath(config), preactTypeShim(preact, reactTypes))
|
|
310
|
+
await writeFile(preactTypeShimPath(config), preactTypeShim(preact, reactTypes))
|
|
312
311
|
}
|
|
313
|
-
const base = tsconfigPath(config.root)
|
|
314
|
-
const baseProject = base ? await readBaseProject(base, native) : undefined
|
|
315
|
-
const baseOptions = baseProject?.options ?? {}
|
|
316
|
-
const preactShim = preactTypeShimPath(config)
|
|
317
|
-
const project = generatedProjectPath(config)
|
|
312
|
+
const base = tsconfigPath(config.root)
|
|
313
|
+
const baseProject = base ? await readBaseProject(base, native) : undefined
|
|
314
|
+
const baseOptions = baseProject?.options ?? {}
|
|
315
|
+
const preactShim = preactTypeShimPath(config)
|
|
316
|
+
const project = generatedProjectPath(config)
|
|
318
317
|
const paths = reactTypePaths(
|
|
319
318
|
config.root,
|
|
320
319
|
absolutePaths(
|
|
@@ -322,12 +321,12 @@ async function writeTypecheckProject(
|
|
|
322
321
|
baseOptions.baseUrl ?? (base ? path.dirname(base) : config.root),
|
|
323
322
|
),
|
|
324
323
|
existsSync(preactShim) ? preactShim : undefined,
|
|
325
|
-
)
|
|
324
|
+
)
|
|
326
325
|
// App sources (and fixture helpers they import) may use node builtins
|
|
327
326
|
// (`node:fs`, `node:path`). Next resolves them through @types/node; put the
|
|
328
327
|
// app's copy (or pnext's fallback) in the program so `Cannot find module
|
|
329
328
|
// 'node:*'` never fails an app build.
|
|
330
|
-
const nodeTypes = resolveTypesDir('node', config.root)
|
|
329
|
+
const nodeTypes = resolveTypesDir('node', config.root)
|
|
331
330
|
await writeFile(
|
|
332
331
|
project,
|
|
333
332
|
JSON.stringify(
|
|
@@ -365,9 +364,7 @@ async function writeTypecheckProject(
|
|
|
365
364
|
...(baseOptions.strict === undefined ? { strict: false } : {}),
|
|
366
365
|
...(baseOptions.target === undefined ? { target: 'es2022' } : {}),
|
|
367
366
|
...(baseOptions.module === undefined ? { module: 'esnext' } : {}),
|
|
368
|
-
...(baseOptions.moduleResolution === undefined
|
|
369
|
-
? { moduleResolution: 'bundler' }
|
|
370
|
-
: {}),
|
|
367
|
+
...(baseOptions.moduleResolution === undefined ? { moduleResolution: 'bundler' } : {}),
|
|
371
368
|
...(baseOptions.lib === undefined ? { lib: ['es2022', 'dom', 'dom.iterable'] } : {}),
|
|
372
369
|
},
|
|
373
370
|
include: [
|
|
@@ -411,43 +408,46 @@ async function writeTypecheckProject(
|
|
|
411
408
|
null,
|
|
412
409
|
2,
|
|
413
410
|
),
|
|
414
|
-
)
|
|
415
|
-
return project
|
|
411
|
+
)
|
|
412
|
+
return project
|
|
416
413
|
}
|
|
417
414
|
|
|
418
415
|
function preactTypeShimPath(config: ResolvedConfig): string {
|
|
419
|
-
return path.join(config.outPath, 'typecheck', 'preact-compat.d.ts')
|
|
416
|
+
return path.join(config.outPath, 'typecheck', 'preact-compat.d.ts')
|
|
420
417
|
}
|
|
421
418
|
|
|
422
419
|
function preactTypeShim(preact: string, react: string): string {
|
|
423
|
-
const preactTypes = JSON.stringify(path.join(preact, 'src', 'index.d.ts'))
|
|
424
|
-
const types = JSON.stringify(path.join(react, 'index.d.ts'))
|
|
420
|
+
const preactTypes = JSON.stringify(path.join(preact, 'src', 'index.d.ts'))
|
|
421
|
+
const types = JSON.stringify(path.join(react, 'index.d.ts'))
|
|
425
422
|
return `import type { ReactNode } from ${types}
|
|
426
423
|
|
|
427
424
|
export * from ${preactTypes}
|
|
428
425
|
export type ComponentChild = ReactNode
|
|
429
426
|
export type ComponentChildren = ReactNode
|
|
430
|
-
|
|
427
|
+
`
|
|
431
428
|
}
|
|
432
429
|
|
|
433
430
|
function typedRoutesEnabled(): boolean {
|
|
434
|
-
return (getNextConfig() as { typedRoutes?: unknown }).typedRoutes === true
|
|
431
|
+
return (getNextConfig() as { typedRoutes?: unknown }).typedRoutes === true
|
|
435
432
|
}
|
|
436
433
|
|
|
437
434
|
// Whether the real `next` package's type entry resolves from the app root.
|
|
438
435
|
function realNextResolvable(root: string): boolean {
|
|
439
436
|
try {
|
|
440
|
-
createRequire(path.join(root, 'noop.js')).resolve('next/package.json')
|
|
441
|
-
return true
|
|
437
|
+
createRequire(path.join(root, 'noop.js')).resolve('next/package.json')
|
|
438
|
+
return true
|
|
442
439
|
} catch {
|
|
443
|
-
return false
|
|
440
|
+
return false
|
|
444
441
|
}
|
|
445
442
|
}
|
|
446
443
|
|
|
447
444
|
/** Absolute `.d.ts` paths the app's own tsconfig would have put in the program. */
|
|
448
|
-
function baseAmbientDeclarations(
|
|
449
|
-
|
|
450
|
-
|
|
445
|
+
function baseAmbientDeclarations(
|
|
446
|
+
fileNames: readonly string[] | undefined,
|
|
447
|
+
config: ResolvedConfig,
|
|
448
|
+
): string[] {
|
|
449
|
+
if (!fileNames) return []
|
|
450
|
+
const outPath = path.resolve(config.outPath) + path.sep
|
|
451
451
|
return fileNames
|
|
452
452
|
.map(name => path.resolve(name))
|
|
453
453
|
.filter(
|
|
@@ -455,20 +455,20 @@ function baseAmbientDeclarations(fileNames: readonly string[] | undefined, confi
|
|
|
455
455
|
name.endsWith('.d.ts') &&
|
|
456
456
|
!name.includes(`${path.sep}node_modules${path.sep}`) &&
|
|
457
457
|
!name.startsWith(outPath),
|
|
458
|
-
)
|
|
458
|
+
)
|
|
459
459
|
}
|
|
460
460
|
|
|
461
461
|
interface BaseProject {
|
|
462
462
|
options: {
|
|
463
|
-
paths?: TS.MapLike<string[]
|
|
464
|
-
baseUrl?: string
|
|
465
|
-
strict?: unknown
|
|
466
|
-
target?: unknown
|
|
467
|
-
module?: unknown
|
|
468
|
-
moduleResolution?: unknown
|
|
469
|
-
lib?: unknown
|
|
470
|
-
}
|
|
471
|
-
fileNames: string[]
|
|
463
|
+
paths?: TS.MapLike<string[]>
|
|
464
|
+
baseUrl?: string
|
|
465
|
+
strict?: unknown
|
|
466
|
+
target?: unknown
|
|
467
|
+
module?: unknown
|
|
468
|
+
moduleResolution?: unknown
|
|
469
|
+
lib?: unknown
|
|
470
|
+
}
|
|
471
|
+
fileNames: string[]
|
|
472
472
|
}
|
|
473
473
|
|
|
474
474
|
/**
|
|
@@ -477,38 +477,41 @@ interface BaseProject {
|
|
|
477
477
|
* reader.
|
|
478
478
|
*/
|
|
479
479
|
async function readBaseProject(file: string, native: string | undefined): Promise<BaseProject> {
|
|
480
|
-
const shown = native ? await showConfigViaNative(native, file) : undefined
|
|
481
|
-
if (shown) return shown
|
|
482
|
-
const ts = await loadTypescript()
|
|
483
|
-
const parsed = readProject(ts, file)
|
|
484
|
-
return { options: parsed.options, fileNames: [...parsed.fileNames] }
|
|
480
|
+
const shown = native ? await showConfigViaNative(native, file) : undefined
|
|
481
|
+
if (shown) return shown
|
|
482
|
+
const ts = await loadTypescript()
|
|
483
|
+
const parsed = readProject(ts, file)
|
|
484
|
+
return { options: parsed.options, fileNames: [...parsed.fileNames] }
|
|
485
485
|
}
|
|
486
486
|
|
|
487
487
|
async function showConfigViaNative(bin: string, file: string): Promise<BaseProject | undefined> {
|
|
488
488
|
try {
|
|
489
|
-
const proc = Bun.spawn([bin, '--showConfig', '-p', file], { stdout: 'pipe', stderr: 'pipe' })
|
|
490
|
-
const stdout = await new Response(proc.stdout).text()
|
|
491
|
-
await proc.exited
|
|
492
|
-
if (proc.exitCode !== 0) return undefined
|
|
493
|
-
const shown = JSON.parse(stdout) as {
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
const
|
|
498
|
-
|
|
489
|
+
const proc = Bun.spawn([bin, '--showConfig', '-p', file], { stdout: 'pipe', stderr: 'pipe' })
|
|
490
|
+
const stdout = await new Response(proc.stdout).text()
|
|
491
|
+
await proc.exited
|
|
492
|
+
if (proc.exitCode !== 0) return undefined
|
|
493
|
+
const shown = JSON.parse(stdout) as {
|
|
494
|
+
compilerOptions?: BaseProject['options']
|
|
495
|
+
files?: string[]
|
|
496
|
+
}
|
|
497
|
+
const dir = path.dirname(file)
|
|
498
|
+
const options = shown.compilerOptions ?? {}
|
|
499
|
+
if (typeof options.baseUrl === 'string') options.baseUrl = path.resolve(dir, options.baseUrl)
|
|
500
|
+
const fileNames = (shown.files ?? []).map(f => path.resolve(dir, f))
|
|
501
|
+
return { options, fileNames }
|
|
499
502
|
} catch {
|
|
500
|
-
return undefined
|
|
503
|
+
return undefined
|
|
501
504
|
}
|
|
502
505
|
}
|
|
503
506
|
|
|
504
507
|
function tsconfigPath(root: string): string | undefined {
|
|
505
|
-
const tsConfig = getNextConfig().typescript as { tsconfigPath?: unknown } | undefined
|
|
506
|
-
const configured = tsConfig?.tsconfigPath
|
|
508
|
+
const tsConfig = getNextConfig().typescript as { tsconfigPath?: unknown } | undefined
|
|
509
|
+
const configured = tsConfig?.tsconfigPath
|
|
507
510
|
const file =
|
|
508
511
|
typeof configured === 'string' && configured.length > 0
|
|
509
512
|
? path.join(root, configured)
|
|
510
|
-
: path.join(root, 'tsconfig.json')
|
|
511
|
-
return existsSync(file) ? file : undefined
|
|
513
|
+
: path.join(root, 'tsconfig.json')
|
|
514
|
+
return existsSync(file) ? file : undefined
|
|
512
515
|
}
|
|
513
516
|
|
|
514
517
|
/**
|
|
@@ -516,47 +519,47 @@ function tsconfigPath(root: string): string | undefined {
|
|
|
516
519
|
* `fileNames`. The cache lives for the process, which for the checker is one build (dev never
|
|
517
520
|
* typechecks).
|
|
518
521
|
*/
|
|
519
|
-
const parsedProjects = new Map<string, { stamp: number; parsed: TS.ParsedCommandLine }>()
|
|
522
|
+
const parsedProjects = new Map<string, { stamp: number; parsed: TS.ParsedCommandLine }>()
|
|
520
523
|
|
|
521
524
|
function readProject(ts: typeof TS, project: string): TS.ParsedCommandLine {
|
|
522
525
|
// The generated project is rewritten before every check, so the cache is
|
|
523
526
|
// keyed on the file's mtime rather than its path alone.
|
|
524
|
-
let stamp = 0
|
|
527
|
+
let stamp = 0
|
|
525
528
|
try {
|
|
526
|
-
stamp = statSync(project).mtimeMs
|
|
529
|
+
stamp = statSync(project).mtimeMs
|
|
527
530
|
} catch {
|
|
528
531
|
/* unreadable: parse and let readConfigFile report it */
|
|
529
532
|
}
|
|
530
|
-
const cached = parsedProjects.get(project)
|
|
531
|
-
if (cached?.stamp === stamp) return cached.parsed
|
|
532
|
-
const read = ts.readConfigFile(project, file => ts.sys.readFile(file))
|
|
533
|
-
if (read.error) throw new PnextTypecheckError(formatDiagnostics(ts, [read.error]))
|
|
534
|
-
const parsed = ts.parseJsonConfigFileContent(read.config, ts.sys, path.dirname(project))
|
|
535
|
-
parsedProjects.set(project, { stamp, parsed })
|
|
536
|
-
return parsed
|
|
533
|
+
const cached = parsedProjects.get(project)
|
|
534
|
+
if (cached?.stamp === stamp) return cached.parsed
|
|
535
|
+
const read = ts.readConfigFile(project, file => ts.sys.readFile(file))
|
|
536
|
+
if (read.error) throw new PnextTypecheckError(formatDiagnostics(ts, [read.error]))
|
|
537
|
+
const parsed = ts.parseJsonConfigFileContent(read.config, ts.sys, path.dirname(project))
|
|
538
|
+
parsedProjects.set(project, { stamp, parsed })
|
|
539
|
+
return parsed
|
|
537
540
|
}
|
|
538
541
|
|
|
539
542
|
function formatDiagnostics(ts: typeof TS, diagnostics: readonly TS.Diagnostic[]): string[] {
|
|
540
|
-
const messages = new Set<string>()
|
|
543
|
+
const messages = new Set<string>()
|
|
541
544
|
for (const diagnostic of diagnostics) {
|
|
542
|
-
const raw = ts.flattenDiagnosticMessageText(diagnostic.messageText, '\n')
|
|
543
|
-
const typedRoute = typedRouteMessage(raw)
|
|
545
|
+
const raw = ts.flattenDiagnosticMessageText(diagnostic.messageText, '\n')
|
|
546
|
+
const typedRoute = typedRouteMessage(raw)
|
|
544
547
|
// Next prints `./relative/file.ts:line:col` on its own line above the
|
|
545
548
|
// message; mirror that so build failures name their source.
|
|
546
|
-
let location = ''
|
|
549
|
+
let location = ''
|
|
547
550
|
if (diagnostic.file && diagnostic.start !== undefined) {
|
|
548
|
-
const { line, character } = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start)
|
|
549
|
-
location = `${diagnostic.file.fileName}:${line + 1}:${character + 1}\n
|
|
551
|
+
const { line, character } = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start)
|
|
552
|
+
location = `${diagnostic.file.fileName}:${line + 1}:${character + 1}\n`
|
|
550
553
|
}
|
|
551
|
-
messages.add(`${location}Type error: ${typedRoute ?? raw}`)
|
|
554
|
+
messages.add(`${location}Type error: ${typedRoute ?? raw}`)
|
|
552
555
|
}
|
|
553
|
-
return [...messages]
|
|
556
|
+
return [...messages]
|
|
554
557
|
}
|
|
555
558
|
|
|
556
559
|
function typedRouteMessage(message: string): string | undefined {
|
|
557
|
-
const match = /^Type '(".*")' is not assignable to type '.*RouteImpl<\1>/.exec(message)
|
|
558
|
-
if (!match?.[1]) return undefined
|
|
559
|
-
return `${match[1]} is not an existing route. If it is intentional, please type it explicitly with \`as Route
|
|
560
|
+
const match = /^Type '(".*")' is not assignable to type '.*RouteImpl<\1>/.exec(message)
|
|
561
|
+
if (!match?.[1]) return undefined
|
|
562
|
+
return `${match[1]} is not an existing route. If it is intentional, please type it explicitly with \`as Route\`.`
|
|
560
563
|
}
|
|
561
564
|
|
|
562
565
|
function rootParamsModule(rootParams: Map<string, Set<RootParamValueType>>): string {
|
|
@@ -567,7 +570,7 @@ function rootParamsModule(rootParams: Map<string, Set<RootParamValueType>>): str
|
|
|
567
570
|
// from some root layout). When the scan finds nothing (no root layout / no
|
|
568
571
|
// dynamic root segments), fall back to the static `lang`/`locale` exports
|
|
569
572
|
// that existing suites rely on.
|
|
570
|
-
const order: RootParamValueType[] = ['string', 'string[]', 'undefined']
|
|
573
|
+
const order: RootParamValueType[] = ['string', 'string[]', 'undefined']
|
|
571
574
|
const entries: [string, string][] =
|
|
572
575
|
rootParams.size > 0
|
|
573
576
|
? [...rootParams.entries()].map(([name, types]) => [
|
|
@@ -577,15 +580,15 @@ function rootParamsModule(rootParams: Map<string, Set<RootParamValueType>>): str
|
|
|
577
580
|
: [
|
|
578
581
|
['lang', 'string | string[] | undefined'],
|
|
579
582
|
['locale', 'string | string[] | undefined'],
|
|
580
|
-
]
|
|
583
|
+
]
|
|
581
584
|
const getters = entries
|
|
582
585
|
.map(([name, union]) => ` export function ${name}(): Promise<${union}>`)
|
|
583
|
-
.join('\n')
|
|
586
|
+
.join('\n')
|
|
584
587
|
return `declare module 'next/root-params' {
|
|
585
588
|
${getters}
|
|
586
589
|
const rootParams: (...args: any[]) => Promise<any>
|
|
587
590
|
export default rootParams
|
|
588
|
-
}
|
|
591
|
+
}`
|
|
589
592
|
}
|
|
590
593
|
|
|
591
594
|
// Remove every top-level `declare module 'next...' { ... }` block from a shim
|
|
@@ -594,22 +597,22 @@ ${getters}
|
|
|
594
597
|
// declarations (node builtins, asset wildcards, RequestInit augmentation) are
|
|
595
598
|
// left intact.
|
|
596
599
|
function stripNextModuleDeclarations(source: string): string {
|
|
597
|
-
const lines = source.split('\n')
|
|
598
|
-
const out: string[] = []
|
|
600
|
+
const lines = source.split('\n')
|
|
601
|
+
const out: string[] = []
|
|
599
602
|
for (let i = 0; i < lines.length; i++) {
|
|
600
|
-
const line = lines[i]
|
|
603
|
+
const line = lines[i]!
|
|
601
604
|
if (/^declare module 'next[^']*' \{/.test(line)) {
|
|
602
|
-
let depth = 0
|
|
605
|
+
let depth = 0
|
|
603
606
|
for (; i < lines.length; i++) {
|
|
604
|
-
const current = lines[i]
|
|
605
|
-
depth += (current.match(/\{/g)?.length ?? 0) - (current.match(/\}/g)?.length ?? 0)
|
|
606
|
-
if (depth === 0) break
|
|
607
|
+
const current = lines[i]!
|
|
608
|
+
depth += (current.match(/\{/g)?.length ?? 0) - (current.match(/\}/g)?.length ?? 0)
|
|
609
|
+
if (depth === 0) break
|
|
607
610
|
}
|
|
608
|
-
continue
|
|
611
|
+
continue
|
|
609
612
|
}
|
|
610
|
-
out.push(line)
|
|
613
|
+
out.push(line)
|
|
611
614
|
}
|
|
612
|
-
return out.join('\n')
|
|
615
|
+
return out.join('\n')
|
|
613
616
|
}
|
|
614
617
|
|
|
615
618
|
function nextShims(
|
|
@@ -650,7 +653,7 @@ declare module 'react/jsx-runtime' {
|
|
|
650
653
|
export const jsxs: any
|
|
651
654
|
export const Fragment: any
|
|
652
655
|
}
|
|
653
|
-
|
|
656
|
+
`
|
|
654
657
|
const source = `${reactShims}
|
|
655
658
|
declare const process: {
|
|
656
659
|
env: Record<string, string | undefined>
|
|
@@ -1441,8 +1444,8 @@ declare module '*.md' {
|
|
|
1441
1444
|
const MDXComponent: (props: any) => any
|
|
1442
1445
|
export default MDXComponent
|
|
1443
1446
|
}
|
|
1444
|
-
${loaderRuleAssetDeclarations()}
|
|
1445
|
-
return omitNextModuleShims ? stripNextModuleDeclarations(source) : source
|
|
1447
|
+
${loaderRuleAssetDeclarations()}`
|
|
1448
|
+
return omitNextModuleShims ? stripNextModuleDeclarations(source) : source
|
|
1446
1449
|
}
|
|
1447
1450
|
|
|
1448
1451
|
// Next's generated `next-env.d.ts` carries ambient wildcard module declarations
|
|
@@ -1452,23 +1455,42 @@ ${loaderRuleAssetDeclarations()}`;
|
|
|
1452
1455
|
// wildcard per configured `turbopack.rules` extension that the standard set
|
|
1453
1456
|
// (and TS's own source/JSON resolution) does not already cover.
|
|
1454
1457
|
const STANDARD_ASSET_DECLARATIONS = new Set([
|
|
1455
|
-
'.css',
|
|
1456
|
-
'.
|
|
1457
|
-
|
|
1458
|
+
'.css',
|
|
1459
|
+
'.scss',
|
|
1460
|
+
'.sass',
|
|
1461
|
+
'.png',
|
|
1462
|
+
'.jpg',
|
|
1463
|
+
'.jpeg',
|
|
1464
|
+
'.gif',
|
|
1465
|
+
'.svg',
|
|
1466
|
+
'.webp',
|
|
1467
|
+
'.wasm',
|
|
1468
|
+
'.mdx',
|
|
1469
|
+
'.md',
|
|
1470
|
+
])
|
|
1458
1471
|
const TS_RESOLVED_EXTENSIONS = new Set([
|
|
1459
|
-
'.ts',
|
|
1460
|
-
|
|
1472
|
+
'.ts',
|
|
1473
|
+
'.tsx',
|
|
1474
|
+
'.mts',
|
|
1475
|
+
'.cts',
|
|
1476
|
+
'.d.ts',
|
|
1477
|
+
'.js',
|
|
1478
|
+
'.jsx',
|
|
1479
|
+
'.mjs',
|
|
1480
|
+
'.cjs',
|
|
1481
|
+
'.json',
|
|
1482
|
+
])
|
|
1461
1483
|
|
|
1462
1484
|
function loaderRuleAssetDeclarations(): string {
|
|
1463
|
-
const specs = new Set<string>()
|
|
1485
|
+
const specs = new Set<string>()
|
|
1464
1486
|
for (const rule of turbopackLoaderRules()) {
|
|
1465
1487
|
// Only leading-`*` globs form a valid ambient wildcard module ('*.data').
|
|
1466
|
-
if (!rule.glob.startsWith('*')) continue
|
|
1467
|
-
const ext = rule.glob.slice(1).toLowerCase()
|
|
1468
|
-
if (STANDARD_ASSET_DECLARATIONS.has(ext) || TS_RESOLVED_EXTENSIONS.has(ext)) continue
|
|
1469
|
-
specs.add(rule.glob)
|
|
1488
|
+
if (!rule.glob.startsWith('*')) continue
|
|
1489
|
+
const ext = rule.glob.slice(1).toLowerCase()
|
|
1490
|
+
if (STANDARD_ASSET_DECLARATIONS.has(ext) || TS_RESOLVED_EXTENSIONS.has(ext)) continue
|
|
1491
|
+
specs.add(rule.glob)
|
|
1470
1492
|
}
|
|
1471
|
-
if (specs.size === 0) return ''
|
|
1493
|
+
if (specs.size === 0) return ''
|
|
1472
1494
|
return `${[...specs]
|
|
1473
1495
|
.map(
|
|
1474
1496
|
spec => `
|
|
@@ -1477,5 +1499,5 @@ declare module '${spec}' {
|
|
|
1477
1499
|
export default content
|
|
1478
1500
|
}`,
|
|
1479
1501
|
)
|
|
1480
|
-
.join('')}\n
|
|
1502
|
+
.join('')}\n`
|
|
1481
1503
|
}
|