@astryxdesign/cli 0.6.3 → 0.6.4-canary.06c8fa3

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 (670) hide show
  1. package/CHANGELOG.md +194 -0
  2. package/README.md +121 -85
  3. package/api/blog/blog.doc.mjs +1 -0
  4. package/api/build/_adapter.d.mts +50 -0
  5. package/api/build/_adapter.mjs +60 -0
  6. package/api/build/build.doc.mjs +16 -9
  7. package/api/build/build.test.mjs +197 -8
  8. package/api/build/build.type.d.mts +91 -2
  9. package/api/build/build.type.mjs +52 -8
  10. package/api/build/help/help.d.mts +12 -5
  11. package/api/build/help/help.mjs +69 -6
  12. package/api/build/kit/kit.d.mts +4 -1
  13. package/api/build/kit/kit.mjs +165 -49
  14. package/api/build/kit/rank.d.mts +44 -0
  15. package/api/build/kit/rank.mjs +432 -0
  16. package/api/build/kit/rank.test.mjs +196 -0
  17. package/api/component/_adapter.d.mts +31 -12
  18. package/api/component/_adapter.mjs +79 -15
  19. package/api/component/component.d.mts +6 -3
  20. package/api/component/component.doc.mjs +36 -13
  21. package/api/component/component.mjs +339 -22
  22. package/api/component/component.test.mjs +38 -0
  23. package/api/component/component.type.d.mts +47 -11
  24. package/api/component/component.type.mjs +76 -24
  25. package/api/component/detail/blocks/blocks.d.mts +2 -1
  26. package/api/component/detail/blocks/blocks.mjs +4 -3
  27. package/api/component/list/list.d.mts +0 -5
  28. package/api/component/list/list.mjs +40 -11
  29. package/api/discover/_adapter.d.mts +114 -6
  30. package/api/discover/_adapter.mjs +372 -17
  31. package/api/discover/_adapter.test.mjs +215 -0
  32. package/api/discover/_catalog-view.d.mts +115 -0
  33. package/api/discover/_catalog-view.mjs +203 -0
  34. package/api/discover/_catalog-view.test.mjs +128 -0
  35. package/api/discover/detail/detail.d.mts +18 -6
  36. package/api/discover/detail/detail.mjs +67 -13
  37. package/api/discover/detail/detail.test.mjs +85 -0
  38. package/api/discover/detail/item/item.d.mts +26 -0
  39. package/api/discover/detail/item/item.mjs +78 -0
  40. package/api/discover/detail/item/item.test.mjs +73 -0
  41. package/api/discover/discover.d.mts +3 -9
  42. package/api/discover/discover.doc.mjs +62 -18
  43. package/api/discover/discover.mjs +220 -36
  44. package/api/discover/discover.test.mjs +11 -2
  45. package/api/discover/discover.type.d.mts +150 -11
  46. package/api/discover/discover.type.mjs +107 -17
  47. package/api/discover/list/list.d.mts +20 -6
  48. package/api/discover/list/list.mjs +45 -12
  49. package/api/discover/list/list.test.mjs +46 -0
  50. package/api/discover/search/search.d.mts +18 -16
  51. package/api/discover/search/search.mjs +102 -56
  52. package/api/discover/search/search.test.mjs +144 -10
  53. package/api/docs/_adapter.d.mts +272 -41
  54. package/api/docs/_adapter.mjs +985 -108
  55. package/api/docs/compiled-topics.test.mjs +78 -0
  56. package/api/docs/detail/detail.mjs +22 -63
  57. package/api/docs/detail/section/section.d.mts +1 -1
  58. package/api/docs/detail/section/section.mjs +54 -19
  59. package/api/docs/detail/section/section.test.mjs +50 -0
  60. package/api/docs/docs.d.mts +10 -3
  61. package/api/docs/docs.doc.mjs +55 -16
  62. package/api/docs/docs.mjs +53 -10
  63. package/api/docs/docs.test.mjs +166 -4
  64. package/api/docs/docs.type.d.mts +221 -5
  65. package/api/docs/docs.type.mjs +153 -11
  66. package/api/docs/index/index.d.mts +18 -0
  67. package/api/docs/index/index.mjs +40 -0
  68. package/api/docs/index/index.test.mjs +62 -0
  69. package/api/docs/integration-tree.test.mjs +555 -0
  70. package/api/docs/integrationDocs.test.mjs +114 -8
  71. package/api/docs/list/list.mjs +28 -12
  72. package/api/docs/node/node.d.mts +43 -0
  73. package/api/docs/node/node.mjs +192 -0
  74. package/api/docs/reference-blocks.test.mjs +406 -0
  75. package/api/doctor/doctor.d.mts +104 -1
  76. package/api/doctor/doctor.doc.mjs +1 -0
  77. package/api/doctor/doctor.mjs +635 -7
  78. package/api/doctor/doctor.test.mjs +732 -11
  79. package/api/gap-report/gap-report.doc.mjs +8 -4
  80. package/api/hook/_adapter.mjs +19 -5
  81. package/api/hook/hook.doc.mjs +1 -0
  82. package/api/hook/hook.type.d.mts +3 -3
  83. package/api/hook/hook.type.mjs +11 -11
  84. package/api/hook/list/list.d.mts +2 -2
  85. package/api/hook/list/list.mjs +69 -17
  86. package/api/index.d.mts +2 -3
  87. package/api/index.mjs +5 -4
  88. package/api/init/init.doc.mjs +6 -1
  89. package/api/init/init.test.mjs +41 -1
  90. package/api/init/remove/remove.mjs +1 -1
  91. package/api/init/run/run.mjs +20 -10
  92. package/api/integration/add-contribution.component-names.test.mjs +120 -0
  93. package/api/integration/add-contribution.d.mts +2 -1
  94. package/api/integration/add-contribution.mjs +130 -15
  95. package/api/integration/add-contribution.test.mjs +258 -7
  96. package/api/integration/add-helpers.d.mts +5 -2
  97. package/api/integration/add-helpers.mjs +36 -9
  98. package/api/integration/add-theme.mjs +34 -64
  99. package/api/integration/add-theme.test.mjs +105 -21
  100. package/api/integration/authoring-checks.mjs +138 -28
  101. package/api/integration/authoring-checks.test.mjs +179 -7
  102. package/api/integration/authoring-checks.type.mjs +6 -1
  103. package/api/integration/integration-authoring.type.d.mts +3 -1
  104. package/api/integration/integration-authoring.type.mjs +2 -0
  105. package/api/integration/integration-block-exports.test.mjs +10 -6
  106. package/api/integration/integrationAdd.doc.mjs +14 -4
  107. package/api/integration/integrationAddAgentDoc.doc.mjs +1 -0
  108. package/api/integration/integrationAddCodemod.doc.mjs +1 -0
  109. package/api/integration/integrationAddComponent.doc.mjs +2 -1
  110. package/api/integration/integrationAddDoc.doc.mjs +8 -1
  111. package/api/integration/integrationAddTemplate.doc.mjs +1 -0
  112. package/api/integration/integrationAddTheme.doc.mjs +6 -5
  113. package/api/integration/integrationComponentConflicts.doc.mjs +1 -0
  114. package/api/integration/integrationDocConflicts.doc.mjs +2 -1
  115. package/api/integration/integrationPackCheck.doc.mjs +2 -1
  116. package/api/integration/integrationTemplateConflicts.doc.d.mts +3 -0
  117. package/api/integration/integrationTemplateConflicts.doc.mjs +4 -0
  118. package/api/integration/pack-check.lifecycle-output.test.mjs +105 -0
  119. package/api/integration/pack-check.mjs +111 -10
  120. package/api/integration/pack-check.test.mjs +387 -47
  121. package/api/integration/pack-check.type.d.mts +26 -2
  122. package/api/integration/pack-check.type.mjs +14 -1
  123. package/api/integration/summarizeIssues.doc.mjs +1 -0
  124. package/api/integration/template-conflict-compatibility.test.mjs +73 -0
  125. package/api/integration/validate-integration-fixes.test.mjs +1389 -0
  126. package/api/integration/validate-integration.mjs +52 -102
  127. package/api/integration/validate-integration.test.mjs +179 -26
  128. package/api/integration/validate-unread-theme-folders.test.mjs +110 -0
  129. package/api/integration/validateIntegration.doc.mjs +3 -2
  130. package/api/json/assertResponse.doc.mjs +1 -0
  131. package/api/json/envelope-types.test.mjs +76 -0
  132. package/api/json/index.ts +2 -1
  133. package/api/json/isError.doc.mjs +1 -0
  134. package/api/json/parseResponse.doc.mjs +3 -2
  135. package/api/search/search-return-type.test.mjs +54 -0
  136. package/api/search/search.d.mts +62 -11
  137. package/api/search/search.doc.mjs +8 -2
  138. package/api/search/search.mjs +471 -83
  139. package/api/search/search.test.mjs +142 -1
  140. package/api/search/search.type.d.mts +15 -3
  141. package/api/search/search.type.mjs +5 -2
  142. package/api/swizzle/copy/copy.mjs +28 -11
  143. package/api/swizzle/swizzle.doc.mjs +2 -1
  144. package/api/swizzle/swizzle.type.d.mts +2 -2
  145. package/api/swizzle/swizzle.type.mjs +2 -2
  146. package/api/template/copy/copy.mjs +17 -23
  147. package/api/template/copy/copy.test.mjs +17 -0
  148. package/api/template/list/list.mjs +1 -0
  149. package/api/template/table-floating-bulk-actions.test.mjs +66 -0
  150. package/api/template/template-integration.test.mjs +1008 -3
  151. package/api/template/template-suffix.test.mjs +41 -21
  152. package/api/template/template.d.mts +1 -1
  153. package/api/template/template.doc.mjs +30 -8
  154. package/api/template/template.mjs +46 -9
  155. package/api/template/template.type.d.mts +12 -14
  156. package/api/template/template.type.mjs +15 -14
  157. package/api/theme/_adapter.d.mts +2 -3
  158. package/api/theme/_adapter.mjs +4 -5
  159. package/api/theme/add/add.binary.test.mjs +84 -0
  160. package/api/theme/add/add.mjs +31 -22
  161. package/api/theme/add/add.rollback.test.mjs +158 -0
  162. package/api/theme/add/add.staging.test.mjs +83 -0
  163. package/api/theme/add/add.test.mjs +14 -1
  164. package/api/theme/build/build.family.test.mjs +7 -12
  165. package/api/theme/build/build.mjs +140 -59
  166. package/api/theme/build/build.public-component-vars.test.mjs +1 -1
  167. package/api/theme/build/build.receipt-doc.test.mjs +111 -0
  168. package/api/theme/build/build.rollback.test.mjs +148 -0
  169. package/api/theme/build/build.test.mjs +127 -0
  170. package/api/theme/build/font-warning.mjs +3 -3
  171. package/api/theme/build/font-warning.test.mjs +5 -2
  172. package/api/theme/generateTonalPalette.doc.mjs +1 -0
  173. package/api/theme/integration-themes.test.mjs +39 -28
  174. package/api/theme/list/list.test.mjs +19 -20
  175. package/api/theme/listThemes.doc.mjs +6 -5
  176. package/api/theme/palette/generate/generate.mjs +8 -3
  177. package/api/theme/palette/generate/generate.test.mjs +96 -0
  178. package/api/theme/palette/generate/generator.d.mts +10 -13
  179. package/api/theme/palette/generate/generator.mjs +15 -4
  180. package/api/theme/palette/generate/generator.test.mjs +10 -0
  181. package/api/theme/template/template.mjs +11 -2
  182. package/api/theme/template/template.test.mjs +20 -0
  183. package/api/theme/theme.type.d.mts +170 -11
  184. package/api/theme/theme.type.mjs +94 -27
  185. package/api/theme/themeAdd.doc.mjs +4 -3
  186. package/api/theme/themeBuild.doc.mjs +8 -4
  187. package/api/theme/themeList.doc.mjs +6 -3
  188. package/api/theme/themeListAvailable.doc.mjs +5 -3
  189. package/api/theme/themePaletteGenerate.doc.mjs +1 -0
  190. package/api/theme/themeTargets.doc.mjs +1 -0
  191. package/api/theme/themeTemplate.doc.mjs +6 -2
  192. package/api/upgrade/_adapter.d.mts +32 -5
  193. package/api/upgrade/_adapter.mjs +139 -22
  194. package/api/upgrade/list/list.mjs +2 -1
  195. package/api/upgrade/list/list.test.mjs +73 -0
  196. package/api/upgrade/project-context.test.mjs +272 -0
  197. package/api/upgrade/provider-agreement.test.mjs +152 -0
  198. package/api/upgrade/run/files-changed.test.mjs +111 -0
  199. package/api/upgrade/run/run.mjs +359 -60
  200. package/api/upgrade/status/status.mjs +2 -2
  201. package/api/upgrade/upgrade.doc.mjs +12 -5
  202. package/api/upgrade/upgrade.type.d.mts +43 -5
  203. package/api/upgrade/upgrade.type.mjs +29 -13
  204. package/assets/codemods/__tests__/registry.test.mjs +1 -0
  205. package/assets/codemods/__tests__/runner.test.mjs +332 -8
  206. package/assets/codemods/file-count.test.mjs +163 -0
  207. package/assets/codemods/integration-discovery.mjs +48 -4
  208. package/assets/codemods/integration-discovery.test.mjs +73 -0
  209. package/assets/codemods/integration-runner.mjs +59 -7
  210. package/assets/codemods/integration-runner.protection.test.mjs +153 -0
  211. package/assets/codemods/registry.mjs +1 -0
  212. package/assets/codemods/run-codemod.mjs +177 -34
  213. package/assets/codemods/runner.mjs +353 -104
  214. package/assets/codemods/term-log.mjs +32 -8
  215. package/assets/codemods/term-log.test.mjs +19 -1
  216. package/assets/codemods/transform-prop.mjs +109 -0
  217. package/assets/codemods/transform-prop.test.mjs +95 -0
  218. package/assets/codemods/transforms/v0.0.14/__tests__/rename-status-variants.test.mjs +86 -165
  219. package/assets/codemods/transforms/v0.0.14/rename-status-variants.mjs +72 -210
  220. package/assets/codemods/transforms/v0.1.8/__tests__/rename-avatar-size-scale.test.mjs +83 -115
  221. package/assets/codemods/transforms/v0.1.8/rename-avatar-size-scale.mjs +57 -186
  222. package/assets/codemods/transforms/v0.3.0/__tests__/unwrap-authoring-factories.test.mjs +27 -5
  223. package/assets/codemods/transforms/v0.3.0/unwrap-authoring-factories.mjs +20 -5
  224. package/assets/codemods/transforms/v0.6.0/__tests__/next-codemods.test.mjs +47 -0
  225. package/assets/codemods/transforms/v0.6.0/rename-resizable-pixel-bounds.mjs +57 -10
  226. package/assets/codemods/transforms/v0.6.4/__tests__/migrate-native-picker-to-presentation.test.mjs +63 -0
  227. package/assets/codemods/transforms/v0.6.4/__tests__/migrate-theme-catalog-to-descriptors.test.mjs +220 -0
  228. package/assets/codemods/transforms/v0.6.4/index.mjs +31 -0
  229. package/assets/codemods/transforms/v0.6.4/migrate-native-picker-to-presentation.mjs +148 -0
  230. package/assets/codemods/transforms/v0.6.4/migrate-theme-catalog-to-descriptors.mjs +141 -0
  231. package/assets/docs/README.md +9 -0
  232. package/assets/docs/authoring.doc.mjs +14 -0
  233. package/assets/docs/getting-started.doc.mjs +2 -2
  234. package/assets/docs/internationalization.doc.mjs +7 -5
  235. package/assets/docs/layout.doc.dense.mjs +2 -2
  236. package/assets/docs/layout.doc.mjs +1 -1
  237. package/assets/docs/principles.doc.mjs +6 -6
  238. package/assets/docs/styling-libraries.doc.mjs +4 -4
  239. package/assets/docs/styling.doc.mjs +4 -4
  240. package/assets/docs/theme.doc.mjs +5 -5
  241. package/assets/docs/tokens.doc.mjs +1 -1
  242. package/assets/docs/tree/api.doc.mjs +30 -0
  243. package/assets/docs/tree/cli.doc.mjs +23 -0
  244. package/assets/docs/tree/commands.doc.mjs +25 -0
  245. package/assets/docs/tree/component-lookups.doc.mjs +149 -0
  246. package/assets/docs/{cli-integrations.doc.mjs → tree/integrations.doc.mjs} +144 -26
  247. package/assets/docs/tree/integrations.test.mjs +62 -0
  248. package/assets/docs/tree/writing-docs.doc.mjs +286 -0
  249. package/assets/docs/working-with-ai.doc.mjs +4 -4
  250. package/assets/templates/blocks/components/CheckboxList/CheckboxListSelectAllPattern.doc.mjs +1 -1
  251. package/assets/templates/blocks/components/CheckboxList/CheckboxListSelectAllPattern.tsx +1 -3
  252. package/assets/templates/blocks/components/DateInput/DateInputDateRange.tsx +1 -1
  253. package/assets/templates/blocks/components/InternationalizationProvider/InternationalizationProvider01ShippedLocale.tsx +1 -1
  254. package/assets/templates/blocks/components/Item/ItemDocumentTabs.doc.mjs +14 -0
  255. package/assets/templates/blocks/components/Item/ItemDocumentTabs.tsx +100 -0
  256. package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaInlineRail.doc.mjs +14 -0
  257. package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaInlineRail.tsx +61 -0
  258. package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaOverscrollChaining.doc.mjs +14 -0
  259. package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaOverscrollChaining.tsx +126 -0
  260. package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaShowcase.doc.mjs +15 -0
  261. package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaShowcase.tsx +86 -0
  262. package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaStickyGroupHeaders.doc.mjs +14 -0
  263. package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaStickyGroupHeaders.tsx +99 -0
  264. package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaStickyPassthrough.doc.mjs +14 -0
  265. package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaStickyPassthrough.tsx +122 -0
  266. package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaTwoAxisBoard.doc.mjs +14 -0
  267. package/assets/templates/blocks/components/ScrollableArea/ScrollableAreaTwoAxisBoard.tsx +95 -0
  268. package/assets/templates/blocks/components/Table/TableBulkActionsTable.doc.mjs +14 -0
  269. package/assets/templates/blocks/components/Table/TableBulkActionsTable.tsx +71 -0
  270. package/assets/templates/blocks/components/Table/TableFloatingBulkActionsTable.doc.mjs +19 -0
  271. package/assets/templates/blocks/components/Table/TableFloatingBulkActionsTable.tsx +139 -0
  272. package/assets/templates/blocks/components/TimeInput/TimeInputConstrained.tsx +1 -0
  273. package/assets/templates/blocks/components/Timer/TimerFormats.doc.mjs +14 -0
  274. package/assets/templates/blocks/components/Timer/TimerFormats.tsx +34 -0
  275. package/assets/templates/blocks/components/Timer/TimerInline.doc.mjs +14 -0
  276. package/assets/templates/blocks/components/Timer/TimerInline.tsx +14 -0
  277. package/assets/templates/blocks/components/Timer/TimerShowcase.doc.mjs +13 -0
  278. package/assets/templates/blocks/components/Timer/TimerShowcase.tsx +47 -0
  279. package/assets/templates/blocks/components/Timer/TimerTypography.doc.mjs +14 -0
  280. package/assets/templates/blocks/components/Timer/TimerTypography.tsx +31 -0
  281. package/assets/templates/blocks/components/Toolbar/ToolbarTableFilter.doc.mjs +19 -3
  282. package/assets/templates/blocks/components/Toolbar/ToolbarTableFilter.tsx +383 -65
  283. package/assets/templates/pages/table-tree/page.tsx +1704 -0
  284. package/assets/templates/pages/table-tree/template.doc.mjs +12 -0
  285. package/assets/templates/themes/butter/butterTheme.doc.mjs +11 -0
  286. package/assets/templates/themes/chocolate/chocolateTheme.doc.mjs +11 -0
  287. package/assets/templates/themes/gothic/gothicTheme.doc.mjs +11 -0
  288. package/assets/templates/themes/matcha/matchaTheme.doc.mjs +11 -0
  289. package/assets/templates/themes/neutral/neutralTheme.doc.mjs +11 -0
  290. package/assets/templates/themes/stone/stoneTheme.doc.mjs +11 -0
  291. package/assets/templates/themes/y2k/y2kTheme.doc.mjs +11 -0
  292. package/authoring/_shared/contract.ts +22 -0
  293. package/authoring/codemod/codemod.doc.mjs +7 -2
  294. package/authoring/codemod/parse.d.mts +8 -8
  295. package/authoring/codemod/parse.mjs +8 -6
  296. package/authoring/codemod/type.ts +12 -0
  297. package/authoring/config/config.doc.mjs +11 -3
  298. package/authoring/config/debug-composition.test.mjs +92 -0
  299. package/authoring/config/parse.d.mts +15 -13
  300. package/authoring/config/parse.mjs +27 -8
  301. package/authoring/config/parse.test.mjs +8 -0
  302. package/authoring/config/type.ts +31 -8
  303. package/authoring/debug/debug.doc.d.mts +11 -0
  304. package/authoring/debug/debug.doc.mjs +182 -0
  305. package/authoring/debug/parse.d.mts +8 -8
  306. package/authoring/debug/parse.mjs +3 -3
  307. package/authoring/discover/discover.doc.d.mts +13 -0
  308. package/authoring/discover/discover.doc.mjs +138 -0
  309. package/authoring/discover/parse.d.mts +24 -0
  310. package/authoring/discover/parse.mjs +128 -0
  311. package/authoring/discover/parse.test.mjs +124 -0
  312. package/authoring/discover/type.ts +87 -0
  313. package/authoring/doctypes/_schema.d.mts +790 -23
  314. package/authoring/doctypes/_schema.mjs +543 -39
  315. package/authoring/doctypes/base/graph-fields.doc.d.mts +9 -0
  316. package/authoring/doctypes/base/graph-fields.doc.mjs +64 -0
  317. package/authoring/doctypes/base/type.ts +41 -0
  318. package/authoring/doctypes/command/command.doc.mjs +5 -4
  319. package/authoring/doctypes/command/parse.d.mts +2 -2
  320. package/authoring/doctypes/command/parse.mjs +1 -1
  321. package/authoring/doctypes/command/type.ts +6 -5
  322. package/authoring/doctypes/component/component.doc.mjs +6 -3
  323. package/authoring/doctypes/component/parse.d.mts +2 -2
  324. package/authoring/doctypes/component/parse.mjs +1 -1
  325. package/authoring/doctypes/component/type.ts +6 -5
  326. package/authoring/doctypes/doctypes-new.test.mjs +48 -6
  327. package/authoring/doctypes/enum/enum.doc.mjs +1 -1
  328. package/authoring/doctypes/enum/parse.d.mts +2 -2
  329. package/authoring/doctypes/enum/parse.mjs +1 -1
  330. package/authoring/doctypes/enum/type.ts +4 -2
  331. package/authoring/doctypes/function/function.doc.mjs +7 -2
  332. package/authoring/doctypes/function/parse.d.mts +2 -2
  333. package/authoring/doctypes/function/parse.mjs +1 -1
  334. package/authoring/doctypes/function/type.ts +9 -4
  335. package/authoring/doctypes/hook/hook.doc.mjs +4 -0
  336. package/authoring/doctypes/hook/parse.d.mts +2 -2
  337. package/authoring/doctypes/hook/parse.mjs +1 -1
  338. package/authoring/doctypes/hook/type.ts +5 -4
  339. package/authoring/doctypes/legacy.d.mts +8 -6
  340. package/authoring/doctypes/legacy.mjs +5 -4
  341. package/authoring/doctypes/load-contract.test.mjs +233 -0
  342. package/authoring/doctypes/namespace/namespace.doc.d.mts +9 -0
  343. package/authoring/doctypes/namespace/namespace.doc.mjs +128 -0
  344. package/authoring/doctypes/namespace/parse.d.mts +12 -0
  345. package/authoring/doctypes/namespace/parse.mjs +25 -0
  346. package/authoring/doctypes/namespace/parse.test.mjs +163 -0
  347. package/authoring/doctypes/namespace/type.ts +74 -0
  348. package/authoring/doctypes/parse.d.mts +22 -18
  349. package/authoring/doctypes/parse.mjs +22 -11
  350. package/authoring/doctypes/parse.test.mjs +77 -3
  351. package/authoring/doctypes/reference/parse.d.mts +2 -2
  352. package/authoring/doctypes/reference/parse.mjs +8 -5
  353. package/authoring/doctypes/reference/reference.doc.mjs +48 -6
  354. package/authoring/doctypes/reference/type.ts +70 -7
  355. package/authoring/doctypes/schema/parse.d.mts +2 -2
  356. package/authoring/doctypes/schema/parse.mjs +1 -1
  357. package/authoring/doctypes/schema/schema.doc.mjs +1 -1
  358. package/authoring/doctypes/schema/type.ts +4 -4
  359. package/authoring/doctypes/template/parse.d.mts +94 -1
  360. package/authoring/doctypes/template/parse.mjs +40 -2
  361. package/authoring/doctypes/template/parse.test.mjs +26 -2
  362. package/authoring/doctypes/template/template.doc.mjs +13 -3
  363. package/authoring/doctypes/template/type.ts +13 -2
  364. package/authoring/doctypes/theme/parse.d.mts +35 -0
  365. package/authoring/doctypes/theme/parse.mjs +76 -0
  366. package/authoring/doctypes/theme/theme.doc.d.mts +9 -0
  367. package/authoring/doctypes/theme/theme.doc.mjs +79 -0
  368. package/authoring/doctypes/theme/type.ts +42 -0
  369. package/authoring/doctypes/types.ts +12 -10
  370. package/authoring/gap-report/gap-report.doc.d.mts +12 -0
  371. package/authoring/gap-report/gap-report.doc.mjs +183 -0
  372. package/authoring/gap-report/parse.d.mts +10 -10
  373. package/authoring/gap-report/parse.mjs +6 -6
  374. package/authoring/gap-report/type.ts +1 -1
  375. package/authoring/identity/identity.doc.d.mts +9 -0
  376. package/authoring/identity/identity.doc.mjs +61 -0
  377. package/authoring/identity/type.ts +132 -0
  378. package/authoring/index.d.mts +3 -0
  379. package/authoring/index.d.ts +62 -17
  380. package/authoring/index.mjs +4 -1
  381. package/authoring/integration/integration.doc.mjs +15 -8
  382. package/authoring/integration/parse.d.mts +2 -2
  383. package/authoring/integration/parse.mjs +1 -1
  384. package/authoring/integration/parse.test.mjs +10 -1
  385. package/authoring/integration/schema.d.mts +6 -4
  386. package/authoring/integration/schema.mjs +9 -3
  387. package/authoring/integration/type.ts +19 -8
  388. package/authoring/shadcn/receipt.d.mts +6 -6
  389. package/clients/cli/__tests__/cliManifest.test.ts +27 -29
  390. package/clients/cli/command-load-failure.test.mjs +83 -0
  391. package/clients/cli/command-result-coverage.test.mjs +7 -7
  392. package/clients/cli/commands/blog.doc.mjs +1 -1
  393. package/clients/cli/commands/blog.mjs +23 -8
  394. package/clients/cli/commands/blog.test.mjs +42 -1
  395. package/clients/cli/commands/build-theme.adaptations.test.mjs +100 -1
  396. package/clients/cli/commands/build-theme.ascii-output.test.mjs +161 -0
  397. package/clients/cli/commands/build-theme.flag-docs.test.mjs +110 -0
  398. package/clients/cli/commands/build-theme.mjs +16 -50
  399. package/clients/cli/commands/build-theme.path-safety.test.mjs +86 -1
  400. package/clients/cli/commands/build-theme.variants.test.mjs +76 -0
  401. package/clients/cli/commands/build.doc.mjs +16 -8
  402. package/clients/cli/commands/build.exit-codes-doc.test.mjs +50 -0
  403. package/clients/cli/commands/build.mjs +137 -114
  404. package/clients/cli/commands/build.playbook.test.mjs +75 -0
  405. package/clients/cli/commands/build.text-fields.test.mjs +81 -0
  406. package/clients/cli/commands/component/index.mjs +153 -61
  407. package/clients/cli/commands/component-batch.test.mjs +341 -0
  408. package/clients/cli/commands/component-ownership.test.mjs +92 -3
  409. package/clients/cli/commands/component-package.test.mjs +46 -0
  410. package/clients/cli/commands/component-resolution.test.mjs +21 -0
  411. package/clients/cli/commands/component.doc.mjs +24 -7
  412. package/clients/cli/commands/component.test.mjs +19 -0
  413. package/clients/cli/commands/debug-result-summary.test.mjs +2 -2
  414. package/clients/cli/commands/detail-levels.test.mjs +2 -2
  415. package/clients/cli/commands/discover.broken-integration.test.mjs +52 -5
  416. package/clients/cli/commands/discover.components-flag.test.mjs +97 -0
  417. package/clients/cli/commands/discover.doc.mjs +55 -9
  418. package/clients/cli/commands/discover.mjs +393 -118
  419. package/clients/cli/commands/discover.sources.test.mjs +267 -0
  420. package/clients/cli/commands/discover.text-projection.test.mjs +103 -0
  421. package/clients/cli/commands/docs.doc.mjs +28 -6
  422. package/clients/cli/commands/docs.mjs +240 -26
  423. package/clients/cli/commands/docs.test.mjs +222 -1
  424. package/clients/cli/commands/doctor-integration-components.doc.mjs +1 -1
  425. package/clients/cli/commands/doctor-integration-docs.doc.mjs +3 -3
  426. package/clients/cli/commands/doctor-integration-templates.doc.mjs +15 -8
  427. package/clients/cli/commands/doctor-integration-validate.doc.mjs +1 -1
  428. package/clients/cli/commands/doctor-integration.doc.mjs +1 -1
  429. package/clients/cli/commands/doctor-integration.package-json.test.mjs +53 -0
  430. package/clients/cli/commands/doctor-integration.test.mjs +90 -8
  431. package/clients/cli/commands/doctor.doc.mjs +1 -1
  432. package/clients/cli/commands/doctor.mjs +59 -32
  433. package/clients/cli/commands/doctor.test.mjs +42 -0
  434. package/clients/cli/commands/gap-report.doc.mjs +17 -6
  435. package/clients/cli/commands/gap-report.test.mjs +72 -0
  436. package/clients/cli/commands/hook/index.mjs +7 -17
  437. package/clients/cli/commands/hook.doc.mjs +1 -1
  438. package/clients/cli/commands/hook.text-projection.test.mjs +45 -0
  439. package/clients/cli/commands/init.doc.mjs +20 -9
  440. package/clients/cli/commands/init.flag-help.test.mjs +153 -0
  441. package/clients/cli/commands/integration-add.controls.test.mjs +132 -0
  442. package/clients/cli/commands/integration-add.doc.mjs +32 -6
  443. package/clients/cli/commands/integration-authoring.test.mjs +13 -9
  444. package/clients/cli/commands/integration-pack.doc.mjs +1 -1
  445. package/clients/cli/commands/integration-real-world.test.mjs +3 -9
  446. package/clients/cli/commands/integration.doc.mjs +1 -1
  447. package/clients/cli/commands/integration.mjs +1 -0
  448. package/clients/cli/commands/interactive-guard.test.mjs +101 -24
  449. package/clients/cli/commands/json-contract.test.mjs +33 -0
  450. package/clients/cli/commands/manifest.doc.mjs +1 -1
  451. package/clients/cli/commands/no-prompt-wording.test.mjs +94 -0
  452. package/clients/cli/commands/search.doc.mjs +7 -4
  453. package/clients/cli/commands/search.mjs +28 -9
  454. package/clients/cli/commands/search.test.mjs +75 -0
  455. package/clients/cli/commands/setup-nudge.test.mjs +6 -0
  456. package/clients/cli/commands/swizzle.doc.mjs +3 -2
  457. package/clients/cli/commands/swizzle.path-safety.test.mjs +42 -0
  458. package/clients/cli/commands/template.doc.mjs +52 -13
  459. package/clients/cli/commands/template.flag-help.test.mjs +117 -0
  460. package/clients/cli/commands/template.mjs +4 -91
  461. package/clients/cli/commands/template.path-help.test.mjs +40 -0
  462. package/clients/cli/commands/text-json-parity.test.mjs +702 -0
  463. package/clients/cli/commands/theme-add.doc.mjs +4 -3
  464. package/clients/cli/commands/theme-build.doc.mjs +8 -7
  465. package/clients/cli/commands/theme-list.doc.mjs +2 -2
  466. package/clients/cli/commands/theme-palette-generate.doc.mjs +9 -5
  467. package/clients/cli/commands/theme-palette-generate.test.mjs +19 -0
  468. package/clients/cli/commands/theme-palette.doc.mjs +1 -1
  469. package/clients/cli/commands/theme-targets.behavior.test.mjs +4 -3
  470. package/clients/cli/commands/theme-targets.doc.mjs +1 -1
  471. package/clients/cli/commands/theme-template.behavior.test.mjs +12 -0
  472. package/clients/cli/commands/theme-template.doc.mjs +2 -2
  473. package/clients/cli/commands/theme.doc.mjs +1 -1
  474. package/clients/cli/commands/upgrade.ascii-output.test.mjs +87 -0
  475. package/clients/cli/commands/upgrade.doc.mjs +22 -10
  476. package/clients/cli/commands/upgrade.file-protection.test.mjs +228 -0
  477. package/clients/cli/commands/upgrade.flag-help.test.mjs +188 -0
  478. package/clients/cli/commands/upgrade.hook-output.test.mjs +88 -0
  479. package/clients/cli/commands/upgrade.mjs +29 -7
  480. package/clients/cli/formatters/index.mjs +164 -1
  481. package/clients/cli/formatters/index.test.mjs +97 -0
  482. package/clients/cli/index.mjs +21 -34
  483. package/clients/cli/latest-version-env.test.mjs +50 -0
  484. package/clients/cli/lib/cli-error.test.mjs +7 -0
  485. package/clients/cli/lib/component-format.mjs +9 -9
  486. package/clients/cli/lib/component-format.test.mjs +1 -1
  487. package/clients/cli/lib/define-command.mjs +32 -6
  488. package/clients/cli/lib/doc-text-ascii.test.mjs +82 -0
  489. package/clients/cli/lib/exit-codes.test.mjs +90 -0
  490. package/clients/cli/lib/hook-format.mjs +19 -10
  491. package/clients/cli/lib/json-shim.mjs +62 -16
  492. package/clients/cli/lib/json-shim.test.mjs +69 -0
  493. package/clients/cli/lib/manifest.d.ts +2 -0
  494. package/clients/cli/lib/manifest.mjs +39 -10
  495. package/clients/cli/lib/manifest.test.mjs +22 -2
  496. package/clients/cli/lib/parse-error-format.test.mjs +81 -0
  497. package/foundation/agent-docs/agent-docs.d.mts +7 -2
  498. package/foundation/agent-docs/agent-docs.mjs +82 -12
  499. package/foundation/agent-docs/agent-docs.path-safety.test.mjs +266 -4
  500. package/foundation/agent-docs/agent-docs.test.mjs +19 -1
  501. package/foundation/config/integration-debug.test.mjs +28 -3
  502. package/foundation/config/project-themes.test.mjs +11 -19
  503. package/foundation/config/project.d.mts +20 -11
  504. package/foundation/config/project.mjs +263 -91
  505. package/foundation/config/project.test.mjs +270 -21
  506. package/foundation/discovery/authoring-self-docs.d.mts +87 -0
  507. package/foundation/discovery/authoring-self-docs.mjs +237 -0
  508. package/foundation/discovery/authoring-self-docs.test.mjs +170 -0
  509. package/foundation/discovery/authoring-surface.d.mts +74 -0
  510. package/foundation/discovery/authoring-surface.mjs +525 -0
  511. package/foundation/discovery/authoring-surface.test.mjs +392 -0
  512. package/foundation/discovery/cli-self-docs.d.mts +119 -0
  513. package/foundation/discovery/cli-self-docs.mjs +490 -0
  514. package/foundation/discovery/cli-self-docs.test.mjs +375 -0
  515. package/foundation/discovery/component-discovery.d.mts +39 -1
  516. package/foundation/discovery/component-discovery.mjs +50 -1
  517. package/foundation/discovery/component-loader.d.mts +35 -38
  518. package/foundation/discovery/component-loader.mjs +53 -222
  519. package/foundation/discovery/docs-discovery.d.mts +119 -11
  520. package/foundation/discovery/docs-discovery.mjs +423 -108
  521. package/foundation/discovery/docs-discovery.test.mjs +365 -20
  522. package/foundation/discovery/docs-output-budget.d.mts +28 -0
  523. package/foundation/discovery/docs-output-budget.mjs +50 -0
  524. package/foundation/discovery/docs-section-key.d.mts +116 -0
  525. package/foundation/discovery/docs-section-key.mjs +322 -0
  526. package/foundation/discovery/docs-section-key.test.mjs +246 -0
  527. package/foundation/discovery/template-adapter.d.mts +113 -11
  528. package/foundation/discovery/template-adapter.fixture-refs.test.mjs +248 -0
  529. package/foundation/discovery/template-adapter.integration-isolation.test.mjs +94 -0
  530. package/foundation/discovery/template-adapter.mjs +775 -84
  531. package/foundation/discovery/template-adapter.test.mjs +57 -0
  532. package/foundation/discovery/template-conflict-release.d.mts +13 -0
  533. package/foundation/discovery/template-conflict-release.mjs +40 -0
  534. package/foundation/discovery/template-conflict-release.test.mjs +40 -0
  535. package/foundation/discovery/theme-discovery.d.mts +67 -7
  536. package/foundation/discovery/theme-discovery.mjs +916 -186
  537. package/foundation/discovery/theme-discovery.test.mjs +613 -219
  538. package/foundation/discovery/theming-targets.test.mjs +4 -0
  539. package/foundation/doc-compiler/bundle.d.mts +47 -0
  540. package/foundation/doc-compiler/bundle.mjs +278 -0
  541. package/foundation/doc-compiler/bundle.test.mjs +266 -0
  542. package/foundation/doc-compiler/compile.d.mts +343 -0
  543. package/foundation/doc-compiler/compile.mjs +558 -0
  544. package/foundation/doc-compiler/diagnostics.d.mts +126 -0
  545. package/foundation/doc-compiler/diagnostics.mjs +305 -0
  546. package/foundation/doc-compiler/doc-compiler.test.mjs +714 -0
  547. package/foundation/doc-compiler/doc-loads.test.mjs +1630 -0
  548. package/foundation/doc-compiler/import.d.mts +24 -0
  549. package/foundation/doc-compiler/import.mjs +59 -0
  550. package/foundation/doc-compiler/inputs.d.mts +102 -0
  551. package/foundation/doc-compiler/inputs.mjs +291 -0
  552. package/foundation/doc-compiler/inputs.test.mjs +299 -0
  553. package/foundation/doc-compiler/ir.d.mts +22 -0
  554. package/foundation/doc-compiler/ir.mjs +471 -0
  555. package/foundation/doc-compiler/lenses.d.mts +36 -0
  556. package/foundation/doc-compiler/lenses.mjs +173 -0
  557. package/foundation/doc-compiler/links.d.mts +162 -0
  558. package/foundation/doc-compiler/links.mjs +294 -0
  559. package/foundation/doc-compiler/links.test.mjs +192 -0
  560. package/foundation/doc-compiler/lower-doc.test.mjs +495 -0
  561. package/foundation/doc-compiler/overlays.d.mts +37 -0
  562. package/foundation/doc-compiler/overlays.mjs +206 -0
  563. package/foundation/doc-compiler/parse-readable.d.mts +9 -0
  564. package/foundation/doc-compiler/parse-readable.mjs +29 -0
  565. package/foundation/doc-compiler/read.d.mts +127 -0
  566. package/foundation/doc-compiler/read.mjs +325 -0
  567. package/foundation/doc-compiler/read.test.mjs +313 -0
  568. package/foundation/doc-compiler/source.d.mts +33 -0
  569. package/foundation/doc-compiler/source.mjs +128 -0
  570. package/foundation/doc-compiler/tree.d.mts +288 -0
  571. package/foundation/doc-compiler/tree.mjs +876 -0
  572. package/foundation/doc-compiler/tree.test.mjs +606 -0
  573. package/foundation/fs/file-protection.d.mts +33 -0
  574. package/foundation/fs/file-protection.mjs +825 -0
  575. package/foundation/fs/file-protection.test.mjs +250 -0
  576. package/foundation/fs/module-loader.d.mts +1 -0
  577. package/foundation/fs/module-loader.mjs +50 -1
  578. package/foundation/fs/module-loader.stdout.test.mjs +332 -0
  579. package/foundation/fs/path-safety.d.mts +3 -2
  580. package/foundation/fs/path-safety.mjs +49 -19
  581. package/foundation/fs/path-safety.test.mjs +50 -0
  582. package/foundation/fs/publish-file-hardlink-unavailable.test.mjs +129 -94
  583. package/foundation/identity/provider-identity.d.mts +90 -0
  584. package/foundation/identity/provider-identity.mjs +320 -0
  585. package/foundation/identity/provider-identity.test.mjs +254 -0
  586. package/foundation/identity/providers.d.mts +7 -0
  587. package/foundation/identity/providers.mjs +16 -0
  588. package/foundation/integrations/autolink.d.mts +58 -1
  589. package/foundation/integrations/autolink.mjs +143 -45
  590. package/foundation/integrations/autolink.test.mjs +1 -1
  591. package/foundation/integrations/cli-requirement.d.mts +45 -0
  592. package/foundation/integrations/cli-requirement.mjs +154 -0
  593. package/foundation/integrations/cli-requirement.test.mjs +84 -0
  594. package/foundation/integrations/contribution-fixes.d.mts +145 -0
  595. package/foundation/integrations/contribution-fixes.mjs +1284 -0
  596. package/foundation/integrations/contribution-inventory.d.mts +3 -2
  597. package/foundation/integrations/contribution-inventory.mjs +27 -24
  598. package/foundation/integrations/contribution-inventory.test.mjs +86 -27
  599. package/foundation/integrations/integration-warnings.d.mts +9 -2
  600. package/foundation/integrations/integration-warnings.mjs +52 -21
  601. package/foundation/integrations/integration-warnings.test.mjs +74 -1
  602. package/foundation/integrations/integrations.d.mts +63 -3
  603. package/foundation/integrations/integrations.mjs +122 -9
  604. package/foundation/integrations/integrations.test.mjs +415 -1
  605. package/foundation/integrations/provider-conflicts.test.mjs +125 -0
  606. package/foundation/integrations/provider-ledger.test.mjs +275 -0
  607. package/foundation/integrations/provider-resolution.d.mts +152 -0
  608. package/foundation/integrations/provider-resolution.mjs +576 -0
  609. package/foundation/integrations/provider-resolution.test.mjs +369 -0
  610. package/foundation/integrations/theme-descriptor.d.mts +8 -0
  611. package/foundation/integrations/theme-descriptor.mjs +44 -0
  612. package/foundation/integrations/validate-contributions.d.mts +2 -0
  613. package/foundation/integrations/validate-contributions.mjs +131 -29
  614. package/foundation/response/base.d.ts +8 -4
  615. package/foundation/response/batch.type.d.mts +33 -0
  616. package/foundation/response/batch.type.mjs +34 -0
  617. package/foundation/response/error-codes.d.mts +3 -1
  618. package/foundation/response/error-codes.d.ts +2 -0
  619. package/foundation/response/error-codes.doc.mjs +13 -4
  620. package/foundation/response/error-codes.mjs +8 -2
  621. package/foundation/response/error-codes.test.mjs +137 -10
  622. package/foundation/response/json-contract.test.mjs +57 -17
  623. package/foundation/response/json.d.mts +4 -2
  624. package/foundation/response/json.mjs +8 -10
  625. package/foundation/response/response-types.doc.d.mts +5 -1
  626. package/foundation/response/response-types.doc.mjs +46 -38
  627. package/foundation/response/response-types.doc.test.mjs +181 -0
  628. package/foundation/response/response.doc.mjs +1 -1
  629. package/foundation/text/string-utils.d.mts +8 -0
  630. package/foundation/text/string-utils.mjs +40 -10
  631. package/foundation/xle/browser.d.mts +3 -3
  632. package/foundation/xle/browser.mjs +3 -3
  633. package/foundation/xle/expand.d.mts +2 -0
  634. package/foundation/xle/expand.mjs +6 -5
  635. package/foundation/xle/expand.test.mjs +54 -0
  636. package/foundation/xle/parse.mjs +1 -1
  637. package/foundation/xle/print.mjs +2 -2
  638. package/foundation/xle/splice.mjs +1 -1
  639. package/foundation/xle/xle.test.mjs +13 -0
  640. package/package.json +10 -11
  641. package/api/layout/_adapter.d.mts +0 -34
  642. package/api/layout/_adapter.mjs +0 -133
  643. package/api/layout/check/check.d.mts +0 -16
  644. package/api/layout/check/check.mjs +0 -40
  645. package/api/layout/expand/expand.d.mts +0 -22
  646. package/api/layout/expand/expand.mjs +0 -153
  647. package/api/layout/grammar/grammar.d.mts +0 -13
  648. package/api/layout/grammar/grammar.mjs +0 -86
  649. package/api/layout/layout.d.mts +0 -6
  650. package/api/layout/layout.mjs +0 -17
  651. package/api/layout/layout.test.mjs +0 -297
  652. package/api/layout/layout.type.d.mts +0 -89
  653. package/api/layout/layout.type.mjs +0 -103
  654. package/api/layout/layoutCheck.doc.d.mts +0 -11
  655. package/api/layout/layoutCheck.doc.mjs +0 -84
  656. package/api/layout/layoutExpand.doc.d.mts +0 -11
  657. package/api/layout/layoutExpand.doc.mjs +0 -106
  658. package/api/layout/layoutGrammar.doc.d.mts +0 -11
  659. package/api/layout/layoutGrammar.doc.mjs +0 -56
  660. package/assets/templates/themes/manifest.json +0 -95
  661. package/clients/cli/commands/layout-check.doc.mjs +0 -54
  662. package/clients/cli/commands/layout-expand.doc.mjs +0 -66
  663. package/clients/cli/commands/layout-grammar.doc.mjs +0 -30
  664. package/clients/cli/commands/layout.doc.mjs +0 -34
  665. package/clients/cli/commands/layout.error-codes.test.mjs +0 -66
  666. package/clients/cli/commands/layout.exit-parity.test.mjs +0 -41
  667. package/clients/cli/commands/layout.mjs +0 -263
  668. package/clients/cli/lib/update-check.mjs +0 -83
  669. package/clients/cli/lib/update-check.test.mjs +0 -137
  670. package/clients/cli/update-hint-commands.test.mjs +0 -54
@@ -0,0 +1,250 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ import {afterEach, beforeEach, describe, expect, it} from 'vitest';
4
+ import * as fs from 'node:fs';
5
+ import * as os from 'node:os';
6
+ import * as path from 'node:path';
7
+ import {
8
+ createFileProtectionResolver,
9
+ ProtectionSourceError,
10
+ } from './file-protection.mjs';
11
+
12
+ let root;
13
+
14
+ beforeEach(() => {
15
+ root = fs.mkdtempSync(path.join(os.tmpdir(), 'astryx-protection-'));
16
+ });
17
+
18
+ afterEach(() => {
19
+ fs.rmSync(root, {recursive: true, force: true});
20
+ });
21
+
22
+ function write(relative, contents = '') {
23
+ const file = path.join(root, relative);
24
+ fs.mkdirSync(path.dirname(file), {recursive: true});
25
+ fs.writeFileSync(file, contents);
26
+ return file;
27
+ }
28
+
29
+ function declarations(relative) {
30
+ return createFileProtectionResolver(root)
31
+ .classify(path.join(root, relative))
32
+ .map(item => item.declaration);
33
+ }
34
+
35
+ describe('working-tree .gitattributes', () => {
36
+ it('honors nested later rules and explicit false or unset values', () => {
37
+ write(
38
+ '.gitattributes',
39
+ [
40
+ '*.css linguist-generated=true',
41
+ 'vendor/** linguist-vendored',
42
+ 'authored.css -linguist-generated',
43
+ 'unset.css !linguist-generated',
44
+ '',
45
+ ].join('\n'),
46
+ );
47
+ write('generated.css', 'body {}');
48
+ write('authored.css', 'body {}');
49
+ write('unset.css', 'body {}');
50
+ write('nested/keep.css', 'body {}');
51
+ write('nested/.gitattributes', 'keep.css linguist-generated=false\n');
52
+ write('vendor/pkg/index.js', 'export {};');
53
+
54
+ expect(declarations('generated.css')).toContain(
55
+ 'linguist-generated in .gitattributes:1',
56
+ );
57
+ expect(declarations('authored.css')).toEqual([]);
58
+ expect(declarations('unset.css')).toEqual([]);
59
+ expect(declarations('nested/keep.css')).toEqual([]);
60
+ expect(declarations('vendor/pkg/index.js')).toContain(
61
+ 'linguist-vendored in .gitattributes:2',
62
+ );
63
+ });
64
+
65
+ it('expands top-level attribute macros, including forward definitions', () => {
66
+ write(
67
+ '.gitattributes',
68
+ 'via-macro/** outer\n[attr]outer generated\n[attr]generated linguist-generated\n',
69
+ );
70
+ write('via-macro/output.js', 'export {};');
71
+ expect(declarations('via-macro/output.js')).toContain(
72
+ 'linguist-generated in .gitattributes:1',
73
+ );
74
+ });
75
+
76
+ it('preserves escaped wildcards as literal path characters', () => {
77
+ write('.gitattributes', 'literal\\*.js linguist-generated\n');
78
+ write('literal*.js', 'export {};');
79
+ write('literalX.js', 'export {};');
80
+ expect(declarations('literal*.js')).toHaveLength(1);
81
+ expect(declarations('literalX.js')).toEqual([]);
82
+ });
83
+
84
+ it('supports quoted attribute patterns with spaces', () => {
85
+ write('.gitattributes', '"generated output/*.js" linguist-generated\n');
86
+ write('generated output/theme.js', 'export {};');
87
+ expect(declarations('generated output/theme.js')).toHaveLength(1);
88
+ });
89
+
90
+ it('matches basename patterns below the declaring directory', () => {
91
+ write('.gitattributes', '*.gen.ts linguist-generated\n');
92
+ write('src/deep/theme.gen.ts', 'export {};');
93
+ expect(declarations('src/deep/theme.gen.ts')).toHaveLength(1);
94
+ });
95
+ });
96
+
97
+ describe('working-tree ignore rules', () => {
98
+ it('honors gitignore negation and nested precedence', () => {
99
+ write('.gitignore', ['src/**/*.js', '!src/keep.js', ''].join('\n'));
100
+ write('src/drop.js', 'drop');
101
+ write('src/keep.js', 'keep');
102
+ write('src/deep/drop.js', 'drop');
103
+ write('src/.gitignore', '!deep/keep.js\n');
104
+ write('src/deep/keep.js', 'keep');
105
+
106
+ expect(declarations('src/drop.js')[0]).toBe('excluded by .gitignore');
107
+ expect(declarations('src/deep/drop.js')[0]).toBe('excluded by .gitignore');
108
+ expect(declarations('src/keep.js')).toEqual([]);
109
+ expect(declarations('src/deep/keep.js')).toEqual([]);
110
+ });
111
+
112
+ it('uses case-sensitive Git matching on case-sensitive platforms', () => {
113
+ write('.gitignore', 'FOO\n');
114
+ write('FOO', 'x');
115
+ write('foo', 'x');
116
+
117
+ expect(declarations('FOO')[0]).toBe('excluded by .gitignore');
118
+ expect(declarations('foo')).toEqual([]);
119
+ });
120
+
121
+ it('does not let a nested ignore file re-include beneath an excluded parent', () => {
122
+ write('.gitignore', 'ignored/\n');
123
+ write('ignored/.gitignore', '!keep.js\n');
124
+ write('ignored/keep.js', 'keep');
125
+
126
+ expect(declarations('ignored/keep.js')[0]).toBe('excluded by .gitignore');
127
+ });
128
+
129
+ it('ignores nested .hgignore files unless the root file includes them', () => {
130
+ write('sub/.hgignore', 'syntax: glob\n*.tmp\n');
131
+ write('sub/file.tmp', 'x');
132
+ expect(declarations('sub/file.tmp')).toEqual([]);
133
+ });
134
+
135
+ it('reads Mercurial glob and regexp syntax without a repository process', () => {
136
+ write(
137
+ '.hgignore',
138
+ ['syntax: glob', '**/*.generated.css', 're:^legacy/.+\\.js$', ''].join(
139
+ '\n',
140
+ ),
141
+ );
142
+ write('src/theme.generated.css', 'x');
143
+ write('legacy/file.js', 'x');
144
+ write('src/file.js', 'x');
145
+
146
+ expect(declarations('src/theme.generated.css')[0]).toMatch(/\.hgignore:2/);
147
+ expect(declarations('legacy/file.js')[0]).toMatch(/\.hgignore:3/);
148
+ expect(declarations('src/file.js')).toEqual([]);
149
+ });
150
+ });
151
+
152
+ describe('leading generated comments', () => {
153
+ it.each([
154
+ ['// @generated\nexport const x = 1;\n', '@generated'],
155
+ [
156
+ '/* @partially-generated */\nexport const x = 1;\n',
157
+ '@partially-generated',
158
+ ],
159
+ [
160
+ '// Code generated by Acme. DO NOT EDIT.\nconst x = 1;\n',
161
+ 'Code generated',
162
+ ],
163
+ ['#!/usr/bin/env node\n// @generated\nconsole.log(1);\n', '@generated'],
164
+ ])('protects a recognized leading marker', (source, expected) => {
165
+ write('file.js', source);
166
+ expect(declarations('file.js')[0]).toContain(expected);
167
+ });
168
+
169
+ it('recognizes hash comments after a shebang in an extensionless file', () => {
170
+ write('script', '#!/bin/sh\n# @generated\necho hi\n');
171
+ expect(declarations('script')[0]).toContain('@generated');
172
+ });
173
+
174
+ it('does not treat a marker after authored code as protection', () => {
175
+ write('file.js', 'export const authored = true;\n// @generated\n');
176
+ expect(declarations('file.js')).toEqual([]);
177
+ });
178
+
179
+ it('does not accept longer generated-like annotations', () => {
180
+ write('file.js', '// @generated-code\nexport const authored = true;\n');
181
+ expect(declarations('file.js')).toEqual([]);
182
+ });
183
+
184
+ it('does not mistake a leading CSS id selector for a comment', () => {
185
+ write('file.css', '#root { color: red; }\n/* @generated */\n');
186
+ expect(declarations('file.css')).toEqual([]);
187
+ });
188
+
189
+ it('extracts an exact regeneration command from a generated header', () => {
190
+ const file = write(
191
+ 'theme.css',
192
+ '/*\n * @generated\n * Command: pnpm astryx theme build src/theme.ts\n */\n',
193
+ );
194
+ const protection = createFileProtectionResolver(root).classify(file)[0];
195
+ expect(protection.command).toBe('pnpm astryx theme build src/theme.ts');
196
+ });
197
+ });
198
+
199
+ describe('hard boundaries and fail-closed parsing', () => {
200
+ it('protects dependency metadata, VCS metadata leaves, symlinks, and paths outside root', () => {
201
+ const dependency = write('node_modules/pkg/index.js', 'x');
202
+ const yarnDependency = write('.yarn/unplugged/pkg/index.js', 'x');
203
+ const yarnVirtual = write('.yarn/__virtual__/pkg/index.js', 'x');
204
+ const yarnInstallState = write('.yarn/install-state.gz', 'x');
205
+ const yarnPatch = write('.yarn/patches/pkg.patch', 'x');
206
+ const pnp = write('.pnp.cjs', 'x');
207
+ const pnpData = write('.pnp.data.json', '{}');
208
+ const metadata = write('.git', 'gitdir: elsewhere\n');
209
+ const target = write('target.js', 'x');
210
+ const link = path.join(root, 'link.js');
211
+ fs.symlinkSync(target, link);
212
+ const resolver = createFileProtectionResolver(root);
213
+
214
+ expect(resolver.classify(dependency)[0].reason).toBe('dependency');
215
+ expect(resolver.classify(yarnDependency)[0].reason).toBe('dependency');
216
+ expect(resolver.classify(yarnVirtual)[0].reason).toBe('dependency');
217
+ expect(resolver.classify(yarnInstallState)[0].reason).toBe('dependency');
218
+ expect(resolver.classify(yarnPatch)).toEqual([]);
219
+ expect(resolver.classify(pnp)[0].reason).toBe('dependency');
220
+ expect(resolver.classify(pnpData)[0].reason).toBe('dependency');
221
+ expect(resolver.classify(metadata)[0].reason).toBe('vcs');
222
+ expect(resolver.classify(link)[0].reason).toBe('symlink');
223
+ expect(
224
+ resolver.classify(path.join(root, '..', 'outside.js'))[0].reason,
225
+ ).toBe('outside-root');
226
+ });
227
+
228
+ it('rejects an .hgignore include reached through a symlink', () => {
229
+ const outside = path.join(
230
+ os.tmpdir(),
231
+ `astryx-ignore-${process.pid}-${Date.now()}`,
232
+ );
233
+ fs.writeFileSync(outside, 'syntax: glob\n*.generated\n');
234
+ try {
235
+ fs.symlinkSync(outside, path.join(root, 'rules'));
236
+ write('.hgignore', 'include:rules\n');
237
+ expect(() => createFileProtectionResolver(root)).toThrow(/symbolic link/);
238
+ } finally {
239
+ fs.rmSync(outside, {force: true});
240
+ }
241
+ });
242
+
243
+ it('fails before use when a protection source cannot be parsed', () => {
244
+ write('.hgignore', 'syntax: regexp\n[unterminated\n');
245
+ expect(() => createFileProtectionResolver(root)).toThrow(
246
+ ProtectionSourceError,
247
+ );
248
+ expect(() => createFileProtectionResolver(root)).toThrow(/\.hgignore/);
249
+ });
250
+ });
@@ -9,6 +9,7 @@
9
9
  * nearest package.json `type` decides `.js`, matching Node's package scopes.
10
10
  * Normal loads retain module caching. `fresh` is an explicit migration-only
11
11
  * escape hatch for rereading files that a codemod changed during this process.
12
+ * Anything the module writes to stdout while it loads goes to stderr.
12
13
  *
13
14
  * @param {string} file absolute path
14
15
  * @param {{fresh?: boolean}} [options]
@@ -7,7 +7,8 @@
7
7
  * user-authored module (`.ts` via jiti, `.mjs`/`.js` via native dynamic
8
8
  * import) and (b) find conventional files by basename in a fixed
9
9
  * load-precedence order. These helpers centralize that so the two callers stay
10
- * in lockstep.
10
+ * in lockstep. A module's stdout writes go to stderr while it loads, so
11
+ * project code that prints cannot corrupt a `--json` envelope.
11
12
  *
12
13
  * `loadModuleWithParser` builds on these primitives to provide the single
13
14
  * load/validation boundary shared by config, integration, codemod, and
@@ -16,6 +17,7 @@
16
17
  */
17
18
 
18
19
  import * as path from 'node:path';
20
+ import {AsyncLocalStorage} from 'node:async_hooks';
19
21
  import {createRequire} from 'node:module';
20
22
  import {pathToFileURL} from 'node:url';
21
23
  import * as fs from 'node:fs';
@@ -56,6 +58,43 @@ function isCommonJsFile(file) {
56
58
  }
57
59
  }
58
60
 
61
+ let loadsInFlight = 0;
62
+ /** @type {typeof process.stdout.write | undefined} */
63
+ let realStdoutWrite;
64
+ /** Set in the async context of a module load, and only there. */
65
+ const moduleLoad = new AsyncLocalStorage();
66
+
67
+ /**
68
+ * Run a module load with the stdout writes made in its async context sent to
69
+ * stderr. Writes from any other context pass through, so the CLI's own output
70
+ * stays on stdout even while an abandoned load is still in flight. The gate
71
+ * is installed for the first overlapping load and removed after the last.
72
+ * @template T
73
+ * @param {() => Promise<T>} load
74
+ * @returns {Promise<T>}
75
+ */
76
+ async function withStdoutOnStderr(load) {
77
+ if (loadsInFlight++ === 0) {
78
+ const write = process.stdout.write;
79
+ realStdoutWrite = write;
80
+ process.stdout.write = /** @type {any} */ (
81
+ function (/** @type {any} */ chunk, /** @type {any[]} */ ...rest) {
82
+ return moduleLoad.getStore()
83
+ ? process.stderr.write(chunk, ...rest)
84
+ : write.call(process.stdout, chunk, ...rest);
85
+ }
86
+ );
87
+ }
88
+ try {
89
+ return await moduleLoad.run(true, load);
90
+ } finally {
91
+ if (--loadsInFlight === 0 && realStdoutWrite) {
92
+ process.stdout.write = realStdoutWrite;
93
+ realStdoutWrite = undefined;
94
+ }
95
+ }
96
+ }
97
+
59
98
  /**
60
99
  * Import a user-authored module. `.ts` is loaded via jiti; `.mjs`/`.js` use
61
100
  * native dynamic import for ordinary cached reads. A fresh `.ts` read uses a
@@ -64,12 +103,22 @@ function isCommonJsFile(file) {
64
103
  * nearest package.json `type` decides `.js`, matching Node's package scopes.
65
104
  * Normal loads retain module caching. `fresh` is an explicit migration-only
66
105
  * escape hatch for rereading files that a codemod changed during this process.
106
+ * Anything the module writes to stdout while it loads goes to stderr.
67
107
  *
68
108
  * @param {string} file absolute path
69
109
  * @param {{fresh?: boolean}} [options]
70
110
  * @returns {Promise<Record<string, unknown>>}
71
111
  */
72
112
  export async function importUserModule(file, {fresh = false} = {}) {
113
+ return await withStdoutOnStderr(() => importModule(file, fresh));
114
+ }
115
+
116
+ /**
117
+ * @param {string} file absolute path
118
+ * @param {boolean} fresh
119
+ * @returns {Promise<Record<string, unknown>>}
120
+ */
121
+ async function importModule(file, fresh) {
73
122
  if (fresh && file.endsWith('.ts')) {
74
123
  return await createJiti(import.meta.url, {moduleCache: false}).import(file);
75
124
  }
@@ -0,0 +1,332 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ /**
4
+ * @file A project module that prints while it loads must not reach stdout.
5
+ * Every `astryx.config.*` and integration manifest runs through
6
+ * `importUserModule`, so one stray `console.log` there used to corrupt every
7
+ * `--json` envelope. The loader cases run in a real Node process (vitest
8
+ * replaces `console`); the CLI cases spawn the real binary.
9
+ */
10
+
11
+ import {afterEach, beforeEach, describe, expect, it} from 'vitest';
12
+ import {spawnSync} from 'node:child_process';
13
+ import * as fs from 'node:fs';
14
+ import * as os from 'node:os';
15
+ import * as path from 'node:path';
16
+ import {fileURLToPath, pathToFileURL} from 'node:url';
17
+
18
+ const HERE = path.dirname(fileURLToPath(import.meta.url));
19
+ const LOADER_URL = pathToFileURL(path.join(HERE, 'module-loader.mjs')).href;
20
+ const CLI = path.resolve(HERE, '..', '..', 'clients', 'cli', 'bin', 'astryx.mjs');
21
+
22
+ const PRINTS =
23
+ "console.log('module log');\nprocess.stdout.write('module write\\n');\n";
24
+
25
+ let tmpDir;
26
+
27
+ beforeEach(() => {
28
+ tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'astryx-module-stdout-'));
29
+ });
30
+
31
+ afterEach(() => {
32
+ fs.rmSync(tmpDir, {recursive: true, force: true});
33
+ });
34
+
35
+ /** @param {string} rel @param {string} body @returns {string} */
36
+ function write(rel, body) {
37
+ const file = path.join(tmpDir, rel);
38
+ fs.mkdirSync(path.dirname(file), {recursive: true});
39
+ fs.writeFileSync(file, body);
40
+ return file;
41
+ }
42
+
43
+ /**
44
+ * Run `body` as an ES module in a real Node process with `importUserModule`
45
+ * in scope.
46
+ * @param {string} body
47
+ */
48
+ function runWithLoader(body) {
49
+ return spawnSync(
50
+ process.execPath,
51
+ [
52
+ '--input-type=module',
53
+ '-e',
54
+ `import {importUserModule} from ${JSON.stringify(LOADER_URL)};\n${body}`,
55
+ ],
56
+ {encoding: 'utf8', timeout: 60_000, stdio: ['ignore', 'pipe', 'pipe']},
57
+ );
58
+ }
59
+
60
+ describe('importUserModule keeps module output off stdout', () => {
61
+ it.each([
62
+ ['.mjs', 'mod.mjs', false, `${PRINTS}export default {answer: 42};\n`],
63
+ ['ESM .js', 'esm/mod.js', false, `${PRINTS}export default {answer: 42};\n`],
64
+ [
65
+ '.ts',
66
+ 'mod.ts',
67
+ false,
68
+ `${PRINTS}const answer: number = 42;\nexport default {answer};\n`,
69
+ ],
70
+ ['fresh .mjs', 'mod.mjs', true, `${PRINTS}export default {answer: 42};\n`],
71
+ [
72
+ 'fresh .ts',
73
+ 'mod.ts',
74
+ true,
75
+ `${PRINTS}const answer: number = 42;\nexport default {answer};\n`,
76
+ ],
77
+ [
78
+ 'fresh CommonJS .js',
79
+ 'cjs/mod.js',
80
+ true,
81
+ `${PRINTS}module.exports = {answer: 42};\n`,
82
+ ],
83
+ ])('sends a printing %s module to stderr', (_label, rel, fresh, source) => {
84
+ write('esm/package.json', JSON.stringify({type: 'module'}));
85
+ write('cjs/package.json', JSON.stringify({type: 'commonjs'}));
86
+ const file = write(rel, source);
87
+
88
+ const r = runWithLoader(
89
+ `const before = process.stdout.write;
90
+ const mod = await importUserModule(${JSON.stringify(file)}, {fresh: ${fresh}});
91
+ process.stdout.write(JSON.stringify({answer: mod.default?.answer, restored: process.stdout.write === before}));`,
92
+ );
93
+
94
+ expect(r.status, r.stderr).toBe(0);
95
+ expect(JSON.parse(r.stdout)).toEqual({answer: 42, restored: true});
96
+ expect(r.stderr).toContain('module log');
97
+ expect(r.stderr).toContain('module write');
98
+ });
99
+
100
+ it('keeps stdout redirected until the last overlapping load settles', () => {
101
+ const first = write(
102
+ 'first.mjs',
103
+ "await new Promise(resolve => setTimeout(resolve, 20));\nprocess.stdout.write('first write\\n');\nexport default 'first';\n",
104
+ );
105
+ const second = write(
106
+ 'second.mjs',
107
+ "await new Promise(resolve => setTimeout(resolve, 150));\nprocess.stdout.write('second write\\n');\nexport default 'second';\n",
108
+ );
109
+
110
+ const r = runWithLoader(
111
+ `const before = process.stdout.write;
112
+ const mods = await Promise.all([
113
+ importUserModule(${JSON.stringify(first)}),
114
+ importUserModule(${JSON.stringify(second)}),
115
+ ]);
116
+ process.stdout.write(JSON.stringify({loaded: mods.map(mod => mod.default), restored: process.stdout.write === before}));`,
117
+ );
118
+
119
+ expect(r.status, r.stderr).toBe(0);
120
+ expect(JSON.parse(r.stdout)).toEqual({
121
+ loaded: ['first', 'second'],
122
+ restored: true,
123
+ });
124
+ expect(r.stderr).toContain('first write');
125
+ expect(r.stderr).toContain('second write');
126
+ });
127
+
128
+ it('leaves the caller on stdout while an abandoned load is still in flight', () => {
129
+ const slow = write(
130
+ 'slow.mjs',
131
+ "await new Promise(resolve => setTimeout(resolve, 150));\nprocess.stdout.write('slow write\\n');\nexport default 'slow';\n",
132
+ );
133
+
134
+ const r = runWithLoader(
135
+ `const before = process.stdout.write;
136
+ const slow = importUserModule(${JSON.stringify(slow)});
137
+ const sibling = new Promise((_, reject) => setTimeout(() => reject(new Error('sibling failed')), 10));
138
+ try {
139
+ await Promise.all([slow, sibling]);
140
+ } catch (error) {
141
+ process.stdout.write('caught: ' + error.message + '\\n');
142
+ }
143
+ await slow;
144
+ process.stdout.write('restored: ' + (process.stdout.write === before) + '\\n');`,
145
+ );
146
+
147
+ expect(r.status, r.stderr).toBe(0);
148
+ expect(r.stdout).toBe('caught: sibling failed\nrestored: true\n');
149
+ expect(r.stderr).toContain('slow write');
150
+ });
151
+
152
+ it('restores stdout when the module throws', () => {
153
+ const file = write(
154
+ 'boom.mjs',
155
+ "process.stdout.write('boom write\\n');\nthrow new Error('boom');\n",
156
+ );
157
+
158
+ const r = runWithLoader(
159
+ `const before = process.stdout.write;
160
+ let message = null;
161
+ try {
162
+ await importUserModule(${JSON.stringify(file)});
163
+ } catch (error) {
164
+ message = error.message;
165
+ }
166
+ process.stdout.write(JSON.stringify({message, restored: process.stdout.write === before}));`,
167
+ );
168
+
169
+ expect(r.status, r.stderr).toBe(0);
170
+ expect(JSON.parse(r.stdout)).toEqual({message: 'boom', restored: true});
171
+ expect(r.stderr).toContain('boom write');
172
+ });
173
+ });
174
+
175
+ /** @param {string[]} args */
176
+ function runCli(args) {
177
+ return spawnSync(process.execPath, [CLI, ...args], {
178
+ cwd: tmpDir,
179
+ encoding: 'utf8',
180
+ timeout: 60_000,
181
+ stdio: ['ignore', 'pipe', 'pipe'],
182
+ env: {...process.env, FORCE_COLOR: '0', CI: ''},
183
+ });
184
+ }
185
+
186
+ /**
187
+ * Stdout must be exactly one envelope and the module's output must be on
188
+ * stderr.
189
+ * @param {ReturnType<typeof runCli>} r
190
+ * @param {string} printed
191
+ */
192
+ function expectOneEnvelope(r, printed) {
193
+ expect(r.signal).toBeNull();
194
+ const envelope = JSON.parse(r.stdout);
195
+ expect(envelope.apiVersion).toBe(1);
196
+ expect(r.stdout).not.toContain(printed);
197
+ expect(r.stderr).toContain(printed);
198
+ return envelope;
199
+ }
200
+
201
+ /** A declared dependency that ships a printing manifest and one component. */
202
+ function installNoisyIntegration() {
203
+ write(
204
+ 'package.json',
205
+ JSON.stringify({
206
+ name: 'consumer',
207
+ private: true,
208
+ type: 'module',
209
+ dependencies: {'@acme/noisy': '1.0.0'},
210
+ }),
211
+ );
212
+ write(
213
+ 'node_modules/@acme/noisy/package.json',
214
+ JSON.stringify({name: '@acme/noisy', version: '1.0.0'}),
215
+ );
216
+ write(
217
+ 'node_modules/@acme/noisy/astryx.integration.mjs',
218
+ "console.log('manifest log');\nexport default {components: './components'};\n",
219
+ );
220
+ write(
221
+ 'node_modules/@acme/noisy/components/Widget.doc.mjs',
222
+ "export const docs = {name: 'Widget', usage: {description: 'A widget'}};\n",
223
+ );
224
+ write(
225
+ 'node_modules/@acme/noisy/components/Widget.tsx',
226
+ 'export function Widget() { return null; }\n',
227
+ );
228
+ }
229
+
230
+ describe('--json stdout stays one envelope when project modules print', () => {
231
+ it.each([
232
+ [['--json', 'docs'], 'docs.list'],
233
+ [['--json', 'template', '--list'], 'template.list'],
234
+ [['--json', 'doctor'], 'doctor'],
235
+ ])('astryx.config.mjs: %j', (args, type) => {
236
+ write(
237
+ 'package.json',
238
+ JSON.stringify({name: 'consumer', private: true, type: 'module'}),
239
+ );
240
+ write(
241
+ 'astryx.config.mjs',
242
+ "console.log('config log');\nprocess.stdout.write('config write\\n');\nexport default {integrations: []};\n",
243
+ );
244
+
245
+ const r = runCli(args);
246
+
247
+ expect(expectOneEnvelope(r, 'config log').type).toBe(type);
248
+ expect(r.stderr).toContain('config write');
249
+ });
250
+
251
+ it('astryx.config.ts through jiti', () => {
252
+ write(
253
+ 'package.json',
254
+ JSON.stringify({name: 'consumer', private: true, type: 'module'}),
255
+ );
256
+ write(
257
+ 'astryx.config.ts',
258
+ "console.log('config log');\nconst config: {integrations: string[]} = {integrations: []};\nexport default config;\n",
259
+ );
260
+
261
+ const r = runCli(['--json', 'template', '--list']);
262
+
263
+ expect(r.status, r.stderr).toBe(0);
264
+ expect(expectOneEnvelope(r, 'config log').type).toBe('template.list');
265
+ });
266
+
267
+ it('CommonJS astryx.config.js reloaded fresh by upgrade', () => {
268
+ write('package.json', JSON.stringify({name: 'consumer', private: true}));
269
+ write(
270
+ 'node_modules/@astryxdesign/core/package.json',
271
+ JSON.stringify({name: '@astryxdesign/core', version: '0.6.3'}),
272
+ );
273
+ write(
274
+ 'astryx.config.js',
275
+ "console.log('config log');\nmodule.exports = {integrations: []};\n",
276
+ );
277
+
278
+ const r = runCli(['--json', 'upgrade', '--from', '0.5.0']);
279
+
280
+ expect(r.status, r.stderr).toBe(0);
281
+ expect(expectOneEnvelope(r, 'config log').type).toBe('upgrade.run');
282
+ });
283
+
284
+ it('an error envelope while sibling project loads are still in flight', () => {
285
+ // search rejects on a Core without sources before its parallel loads settle.
286
+ write(
287
+ 'package.json',
288
+ JSON.stringify({name: 'consumer', private: true, type: 'module'}),
289
+ );
290
+ write(
291
+ 'node_modules/@astryxdesign/core/package.json',
292
+ JSON.stringify({name: '@astryxdesign/core', version: '0.6.3'}),
293
+ );
294
+ write(
295
+ 'astryx.config.mjs',
296
+ "console.log('config log');\nexport default {integrations: []};\n",
297
+ );
298
+
299
+ const r = runCli(['--json', 'search', 'button']);
300
+
301
+ expect(r.status).toBe(1);
302
+ expect(typeof expectOneEnvelope(r, 'config log').code).toBe('string');
303
+ });
304
+
305
+ it('an autolinked integration manifest', () => {
306
+ installNoisyIntegration();
307
+
308
+ const r = runCli(['--json', 'docs']);
309
+
310
+ expect(r.status, r.stderr).toBe(0);
311
+ expect(expectOneEnvelope(r, 'manifest log').type).toBe('docs.list');
312
+ });
313
+
314
+ it.each([
315
+ [['--json', 'integration', 'add', 'doc', 'deploying'], 'integration.add'],
316
+ [['--json', 'doctor', 'integration', 'validate'], 'integration.validate'],
317
+ ])('the local package manifest: %j', (args, type) => {
318
+ write(
319
+ 'package.json',
320
+ JSON.stringify({name: 'acme-kit', version: '1.0.0', type: 'module'}),
321
+ );
322
+ write(
323
+ 'astryx.integration.mjs',
324
+ "console.log('manifest log');\nexport default {};\n",
325
+ );
326
+
327
+ const r = runCli(args);
328
+
329
+ expect(r.status, r.stderr).toBe(0);
330
+ expect(expectOneEnvelope(r, 'manifest log').type).toBe(type);
331
+ });
332
+ });
@@ -7,7 +7,7 @@
7
7
  *
8
8
  * - Absolute paths (e.g. `/tmp/x`) — re-rooted by `path.join` is silent;
9
9
  * better to fail loudly. Pass `{allowAbsolute: true}` to opt in.
10
- * - Paths that escape via `..` segments.
10
+ * - Paths that escape via `..` segments or a symlink, dangling or not.
11
11
  *
12
12
  * Returns the resolved absolute path on success.
13
13
  *
@@ -19,7 +19,8 @@
19
19
  * @param {string} [options.label='path'] - Human-readable name of the arg
20
20
  * being checked (used in error messages, e.g. 'output directory').
21
21
  * @returns {string} Absolute resolved path inside `rootDir`.
22
- * @throws {PathSafetyError}
22
+ * @throws {PathSafetyError} An escape carries the registered
23
+ * `ERR_PATH_TRAVERSAL`, so it reaches an envelope correctly even uncaught.
23
24
  */
24
25
  export function assertWithin(targetPath: string, rootDir: string, options?: {
25
26
  allowAbsolute?: boolean | undefined;