@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.
Files changed (371) hide show
  1. package/README.md +153 -0
  2. package/bin/pnext +67 -0
  3. package/config/lint/base.js +48 -0
  4. package/config/ts/base.json +26 -0
  5. package/config/ts/react.json +13 -0
  6. package/package.json +70 -0
  7. package/reference/compat.md +63 -0
  8. package/reference/config.md +120 -0
  9. package/reference/css.md +58 -0
  10. package/reference/dev.md +69 -0
  11. package/reference/env.md +40 -0
  12. package/reference/metadata.md +86 -0
  13. package/reference/navigation.md +149 -0
  14. package/reference/overview.md +35 -0
  15. package/reference/performance.md +97 -0
  16. package/reference/rendering.md +127 -0
  17. package/reference/routing.md +167 -0
  18. package/reference/typegen.md +64 -0
  19. package/src/api/cache.ts +80 -0
  20. package/src/api/client-cache.ts +9 -0
  21. package/src/api/client-navigation.ts +279 -0
  22. package/src/api/dynamic.tsx +102 -0
  23. package/src/api/link.tsx +119 -0
  24. package/src/api/navigation.ts +198 -0
  25. package/src/api/router/events.ts +53 -0
  26. package/src/api/router/history.ts +70 -0
  27. package/src/api/router/hub.ts +194 -0
  28. package/src/api/router/policies.ts +107 -0
  29. package/src/api/router/runtime.ts +5238 -0
  30. package/src/api/router/types.ts +299 -0
  31. package/src/api/router.ts +167 -0
  32. package/src/api/server.ts +323 -0
  33. package/src/api/suspense.ts +16 -0
  34. package/src/cache/context.ts +61 -0
  35. package/src/cli/adapters/vercel-warm.ts +375 -0
  36. package/src/cli/adapters/vercel.ts +1310 -0
  37. package/src/cli/analyze-print.ts +181 -0
  38. package/src/cli/analyze.ts +328 -0
  39. package/src/cli/boot-trace.ts +29 -0
  40. package/src/cli/build.ts +3114 -0
  41. package/src/cli/dev.ts +276 -0
  42. package/src/cli/index.ts +196 -0
  43. package/src/cli/named-bin.ts +119 -0
  44. package/src/cli/serve-ui.ts +160 -0
  45. package/src/cli/start.ts +1425 -0
  46. package/src/client/build.ts +2136 -0
  47. package/src/client/chunk-fold.ts +526 -0
  48. package/src/client/entry.ts +1525 -0
  49. package/src/client/paths.ts +22 -0
  50. package/src/client/prebuilt.ts +621 -0
  51. package/src/client/profile.ts +75 -0
  52. package/src/client/react-compiler.ts +94 -0
  53. package/src/client/reference-stub.ts +145 -0
  54. package/src/client/reference.ts +47 -0
  55. package/src/compat/actions/action-client.ts +531 -0
  56. package/src/compat/actions/action-dispatch.ts +676 -0
  57. package/src/compat/actions/action-router.ts +40 -0
  58. package/src/compat/actions/action-shared.ts +95 -0
  59. package/src/compat/actions/client-plugin.ts +135 -0
  60. package/src/compat/actions/client-stub.ts +65 -0
  61. package/src/compat/actions/config.ts +164 -0
  62. package/src/compat/actions/detect.ts +208 -0
  63. package/src/compat/actions/discovery.ts +244 -0
  64. package/src/compat/actions/early-submit.ts +40 -0
  65. package/src/compat/actions/endpoint.ts +602 -0
  66. package/src/compat/actions/flight.ts +52 -0
  67. package/src/compat/actions/form-state.ts +73 -0
  68. package/src/compat/actions/hoist.ts +485 -0
  69. package/src/compat/actions/ids.ts +39 -0
  70. package/src/compat/actions/index.ts +41 -0
  71. package/src/compat/actions/instances.ts +144 -0
  72. package/src/compat/actions/origin.ts +109 -0
  73. package/src/compat/actions/protocol.ts +125 -0
  74. package/src/compat/actions/registry.ts +74 -0
  75. package/src/compat/actions/rewrite.ts +282 -0
  76. package/src/compat/actions/serve.ts +414 -0
  77. package/src/compat/actions/server-tag.ts +21 -0
  78. package/src/compat/actions/unrecognized-error.ts +30 -0
  79. package/src/compat/adapter/build-complete.ts +257 -0
  80. package/src/compat/bundler/bun-externals.ts +53 -0
  81. package/src/compat/bundler/cjs-exports.ts +542 -0
  82. package/src/compat/bundler/config.ts +363 -0
  83. package/src/compat/bundler/externals.ts +34 -0
  84. package/src/compat/bundler/import-meta-url.ts +60 -0
  85. package/src/compat/bundler/modularize-imports.ts +119 -0
  86. package/src/compat/bundler/new-url-asset.ts +87 -0
  87. package/src/compat/bundler/optimize-package-imports.ts +273 -0
  88. package/src/compat/bundler/polyfill.ts +88 -0
  89. package/src/compat/bundler/react-compiler.ts +61 -0
  90. package/src/compat/bundler/react-profiler.tsx +25 -0
  91. package/src/compat/bundler/relay-transform.ts +116 -0
  92. package/src/compat/bundler/require-context.ts +281 -0
  93. package/src/compat/bundler/resolve-extensions.ts +75 -0
  94. package/src/compat/bundler/source-cache.ts +61 -0
  95. package/src/compat/bundler/static-imports.ts +25 -0
  96. package/src/compat/bundler/symlink-imports.ts +119 -0
  97. package/src/compat/bundler/tsconfig-paths.ts +50 -0
  98. package/src/compat/bundler/wasm.ts +153 -0
  99. package/src/compat/bundler/webpack-loaders.ts +685 -0
  100. package/src/compat/bundler/worker.ts +278 -0
  101. package/src/compat/cache/build-flags.ts +81 -0
  102. package/src/compat/cache/build-prerender-errors.ts +163 -0
  103. package/src/compat/cache/custom-handler.ts +159 -0
  104. package/src/compat/cache/fetch-patch.ts +745 -0
  105. package/src/compat/cache/handler.ts +100 -0
  106. package/src/compat/cache/modern-handler.ts +275 -0
  107. package/src/compat/cache/resume-data-cache.ts +143 -0
  108. package/src/compat/cache/revalidate.ts +759 -0
  109. package/src/compat/cache/runtime-error.ts +124 -0
  110. package/src/compat/cache/use-cache-transform.ts +961 -0
  111. package/src/compat/cache/use-cache.ts +1695 -0
  112. package/src/compat/cache-control.ts +269 -0
  113. package/src/compat/client/base-path.ts +64 -0
  114. package/src/compat/client/css-order.ts +36 -0
  115. package/src/compat/client/errors/control-flow.ts +92 -0
  116. package/src/compat/client/errors/error-boundary.ts +222 -0
  117. package/src/compat/client/errors/global-error.ts +238 -0
  118. package/src/compat/client/errors/install.ts +217 -0
  119. package/src/compat/client/errors/lazy.ts +53 -0
  120. package/src/compat/client/errors/primitive-throw.ts +126 -0
  121. package/src/compat/client/errors/soft-refresh.ts +14 -0
  122. package/src/compat/client/link-status.ts +86 -0
  123. package/src/compat/client/nav-compat-runtime.ts +57 -0
  124. package/src/compat/client/nav-compat.ts +42 -0
  125. package/src/compat/client/navigation-scroll.ts +154 -0
  126. package/src/compat/client/optimistic-routing.ts +206 -0
  127. package/src/compat/client/prefetch-cache.ts +111 -0
  128. package/src/compat/client/route-announcer.ts +72 -0
  129. package/src/compat/client/segment-cache-policy.ts +159 -0
  130. package/src/compat/client/segment-cache.ts +1077 -0
  131. package/src/compat/client/segment-prefetch.ts +375 -0
  132. package/src/compat/client/trailing-slash.ts +24 -0
  133. package/src/compat/css/chunking.ts +254 -0
  134. package/src/compat/css/inline-css.ts +73 -0
  135. package/src/compat/css/lightningcss.ts +90 -0
  136. package/src/compat/css/modules.ts +373 -0
  137. package/src/compat/css/nonce.ts +30 -0
  138. package/src/compat/css/sass-plugin.ts +65 -0
  139. package/src/compat/css/sass.ts +392 -0
  140. package/src/compat/css/styled-jsx-runtime.ts +80 -0
  141. package/src/compat/css/styled-jsx.ts +49 -0
  142. package/src/compat/edge-runtime.ts +71 -0
  143. package/src/compat/export/client.ts +112 -0
  144. package/src/compat/export/index.ts +272 -0
  145. package/src/compat/export/standalone.ts +207 -0
  146. package/src/compat/image-optimizer/cache.ts +119 -0
  147. package/src/compat/image-optimizer/detect.ts +143 -0
  148. package/src/compat/image-optimizer/index.ts +601 -0
  149. package/src/compat/image-optimizer/source.ts +243 -0
  150. package/src/compat/index.ts +458 -0
  151. package/src/compat/lifecycle/after-scope.ts +86 -0
  152. package/src/compat/lifecycle/after.ts +173 -0
  153. package/src/compat/lifecycle/error-funnel.ts +306 -0
  154. package/src/compat/lifecycle/error-serialize.ts +87 -0
  155. package/src/compat/lifecycle/error-ui.ts +167 -0
  156. package/src/compat/lifecycle/instrumentation-client.ts +138 -0
  157. package/src/compat/lifecycle/instrumentation.ts +277 -0
  158. package/src/compat/lifecycle/node-console.ts +19 -0
  159. package/src/compat/lifecycle/testmode.ts +263 -0
  160. package/src/compat/mdx/compile.ts +219 -0
  161. package/src/compat/mdx/next-mdx-stub.ts +46 -0
  162. package/src/compat/mdx/plugin.ts +37 -0
  163. package/src/compat/metadata-route-artifacts.ts +458 -0
  164. package/src/compat/metadata.ts +295 -0
  165. package/src/compat/middleware/manifest.ts +210 -0
  166. package/src/compat/misc/action-return.ts +173 -0
  167. package/src/compat/next/cache.ts +211 -0
  168. package/src/compat/next/canonical-url.ts +35 -0
  169. package/src/compat/next/client-cache.ts +57 -0
  170. package/src/compat/next/client-navigation.ts +313 -0
  171. package/src/compat/next/client-only.ts +3 -0
  172. package/src/compat/next/client-script.tsx +215 -0
  173. package/src/compat/next/client-server.ts +39 -0
  174. package/src/compat/next/config-loader.ts +569 -0
  175. package/src/compat/next/config.ts +29 -0
  176. package/src/compat/next/constants.cjs +6 -0
  177. package/src/compat/next/constants.ts +6 -0
  178. package/src/compat/next/custom-server.ts +236 -0
  179. package/src/compat/next/dist/client/components/app-router-headers.ts +32 -0
  180. package/src/compat/next/dist/server/app-render/work-unit-async-storage.external.cjs +38 -0
  181. package/src/compat/next/dist/server/web/spec-extension/revalidate.ts +1 -0
  182. package/src/compat/next/dist/server/web/spec-extension/unstable-cache.ts +1 -0
  183. package/src/compat/next/dist/server/web/spec-extension/unstable-no-store.ts +1 -0
  184. package/src/compat/next/dynamic.tsx +46 -0
  185. package/src/compat/next/error.tsx +148 -0
  186. package/src/compat/next/font/cache.ts +171 -0
  187. package/src/compat/next/font/google.ts +2 -0
  188. package/src/compat/next/font/index.ts +8 -0
  189. package/src/compat/next/font/local.ts +5 -0
  190. package/src/compat/next/font/runtime-client.ts +71 -0
  191. package/src/compat/next/font/runtime.ts +974 -0
  192. package/src/compat/next/font/shared.ts +281 -0
  193. package/src/compat/next/form.tsx +156 -0
  194. package/src/compat/next/head.tsx +10 -0
  195. package/src/compat/next/headers.ts +247 -0
  196. package/src/compat/next/image/config.ts +196 -0
  197. package/src/compat/next/image/optimizer.ts +96 -0
  198. package/src/compat/next/image/patterns.ts +103 -0
  199. package/src/compat/next/image/shared.ts +141 -0
  200. package/src/compat/next/image/static-metadata.ts +283 -0
  201. package/src/compat/next/image/validate.ts +269 -0
  202. package/src/compat/next/image-client.tsx +215 -0
  203. package/src/compat/next/image-props.ts +575 -0
  204. package/src/compat/next/image-usage.ts +102 -0
  205. package/src/compat/next/image.tsx +56 -0
  206. package/src/compat/next/index.ts +1 -0
  207. package/src/compat/next/legacy-image.tsx +97 -0
  208. package/src/compat/next/link-usage.ts +29 -0
  209. package/src/compat/next/link-validation-transform.ts +200 -0
  210. package/src/compat/next/link.tsx +466 -0
  211. package/src/compat/next/navigation.cjs +21 -0
  212. package/src/compat/next/navigation.ts +188 -0
  213. package/src/compat/next/offline.ts +51 -0
  214. package/src/compat/next/og.ts +324 -0
  215. package/src/compat/next/optimistic-route-state.ts +188 -0
  216. package/src/compat/next/preferred-region.ts +39 -0
  217. package/src/compat/next/redirects.ts +131 -0
  218. package/src/compat/next/resource-hints.ts +136 -0
  219. package/src/compat/next/rewrites.ts +350 -0
  220. package/src/compat/next/root-params.ts +142 -0
  221. package/src/compat/next/router.cjs +49 -0
  222. package/src/compat/next/router.ts +143 -0
  223. package/src/compat/next/script.tsx +355 -0
  224. package/src/compat/next/server-only.ts +3 -0
  225. package/src/compat/next/server.ts +28 -0
  226. package/src/compat/next/svgr.ts +58 -0
  227. package/src/compat/next/telemetry.ts +77 -0
  228. package/src/compat/next/user-agent.ts +100 -0
  229. package/src/compat/next/web-vitals.ts +56 -0
  230. package/src/compat/otel/api.ts +95 -0
  231. package/src/compat/otel/client-trace-metadata.ts +71 -0
  232. package/src/compat/otel/fetch-span.ts +77 -0
  233. package/src/compat/otel/tracer.ts +944 -0
  234. package/src/compat/pages/client-plugin.ts +108 -0
  235. package/src/compat/pages/index.ts +527 -0
  236. package/src/compat/pages/router-state.ts +94 -0
  237. package/src/compat/ppr/io.ts +38 -0
  238. package/src/compat/ppr/missing-root-params.ts +105 -0
  239. package/src/compat/ppr/root-params-scan.ts +164 -0
  240. package/src/compat/ppr/root-params-transform.ts +75 -0
  241. package/src/compat/ppr/root-params.ts +129 -0
  242. package/src/compat/ppr/segment-config-incompat.ts +34 -0
  243. package/src/compat/protocol.ts +202 -0
  244. package/src/compat/react/client.ts +59 -0
  245. package/src/compat/react/compiler-runtime.ts +60 -0
  246. package/src/compat/react/dom-client.ts +115 -0
  247. package/src/compat/react/dom-react-server.ts +20 -0
  248. package/src/compat/react/dom-server.ts +40 -0
  249. package/src/compat/react/dom.ts +154 -0
  250. package/src/compat/react/preact.ts +522 -0
  251. package/src/compat/react/react-server.ts +84 -0
  252. package/src/compat/react/router-shim.ts +26 -0
  253. package/src/compat/react/server-component-use.ts +48 -0
  254. package/src/compat/react/server-inserted-html.ts +87 -0
  255. package/src/compat/react/server.ts +156 -0
  256. package/src/compat/react/view-transition.ts +60 -0
  257. package/src/compat/register/actions.ts +875 -0
  258. package/src/compat/register/boot.ts +141 -0
  259. package/src/compat/register/build-tier.ts +11 -0
  260. package/src/compat/register/build.ts +182 -0
  261. package/src/compat/register/bundler.ts +587 -0
  262. package/src/compat/register/cache.ts +85 -0
  263. package/src/compat/register/client-errors.ts +18 -0
  264. package/src/compat/register/config.ts +17 -0
  265. package/src/compat/register/css-extras.ts +120 -0
  266. package/src/compat/register/edge-runtime.ts +6 -0
  267. package/src/compat/register/errors.ts +46 -0
  268. package/src/compat/register/export.ts +23 -0
  269. package/src/compat/register/font.ts +36 -0
  270. package/src/compat/register/hooks.ts +34 -0
  271. package/src/compat/register/image.ts +133 -0
  272. package/src/compat/register/index.ts +111 -0
  273. package/src/compat/register/instrumentation-client.ts +35 -0
  274. package/src/compat/register/lifecycle.ts +86 -0
  275. package/src/compat/register/mdx.ts +48 -0
  276. package/src/compat/register/middleware.ts +36 -0
  277. package/src/compat/register/misc.ts +44 -0
  278. package/src/compat/register/otel.ts +288 -0
  279. package/src/compat/register/pages-api.ts +473 -0
  280. package/src/compat/register/ppr.ts +56 -0
  281. package/src/compat/register/protocol.ts +57 -0
  282. package/src/compat/register/proxy.ts +127 -0
  283. package/src/compat/register/render.ts +268 -0
  284. package/src/compat/register/routing.ts +410 -0
  285. package/src/compat/register/segment.ts +1903 -0
  286. package/src/compat/register/static-image.ts +21 -0
  287. package/src/compat/register/typed-routes.ts +35 -0
  288. package/src/compat/register/usecache.ts +131 -0
  289. package/src/compat/register/validation.ts +56 -0
  290. package/src/compat/segment/loading-boundary.ts +113 -0
  291. package/src/compat/segment/page-slot.ts +200 -0
  292. package/src/compat/segment/tree.ts +481 -0
  293. package/src/compat/segment/vary-key.ts +102 -0
  294. package/src/compat/segment/vary-params.ts +551 -0
  295. package/src/compat/static-params.ts +33 -0
  296. package/src/compat/tsconfig-defaults.ts +301 -0
  297. package/src/compat/typecheck/index.ts +1481 -0
  298. package/src/compat/typecheck/worker.ts +26 -0
  299. package/src/compat/typed-routes/index.ts +92 -0
  300. package/src/compat/typed-routes/manifest.ts +356 -0
  301. package/src/compat/typed-routes/typegen.ts +566 -0
  302. package/src/compat/validation/errors.ts +159 -0
  303. package/src/compat/validation/index.ts +1770 -0
  304. package/src/compat/validation/prerender-diagnostics.ts +1508 -0
  305. package/src/compat-bootstrap.ts +67 -0
  306. package/src/config.ts +218 -0
  307. package/src/css/build.ts +697 -0
  308. package/src/css/index.ts +2 -0
  309. package/src/css/postcss.ts +236 -0
  310. package/src/css/worker.ts +34 -0
  311. package/src/dev/client-actions.ts +35 -0
  312. package/src/dev/client-chunk-store.ts +92 -0
  313. package/src/dev/client-key-cache.ts +178 -0
  314. package/src/dev/global-css-cache.ts +212 -0
  315. package/src/dev/imports.ts +2430 -0
  316. package/src/dev/module-cache.ts +721 -0
  317. package/src/dev/module-generations.ts +38 -0
  318. package/src/dev/module-transform.ts +188 -0
  319. package/src/dev/node-module-bundle-cache.ts +63 -0
  320. package/src/dev/restart-cache.ts +10 -0
  321. package/src/dev/route-bundle-key-cache.ts +154 -0
  322. package/src/dev/route-facts-cache.ts +223 -0
  323. package/src/dev/server.ts +1710 -0
  324. package/src/dynamic/source.ts +307 -0
  325. package/src/dynamic/tree-shake.ts +262 -0
  326. package/src/env.ts +92 -0
  327. package/src/extensions.ts +1898 -0
  328. package/src/index.ts +34 -0
  329. package/src/internal.ts +43 -0
  330. package/src/islands/boundary-error.ts +8 -0
  331. package/src/islands/static-children.ts +37 -0
  332. package/src/islands/static-slots.ts +106 -0
  333. package/src/ppr-postpone.ts +24 -0
  334. package/src/ppr.ts +784 -0
  335. package/src/proxy.ts +752 -0
  336. package/src/render/hooks.ts +384 -0
  337. package/src/render/index.ts +1 -0
  338. package/src/render/island-context.ts +47 -0
  339. package/src/render/metadata.ts +857 -0
  340. package/src/render/renderer.ts +7391 -0
  341. package/src/render/resource-hints.ts +44 -0
  342. package/src/render/slots.tsx +679 -0
  343. package/src/request/context.ts +396 -0
  344. package/src/resolve/engine.ts +219 -0
  345. package/src/resolve/imports.ts +1104 -0
  346. package/src/resolve/scan-facts.ts +474 -0
  347. package/src/resolve/source-text.ts +86 -0
  348. package/src/routing/forwarded.ts +41 -0
  349. package/src/routing/handler.ts +271 -0
  350. package/src/routing/href.ts +203 -0
  351. package/src/routing/metadata.ts +1018 -0
  352. package/src/routing/request-runtime.ts +43 -0
  353. package/src/routing/routes.ts +2560 -0
  354. package/src/routing/slots.ts +432 -0
  355. package/src/runtime/server.ts +3453 -0
  356. package/src/runtime/vendor.ts +1160 -0
  357. package/src/style-modules.d.ts +9 -0
  358. package/src/typegen.ts +151 -0
  359. package/src/types.ts +725 -0
  360. package/src/utils/ansi.ts +9 -0
  361. package/src/utils/content-type.ts +31 -0
  362. package/src/utils/decode.ts +7 -0
  363. package/src/utils/dev-profile.ts +31 -0
  364. package/src/utils/error-log.ts +29 -0
  365. package/src/utils/fs-cache.ts +31 -0
  366. package/src/utils/fs.ts +119 -0
  367. package/src/utils/html.ts +46 -0
  368. package/src/utils/serialize.ts +378 -0
  369. package/src/utils/source.ts +35 -0
  370. package/src/utils/verbose.ts +39 -0
  371. package/tsconfig.json +10 -0
@@ -0,0 +1,281 @@
1
+ // webpack's `require.context()` (COMPAT).
2
+ //
3
+ // `require.context(dir, recursive, regExp)` is a webpack-only build-time API: it eagerly includes every
4
+ // file under `dir` matching `regExp` and returns a callable context module - `ctx(key)` yields a module,
5
+ // `ctx.keys()` lists the request keys, `ctx.resolve(key)` the underlying path, `ctx.id` the context
6
+ // module id. pnext has no webpack graph, so the call is expanded at transform time: the directory is
7
+ // walked on disk, the matching files become static top-level imports, and the call expression is
8
+ // replaced by a synthesized context object built from them.
9
+ //
10
+ // Wired as a server source transform (covering both the Bun runtime's per-file SSR loading and the
11
+ // esbuild server passes) and as a client source transform.
12
+
13
+ import { existsSync, readdirSync, statSync } from 'node:fs';
14
+ import path from 'node:path';
15
+
16
+ /** Extensions whose files also get an extension-less request key (webpack resolves both). */
17
+ const RESOLVABLE_EXTENSIONS = ['.js', '.jsx', '.ts', '.tsx', '.mjs', '.cjs', '.json'];
18
+
19
+ // `require.context(` — also matches the TS-cast form the Next fixtures use,
20
+ // `(require as any).context(`, since the transform runs on pre-compiled source.
21
+ const CONTEXT_CALL = /(?:\(\s*require\s+as\s+[^)]*\)|\brequire)\s*\.\s*context\s*\(/g;
22
+
23
+ /** Cheap gate: does this source contain any candidate `require.context(` call? */
24
+ export function sourceHasRequireContext(source: string): boolean {
25
+ return source.includes('.context(') && source.includes('require');
26
+ }
27
+
28
+ interface ContextEntry {
29
+ /** Request key, e.g. `./parent/file1.js`. */
30
+ key: string;
31
+ /** Absolute path of the file the key resolves to. */
32
+ file: string;
33
+ }
34
+
35
+ /**
36
+ * Split a call's argument list (the text between the outer parens) on top-level
37
+ * commas, ignoring commas nested in parens/brackets/braces, strings, regex
38
+ * literals and comments. Returns `undefined` when the parens never balance.
39
+ */
40
+ function splitCallArguments(source: string, openIndex: number): { args: string[]; end: number } | undefined {
41
+ const args: string[] = [];
42
+ let depth = 0;
43
+ let start = openIndex + 1;
44
+ let index = openIndex;
45
+ let quote: string | undefined;
46
+ let inRegex = false;
47
+ while (index < source.length) {
48
+ const char = source[index]!;
49
+ const prev = source[index - 1];
50
+ if (quote) {
51
+ if (char === quote && prev !== '\\') quote = undefined;
52
+ } else if (inRegex) {
53
+ if (char === '/' && prev !== '\\') inRegex = false;
54
+ } else if (char === '"' || char === "'" || char === '`') {
55
+ quote = char;
56
+ } else if (char === '/' && source[index + 1] === '/') {
57
+ index = source.indexOf('\n', index);
58
+ if (index === -1) return undefined;
59
+ } else if (char === '/' && source[index + 1] === '*') {
60
+ const close = source.indexOf('*/', index + 2);
61
+ if (close === -1) return undefined;
62
+ index = close + 1;
63
+ } else if (char === '/' && depth > 0) {
64
+ // Inside the argument list a `/` can only start a regex literal (the
65
+ // division case would need a preceding operand, which no argument
66
+ // position of `require.context` produces).
67
+ inRegex = true;
68
+ } else if (char === '(' || char === '[' || char === '{') {
69
+ depth++;
70
+ } else if (char === ')' || char === ']' || char === '}') {
71
+ depth--;
72
+ if (depth === 0) {
73
+ args.push(source.slice(start, index));
74
+ const trimmed = args.map(arg => arg.trim());
75
+ return { args: trimmed.length === 1 && trimmed[0] === '' ? [] : trimmed, end: index };
76
+ }
77
+ } else if (char === ',' && depth === 1) {
78
+ args.push(source.slice(start, index));
79
+ start = index + 1;
80
+ }
81
+ index++;
82
+ }
83
+ return undefined;
84
+ }
85
+
86
+ /** Parse a `/pattern/flags` literal; returns `undefined` for anything else. */
87
+ function parseRegExpLiteral(text: string): RegExp | undefined {
88
+ const match = /^\/((?:\\.|\[(?:\\.|[^\]])*\]|[^/])+)\/([a-z]*)$/.exec(text);
89
+ if (!match) return undefined;
90
+ try {
91
+ return new RegExp(match[1]!, match[2]!.replace(/[gy]/g, ''));
92
+ } catch {
93
+ return undefined;
94
+ }
95
+ }
96
+
97
+ /** Parse a plain string literal argument; returns `undefined` for anything else. */
98
+ function parseStringLiteral(text: string): string | undefined {
99
+ const match = /^(['"`])((?:\\.|[^\\])*)\1$/.exec(text);
100
+ if (!match) return undefined;
101
+ try {
102
+ return JSON.parse(`"${match[2]!.replace(/"/g, '\\"').replace(/\\'/g, "'")}"`) as string;
103
+ } catch {
104
+ return match[2];
105
+ }
106
+ }
107
+
108
+ function walkFiles(dir: string, recursive: boolean, prefix = ''): string[] {
109
+ let names: string[];
110
+ try {
111
+ names = readdirSync(dir).sort();
112
+ } catch {
113
+ return [];
114
+ }
115
+ const files: string[] = [];
116
+ for (const name of names) {
117
+ if (name.startsWith('.') || name === 'node_modules') continue;
118
+ const full = path.join(dir, name);
119
+ let isDirectory = false;
120
+ try {
121
+ isDirectory = statSync(full).isDirectory();
122
+ } catch {
123
+ continue;
124
+ }
125
+ if (isDirectory) {
126
+ if (recursive) files.push(...walkFiles(full, recursive, `${prefix}${name}/`));
127
+ } else {
128
+ files.push(`${prefix}${name}`);
129
+ }
130
+ }
131
+ return files;
132
+ }
133
+
134
+ /**
135
+ * The request keys a context over `dir` exposes, webpack-style: `'./'`-prefixed
136
+ * POSIX paths relative to `dir`, filtered by `regExp` (tested against the key),
137
+ * sorted lexicographically. With no `regExp` webpack's default (`/^\.\/.*$/`)
138
+ * accepts everything AND the extension-less form of each resolvable file also
139
+ * becomes a key, since `require('./parent/file1')` resolves there too.
140
+ */
141
+ export function requireContextEntries(dir: string, recursive: boolean, regExp?: RegExp): ContextEntry[] {
142
+ const entries: ContextEntry[] = [];
143
+ const seen = new Set<string>();
144
+ for (const relative of walkFiles(dir, recursive)) {
145
+ const file = path.join(dir, ...relative.split('/'));
146
+ const keys = [`./${relative}`];
147
+ if (!regExp && RESOLVABLE_EXTENSIONS.includes(path.extname(relative))) {
148
+ keys.push(`./${relative.slice(0, -path.extname(relative).length)}`);
149
+ }
150
+ for (const key of keys) {
151
+ if (regExp && !regExp.test(key)) continue;
152
+ if (seen.has(key)) continue;
153
+ seen.add(key);
154
+ entries.push({ key, file });
155
+ }
156
+ }
157
+ return entries.sort((a, b) => (a.key < b.key ? -1 : a.key > b.key ? 1 : 0));
158
+ }
159
+
160
+ // Runtime helper injected alongside the expanded contexts. `ctx(key)` mirrors
161
+ // webpack's "returns module.exports": for a CommonJS target esbuild/Bun expose
162
+ // the exports object as the namespace's `default`, so unwrap that case; a real
163
+ // ESM module keeps its namespace.
164
+ const CONTEXT_RUNTIME = `function __pnext_require_context(entries, id) {
165
+ const map = new Map(entries.map(entry => [entry[0], entry]));
166
+ const missing = key => {
167
+ const error = new Error("Cannot find module '" + key + "'");
168
+ error.code = 'MODULE_NOT_FOUND';
169
+ return error;
170
+ };
171
+ const context = key => {
172
+ const entry = map.get(key);
173
+ if (!entry) throw missing(key);
174
+ const mod = entry[2];
175
+ if (mod && typeof mod === 'object' && 'default' in mod) {
176
+ const extra = Object.keys(mod).filter(name => name !== 'default' && name !== '__esModule');
177
+ if (extra.length === 0 && mod.__esModule !== true) return mod.default;
178
+ }
179
+ return mod;
180
+ };
181
+ context.keys = () => entries.map(entry => entry[0]);
182
+ context.resolve = key => {
183
+ const entry = map.get(key);
184
+ if (!entry) throw missing(key);
185
+ return entry[1];
186
+ };
187
+ context.id = id;
188
+ return context;
189
+ }`;
190
+
191
+ /**
192
+ * Resolve the context directory argument against the importing file. Server
193
+ * builds can compile materialized copies of the app tree (see
194
+ * `originalResourcePath` in webpack-loaders.ts); when the directory does not
195
+ * exist next to the copy, rebase the importer onto `workspaceRoot` and retry so
196
+ * sibling directories of the ORIGINAL source are found.
197
+ */
198
+ function resolveContextDir(
199
+ specifier: string,
200
+ file: string,
201
+ paths: { outPath?: string; workspaceRoot?: string } | undefined,
202
+ ): string {
203
+ const direct = path.resolve(path.dirname(file), specifier);
204
+ if (existsSync(direct)) return direct;
205
+ if (paths?.outPath && paths.workspaceRoot) {
206
+ const cacheRoot = path.join(paths.outPath, 'cache', 'server');
207
+ const relative = path.relative(cacheRoot, file);
208
+ if (relative && !relative.startsWith('..') && !path.isAbsolute(relative)) {
209
+ const segments = relative.split(path.sep);
210
+ segments.shift(); // drop <profileDir>
211
+ const original = path.resolve(
212
+ path.dirname(path.join(paths.workspaceRoot, ...segments)),
213
+ specifier,
214
+ );
215
+ if (existsSync(original)) return original;
216
+ }
217
+ }
218
+ return direct;
219
+ }
220
+
221
+ /**
222
+ * Expand every `require.context(dir, recursive?, regExp?)` in `source` into a
223
+ * static context module. Calls whose arguments are not statically analyzable
224
+ * (a non-literal directory) are left untouched. Returns the source unchanged
225
+ * when there is nothing to rewrite.
226
+ */
227
+ export function rewriteRequireContextSource(
228
+ source: string,
229
+ file: string,
230
+ paths?: { outPath?: string; workspaceRoot?: string },
231
+ ): string {
232
+ if (!sourceHasRequireContext(source)) return source;
233
+ const imports: string[] = [];
234
+ const contexts: string[] = [];
235
+ let output = '';
236
+ let cursor = 0;
237
+ CONTEXT_CALL.lastIndex = 0;
238
+ let match: RegExpExecArray | null;
239
+ while ((match = CONTEXT_CALL.exec(source))) {
240
+ const openIndex = match.index + match[0].length - 1;
241
+ const parsed = splitCallArguments(source, openIndex);
242
+ if (!parsed) continue;
243
+ const [dirArg, recursiveArg, regExpArg] = parsed.args;
244
+ const specifier = dirArg === undefined ? undefined : parseStringLiteral(dirArg);
245
+ if (specifier === undefined) continue;
246
+ const recursive = recursiveArg === undefined ? true : recursiveArg.trim() !== 'false';
247
+ const regExp = regExpArg === undefined ? undefined : parseRegExpLiteral(regExpArg.trim());
248
+ if (regExpArg !== undefined && !regExp) continue;
249
+
250
+ const dir = resolveContextDir(specifier, file, paths);
251
+ const entries = requireContextEntries(dir, recursive, regExp);
252
+ const id = contexts.length;
253
+ const binding = `__pnext_context_${id}`;
254
+ const rows = entries.map((entry, index) => {
255
+ const namespace = `${binding}_${index}`;
256
+ imports.push(`import * as ${namespace} from ${JSON.stringify(entry.file)};`);
257
+ return `[${JSON.stringify(entry.key)}, ${JSON.stringify(entry.file)}, ${namespace}]`;
258
+ });
259
+ const contextId = `${specifier} ${recursive ? 'recursive ' : ''}${regExp ? regExp.source : '^\\.\\/.*$'}`;
260
+ contexts.push(
261
+ `const ${binding} = __pnext_require_context([${rows.join(', ')}], ${JSON.stringify(contextId)});`,
262
+ );
263
+ output += source.slice(cursor, match.index) + binding;
264
+ cursor = parsed.end + 1;
265
+ CONTEXT_CALL.lastIndex = cursor;
266
+ }
267
+ if (contexts.length === 0) return source;
268
+ output += source.slice(cursor);
269
+ const injection = [...imports, CONTEXT_RUNTIME, ...contexts].join('\n');
270
+ return injectAfterDirectives(output, injection);
271
+ }
272
+
273
+ // Injected declarations go after any leading directive prologue ('use client' /
274
+ // 'use server') and optional shebang so the directive stays the first statement.
275
+ function injectAfterDirectives(source: string, injection: string): string {
276
+ const prologue = /^(\uFEFF?(?:#![^\n]*\n)?(?:[ \t]*(['"])use [\w-]+\2[ \t]*;?[ \t]*(?:\r?\n|$))*)/.exec(
277
+ source,
278
+ );
279
+ const index = prologue ? prologue[0].length : 0;
280
+ return `${source.slice(0, index)}${injection}\n${source.slice(index)}`;
281
+ }
@@ -0,0 +1,75 @@
1
+ // next.config `resolveExtensions` for the CLIENT esbuild graph (COMPAT).
2
+ //
3
+ // The server resolver already honors the configured extension probe order. The client graph is bundled
4
+ // by esbuild, whose native `resolveExtensions` option cannot express two things the Next option allows:
5
+ // an `''` entry ("try the bare name with no extension"), and asset extensions like `.png` whose
6
+ // resolution must still flow through the static-asset onResolve plugin, keyed on the extensioned
7
+ // specifier. So instead of setting the esbuild option, this plugin probes relative specifiers in the
8
+ // configured order and re-dispatches the extensioned specifier through build.resolve(), so every
9
+ // downstream plugin sees the same path it would for an explicit extension. Only registered when the app
10
+ // configures resolveExtensions.
11
+
12
+ import { existsSync, statSync } from 'node:fs';
13
+ import path from 'node:path';
14
+ import type { Plugin } from 'esbuild';
15
+
16
+ const resolvedMarker = Symbol('pnext-resolve-extensions');
17
+
18
+ function isFile(file: string): boolean {
19
+ try {
20
+ return statSync(file).isFile();
21
+ } catch {
22
+ return false;
23
+ }
24
+ }
25
+
26
+ /**
27
+ * Client esbuild plugin applying the configured `resolveExtensions` probe
28
+ * order to relative imports (user extension order replaces esbuild's default,
29
+ * matching the server resolver's semantics: first hit wins, `''` = bare name).
30
+ */
31
+ export function clientResolveExtensionsPlugin(extensions: readonly string[]): Plugin {
32
+ return {
33
+ name: 'pnext-resolve-extensions',
34
+ setup(build) {
35
+ build.onResolve({ filter: /^\.\.?\// }, async args => {
36
+ if ((args.pluginData as Record<PropertyKey, unknown> | undefined)?.[resolvedMarker]) {
37
+ return undefined;
38
+ }
39
+ if (!args.resolveDir) return undefined;
40
+ const base = path.resolve(args.resolveDir, args.path);
41
+ // An import that already names an existing file resolves as-is.
42
+ if (isFile(base)) return undefined;
43
+ for (const extension of extensions) {
44
+ const candidate = `${base}${extension}`;
45
+ if (!isFile(candidate)) continue;
46
+ // Re-dispatch with the extension made explicit so downstream
47
+ // onResolve plugins (static assets, css) match on it.
48
+ return build.resolve(`${args.path}${extension}`, {
49
+ kind: args.kind,
50
+ importer: args.importer,
51
+ namespace: args.namespace,
52
+ resolveDir: args.resolveDir,
53
+ pluginData: { ...(args.pluginData as object | undefined), [resolvedMarker]: true },
54
+ });
55
+ }
56
+ // Directory (index probe) or genuinely missing: preserve the probe
57
+ // order for index files too, then fall back to esbuild's resolution.
58
+ if (existsSync(base)) {
59
+ for (const extension of extensions) {
60
+ if (extension === '') continue;
61
+ if (!isFile(path.join(base, `index${extension}`))) continue;
62
+ return build.resolve(`${args.path.replace(/\/$/, '')}/index${extension}`, {
63
+ kind: args.kind,
64
+ importer: args.importer,
65
+ namespace: args.namespace,
66
+ resolveDir: args.resolveDir,
67
+ pluginData: { ...(args.pluginData as object | undefined), [resolvedMarker]: true },
68
+ });
69
+ }
70
+ }
71
+ return undefined;
72
+ });
73
+ },
74
+ };
75
+ }
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Per-file memo for the bundler plugins' load/resolve callbacks. Those callbacks are the plugin
3
+ * chain's whole JS cost - they run once per FILE per BUILD, and the vendor pipeline runs hundreds
4
+ * of builds over an overlapping set of node_modules files.
5
+ *
6
+ * Staleness follows the rule the rest of the runtime uses: a file under `node_modules` is immutable
7
+ * for the life of the process (the same assumption the vendor artifact cache makes), and anything
8
+ * else is keyed on mtime + size so an edit is never served from the memo.
9
+ */
10
+ import { statSync } from 'node:fs';
11
+ import path from 'node:path';
12
+
13
+ const NODE_MODULES = `${path.sep}node_modules${path.sep}`;
14
+
15
+ interface Entry<T> {
16
+ stamp: string;
17
+ value: T;
18
+ }
19
+
20
+ /** mtime+size stamp, or '' for a file whose contents cannot change here. */
21
+ function stamp(file: string) {
22
+ if (file.includes(NODE_MODULES)) return '';
23
+ try {
24
+ const info = statSync(file);
25
+ return `${info.mtimeMs}\0${info.size}`;
26
+ } catch {
27
+ // A missing file is a real answer for the callers here (they all catch), so
28
+ // it is cached like any other — under a stamp no live file can produce.
29
+ return 'missing';
30
+ }
31
+ }
32
+
33
+ /** A memo whose entries are recomputed when their file changes on disk. */
34
+ export function fileMemo<T>(compute: (file: string) => T) {
35
+ const entries = new Map<string, Entry<T>>();
36
+ return (file: string): T => {
37
+ const current = stamp(file);
38
+ const cached = entries.get(file);
39
+ if (cached?.stamp === current) return cached.value;
40
+ const value = compute(file);
41
+ entries.set(file, { stamp: current, value });
42
+ return value;
43
+ };
44
+ }
45
+
46
+ /**
47
+ * The same memo for a callback that reads off the event loop. A bundler plugin callback runs on the
48
+ * SINGLE JS thread the whole pipeline shares, so a synchronous read there is time no other build can
49
+ * use - awaiting one lets the other builds' callbacks interleave with it.
50
+ */
51
+ export function fileMemoAsync<T>(compute: (file: string) => Promise<T>) {
52
+ const entries = new Map<string, Entry<Promise<T>>>();
53
+ return (file: string): Promise<T> => {
54
+ const current = stamp(file);
55
+ const cached = entries.get(file);
56
+ if (cached?.stamp === current) return cached.value;
57
+ const value = compute(file);
58
+ entries.set(file, { stamp: current, value });
59
+ return value;
60
+ };
61
+ }
@@ -0,0 +1,25 @@
1
+ import { pathToFileHref } from '../../config';
2
+ import { rewriteSpecifierLiterals } from '../../resolve/scan-facts';
3
+
4
+ /**
5
+ * Resolve registered compat aliases before Bun reaches installed package entries. Folded onto the
6
+ * memoized module record: only real import/export/dynamic-import/require specifiers are considered, so
7
+ * an alias key quoted inside a string or a comment - which the old specifier regex rewrote - is never
8
+ * touched.
9
+ */
10
+ export function rewriteStaticCompatImports(
11
+ source: string,
12
+ file: string,
13
+ aliases: Readonly<Record<string, string>>,
14
+ requireAliases: Readonly<Record<string, string>> = {},
15
+ ): string {
16
+ return rewriteSpecifierLiterals(source, file, (specifier, kind) => {
17
+ // A side-effect `import 'x'` keeps resolving through the host resolver, as
18
+ // it did under the `from`-anchored regex this replaced.
19
+ const target = kind === 'side-effect' ? undefined : aliases[specifier];
20
+ if (!target) return undefined;
21
+ const resolved =
22
+ kind === 'require' ? (requireAliases[specifier] ?? target) : pathToFileHref(target);
23
+ return JSON.stringify(resolved);
24
+ });
25
+ }
@@ -0,0 +1,119 @@
1
+ import { readdirSync, realpathSync } from 'node:fs';
2
+ import { realpath } from 'node:fs/promises';
3
+ import path from 'node:path';
4
+ import type { Plugin } from 'esbuild';
5
+ import type { ResolvedConfig } from '../../config';
6
+ import { resolveImport } from '../../resolve/imports';
7
+
8
+ const resolvedMarker = Symbol('pnext-symlink-import');
9
+
10
+ /**
11
+ * Whether a file IS its own real path - asked once per relative import, so the same importers are
12
+ * re-resolved component-by-component across every build. Keyed on the path alone: a path's symlink
13
+ * identity changes only on an install, which already invalidates every resolved artifact key.
14
+ */
15
+ const realPaths = new Map<string, Promise<boolean>>();
16
+
17
+ function isRealPath(file: string) {
18
+ let real = realPaths.get(file);
19
+ if (!real) {
20
+ real = realpath(file).then(
21
+ resolved => resolved === file,
22
+ () => true,
23
+ );
24
+ realPaths.set(file, real);
25
+ }
26
+ return real;
27
+ }
28
+
29
+ /**
30
+ * What the layout scan concluded:
31
+ * 'none' no symlink anywhere the resolver could meet one
32
+ * 'package-links' only whole-package node_modules links (workspace or link installs) - esbuild follows
33
+ * these during node_modules resolution, so importers come out as realpaths
34
+ * 'other' pnpm trees, symlinked roots, stray source symlinks, or a failed scan
35
+ */
36
+ type SymlinkLayout = 'none' | 'package-links' | 'other';
37
+
38
+ const symlinkLayouts = new Map<string, SymlinkLayout>();
39
+
40
+ /**
41
+ * Whether this build can see a SYMLINKED importer, so the plugin's onResolve is registered only where it
42
+ * can matter. `realPathEntries` builds hand esbuild realpath-resolved entries, and esbuild's own
43
+ * resolution follows symlinks - there, workspace links alone cannot produce a symlinked importer. Any
44
+ * detection error registers the plugin: a missed hook silently changes resolution.
45
+ */
46
+ export function symlinkedImportsPossible(
47
+ config: ResolvedConfig,
48
+ realPathEntries?: boolean,
49
+ ): boolean {
50
+ const key = `${config.root}\0${config.workspaceRoot}`;
51
+ let layout = symlinkLayouts.get(key);
52
+ if (layout === undefined) {
53
+ layout = detectSymlinkLayout(config);
54
+ symlinkLayouts.set(key, layout);
55
+ }
56
+ if (layout === 'none') return false;
57
+ if (layout === 'package-links') return !realPathEntries;
58
+ return true;
59
+ }
60
+
61
+ function detectSymlinkLayout(config: ResolvedConfig): SymlinkLayout {
62
+ try {
63
+ const roots = [...new Set([config.root, config.workspaceRoot])].map(root =>
64
+ path.resolve(root),
65
+ );
66
+ let packageLinks = false;
67
+ for (const root of roots) {
68
+ if (realpathSync(root) !== root) return 'other';
69
+ if (readDirEntries(root).some(entry => entry.isSymbolicLink())) return 'other';
70
+ const nodeModules = path.join(root, 'node_modules');
71
+ for (const entry of readDirEntries(nodeModules)) {
72
+ if (entry.name === '.pnpm') return 'other';
73
+ if (entry.isSymbolicLink()) packageLinks = true;
74
+ else if (entry.isDirectory() && entry.name.startsWith('@')) {
75
+ const scopeDir = path.join(nodeModules, entry.name);
76
+ if (readDirEntries(scopeDir).some(scoped => scoped.isSymbolicLink()))
77
+ packageLinks = true;
78
+ }
79
+ }
80
+ }
81
+ return packageLinks ? 'package-links' : 'none';
82
+ } catch {
83
+ return 'other';
84
+ }
85
+ }
86
+
87
+ /** Missing dir = no symlinks there; any other failure propagates as "uncertain". */
88
+ function readDirEntries(dir: string) {
89
+ try {
90
+ return readdirSync(dir, { withFileTypes: true });
91
+ } catch (error) {
92
+ if ((error as NodeJS.ErrnoException).code === 'ENOENT') return [];
93
+ throw error;
94
+ }
95
+ }
96
+
97
+ /** Resolve relative imports from the real target of a symlinked source file. */
98
+ export function serverSymlinkImportPlugin(config: ResolvedConfig): Plugin {
99
+ return {
100
+ name: 'pnext-symlink-imports',
101
+ setup(build) {
102
+ build.onResolve({ filter: /^\.\.?\// }, async args => {
103
+ if (!args.importer || (args.pluginData as Record<PropertyKey, unknown> | undefined)?.[resolvedMarker]) {
104
+ return undefined;
105
+ }
106
+ if (await isRealPath(args.importer)) return undefined;
107
+ const target = resolveImport(config.root, args.importer, args.path);
108
+ if (!target) return undefined;
109
+ return build.resolve(target, {
110
+ kind: args.kind,
111
+ importer: args.importer,
112
+ namespace: args.namespace,
113
+ resolveDir: args.resolveDir,
114
+ pluginData: { ...(args.pluginData as object | undefined), [resolvedMarker]: true },
115
+ });
116
+ });
117
+ },
118
+ };
119
+ }
@@ -0,0 +1,50 @@
1
+ // ---------------------------------------------------------------------------
2
+ // tsconfig `paths` resolution for esbuild graphs (COMPAT).
3
+ //
4
+ // esbuild natively discovers a `tsconfig.json` next to the resolveDir and
5
+ // applies its `paths`/`baseUrl`. Next's `typescript.tsconfigPath` lets an app
6
+ // keep its compiler config (including `paths`) in a DIFFERENTLY-named file
7
+ // (e.g. `myconfig.json`); esbuild never discovers that file, so bare aliases
8
+ // declared there ("foo" -> "./bar.ts") are unresolved in esbuild bundles.
9
+ //
10
+ // Core's source resolver honors the configured tsconfig, but direct esbuild
11
+ // graphs do not consult it. This plugin resolves matching bare specifiers
12
+ // through the same configured-tsconfig resolver.
13
+ //
14
+ // The filter is the DECLARED `paths` patterns, read once from every tsconfig
15
+ // that can drive a resolution here (the app root, the workspace root and its
16
+ // members). Aliases are the only thing this plugin can ever claim, so a
17
+ // catch-all bare filter just paid a JS round-trip per import to say "not mine"
18
+ // (611 fires on a 401-route app that declares no `paths` at all). No patterns
19
+ // anywhere -> no plugin.
20
+ // ---------------------------------------------------------------------------
21
+
22
+ import path from 'node:path';
23
+ import type { Plugin } from 'esbuild';
24
+ import type { ResolvedConfig } from '../../config';
25
+ import { configuredTsPathPatterns, resolveConfiguredTsPath } from '../../resolve/imports';
26
+ import { escapeRegex } from '../../utils/source';
27
+
28
+ export function tsconfigPathsPlugin(config: ResolvedConfig): Plugin | undefined {
29
+ const patterns = configuredTsPathPatterns(config.root, config.workspaceRoot);
30
+ if (patterns.length === 0) return undefined;
31
+ // A TS `paths` key holds at most one `*`; everything else is literal.
32
+ const filter = new RegExp(
33
+ `^(?:${patterns
34
+ .map(pattern => pattern.split('*').map(escapeRegex).join('[^:]*'))
35
+ .join('|')})$`,
36
+ );
37
+ return {
38
+ name: 'pnext-tsconfig-paths',
39
+ setup(build) {
40
+ build.onResolve({ filter }, args => {
41
+ const resolved = resolveConfiguredTsPath(
42
+ config.root,
43
+ path.join(args.resolveDir || config.root, 'pnext-resolve.ts'),
44
+ args.path,
45
+ );
46
+ return resolved ? { path: resolved } : undefined;
47
+ });
48
+ },
49
+ };
50
+ }