@wular/pnext 0.0.4 → 0.0.6

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 (392) hide show
  1. package/README.md +11 -11
  2. package/bin/pnext +1 -1
  3. package/config/lint/base.js +7 -7
  4. package/config/ts/base.json +2 -4
  5. package/config/ts/react.json +2 -6
  6. package/package.json +23 -2
  7. package/reference/compat.md +1 -1
  8. package/reference/config.md +2 -2
  9. package/reference/css.md +13 -9
  10. package/reference/dev.md +1 -1
  11. package/reference/metadata.md +7 -7
  12. package/reference/navigation.md +35 -28
  13. package/reference/performance.md +70 -70
  14. package/reference/rendering.md +17 -17
  15. package/reference/routing.md +17 -17
  16. package/reference/typegen.md +12 -8
  17. package/src/api/cache.ts +36 -37
  18. package/src/api/client-cache.ts +2 -2
  19. package/src/api/client-navigation.ts +113 -109
  20. package/src/api/dynamic.tsx +58 -55
  21. package/src/api/link.tsx +49 -52
  22. package/src/api/navigation.ts +59 -58
  23. package/src/api/server.ts +152 -144
  24. package/src/api/suspense.ts +4 -4
  25. package/src/cli/adapters/vercel-warm.ts +126 -121
  26. package/src/cli/adapters/vercel.ts +437 -443
  27. package/src/cli/analyze.ts +333 -144
  28. package/src/cli/{named-bin.ts → boot/named-bin.ts} +37 -37
  29. package/src/cli/{boot-trace.ts → boot/trace.ts} +10 -10
  30. package/src/cli/build.ts +976 -978
  31. package/src/cli/create.ts +71 -63
  32. package/src/cli/dev.ts +116 -116
  33. package/src/cli/index.ts +88 -85
  34. package/src/cli/migrate/package-json.ts +73 -71
  35. package/src/cli/migrate/report.ts +32 -33
  36. package/src/cli/migrate/{index.ts → run.ts} +48 -49
  37. package/src/cli/migrate/scan.ts +46 -46
  38. package/src/cli/migrate/spinner.ts +9 -9
  39. package/src/cli/migrate/tsconfig.ts +35 -35
  40. package/src/cli/{server-entry.ts → serve/entry.ts} +57 -57
  41. package/src/cli/{request-pipeline.ts → serve/pipeline.ts} +386 -394
  42. package/src/cli/{serve-ui.ts → serve/ui.ts} +47 -47
  43. package/src/cli/start.ts +65 -66
  44. package/src/{typegen.ts → cli/typegen.ts} +59 -59
  45. package/src/client/build.ts +794 -768
  46. package/src/client/chunk-fold.ts +245 -240
  47. package/src/client/{paths.ts → chunk-name.ts} +6 -6
  48. package/src/client/entry.ts +162 -147
  49. package/src/client/prebuilt.ts +231 -223
  50. package/src/client/profile.ts +29 -29
  51. package/src/client/react-compiler.ts +20 -15
  52. package/src/client/{compat-surface.ts → react-tier.ts} +64 -64
  53. package/src/client/reference-stub.ts +51 -51
  54. package/src/client/reference.ts +19 -19
  55. package/src/{api → client}/router/events.ts +17 -17
  56. package/src/{api → client}/router/history.ts +16 -16
  57. package/src/{api → client}/router/hub.ts +52 -53
  58. package/src/{api/router.ts → client/router/index.ts} +61 -60
  59. package/src/{api → client}/router/policies.ts +24 -24
  60. package/src/{api → client}/router/runtime.ts +1988 -1992
  61. package/src/{api → client}/router/types.ts +93 -98
  62. package/src/compat/actions/client-plugin.ts +42 -43
  63. package/src/compat/actions/client-stub.ts +14 -14
  64. package/src/compat/actions/{action-client.ts → client.ts} +194 -193
  65. package/src/compat/actions/config.ts +63 -64
  66. package/src/compat/actions/detect.ts +68 -68
  67. package/src/compat/actions/discovery.ts +105 -105
  68. package/src/compat/actions/{action-dispatch.ts → dispatch.ts} +277 -274
  69. package/src/compat/actions/early-submit.ts +1 -1
  70. package/src/compat/actions/endpoint.ts +198 -198
  71. package/src/compat/actions/extensions.ts +811 -0
  72. package/src/compat/actions/flight.ts +23 -23
  73. package/src/compat/actions/form-state.ts +34 -34
  74. package/src/compat/actions/hoist.ts +382 -236
  75. package/src/compat/actions/ids.ts +7 -12
  76. package/src/compat/actions/index.ts +8 -8
  77. package/src/compat/actions/instances.ts +46 -46
  78. package/src/compat/actions/origin.ts +47 -48
  79. package/src/compat/actions/protocol.ts +22 -22
  80. package/src/compat/actions/registry.ts +19 -19
  81. package/src/compat/{misc/action-return.ts → actions/return.ts} +60 -57
  82. package/src/compat/actions/rewrite.ts +125 -125
  83. package/src/compat/actions/{action-router.ts → router.ts} +10 -10
  84. package/src/compat/actions/serve.ts +132 -136
  85. package/src/compat/actions/server-tag.ts +4 -4
  86. package/src/compat/actions/{action-shared.ts → shared.ts} +34 -34
  87. package/src/compat/actions/unrecognized-error.ts +4 -4
  88. package/src/compat/{index.ts → aliases.ts} +112 -109
  89. package/src/compat/bundler/bun-externals.ts +18 -18
  90. package/src/compat/bundler/cjs-exports.ts +271 -223
  91. package/src/compat/bundler/config.ts +116 -111
  92. package/src/compat/bundler/externals.ts +12 -12
  93. package/src/compat/bundler/import-meta-url.ts +19 -19
  94. package/src/compat/bundler/modularize-imports.ts +36 -33
  95. package/src/compat/bundler/new-url-asset.ts +22 -24
  96. package/src/compat/bundler/optimize-package-imports.ts +111 -107
  97. package/src/compat/bundler/polyfill.ts +28 -28
  98. package/src/compat/bundler/react-compiler.ts +35 -29
  99. package/src/compat/bundler/react-profiler.tsx +11 -11
  100. package/src/compat/bundler/relay-transform.ts +48 -47
  101. package/src/compat/bundler/require-context.ts +119 -113
  102. package/src/compat/bundler/resolve-extensions.ts +19 -19
  103. package/src/compat/bundler/source-cache.ts +25 -25
  104. package/src/compat/bundler/static-imports.ts +7 -7
  105. package/src/compat/bundler/symlink-imports.ts +46 -46
  106. package/src/compat/bundler/tsconfig-paths.ts +13 -15
  107. package/src/compat/bundler/wasm.ts +58 -60
  108. package/src/compat/bundler/webpack-loaders.ts +254 -241
  109. package/src/compat/bundler/worker.ts +101 -104
  110. package/src/compat/cache/build-flags.ts +29 -29
  111. package/src/compat/cache/build-prerender-errors.ts +40 -44
  112. package/src/compat/cache/custom-handler.ts +60 -53
  113. package/src/compat/cache/fetch-patch.ts +240 -240
  114. package/src/compat/cache/handler.ts +27 -31
  115. package/src/compat/cache/modern-handler.ts +148 -126
  116. package/src/compat/cache/resume-data-cache.ts +47 -45
  117. package/src/compat/cache/revalidate.ts +233 -232
  118. package/src/compat/cache/runtime-error.ts +35 -35
  119. package/src/compat/cache/use-cache-transform.ts +442 -417
  120. package/src/compat/cache/use-cache.ts +650 -614
  121. package/src/compat/cache-control.ts +140 -142
  122. package/src/compat/client/base-path.ts +21 -20
  123. package/src/compat/client/css-order.ts +18 -18
  124. package/src/compat/client/errors/bare-boundary.ts +11 -11
  125. package/src/compat/client/errors/control-flow.ts +23 -23
  126. package/src/compat/client/errors/error-boundary.ts +61 -61
  127. package/src/compat/client/errors/global-error.ts +101 -91
  128. package/src/compat/client/errors/install.ts +71 -72
  129. package/src/compat/client/errors/lazy.ts +23 -23
  130. package/src/compat/client/errors/primitive-throw.ts +47 -45
  131. package/src/compat/client/errors/soft-refresh.ts +4 -4
  132. package/src/compat/client/link-status.ts +33 -33
  133. package/src/compat/client/{nav-compat-runtime.ts → nav-runtime.ts} +20 -20
  134. package/src/compat/client/{nav-compat.ts → nav.ts} +12 -13
  135. package/src/compat/client/navigation-scroll.ts +63 -63
  136. package/src/compat/client/optimistic-routing.ts +93 -88
  137. package/src/compat/client/prefetch-cache.ts +23 -24
  138. package/src/compat/client/route-announcer.ts +35 -35
  139. package/src/compat/client/segment-cache-policy.ts +20 -20
  140. package/src/compat/client/segment-cache.ts +309 -315
  141. package/src/compat/client/segment-prefetch.ts +127 -132
  142. package/src/compat/client/trailing-slash.ts +5 -4
  143. package/src/compat/css/chunking.ts +113 -116
  144. package/src/compat/css/inline-css.ts +21 -21
  145. package/src/compat/css/lightningcss.ts +37 -38
  146. package/src/compat/css/modules.ts +161 -175
  147. package/src/compat/css/nonce.ts +7 -7
  148. package/src/compat/css/sass-plugin.ts +18 -21
  149. package/src/compat/css/sass.ts +150 -152
  150. package/src/compat/css/styled-jsx-runtime.ts +27 -27
  151. package/src/compat/css/styled-jsx.ts +21 -21
  152. package/src/compat/edge-runtime.ts +27 -27
  153. package/src/compat/{adapter → export}/build-complete.ts +72 -75
  154. package/src/compat/export/client.ts +29 -31
  155. package/src/compat/export/{index.ts → emit.ts} +111 -110
  156. package/src/compat/export/standalone.ts +62 -54
  157. package/src/compat/image-optimizer/cache.ts +51 -49
  158. package/src/compat/image-optimizer/detect.ts +52 -52
  159. package/src/compat/image-optimizer/{index.ts → optimize.ts} +189 -194
  160. package/src/compat/image-optimizer/source.ts +77 -80
  161. package/src/compat/lifecycle/after-scope.ts +26 -26
  162. package/src/compat/lifecycle/after.ts +48 -45
  163. package/src/compat/lifecycle/error-funnel.ts +98 -102
  164. package/src/compat/lifecycle/error-serialize.ts +30 -26
  165. package/src/compat/lifecycle/error-ui.ts +67 -32
  166. package/src/compat/lifecycle/instrumentation-client.ts +36 -38
  167. package/src/compat/lifecycle/instrumentation.ts +85 -85
  168. package/src/compat/lifecycle/node-console.ts +11 -11
  169. package/src/compat/lifecycle/testmode.ts +160 -132
  170. package/src/compat/mdx/compile.ts +60 -57
  171. package/src/compat/mdx/plugin.ts +11 -11
  172. package/src/compat/mdx/{next-mdx-stub.ts → stub.ts} +5 -5
  173. package/src/compat/{metadata-route-artifacts.ts → metadata-artifacts.ts} +195 -191
  174. package/src/compat/metadata.ts +75 -81
  175. package/src/compat/next/cache.ts +68 -69
  176. package/src/compat/next/canonical-url.ts +9 -9
  177. package/src/compat/next/client-cache.ts +19 -19
  178. package/src/compat/next/client-navigation.ts +112 -116
  179. package/src/compat/next/client-only.ts +1 -1
  180. package/src/compat/next/client-script.tsx +99 -93
  181. package/src/compat/next/client-server.ts +10 -10
  182. package/src/compat/next/config-loader.ts +176 -173
  183. package/src/compat/next/config.ts +7 -7
  184. package/src/compat/next/constants.cjs +6 -6
  185. package/src/compat/next/constants.ts +6 -6
  186. package/src/compat/next/custom-server.ts +26 -24
  187. package/src/compat/next/dist/client/components/app-router-headers.ts +21 -21
  188. package/src/compat/next/dist/server/app-render/work-unit-async-storage.external.cjs +3 -4
  189. package/src/compat/next/dist/server/web/spec-extension/revalidate.ts +1 -1
  190. package/src/compat/next/dist/server/web/spec-extension/unstable-cache.ts +1 -1
  191. package/src/compat/next/dist/server/web/spec-extension/unstable-no-store.ts +1 -1
  192. package/src/compat/next/dynamic.tsx +21 -18
  193. package/src/compat/next/error.tsx +52 -52
  194. package/src/compat/next/font/cache.ts +74 -74
  195. package/src/compat/next/font/google.ts +2 -2
  196. package/src/compat/next/font/index.ts +1 -1
  197. package/src/compat/next/font/local.ts +3 -3
  198. package/src/compat/next/font/runtime-client.ts +17 -15
  199. package/src/compat/next/font/runtime.ts +443 -408
  200. package/src/compat/next/font/shared.ts +120 -108
  201. package/src/compat/next/form.tsx +63 -63
  202. package/src/compat/next/head.tsx +2 -2
  203. package/src/compat/next/headers.ts +103 -95
  204. package/src/compat/next/image/client.tsx +220 -0
  205. package/src/compat/next/image/config.ts +56 -58
  206. package/src/compat/next/image/optimizer.ts +40 -36
  207. package/src/compat/next/image/patterns.ts +37 -40
  208. package/src/compat/next/{image-props.ts → image/props.ts} +208 -202
  209. package/src/compat/next/image/shared.ts +65 -57
  210. package/src/compat/next/image/static-metadata.ts +98 -107
  211. package/src/compat/next/image/validate.ts +79 -88
  212. package/src/compat/next/image.tsx +19 -23
  213. package/src/compat/next/index.ts +1 -1
  214. package/src/compat/next/legacy-image.tsx +59 -60
  215. package/src/compat/next/{link-validation-transform.ts → link-transform.ts} +95 -96
  216. package/src/compat/next/link.tsx +158 -158
  217. package/src/compat/next/navigation.cjs +12 -3
  218. package/src/compat/next/navigation.ts +48 -50
  219. package/src/compat/next/offline.ts +27 -27
  220. package/src/compat/next/og.ts +121 -124
  221. package/src/compat/next/preferred-region.ts +13 -14
  222. package/src/compat/next/redirects.ts +58 -56
  223. package/src/compat/next/resource-hints.ts +73 -76
  224. package/src/compat/next/rewrites.ts +130 -133
  225. package/src/compat/next/root-params.ts +45 -45
  226. package/src/compat/next/{optimistic-route-state.ts → route-state.ts} +52 -52
  227. package/src/compat/next/router.cjs +4 -2
  228. package/src/compat/next/router.ts +58 -61
  229. package/src/compat/next/script.tsx +108 -108
  230. package/src/compat/next/server-only.ts +1 -1
  231. package/src/compat/next/server.ts +19 -19
  232. package/src/compat/next/svgr.ts +18 -17
  233. package/src/compat/next/telemetry.ts +24 -24
  234. package/src/compat/next/{image-usage.ts → usage.ts} +70 -39
  235. package/src/compat/next/user-agent.ts +53 -49
  236. package/src/compat/next/web-vitals.ts +22 -24
  237. package/src/compat/otel/api.ts +41 -41
  238. package/src/compat/otel/client-trace-metadata.ts +25 -27
  239. package/src/compat/otel/fetch-span.ts +29 -29
  240. package/src/compat/otel/tracer.ts +331 -331
  241. package/src/compat/pages/api.ts +456 -0
  242. package/src/compat/pages/client-plugin.ts +36 -36
  243. package/src/compat/pages/router-state.ts +34 -34
  244. package/src/compat/pages/{index.ts → router.ts} +130 -135
  245. package/src/compat/ppr/io.ts +12 -12
  246. package/src/compat/ppr/missing-root-params.ts +34 -38
  247. package/src/compat/ppr/root-params-scan.ts +66 -66
  248. package/src/compat/ppr/root-params-transform.ts +24 -26
  249. package/src/compat/ppr/root-params.ts +30 -30
  250. package/src/compat/ppr/segment-config-incompat.ts +6 -7
  251. package/src/compat/protocol.ts +71 -70
  252. package/src/compat/react/action-state.ts +47 -48
  253. package/src/compat/react/client-lite.ts +15 -15
  254. package/src/compat/react/client.ts +4 -4
  255. package/src/compat/react/compiler-runtime.ts +11 -11
  256. package/src/compat/react/dom-client.ts +44 -44
  257. package/src/compat/react/dom-react-server.ts +10 -16
  258. package/src/compat/react/dom-server.ts +10 -10
  259. package/src/compat/react/dom.ts +52 -52
  260. package/src/compat/react/hooks-extra.ts +34 -35
  261. package/src/compat/react/parity.ts +64 -61
  262. package/src/compat/react/preact.ts +81 -82
  263. package/src/compat/react/react-server.ts +28 -28
  264. package/src/compat/react/router-shim.ts +1 -1
  265. package/src/compat/react/server-component-use.ts +8 -8
  266. package/src/compat/react/server-inserted-html.ts +30 -31
  267. package/src/compat/react/server.ts +53 -55
  268. package/src/compat/react/use.ts +32 -32
  269. package/src/compat/react/view-transition.ts +20 -20
  270. package/src/compat/register/actions.ts +35 -824
  271. package/src/compat/register/boot.ts +41 -41
  272. package/src/compat/register/build-tier.ts +5 -5
  273. package/src/compat/register/build.ts +74 -70
  274. package/src/compat/register/bundler.ts +161 -156
  275. package/src/compat/register/cache.ts +20 -20
  276. package/src/compat/register/client-errors.ts +3 -3
  277. package/src/compat/register/config.ts +6 -6
  278. package/src/compat/register/css-extras.ts +30 -34
  279. package/src/compat/register/edge-runtime.ts +3 -3
  280. package/src/compat/register/errors.ts +10 -12
  281. package/src/compat/register/export.ts +16 -16
  282. package/src/compat/register/font.ts +11 -11
  283. package/src/compat/register/hooks.ts +2 -2
  284. package/src/compat/register/image.ts +40 -40
  285. package/src/compat/register/index.ts +59 -62
  286. package/src/compat/register/instrumentation-client.ts +10 -10
  287. package/src/compat/register/lifecycle.ts +25 -28
  288. package/src/compat/register/mdx.ts +10 -10
  289. package/src/compat/register/middleware.ts +226 -16
  290. package/src/compat/register/otel.ts +80 -88
  291. package/src/compat/register/pages-api.ts +10 -463
  292. package/src/compat/register/ppr.ts +16 -16
  293. package/src/compat/register/protocol.ts +17 -18
  294. package/src/compat/register/proxy.ts +49 -51
  295. package/src/compat/register/render.ts +79 -76
  296. package/src/compat/register/routing.ts +162 -159
  297. package/src/compat/register/segment.ts +24 -1897
  298. package/src/compat/register/static-image.ts +3 -3
  299. package/src/compat/register/{misc.ts → taint.ts} +9 -9
  300. package/src/compat/register/typed-routes.ts +14 -14
  301. package/src/compat/register/{usecache.ts → use-cache.ts} +39 -39
  302. package/src/compat/register/validation.ts +18 -18
  303. package/src/compat/segment/loading-boundary.ts +43 -45
  304. package/src/compat/segment/page-slot.ts +69 -69
  305. package/src/compat/segment/serve.ts +1884 -0
  306. package/src/compat/segment/tree.ts +113 -112
  307. package/src/compat/segment/vary-key.ts +38 -38
  308. package/src/compat/segment/vary-params.ts +138 -142
  309. package/src/compat/static-params.ts +14 -12
  310. package/src/compat/tsconfig-defaults.ts +87 -91
  311. package/src/compat/typecheck/{index.ts → check.ts} +234 -212
  312. package/src/compat/typecheck/worker.ts +15 -12
  313. package/src/compat/typed-routes/{index.ts → generate.ts} +36 -36
  314. package/src/compat/typed-routes/manifest.ts +174 -170
  315. package/src/compat/typed-routes/typegen.ts +127 -110
  316. package/src/compat/validation/errors.ts +16 -19
  317. package/src/compat/validation/prerender-diagnostics.ts +521 -504
  318. package/src/compat/validation/{index.ts → validate.ts} +647 -648
  319. package/src/compat-bootstrap.ts +16 -16
  320. package/src/config.ts +69 -69
  321. package/src/css/build.ts +230 -227
  322. package/src/css/postcss.ts +79 -80
  323. package/src/css/worker.ts +14 -15
  324. package/src/dev/client-actions.ts +10 -10
  325. package/src/dev/client-chunk-store.ts +27 -27
  326. package/src/dev/{client-key-cache.ts → restart/client-key.ts} +76 -76
  327. package/src/dev/{restart-cache.ts → restart/enabled.ts} +1 -1
  328. package/src/dev/{global-css-cache.ts → restart/global-css.ts} +91 -83
  329. package/src/dev/{node-module-bundle-cache.ts → restart/node-modules.ts} +24 -24
  330. package/src/dev/{route-bundle-key-cache.ts → restart/route-bundle-key.ts} +53 -53
  331. package/src/dev/{route-facts-cache.ts → restart/route-facts.ts} +82 -82
  332. package/src/dev/server.ts +804 -820
  333. package/src/env.ts +46 -43
  334. package/src/extensions.ts +491 -478
  335. package/src/index.ts +8 -8
  336. package/src/internal.ts +20 -23
  337. package/src/{islands → render}/boundary-error.ts +3 -3
  338. package/src/render/hooks.ts +71 -71
  339. package/src/render/island-context.ts +14 -14
  340. package/src/render/metadata.ts +310 -310
  341. package/src/{ppr-postpone.ts → render/postpone.ts} +5 -5
  342. package/src/{ppr.ts → render/ppr.ts} +244 -245
  343. package/src/render/renderer.ts +2076 -2082
  344. package/src/render/resource-hints.ts +16 -17
  345. package/src/render/slots.tsx +224 -235
  346. package/src/{islands → render}/static-children.ts +9 -12
  347. package/src/{islands → render}/static-slots.ts +37 -37
  348. package/src/{cache/context.ts → request/cache.ts} +20 -20
  349. package/src/request/context.ts +107 -107
  350. package/src/{dynamic/source.ts → resolve/dynamic.ts} +139 -139
  351. package/src/resolve/engine.ts +90 -77
  352. package/src/resolve/imports.ts +475 -463
  353. package/src/resolve/scan-facts.ts +318 -296
  354. package/src/resolve/source-text.ts +37 -37
  355. package/src/{dynamic → resolve}/tree-shake.ts +132 -128
  356. package/src/routing/forwarded.ts +19 -19
  357. package/src/routing/handler.ts +84 -91
  358. package/src/routing/href.ts +69 -70
  359. package/src/routing/{metadata.ts → metadata-files.ts} +403 -401
  360. package/src/{proxy.ts → routing/proxy.ts} +306 -312
  361. package/src/routing/{request-runtime.ts → request-environment.ts} +10 -10
  362. package/src/routing/routes.ts +827 -815
  363. package/src/routing/slots.ts +164 -160
  364. package/src/runtime/loader.ts +952 -0
  365. package/src/{dev → runtime}/module-cache.ts +309 -287
  366. package/src/{dev → runtime}/module-generations.ts +9 -9
  367. package/src/{dev → runtime}/module-transform.ts +81 -72
  368. package/src/{dev/imports.ts → runtime/modules.ts} +934 -847
  369. package/src/runtime/{server.ts → vendor-build.ts} +848 -1696
  370. package/src/runtime/vendor.ts +425 -404
  371. package/src/styles.d.ts +9 -0
  372. package/src/types.ts +320 -335
  373. package/src/utils/ansi.ts +5 -5
  374. package/src/utils/{source.ts → code.ts} +15 -12
  375. package/src/utils/content-type.ts +3 -3
  376. package/src/utils/decode.ts +2 -2
  377. package/src/utils/dev-profile.ts +13 -13
  378. package/src/utils/error-log.ts +6 -6
  379. package/src/utils/esbuild.ts +18 -18
  380. package/src/utils/fs-cache.ts +13 -13
  381. package/src/utils/fs.ts +57 -49
  382. package/src/utils/html.ts +20 -24
  383. package/src/utils/native-require.ts +8 -8
  384. package/src/utils/serialize.ts +139 -146
  385. package/src/utils/verbose.ts +18 -18
  386. package/src/cli/analyze-print.ts +0 -181
  387. package/src/compat/middleware/manifest.ts +0 -210
  388. package/src/compat/next/image-client.tsx +0 -215
  389. package/src/compat/next/link-usage.ts +0 -29
  390. package/src/css/index.ts +0 -2
  391. package/src/render/index.ts +0 -1
  392. package/src/style-modules.d.ts +0 -9
package/src/cli/index.ts CHANGED
@@ -1,117 +1,120 @@
1
1
  #!/usr/bin/env bun
2
- import { existsSync, statSync } from 'node:fs';
3
- import path from 'node:path';
4
- import { markBoot } from './boot-trace';
5
- import { commandBinaryName, nameEsbuildProcess, namedBunBinary } from './named-bin';
2
+ import { existsSync, statSync } from 'node:fs'
3
+ import path from 'node:path'
4
+ import { markBoot } from './boot/trace'
5
+ import { commandBinaryName, nameEsbuildProcess, namedBunBinary } from './boot/named-bin'
6
6
 
7
- const [, , command, ...args] = process.argv;
8
- markBoot('cli:entry');
7
+ const [, , command, ...args] = process.argv
8
+ markBoot('cli:entry')
9
9
 
10
10
  // A no-op once we already run under the command's name; otherwise it creates
11
11
  // the hardlink so bin/pnext can exec it directly from the next run on.
12
- namedBunBinary(commandBinaryName(command));
12
+ namedBunBinary(commandBinaryName(command))
13
13
 
14
14
  // Before any command lazily imports esbuild, which captures the binary path on
15
15
  // module load.
16
- nameEsbuildProcess();
17
- markBoot('cli:naming');
16
+ nameEsbuildProcess()
17
+ markBoot('cli:naming')
18
18
 
19
19
  try {
20
20
  if (command === 'dev') {
21
- const { dev } = await import('./dev');
21
+ const { dev } = await import('./dev')
22
22
  await dev({
23
23
  root: positionalRoot(args),
24
24
  port: optionNumber(args, '--port'),
25
25
  hostname: optionString(args, '--hostname'),
26
- });
26
+ })
27
27
  } else if (command === 'build') {
28
- const { buildProject } = await import('./build');
28
+ const { buildProject } = await import('./build')
29
29
  await buildProject(positionalRoot(args), {
30
30
  adapter: adapterOption(args),
31
31
  verbose: args.includes('--verbose'),
32
32
  debugBuildPaths: optionString(args, '--debug-build-paths'),
33
33
  buildMode: buildModeOption(args),
34
34
  debugPrerender: args.includes('--debug-prerender'),
35
- });
35
+ })
36
36
  // A live CSS worker thread races Bun's exit teardown (Linux: silent exit 1
37
37
  // after a successful build); stop it before force-exiting.
38
- await (await import('../css/build')).stopCssWorker();
38
+ await (await import('../css/build')).stopCssWorker()
39
39
  // Nothing here keeps the event loop alive on success, but a project's
40
40
  // next.config can (e.g. a stray setInterval) and Next's own `next build`
41
41
  // force-exits regardless of such handles. Do the same so `build` always
42
42
  // terminates once buildProject resolves.
43
- process.exit(0);
43
+ process.exit(0)
44
44
  } else if (command === 'start') {
45
- const root = positionalRoot(args);
45
+ const root = positionalRoot(args)
46
46
  // The build emits src/cli/start.ts prebundled into one file; parsing that
47
47
  // instead of walking the framework's source graph is most of `start`'s
48
48
  // spawn→first-200. Absent (no build yet, custom outDir) → source path.
49
- const { prebuiltServerEntry } = await import('./server-entry');
50
- const prebuilt = prebuiltServerEntry(root);
49
+ const { prebuiltServerEntry } = await import('./serve/entry')
50
+ const prebuilt = prebuiltServerEntry(root)
51
51
  const { start } = prebuilt
52
52
  ? ((await import(prebuilt)) as typeof import('./start'))
53
- : await import('./start');
53
+ : await import('./start')
54
54
  await start({
55
55
  root,
56
56
  port: optionNumber(args, '--port'),
57
57
  hostname: optionString(args, '--hostname'),
58
- });
58
+ })
59
59
  } else if (command === 'analyze') {
60
- const { analyzeProject } = await import('./analyze');
61
- const { route, root } = analyzePositionals(args);
60
+ const { analyzeProject } = await import('./analyze')
61
+ const { route, root } = analyzePositionals(args)
62
62
  const result = await analyzeProject(root, {
63
63
  compression: analyzeCompression(args),
64
64
  route,
65
- });
65
+ })
66
66
  if (args.includes('--json')) {
67
- console.log(JSON.stringify(result, null, 2));
67
+ console.log(JSON.stringify(result, null, 2))
68
68
  } else {
69
- const { printAnalyzeResult } = await import('./analyze-print');
70
- printAnalyzeResult(result, { route, files: args.includes('--files') });
69
+ const { printAnalyzeResult } = await import('./analyze')
70
+ printAnalyzeResult(result, { route, files: args.includes('--files') })
71
71
  }
72
72
  } else if (command === 'typegen') {
73
- const { typegenProject } = await import('../typegen');
74
- const result = await typegenProject(positionalRoot(args));
73
+ const { typegenProject } = await import('./typegen')
74
+ const result = await typegenProject(positionalRoot(args))
75
75
  console.log(
76
76
  `Generated ${result.routes} route types, ${result.aliases} aliases, and ${result.checks} checks at ${result.file}`,
77
- );
77
+ )
78
78
  // Like `next typegen`, exit even when the loaded next.config leaves open
79
79
  // handles (timers/connections) alive — a one-shot command must not hang.
80
- process.exit(0);
80
+ process.exit(0)
81
81
  } else if (command === 'create') {
82
- const { createApp } = await import('./create');
83
- await createApp(positionals(args)[0], { install: !args.includes('--no-install') });
84
- process.exit(0);
82
+ const { createApp } = await import('./create')
83
+ await createApp(positionals(args)[0], { install: !args.includes('--no-install') })
84
+ process.exit(0)
85
85
  } else if (command === 'migrate') {
86
- const { migrateApp } = await import('./migrate');
87
- const code = await migrateApp(positionalRoot(args), { dryRun: args.includes('--dry-run') });
88
- process.exit(code);
86
+ const { migrateApp } = await import('./migrate/run')
87
+ const code = await migrateApp(positionalRoot(args), { dryRun: args.includes('--dry-run') })
88
+ process.exit(code)
89
89
  } else {
90
- printHelp();
91
- process.exit(command ? 1 : 0);
90
+ printHelp()
91
+ process.exit(command ? 1 : 0)
92
92
  }
93
93
  } catch (error) {
94
- const formatted = formatCliError(error);
94
+ const formatted = formatCliError(error)
95
95
  // A blank formatted message exits 1 with no explanation; fall back to the
96
96
  // raw error so the failure is never silent.
97
- if (formatted.message.trim()) console.error(formatted.message);
98
- else console.error(error instanceof Error ? (error.stack ?? `${error.name}: ${error.message}`) : String(error));
99
- if (formatted.trace) console.log(`\n${formatted.trace}`);
100
- process.exit(1);
97
+ if (formatted.message.trim()) console.error(formatted.message)
98
+ else
99
+ console.error(
100
+ error instanceof Error ? (error.stack ?? `${error.name}: ${error.message}`) : String(error),
101
+ )
102
+ if (formatted.trace) console.log(`\n${formatted.trace}`)
103
+ process.exit(1)
101
104
  }
102
105
 
103
106
  function formatCliError(error: unknown) {
104
- const message = error instanceof Error ? error.message : String(error);
105
- const traceStart = message.indexOf('\npnext client import trace for route ');
106
- if (traceStart === -1) return { message };
107
+ const message = error instanceof Error ? error.message : String(error)
108
+ const traceStart = message.indexOf('\npnext client import trace for route ')
109
+ if (traceStart === -1) return { message }
107
110
  return {
108
111
  message: message.slice(0, traceStart),
109
112
  trace: message.slice(traceStart + 1),
110
- };
113
+ }
111
114
  }
112
115
 
113
116
  function positionalRoot(args: string[]) {
114
- return positionals(args)[0];
117
+ return positionals(args)[0]
115
118
  }
116
119
 
117
120
  // The analyze command takes optional [route] and [directory] positionals. A
@@ -119,27 +122,27 @@ function positionalRoot(args: string[]) {
119
122
  // that looks like a project root — system directories like /home or /run
120
123
  // collide with real route names.
121
124
  function analyzePositionals(args: string[]) {
122
- let route: string | undefined;
123
- let root: string | undefined;
125
+ let route: string | undefined
126
+ let root: string | undefined
124
127
  for (const arg of positionals(args)) {
125
- if (!route && arg.startsWith('/') && !isProjectDirectory(arg)) route = arg;
126
- else root ??= arg;
128
+ if (!route && arg.startsWith('/') && !isProjectDirectory(arg)) route = arg
129
+ else root ??= arg
127
130
  }
128
- return { route, root };
131
+ return { route, root }
129
132
  }
130
133
 
131
134
  function isProjectDirectory(candidate: string) {
132
- if (!isDirectory(candidate)) return false;
135
+ if (!isDirectory(candidate)) return false
133
136
  return ['package.json', '.pnext', 'app', path.join('src', 'app')].some(entry =>
134
137
  existsSync(path.join(candidate, entry)),
135
- );
138
+ )
136
139
  }
137
140
 
138
141
  function positionals(args: string[]) {
139
- const out: string[] = [];
142
+ const out: string[] = []
140
143
  for (let index = 0; index < args.length; index += 1) {
141
- const arg = args[index];
142
- if (!arg) continue;
144
+ const arg = args[index]
145
+ if (!arg) continue
143
146
  if (
144
147
  arg === '--port' ||
145
148
  arg === '--adapter' ||
@@ -147,36 +150,36 @@ function positionals(args: string[]) {
147
150
  arg === '--debug-build-paths' ||
148
151
  arg === '--experimental-build-mode'
149
152
  ) {
150
- index += 1;
151
- continue;
153
+ index += 1
154
+ continue
152
155
  }
153
- if (!arg.startsWith('--')) out.push(arg);
156
+ if (!arg.startsWith('--')) out.push(arg)
154
157
  }
155
- return out;
158
+ return out
156
159
  }
157
160
 
158
161
  function isDirectory(candidate: string) {
159
162
  try {
160
- return statSync(candidate).isDirectory();
163
+ return statSync(candidate).isDirectory()
161
164
  } catch {
162
- return false;
165
+ return false
163
166
  }
164
167
  }
165
168
 
166
169
  function optionNumber(args: string[], name: string) {
167
- const index = args.indexOf(name);
168
- if (index === -1) return undefined;
169
- const value = args[index + 1];
170
- return value ? Number(value) : undefined;
170
+ const index = args.indexOf(name)
171
+ if (index === -1) return undefined
172
+ const value = args[index + 1]
173
+ return value ? Number(value) : undefined
171
174
  }
172
175
 
173
176
  function optionString(args: string[], name: string) {
174
177
  // Accept both `--name value` and `--name=value`.
175
- const inline = args.find(arg => arg.startsWith(`${name}=`));
176
- if (inline !== undefined) return inline.slice(name.length + 1);
177
- const index = args.indexOf(name);
178
- if (index === -1) return undefined;
179
- return args[index + 1];
178
+ const inline = args.find(arg => arg.startsWith(`${name}=`))
179
+ if (inline !== undefined) return inline.slice(name.length + 1)
180
+ const index = args.indexOf(name)
181
+ if (index === -1) return undefined
182
+ return args[index + 1]
180
183
  }
181
184
 
182
185
  /**
@@ -186,27 +189,27 @@ function optionString(args: string[], name: string) {
186
189
  * the standard full build (idempotent over a prior `compile` run).
187
190
  */
188
191
  function buildModeOption(args: string[]): 'compile' | 'generate' | undefined {
189
- const value = optionString(args, '--experimental-build-mode');
190
- if (value === 'compile' || value === 'generate') return value;
192
+ const value = optionString(args, '--experimental-build-mode')
193
+ if (value === 'compile' || value === 'generate') return value
191
194
  if (value !== undefined) {
192
195
  console.error(
193
196
  `error: option '--experimental-build-mode <mode>' argument '${value}' is invalid. Expected 'compile' or 'generate'.`,
194
- );
195
- process.exit(1);
197
+ )
198
+ process.exit(1)
196
199
  }
197
- return undefined;
200
+ return undefined
198
201
  }
199
202
 
200
203
  function adapterOption(args: string[]) {
201
- const index = args.indexOf('--adapter');
202
- if (index === -1) return undefined;
203
- const adapter = args[index + 1];
204
- if (adapter === 'vercel') return adapter;
205
- throw new Error(`Unsupported adapter: ${adapter ?? ''}`);
204
+ const index = args.indexOf('--adapter')
205
+ if (index === -1) return undefined
206
+ const adapter = args[index + 1]
207
+ if (adapter === 'vercel') return adapter
208
+ throw new Error(`Unsupported adapter: ${adapter ?? ''}`)
206
209
  }
207
210
 
208
211
  function analyzeCompression(args: string[]) {
209
- return args.includes('--brotli') ? 'brotli' : 'gzip';
212
+ return args.includes('--brotli') ? 'brotli' : 'gzip'
210
213
  }
211
214
 
212
215
  function printHelp() {
@@ -216,5 +219,5 @@ pnext start [directory] [--port 3000] [--hostname 127.0.0.1]
216
219
  pnext analyze [route] [directory] [--brotli] [--files] [--json]
217
220
  pnext typegen [directory]
218
221
  pnext create <directory> [--no-install]
219
- pnext migrate [directory] [--dry-run]`);
222
+ pnext migrate [directory] [--dry-run]`)
220
223
  }
@@ -1,15 +1,16 @@
1
1
  // package.json rewriting: scripts and dependencies. Structured edit only —
2
2
  // JSON.parse -> mutate -> stringify, which preserves key insertion order.
3
3
 
4
- import { readFile, writeFile } from 'node:fs/promises';
5
- import path from 'node:path';
6
- import type { MigrationResult } from './report';
4
+ import { readFile, writeFile } from 'node:fs/promises'
5
+ import path from 'node:path'
6
+ import { pnextVersionRange } from '../../utils/fs'
7
+ import type { MigrationResult } from './report'
7
8
 
8
- const SEPARATORS = new Set(['&&', '||', ';', '|', '&']);
9
- const MAPPED_SUBCOMMANDS = new Set(['dev', 'build', 'start', 'typegen']);
10
- const DROPPED_FLAGS = new Set(['--turbo', '--turbopack']);
9
+ const SEPARATORS = new Set(['&&', '||', ';', '|', '&'])
10
+ const MAPPED_SUBCOMMANDS = new Set(['dev', 'build', 'start', 'typegen'])
11
+ const DROPPED_FLAGS = new Set(['--turbo', '--turbopack'])
11
12
 
12
- type Json = Record<string, unknown>;
13
+ type Json = Record<string, unknown>
13
14
 
14
15
  /**
15
16
  * Rewrite `next` only where it is a command word: the first token of the
@@ -17,64 +18,64 @@ type Json = Record<string, unknown>;
17
18
  * `nextron build` or `npx next-sitemap` are never touched.
18
19
  */
19
20
  export function rewriteScript(script: string): { script: string; reports: string[] } {
20
- const tokens = script.split(/\s+/).filter(Boolean);
21
- const reports: string[] = [];
22
- const out: string[] = [];
23
- let commandStart = true;
24
- let changed = false;
21
+ const tokens = script.split(/\s+/).filter(Boolean)
22
+ const reports: string[] = []
23
+ const out: string[] = []
24
+ let commandStart = true
25
+ let changed = false
25
26
 
26
27
  for (let index = 0; index < tokens.length; index += 1) {
27
- const token = tokens[index]!;
28
+ const token = tokens[index]!
28
29
  if (SEPARATORS.has(token)) {
29
- out.push(token);
30
- commandStart = true;
31
- continue;
30
+ out.push(token)
31
+ commandStart = true
32
+ continue
32
33
  }
33
34
  // Env-var prefixes (NODE_OPTIONS=x next dev) don't end the command position.
34
35
  if (commandStart && /^[A-Za-z_][A-Za-z0-9_]*=/.test(token)) {
35
- out.push(token);
36
- continue;
36
+ out.push(token)
37
+ continue
37
38
  }
38
39
  if (!commandStart || token !== 'next') {
39
- out.push(token);
40
- commandStart = false;
41
- continue;
40
+ out.push(token)
41
+ commandStart = false
42
+ continue
42
43
  }
43
44
 
44
- let end = index + 1;
45
- while (end < tokens.length && !SEPARATORS.has(tokens[end]!)) end += 1;
46
- const subcommand = tokens[index + 1];
47
- const rest = tokens.slice(index + 2, end);
45
+ let end = index + 1
46
+ while (end < tokens.length && !SEPARATORS.has(tokens[end]!)) end += 1
47
+ const subcommand = tokens[index + 1]
48
+ const rest = tokens.slice(index + 2, end)
48
49
 
49
50
  if (subcommand && MAPPED_SUBCOMMANDS.has(subcommand)) {
50
- out.push('pnext', subcommand, ...translateFlags(subcommand, rest));
51
- changed = true;
51
+ out.push('pnext', subcommand, ...translateFlags(subcommand, rest))
52
+ changed = true
52
53
  } else if (subcommand === 'lint') {
53
- out.push(...tokens.slice(index, end));
54
- reports.push('`next lint` left as-is — pnext has no lint command; run eslint directly.');
54
+ out.push(...tokens.slice(index, end))
55
+ reports.push('`next lint` left as-is — pnext has no lint command; run eslint directly.')
55
56
  } else {
56
- out.push(...tokens.slice(index, end));
57
- const command = subcommand ? `next ${subcommand}` : 'next';
58
- reports.push(`\`${command}\` has no pnext equivalent — left as-is.`);
57
+ out.push(...tokens.slice(index, end))
58
+ const command = subcommand ? `next ${subcommand}` : 'next'
59
+ reports.push(`\`${command}\` has no pnext equivalent — left as-is.`)
59
60
  }
60
- index = end - 1;
61
- commandStart = false;
61
+ index = end - 1
62
+ commandStart = false
62
63
  }
63
64
 
64
- return { script: changed ? out.join(' ') : script, reports };
65
+ return { script: changed ? out.join(' ') : script, reports }
65
66
  }
66
67
 
67
68
  function translateFlags(subcommand: string, rest: string[]) {
68
- const out: string[] = [];
69
+ const out: string[] = []
69
70
  for (const flag of rest) {
70
- if (DROPPED_FLAGS.has(flag)) continue;
71
+ if (DROPPED_FLAGS.has(flag)) continue
71
72
  if (flag === '-p' && (subcommand === 'dev' || subcommand === 'start')) {
72
- out.push('--port');
73
- continue;
73
+ out.push('--port')
74
+ continue
74
75
  }
75
- out.push(flag);
76
+ out.push(flag)
76
77
  }
77
- return out;
78
+ return out
78
79
  }
79
80
 
80
81
  export async function migratePackageJson(
@@ -83,18 +84,18 @@ export async function migratePackageJson(
83
84
  result: MigrationResult,
84
85
  dryRun: boolean,
85
86
  ) {
86
- const scripts = isObject(pkg.scripts) ? pkg.scripts : undefined;
87
+ const scripts = isObject(pkg.scripts) ? pkg.scripts : undefined
87
88
  if (scripts) {
88
- const rewritten: string[] = [];
89
+ const rewritten: string[] = []
89
90
  for (const [name, value] of Object.entries(scripts)) {
90
- if (typeof value !== 'string') continue;
91
- const { script, reports } = rewriteScript(value);
91
+ if (typeof value !== 'string') continue
92
+ const { script, reports } = rewriteScript(value)
92
93
  if (script !== value) {
93
- scripts[name] = script;
94
- rewritten.push(`${name}: ${value} → ${script}`);
94
+ scripts[name] = script
95
+ rewritten.push(`${name}: ${value} → ${script}`)
95
96
  }
96
97
  for (const detail of reports) {
97
- result.reports.push({ title: `package.json script "${name}"`, detail });
98
+ result.reports.push({ title: `package.json script "${name}"`, detail })
98
99
  }
99
100
  }
100
101
  if (rewritten.length > 0) {
@@ -102,82 +103,83 @@ export async function migratePackageJson(
102
103
  file: 'package.json',
103
104
  description: `scripts rewritten (${rewritten.length})`,
104
105
  details: rewritten,
105
- });
106
+ })
106
107
  }
107
108
  }
108
109
 
109
- const dependencies = ensureObject(pkg, 'dependencies');
110
- const devDependencies = ensureObject(pkg, 'devDependencies');
110
+ const dependencies = ensureObject(pkg, 'dependencies')
111
+ const devDependencies = ensureObject(pkg, 'devDependencies')
111
112
 
112
113
  for (const [field, bucket] of [
113
114
  ['dependencies', dependencies],
114
115
  ['devDependencies', devDependencies],
115
116
  ] as const) {
116
117
  if ('next' in bucket) {
117
- delete bucket.next;
118
+ delete bucket.next
118
119
  result.edits.push({
119
120
  file: 'package.json',
120
121
  description: 'next removed',
121
122
  details: [`next removed from ${field}`],
122
- });
123
+ })
123
124
  }
124
125
  }
125
126
  if (!('@wular/pnext' in devDependencies) && !('@wular/pnext' in dependencies)) {
126
- devDependencies['@wular/pnext'] = '^0.0.1';
127
+ const versionRange = pnextVersionRange()
128
+ devDependencies['@wular/pnext'] = versionRange
127
129
  result.edits.push({
128
130
  file: 'package.json',
129
131
  description: '@wular/pnext added',
130
- details: ['devDependencies: @wular/pnext ^0.0.1'],
131
- });
132
+ details: [`devDependencies: @wular/pnext ${versionRange}`],
133
+ })
132
134
  }
133
135
  if (!('preact' in dependencies) && !('preact' in devDependencies)) {
134
- dependencies.preact = '^10';
136
+ dependencies.preact = '^10'
135
137
  result.edits.push({
136
138
  file: 'package.json',
137
139
  description: 'preact added',
138
140
  details: ['dependencies: preact ^10 (react/react-dom kept — compat aliases them)'],
139
- });
141
+ })
140
142
  }
141
143
 
142
144
  const leftovers = [...Object.keys(dependencies), ...Object.keys(devDependencies)].filter(
143
145
  name => name === 'eslint-config-next' || name.startsWith('@next/'),
144
- );
146
+ )
145
147
  if (leftovers.length > 0) {
146
148
  result.reports.push({
147
149
  title: 'Next-specific packages still installed',
148
150
  detail: 'Optional cleanup — these are unused under pnext. See reference/compat.md.',
149
151
  files: leftovers,
150
- });
152
+ })
151
153
  }
152
154
 
153
- pruneEmpty(pkg, 'dependencies');
154
- pruneEmpty(pkg, 'devDependencies');
155
+ pruneEmpty(pkg, 'dependencies')
156
+ pruneEmpty(pkg, 'devDependencies')
155
157
 
156
158
  if (!dryRun) {
157
- await writeFile(path.join(root, 'package.json'), `${JSON.stringify(pkg, null, 2)}\n`);
159
+ await writeFile(path.join(root, 'package.json'), `${JSON.stringify(pkg, null, 2)}\n`)
158
160
  }
159
161
  }
160
162
 
161
163
  export async function readPackageJson(root: string): Promise<Json | undefined> {
162
164
  try {
163
- const parsed = JSON.parse(await readFile(path.join(root, 'package.json'), 'utf8')) as unknown;
164
- return isObject(parsed) ? parsed : undefined;
165
+ const parsed = JSON.parse(await readFile(path.join(root, 'package.json'), 'utf8')) as unknown
166
+ return isObject(parsed) ? parsed : undefined
165
167
  } catch {
166
- return undefined;
168
+ return undefined
167
169
  }
168
170
  }
169
171
 
170
172
  function isObject(value: unknown): value is Json {
171
- return typeof value === 'object' && value !== null && !Array.isArray(value);
173
+ return typeof value === 'object' && value !== null && !Array.isArray(value)
172
174
  }
173
175
 
174
176
  // Create the bucket in place so an existing key keeps its position.
175
177
  function ensureObject(pkg: Json, key: string): Json {
176
- if (!isObject(pkg[key])) pkg[key] = {};
177
- return pkg[key] as Json;
178
+ if (!isObject(pkg[key])) pkg[key] = {}
179
+ return pkg[key] as Json
178
180
  }
179
181
 
180
182
  function pruneEmpty(pkg: Json, key: string) {
181
- const value = pkg[key];
182
- if (isObject(value) && Object.keys(value).length === 0) delete pkg[key];
183
+ const value = pkg[key]
184
+ if (isObject(value) && Object.keys(value).length === 0) delete pkg[key]
183
185
  }
@@ -3,78 +3,77 @@
3
3
  // hand. The body of the output is identical under --dry-run — only the header
4
4
  // says whether anything was written.
5
5
 
6
- import { bold, cyan, dim, green } from '../../utils/ansi';
6
+ import { bold, cyan, dim, green } from '../../utils/ansi'
7
7
 
8
8
  /** Amber for warnings — ansi.ts has no yellow, so hand-roll the same shape. */
9
- const amber = (value: string) =>
10
- process.stdout.isTTY ? `\x1b[38;5;214m${value}\x1b[39m` : value;
9
+ const amber = (value: string) => (process.stdout.isTTY ? `\x1b[38;5;214m${value}\x1b[39m` : value)
11
10
 
12
11
  export interface Edit {
13
- file: string;
12
+ file: string
14
13
  /** Short phrase joined into the file's summary line. */
15
- description: string;
14
+ description: string
16
15
  /** Dim lines printed under the summary. */
17
- details?: string[];
16
+ details?: string[]
18
17
  }
19
18
 
20
19
  export interface ReportItem {
21
- title: string;
22
- detail: string;
23
- files?: string[];
20
+ title: string
21
+ detail: string
22
+ files?: string[]
24
23
  }
25
24
 
26
25
  export interface MigrationResult {
27
- edits: Edit[];
28
- reports: ReportItem[];
26
+ edits: Edit[]
27
+ reports: ReportItem[]
29
28
  }
30
29
 
31
30
  export function emptyResult(): MigrationResult {
32
- return { edits: [], reports: [] };
31
+ return { edits: [], reports: [] }
33
32
  }
34
33
 
35
34
  export function printHeader(root: string, dryRun: boolean) {
36
- const suffix = dryRun ? 'dry run, nothing will be written' : root;
37
- console.log(`\n${cyan('▲')} ${bold('pnext migrate')} ${dim(`— ${suffix}`)}`);
35
+ const suffix = dryRun ? 'dry run, nothing will be written' : root
36
+ console.log(`\n${cyan('▲')} ${bold('pnext migrate')} ${dim(`— ${suffix}`)}`)
38
37
  }
39
38
 
40
39
  export function printResult(result: MigrationResult, options: { install: string }) {
41
- const lines: string[] = [];
40
+ const lines: string[] = []
42
41
 
43
- lines.push(`\n${bold('Changes')}`);
42
+ lines.push(`\n${bold('Changes')}`)
44
43
  if (result.edits.length === 0) {
45
- lines.push(` ${dim('nothing to change')}`);
44
+ lines.push(` ${dim('nothing to change')}`)
46
45
  }
47
46
  for (const [file, edits] of groupByFile(result.edits)) {
48
47
  lines.push(
49
48
  `${green('✓')} ${bold(file)} ${dim(`— ${edits.map(edit => edit.description).join(', ')}`)}`,
50
- );
49
+ )
51
50
  for (const edit of edits) {
52
- for (const detail of edit.details ?? []) lines.push(` ${dim(detail)}`);
51
+ for (const detail of edit.details ?? []) lines.push(` ${dim(detail)}`)
53
52
  }
54
53
  }
55
54
 
56
- lines.push(`\n${bold('Review')}${result.reports.length > 0 ? ` (${result.reports.length})` : ''}`);
55
+ lines.push(`\n${bold('Review')}${result.reports.length > 0 ? ` (${result.reports.length})` : ''}`)
57
56
  if (result.reports.length === 0) {
58
- lines.push(` ${dim('nothing flagged')}`);
57
+ lines.push(` ${dim('nothing flagged')}`)
59
58
  }
60
59
  for (const item of result.reports) {
61
- lines.push(`${amber('!')} ${bold(item.title)}`);
62
- lines.push(` ${dim(item.detail)}`);
63
- for (const file of item.files ?? []) lines.push(` ${dim(`· ${file}`)}`);
60
+ lines.push(`${amber('!')} ${bold(item.title)}`)
61
+ lines.push(` ${dim(item.detail)}`)
62
+ for (const file of item.files ?? []) lines.push(` ${dim(`· ${file}`)}`)
64
63
  }
65
64
 
66
- lines.push(`\n${bold('Next steps')}`);
67
- lines.push(` Run ${cyan(options.install)} to install the new dependencies.`);
68
- lines.push(` ${cyan('pnext dev')} to start the app.`);
69
- console.log(lines.join('\n'));
65
+ lines.push(`\n${bold('Next steps')}`)
66
+ lines.push(` Run ${cyan(options.install)} to install the new dependencies.`)
67
+ lines.push(` ${cyan('pnext dev')} to start the app.`)
68
+ console.log(lines.join('\n'))
70
69
  }
71
70
 
72
71
  function groupByFile(edits: Edit[]) {
73
- const grouped = new Map<string, Edit[]>();
72
+ const grouped = new Map<string, Edit[]>()
74
73
  for (const edit of edits) {
75
- const bucket = grouped.get(edit.file);
76
- if (bucket) bucket.push(edit);
77
- else grouped.set(edit.file, [edit]);
74
+ const bucket = grouped.get(edit.file)
75
+ if (bucket) bucket.push(edit)
76
+ else grouped.set(edit.file, [edit])
78
77
  }
79
- return grouped;
78
+ return grouped
80
79
  }