@wular/pnext 0.0.1
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 +153 -0
- package/bin/pnext +67 -0
- package/config/lint/base.js +48 -0
- package/config/ts/base.json +26 -0
- package/config/ts/react.json +13 -0
- package/package.json +70 -0
- package/reference/compat.md +63 -0
- package/reference/config.md +120 -0
- package/reference/css.md +58 -0
- package/reference/dev.md +69 -0
- package/reference/env.md +40 -0
- package/reference/metadata.md +86 -0
- package/reference/navigation.md +149 -0
- package/reference/overview.md +35 -0
- package/reference/performance.md +97 -0
- package/reference/rendering.md +127 -0
- package/reference/routing.md +167 -0
- package/reference/typegen.md +64 -0
- package/src/api/cache.ts +80 -0
- package/src/api/client-cache.ts +9 -0
- package/src/api/client-navigation.ts +279 -0
- package/src/api/dynamic.tsx +102 -0
- package/src/api/link.tsx +119 -0
- package/src/api/navigation.ts +198 -0
- package/src/api/router/events.ts +53 -0
- package/src/api/router/history.ts +70 -0
- package/src/api/router/hub.ts +194 -0
- package/src/api/router/policies.ts +107 -0
- package/src/api/router/runtime.ts +5238 -0
- package/src/api/router/types.ts +299 -0
- package/src/api/router.ts +167 -0
- package/src/api/server.ts +323 -0
- package/src/api/suspense.ts +16 -0
- package/src/cache/context.ts +61 -0
- package/src/cli/adapters/vercel-warm.ts +375 -0
- package/src/cli/adapters/vercel.ts +1310 -0
- package/src/cli/analyze-print.ts +181 -0
- package/src/cli/analyze.ts +328 -0
- package/src/cli/boot-trace.ts +29 -0
- package/src/cli/build.ts +3114 -0
- package/src/cli/dev.ts +276 -0
- package/src/cli/index.ts +196 -0
- package/src/cli/named-bin.ts +119 -0
- package/src/cli/serve-ui.ts +160 -0
- package/src/cli/start.ts +1425 -0
- package/src/client/build.ts +2136 -0
- package/src/client/chunk-fold.ts +526 -0
- package/src/client/entry.ts +1525 -0
- package/src/client/paths.ts +22 -0
- package/src/client/prebuilt.ts +621 -0
- package/src/client/profile.ts +75 -0
- package/src/client/react-compiler.ts +94 -0
- package/src/client/reference-stub.ts +145 -0
- package/src/client/reference.ts +47 -0
- package/src/compat/actions/action-client.ts +531 -0
- package/src/compat/actions/action-dispatch.ts +676 -0
- package/src/compat/actions/action-router.ts +40 -0
- package/src/compat/actions/action-shared.ts +95 -0
- package/src/compat/actions/client-plugin.ts +135 -0
- package/src/compat/actions/client-stub.ts +65 -0
- package/src/compat/actions/config.ts +164 -0
- package/src/compat/actions/detect.ts +208 -0
- package/src/compat/actions/discovery.ts +244 -0
- package/src/compat/actions/early-submit.ts +40 -0
- package/src/compat/actions/endpoint.ts +602 -0
- package/src/compat/actions/flight.ts +52 -0
- package/src/compat/actions/form-state.ts +73 -0
- package/src/compat/actions/hoist.ts +485 -0
- package/src/compat/actions/ids.ts +39 -0
- package/src/compat/actions/index.ts +41 -0
- package/src/compat/actions/instances.ts +144 -0
- package/src/compat/actions/origin.ts +109 -0
- package/src/compat/actions/protocol.ts +125 -0
- package/src/compat/actions/registry.ts +74 -0
- package/src/compat/actions/rewrite.ts +282 -0
- package/src/compat/actions/serve.ts +414 -0
- package/src/compat/actions/server-tag.ts +21 -0
- package/src/compat/actions/unrecognized-error.ts +30 -0
- package/src/compat/adapter/build-complete.ts +257 -0
- package/src/compat/bundler/bun-externals.ts +53 -0
- package/src/compat/bundler/cjs-exports.ts +542 -0
- package/src/compat/bundler/config.ts +363 -0
- package/src/compat/bundler/externals.ts +34 -0
- package/src/compat/bundler/import-meta-url.ts +60 -0
- package/src/compat/bundler/modularize-imports.ts +119 -0
- package/src/compat/bundler/new-url-asset.ts +87 -0
- package/src/compat/bundler/optimize-package-imports.ts +273 -0
- package/src/compat/bundler/polyfill.ts +88 -0
- package/src/compat/bundler/react-compiler.ts +61 -0
- package/src/compat/bundler/react-profiler.tsx +25 -0
- package/src/compat/bundler/relay-transform.ts +116 -0
- package/src/compat/bundler/require-context.ts +281 -0
- package/src/compat/bundler/resolve-extensions.ts +75 -0
- package/src/compat/bundler/source-cache.ts +61 -0
- package/src/compat/bundler/static-imports.ts +25 -0
- package/src/compat/bundler/symlink-imports.ts +119 -0
- package/src/compat/bundler/tsconfig-paths.ts +50 -0
- package/src/compat/bundler/wasm.ts +153 -0
- package/src/compat/bundler/webpack-loaders.ts +685 -0
- package/src/compat/bundler/worker.ts +278 -0
- package/src/compat/cache/build-flags.ts +81 -0
- package/src/compat/cache/build-prerender-errors.ts +163 -0
- package/src/compat/cache/custom-handler.ts +159 -0
- package/src/compat/cache/fetch-patch.ts +745 -0
- package/src/compat/cache/handler.ts +100 -0
- package/src/compat/cache/modern-handler.ts +275 -0
- package/src/compat/cache/resume-data-cache.ts +143 -0
- package/src/compat/cache/revalidate.ts +759 -0
- package/src/compat/cache/runtime-error.ts +124 -0
- package/src/compat/cache/use-cache-transform.ts +961 -0
- package/src/compat/cache/use-cache.ts +1695 -0
- package/src/compat/cache-control.ts +269 -0
- package/src/compat/client/base-path.ts +64 -0
- package/src/compat/client/css-order.ts +36 -0
- package/src/compat/client/errors/control-flow.ts +92 -0
- package/src/compat/client/errors/error-boundary.ts +222 -0
- package/src/compat/client/errors/global-error.ts +238 -0
- package/src/compat/client/errors/install.ts +217 -0
- package/src/compat/client/errors/lazy.ts +53 -0
- package/src/compat/client/errors/primitive-throw.ts +126 -0
- package/src/compat/client/errors/soft-refresh.ts +14 -0
- package/src/compat/client/link-status.ts +86 -0
- package/src/compat/client/nav-compat-runtime.ts +57 -0
- package/src/compat/client/nav-compat.ts +42 -0
- package/src/compat/client/navigation-scroll.ts +154 -0
- package/src/compat/client/optimistic-routing.ts +206 -0
- package/src/compat/client/prefetch-cache.ts +111 -0
- package/src/compat/client/route-announcer.ts +72 -0
- package/src/compat/client/segment-cache-policy.ts +159 -0
- package/src/compat/client/segment-cache.ts +1077 -0
- package/src/compat/client/segment-prefetch.ts +375 -0
- package/src/compat/client/trailing-slash.ts +24 -0
- package/src/compat/css/chunking.ts +254 -0
- package/src/compat/css/inline-css.ts +73 -0
- package/src/compat/css/lightningcss.ts +90 -0
- package/src/compat/css/modules.ts +373 -0
- package/src/compat/css/nonce.ts +30 -0
- package/src/compat/css/sass-plugin.ts +65 -0
- package/src/compat/css/sass.ts +392 -0
- package/src/compat/css/styled-jsx-runtime.ts +80 -0
- package/src/compat/css/styled-jsx.ts +49 -0
- package/src/compat/edge-runtime.ts +71 -0
- package/src/compat/export/client.ts +112 -0
- package/src/compat/export/index.ts +272 -0
- package/src/compat/export/standalone.ts +207 -0
- package/src/compat/image-optimizer/cache.ts +119 -0
- package/src/compat/image-optimizer/detect.ts +143 -0
- package/src/compat/image-optimizer/index.ts +601 -0
- package/src/compat/image-optimizer/source.ts +243 -0
- package/src/compat/index.ts +458 -0
- package/src/compat/lifecycle/after-scope.ts +86 -0
- package/src/compat/lifecycle/after.ts +173 -0
- package/src/compat/lifecycle/error-funnel.ts +306 -0
- package/src/compat/lifecycle/error-serialize.ts +87 -0
- package/src/compat/lifecycle/error-ui.ts +167 -0
- package/src/compat/lifecycle/instrumentation-client.ts +138 -0
- package/src/compat/lifecycle/instrumentation.ts +277 -0
- package/src/compat/lifecycle/node-console.ts +19 -0
- package/src/compat/lifecycle/testmode.ts +263 -0
- package/src/compat/mdx/compile.ts +219 -0
- package/src/compat/mdx/next-mdx-stub.ts +46 -0
- package/src/compat/mdx/plugin.ts +37 -0
- package/src/compat/metadata-route-artifacts.ts +458 -0
- package/src/compat/metadata.ts +295 -0
- package/src/compat/middleware/manifest.ts +210 -0
- package/src/compat/misc/action-return.ts +173 -0
- package/src/compat/next/cache.ts +211 -0
- package/src/compat/next/canonical-url.ts +35 -0
- package/src/compat/next/client-cache.ts +57 -0
- package/src/compat/next/client-navigation.ts +313 -0
- package/src/compat/next/client-only.ts +3 -0
- package/src/compat/next/client-script.tsx +215 -0
- package/src/compat/next/client-server.ts +39 -0
- package/src/compat/next/config-loader.ts +569 -0
- package/src/compat/next/config.ts +29 -0
- package/src/compat/next/constants.cjs +6 -0
- package/src/compat/next/constants.ts +6 -0
- package/src/compat/next/custom-server.ts +236 -0
- package/src/compat/next/dist/client/components/app-router-headers.ts +32 -0
- package/src/compat/next/dist/server/app-render/work-unit-async-storage.external.cjs +38 -0
- package/src/compat/next/dist/server/web/spec-extension/revalidate.ts +1 -0
- package/src/compat/next/dist/server/web/spec-extension/unstable-cache.ts +1 -0
- package/src/compat/next/dist/server/web/spec-extension/unstable-no-store.ts +1 -0
- package/src/compat/next/dynamic.tsx +46 -0
- package/src/compat/next/error.tsx +148 -0
- package/src/compat/next/font/cache.ts +171 -0
- package/src/compat/next/font/google.ts +2 -0
- package/src/compat/next/font/index.ts +8 -0
- package/src/compat/next/font/local.ts +5 -0
- package/src/compat/next/font/runtime-client.ts +71 -0
- package/src/compat/next/font/runtime.ts +974 -0
- package/src/compat/next/font/shared.ts +281 -0
- package/src/compat/next/form.tsx +156 -0
- package/src/compat/next/head.tsx +10 -0
- package/src/compat/next/headers.ts +247 -0
- package/src/compat/next/image/config.ts +196 -0
- package/src/compat/next/image/optimizer.ts +96 -0
- package/src/compat/next/image/patterns.ts +103 -0
- package/src/compat/next/image/shared.ts +141 -0
- package/src/compat/next/image/static-metadata.ts +283 -0
- package/src/compat/next/image/validate.ts +269 -0
- package/src/compat/next/image-client.tsx +215 -0
- package/src/compat/next/image-props.ts +575 -0
- package/src/compat/next/image-usage.ts +102 -0
- package/src/compat/next/image.tsx +56 -0
- package/src/compat/next/index.ts +1 -0
- package/src/compat/next/legacy-image.tsx +97 -0
- package/src/compat/next/link-usage.ts +29 -0
- package/src/compat/next/link-validation-transform.ts +200 -0
- package/src/compat/next/link.tsx +466 -0
- package/src/compat/next/navigation.cjs +21 -0
- package/src/compat/next/navigation.ts +188 -0
- package/src/compat/next/offline.ts +51 -0
- package/src/compat/next/og.ts +324 -0
- package/src/compat/next/optimistic-route-state.ts +188 -0
- package/src/compat/next/preferred-region.ts +39 -0
- package/src/compat/next/redirects.ts +131 -0
- package/src/compat/next/resource-hints.ts +136 -0
- package/src/compat/next/rewrites.ts +350 -0
- package/src/compat/next/root-params.ts +142 -0
- package/src/compat/next/router.cjs +49 -0
- package/src/compat/next/router.ts +143 -0
- package/src/compat/next/script.tsx +355 -0
- package/src/compat/next/server-only.ts +3 -0
- package/src/compat/next/server.ts +28 -0
- package/src/compat/next/svgr.ts +58 -0
- package/src/compat/next/telemetry.ts +77 -0
- package/src/compat/next/user-agent.ts +100 -0
- package/src/compat/next/web-vitals.ts +56 -0
- package/src/compat/otel/api.ts +95 -0
- package/src/compat/otel/client-trace-metadata.ts +71 -0
- package/src/compat/otel/fetch-span.ts +77 -0
- package/src/compat/otel/tracer.ts +944 -0
- package/src/compat/pages/client-plugin.ts +108 -0
- package/src/compat/pages/index.ts +527 -0
- package/src/compat/pages/router-state.ts +94 -0
- package/src/compat/ppr/io.ts +38 -0
- package/src/compat/ppr/missing-root-params.ts +105 -0
- package/src/compat/ppr/root-params-scan.ts +164 -0
- package/src/compat/ppr/root-params-transform.ts +75 -0
- package/src/compat/ppr/root-params.ts +129 -0
- package/src/compat/ppr/segment-config-incompat.ts +34 -0
- package/src/compat/protocol.ts +202 -0
- package/src/compat/react/client.ts +59 -0
- package/src/compat/react/compiler-runtime.ts +60 -0
- package/src/compat/react/dom-client.ts +115 -0
- package/src/compat/react/dom-react-server.ts +20 -0
- package/src/compat/react/dom-server.ts +40 -0
- package/src/compat/react/dom.ts +154 -0
- package/src/compat/react/preact.ts +522 -0
- package/src/compat/react/react-server.ts +84 -0
- package/src/compat/react/router-shim.ts +26 -0
- package/src/compat/react/server-component-use.ts +48 -0
- package/src/compat/react/server-inserted-html.ts +87 -0
- package/src/compat/react/server.ts +156 -0
- package/src/compat/react/view-transition.ts +60 -0
- package/src/compat/register/actions.ts +875 -0
- package/src/compat/register/boot.ts +141 -0
- package/src/compat/register/build-tier.ts +11 -0
- package/src/compat/register/build.ts +182 -0
- package/src/compat/register/bundler.ts +587 -0
- package/src/compat/register/cache.ts +85 -0
- package/src/compat/register/client-errors.ts +18 -0
- package/src/compat/register/config.ts +17 -0
- package/src/compat/register/css-extras.ts +120 -0
- package/src/compat/register/edge-runtime.ts +6 -0
- package/src/compat/register/errors.ts +46 -0
- package/src/compat/register/export.ts +23 -0
- package/src/compat/register/font.ts +36 -0
- package/src/compat/register/hooks.ts +34 -0
- package/src/compat/register/image.ts +133 -0
- package/src/compat/register/index.ts +111 -0
- package/src/compat/register/instrumentation-client.ts +35 -0
- package/src/compat/register/lifecycle.ts +86 -0
- package/src/compat/register/mdx.ts +48 -0
- package/src/compat/register/middleware.ts +36 -0
- package/src/compat/register/misc.ts +44 -0
- package/src/compat/register/otel.ts +288 -0
- package/src/compat/register/pages-api.ts +473 -0
- package/src/compat/register/ppr.ts +56 -0
- package/src/compat/register/protocol.ts +57 -0
- package/src/compat/register/proxy.ts +127 -0
- package/src/compat/register/render.ts +268 -0
- package/src/compat/register/routing.ts +410 -0
- package/src/compat/register/segment.ts +1903 -0
- package/src/compat/register/static-image.ts +21 -0
- package/src/compat/register/typed-routes.ts +35 -0
- package/src/compat/register/usecache.ts +131 -0
- package/src/compat/register/validation.ts +56 -0
- package/src/compat/segment/loading-boundary.ts +113 -0
- package/src/compat/segment/page-slot.ts +200 -0
- package/src/compat/segment/tree.ts +481 -0
- package/src/compat/segment/vary-key.ts +102 -0
- package/src/compat/segment/vary-params.ts +551 -0
- package/src/compat/static-params.ts +33 -0
- package/src/compat/tsconfig-defaults.ts +301 -0
- package/src/compat/typecheck/index.ts +1481 -0
- package/src/compat/typecheck/worker.ts +26 -0
- package/src/compat/typed-routes/index.ts +92 -0
- package/src/compat/typed-routes/manifest.ts +356 -0
- package/src/compat/typed-routes/typegen.ts +566 -0
- package/src/compat/validation/errors.ts +159 -0
- package/src/compat/validation/index.ts +1770 -0
- package/src/compat/validation/prerender-diagnostics.ts +1508 -0
- package/src/compat-bootstrap.ts +67 -0
- package/src/config.ts +218 -0
- package/src/css/build.ts +697 -0
- package/src/css/index.ts +2 -0
- package/src/css/postcss.ts +236 -0
- package/src/css/worker.ts +34 -0
- package/src/dev/client-actions.ts +35 -0
- package/src/dev/client-chunk-store.ts +92 -0
- package/src/dev/client-key-cache.ts +178 -0
- package/src/dev/global-css-cache.ts +212 -0
- package/src/dev/imports.ts +2430 -0
- package/src/dev/module-cache.ts +721 -0
- package/src/dev/module-generations.ts +38 -0
- package/src/dev/module-transform.ts +188 -0
- package/src/dev/node-module-bundle-cache.ts +63 -0
- package/src/dev/restart-cache.ts +10 -0
- package/src/dev/route-bundle-key-cache.ts +154 -0
- package/src/dev/route-facts-cache.ts +223 -0
- package/src/dev/server.ts +1710 -0
- package/src/dynamic/source.ts +307 -0
- package/src/dynamic/tree-shake.ts +262 -0
- package/src/env.ts +92 -0
- package/src/extensions.ts +1898 -0
- package/src/index.ts +34 -0
- package/src/internal.ts +43 -0
- package/src/islands/boundary-error.ts +8 -0
- package/src/islands/static-children.ts +37 -0
- package/src/islands/static-slots.ts +106 -0
- package/src/ppr-postpone.ts +24 -0
- package/src/ppr.ts +784 -0
- package/src/proxy.ts +752 -0
- package/src/render/hooks.ts +384 -0
- package/src/render/index.ts +1 -0
- package/src/render/island-context.ts +47 -0
- package/src/render/metadata.ts +857 -0
- package/src/render/renderer.ts +7391 -0
- package/src/render/resource-hints.ts +44 -0
- package/src/render/slots.tsx +679 -0
- package/src/request/context.ts +396 -0
- package/src/resolve/engine.ts +219 -0
- package/src/resolve/imports.ts +1104 -0
- package/src/resolve/scan-facts.ts +474 -0
- package/src/resolve/source-text.ts +86 -0
- package/src/routing/forwarded.ts +41 -0
- package/src/routing/handler.ts +271 -0
- package/src/routing/href.ts +203 -0
- package/src/routing/metadata.ts +1018 -0
- package/src/routing/request-runtime.ts +43 -0
- package/src/routing/routes.ts +2560 -0
- package/src/routing/slots.ts +432 -0
- package/src/runtime/server.ts +3453 -0
- package/src/runtime/vendor.ts +1160 -0
- package/src/style-modules.d.ts +9 -0
- package/src/typegen.ts +151 -0
- package/src/types.ts +725 -0
- package/src/utils/ansi.ts +9 -0
- package/src/utils/content-type.ts +31 -0
- package/src/utils/decode.ts +7 -0
- package/src/utils/dev-profile.ts +31 -0
- package/src/utils/error-log.ts +29 -0
- package/src/utils/fs-cache.ts +31 -0
- package/src/utils/fs.ts +119 -0
- package/src/utils/html.ts +46 -0
- package/src/utils/serialize.ts +378 -0
- package/src/utils/source.ts +35 -0
- package/src/utils/verbose.ts +39 -0
- package/tsconfig.json +10 -0
|
@@ -0,0 +1,542 @@
|
|
|
1
|
+
import type { Plugin } from 'esbuild';
|
|
2
|
+
import { readFileSync } from 'node:fs';
|
|
3
|
+
import { readFile } from 'node:fs/promises';
|
|
4
|
+
import { dirname, extname, isAbsolute } from 'node:path';
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
isCommonJsModuleSource,
|
|
8
|
+
providedEntryResolution,
|
|
9
|
+
resolveLinkedPackageSpecifier,
|
|
10
|
+
resolveRuntimeSpecifier,
|
|
11
|
+
} from '../../resolve/imports';
|
|
12
|
+
import { rewriteFacts } from '../../resolve/scan-facts';
|
|
13
|
+
import { spliceSource } from '../../dev/module-transform';
|
|
14
|
+
import { clientReferenceId } from '../../client/reference';
|
|
15
|
+
import { hasUseClientDirective } from '../../client/reference-stub';
|
|
16
|
+
import { isIdentifier, uniqueIdentifier } from '../../utils/source';
|
|
17
|
+
import { fileMemo, fileMemoAsync } from './source-cache';
|
|
18
|
+
|
|
19
|
+
const encoder = new TextEncoder();
|
|
20
|
+
const decoder = new TextDecoder();
|
|
21
|
+
|
|
22
|
+
// esbuild treats a CommonJS entry point as `module.exports`, bypassing its
|
|
23
|
+
// normal `__esModule` default-import interop. Route CJS package entries through
|
|
24
|
+
// a JavaScript ESM facade so Babel/TypeScript-shaped modules expose
|
|
25
|
+
// `exports.default`, while ordinary CJS continues to expose `module.exports`.
|
|
26
|
+
const interopEntryPrefix = 'pnext-cjs-interop:';
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Entry-point CJS classification, done ONCE where the caller already knows the entry - the marker keeps
|
|
30
|
+
* the plugin's onResolve off every non-entry resolve, where its old catch-all filter answered a large
|
|
31
|
+
* volume of dead callbacks. Returns undefined for ESM/unresolvable entries: use the specifier as-is.
|
|
32
|
+
*/
|
|
33
|
+
export function commonJsInteropEntry(
|
|
34
|
+
specifier: string,
|
|
35
|
+
resolveDir: string,
|
|
36
|
+
resolved?: string,
|
|
37
|
+
): string | undefined {
|
|
38
|
+
const classified =
|
|
39
|
+
resolved ?? (isAbsolute(specifier) ? specifier : resolveEntryPath(specifier, resolveDir));
|
|
40
|
+
if (!classified || !isCommonJsJavaScriptFile(classified)) return undefined;
|
|
41
|
+
return interopEntryPrefix + specifier;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function commonJsDefaultInteropPlugin(): Plugin {
|
|
45
|
+
return {
|
|
46
|
+
name: 'pnext-cjs-default-interop',
|
|
47
|
+
setup(build) {
|
|
48
|
+
build.onResolve({ filter: /^pnext-cjs-interop:/ }, args => {
|
|
49
|
+
const source = args.path.slice(interopEntryPrefix.length);
|
|
50
|
+
const resolved = isAbsolute(source)
|
|
51
|
+
? source
|
|
52
|
+
: resolveEntryPath(source, args.resolveDir || process.cwd());
|
|
53
|
+
return {
|
|
54
|
+
path: `${source}.pnext-cjs-default-interop.js`,
|
|
55
|
+
namespace: 'pnext-cjs-default-interop',
|
|
56
|
+
pluginData: { source, resolved: resolved ?? source },
|
|
57
|
+
};
|
|
58
|
+
});
|
|
59
|
+
build.onLoad({ filter: /.*/, namespace: 'pnext-cjs-default-interop' }, args => {
|
|
60
|
+
const data = args.pluginData as { source?: string; resolved?: string } | undefined;
|
|
61
|
+
const source = data?.source ?? args.path;
|
|
62
|
+
// The facade's `export default` alone breaks a consumer's named import
|
|
63
|
+
// (`import { Network } from 'relay-runtime'`), so mirror the entry's
|
|
64
|
+
// statically discoverable CommonJS keys as named exports too. Read them
|
|
65
|
+
// from the *resolved* file — `source` may be a bare specifier.
|
|
66
|
+
const names = data?.resolved ? namedFacadeExportNames(data.resolved) : [];
|
|
67
|
+
const namespaceName = '__pnext_cjs_ns';
|
|
68
|
+
const bindings = names.map((name, index) => ({
|
|
69
|
+
name,
|
|
70
|
+
localName: `__pnext_cjs_named_${index}`,
|
|
71
|
+
}));
|
|
72
|
+
return {
|
|
73
|
+
contents: [
|
|
74
|
+
`const value = require(${JSON.stringify(source)});`,
|
|
75
|
+
`const ${namespaceName} = value != null && value.__esModule ? value.default : value;`,
|
|
76
|
+
`export default ${namespaceName};`,
|
|
77
|
+
// `__esModule` only redirects the *default* binding; named exports
|
|
78
|
+
// live on the raw `module.exports` (a tsc-shaped CJS module sets
|
|
79
|
+
// `__esModule` with no `exports.default`, so the unwrapped namespace
|
|
80
|
+
// is undefined). Read names off `value`, falling back to the
|
|
81
|
+
// namespace for packages that expose them only under `.default`.
|
|
82
|
+
...bindings.map(({ name, localName }) => {
|
|
83
|
+
const key = JSON.stringify(name);
|
|
84
|
+
return `const ${localName} = value != null && value[${key}] !== undefined ? value[${key}] : (${namespaceName} == null ? undefined : ${namespaceName}[${key}]);`;
|
|
85
|
+
}),
|
|
86
|
+
...(bindings.length > 0
|
|
87
|
+
? [
|
|
88
|
+
`export { ${bindings
|
|
89
|
+
.map(({ name, localName }) => `${localName} as ${name}`)
|
|
90
|
+
.join(', ')} };`,
|
|
91
|
+
]
|
|
92
|
+
: []),
|
|
93
|
+
].join('\n'),
|
|
94
|
+
loader: 'js',
|
|
95
|
+
// resolveDir must be a real directory. `dirname()` of a scoped bare
|
|
96
|
+
// specifier ('@scope/pkg' -> '@scope') is not one, and esbuild will
|
|
97
|
+
// not walk up for node_modules from it; unscoped only worked by
|
|
98
|
+
// accident ('pkg' -> '.'). Anchor on the resolved file.
|
|
99
|
+
resolveDir: dirname(data?.resolved ?? source),
|
|
100
|
+
};
|
|
101
|
+
});
|
|
102
|
+
},
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* `use client` in a CommonJS file, resolved once per file: the callback fires
|
|
108
|
+
* for every `.js` in every build, and the overwhelming majority answer "not a
|
|
109
|
+
* client reference" after a full read the bundler then repeats itself.
|
|
110
|
+
*/
|
|
111
|
+
export const clientReferenceLoad = fileMemoAsync(async (file: string) => {
|
|
112
|
+
let bytes: Buffer;
|
|
113
|
+
try {
|
|
114
|
+
bytes = await readFile(file);
|
|
115
|
+
} catch {
|
|
116
|
+
return undefined;
|
|
117
|
+
}
|
|
118
|
+
// Almost every file the bundler loads has no directive at all. Search the
|
|
119
|
+
// raw bytes for the only string one can be spelled with, and decode (plus
|
|
120
|
+
// run the real directive-prologue test) for the few that could.
|
|
121
|
+
if (!bytes.includes('use client')) return undefined;
|
|
122
|
+
const source = bytes.toString('utf8');
|
|
123
|
+
if (!isCommonJsModuleSource(source, file) || !hasUseClientDirective(source)) return undefined;
|
|
124
|
+
const references = commonJsExportNames(source)
|
|
125
|
+
.map(name => {
|
|
126
|
+
const value = name === 'default' ? 'exports.default' : `exports[${JSON.stringify(name)}]`;
|
|
127
|
+
const reference = JSON.stringify({
|
|
128
|
+
id: `c-${clientReferenceId(file, name)}`,
|
|
129
|
+
file,
|
|
130
|
+
exportName: name,
|
|
131
|
+
});
|
|
132
|
+
return `if (typeof ${value} === "function") ${value}[Symbol.for("pnext.clientReference")] = ${reference};`;
|
|
133
|
+
})
|
|
134
|
+
.join('\n');
|
|
135
|
+
return {
|
|
136
|
+
contents: references ? `${source}\n${references}\n` : source,
|
|
137
|
+
loader: 'js' as const,
|
|
138
|
+
resolveDir: dirname(file),
|
|
139
|
+
};
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
export function commonJsClientReferencePlugin(): Plugin {
|
|
143
|
+
return {
|
|
144
|
+
name: 'pnext-cjs-client-references',
|
|
145
|
+
setup(build) {
|
|
146
|
+
build.onLoad({ filter: /\.c?js$/, namespace: 'file' }, args =>
|
|
147
|
+
clientReferenceLoad(args.path),
|
|
148
|
+
);
|
|
149
|
+
},
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
const isCommonJsJavaScriptFile = fileMemo((file: string) => {
|
|
154
|
+
try {
|
|
155
|
+
return isCommonJsModuleSource(readFileSync(file, 'utf8'), file);
|
|
156
|
+
} catch {
|
|
157
|
+
return true;
|
|
158
|
+
}
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
/** Entry classification is per (specifier, resolveDir) and never changes. */
|
|
162
|
+
const entryResolutions = new Map<string, string | undefined>();
|
|
163
|
+
|
|
164
|
+
function resolveEntryPath(specifier: string, resolveDir: string) {
|
|
165
|
+
const key = `${specifier}\0${resolveDir}`;
|
|
166
|
+
if (entryResolutions.has(key)) return entryResolutions.get(key);
|
|
167
|
+
// The vendor build already resolved bare entry specifiers; never re-resolve.
|
|
168
|
+
const provided = providedEntryResolution(specifier, resolveDir);
|
|
169
|
+
if (provided) {
|
|
170
|
+
entryResolutions.set(key, provided);
|
|
171
|
+
return provided;
|
|
172
|
+
}
|
|
173
|
+
let resolved: string | undefined;
|
|
174
|
+
try {
|
|
175
|
+
resolved = Bun.resolveSync(specifier, resolveDir);
|
|
176
|
+
} catch {
|
|
177
|
+
resolved = undefined;
|
|
178
|
+
}
|
|
179
|
+
entryResolutions.set(key, resolved);
|
|
180
|
+
return resolved;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// esbuild turns a bundled CommonJS dependency into an ESM wrapper whose
|
|
184
|
+
// default export is the complete `module.exports` object. That is right for a
|
|
185
|
+
// static default import, but webpack's static namespace interop exposes an
|
|
186
|
+
// own `.default` value (when present) as `namespace.default`. Dynamic import
|
|
187
|
+
// intentionally retains the native ESM-wrapper namespace and is left alone.
|
|
188
|
+
export function rewriteStaticCommonJsNamespaceImports(source: string, file: string): string {
|
|
189
|
+
const facts = rewriteFacts(file, source);
|
|
190
|
+
const edits: { start: number; end: number; value: string }[] = [];
|
|
191
|
+
const taken: string[] = [];
|
|
192
|
+
for (const statement of facts.imports) {
|
|
193
|
+
// Namespace-only: `import d, * as ns from 'x'` would lose its default.
|
|
194
|
+
const binding = statement.bindings[0];
|
|
195
|
+
if (statement.bindings.length !== 1 || binding?.imported !== '*') continue;
|
|
196
|
+
if (!isCommonJsImport(statement.specifier, file)) continue;
|
|
197
|
+
|
|
198
|
+
const defaultBinding = uniqueIdentifier(source, '__pnext_cjs_namespace_default', ...taken);
|
|
199
|
+
taken.push(defaultBinding);
|
|
200
|
+
const quote = source[statement.specifierStart] ?? "'";
|
|
201
|
+
const indent = statementIndent(source, statement.start);
|
|
202
|
+
edits.push({
|
|
203
|
+
start: statement.start,
|
|
204
|
+
end: statement.end,
|
|
205
|
+
value: `import ${defaultBinding} from ${quote}${statement.specifier}${quote};\n${indent}const ${binding.local} = { ...${defaultBinding} };`,
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
return edits.length > 0 ? spliceSource(source, edits) : source;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/** Leading whitespace of the line the statement starts on. */
|
|
212
|
+
function statementIndent(source: string, start: number) {
|
|
213
|
+
const lineStart = source.lastIndexOf('\n', start - 1) + 1;
|
|
214
|
+
const indent = source.slice(lineStart, start);
|
|
215
|
+
return /^[\t ]*$/.test(indent) ? indent : '';
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
function isCommonJsImport(specifier: string, file: string): boolean {
|
|
219
|
+
const resolved = resolveRuntimeSpecifier(dirname(file), specifier);
|
|
220
|
+
return resolved !== undefined && extname(resolved) === '.cjs';
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
export function recoverCommonJsNamedExportsPlugin(): Plugin {
|
|
224
|
+
return {
|
|
225
|
+
name: 'pnext-recover-cjs-named-exports',
|
|
226
|
+
setup(build) {
|
|
227
|
+
build.onEnd(result => {
|
|
228
|
+
const output = result.outputFiles?.[0];
|
|
229
|
+
if (!output) return;
|
|
230
|
+
const next = recoverCommonJsNamedExports(decoder.decode(output.contents));
|
|
231
|
+
if (next === decoder.decode(output.contents)) {
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
output.contents = encoder.encode(next);
|
|
235
|
+
});
|
|
236
|
+
},
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// esbuild's native CommonJS dynamic-import facade only exports `default`. Webpack's namespace has the
|
|
241
|
+
// statically discoverable CJS keys too, so create a tiny ESM facade for client-side dynamic imports
|
|
242
|
+
// that forwards both forms. Static imports keep esbuild's normal interop path: their namespace shape is
|
|
243
|
+
// handled separately above and changing it here would alter static output.
|
|
244
|
+
//
|
|
245
|
+
// The filter admits any specifier that can still land on a `.cjs` file: a bare package name, a path
|
|
246
|
+
// whose final segment carries no extension, or an explicit `.cjs`. Anything ending in another extension
|
|
247
|
+
// is excluded in the FILTER - esbuild's Go regexp has no lookahead, so the rule is spelled positively.
|
|
248
|
+
const dynamicCjsCandidate = /^[^./]|(^|\/)[^/.]+$|\.cjs([?#]|$)/;
|
|
249
|
+
|
|
250
|
+
export function clientDynamicCommonJsImportsPlugin(root: string): Plugin {
|
|
251
|
+
return {
|
|
252
|
+
name: 'pnext-client-dynamic-cjs-exports',
|
|
253
|
+
setup(build) {
|
|
254
|
+
// Per-BUILD memo of the whole classification. Each miss walks node_modules, probes package
|
|
255
|
+
// targets and may parse the file for its CJS export names, overwhelmingly for the same handful
|
|
256
|
+
// of lazily-imported specifiers.
|
|
257
|
+
const classified = new Map<string, { path: string; names: string[] } | undefined>();
|
|
258
|
+
const classify = (specifier: string, resolveDir: string) => {
|
|
259
|
+
let file: string;
|
|
260
|
+
try {
|
|
261
|
+
file =
|
|
262
|
+
resolveLinkedPackageSpecifier(root, `${resolveDir}/pnext-resolve.ts`, specifier, [
|
|
263
|
+
'browser',
|
|
264
|
+
'style',
|
|
265
|
+
'import',
|
|
266
|
+
'default',
|
|
267
|
+
]) ?? Bun.resolveSync(specifier, resolveDir);
|
|
268
|
+
} catch {
|
|
269
|
+
return undefined;
|
|
270
|
+
}
|
|
271
|
+
if (extname(file) !== '.cjs') return undefined;
|
|
272
|
+
const names = commonJsExportNamesFromFile(file).filter(name => name !== 'default');
|
|
273
|
+
return names.length === 0 ? undefined : { path: file, names };
|
|
274
|
+
};
|
|
275
|
+
build.onResolve({ filter: dynamicCjsCandidate }, args => {
|
|
276
|
+
if (args.kind !== 'dynamic-import' || !args.resolveDir) return undefined;
|
|
277
|
+
const key = `${args.resolveDir}\0${args.path}`;
|
|
278
|
+
let hit = classified.get(key);
|
|
279
|
+
if (hit === undefined && !classified.has(key)) {
|
|
280
|
+
hit = classify(args.path, args.resolveDir);
|
|
281
|
+
classified.set(key, hit);
|
|
282
|
+
}
|
|
283
|
+
if (!hit) return undefined;
|
|
284
|
+
return {
|
|
285
|
+
path: hit.path,
|
|
286
|
+
namespace: 'pnext-dynamic-cjs-facade',
|
|
287
|
+
pluginData: { names: hit.names },
|
|
288
|
+
};
|
|
289
|
+
});
|
|
290
|
+
build.onLoad({ filter: /.*/, namespace: 'pnext-dynamic-cjs-facade' }, args => {
|
|
291
|
+
const names = (args.pluginData as { names?: string[] } | undefined)?.names ?? [];
|
|
292
|
+
const forwards = names
|
|
293
|
+
.map(name => `export const ${name} = value[${JSON.stringify(name)}];`)
|
|
294
|
+
.join('\n');
|
|
295
|
+
return {
|
|
296
|
+
contents: `import value from ${JSON.stringify(args.path)};\nexport default value;\n${forwards}\n`,
|
|
297
|
+
loader: 'js',
|
|
298
|
+
resolveDir: dirname(args.path),
|
|
299
|
+
};
|
|
300
|
+
});
|
|
301
|
+
},
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
// React 19 renders a thenable child by unwrapping it through `use()`. Preact
|
|
306
|
+
// does not perform that conversion for a bare child, so a client component's
|
|
307
|
+
// `const value = import('pkg').then(...)` otherwise remains an empty node even
|
|
308
|
+
// after its chunk has loaded. Rewrite this narrow direct-child pattern to use
|
|
309
|
+
// the compat React `use()` shim, which suspends and retries inside pnext's
|
|
310
|
+
// implicit client Suspense boundary.
|
|
311
|
+
export function rewriteClientDynamicImportPromises(source: string): string {
|
|
312
|
+
const names = [
|
|
313
|
+
...source.matchAll(
|
|
314
|
+
/\b(?:const|let|var)\s+([A-Za-z_$][\w$]*)\s*=\s*import\(\s*(['"])[^'"]+\2\s*\)\s*\.then\s*\(/g,
|
|
315
|
+
),
|
|
316
|
+
]
|
|
317
|
+
.map(match => match[1])
|
|
318
|
+
.filter((name): name is string => Boolean(name));
|
|
319
|
+
if (names.length === 0) return source;
|
|
320
|
+
|
|
321
|
+
const hook = uniqueIdentifier(source, '__pnext_use');
|
|
322
|
+
let next = source;
|
|
323
|
+
let changed = false;
|
|
324
|
+
for (const name of names) {
|
|
325
|
+
const expression = new RegExp(`\\{${escapeRegExp(name)}\\}`, 'g');
|
|
326
|
+
const rewritten = next.replace(expression, `{${hook}(${name})}`);
|
|
327
|
+
changed ||= rewritten !== next;
|
|
328
|
+
next = rewritten;
|
|
329
|
+
}
|
|
330
|
+
if (!changed) return source;
|
|
331
|
+
|
|
332
|
+
const directive = /^(?:\s*['"][^'"]+['"];?\s*)*/.exec(next)?.[0] ?? '';
|
|
333
|
+
return `${directive}import { use as ${hook} } from 'react';\n${next.slice(directive.length)}`;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
function recoverCommonJsNamedExports(code: string) {
|
|
337
|
+
if (hasNonDefaultExport(code)) return code;
|
|
338
|
+
const names = [...new Set([...commonJsExportNames(code), ...esbuildEntryExportNames(code)])]
|
|
339
|
+
.filter(name => name !== 'default' && name !== '__esModule')
|
|
340
|
+
.sort();
|
|
341
|
+
if (names.length === 0) return code;
|
|
342
|
+
|
|
343
|
+
const directDefaultExport = /(^|\n)export default ([^;\n]+);/.exec(code);
|
|
344
|
+
const listedDefaultExport = /(^|\n)export\s*\{\s*([A-Za-z_$][\w$]*)\s+as\s+default\s*,?\s*\};?/.exec(
|
|
345
|
+
code,
|
|
346
|
+
);
|
|
347
|
+
const defaultExport = directDefaultExport ?? listedDefaultExport;
|
|
348
|
+
if (!defaultExport?.[2]) return code;
|
|
349
|
+
|
|
350
|
+
const defaultName = uniqueIdentifier(code, '__pnext_cjs_default');
|
|
351
|
+
const namespaceName = commonJsNamespaceBinding(code, defaultExport[2]);
|
|
352
|
+
const usedNames = [defaultName];
|
|
353
|
+
const bindings = names.map(name => {
|
|
354
|
+
const localName = uniqueIdentifier(code, `__pnext_cjs_export_${name}`, ...usedNames);
|
|
355
|
+
usedNames.push(localName);
|
|
356
|
+
return { name, localName };
|
|
357
|
+
});
|
|
358
|
+
const namedBindings = bindings
|
|
359
|
+
.map(
|
|
360
|
+
({ name, localName }) =>
|
|
361
|
+
`const ${localName} = ${(namespaceName ?? defaultName)}[${JSON.stringify(name)}];`,
|
|
362
|
+
)
|
|
363
|
+
.join('\n');
|
|
364
|
+
const namedExports = bindings.map(({ name, localName }) => `${localName} as ${name}`).join(', ');
|
|
365
|
+
|
|
366
|
+
return code.replace(
|
|
367
|
+
defaultExport[0],
|
|
368
|
+
`${defaultExport[1]}const ${defaultName} = ${defaultExport[2]};\nexport default ${defaultName};\n${namedBindings}\nexport { ${namedExports} };\n`,
|
|
369
|
+
);
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
function commonJsNamespaceBinding(code: string, defaultName: string) {
|
|
373
|
+
const assignment = new RegExp(
|
|
374
|
+
`(?:^|\\n)(?:var|const|let)\\s+${escapeRegExp(defaultName)}\\s*=\\s*([A-Za-z_$][\\w$]*)\\.default\\s*;`,
|
|
375
|
+
).exec(code);
|
|
376
|
+
if (assignment?.[1]) return assignment[1];
|
|
377
|
+
|
|
378
|
+
return new RegExp(
|
|
379
|
+
`(?:^|\\n)(?:var|const|let)\\s+${escapeRegExp(defaultName)}\\s*=\\s*([A-Za-z_$][\\w$]*)\\s*!=\\s*null\\s*&&[\\s\\S]*?\\?\\s*\\1\\.default\\s*:\\s*\\1\\s*;`,
|
|
380
|
+
).exec(code)?.[1];
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
function hasNonDefaultExport(code: string) {
|
|
384
|
+
if (/(^|\n)export\s+(?:\*|(?:const|let|var|function|class)\s+)/.test(code)) return true;
|
|
385
|
+
for (const statement of code.matchAll(/(^|\n)export\s*\{([^}]*)\}/g)) {
|
|
386
|
+
const names = (statement[2] ?? '')
|
|
387
|
+
.split(',')
|
|
388
|
+
.map(name => name.trim().split(/\s+as\s+/i).at(-1))
|
|
389
|
+
.filter((name): name is string => Boolean(name));
|
|
390
|
+
if (names.some(name => name !== 'default')) return true;
|
|
391
|
+
}
|
|
392
|
+
return false;
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
function commonJsExportNames(code: string) {
|
|
396
|
+
return [
|
|
397
|
+
...new Set([
|
|
398
|
+
...[...code.matchAll(/\bexports\.([A-Za-z_$][\w$]*)\s*=\s*/g)].map(match => match[1]),
|
|
399
|
+
...[
|
|
400
|
+
...code.matchAll(
|
|
401
|
+
/\bObject\.defineProperty\(\s*exports\s*,\s*["']([A-Za-z_$][\w$]*)["']/g,
|
|
402
|
+
),
|
|
403
|
+
].map(match => match[1]),
|
|
404
|
+
...extractModuleExportsObjectNames(code),
|
|
405
|
+
]
|
|
406
|
+
.filter((name): name is string => Boolean(name && name !== '__esModule' && isIdentifier(name)))
|
|
407
|
+
.sort(),
|
|
408
|
+
),
|
|
409
|
+
];
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
function commonJsExportNamesFromFile(file: string, visited = new Set<string>()): string[] {
|
|
413
|
+
if (visited.has(file)) return [];
|
|
414
|
+
visited.add(file);
|
|
415
|
+
let code: string;
|
|
416
|
+
try {
|
|
417
|
+
code = readFileSync(file, 'utf8');
|
|
418
|
+
} catch {
|
|
419
|
+
return [];
|
|
420
|
+
}
|
|
421
|
+
const names = commonJsExportNames(code);
|
|
422
|
+
if (names.length > 0) return names;
|
|
423
|
+
|
|
424
|
+
// Follow the simple `const value = require('...'); module.exports = value`
|
|
425
|
+
// form used by packages that re-export an `imports` map entry, plus the
|
|
426
|
+
// equally common direct `module.exports = require('./lib')` (relay-runtime).
|
|
427
|
+
const reexport =
|
|
428
|
+
/\b(?:const|let|var)\s+([A-Za-z_$][\w$]*)\s*=\s*require\(\s*['"]([^'"]+)['"]\s*\)[\s\S]*?\bmodule\.exports\s*=\s*\1\s*;?/.exec(
|
|
429
|
+
code,
|
|
430
|
+
) ?? /\bmodule\.exports\s*=\s*require\(\s*['"]([^'"]+)['"]\s*\)/.exec(code);
|
|
431
|
+
const specifier = reexport?.[2] ?? reexport?.[1];
|
|
432
|
+
if (!specifier) return [];
|
|
433
|
+
try {
|
|
434
|
+
return commonJsExportNamesFromFile(Bun.resolveSync(specifier, dirname(file)), visited);
|
|
435
|
+
} catch {
|
|
436
|
+
return [];
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
function escapeRegExp(value: string) {
|
|
441
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
function extractModuleExportsObjectNames(code: string) {
|
|
445
|
+
const start = /\bmodule\.exports\s*=\s*\{/.exec(code);
|
|
446
|
+
if (!start) return [];
|
|
447
|
+
const objectBody = topLevelObjectBody(code, start.index + start[0].length - 1);
|
|
448
|
+
if (objectBody === undefined) return [];
|
|
449
|
+
return [...objectBody.matchAll(/(?:^|,)\s*(?:([A-Za-z_$][\w$]*)\s*:|["']([A-Za-z_$][\w$]*)["']\s*:)/g)]
|
|
450
|
+
.map(match => match[1] || match[2])
|
|
451
|
+
.filter((name): name is string => Boolean(name && isIdentifier(name)));
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
// Scan an object literal from its opening brace, keeping only top-level text: nested bodies, strings
|
|
455
|
+
// and comments are blanked out so a nested key (or a comment separating keys) cannot be mistaken for -
|
|
456
|
+
// or hide - a top-level one. Returns undefined when the literal is unterminated.
|
|
457
|
+
function topLevelObjectBody(code: string, openIndex: number): string | undefined {
|
|
458
|
+
let depth = 0;
|
|
459
|
+
let out = '';
|
|
460
|
+
for (let index = openIndex; index < code.length; index += 1) {
|
|
461
|
+
const char = code[index]!;
|
|
462
|
+
if (char === '"' || char === "'" || char === '`') {
|
|
463
|
+
const end = skipString(code, index, char);
|
|
464
|
+
if (depth === 1) out += ' '.repeat(end - index + 1);
|
|
465
|
+
index = end;
|
|
466
|
+
continue;
|
|
467
|
+
}
|
|
468
|
+
if (char === '/' && (code[index + 1] === '/' || code[index + 1] === '*')) {
|
|
469
|
+
const end = commentEnd(code, index);
|
|
470
|
+
if (depth === 1) out += ' '.repeat(end - index + 1);
|
|
471
|
+
index = end;
|
|
472
|
+
continue;
|
|
473
|
+
}
|
|
474
|
+
if (char === '{' || char === '[' || char === '(') {
|
|
475
|
+
depth += 1;
|
|
476
|
+
if (depth === 1) continue;
|
|
477
|
+
out += depth === 2 ? ' ' : '';
|
|
478
|
+
continue;
|
|
479
|
+
}
|
|
480
|
+
if (char === '}' || char === ']' || char === ')') {
|
|
481
|
+
depth -= 1;
|
|
482
|
+
if (depth === 0) return out;
|
|
483
|
+
continue;
|
|
484
|
+
}
|
|
485
|
+
if (depth === 1) out += char;
|
|
486
|
+
}
|
|
487
|
+
return undefined;
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
// Index of the last character of the comment starting at `start`.
|
|
491
|
+
function commentEnd(code: string, start: number): number {
|
|
492
|
+
if (code[start + 1] === '/') {
|
|
493
|
+
const newline = code.indexOf('\n', start);
|
|
494
|
+
return (newline < 0 ? code.length : newline) - 1;
|
|
495
|
+
}
|
|
496
|
+
const close = code.indexOf('*/', start);
|
|
497
|
+
return close < 0 ? code.length - 1 : close + 1;
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
function skipString(code: string, start: number, quote: string): number {
|
|
501
|
+
for (let index = start + 1; index < code.length; index += 1) {
|
|
502
|
+
const char = code[index];
|
|
503
|
+
if (char === '\\') {
|
|
504
|
+
index += 1;
|
|
505
|
+
continue;
|
|
506
|
+
}
|
|
507
|
+
if (char === quote) return index;
|
|
508
|
+
}
|
|
509
|
+
return code.length - 1;
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
// Reserved words are legal CommonJS object keys but illegal export bindings, so
|
|
513
|
+
// a `module.exports = { class: … }` entry must not reach the facade.
|
|
514
|
+
const reservedWords = new Set([
|
|
515
|
+
'await', 'break', 'case', 'catch', 'class', 'const', 'continue', 'debugger', 'default',
|
|
516
|
+
'delete', 'do', 'else', 'enum', 'export', 'extends', 'false', 'finally', 'for', 'function',
|
|
517
|
+
'if', 'implements', 'import', 'in', 'instanceof', 'interface', 'let', 'new', 'null',
|
|
518
|
+
'package', 'private', 'protected', 'public', 'return', 'static', 'super', 'switch', 'this',
|
|
519
|
+
'throw', 'true', 'try', 'typeof', 'var', 'void', 'while', 'with', 'yield',
|
|
520
|
+
]);
|
|
521
|
+
|
|
522
|
+
export const namedFacadeExportNames = fileMemo((file: string): string[] =>
|
|
523
|
+
commonJsExportNamesFromFile(file).filter(
|
|
524
|
+
name => name !== 'default' && name !== '__esModule' && !reservedWords.has(name),
|
|
525
|
+
),
|
|
526
|
+
);
|
|
527
|
+
|
|
528
|
+
// Recover named exports from esbuild's `__export(entry, {...}); module.exports = __toCommonJS(entry)` shape.
|
|
529
|
+
function esbuildEntryExportNames(code: string) {
|
|
530
|
+
const toCommonJs = [
|
|
531
|
+
...code.matchAll(/module\.exports\s*=\s*__toCommonJS\w*\(\s*([A-Za-z_$][\w$]*)\s*\)/g),
|
|
532
|
+
];
|
|
533
|
+
const entryVar = toCommonJs.at(-1)?.[1];
|
|
534
|
+
if (!entryVar) return [];
|
|
535
|
+
const exportCall = new RegExp(
|
|
536
|
+
`__export\\w*\\(\\s*${entryVar}\\s*,\\s*\\{([\\s\\S]*?)\\}\\s*\\)`,
|
|
537
|
+
).exec(code);
|
|
538
|
+
if (!exportCall?.[1]) return [];
|
|
539
|
+
return [...exportCall[1].matchAll(/(?:^|,)\s*([A-Za-z_$][\w$]*)\s*:/g)]
|
|
540
|
+
.map(match => match[1])
|
|
541
|
+
.filter((name): name is string => Boolean(name && isIdentifier(name)));
|
|
542
|
+
}
|