@astryxdesign/cli 0.7.2-canary.fe2c655 → 0.7.2

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 (509) hide show
  1. package/CHANGELOG.md +119 -0
  2. package/README.md +175 -154
  3. package/api/build/_adapter.d.mts +8 -0
  4. package/api/build/_adapter.mjs +12 -1
  5. package/api/build/build.doc.mjs +4 -0
  6. package/api/build/help/help.mjs +1 -1
  7. package/api/build/kit/kit.mjs +3 -11
  8. package/api/component/_adapter.d.mts +72 -1
  9. package/api/component/_adapter.mjs +212 -18
  10. package/api/component/component.doc.mjs +6 -1
  11. package/api/component/component.mjs +82 -15
  12. package/api/component/component.test.mjs +80 -0
  13. package/api/component/doc-links.test.mjs +386 -0
  14. package/api/component/integration-export-name.test.mjs +644 -0
  15. package/api/component/list/list.mjs +42 -4
  16. package/api/discover/_adapter.d.mts +132 -12
  17. package/api/discover/_adapter.mjs +488 -27
  18. package/api/discover/_adapter.test.mjs +599 -17
  19. package/api/discover/_catalog-view.d.mts +16 -5
  20. package/api/discover/_catalog-view.mjs +32 -8
  21. package/api/discover/detail/doc/doc.mjs +9 -1
  22. package/api/discover/discover.d.mts +11 -0
  23. package/api/discover/discover.doc.mjs +9 -7
  24. package/api/discover/discover.mjs +121 -19
  25. package/api/discover/discover.type.d.mts +20 -7
  26. package/api/discover/discover.type.mjs +17 -7
  27. package/api/discover/list/list.d.mts +4 -3
  28. package/api/discover/list/list.mjs +17 -10
  29. package/api/docs/_adapter.d.mts +74 -0
  30. package/api/docs/_adapter.mjs +553 -16
  31. package/api/docs/docs.doc.mjs +2 -1
  32. package/api/docs/docs.mjs +2 -1
  33. package/api/docs/docs.test.mjs +5 -2
  34. package/api/docs/integration-tree.test.mjs +22 -0
  35. package/api/docs/integrationDocs.test.mjs +124 -0
  36. package/api/docs/list/list.mjs +12 -2
  37. package/api/docs/reference-blocks.test.mjs +1 -3
  38. package/api/doctor/_adapter.d.mts +108 -0
  39. package/api/doctor/_adapter.mjs +223 -4
  40. package/api/doctor/doctor.d.mts +199 -0
  41. package/api/doctor/doctor.doc.mjs +3 -2
  42. package/api/doctor/doctor.mjs +530 -34
  43. package/api/doctor/doctor.test.mjs +180 -14
  44. package/api/doctor/release-checks.test.mjs +156 -0
  45. package/api/doctor/theme-checks.mjs +17 -4
  46. package/api/doctor/theme-checks.test.mjs +223 -7
  47. package/api/error.d.mts +10 -0
  48. package/api/error.mjs +25 -0
  49. package/api/gap-report/gap-report.d.mts +3 -0
  50. package/api/gap-report/gap-report.doc.mjs +11 -3
  51. package/api/gap-report/gap-report.mjs +219 -52
  52. package/api/gap-report/gap-report.test.mjs +233 -0
  53. package/api/gap-report/gap-report.type.d.mts +41 -0
  54. package/api/gap-report/gap-report.type.mjs +18 -0
  55. package/api/hook/_adapter.mjs +3 -11
  56. package/api/hook/hook.doc.mjs +4 -0
  57. package/api/hook/list/list.d.mts +1 -1
  58. package/api/index.d.mts +2 -0
  59. package/api/index.mjs +2 -0
  60. package/api/init/_adapter.d.mts +22 -0
  61. package/api/init/_adapter.mjs +59 -0
  62. package/api/init/init.d.mts +7 -5
  63. package/api/init/init.doc.mjs +28 -7
  64. package/api/init/init.mjs +28 -4
  65. package/api/init/init.type.d.mts +48 -3
  66. package/api/init/init.type.mjs +37 -3
  67. package/api/init/run/run.d.mts +1 -1
  68. package/api/init/run/run.mjs +17 -6
  69. package/api/init/user/user.d.mts +14 -0
  70. package/api/init/user/user.mjs +87 -0
  71. package/api/init/user/user.test.mjs +232 -0
  72. package/api/integration/_adapter.d.mts +45 -0
  73. package/api/integration/_adapter.mjs +112 -0
  74. package/api/integration/add-contribution.component-names.test.mjs +66 -0
  75. package/api/integration/add-contribution.mjs +8 -4
  76. package/api/integration/add-contribution.test.mjs +4 -2
  77. package/api/integration/authoring-checks.mjs +110 -6
  78. package/api/integration/authoring-checks.test.mjs +808 -0
  79. package/api/integration/authoring-checks.type.d.mts +143 -0
  80. package/api/integration/authoring-checks.type.mjs +74 -2
  81. package/api/integration/check/check.d.mts +96 -0
  82. package/api/integration/check/check.mjs +357 -0
  83. package/api/integration/check/check.test.mjs +489 -0
  84. package/api/integration/integration-check.type.d.mts +118 -0
  85. package/api/integration/integration-check.type.mjs +84 -0
  86. package/api/integration/integrationCheck.doc.d.mts +10 -0
  87. package/api/integration/integrationCheck.doc.mjs +73 -0
  88. package/api/integration/integrationComponentConflicts.doc.mjs +45 -6
  89. package/api/integration/integrationDocConflicts.doc.mjs +22 -5
  90. package/api/integration/pack-check.mjs +364 -120
  91. package/api/integration/pack-check.test.mjs +730 -10
  92. package/api/integration/validate-integration-fixes.test.mjs +67 -0
  93. package/api/integration/validate-integration.d.mts +8 -0
  94. package/api/integration/validate-integration.mjs +63 -9
  95. package/api/integration/validate-integration.test.mjs +88 -8
  96. package/api/integration/validate-integration.type.d.mts +16 -0
  97. package/api/integration/validate-integration.type.mjs +14 -1
  98. package/api/integration/validate-unread-theme-folders.test.mjs +3 -2
  99. package/api/integration/validateIntegration.doc.mjs +19 -3
  100. package/api/search/_adapter.d.mts +11 -0
  101. package/api/search/_adapter.mjs +25 -0
  102. package/api/search/search.d.mts +82 -13
  103. package/api/search/search.doc.mjs +8 -3
  104. package/api/search/search.domain-priority.test.mjs +108 -18
  105. package/api/search/search.integration-check.test.mjs +24 -0
  106. package/api/search/search.mjs +645 -64
  107. package/api/search/search.test.mjs +179 -1
  108. package/api/search/search.type.d.mts +14 -1
  109. package/api/search/search.type.mjs +6 -1
  110. package/api/swizzle/_adapter.mjs +2 -2
  111. package/api/swizzle/copy/copy.mjs +29 -15
  112. package/api/template/template-integration.test.mjs +1 -1
  113. package/api/template/template.test.mjs +120 -3
  114. package/api/theme/_adapter.d.mts +16 -0
  115. package/api/theme/_adapter.mjs +32 -5
  116. package/api/theme/build/build.d.mts +2 -1
  117. package/api/theme/build/build.family.test.mjs +64 -0
  118. package/api/theme/build/build.mjs +250 -38
  119. package/api/theme/build/build.packed-old-core.test.mjs +20 -3
  120. package/api/theme/build/font-warning.mjs +5 -3
  121. package/api/theme/build/font-warning.test.mjs +2 -1
  122. package/api/theme/remove/remove.test.mjs +2 -2
  123. package/api/theme/targets/targets.mjs +3 -10
  124. package/api/theme/themeBuild.doc.mjs +4 -4
  125. package/api/theme/themeTargets.doc.mjs +4 -0
  126. package/api/theme/use/use.test.mjs +1 -1
  127. package/api/upgrade/_adapter.d.mts +40 -2
  128. package/api/upgrade/_adapter.mjs +118 -5
  129. package/api/upgrade/run/cli-behind-core.test.mjs +438 -0
  130. package/api/upgrade/run/run.mjs +35 -2
  131. package/api/upgrade/status/status.d.mts +21 -5
  132. package/api/upgrade/status/status.mjs +45 -8
  133. package/api/upgrade/upgrade.doc.mjs +6 -3
  134. package/api/upgrade/upgrade.mjs +5 -1
  135. package/api/upgrade/upgrade.type.d.mts +23 -0
  136. package/api/upgrade/upgrade.type.mjs +16 -1
  137. package/assets/codemods/__tests__/registry.test.mjs +1 -0
  138. package/assets/codemods/registry.mjs +1 -0
  139. package/assets/codemods/runner.mjs +7 -1
  140. package/assets/codemods/transforms/v0.7.2/__tests__/migrate-list-edge-compensation-to-edge.test.mjs +120 -0
  141. package/assets/codemods/transforms/v0.7.2/index.mjs +20 -0
  142. package/assets/codemods/transforms/v0.7.2/migrate-list-edge-compensation-to-edge.mjs +198 -0
  143. package/assets/discover/official-packages.json +367 -0
  144. package/assets/docs/README.md +10 -0
  145. package/assets/docs/author-a-theme.doc.mjs +3 -3
  146. package/assets/docs/browser-support.doc.mjs +1 -1
  147. package/assets/docs/getting-started.doc.mjs +26 -6
  148. package/assets/docs/styling-overview.doc.mjs +1 -1
  149. package/assets/docs/theme.doc.dense.mjs +1 -1
  150. package/assets/docs/theme.doc.mjs +2 -2
  151. package/assets/docs/theme.doc.zh.mjs +1 -1
  152. package/assets/docs/tree/add-a-component.doc.mjs +22 -2
  153. package/assets/docs/tree/add-a-theme.doc.mjs +13 -3
  154. package/assets/docs/tree/add-a-topic.doc.mjs +54 -9
  155. package/assets/docs/tree/agent-guidance.doc.mjs +19 -5
  156. package/assets/docs/tree/block-template.doc.mjs +8 -20
  157. package/assets/docs/tree/build-the-template.doc.mjs +1 -1
  158. package/assets/docs/tree/building-blocks.doc.mjs +4 -0
  159. package/assets/docs/tree/check-the-props.doc.mjs +201 -0
  160. package/assets/docs/tree/check-your-docs.doc.mjs +69 -11
  161. package/assets/docs/tree/checks.doc.mjs +32 -24
  162. package/assets/docs/tree/ci-and-containers.doc.mjs +88 -0
  163. package/assets/docs/tree/cli-command.doc.mjs +142 -0
  164. package/assets/docs/tree/cli.doc.mjs +6 -0
  165. package/assets/docs/tree/codemods.doc.mjs +17 -7
  166. package/assets/docs/tree/commands.doc.mjs +7 -1
  167. package/assets/docs/tree/component-family.doc.mjs +8 -6
  168. package/assets/docs/tree/component-imports.doc.mjs +21 -3
  169. package/assets/docs/tree/components.doc.mjs +7 -1
  170. package/assets/docs/tree/computer-agent-guide.doc.mjs +160 -0
  171. package/assets/docs/tree/computer-integrations.doc.mjs +93 -0
  172. package/assets/docs/tree/configuration.doc.mjs +7 -3
  173. package/assets/docs/tree/debug-and-gap-reports.doc.mjs +41 -22
  174. package/assets/docs/tree/define-the-theme.doc.mjs +6 -5
  175. package/assets/docs/tree/describe-the-component.doc.mjs +3 -3
  176. package/assets/docs/tree/docs.doc.mjs +9 -3
  177. package/assets/docs/tree/document-the-template.doc.mjs +1 -1
  178. package/assets/docs/tree/document-the-theme.doc.mjs +3 -3
  179. package/assets/docs/tree/export-template-assets.doc.mjs +1 -1
  180. package/assets/docs/tree/extend-or-replace.doc.mjs +19 -9
  181. package/assets/docs/tree/fonts-and-assets.doc.mjs +2 -2
  182. package/assets/docs/tree/generate-a-palette.doc.mjs +7 -5
  183. package/assets/docs/tree/global-integrations.doc.mjs +124 -0
  184. package/assets/docs/tree/global.doc.mjs +131 -0
  185. package/assets/docs/tree/grade-template-with-agent.doc.mjs +5 -5
  186. package/assets/docs/tree/install-once.doc.mjs +105 -0
  187. package/assets/docs/tree/integrations.doc.mjs +13 -1
  188. package/assets/docs/tree/layout-spacing.doc.mjs +2 -3
  189. package/assets/docs/tree/layout.doc.mjs +6 -6
  190. package/assets/docs/tree/links.doc.mjs +7 -6
  191. package/assets/docs/tree/migration-setup.doc.mjs +3 -2
  192. package/assets/docs/tree/migration-verification.doc.mjs +0 -1
  193. package/assets/docs/tree/migration.doc.mjs +0 -1
  194. package/assets/docs/tree/monorepos.doc.mjs +84 -0
  195. package/assets/docs/tree/package-and-test.doc.mjs +1 -1
  196. package/assets/docs/tree/page-template.doc.mjs +4 -8
  197. package/assets/docs/tree/problems.doc.mjs +205 -0
  198. package/assets/docs/tree/project-global-or-both.doc.mjs +131 -0
  199. package/assets/docs/tree/publishing.doc.mjs +6 -6
  200. package/assets/docs/tree/quick-start.doc.mjs +53 -27
  201. package/assets/docs/tree/reference.doc.mjs +192 -0
  202. package/assets/docs/tree/replace-a-core-component.doc.mjs +15 -7
  203. package/assets/docs/tree/replace-a-core-template.doc.mjs +10 -12
  204. package/assets/docs/tree/scaffold.doc.mjs +1 -1
  205. package/assets/docs/tree/sections-and-placement.doc.mjs +9 -11
  206. package/assets/docs/tree/see-it-in-an-app.doc.mjs +17 -5
  207. package/assets/docs/tree/short-and-findable.doc.mjs +9 -8
  208. package/assets/docs/tree/single-component.doc.mjs +15 -6
  209. package/assets/docs/tree/start-a-template.doc.mjs +18 -8
  210. package/assets/docs/tree/subcomponent.doc.mjs +6 -6
  211. package/assets/docs/tree/template-assets.doc.mjs +2 -2
  212. package/assets/docs/tree/template-doc-overview.doc.mjs +6 -17
  213. package/assets/docs/tree/template-fonts.doc.mjs +1 -1
  214. package/assets/docs/tree/template-icons.doc.mjs +1 -1
  215. package/assets/docs/tree/template-images-media.doc.mjs +1 -1
  216. package/assets/docs/tree/template-styles.doc.mjs +2 -2
  217. package/assets/docs/tree/templates.doc.mjs +7 -1
  218. package/assets/docs/tree/test-in-an-app.doc.mjs +7 -7
  219. package/assets/docs/tree/test-template-in-app.doc.mjs +5 -5
  220. package/assets/docs/tree/themes.doc.mjs +4 -0
  221. package/assets/docs/tree/tokens-and-setup.doc.mjs +19 -15
  222. package/assets/docs/tree/troubleshooting.doc.mjs +29 -13
  223. package/assets/docs/tree/type-scale.doc.mjs +3 -3
  224. package/assets/docs/tree/uninstall.doc.mjs +109 -0
  225. package/assets/docs/tree/updates.doc.mjs +92 -0
  226. package/assets/docs/tree/upgrading.doc.mjs +6 -6
  227. package/assets/docs/tree/use-a-theme-in-an-app.doc.mjs +14 -2
  228. package/assets/docs/tree/verify-packed-template.doc.mjs +3 -3
  229. package/assets/docs/tree/versioning.doc.mjs +10 -9
  230. package/assets/docs/tree/who-answers.doc.mjs +119 -0
  231. package/assets/docs/tree/write-the-template-file.doc.mjs +7 -6
  232. package/assets/docs/use-a-theme.doc.mjs +2 -2
  233. package/assets/docs/working-with-ai.doc.mjs +66 -13
  234. package/assets/theme.template.ts +1 -1
  235. package/authoring/codemod/codemod.doc.mjs +7 -3
  236. package/authoring/config/config.doc.mjs +9 -6
  237. package/authoring/config/type.ts +4 -2
  238. package/authoring/debug/parse.d.mts +5 -5
  239. package/authoring/discover/discover.doc.mjs +7 -1
  240. package/authoring/doctypes/_schema.d.mts +8 -3
  241. package/authoring/doctypes/_schema.mjs +1 -0
  242. package/authoring/doctypes/base/graph-fields.doc.mjs +6 -4
  243. package/authoring/doctypes/command/command.doc.mjs +20 -12
  244. package/authoring/doctypes/command/type.ts +14 -0
  245. package/authoring/doctypes/component/component.doc.mjs +30 -27
  246. package/authoring/doctypes/component/type.ts +21 -8
  247. package/authoring/doctypes/enum/enum.doc.mjs +7 -4
  248. package/authoring/doctypes/function/function.doc.mjs +9 -8
  249. package/authoring/doctypes/hook/hook.doc.mjs +5 -4
  250. package/authoring/doctypes/hook/type.ts +4 -0
  251. package/authoring/doctypes/namespace/namespace.doc.mjs +7 -6
  252. package/authoring/doctypes/reference/reference.doc.mjs +12 -11
  253. package/authoring/doctypes/schema/schema.doc.mjs +9 -9
  254. package/authoring/doctypes/template/integration-template.doc.d.mts +11 -0
  255. package/authoring/doctypes/template/integration-template.doc.mjs +49 -0
  256. package/authoring/doctypes/template/parse.d.mts +6 -2
  257. package/authoring/doctypes/template/parse.mjs +3 -1
  258. package/authoring/doctypes/template/template.doc.mjs +3 -3
  259. package/authoring/doctypes/template/type.ts +22 -0
  260. package/authoring/doctypes/theme/theme.doc.mjs +2 -2
  261. package/authoring/gap-report/gap-report.doc.mjs +2 -2
  262. package/authoring/identity/identity.doc.mjs +3 -3
  263. package/authoring/index.d.ts +2 -0
  264. package/authoring/integration/integration.doc.mjs +30 -6
  265. package/authoring/integration/parse.test.mjs +21 -0
  266. package/authoring/integration/schema.d.mts +16 -3
  267. package/authoring/integration/schema.mjs +34 -2
  268. package/authoring/integration/type.ts +12 -0
  269. package/clients/cli/bin/astryx.mjs +20 -3
  270. package/clients/cli/cli-command.test.mjs +166 -0
  271. package/clients/cli/commands/blog.doc.mjs +1 -0
  272. package/clients/cli/commands/build-theme.batch-report.test.mjs +17 -3
  273. package/clients/cli/commands/build-theme.font-warning.test.mjs +3 -3
  274. package/clients/cli/commands/build-theme.mjs +26 -13
  275. package/clients/cli/commands/build-theme.path-safety.test.mjs +224 -6
  276. package/clients/cli/commands/build-theme.registry.test.mjs +5 -2
  277. package/clients/cli/commands/build.doc.mjs +1 -0
  278. package/clients/cli/commands/build.exit-codes-doc.test.mjs +4 -0
  279. package/clients/cli/commands/cli-postinstall.test.mjs +49 -1
  280. package/clients/cli/commands/component.doc.mjs +1 -0
  281. package/clients/cli/commands/discover.broken-integration.test.mjs +11 -7
  282. package/clients/cli/commands/discover.doc.mjs +9 -1
  283. package/clients/cli/commands/discover.mjs +144 -93
  284. package/clients/cli/commands/discover.no-source.test.mjs +448 -33
  285. package/clients/cli/commands/discover.sources.test.mjs +20 -1
  286. package/clients/cli/commands/docs.doc.mjs +1 -0
  287. package/clients/cli/commands/docs.mjs +49 -19
  288. package/clients/cli/commands/docs.test.mjs +2 -2
  289. package/clients/cli/commands/doctor-integration-components.doc.mjs +19 -4
  290. package/clients/cli/commands/doctor-integration-docs.doc.mjs +20 -5
  291. package/clients/cli/commands/doctor-integration-templates.doc.mjs +1 -0
  292. package/clients/cli/commands/doctor-integration-validate.doc.mjs +22 -2
  293. package/clients/cli/commands/doctor-integration.test.mjs +888 -3
  294. package/clients/cli/commands/doctor.doc.mjs +12 -2
  295. package/clients/cli/commands/doctor.mjs +292 -7
  296. package/clients/cli/commands/doctor.test.mjs +10 -4
  297. package/clients/cli/commands/gap-report.doc.mjs +15 -2
  298. package/clients/cli/commands/gap-report.mjs +24 -2
  299. package/clients/cli/commands/gap-report.test.mjs +79 -0
  300. package/clients/cli/commands/hook.doc.mjs +1 -0
  301. package/clients/cli/commands/init.behavior.test.mjs +5 -0
  302. package/clients/cli/commands/init.doc.mjs +29 -3
  303. package/clients/cli/commands/integration-add.doc.mjs +7 -0
  304. package/clients/cli/commands/integration-authoring.test.mjs +49 -3
  305. package/clients/cli/commands/integration-check.doc.mjs +93 -0
  306. package/clients/cli/commands/integration-check.test.mjs +441 -0
  307. package/clients/cli/commands/integration-pack.doc.mjs +8 -1
  308. package/clients/cli/commands/integration-verify.doc.mjs +8 -1
  309. package/clients/cli/commands/integration.doc.mjs +6 -2
  310. package/clients/cli/commands/integration.mjs +119 -7
  311. package/clients/cli/commands/json-contract.test.mjs +11 -2
  312. package/clients/cli/commands/manifest.doc.mjs +1 -0
  313. package/clients/cli/commands/outside-project.test.mjs +774 -0
  314. package/clients/cli/commands/search.doc.mjs +1 -0
  315. package/clients/cli/commands/search.mjs +16 -11
  316. package/clients/cli/commands/search.test.mjs +429 -296
  317. package/clients/cli/commands/setup-nudge.test.mjs +102 -2
  318. package/clients/cli/commands/swizzle.doc.mjs +7 -0
  319. package/clients/cli/commands/swizzle.mjs +5 -3
  320. package/clients/cli/commands/swizzle.routing.test.mjs +19 -2
  321. package/clients/cli/commands/template.doc.mjs +1 -0
  322. package/clients/cli/commands/text-json-parity.test.mjs +5 -0
  323. package/clients/cli/commands/theme-add-lifecycle.test.mjs +3 -3
  324. package/clients/cli/commands/theme-add.doc.mjs +8 -1
  325. package/clients/cli/commands/theme-build.doc.mjs +3 -2
  326. package/clients/cli/commands/theme-eject.doc.mjs +1 -0
  327. package/clients/cli/commands/theme-list.behavior.test.mjs +6 -0
  328. package/clients/cli/commands/theme-list.doc.mjs +1 -0
  329. package/clients/cli/commands/theme-palette-generate.doc.mjs +1 -0
  330. package/clients/cli/commands/theme-remove.doc.mjs +7 -0
  331. package/clients/cli/commands/theme-targets.doc.mjs +1 -0
  332. package/clients/cli/commands/theme-template.doc.mjs +1 -0
  333. package/clients/cli/commands/theme-use.doc.mjs +7 -0
  334. package/clients/cli/commands/upgrade.config-ordering.test.mjs +2 -1
  335. package/clients/cli/commands/upgrade.doc.mjs +22 -1
  336. package/clients/cli/commands/upgrade.file-protection.test.mjs +3 -2
  337. package/clients/cli/commands/upgrade.hook-output.test.mjs +2 -1
  338. package/clients/cli/commands/upgrade.older-cli.test.mjs +160 -0
  339. package/clients/cli/index.mjs +112 -16
  340. package/clients/cli/lib/cli-error.mjs +4 -1
  341. package/clients/cli/lib/component-format.test.mjs +1 -1
  342. package/clients/cli/lib/define-command.mjs +2 -2
  343. package/clients/cli/lib/json-shim.mjs +3 -1
  344. package/clients/cli/lib/manifest.d.ts +9 -0
  345. package/clients/cli/lib/manifest.mjs +17 -1
  346. package/clients/cli/lib/manifest.test.mjs +25 -0
  347. package/foundation/agent-docs/agent-doc-state.d.mts +35 -6
  348. package/foundation/agent-docs/agent-doc-state.mjs +66 -6
  349. package/foundation/agent-docs/agent-docs.d.mts +4 -3
  350. package/foundation/agent-docs/agent-docs.mjs +11 -9
  351. package/foundation/agent-docs/computer-agent-text.d.mts +133 -0
  352. package/foundation/agent-docs/computer-agent-text.mjs +623 -0
  353. package/foundation/agent-docs/computer-agent-text.test.mjs +602 -0
  354. package/foundation/config/project.d.mts +35 -3
  355. package/foundation/config/project.mjs +226 -7
  356. package/foundation/config/project.test.mjs +66 -0
  357. package/foundation/config/theme-state.mjs +5 -4
  358. package/foundation/discovery/authoring-self-docs.mjs +2 -1
  359. package/foundation/discovery/cli-self-docs.mjs +20 -3
  360. package/foundation/discovery/cli-self-docs.test.mjs +3 -2
  361. package/foundation/discovery/component-discovery.d.mts +190 -10
  362. package/foundation/discovery/component-discovery.export-names.test.mjs +760 -0
  363. package/foundation/discovery/component-discovery.mjs +864 -56
  364. package/foundation/discovery/component-discovery.test.mjs +96 -0
  365. package/foundation/discovery/component-replacement.mjs +20 -1
  366. package/foundation/discovery/component-replacement.test.mjs +40 -0
  367. package/foundation/discovery/copied-passages.d.mts +216 -0
  368. package/foundation/discovery/copied-passages.mjs +720 -0
  369. package/foundation/discovery/copied-passages.test.mjs +124 -0
  370. package/foundation/discovery/doc-consistency.d.mts +34 -0
  371. package/foundation/discovery/doc-consistency.mjs +513 -0
  372. package/foundation/discovery/doc-consistency.test.mjs +347 -0
  373. package/foundation/discovery/doc-fluff.d.mts +112 -0
  374. package/foundation/discovery/doc-fluff.mjs +328 -0
  375. package/foundation/discovery/doc-fluff.test.mjs +142 -0
  376. package/foundation/discovery/doc-types.d.mts +157 -0
  377. package/foundation/discovery/doc-types.mjs +1231 -0
  378. package/foundation/discovery/doc-types.test.mjs +744 -0
  379. package/foundation/discovery/docs-discovery.d.mts +88 -0
  380. package/foundation/discovery/docs-discovery.mjs +83 -2
  381. package/foundation/discovery/integration-doc-files.d.mts +22 -0
  382. package/foundation/discovery/integration-doc-files.mjs +231 -0
  383. package/foundation/discovery/integration-doc-files.test.mjs +246 -0
  384. package/foundation/discovery/module-exports.d.mts +27 -0
  385. package/foundation/discovery/module-exports.mjs +356 -31
  386. package/foundation/discovery/module-exports.test.mjs +172 -0
  387. package/foundation/discovery/package-tsconfig.d.mts +14 -0
  388. package/foundation/discovery/package-tsconfig.mjs +228 -0
  389. package/foundation/discovery/package-tsconfig.test.mjs +210 -0
  390. package/foundation/discovery/project-typescript.d.mts +32 -0
  391. package/foundation/discovery/project-typescript.mjs +89 -0
  392. package/foundation/discovery/prop-drift.d.mts +297 -0
  393. package/foundation/discovery/prop-drift.mjs +2428 -0
  394. package/foundation/discovery/prop-drift.test.mjs +2337 -0
  395. package/foundation/discovery/runner-allowlist.d.mts +40 -0
  396. package/foundation/discovery/runner-allowlist.mjs +53 -0
  397. package/foundation/discovery/stray-pointers.d.mts +52 -0
  398. package/foundation/discovery/stray-pointers.mjs +293 -0
  399. package/foundation/discovery/stray-pointers.test.mjs +86 -0
  400. package/foundation/discovery/template-adapter.mjs +74 -5
  401. package/foundation/discovery/template-needs.mjs +5 -2
  402. package/foundation/discovery/theme-imports.mjs +8 -4
  403. package/foundation/discovery/theme-imports.test.mjs +1 -1
  404. package/foundation/discovery/type-match.d.mts +53 -0
  405. package/foundation/discovery/type-match.mjs +660 -0
  406. package/foundation/discovery/type-match.test.mjs +169 -0
  407. package/foundation/discovery/type-text.d.mts +68 -0
  408. package/foundation/discovery/type-text.mjs +658 -0
  409. package/foundation/discovery/type-text.test.mjs +196 -0
  410. package/foundation/discovery/unresolved-references.d.mts +62 -0
  411. package/foundation/discovery/unresolved-references.mjs +790 -0
  412. package/foundation/discovery/unresolved-references.test.mjs +567 -0
  413. package/foundation/doc-compiler/doc-loads.test.mjs +51 -1
  414. package/foundation/doc-compiler/inputs.mjs +27 -1
  415. package/foundation/doc-compiler/inputs.test.mjs +0 -1
  416. package/foundation/doc-compiler/links.d.mts +41 -5
  417. package/foundation/doc-compiler/links.mjs +167 -28
  418. package/foundation/doc-compiler/links.test.mjs +97 -4
  419. package/foundation/doc-compiler/read.d.mts +1 -1
  420. package/foundation/doc-compiler/tree.mjs +30 -1
  421. package/foundation/doc-compiler/tree.test.mjs +8 -1
  422. package/foundation/env/cli-command.d.mts +83 -0
  423. package/foundation/env/cli-command.mjs +152 -0
  424. package/foundation/env/cli-command.test.mjs +129 -0
  425. package/foundation/env/node-version.test.mjs +15 -3
  426. package/foundation/env/package-manager.d.mts +93 -9
  427. package/foundation/env/package-manager.global.test.mjs +66 -0
  428. package/foundation/env/package-manager.mjs +184 -13
  429. package/foundation/env/package-manager.test.mjs +341 -15
  430. package/foundation/env/project-scope.d.mts +9 -0
  431. package/foundation/env/project-scope.mjs +33 -0
  432. package/foundation/env/search-path.d.mts +42 -0
  433. package/foundation/env/search-path.mjs +205 -0
  434. package/foundation/env/search-path.test.mjs +122 -0
  435. package/foundation/env/user-dirs.d.mts +39 -0
  436. package/foundation/env/user-dirs.mjs +93 -0
  437. package/foundation/env/user-dirs.test.mjs +72 -0
  438. package/foundation/env/user-settings.d.mts +46 -0
  439. package/foundation/env/user-settings.mjs +106 -0
  440. package/foundation/env/user-settings.test.mjs +64 -0
  441. package/foundation/fs/file-protection.mjs +15 -1
  442. package/foundation/fs/module-loader.d.mts +2 -1
  443. package/foundation/fs/module-loader.mjs +60 -4
  444. package/foundation/fs/module-loader.stdout.test.mjs +3 -2
  445. package/foundation/fs/module-loader.test.mjs +194 -0
  446. package/foundation/fs/path-compare.d.mts +33 -0
  447. package/foundation/fs/path-compare.mjs +73 -0
  448. package/foundation/fs/paths.d.mts +57 -1
  449. package/foundation/fs/paths.mjs +131 -3
  450. package/foundation/fs/paths.test.mjs +10 -1
  451. package/foundation/integrations/computer-integrations.d.mts +78 -0
  452. package/foundation/integrations/computer-integrations.mjs +316 -0
  453. package/foundation/integrations/computer-integrations.test.mjs +292 -0
  454. package/foundation/integrations/contribution-inventory.d.mts +11 -0
  455. package/foundation/integrations/contribution-inventory.mjs +56 -3
  456. package/foundation/integrations/integration-warnings.mjs +3 -2
  457. package/foundation/integrations/integration-warnings.test.mjs +8 -9
  458. package/foundation/integrations/integrations.d.mts +25 -1
  459. package/foundation/integrations/integrations.mjs +46 -3
  460. package/foundation/integrations/issue.ts +6 -0
  461. package/foundation/integrations/validate-contributions.d.mts +2 -0
  462. package/foundation/integrations/validate-contributions.mjs +41 -1
  463. package/foundation/release/agent-text-worker.d.mts +4 -0
  464. package/foundation/release/agent-text-worker.mjs +52 -0
  465. package/foundation/release/cache.d.mts +310 -0
  466. package/foundation/release/cache.mjs +1216 -0
  467. package/foundation/release/cache.test.mjs +920 -0
  468. package/foundation/release/choose.d.mts +207 -0
  469. package/foundation/release/choose.mjs +677 -0
  470. package/foundation/release/choose.test.mjs +427 -0
  471. package/foundation/release/core-worker.d.mts +4 -0
  472. package/foundation/release/core-worker.mjs +38 -0
  473. package/foundation/release/global-state.d.mts +259 -0
  474. package/foundation/release/global-state.mjs +472 -0
  475. package/foundation/release/global-state.test.mjs +381 -0
  476. package/foundation/release/handoff.d.mts +60 -0
  477. package/foundation/release/handoff.e2e.test.mjs +278 -0
  478. package/foundation/release/handoff.mjs +357 -0
  479. package/foundation/release/lock-lease.d.mts +23 -0
  480. package/foundation/release/lock-lease.mjs +80 -0
  481. package/foundation/release/notices.d.mts +253 -0
  482. package/foundation/release/notices.mjs +596 -0
  483. package/foundation/release/notices.test.mjs +565 -0
  484. package/foundation/release/npm-guard.d.mts +4 -0
  485. package/foundation/release/npm-guard.mjs +126 -0
  486. package/foundation/release/project.d.mts +141 -0
  487. package/foundation/release/project.mjs +466 -0
  488. package/foundation/release/project.test.mjs +288 -0
  489. package/foundation/release/refresh-worker.d.mts +4 -0
  490. package/foundation/release/refresh-worker.mjs +27 -0
  491. package/foundation/release/run-context.d.mts +47 -0
  492. package/foundation/release/run-context.mjs +149 -0
  493. package/foundation/release/update-notice-env.d.mts +28 -0
  494. package/foundation/release/update-notice-env.mjs +39 -0
  495. package/foundation/response/base.d.ts +26 -3
  496. package/foundation/response/error-codes.d.mts +3 -1
  497. package/foundation/response/error-codes.doc.mjs +12 -0
  498. package/foundation/response/error-codes.mjs +17 -0
  499. package/foundation/response/error-codes.test.mjs +2 -0
  500. package/foundation/response/json-contract.test.mjs +7 -2
  501. package/foundation/response/json.mjs +4 -1
  502. package/foundation/response/response-types.doc.mjs +22 -11
  503. package/foundation/response/response-types.doc.test.mjs +46 -0
  504. package/foundation/response/response.doc.mjs +3 -3
  505. package/foundation/xle/browser-imports.test.mjs +74 -0
  506. package/foundation/xle/registry.mjs +4 -0
  507. package/foundation/xle/registry.test.mjs +28 -0
  508. package/package.json +11 -11
  509. package/scripts/postinstall.mjs +24 -5
@@ -1,16 +1,32 @@
1
1
  // Copyright (c) Meta Platforms, Inc. and affiliates.
2
2
 
3
3
  /**
4
- * @file Tests for how the discover adapter calls discover sources: order,
5
- * failure isolation, timeouts, and the saved copy. Sources are plain functions
6
- * on a stand-in project, and the saved copies go to a temp directory.
4
+ * @file Tests for how the discover adapter reads the official list and calls
5
+ * discover sources: order, failure isolation, timeouts, and the saved copy,
6
+ * plus what the official list adds to the installed list and the add command.
7
+ * Sources are plain functions on a stand-in project, and the saved copies go
8
+ * to a temp directory.
7
9
  */
8
10
 
9
11
  import {afterEach, beforeEach, describe, expect, it, vi} from 'vitest';
10
12
  import * as fs from 'node:fs';
11
13
  import * as os from 'node:os';
12
14
  import * as path from 'node:path';
13
- import {callSources} from './_adapter.mjs';
15
+ import {
16
+ addCommand,
17
+ callSources,
18
+ OFFICIAL_LIST_FILE,
19
+ officialDeclarations,
20
+ officialList,
21
+ withDeclaredOfficial,
22
+ } from './_adapter.mjs';
23
+ import {parseDiscoverCatalog} from '../../authoring/discover/parse.mjs';
24
+
25
+ /** No official packages, so a test sees only its own sources after it. */
26
+ const NO_OFFICIAL = {packages: []};
27
+
28
+ /** How the official list reports itself among the sources. */
29
+ const OFFICIAL_STATE = ['Astryx', '@astryxdesign/cli', 'fresh'];
14
30
 
15
31
  /**
16
32
  * @param {string} name
@@ -43,11 +59,28 @@ function pkg(name, extra = {}) {
43
59
  }
44
60
 
45
61
  /**
46
- * @param {{config?: object, integrations?: object[]}} parts
62
+ * @param {{config?: object, integrations?: object[], cwd?: string}} parts
47
63
  * @returns {any}
48
64
  */
49
- function project({config = {}, integrations = []}) {
50
- return {config, loadedIntegrations: integrations, cwd: '/virtual/project'};
65
+ function project({config = {}, integrations = [], cwd = '/virtual/project'}) {
66
+ return {config, loadedIntegrations: integrations, cwd};
67
+ }
68
+
69
+ /**
70
+ * An official package as officialList() returns it.
71
+ * @param {string} name
72
+ * @param {object} [extra]
73
+ */
74
+ function official(name, extra = {}) {
75
+ return {
76
+ ...pkg(name, {latest: '0.7.1'}),
77
+ versions: [
78
+ {version: '0.7.1', publishedAt: null, prerelease: false, status: 'ok'},
79
+ ],
80
+ contributions: [{kind: 'theme', name: name.split('-').pop()}],
81
+ pin: '0.7.1',
82
+ ...extra,
83
+ };
51
84
  }
52
85
 
53
86
  let cacheDir;
@@ -82,13 +115,14 @@ describe('callSources', () => {
82
115
  ],
83
116
  }),
84
117
  {},
85
- {cacheDir},
118
+ {cacheDir, official: NO_OFFICIAL},
86
119
  );
87
120
 
88
121
  expect(calls).toEqual(['own', 'shared']);
89
122
  expect(result.sources.map(s => [s.name, s.from, s.status])).toEqual([
90
123
  ['Own', 'astryx.config', 'fresh'],
91
124
  ['Shared', '@x/first', 'fresh'],
125
+ OFFICIAL_STATE,
92
126
  ]);
93
127
  expect(result.packages.map(p => [p.package, p.latest, p.source])).toEqual([
94
128
  ['@a/one', '9.9.9', 'Own'],
@@ -102,7 +136,7 @@ describe('callSources', () => {
102
136
  await callSources(
103
137
  project({integrations: [{name: '@x/src', __discover: source}]}),
104
138
  {package: '@a/one', version: '1.0.0'},
105
- {cacheDir},
139
+ {cacheDir, official: NO_OFFICIAL},
106
140
  );
107
141
 
108
142
  expect(source).toHaveBeenCalledWith({
@@ -134,7 +168,7 @@ describe('callSources', () => {
134
168
  ],
135
169
  }),
136
170
  {},
137
- {cacheDir},
171
+ {cacheDir, official: NO_OFFICIAL},
138
172
  );
139
173
 
140
174
  expect(result.sources.map(s => [s.from, s.status])).toEqual([
@@ -142,6 +176,7 @@ describe('callSources', () => {
142
176
  ['@x/bad', 'failed'],
143
177
  ['@x/broken', 'failed'],
144
178
  ['@x/good', 'fresh'],
179
+ ['@astryxdesign/cli', 'fresh'],
145
180
  ]);
146
181
  expect(result.sources[0].error).toContain('offline');
147
182
  expect(result.sources[1].error).toContain('schemaVersion 2');
@@ -160,7 +195,7 @@ describe('callSources', () => {
160
195
  const result = await callSources(
161
196
  project({integrations: [{name: '@x/slow', __discover: slow}]}),
162
197
  {},
163
- {cacheDir, timeoutMs: 20},
198
+ {cacheDir, timeoutMs: 20, official: NO_OFFICIAL},
164
199
  );
165
200
 
166
201
  expect(result.sources[0]).toMatchObject({
@@ -177,10 +212,11 @@ describe('callSources', () => {
177
212
  return catalog('S', [pkg('@a/one')]);
178
213
  };
179
214
  const p = project({integrations: [{name: '@x/src', __discover: source}]});
215
+ const options = {cacheDir, official: NO_OFFICIAL};
180
216
 
181
- await callSources(p, {}, {cacheDir});
217
+ await callSources(p, {}, options);
182
218
  online = false;
183
- const offline = await callSources(p, {}, {cacheDir});
219
+ const offline = await callSources(p, {}, options);
184
220
 
185
221
  expect(offline.sources[0]).toMatchObject({
186
222
  name: 'S',
@@ -190,7 +226,7 @@ describe('callSources', () => {
190
226
  });
191
227
  expect(offline.packages.map(x => x.package)).toEqual(['@a/one']);
192
228
 
193
- const otherRequest = await callSources(p, {package: '@a/one'}, {cacheDir});
229
+ const otherRequest = await callSources(p, {package: '@a/one'}, options);
194
230
  expect(otherRequest.sources[0].status).toBe('failed');
195
231
  });
196
232
 
@@ -202,14 +238,560 @@ describe('callSources', () => {
202
238
  ],
203
239
  }),
204
240
  {},
205
- {cacheDir},
241
+ {cacheDir, official: NO_OFFICIAL},
206
242
  );
207
243
 
208
244
  expect(fs.readdirSync(path.join(cacheDir, 'discover'))).toHaveLength(1);
209
245
  expect(fs.existsSync('/virtual/project')).toBe(false);
210
246
  });
211
247
 
212
- it('returns nothing when there is no project', async () => {
213
- expect(await callSources(undefined)).toEqual({sources: [], packages: []});
248
+ it('returns only the official list when there is no project', async () => {
249
+ const result = await callSources(
250
+ undefined,
251
+ {},
252
+ {official: {packages: [official('@astryxdesign/theme-gothic')]}},
253
+ );
254
+ expect(result.sources.map(s => [s.name, s.from, s.status])).toEqual([
255
+ OFFICIAL_STATE,
256
+ ]);
257
+ expect(result.packages.map(p => [p.package, p.source])).toEqual([
258
+ ['@astryxdesign/theme-gothic', 'Astryx'],
259
+ ]);
260
+ });
261
+
262
+ it('reads the official list last, so another source keeps its entry', async () => {
263
+ const own = async () =>
264
+ catalog('Own', [
265
+ pkg('@a/two'),
266
+ pkg('@astryxdesign/theme-matcha', {latest: '0.6.8'}),
267
+ ]);
268
+ const result = await callSources(
269
+ project({config: {discover: own}}),
270
+ {},
271
+ {
272
+ cacheDir,
273
+ official: {
274
+ packages: [
275
+ official('@astryxdesign/theme-gothic'),
276
+ official('@astryxdesign/theme-matcha'),
277
+ ],
278
+ },
279
+ },
280
+ );
281
+
282
+ expect(result.sources.map(s => [s.name, s.from, s.status])).toEqual([
283
+ ['Own', 'astryx.config', 'fresh'],
284
+ OFFICIAL_STATE,
285
+ ]);
286
+ // The add command's pin stays with the list; a catalog entry never
287
+ // carries it.
288
+ for (const entry of result.packages)
289
+ expect(entry).not.toHaveProperty('pin');
290
+ // Source order: discover puts official packages first only where it
291
+ // shows them.
292
+ expect(
293
+ result.packages.map(p => [p.package, p.latest, p.source, !!p.official]),
294
+ ).toEqual([
295
+ ['@a/two', '1.0.0', 'Own', false],
296
+ ['@astryxdesign/theme-matcha', '0.6.8', 'Own', false],
297
+ ['@astryxdesign/theme-gothic', '0.7.1', 'Astryx', true],
298
+ ]);
299
+ });
300
+
301
+ it('keeps a source’s package for an official integration it publishes under another name', async () => {
302
+ const own = async () =>
303
+ catalog('Own', [
304
+ pkg('@acme/gothic-fork', {
305
+ integration: '@astryxdesign/theme-gothic',
306
+ contributions: [{kind: 'theme', name: 'gothic'}],
307
+ }),
308
+ pkg('@acme/stone-mirror', {aliases: ['@astryxdesign/theme-stone']}),
309
+ ]);
310
+ const result = await callSources(
311
+ project({config: {discover: own}}),
312
+ {},
313
+ {
314
+ cacheDir,
315
+ official: {
316
+ packages: [
317
+ official('@astryxdesign/theme-gothic'),
318
+ official('@astryxdesign/theme-stone'),
319
+ official('@astryxdesign/theme-matcha'),
320
+ ],
321
+ },
322
+ },
323
+ );
324
+ expect(result.packages.map(p => [p.package, p.source])).toEqual([
325
+ ['@acme/gothic-fork', 'Own'],
326
+ ['@acme/stone-mirror', 'Own'],
327
+ ['@astryxdesign/theme-matcha', 'Astryx'],
328
+ ]);
329
+ });
330
+
331
+ it('answers a package request with only that official package', async () => {
332
+ const result = await callSources(
333
+ project({}),
334
+ {package: '@astryxdesign/theme-matcha'},
335
+ {
336
+ cacheDir,
337
+ official: {
338
+ packages: [
339
+ official('@astryxdesign/theme-gothic'),
340
+ official('@astryxdesign/theme-matcha'),
341
+ ],
342
+ },
343
+ },
344
+ );
345
+ expect(result.packages.map(p => p.package)).toEqual([
346
+ '@astryxdesign/theme-matcha',
347
+ ]);
348
+ });
349
+
350
+ it('reports an official list it could not read like a failed source', async () => {
351
+ const result = await callSources(
352
+ project({}),
353
+ {},
354
+ {cacheDir, official: {packages: [], error: 'the list is missing'}},
355
+ );
356
+ expect(result.sources.slice(-1)).toEqual([
357
+ {
358
+ name: 'Astryx',
359
+ from: '@astryxdesign/cli',
360
+ status: 'failed',
361
+ error: 'the list is missing',
362
+ },
363
+ ]);
364
+ expect(result.packages).toEqual([]);
365
+ });
366
+ });
367
+
368
+ /**
369
+ * A stand-in project folder whose installed Core is `version`.
370
+ * @param {string} dir
371
+ * @param {string} version
372
+ */
373
+ function withCore(dir, version) {
374
+ const at = path.join(dir, 'node_modules', '@astryxdesign', 'core');
375
+ fs.mkdirSync(at, {recursive: true});
376
+ fs.writeFileSync(
377
+ path.join(at, 'package.json'),
378
+ JSON.stringify({name: '@astryxdesign/core', version}),
379
+ );
380
+ return project({cwd: dir});
381
+ }
382
+
383
+ /** The version an entry lists, with its latest. */
384
+ const versionsOf = (
385
+ /** @type {{latest: string | null, versions: {version: string, prerelease: boolean}[]} | undefined} */ entry,
386
+ ) =>
387
+ entry && {
388
+ latest: entry.latest,
389
+ versions: entry.versions.map(v => [v.version, v.prerelease]),
390
+ };
391
+
392
+ /** @param {{package: string}[]} packages @param {string} name */
393
+ const find = (packages, name) => packages.find(p => p.package === name);
394
+
395
+ const NEUTRAL = '@astryxdesign/theme-neutral';
396
+
397
+ /** The canary-only package names in the committed list. */
398
+ function canaryOnlyNames() {
399
+ return JSON.parse(fs.readFileSync(OFFICIAL_LIST_FILE, 'utf8'))
400
+ .packages.filter((/** @type {{canaryOnly?: boolean}} */ p) => p.canaryOnly)
401
+ .map((/** @type {{package: string}} */ p) => p.package);
402
+ }
403
+
404
+ describe('officialList', () => {
405
+ it('gives every official package the release CLI’s version when the project has no Core', () => {
406
+ const {packages, error} = officialList({version: '0.7.1'});
407
+ expect(error).toBeUndefined();
408
+ expect(packages.length).toBeGreaterThan(0);
409
+ for (const entry of packages) {
410
+ expect(entry.package.startsWith('@astryxdesign/')).toBe(true);
411
+ expect(versionsOf(entry)).toEqual({
412
+ latest: '0.7.1',
413
+ versions: [['0.7.1', false]],
414
+ });
415
+ expect(entry.contributions.length).toBeGreaterThan(0);
416
+ }
417
+ expect(packages.map(p => p.package)).toContain(NEUTRAL);
418
+ for (const name of canaryOnlyNames()) {
419
+ expect(find(packages, name)).toBeUndefined();
420
+ }
421
+ });
422
+
423
+ it('lists the latest release and the project’s Core version, and pins the Core version', () => {
424
+ for (const [core, latest, versions] of [
425
+ [
426
+ '0.6.8',
427
+ '0.7.1',
428
+ [
429
+ ['0.7.1', false],
430
+ ['0.6.8', false],
431
+ ],
432
+ ],
433
+ [
434
+ '0.8.0',
435
+ '0.8.0',
436
+ [
437
+ ['0.8.0', false],
438
+ ['0.7.1', false],
439
+ ],
440
+ ],
441
+ ['0.7.1', '0.7.1', [['0.7.1', false]]],
442
+ [
443
+ '0.7.1-canary.def5678',
444
+ '0.7.1',
445
+ [
446
+ ['0.7.1', false],
447
+ ['0.7.1-canary.def5678', true],
448
+ ],
449
+ ],
450
+ [
451
+ '0.7.2-canary.def5678',
452
+ '0.7.1',
453
+ [
454
+ ['0.7.2-canary.def5678', true],
455
+ ['0.7.1', false],
456
+ ],
457
+ ],
458
+ ]) {
459
+ const dir = fs.mkdtempSync(path.join(cacheDir, 'core-'));
460
+ const entry = find(
461
+ officialList({version: '0.7.1', project: withCore(dir, core)}).packages,
462
+ NEUTRAL,
463
+ );
464
+ expect(versionsOf(entry), core).toEqual({latest, versions});
465
+ expect(entry.pin, core).toBe(core);
466
+ }
467
+ });
468
+
469
+ it('pins the Core version or range a fresh clone declares, and nothing for another spec', () => {
470
+ const p = project({cwd: path.join(cacheDir, 'src')});
471
+ for (const [spec, pin, versions] of [
472
+ [
473
+ '0.6.8',
474
+ '0.6.8',
475
+ [
476
+ ['0.7.1', false],
477
+ ['0.6.8', false],
478
+ ],
479
+ ],
480
+ [
481
+ '=0.6.8',
482
+ '0.6.8',
483
+ [
484
+ ['0.7.1', false],
485
+ ['0.6.8', false],
486
+ ],
487
+ ],
488
+ ['^0.6.8', '^0.6.8', [['0.7.1', false]]],
489
+ ['>=0.6.8 <0.8.0', '>=0.6.8 <0.8.0', [['0.7.1', false]]],
490
+ ['0.6.x || ^0.7.0', '0.6.x || ^0.7.0', [['0.7.1', false]]],
491
+ // A space after an operator: node-semver reads both as >=0.6.8 <0.7.0.
492
+ ['~ 0.6.8', '~0.6.8', [['0.7.1', false]]],
493
+ ['>= 0.6.8 < 0.7.0', '>=0.6.8 <0.7.0', [['0.7.1', false]]],
494
+ ['workspace:*', '0.7.1', [['0.7.1', false]]],
495
+ ['file:../core', '0.7.1', [['0.7.1', false]]],
496
+ ['latest', '0.7.1', [['0.7.1', false]]],
497
+ ]) {
498
+ fs.writeFileSync(
499
+ path.join(cacheDir, 'package.json'),
500
+ JSON.stringify({devDependencies: {'@astryxdesign/core': spec}}),
501
+ );
502
+ const entry = find(
503
+ officialList({version: '0.7.1', project: p}).packages,
504
+ NEUTRAL,
505
+ );
506
+ expect(versionsOf(entry), spec).toEqual({latest: '0.7.1', versions});
507
+ expect(entry.pin, spec).toBe(pin);
508
+ }
509
+ });
510
+
511
+ it('on a canary CLI with no Core, pins only the canary-only packages', () => {
512
+ const canary = officialList({
513
+ version: '0.7.2-canary.abc1234',
514
+ project: project({cwd: cacheDir}),
515
+ }).packages;
516
+ expect(versionsOf(find(canary, NEUTRAL))).toEqual({
517
+ latest: null,
518
+ versions: [],
519
+ });
520
+ expect(find(canary, NEUTRAL).pin).toBeUndefined();
521
+ const names = canaryOnlyNames();
522
+ expect(names.length).toBeGreaterThan(0);
523
+ for (const name of names) {
524
+ expect(versionsOf(find(canary, name)), name).toEqual({
525
+ latest: null,
526
+ versions: [['0.7.2-canary.abc1234', true]],
527
+ });
528
+ expect(find(canary, name).pin, name).toBe('0.7.2-canary.abc1234');
529
+ }
530
+ });
531
+
532
+ it('lists the canary-only packages beside a canary Core, never beside a released one', () => {
533
+ const released = officialList({
534
+ version: '0.7.2-canary.abc1234',
535
+ project: withCore(cacheDir, '0.7.1'),
536
+ }).packages;
537
+ expect(versionsOf(find(released, NEUTRAL))).toEqual({
538
+ latest: '0.7.1',
539
+ versions: [['0.7.1', false]],
540
+ });
541
+ for (const name of canaryOnlyNames()) {
542
+ expect(find(released, name), name).toBeUndefined();
543
+ }
544
+
545
+ fs.writeFileSync(
546
+ path.join(cacheDir, 'package.json'),
547
+ JSON.stringify({dependencies: {'@astryxdesign/core': '^0.7.0'}}),
548
+ );
549
+ const declared = officialList({
550
+ version: '0.7.2-canary.abc1234',
551
+ project: project({cwd: cacheDir}),
552
+ }).packages;
553
+ for (const name of canaryOnlyNames()) {
554
+ expect(find(declared, name), name).toBeUndefined();
555
+ }
556
+
557
+ const beside = officialList({
558
+ version: '0.7.2-canary.abc1234',
559
+ project: withCore(cacheDir, '0.7.2-canary.def5678'),
560
+ }).packages;
561
+ for (const name of canaryOnlyNames()) {
562
+ expect(versionsOf(find(beside, name)), name).toEqual({
563
+ latest: null,
564
+ versions: [['0.7.2-canary.def5678', true]],
565
+ });
566
+ }
567
+ });
568
+
569
+ it('reads back as a valid discover catalog on a release and a canary CLI', () => {
570
+ for (const version of ['0.7.1', '0.7.2-canary.abc1234']) {
571
+ const packages = officialList({version}).packages.map(
572
+ ({pin: _pin, ...entry}) => entry,
573
+ );
574
+ const parsed = parseDiscoverCatalog(
575
+ catalog('Astryx', packages),
576
+ 'the official list',
577
+ );
578
+ expect(parsed.packages).toEqual(packages);
579
+ }
580
+ });
581
+
582
+ it('reports a list it cannot read instead of throwing', () => {
583
+ const result = officialList({
584
+ file: path.join(cacheDir, 'missing.json'),
585
+ version: '0.7.1',
586
+ });
587
+ expect(result.packages).toEqual([]);
588
+ expect(result.error).toContain('the official list could not be read');
589
+ });
590
+
591
+ it('pins what each entry names, quoting a range, and the pin is a version it lists', () => {
592
+ for (const [cli, core, declared] of [
593
+ ['0.7.1', '0.6.8', undefined],
594
+ ['0.7.1', '0.8.0', undefined],
595
+ ['0.7.1', undefined, '^0.6.8'],
596
+ ['0.7.1', undefined, '>=0.6.8 <0.8.0'],
597
+ ['0.7.2-canary.abc1234', undefined, undefined],
598
+ ['0.7.2-canary.abc1234', '0.7.2-canary.def5678', undefined],
599
+ ]) {
600
+ const dir = fs.mkdtempSync(path.join(cacheDir, 'pin-'));
601
+ if (declared) {
602
+ fs.writeFileSync(
603
+ path.join(dir, 'package.json'),
604
+ JSON.stringify({dependencies: {'@astryxdesign/core': declared}}),
605
+ );
606
+ }
607
+ const p = core ? withCore(dir, core) : project({cwd: dir});
608
+ const {packages} = officialList({version: cli, project: p});
609
+ const add = addCommand(p, {official: packages});
610
+ for (const entry of packages) {
611
+ const label = `${cli} ${core ?? declared} ${entry.package}`;
612
+ const command = add(entry.package);
613
+ if (entry.pin == null) {
614
+ expect(command.endsWith(` ${entry.package}`), label).toBe(true);
615
+ } else if (entry.versions.some(v => v.version === entry.pin)) {
616
+ expect(
617
+ command.endsWith(` ${entry.package}@${entry.pin}`),
618
+ label,
619
+ ).toBe(true);
620
+ } else {
621
+ // Only a declared range is pinned without being a listed version.
622
+ expect(entry.pin, label).toBe(declared);
623
+ expect(
624
+ command.endsWith(` "${entry.package}@${declared}"`),
625
+ label,
626
+ ).toBe(true);
627
+ }
628
+ }
629
+ }
630
+ });
631
+ });
632
+
633
+ describe('officialDeclarations', () => {
634
+ const list = [
635
+ official('@astryxdesign/theme-gothic'),
636
+ official('@astryxdesign/theme-matcha'),
637
+ official('@astryxdesign/theme-stone'),
638
+ ];
639
+
640
+ it('reads the project’s own package.json from a subfolder, aliases included, and keeps peers apart', () => {
641
+ fs.writeFileSync(
642
+ path.join(cacheDir, 'package.json'),
643
+ JSON.stringify({
644
+ dependencies: {
645
+ 'my-gothic': 'npm:@astryxdesign/theme-gothic@0.7.0',
646
+ react: '19.0.0',
647
+ },
648
+ devDependencies: {'@astryxdesign/theme-matcha': '0.7.0'},
649
+ peerDependencies: {'@astryxdesign/theme-stone': '>=0.7.0'},
650
+ }),
651
+ );
652
+ const declared = officialDeclarations(
653
+ project({cwd: path.join(cacheDir, 'src', 'components')}),
654
+ list,
655
+ );
656
+ expect([...declared.dependency]).toEqual([
657
+ ['@astryxdesign/theme-gothic', 'my-gothic'],
658
+ ['@astryxdesign/theme-matcha', '@astryxdesign/theme-matcha'],
659
+ ]);
660
+ expect([...declared.any].sort()).toEqual([
661
+ '@astryxdesign/theme-gothic',
662
+ '@astryxdesign/theme-matcha',
663
+ '@astryxdesign/theme-stone',
664
+ ]);
665
+ });
666
+ });
667
+
668
+ describe('withDeclaredOfficial', () => {
669
+ /** @param {string} dir @param {string} name @param {string} version */
670
+ function install(dir, name, version) {
671
+ const at = path.join(dir, 'node_modules', ...name.split('/'));
672
+ fs.mkdirSync(at, {recursive: true});
673
+ fs.writeFileSync(
674
+ path.join(at, 'package.json'),
675
+ JSON.stringify({name, version}),
676
+ );
677
+ }
678
+
679
+ /** @param {object[]} packages */
680
+ const result = packages => ({sources: [], packages});
681
+ /** @param {Array<[string, string]>} entries */
682
+ const declares = entries => ({
683
+ dependency: new Map(entries),
684
+ any: new Set(entries.map(([name]) => name)),
685
+ });
686
+ const gothic = {
687
+ ...official('@astryxdesign/theme-gothic', {description: 'Dark.'}),
688
+ source: 'Astryx',
689
+ official: true,
690
+ };
691
+
692
+ it('counts a declared official package as installed, first, with its installed version', () => {
693
+ install(cacheDir, '@astryxdesign/theme-gothic', '0.7.0');
694
+ const installed = withDeclaredOfficial(
695
+ project({cwd: cacheDir}),
696
+ [{name: '@acme/ui', category: '@acme/ui', components: []}],
697
+ result([gothic]),
698
+ declares([['@astryxdesign/theme-gothic', '@astryxdesign/theme-gothic']]),
699
+ [gothic],
700
+ );
701
+ expect(installed).toEqual([
702
+ {
703
+ name: '@astryxdesign/theme-gothic',
704
+ category: '@astryxdesign/theme-gothic',
705
+ version: '0.7.0',
706
+ description: 'Dark.',
707
+ components: [],
708
+ themes: ['gothic'],
709
+ declaredOfficial: true,
710
+ },
711
+ {name: '@acme/ui', category: '@acme/ui', components: []},
712
+ ]);
713
+ });
714
+
715
+ it('reads the version of a package installed under an npm alias', () => {
716
+ install(cacheDir, 'my-gothic', '0.6.8');
717
+ const [entry] = withDeclaredOfficial(
718
+ project({cwd: cacheDir}),
719
+ [],
720
+ result([gothic]),
721
+ declares([['@astryxdesign/theme-gothic', 'my-gothic']]),
722
+ [gothic],
723
+ );
724
+ expect(entry).toMatchObject({
725
+ name: '@astryxdesign/theme-gothic',
726
+ version: '0.6.8',
727
+ });
728
+ });
729
+
730
+ it('leaves a declared official package alone when another source supplied its entry', () => {
731
+ const fromOwn = {...gothic, source: 'Own', official: undefined};
732
+ expect(
733
+ withDeclaredOfficial(
734
+ project({cwd: cacheDir}),
735
+ [],
736
+ result([fromOwn]),
737
+ declares([
738
+ ['@astryxdesign/theme-gothic', '@astryxdesign/theme-gothic'],
739
+ ]),
740
+ [gothic],
741
+ ),
742
+ ).toEqual([]);
743
+ });
744
+
745
+ it('leaves out an official integration that failed to load, even when declared', () => {
746
+ expect(
747
+ withDeclaredOfficial(
748
+ project({
749
+ cwd: cacheDir,
750
+ integrations: [
751
+ {name: '@astryxdesign/theme-gothic', __loadError: 'x'},
752
+ ],
753
+ }),
754
+ [],
755
+ result([gothic]),
756
+ declares([
757
+ ['@astryxdesign/theme-gothic', '@astryxdesign/theme-gothic'],
758
+ ]),
759
+ [gothic],
760
+ ),
761
+ ).toEqual([]);
762
+ });
763
+ });
764
+
765
+ describe('addCommand with the official list', () => {
766
+ const list = [
767
+ official('@astryxdesign/theme-gothic', {pin: '0.6.8'}),
768
+ official('@astryxdesign/theme-matcha', {pin: '^0.6.8'}),
769
+ official('@astryxdesign/theme-stone', {pin: undefined}),
770
+ official('@astryxdesign/charts', {pin: '0.7.2-canary.abc1234'}),
771
+ ];
772
+ const add = () => addCommand(project({cwd: cacheDir}), {official: list});
773
+
774
+ it('pins what an official entry names, quoting a range', () => {
775
+ const command = add();
776
+ expect(command('@astryxdesign/theme-gothic')).toMatch(
777
+ / @astryxdesign\/theme-gothic@0\.6\.8$/,
778
+ );
779
+ expect(command('@astryxdesign/theme-matcha')).toMatch(
780
+ / "@astryxdesign\/theme-matcha@\^0\.6\.8"$/,
781
+ );
782
+ expect(command('@astryxdesign/theme-stone')).toMatch(
783
+ / @astryxdesign\/theme-stone$/,
784
+ );
785
+ expect(command('@astryxdesign/charts')).toMatch(
786
+ / @astryxdesign\/charts@0\.7\.2-canary\.abc1234$/,
787
+ );
788
+ });
789
+
790
+ it('adds a version that was asked for, and leaves other packages alone', () => {
791
+ const command = add();
792
+ expect(command('@acme/ui')).toMatch(/ @acme\/ui$/);
793
+ expect(command('@astryxdesign/theme-matcha', '0.7.1')).toMatch(
794
+ / @astryxdesign\/theme-matcha@0\.7\.1$/,
795
+ );
214
796
  });
215
797
  });