@endora-commerce/cli 0.100.0

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 (356) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +37 -0
  3. package/dist/bin/endora.d.ts +28 -0
  4. package/dist/bin/endora.d.ts.map +1 -0
  5. package/dist/bin/endora.js +926 -0
  6. package/dist/bin/endora.js.map +1 -0
  7. package/dist/check/estate.d.ts +189 -0
  8. package/dist/check/estate.d.ts.map +1 -0
  9. package/dist/check/estate.js +1037 -0
  10. package/dist/check/estate.js.map +1 -0
  11. package/dist/check/hosts.d.ts +25 -0
  12. package/dist/check/hosts.d.ts.map +1 -0
  13. package/dist/check/hosts.js +1347 -0
  14. package/dist/check/hosts.js.map +1 -0
  15. package/dist/check/index.d.ts +60 -0
  16. package/dist/check/index.d.ts.map +1 -0
  17. package/dist/check/index.js +111 -0
  18. package/dist/check/index.js.map +1 -0
  19. package/dist/check/layout.d.ts +136 -0
  20. package/dist/check/layout.d.ts.map +1 -0
  21. package/dist/check/layout.js +262 -0
  22. package/dist/check/layout.js.map +1 -0
  23. package/dist/check/ledger.d.ts +98 -0
  24. package/dist/check/ledger.d.ts.map +1 -0
  25. package/dist/check/ledger.js +173 -0
  26. package/dist/check/ledger.js.map +1 -0
  27. package/dist/check/peer-owners.d.ts +116 -0
  28. package/dist/check/peer-owners.d.ts.map +1 -0
  29. package/dist/check/peer-owners.js +225 -0
  30. package/dist/check/peer-owners.js.map +1 -0
  31. package/dist/check/report.d.ts +33 -0
  32. package/dist/check/report.d.ts.map +1 -0
  33. package/dist/check/report.js +107 -0
  34. package/dist/check/report.js.map +1 -0
  35. package/dist/check/run.d.ts +147 -0
  36. package/dist/check/run.d.ts.map +1 -0
  37. package/dist/check/run.js +111 -0
  38. package/dist/check/run.js.map +1 -0
  39. package/dist/checks.d.ts +17 -0
  40. package/dist/checks.d.ts.map +1 -0
  41. package/dist/checks.js +17 -0
  42. package/dist/checks.js.map +1 -0
  43. package/dist/dev/index.d.ts +83 -0
  44. package/dist/dev/index.d.ts.map +1 -0
  45. package/dist/dev/index.js +298 -0
  46. package/dist/dev/index.js.map +1 -0
  47. package/dist/generate/divergence.d.ts +38 -0
  48. package/dist/generate/divergence.d.ts.map +1 -0
  49. package/dist/generate/divergence.js +237 -0
  50. package/dist/generate/divergence.js.map +1 -0
  51. package/dist/generate/index.d.ts +90 -0
  52. package/dist/generate/index.d.ts.map +1 -0
  53. package/dist/generate/index.js +369 -0
  54. package/dist/generate/index.js.map +1 -0
  55. package/dist/index.d.ts +23 -0
  56. package/dist/index.d.ts.map +1 -0
  57. package/dist/index.js +35 -0
  58. package/dist/index.js.map +1 -0
  59. package/dist/inputs/declaration.d.ts +18 -0
  60. package/dist/inputs/declaration.d.ts.map +1 -0
  61. package/dist/inputs/declaration.js +64 -0
  62. package/dist/inputs/declaration.js.map +1 -0
  63. package/dist/inputs/env-file.d.ts +73 -0
  64. package/dist/inputs/env-file.d.ts.map +1 -0
  65. package/dist/inputs/env-file.js +134 -0
  66. package/dist/inputs/env-file.js.map +1 -0
  67. package/dist/inputs/prompt.d.ts +21 -0
  68. package/dist/inputs/prompt.d.ts.map +1 -0
  69. package/dist/inputs/prompt.js +59 -0
  70. package/dist/inputs/prompt.js.map +1 -0
  71. package/dist/inputs/resolve.d.ts +163 -0
  72. package/dist/inputs/resolve.d.ts.map +1 -0
  73. package/dist/inputs/resolve.js +290 -0
  74. package/dist/inputs/resolve.js.map +1 -0
  75. package/dist/install/host.d.ts +27 -0
  76. package/dist/install/host.d.ts.map +1 -0
  77. package/dist/install/host.js +90 -0
  78. package/dist/install/host.js.map +1 -0
  79. package/dist/install/index.d.ts +173 -0
  80. package/dist/install/index.d.ts.map +1 -0
  81. package/dist/install/index.js +793 -0
  82. package/dist/install/index.js.map +1 -0
  83. package/dist/install/wizard.d.ts +144 -0
  84. package/dist/install/wizard.d.ts.map +1 -0
  85. package/dist/install/wizard.js +362 -0
  86. package/dist/install/wizard.js.map +1 -0
  87. package/dist/lib/admin-artefacts.d.ts +70 -0
  88. package/dist/lib/admin-artefacts.d.ts.map +1 -0
  89. package/dist/lib/admin-artefacts.js +354 -0
  90. package/dist/lib/admin-artefacts.js.map +1 -0
  91. package/dist/lib/admin-surfaces.d.ts +298 -0
  92. package/dist/lib/admin-surfaces.d.ts.map +1 -0
  93. package/dist/lib/admin-surfaces.js +669 -0
  94. package/dist/lib/admin-surfaces.js.map +1 -0
  95. package/dist/lib/delegated-composer.d.ts +85 -0
  96. package/dist/lib/delegated-composer.d.ts.map +1 -0
  97. package/dist/lib/delegated-composer.js +241 -0
  98. package/dist/lib/delegated-composer.js.map +1 -0
  99. package/dist/lib/divergence-artefacts.d.ts +305 -0
  100. package/dist/lib/divergence-artefacts.d.ts.map +1 -0
  101. package/dist/lib/divergence-artefacts.js +828 -0
  102. package/dist/lib/divergence-artefacts.js.map +1 -0
  103. package/dist/lib/divergence.d.ts +337 -0
  104. package/dist/lib/divergence.d.ts.map +1 -0
  105. package/dist/lib/divergence.js +1005 -0
  106. package/dist/lib/divergence.js.map +1 -0
  107. package/dist/lib/docs-artefacts.d.ts +395 -0
  108. package/dist/lib/docs-artefacts.d.ts.map +1 -0
  109. package/dist/lib/docs-artefacts.js +781 -0
  110. package/dist/lib/docs-artefacts.js.map +1 -0
  111. package/dist/lib/emitted-exports.d.ts +21 -0
  112. package/dist/lib/emitted-exports.d.ts.map +1 -0
  113. package/dist/lib/emitted-exports.js +96 -0
  114. package/dist/lib/emitted-exports.js.map +1 -0
  115. package/dist/lib/emitted-freshness.d.ts +112 -0
  116. package/dist/lib/emitted-freshness.d.ts.map +1 -0
  117. package/dist/lib/emitted-freshness.js +288 -0
  118. package/dist/lib/emitted-freshness.js.map +1 -0
  119. package/dist/lib/entity-index-artefact.d.ts +95 -0
  120. package/dist/lib/entity-index-artefact.d.ts.map +1 -0
  121. package/dist/lib/entity-index-artefact.js +210 -0
  122. package/dist/lib/entity-index-artefact.js.map +1 -0
  123. package/dist/lib/instance-build-inputs.d.ts +108 -0
  124. package/dist/lib/instance-build-inputs.d.ts.map +1 -0
  125. package/dist/lib/instance-build-inputs.js +165 -0
  126. package/dist/lib/instance-build-inputs.js.map +1 -0
  127. package/dist/lib/module-docs.d.ts +473 -0
  128. package/dist/lib/module-docs.d.ts.map +1 -0
  129. package/dist/lib/module-docs.js +711 -0
  130. package/dist/lib/module-docs.js.map +1 -0
  131. package/dist/lib/module-package-subpaths.d.ts +56 -0
  132. package/dist/lib/module-package-subpaths.d.ts.map +1 -0
  133. package/dist/lib/module-package-subpaths.js +223 -0
  134. package/dist/lib/module-package-subpaths.js.map +1 -0
  135. package/dist/lib/module-packages.d.ts +200 -0
  136. package/dist/lib/module-packages.d.ts.map +1 -0
  137. package/dist/lib/module-packages.js +580 -0
  138. package/dist/lib/module-packages.js.map +1 -0
  139. package/dist/lib/module-population.d.ts +129 -0
  140. package/dist/lib/module-population.d.ts.map +1 -0
  141. package/dist/lib/module-population.js +172 -0
  142. package/dist/lib/module-population.js.map +1 -0
  143. package/dist/lib/module-roots.d.ts +337 -0
  144. package/dist/lib/module-roots.d.ts.map +1 -0
  145. package/dist/lib/module-roots.js +586 -0
  146. package/dist/lib/module-roots.js.map +1 -0
  147. package/dist/lib/nested-checkouts.d.ts +33 -0
  148. package/dist/lib/nested-checkouts.d.ts.map +1 -0
  149. package/dist/lib/nested-checkouts.js +160 -0
  150. package/dist/lib/nested-checkouts.js.map +1 -0
  151. package/dist/lib/platform-root.d.ts +43 -0
  152. package/dist/lib/platform-root.d.ts.map +1 -0
  153. package/dist/lib/platform-root.js +134 -0
  154. package/dist/lib/platform-root.js.map +1 -0
  155. package/dist/lib/platform-surface.d.ts +235 -0
  156. package/dist/lib/platform-surface.d.ts.map +1 -0
  157. package/dist/lib/platform-surface.js +393 -0
  158. package/dist/lib/platform-surface.js.map +1 -0
  159. package/dist/lib/port-registrations.d.ts +223 -0
  160. package/dist/lib/port-registrations.d.ts.map +1 -0
  161. package/dist/lib/port-registrations.js +532 -0
  162. package/dist/lib/port-registrations.js.map +1 -0
  163. package/dist/lib/read-size.d.ts +154 -0
  164. package/dist/lib/read-size.d.ts.map +1 -0
  165. package/dist/lib/read-size.js +182 -0
  166. package/dist/lib/read-size.js.map +1 -0
  167. package/dist/lib/registration-owners.d.ts +79 -0
  168. package/dist/lib/registration-owners.d.ts.map +1 -0
  169. package/dist/lib/registration-owners.js +77 -0
  170. package/dist/lib/registration-owners.js.map +1 -0
  171. package/dist/lib/release-index.d.ts +53 -0
  172. package/dist/lib/release-index.d.ts.map +1 -0
  173. package/dist/lib/release-index.js +162 -0
  174. package/dist/lib/release-index.js.map +1 -0
  175. package/dist/lib/repeating-timers.d.ts +79 -0
  176. package/dist/lib/repeating-timers.d.ts.map +1 -0
  177. package/dist/lib/repeating-timers.js +189 -0
  178. package/dist/lib/repeating-timers.js.map +1 -0
  179. package/dist/lib/source-text.d.ts +34 -0
  180. package/dist/lib/source-text.d.ts.map +1 -0
  181. package/dist/lib/source-text.js +80 -0
  182. package/dist/lib/source-text.js.map +1 -0
  183. package/dist/lib/specifiers.d.ts +20 -0
  184. package/dist/lib/specifiers.d.ts.map +1 -0
  185. package/dist/lib/specifiers.js +130 -0
  186. package/dist/lib/specifiers.js.map +1 -0
  187. package/dist/lib/sql-tables.d.ts +166 -0
  188. package/dist/lib/sql-tables.d.ts.map +1 -0
  189. package/dist/lib/sql-tables.js +464 -0
  190. package/dist/lib/sql-tables.js.map +1 -0
  191. package/dist/lib/switchable-modules.d.ts +54 -0
  192. package/dist/lib/switchable-modules.d.ts.map +1 -0
  193. package/dist/lib/switchable-modules.js +104 -0
  194. package/dist/lib/switchable-modules.js.map +1 -0
  195. package/dist/lib/tailwind-sources.d.ts +136 -0
  196. package/dist/lib/tailwind-sources.d.ts.map +1 -0
  197. package/dist/lib/tailwind-sources.js +307 -0
  198. package/dist/lib/tailwind-sources.js.map +1 -0
  199. package/dist/lib/ui-layer.d.ts +54 -0
  200. package/dist/lib/ui-layer.d.ts.map +1 -0
  201. package/dist/lib/ui-layer.js +57 -0
  202. package/dist/lib/ui-layer.js.map +1 -0
  203. package/dist/lib/workspace-packages.d.ts +186 -0
  204. package/dist/lib/workspace-packages.d.ts.map +1 -0
  205. package/dist/lib/workspace-packages.js +351 -0
  206. package/dist/lib/workspace-packages.js.map +1 -0
  207. package/dist/new-instance/deploy.d.ts +211 -0
  208. package/dist/new-instance/deploy.d.ts.map +1 -0
  209. package/dist/new-instance/deploy.js +1381 -0
  210. package/dist/new-instance/deploy.js.map +1 -0
  211. package/dist/new-instance/docs-toolchain.d.ts +66 -0
  212. package/dist/new-instance/docs-toolchain.d.ts.map +1 -0
  213. package/dist/new-instance/docs-toolchain.js +69 -0
  214. package/dist/new-instance/docs-toolchain.js.map +1 -0
  215. package/dist/new-instance/host.d.ts +124 -0
  216. package/dist/new-instance/host.d.ts.map +1 -0
  217. package/dist/new-instance/host.js +276 -0
  218. package/dist/new-instance/host.js.map +1 -0
  219. package/dist/new-instance/index.d.ts +118 -0
  220. package/dist/new-instance/index.d.ts.map +1 -0
  221. package/dist/new-instance/index.js +567 -0
  222. package/dist/new-instance/index.js.map +1 -0
  223. package/dist/new-instance/modules.d.ts +188 -0
  224. package/dist/new-instance/modules.d.ts.map +1 -0
  225. package/dist/new-instance/modules.js +392 -0
  226. package/dist/new-instance/modules.js.map +1 -0
  227. package/dist/new-instance/template.d.ts +505 -0
  228. package/dist/new-instance/template.d.ts.map +1 -0
  229. package/dist/new-instance/template.js +1886 -0
  230. package/dist/new-instance/template.js.map +1 -0
  231. package/dist/new-module/emit.d.ts +67 -0
  232. package/dist/new-module/emit.d.ts.map +1 -0
  233. package/dist/new-module/emit.js +1393 -0
  234. package/dist/new-module/emit.js.map +1 -0
  235. package/dist/new-module/host.d.ts +67 -0
  236. package/dist/new-module/host.d.ts.map +1 -0
  237. package/dist/new-module/host.js +224 -0
  238. package/dist/new-module/host.js.map +1 -0
  239. package/dist/new-module/index.d.ts +32 -0
  240. package/dist/new-module/index.d.ts.map +1 -0
  241. package/dist/new-module/index.js +193 -0
  242. package/dist/new-module/index.js.map +1 -0
  243. package/dist/new-module/spec.d.ts +188 -0
  244. package/dist/new-module/spec.d.ts.map +1 -0
  245. package/dist/new-module/spec.js +404 -0
  246. package/dist/new-module/spec.js.map +1 -0
  247. package/dist/new-module/text.d.ts +15 -0
  248. package/dist/new-module/text.d.ts.map +1 -0
  249. package/dist/new-module/text.js +22 -0
  250. package/dist/new-module/text.js.map +1 -0
  251. package/dist/new-storefront/dockerfile.d.ts +20 -0
  252. package/dist/new-storefront/dockerfile.d.ts.map +1 -0
  253. package/dist/new-storefront/dockerfile.js +131 -0
  254. package/dist/new-storefront/dockerfile.js.map +1 -0
  255. package/dist/new-storefront/gitignore.d.ts +23 -0
  256. package/dist/new-storefront/gitignore.d.ts.map +1 -0
  257. package/dist/new-storefront/gitignore.js +39 -0
  258. package/dist/new-storefront/gitignore.js.map +1 -0
  259. package/dist/new-storefront/index.d.ts +93 -0
  260. package/dist/new-storefront/index.d.ts.map +1 -0
  261. package/dist/new-storefront/index.js +329 -0
  262. package/dist/new-storefront/index.js.map +1 -0
  263. package/dist/new-storefront/npmrc.d.ts +98 -0
  264. package/dist/new-storefront/npmrc.d.ts.map +1 -0
  265. package/dist/new-storefront/npmrc.js +217 -0
  266. package/dist/new-storefront/npmrc.js.map +1 -0
  267. package/dist/new-storefront/reference.d.ts +189 -0
  268. package/dist/new-storefront/reference.d.ts.map +1 -0
  269. package/dist/new-storefront/reference.js +430 -0
  270. package/dist/new-storefront/reference.js.map +1 -0
  271. package/dist/new-storefront/rewrite.d.ts +171 -0
  272. package/dist/new-storefront/rewrite.d.ts.map +1 -0
  273. package/dist/new-storefront/rewrite.js +701 -0
  274. package/dist/new-storefront/rewrite.js.map +1 -0
  275. package/dist/release-index.json +284 -0
  276. package/dist/rules/action-route-permissions.d.ts +141 -0
  277. package/dist/rules/action-route-permissions.d.ts.map +1 -0
  278. package/dist/rules/action-route-permissions.js +556 -0
  279. package/dist/rules/action-route-permissions.js.map +1 -0
  280. package/dist/rules/bundle-pairing.d.ts +74 -0
  281. package/dist/rules/bundle-pairing.d.ts.map +1 -0
  282. package/dist/rules/bundle-pairing.js +281 -0
  283. package/dist/rules/bundle-pairing.js.map +1 -0
  284. package/dist/rules/channel-resolution.d.ts +17 -0
  285. package/dist/rules/channel-resolution.d.ts.map +1 -0
  286. package/dist/rules/channel-resolution.js +382 -0
  287. package/dist/rules/channel-resolution.js.map +1 -0
  288. package/dist/rules/command-coverage.d.ts +210 -0
  289. package/dist/rules/command-coverage.d.ts.map +1 -0
  290. package/dist/rules/command-coverage.js +714 -0
  291. package/dist/rules/command-coverage.js.map +1 -0
  292. package/dist/rules/container-imports.d.ts +60 -0
  293. package/dist/rules/container-imports.d.ts.map +1 -0
  294. package/dist/rules/container-imports.js +158 -0
  295. package/dist/rules/container-imports.js.map +1 -0
  296. package/dist/rules/default-language-prose.d.ts +212 -0
  297. package/dist/rules/default-language-prose.d.ts.map +1 -0
  298. package/dist/rules/default-language-prose.js +710 -0
  299. package/dist/rules/default-language-prose.js.map +1 -0
  300. package/dist/rules/diacritic-folds.d.ts +238 -0
  301. package/dist/rules/diacritic-folds.d.ts.map +1 -0
  302. package/dist/rules/diacritic-folds.js +681 -0
  303. package/dist/rules/diacritic-folds.js.map +1 -0
  304. package/dist/rules/entity-tenant-classification.d.ts +171 -0
  305. package/dist/rules/entity-tenant-classification.d.ts.map +1 -0
  306. package/dist/rules/entity-tenant-classification.js +323 -0
  307. package/dist/rules/entity-tenant-classification.js.map +1 -0
  308. package/dist/rules/entry-presence.d.ts +142 -0
  309. package/dist/rules/entry-presence.d.ts.map +1 -0
  310. package/dist/rules/entry-presence.js +339 -0
  311. package/dist/rules/entry-presence.js.map +1 -0
  312. package/dist/rules/entry-scope.d.ts +91 -0
  313. package/dist/rules/entry-scope.d.ts.map +1 -0
  314. package/dist/rules/entry-scope.js +404 -0
  315. package/dist/rules/entry-scope.js.map +1 -0
  316. package/dist/rules/env-inputs.d.ts +222 -0
  317. package/dist/rules/env-inputs.d.ts.map +1 -0
  318. package/dist/rules/env-inputs.js +951 -0
  319. package/dist/rules/env-inputs.js.map +1 -0
  320. package/dist/rules/kernel-boundary.d.ts +37 -0
  321. package/dist/rules/kernel-boundary.d.ts.map +1 -0
  322. package/dist/rules/kernel-boundary.js +195 -0
  323. package/dist/rules/kernel-boundary.js.map +1 -0
  324. package/dist/rules/nul-bytes.d.ts +233 -0
  325. package/dist/rules/nul-bytes.d.ts.map +1 -0
  326. package/dist/rules/nul-bytes.js +332 -0
  327. package/dist/rules/nul-bytes.js.map +1 -0
  328. package/dist/rules/platform-surface.d.ts +479 -0
  329. package/dist/rules/platform-surface.d.ts.map +1 -0
  330. package/dist/rules/platform-surface.js +749 -0
  331. package/dist/rules/platform-surface.js.map +1 -0
  332. package/dist/rules/port-catches.d.ts +225 -0
  333. package/dist/rules/port-catches.d.ts.map +1 -0
  334. package/dist/rules/port-catches.js +1374 -0
  335. package/dist/rules/port-catches.js.map +1 -0
  336. package/dist/rules/port-shape.d.ts +213 -0
  337. package/dist/rules/port-shape.d.ts.map +1 -0
  338. package/dist/rules/port-shape.js +670 -0
  339. package/dist/rules/port-shape.js.map +1 -0
  340. package/dist/rules/queue-names.d.ts +108 -0
  341. package/dist/rules/queue-names.d.ts.map +1 -0
  342. package/dist/rules/queue-names.js +395 -0
  343. package/dist/rules/queue-names.js.map +1 -0
  344. package/dist/rules/singleton-identity.d.ts +205 -0
  345. package/dist/rules/singleton-identity.d.ts.map +1 -0
  346. package/dist/rules/singleton-identity.js +830 -0
  347. package/dist/rules/singleton-identity.js.map +1 -0
  348. package/dist/rules/subscribe-seam.d.ts +121 -0
  349. package/dist/rules/subscribe-seam.d.ts.map +1 -0
  350. package/dist/rules/subscribe-seam.js +594 -0
  351. package/dist/rules/subscribe-seam.js.map +1 -0
  352. package/dist/rules/transaction-context.d.ts +40 -0
  353. package/dist/rules/transaction-context.d.ts.map +1 -0
  354. package/dist/rules/transaction-context.js +294 -0
  355. package/dist/rules/transaction-context.js.map +1 -0
  356. package/package.json +59 -0
@@ -0,0 +1,701 @@
1
+ /**
2
+ * The transformation: a copy of the reference storefront that names nothing
3
+ * above its own directory.
4
+ *
5
+ * ## What a rewrite is keyed on
6
+ *
7
+ * **The shape of the declaration, never which file or which package writes it.**
8
+ * `specs/071-modular-packaging/roadmap.md` § *F7* enumerated the declarations
9
+ * once and the enumeration was stale within a day; a tool carrying it would have
10
+ * rewritten a dependency that had been deleted and copied three later ones out
11
+ * unchanged. So every rule below reads a *kind* of declaration — a `workspace:`
12
+ * protocol range, a `tsconfig` `extends`, an import from a configuration file, a
13
+ * Tailwind `@source` glob — and the population it runs over is
14
+ * {@link outwardReferences}' answer for this checkout, on this run.
15
+ *
16
+ * ## The refusal is the load-bearing half
17
+ *
18
+ * An outward reference no rule classifies is {@link UnclassifiedReferenceError},
19
+ * exit 1, naming the file and the specifier. That is what stops this command
20
+ * from doing quietly what the roadmap's own sentence did loudly: copy a
21
+ * monorepo-relative declaration out of the repository and call it a storefront.
22
+ * A green run therefore means *"every declaration naming something above this
23
+ * directory was rewritten"*, and never *"the ones I knew about were"*.
24
+ *
25
+ * ## The four rules, and why each is the shape it is
26
+ *
27
+ * 1. **`workspace:` → published semver.** pnpm's own publish semantics, applied
28
+ * to the version the named package declares: `workspace:*` is that version
29
+ * exactly, `workspace:^` and `workspace:~` are it with the operator, and
30
+ * `workspace:<range>` is the range as written. This is the rewrite
31
+ * publication makes real; until the packages are published a consumer
32
+ * substitutes a tarball, which is what the acceptance criterion does.
33
+ * 2. **Vendor a referenced configuration file, and make the copy standalone.**
34
+ * One mechanism for all three configuration references. The copy is then
35
+ * walked for its *own* outward references, and each is dropped when its
36
+ * target cannot come with it — for `tsconfig.base.json` that is the whole
37
+ * `compilerOptions.paths` block, whose every target names a directory under
38
+ * `packages/`; for the vitest base it is this repository's issue-#255
39
+ * workspace-resolution guard, whose closure reaches a package the scaffold
40
+ * does not install and which returns without doing anything outside a
41
+ * checkout by its own author's design.
42
+ * 3. **Retarget a glob that names the workspace's package tree** at where those
43
+ * packages are installed in a standalone application: `node_modules/<scope>`.
44
+ * A `@source` glob whose prefix does not exist is not an error in Tailwind —
45
+ * it contributes nothing, silently — which is the failure mode
46
+ * `app/globals.css`' own comment describes and the reason this rule is a
47
+ * rewrite rather than a deletion.
48
+ * 4. **A file whose outward reference cannot be made standalone is not copied,
49
+ * and is reported.** It is reported rather than dropped in silence, and it is
50
+ * refused outright when it sits under one of the application's own source
51
+ * roots — a test asserting a property of *this repository's* layout has no
52
+ * subject in a scaffold, an application file that reached out has no answer
53
+ * at all.
54
+ */
55
+ import { existsSync, readFileSync } from 'node:fs';
56
+ import { dirname, join, posix, relative, resolve, sep } from 'node:path';
57
+ import { STOREFRONT_DOCKERIGNORE, storefrontDockerfile } from './dockerfile.js';
58
+ import { storefrontGitignore } from './gitignore.js';
59
+ import { installedScopes, normalizeRegistry, npmrcContent, TOKEN_VARIABLE } from './npmrc.js';
60
+ import { declaredPackages, DEPENDENCY_FIELDS, globPrefix, importedPackages, outwardReferences, StorefrontInputError, workspaceRanges, } from './reference.js';
61
+ /** An outward reference no rule below classifies. */
62
+ export class UnclassifiedReferenceError extends StorefrontInputError {
63
+ }
64
+ /** A vendored configuration imports a package the scaffold's manifest does not declare. */
65
+ export class UndeclaredImportError extends StorefrontInputError {
66
+ }
67
+ /**
68
+ * `workspace:<protocol>` as pnpm itself publishes it.
69
+ *
70
+ * The version comes from the named package's own manifest, so a repository that
71
+ * has started versioning its packages produces real ranges with no change here.
72
+ */
73
+ export function publishedRange(declared, version) {
74
+ const tail = declared.slice('workspace:'.length);
75
+ if (tail === '*' || tail === '')
76
+ return version;
77
+ if (tail === '^')
78
+ return `^${version}`;
79
+ if (tail === '~')
80
+ return `~${version}`;
81
+ return tail;
82
+ }
83
+ /** The version a workspace member declares, or `null` when it is not a member. */
84
+ export function memberVersion(memberDirs, name) {
85
+ for (const dir of memberDirs) {
86
+ const manifestPath = join(dir, 'package.json');
87
+ if (!existsSync(manifestPath))
88
+ continue;
89
+ let manifest;
90
+ try {
91
+ manifest = JSON.parse(readFileSync(manifestPath, 'utf8'));
92
+ }
93
+ catch {
94
+ continue;
95
+ }
96
+ if (manifest.name !== name)
97
+ continue;
98
+ if (typeof manifest.version !== 'string')
99
+ return null;
100
+ return { version: manifest.version, dir };
101
+ }
102
+ return null;
103
+ }
104
+ /** The single npm scope the workspace's `@`-scoped members publish under. */
105
+ export function workspaceScope(memberDirs) {
106
+ const scopes = new Set();
107
+ for (const dir of memberDirs) {
108
+ const manifestPath = join(dir, 'package.json');
109
+ if (!existsSync(manifestPath))
110
+ continue;
111
+ let name;
112
+ try {
113
+ name = JSON.parse(readFileSync(manifestPath, 'utf8')).name;
114
+ }
115
+ catch {
116
+ continue;
117
+ }
118
+ if (typeof name !== 'string' || !name.startsWith('@'))
119
+ continue;
120
+ const slash = name.indexOf('/');
121
+ if (slash > 0)
122
+ scopes.add(name.slice(0, slash));
123
+ }
124
+ const only = [...scopes];
125
+ return only.length === 1 ? only[0] : null;
126
+ }
127
+ /** A `packageManager` value corepack accepts: `<name>@<version>`, optionally hashed. */
128
+ const PACKAGE_MANAGER = /^[a-z]+@\d+\.\d+\.\d+(?:[-+][\w.+-]+)?$/;
129
+ /**
130
+ * The `packageManager` the scaffolded manifest declares.
131
+ *
132
+ * **It is a fact about the client's migration cost, not a formality**
133
+ * (`specs/104-package-publication/` FR-023). Measured in that feature's
134
+ * `research.md` §4: a pnpm lockfile records integrity and no registry, an npm
135
+ * lockfile records a `resolved` URL per package — so a client moving between
136
+ * registries edits one `.npmrc` line or regenerates their whole lockfile, and
137
+ * which of the two applies is decided by a field nobody had written down.
138
+ *
139
+ * The value is the checkout's own: the reference storefront's if it declares
140
+ * one, otherwise the repository root's, because that is the manager this
141
+ * repository builds and tests the reference storefront with. A checkout that
142
+ * declares neither is a refusal — this command invents no version, for
143
+ * {@link rewriteManifest}'s reason one field over: a `packageManager` corepack
144
+ * rejects is worse than the absent field it replaced.
145
+ */
146
+ export function packageManagerFor(reference) {
147
+ const own = reference.manifest['packageManager'];
148
+ const declared = typeof own === 'string' && own.length > 0 ? own : rootPackageManager(reference.repoRoot);
149
+ if (declared === null) {
150
+ throw new StorefrontInputError(`neither ${reference.dir}/package.json nor ${reference.repoRoot}/package.json declares ` +
151
+ `\`packageManager\`, so this command has no answer to give the scaffold. What a ` +
152
+ `client's lockfile records about the registry it resolved from depends on which ` +
153
+ `package manager wrote it, and a scaffold that stayed silent would leave that to their ` +
154
+ `habits. Declare it in this checkout and run again.`);
155
+ }
156
+ if (!PACKAGE_MANAGER.test(declared)) {
157
+ throw new StorefrontInputError(`\`packageManager\` reads "${declared}" in this checkout, which is not the ` +
158
+ `\`<name>@<version>\` corepack resolves. Copying it into the scaffold would move a ` +
159
+ `refusal from this command to the client's first install.`);
160
+ }
161
+ return declared;
162
+ }
163
+ function rootPackageManager(repoRoot) {
164
+ const path = join(repoRoot, 'package.json');
165
+ if (!existsSync(path))
166
+ return null;
167
+ let manifest;
168
+ try {
169
+ manifest = JSON.parse(readFileSync(path, 'utf8'));
170
+ }
171
+ catch {
172
+ return null;
173
+ }
174
+ return typeof manifest.packageManager === 'string' && manifest.packageManager.length > 0
175
+ ? manifest.packageManager
176
+ : null;
177
+ }
178
+ /** Rule 1 — the manifest, with every `workspace:` range published. */
179
+ export function rewriteManifest(reference, memberDirs) {
180
+ const manifest = withPackageManager(JSON.parse(JSON.stringify(reference.manifest)), packageManagerFor(reference));
181
+ const ranges = [];
182
+ for (const range of workspaceRanges(reference.manifest)) {
183
+ const member = memberVersion(memberDirs, range.name);
184
+ if (member === null) {
185
+ throw new StorefrontInputError(`${range.field}.${range.name} is declared "${range.declared}", but no workspace member ` +
186
+ `of this checkout is called "${range.name}" with a version. A \`workspace:\` range is ` +
187
+ `rewritten from the version its own package declares, and this command will not ` +
188
+ `invent one: a scaffold carrying a range nothing resolves is a storefront that ` +
189
+ `cannot install.`);
190
+ }
191
+ const to = publishedRange(range.declared, member.version);
192
+ manifest[range.field][range.name] = to;
193
+ ranges.push({ field: range.field, name: range.name, from: range.declared, to });
194
+ }
195
+ return { text: `${JSON.stringify(manifest, null, 2)}\n`, ranges };
196
+ }
197
+ /**
198
+ * `packageManager` beside `version`, rather than appended.
199
+ *
200
+ * A new key lands last in JSON.stringify's order, which for the client's own
201
+ * manifest would put the declaration of how to install it underneath every
202
+ * dependency it installs. The insertion is positional and touches no value.
203
+ */
204
+ function withPackageManager(manifest, packageManager) {
205
+ const ordered = {};
206
+ let placed = false;
207
+ for (const [key, value] of Object.entries(manifest)) {
208
+ if (key === 'packageManager')
209
+ continue;
210
+ ordered[key] = value;
211
+ if (key === 'version') {
212
+ ordered['packageManager'] = packageManager;
213
+ placed = true;
214
+ }
215
+ }
216
+ if (!placed)
217
+ return { packageManager, ...ordered };
218
+ return ordered;
219
+ }
220
+ /**
221
+ * Rule 2 — vendor a configuration file the storefront extends, and cut the
222
+ * declarations that cannot come with it.
223
+ *
224
+ * The cut is derived, not listed: each of the vendored file's *own* relative
225
+ * references is resolved, and one whose target is outside the set being vendored
226
+ * is removed together with the declaration that uses it. A JSON `paths` entry
227
+ * and an ES import are the two shapes that occur; anything else is refused, so
228
+ * a base configuration that grows a third shape stops this command rather than
229
+ * being copied out half-rewritten.
230
+ */
231
+ export function vendorConfiguration(reference, storefrontDir, taken = new Set()) {
232
+ const source = resolveTarget(reference.target);
233
+ if (source === null) {
234
+ throw new UnclassifiedReferenceError(`${reference.file} names "${reference.specifier}", which resolves to ${reference.target} ` +
235
+ `— and there is no file there. A reference the scaffold cannot resolve cannot be made ` +
236
+ `standalone.`);
237
+ }
238
+ // The vendored file lands under its own name unless the storefront already
239
+ // has a file of that name — `eslint.config.js` extends `../eslint.config.js`
240
+ // — and then under `<name>.base.<ext>`. CLI 0.15.0 used the name regardless:
241
+ // the plan held two files at one path, the vendored one was written last and
242
+ // replaced the storefront's own, and the rewritten import named the file it
243
+ // was written in.
244
+ const own = source.split(sep).pop();
245
+ const collides = taken.has(own);
246
+ const base = collides ? withBaseInfix(own) : own;
247
+ // The *specifier* keeps the extension the referring file wrote.
248
+ // `vitest.config.mts` names the base configuration `../vitest.config.base.js`
249
+ // although the file is `.ts`, which is the ESM spelling TypeScript requires —
250
+ // rewriting it to `./…​.ts` would be `allowImportingTsExtensions` territory
251
+ // and a type error in the copy.
252
+ const written = reference.specifier.split('/').pop();
253
+ const spelt = collides ? withBaseInfix(written) : written;
254
+ const text = readFileSync(source, 'utf8');
255
+ if (source.endsWith('.json')) {
256
+ const cut = cutForeignJsonPaths(text, dirname(source), storefrontDir);
257
+ return {
258
+ path: base,
259
+ content: cut.text,
260
+ specifier: `./${spelt}`,
261
+ note: cut.dropped.length === 0
262
+ ? `vendored from ${own}${collides ? ` as ${base}` : ''}`
263
+ : `vendored from ${own}${collides ? ` as ${base}` : ''}, without ${String(cut.dropped.length)} ` +
264
+ `${cut.dropped.length === 1 ? 'declaration' : 'declarations'} whose ` +
265
+ `${cut.dropped.length === 1 ? 'target names' : 'targets name'} a directory of the ` +
266
+ `platform repository that a standalone storefront does not have ` +
267
+ `(${cut.dropped.join(', ')})`,
268
+ };
269
+ }
270
+ const cut = cutForeignImports(text, dirname(source), storefrontDir);
271
+ return {
272
+ path: base,
273
+ content: cut.text,
274
+ specifier: `./${spelt}`,
275
+ note: cut.dropped.length === 0
276
+ ? `vendored from ${own}${collides ? ` as ${base}` : ''}`
277
+ : `vendored from ${own}${collides ? ` as ${base}` : ''}, without its import of ${cut.dropped.join(', ')} — ` +
278
+ `${cut.dropped.length === 1 ? 'that module reaches' : 'those modules reach'} into ` +
279
+ `the platform repository, and a standalone storefront installs no part of it`,
280
+ };
281
+ }
282
+ /** `eslint.config.js` -> `eslint.config.base.js`: `.base` before the last extension. */
283
+ function withBaseInfix(name) {
284
+ const dot = name.lastIndexOf('.');
285
+ return dot <= 0 ? `${name}.base` : `${name.slice(0, dot)}.base${name.slice(dot)}`;
286
+ }
287
+ /** `../x.js` may be written for `../x.ts`; try the extensions TypeScript does. */
288
+ function resolveTarget(target) {
289
+ if (existsSync(target) && !target.endsWith(sep))
290
+ return target;
291
+ const swapped = target.replace(/\.js$/, '');
292
+ for (const extension of ['.ts', '.mts', '.cts', '.tsx', '.js', '.mjs', '.cjs']) {
293
+ if (existsSync(swapped + extension))
294
+ return swapped + extension;
295
+ }
296
+ return null;
297
+ }
298
+ /**
299
+ * Drop every `compilerOptions.paths` entry whose target leaves the scaffold.
300
+ *
301
+ * `paths` is the one declaration in a shared `tsconfig` that is repository
302
+ * geometry rather than compiler policy: its targets are directories under
303
+ * `packages/`, which a standalone storefront replaces with installed packages.
304
+ * Left in place they are dead configuration pointing at nothing; TypeScript
305
+ * falls back to node resolution and the scaffold's author is left reading a
306
+ * block that describes a tree they do not have.
307
+ */
308
+ export function cutForeignJsonPaths(text, configDir, storefrontDir) {
309
+ const parsed = JSON.parse(text);
310
+ const paths = parsed.compilerOptions?.paths;
311
+ if (paths === undefined)
312
+ return { text, dropped: [] };
313
+ const kept = {};
314
+ const dropped = [];
315
+ for (const [key, targets] of Object.entries(paths)) {
316
+ const inside = targets.every((target) => {
317
+ const absolute = resolve(configDir, globPrefix(target));
318
+ return absolute === storefrontDir || absolute.startsWith(storefrontDir + sep);
319
+ });
320
+ if (inside)
321
+ kept[key] = targets;
322
+ else
323
+ dropped.push(`paths."${key}"`);
324
+ }
325
+ if (dropped.length === 0)
326
+ return { text, dropped: [] };
327
+ if (Object.keys(kept).length === 0)
328
+ delete parsed.compilerOptions.paths;
329
+ else
330
+ parsed.compilerOptions.paths = kept;
331
+ return { text: `${JSON.stringify(parsed, null, 2)}\n`, dropped };
332
+ }
333
+ /**
334
+ * Drop an ES import whose target leaves the scaffold, and the statements that
335
+ * use what it bound.
336
+ *
337
+ * Deliberately narrow: it removes the import line and any *expression statement*
338
+ * that is a bare call of a removed binding, which is the shape a configuration
339
+ * file's side-effecting guard takes. A removed binding used anywhere else is a
340
+ * refusal — rewriting an expression is not something this command does, and
341
+ * emitting a configuration with a dangling identifier would be worse than
342
+ * stopping.
343
+ */
344
+ export function cutForeignImports(text, fileDir, storefrontDir) {
345
+ const lines = text.split('\n');
346
+ const dropped = [];
347
+ const removedBindings = new Set();
348
+ const removedLines = new Set();
349
+ for (let index = 0; index < lines.length; index += 1) {
350
+ const specifier = /^\s*import\s+([\s\S]*?)\s*from\s*['"](\.[^'"]*)['"];?\s*$/.exec(lines[index]);
351
+ // A multi-line import: join forward until the `from` clause closes.
352
+ let clause = specifier?.[1];
353
+ let path = specifier?.[2];
354
+ let last = index;
355
+ if (specifier === null && /^\s*import\s*\{\s*$/.test(lines[index])) {
356
+ const parts = [];
357
+ let cursor = index + 1;
358
+ while (cursor < lines.length && !/\}\s*from\s*['"]/.test(lines[cursor])) {
359
+ parts.push(lines[cursor]);
360
+ cursor += 1;
361
+ }
362
+ const closing = /^\s*\}\s*from\s*['"]([^'"]+)['"];?\s*$/.exec(lines[cursor] ?? '');
363
+ if (closing !== null && closing[1].startsWith('.')) {
364
+ clause = `{ ${parts.join(' ')} }`;
365
+ path = closing[1];
366
+ last = cursor;
367
+ }
368
+ }
369
+ if (clause === undefined || path === undefined)
370
+ continue;
371
+ const target = resolve(fileDir, globPrefix(path));
372
+ if (target === storefrontDir || target.startsWith(storefrontDir + sep))
373
+ continue;
374
+ for (let line = index; line <= last; line += 1)
375
+ removedLines.add(line);
376
+ for (const name of bindingsOf(clause))
377
+ removedBindings.add(name);
378
+ dropped.push(path);
379
+ index = last;
380
+ }
381
+ if (dropped.length === 0)
382
+ return { text, dropped: [] };
383
+ for (let index = 0; index < lines.length; index += 1) {
384
+ if (removedLines.has(index))
385
+ continue;
386
+ const call = /^\s*([A-Za-z_$][\w$]*)\s*\([^)]*\)\s*;?\s*$/.exec(lines[index]);
387
+ if (call !== null && removedBindings.has(call[1])) {
388
+ removedLines.add(index);
389
+ continue;
390
+ }
391
+ for (const binding of removedBindings) {
392
+ if (new RegExp(`\\b${binding}\\b`).test(lines[index])) {
393
+ throw new UnclassifiedReferenceError(`the configuration this command vendors uses \`${binding}\` on line ` +
394
+ `${String(index + 1)}, and \`${binding}\` comes from an import that reaches into ` +
395
+ `the platform repository. This command removes such an import and a bare call of ` +
396
+ `what it bound, and nothing else: rewriting the expression would be inventing ` +
397
+ `configuration nobody reviewed.`);
398
+ }
399
+ }
400
+ }
401
+ const kept = lines.filter((_, index) => !removedLines.has(index));
402
+ return { text: collapseBlankRun(kept).join('\n'), dropped };
403
+ }
404
+ function bindingsOf(clause) {
405
+ const names = [];
406
+ const braces = /\{([\s\S]*)\}/.exec(clause);
407
+ if (braces !== null) {
408
+ for (const part of braces[1].split(',')) {
409
+ const name = part.trim().split(/\s+as\s+/).pop()?.trim();
410
+ if (name !== undefined && name.length > 0)
411
+ names.push(name);
412
+ }
413
+ }
414
+ const outside = clause.replace(/\{[\s\S]*\}/, '').replace(/\*\s+as\s+/, '');
415
+ for (const part of outside.split(',')) {
416
+ const name = part.trim();
417
+ if (/^[A-Za-z_$][\w$]*$/.test(name))
418
+ names.push(name);
419
+ }
420
+ return names;
421
+ }
422
+ /** Two blank lines left by a removed import read as an editing accident. */
423
+ function collapseBlankRun(lines) {
424
+ const out = [];
425
+ for (const line of lines) {
426
+ if (line.trim() === '' && out.length > 0 && out[out.length - 1].trim() === '')
427
+ continue;
428
+ out.push(line);
429
+ }
430
+ return out;
431
+ }
432
+ /**
433
+ * Rule 3 — a glob naming the workspace's package tree, retargeted at where a
434
+ * standalone application finds those packages.
435
+ *
436
+ * `null` when the glob names something else, so the caller refuses it rather
437
+ * than this function guessing.
438
+ */
439
+ export function retargetPackageGlob(reference, repoRoot, memberDirs, referringFileDir, scaffoldDir) {
440
+ const scope = workspaceScope(memberDirs);
441
+ if (scope === null)
442
+ return null;
443
+ const prefix = reference.target;
444
+ const covers = memberDirs.some((dir) => dir === prefix || dir.startsWith(prefix + sep));
445
+ if (!covers)
446
+ return null;
447
+ const tail = reference.specifier.slice(globPrefix(reference.specifier).length);
448
+ const installed = join(scaffoldDir, 'node_modules', scope);
449
+ const relativePath = relative(referringFileDir, installed).split(sep).join(posix.sep);
450
+ void repoRoot;
451
+ return `${relativePath.startsWith('.') ? relativePath : `./${relativePath}`}${tail}`;
452
+ }
453
+ /**
454
+ * The directories the application's **test** configuration collects from.
455
+ *
456
+ * This is the population rule 4 may omit a file from, and it is derived from the
457
+ * test runner's own `include` globs rather than from a path convention —
458
+ * `test/` is this storefront's name for it and the next one's may not be.
459
+ *
460
+ * **It fails closed on purpose.** An application with no readable test
461
+ * configuration has no test population, so every outward reference rule 4 reaches
462
+ * is a refusal. The other way round — treating "I could not tell" as "not
463
+ * application code" — is how a file that genuinely reaches into the platform
464
+ * repository gets dropped out of a client's storefront in silence, which is the
465
+ * defect this command exists to refuse one layer up.
466
+ */
467
+ export function testRoots(reference) {
468
+ const roots = new Set();
469
+ for (const file of reference.files) {
470
+ if (file.includes('/') || !/^vitest\.config\.[cm]?[jt]s$/.test(file))
471
+ continue;
472
+ const text = readFileSync(join(reference.dir, file), 'utf8');
473
+ const include = /include\s*:\s*\[([^\]]*)\]/.exec(text);
474
+ if (include === null)
475
+ continue;
476
+ for (const match of include[1].matchAll(/['"]([^'"]+)['"]/g)) {
477
+ const prefix = globPrefix(match[1]).replace(/\/$/, '');
478
+ if (prefix.length > 0 && !prefix.startsWith('.'))
479
+ roots.add(prefix);
480
+ }
481
+ }
482
+ return [...roots].sort();
483
+ }
484
+ /**
485
+ * The whole plan: every file the scaffold writes, and what each rewrite did.
486
+ *
487
+ * @param scaffoldDir where the copy will live, used only to express a retargeted
488
+ * glob relative to the file that writes it.
489
+ */
490
+ export function planStorefront(reference, memberDirs, scaffoldDir, options = {}) {
491
+ const references = outwardReferences(reference);
492
+ const byFile = new Map();
493
+ for (const entry of references) {
494
+ byFile.set(entry.file, [...(byFile.get(entry.file) ?? []), entry]);
495
+ }
496
+ const vendored = new Map();
497
+ const rewrites = [];
498
+ const rewrittenText = new Map();
499
+ const omitted = [];
500
+ const roots = testRoots(reference);
501
+ for (const [file, entries] of [...byFile].sort(([a], [b]) => a.localeCompare(b))) {
502
+ let text = readFileSync(join(reference.dir, file), 'utf8');
503
+ let omit = null;
504
+ for (const entry of entries) {
505
+ if (entry.kind === 'css-source') {
506
+ const to = retargetPackageGlob(entry, reference.repoRoot, memberDirs, dirname(join(scaffoldDir, file)), scaffoldDir);
507
+ if (to === null) {
508
+ throw new UnclassifiedReferenceError(refusal(entry));
509
+ }
510
+ text = replaceOnce(text, entry.specifier, to);
511
+ rewrites.push({ ...entry, to });
512
+ continue;
513
+ }
514
+ if (isConfiguration(file)) {
515
+ const plan = vendorConfiguration(entry, reference.dir, new Set(reference.files));
516
+ vendored.set(plan.path, plan);
517
+ text = replaceOnce(text, entry.specifier, plan.specifier);
518
+ rewrites.push({ ...entry, to: plan.specifier });
519
+ continue;
520
+ }
521
+ // Rule 4 — a file that reaches into the repository and is not a
522
+ // configuration the scaffold can vendor. Only a file the application's own
523
+ // test configuration collects may be omitted; anything else is a refusal.
524
+ if (!roots.some((root) => file === root || file.startsWith(`${root}/`))) {
525
+ throw new UnclassifiedReferenceError(refusal(entry));
526
+ }
527
+ omit =
528
+ `it imports "${entry.specifier}", a script of the platform repository whose own ` +
529
+ `imports reach a package a standalone storefront does not install. What it asserts ` +
530
+ `is a property of this repository's layout, which a scaffolded storefront does not have`;
531
+ }
532
+ if (omit !== null)
533
+ omitted.push({ path: file, reason: omit });
534
+ else
535
+ rewrittenText.set(file, text);
536
+ }
537
+ const manifest = rewriteManifest(reference, memberDirs);
538
+ assertVendoredImportsDeclared(vendored, reference);
539
+ const omittedPaths = new Set(omitted.map((entry) => entry.path));
540
+ const registry = options.registry === undefined ? null : normalizeRegistry(options.registry);
541
+ const rewritten = JSON.parse(manifest.text);
542
+ // The reference's own Dockerfile builds from the platform repository's root;
543
+ // the copy gets one that builds in its own tree (`./dockerfile.ts`).
544
+ const rendered = new Map([
545
+ [
546
+ 'Dockerfile',
547
+ {
548
+ content: storefrontDockerfile({
549
+ enginesNode: rewritten.engines?.node,
550
+ packageManager: rewritten.packageManager,
551
+ npmrc: registry !== null,
552
+ }),
553
+ note: 'rendered to build in this tree rather than from the platform repository root',
554
+ },
555
+ ],
556
+ [
557
+ '.dockerignore',
558
+ {
559
+ content: STOREFRONT_DOCKERIGNORE,
560
+ note: 'keeps `.env` and the installed trees out of the image build context',
561
+ },
562
+ ],
563
+ [
564
+ '.gitignore',
565
+ {
566
+ content: storefrontGitignore(reference.files.includes('.gitignore')
567
+ ? readFileSync(join(reference.dir, '.gitignore'), 'utf8')
568
+ : null),
569
+ note: 'keeps `.env` and the installed and built trees out of this repository',
570
+ },
571
+ ],
572
+ ]);
573
+ const files = [];
574
+ for (const file of [...reference.files].sort()) {
575
+ if (omittedPaths.has(file) || rendered.has(file))
576
+ continue;
577
+ if (file === 'package.json') {
578
+ files.push({
579
+ path: file,
580
+ source: null,
581
+ content: manifest.text,
582
+ note: `${String(manifest.ranges.length)} workspace: ${manifest.ranges.length === 1 ? 'range' : 'ranges'} published`,
583
+ });
584
+ continue;
585
+ }
586
+ const text = rewrittenText.get(file);
587
+ if (text !== undefined) {
588
+ const notes = (byFile.get(file) ?? []).map((entry) => entry.specifier);
589
+ files.push({
590
+ path: file,
591
+ source: join(reference.dir, file),
592
+ content: text,
593
+ note: `rewrote ${notes.join(', ')}`,
594
+ });
595
+ continue;
596
+ }
597
+ files.push({ path: file, source: join(reference.dir, file), content: null, note: null });
598
+ }
599
+ for (const [path, plan] of [...vendored].sort(([a], [b]) => a.localeCompare(b))) {
600
+ files.push({ path, source: null, content: plan.content, note: plan.note });
601
+ }
602
+ for (const [path, file] of rendered) {
603
+ files.push({ path, source: null, content: file.content, note: file.note });
604
+ }
605
+ // The registry, when there is one. It is a file the copy gains rather than a
606
+ // rewrite of one it has: the reference storefront installs from the workspace
607
+ // and holds no `.npmrc` of its own, so there is nothing here to overwrite —
608
+ // and a scaffold that already carried one would be a declaration the copy
609
+ // population, not this option, is answerable for.
610
+ if (registry !== null) {
611
+ const scopes = installedScopes(reference.manifest);
612
+ files.push({
613
+ path: '.npmrc',
614
+ source: null,
615
+ content: npmrcContent(registry, scopes),
616
+ note: `installs ${scopes.join(', ')} from ${registry}, with the token as ` +
617
+ `\${${TOKEN_VARIABLE}} — an environment reference pnpm expands at install time, so ` +
618
+ `this file holds no secret`,
619
+ });
620
+ }
621
+ assertEachPathOnce(files);
622
+ return {
623
+ files: files.sort((a, b) => a.path.localeCompare(b.path)),
624
+ ranges: manifest.ranges,
625
+ rewrites,
626
+ omitted,
627
+ registry,
628
+ };
629
+ }
630
+ /**
631
+ * Rule 2's other half: a vendored configuration's bare imports are declared by
632
+ * the scaffold's own manifest.
633
+ *
634
+ * In this repository a configuration the storefront extends resolves its
635
+ * packages through the manifest *beside it* — the root one. Vendored, the same
636
+ * text resolves them through the storefront's, and nothing about the copy
637
+ * changes that. CLI 0.15.0 shipped a scaffold whose vendored ESLint
638
+ * configuration imported four packages its manifest never named, so the first
639
+ * `pnpm run lint` on a stranger's machine failed to load it. The repair is in the
640
+ * reference storefront's manifest; this refusal is what stops it recurring.
641
+ */
642
+ function assertVendoredImportsDeclared(vendored, reference) {
643
+ const declared = declaredPackages(reference.manifest);
644
+ for (const [path, plan] of [...vendored].sort(([a], [b]) => a.localeCompare(b))) {
645
+ const missing = importedPackages(plan.content).filter((name) => !declared.has(name));
646
+ if (missing.length === 0)
647
+ continue;
648
+ throw new UndeclaredImportError(`the configuration vendored as ${path} imports ` +
649
+ `${missing.map((name) => `"${name}"`).join(', ')}, which ` +
650
+ `${reference.dir}/package.json does not declare. In this repository that import ` +
651
+ `resolves through the manifest beside the file it was vendored from; in the scaffold ` +
652
+ `it resolves through the storefront's own, so the copy would fail to load on its ` +
653
+ `first install. Declare ${missing.length === 1 ? 'it' : 'them'} in the reference ` +
654
+ `storefront's devDependencies at the version this repository already uses.`);
655
+ }
656
+ }
657
+ /**
658
+ * A plan writes each path once.
659
+ *
660
+ * Two entries at one path are two authors of one file, and the writer keeps
661
+ * whichever comes last without saying so — which is how CLI 0.15.0's scaffold
662
+ * lost the storefront's own `eslint.config.js` to the vendored root one. So it
663
+ * is a refusal before anything is written, naming both sides.
664
+ */
665
+ function assertEachPathOnce(files) {
666
+ const seen = new Map();
667
+ for (const file of files) {
668
+ const first = seen.get(file.path);
669
+ if (first === undefined) {
670
+ seen.set(file.path, file);
671
+ continue;
672
+ }
673
+ const describe = (entry) => entry.note ?? (entry.source === null ? 'rendered' : `copied from ${entry.source}`);
674
+ throw new StorefrontInputError(`this run would write ${file.path} twice (${describe(first)}; ${describe(file)}), and ` +
675
+ `the second would silently replace the first. Rename or remove one of them in the ` +
676
+ `reference storefront, or drop the option that renders the other.`);
677
+ }
678
+ }
679
+ function refusal(entry) {
680
+ return (`${entry.file} names "${entry.specifier}", which resolves to ${entry.target} — above the ` +
681
+ `storefront directory. This command rewrites a \`workspace:\` range, a configuration file ` +
682
+ `the storefront extends, and a glob naming the workspace's package tree; "${entry.specifier}" ` +
683
+ `is none of those. Copying it out unchanged would produce a storefront that names a ` +
684
+ `directory of the platform repository, which is the one thing this command exists to ` +
685
+ `prevent. Either make the declaration internal to the storefront, or add the rule that ` +
686
+ `makes it standalone and its red proof.`);
687
+ }
688
+ /** A configuration file is one the application is configured by, not built from. */
689
+ function isConfiguration(file) {
690
+ return !file.includes('/') && /(^|\.)(tsconfig[^/]*\.json|[^/]*\.config\.[cm]?[jt]s)$/.test(file);
691
+ }
692
+ function replaceOnce(text, from, to) {
693
+ const index = text.indexOf(from);
694
+ if (index === -1) {
695
+ throw new UnclassifiedReferenceError(`"${from}" is no longer in the text this run is rewriting. That cannot happen unless two ` +
696
+ `rules edited one file; it is reported rather than written out.`);
697
+ }
698
+ return text.slice(0, index) + to + text.slice(index + from.length);
699
+ }
700
+ export { DEPENDENCY_FIELDS };
701
+ //# sourceMappingURL=rewrite.js.map