@astryxdesign/cli 0.6.4 → 0.6.5-canary.031021b

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 (288) hide show
  1. package/CHANGELOG.md +56 -0
  2. package/README.md +97 -90
  3. package/api/build/build.doc.mjs +6 -1
  4. package/api/build/build.test.mjs +22 -0
  5. package/api/build/kit/kit.mjs +44 -5
  6. package/api/component/_adapter.d.mts +25 -0
  7. package/api/component/_adapter.mjs +59 -5
  8. package/api/component/component.d.mts +6 -3
  9. package/api/component/component.doc.mjs +37 -17
  10. package/api/component/component.mjs +249 -9
  11. package/api/component/component.type.d.mts +25 -0
  12. package/api/component/component.type.mjs +44 -0
  13. package/api/discover/_adapter.d.mts +114 -6
  14. package/api/discover/_adapter.mjs +372 -17
  15. package/api/discover/_adapter.test.mjs +215 -0
  16. package/api/discover/_catalog-view.d.mts +115 -0
  17. package/api/discover/_catalog-view.mjs +203 -0
  18. package/api/discover/_catalog-view.test.mjs +128 -0
  19. package/api/discover/detail/detail.d.mts +18 -6
  20. package/api/discover/detail/detail.mjs +67 -13
  21. package/api/discover/detail/detail.test.mjs +85 -0
  22. package/api/discover/detail/item/item.d.mts +26 -0
  23. package/api/discover/detail/item/item.mjs +78 -0
  24. package/api/discover/detail/item/item.test.mjs +73 -0
  25. package/api/discover/discover.d.mts +3 -9
  26. package/api/discover/discover.doc.mjs +61 -18
  27. package/api/discover/discover.mjs +220 -36
  28. package/api/discover/discover.test.mjs +11 -2
  29. package/api/discover/discover.type.d.mts +147 -8
  30. package/api/discover/discover.type.mjs +102 -12
  31. package/api/discover/list/list.d.mts +20 -6
  32. package/api/discover/list/list.mjs +45 -12
  33. package/api/discover/list/list.test.mjs +46 -0
  34. package/api/discover/search/search.d.mts +18 -16
  35. package/api/discover/search/search.mjs +102 -56
  36. package/api/discover/search/search.test.mjs +144 -10
  37. package/api/docs/_adapter.d.mts +8 -3
  38. package/api/docs/_adapter.mjs +14 -6
  39. package/api/docs/docOverlays.test.mjs +27 -1
  40. package/api/docs/docs.doc.mjs +2 -2
  41. package/api/doctor/doctor.d.mts +8 -3
  42. package/api/doctor/doctor.doc.mjs +17 -8
  43. package/api/doctor/doctor.mjs +90 -9
  44. package/api/doctor/doctor.test.mjs +122 -10
  45. package/api/doctor/doctor.type.d.mts +1 -1
  46. package/api/doctor/doctor.type.mjs +1 -1
  47. package/api/gap-report/gap-report.doc.mjs +19 -10
  48. package/api/hook/hook.doc.mjs +6 -3
  49. package/api/index.d.mts +1 -0
  50. package/api/index.mjs +5 -3
  51. package/api/init/init.doc.mjs +17 -12
  52. package/api/integration/add-helpers.d.mts +5 -2
  53. package/api/integration/add-helpers.mjs +36 -9
  54. package/api/integration/add-theme.mjs +22 -1
  55. package/api/integration/add-theme.test.mjs +34 -0
  56. package/api/integration/authoring-checks.mjs +2 -2
  57. package/api/integration/integrationPackCheck.doc.mjs +3 -3
  58. package/api/integration/pack-check.lifecycle-output.test.mjs +107 -0
  59. package/api/integration/pack-check.mjs +82 -9
  60. package/api/integration/pack-check.test.mjs +90 -0
  61. package/api/integration/pack-check.type.mjs +1 -1
  62. package/api/json/assertResponse.doc.mjs +1 -1
  63. package/api/json/isError.doc.mjs +1 -1
  64. package/api/search/search.d.mts +27 -1
  65. package/api/search/search.doc.mjs +2 -2
  66. package/api/search/search.mjs +228 -16
  67. package/api/swizzle/swizzle.doc.mjs +7 -5
  68. package/api/template/copy/copy.mjs +1 -1
  69. package/api/template/copy/copy.test.mjs +9 -0
  70. package/api/template/template.doc.mjs +2 -1
  71. package/api/theme/add/add.mjs +17 -25
  72. package/api/theme/add/add.rollback.test.mjs +158 -0
  73. package/api/theme/add/add.staging.test.mjs +40 -23
  74. package/api/theme/build/build.family.test.mjs +7 -12
  75. package/api/theme/build/build.mjs +8 -18
  76. package/api/theme/build/build.rollback.test.mjs +148 -0
  77. package/api/theme/generateTonalPalette.doc.mjs +1 -2
  78. package/api/theme/listThemes.doc.mjs +1 -1
  79. package/api/theme/themeAdd.doc.mjs +9 -10
  80. package/api/theme/themeBuild.doc.mjs +13 -13
  81. package/api/theme/themeList.doc.mjs +1 -1
  82. package/api/theme/themeListAvailable.doc.mjs +2 -1
  83. package/api/theme/themePaletteGenerate.doc.mjs +15 -8
  84. package/api/theme/themeTargets.doc.mjs +3 -2
  85. package/api/theme/themeTemplate.doc.mjs +2 -1
  86. package/api/upgrade/run/files-changed.test.mjs +111 -0
  87. package/api/upgrade/run/run.mjs +5 -3
  88. package/api/upgrade/upgrade.doc.mjs +24 -22
  89. package/api/upgrade/upgrade.type.mjs +2 -2
  90. package/assets/codemods/__tests__/runner.test.mjs +3 -1
  91. package/assets/codemods/file-count.test.mjs +163 -0
  92. package/assets/codemods/integration-runner.mjs +3 -3
  93. package/assets/codemods/runner.mjs +5 -4
  94. package/assets/docs/README.md +4 -2
  95. package/assets/docs/browser-support.doc.mjs +11 -11
  96. package/assets/docs/color.doc.mjs +8 -2
  97. package/assets/docs/elevation.doc.mjs +6 -4
  98. package/assets/docs/getting-started.doc.mjs +5 -16
  99. package/assets/docs/icons.doc.mjs +2 -21
  100. package/assets/docs/illustrations.doc.mjs +7 -15
  101. package/assets/docs/internationalization.doc.mjs +7 -5
  102. package/assets/docs/layout.doc.dense.mjs +130 -82
  103. package/assets/docs/layout.doc.mjs +133 -77
  104. package/assets/docs/migration.doc.mjs +19 -21
  105. package/assets/docs/motion.doc.mjs +16 -3
  106. package/assets/docs/principles.doc.dense.mjs +5 -5
  107. package/assets/docs/principles.doc.mjs +8 -0
  108. package/assets/docs/principles.doc.zh.mjs +6 -6
  109. package/assets/docs/shape.doc.mjs +8 -3
  110. package/assets/docs/spacing.doc.mjs +7 -2
  111. package/assets/docs/styling-libraries.doc.mjs +6 -2
  112. package/assets/docs/styling.doc.mjs +19 -23
  113. package/assets/docs/theme.doc.dense.mjs +58 -18
  114. package/assets/docs/theme.doc.mjs +57 -47
  115. package/assets/docs/theme.doc.zh.mjs +9 -8
  116. package/assets/docs/tokens.doc.dense.mjs +2 -2
  117. package/assets/docs/tokens.doc.mjs +389 -8
  118. package/assets/docs/tokens.doc.zh.mjs +2 -2
  119. package/assets/docs/tree/add-a-component.doc.mjs +75 -0
  120. package/assets/docs/tree/add-a-theme.doc.mjs +85 -0
  121. package/assets/docs/tree/add-a-topic.doc.mjs +144 -0
  122. package/assets/docs/tree/agent-guidance.doc.mjs +138 -0
  123. package/assets/docs/tree/block-template.doc.mjs +130 -0
  124. package/assets/docs/tree/build-the-template.doc.mjs +28 -0
  125. package/assets/docs/tree/building-blocks.doc.mjs +46 -0
  126. package/assets/docs/tree/check-your-docs.doc.mjs +137 -0
  127. package/assets/docs/tree/checks.doc.mjs +119 -0
  128. package/assets/docs/tree/codemods.doc.mjs +147 -0
  129. package/assets/docs/tree/component-family.doc.mjs +113 -0
  130. package/assets/docs/tree/component-imports.doc.mjs +69 -0
  131. package/assets/docs/tree/component-lookups.doc.mjs +149 -0
  132. package/assets/docs/tree/components.doc.mjs +23 -0
  133. package/assets/docs/tree/configuration.doc.mjs +23 -0
  134. package/assets/docs/tree/debug-and-gap-reports.doc.mjs +182 -0
  135. package/assets/docs/tree/define-the-theme.doc.mjs +118 -0
  136. package/assets/docs/tree/describe-the-component.doc.mjs +57 -0
  137. package/assets/docs/tree/docs.doc.mjs +21 -0
  138. package/assets/docs/tree/document-the-template.doc.mjs +28 -0
  139. package/assets/docs/tree/document-the-theme.doc.mjs +68 -0
  140. package/assets/docs/tree/export-template-assets.doc.mjs +147 -0
  141. package/assets/docs/tree/extend-or-replace.doc.mjs +103 -0
  142. package/assets/docs/tree/fonts-and-assets.doc.mjs +106 -0
  143. package/assets/docs/tree/generate-a-palette.doc.mjs +66 -0
  144. package/assets/docs/tree/grade-template-with-agent.doc.mjs +105 -0
  145. package/assets/docs/tree/help.doc.mjs +16 -0
  146. package/assets/docs/tree/integrations.doc.mjs +25 -451
  147. package/assets/docs/tree/links.doc.mjs +98 -0
  148. package/assets/docs/tree/package-and-test.doc.mjs +32 -0
  149. package/assets/docs/tree/page-template.doc.mjs +71 -0
  150. package/assets/docs/tree/publishing.doc.mjs +111 -0
  151. package/assets/docs/tree/quick-start.doc.mjs +272 -0
  152. package/assets/docs/tree/replace-a-core-component.doc.mjs +104 -0
  153. package/assets/docs/tree/replace-a-core-template.doc.mjs +172 -0
  154. package/assets/docs/tree/sections-and-placement.doc.mjs +108 -0
  155. package/assets/docs/tree/see-it-in-an-app.doc.mjs +59 -0
  156. package/assets/docs/tree/ship.doc.mjs +16 -0
  157. package/assets/docs/tree/short-and-findable.doc.mjs +108 -0
  158. package/assets/docs/tree/single-component.doc.mjs +165 -0
  159. package/assets/docs/tree/start-a-template.doc.mjs +143 -0
  160. package/assets/docs/tree/subcomponent.doc.mjs +115 -0
  161. package/assets/docs/tree/template-assets.doc.mjs +64 -0
  162. package/assets/docs/tree/template-doc-overview.doc.mjs +109 -0
  163. package/assets/docs/tree/template-fonts.doc.mjs +102 -0
  164. package/assets/docs/tree/template-grading-rubric.doc.mjs +452 -0
  165. package/assets/docs/tree/template-icons.doc.mjs +97 -0
  166. package/assets/docs/tree/template-images-media.doc.mjs +127 -0
  167. package/assets/docs/tree/template-styles.doc.mjs +93 -0
  168. package/assets/docs/tree/templates.doc.mjs +34 -0
  169. package/assets/docs/tree/test-in-an-app.doc.mjs +115 -0
  170. package/assets/docs/tree/test-template-in-app.doc.mjs +128 -0
  171. package/assets/docs/tree/themes.doc.mjs +39 -0
  172. package/assets/docs/tree/troubleshooting.doc.mjs +149 -0
  173. package/assets/docs/tree/upgrading.doc.mjs +103 -0
  174. package/assets/docs/tree/use-a-theme-in-an-app.doc.mjs +51 -0
  175. package/assets/docs/tree/verify-packed-template.doc.mjs +77 -0
  176. package/assets/docs/tree/versioning.doc.mjs +161 -0
  177. package/assets/docs/tree/write-good-templates.doc.mjs +64 -0
  178. package/assets/docs/tree/write-the-template-file.doc.mjs +154 -0
  179. package/assets/docs/typography.doc.mjs +24 -4
  180. package/assets/docs/working-with-ai.doc.mjs +30 -22
  181. package/assets/templates/blocks/components/InternationalizationProvider/InternationalizationProvider01ShippedLocale.tsx +1 -1
  182. package/authoring/config/config.doc.mjs +9 -1
  183. package/authoring/config/parse.d.mts +2 -0
  184. package/authoring/config/parse.mjs +19 -0
  185. package/authoring/config/parse.test.mjs +8 -0
  186. package/authoring/config/type.ts +11 -0
  187. package/authoring/discover/discover.doc.d.mts +13 -0
  188. package/authoring/discover/discover.doc.mjs +138 -0
  189. package/authoring/discover/parse.d.mts +24 -0
  190. package/authoring/discover/parse.mjs +128 -0
  191. package/authoring/discover/parse.test.mjs +124 -0
  192. package/authoring/discover/type.ts +87 -0
  193. package/authoring/doctypes/_schema.d.mts +3 -2
  194. package/authoring/doctypes/_schema.mjs +6 -0
  195. package/authoring/doctypes/base/graph-fields.doc.mjs +3 -3
  196. package/authoring/doctypes/base/type.ts +4 -2
  197. package/authoring/doctypes/component/component.doc.mjs +6 -0
  198. package/authoring/doctypes/component/type.ts +8 -0
  199. package/authoring/doctypes/reference/reference.doc.mjs +7 -0
  200. package/authoring/doctypes/reference/type.ts +5 -0
  201. package/authoring/doctypes/schema/schema.doc.mjs +2 -2
  202. package/authoring/doctypes/template/template.doc.mjs +1 -1
  203. package/authoring/doctypes/template/type.ts +2 -2
  204. package/authoring/index.d.mts +1 -0
  205. package/authoring/index.d.ts +10 -0
  206. package/authoring/index.mjs +1 -0
  207. package/authoring/integration/integration.doc.mjs +12 -10
  208. package/clients/cli/commands/component/index.mjs +152 -55
  209. package/clients/cli/commands/component-batch.test.mjs +341 -0
  210. package/clients/cli/commands/component-ownership.test.mjs +89 -0
  211. package/clients/cli/commands/component.doc.mjs +27 -9
  212. package/clients/cli/commands/discover.doc.mjs +53 -9
  213. package/clients/cli/commands/discover.mjs +393 -118
  214. package/clients/cli/commands/discover.sources.test.mjs +267 -0
  215. package/clients/cli/commands/docs.doc.mjs +1 -1
  216. package/clients/cli/commands/docs.mjs +60 -17
  217. package/clients/cli/commands/doctor-integration-docs.doc.mjs +3 -2
  218. package/clients/cli/commands/doctor-integration.test.mjs +53 -0
  219. package/clients/cli/commands/doctor.doc.mjs +3 -1
  220. package/clients/cli/commands/doctor.mjs +49 -5
  221. package/clients/cli/commands/gap-report.doc.mjs +10 -9
  222. package/clients/cli/commands/init.doc.mjs +9 -6
  223. package/clients/cli/commands/integration-add.doc.mjs +9 -9
  224. package/clients/cli/commands/integration-authoring.test.mjs +61 -10
  225. package/clients/cli/commands/integration-pack.doc.mjs +5 -9
  226. package/clients/cli/commands/integration-real-world.test.mjs +1 -1
  227. package/clients/cli/commands/integration-verify.doc.mjs +22 -0
  228. package/clients/cli/commands/integration.doc.mjs +4 -4
  229. package/clients/cli/commands/integration.mjs +74 -43
  230. package/clients/cli/commands/manifest.doc.mjs +1 -1
  231. package/clients/cli/commands/search.doc.mjs +10 -3
  232. package/clients/cli/commands/search.mjs +21 -2
  233. package/clients/cli/commands/search.test.mjs +21 -4
  234. package/clients/cli/commands/swizzle.doc.mjs +1 -1
  235. package/clients/cli/commands/template.doc.mjs +1 -1
  236. package/clients/cli/commands/text-json-parity.test.mjs +7 -1
  237. package/clients/cli/commands/theme-add.doc.mjs +1 -1
  238. package/clients/cli/commands/theme-palette-generate.doc.mjs +3 -2
  239. package/clients/cli/commands/theme-palette.doc.mjs +1 -2
  240. package/clients/cli/commands/theme-targets.doc.mjs +2 -2
  241. package/clients/cli/commands/theme.doc.mjs +2 -1
  242. package/clients/cli/commands/upgrade.doc.mjs +62 -3
  243. package/clients/cli/index.mjs +28 -6
  244. package/clients/cli/lib/define-command.mjs +28 -4
  245. package/clients/cli/lib/define-command.test.mjs +54 -0
  246. package/clients/cli/lib/exit-codes.test.mjs +17 -1
  247. package/clients/cli/lib/json-shim.mjs +24 -14
  248. package/clients/cli/lib/manifest.mjs +18 -5
  249. package/clients/cli/lib/manifest.test.mjs +5 -2
  250. package/clients/cli/lib/parse-error-format.test.mjs +81 -0
  251. package/foundation/agent-docs/agent-docs.mjs +1 -1
  252. package/foundation/discovery/authoring-self-docs.mjs +1 -0
  253. package/foundation/discovery/authoring-self-docs.test.mjs +6 -2
  254. package/foundation/discovery/cli-self-docs.mjs +16 -2
  255. package/foundation/discovery/cli-self-docs.test.mjs +20 -0
  256. package/foundation/discovery/docs-discovery.mjs +5 -1
  257. package/foundation/discovery/docs-discovery.test.mjs +21 -0
  258. package/foundation/discovery/docs-section-key.d.mts +1 -1
  259. package/foundation/discovery/docs-section-key.mjs +1 -1
  260. package/foundation/doc-compiler/doc-loads.test.mjs +3 -2
  261. package/foundation/doc-compiler/inputs.test.mjs +0 -1
  262. package/foundation/doc-compiler/tree.d.mts +4 -0
  263. package/foundation/doc-compiler/tree.mjs +6 -1
  264. package/foundation/integrations/cli-requirement.d.mts +26 -6
  265. package/foundation/integrations/cli-requirement.mjs +46 -11
  266. package/foundation/integrations/cli-requirement.test.mjs +7 -2
  267. package/foundation/integrations/contribution-inventory.mjs +1 -1
  268. package/foundation/integrations/integrations.d.mts +14 -1
  269. package/foundation/integrations/integrations.mjs +41 -1
  270. package/foundation/integrations/integrations.test.mjs +31 -0
  271. package/foundation/response/batch.type.d.mts +33 -0
  272. package/foundation/response/batch.type.mjs +34 -0
  273. package/foundation/response/error-codes.doc.mjs +6 -8
  274. package/foundation/response/error-codes.test.mjs +30 -5
  275. package/foundation/response/response-types.doc.d.mts +4 -3
  276. package/foundation/response/response-types.doc.mjs +40 -10
  277. package/foundation/response/response-types.doc.test.mjs +23 -0
  278. package/foundation/response/response.doc.mjs +11 -10
  279. package/package.json +9 -9
  280. package/api/docs/docs.test.mjs +0 -243
  281. package/api/docs/integration-tree.test.mjs +0 -555
  282. package/api/docs/integrationDocs.test.mjs +0 -314
  283. package/api/search/search.test.mjs +0 -512
  284. package/assets/docs/tree/integrations.test.mjs +0 -62
  285. package/assets/docs/tree/writing-docs.doc.mjs +0 -286
  286. package/clients/cli/commands/docs.test.mjs +0 -294
  287. package/foundation/agent-docs/agent-docs.test.mjs +0 -1159
  288. package/foundation/doc-compiler/tree.test.mjs +0 -598
@@ -0,0 +1,34 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ /**
4
+ * @file Shared published types for complete multi-selector lookup receipts.
5
+ * Adopting API subjects specialize these types with their single-result and
6
+ * ambiguity-candidate types instead of defining command-specific row shapes.
7
+ *
8
+ * @input One exact selector, its single-result response, and its candidate shape.
9
+ * @output BatchRow and BatchResponse for every AST-053 lookup adopter.
10
+ * @position packages/cli/foundation/response — shared JSON response types
11
+ */
12
+
13
+ /**
14
+ * One complete row for an accepted selector.
15
+ * @template TResult
16
+ * @template TCandidate
17
+ * @typedef {(
18
+ * | {selector: string; status: 'found'; result: TResult}
19
+ * | {selector: string; status: 'ambiguous'; code: string; error: string; candidates: TCandidate[]}
20
+ * | {selector: string; status: 'not_found' | 'error'; code: string; error: string; suggestions?: import('./base').Suggestion[]}
21
+ * )} BatchRow
22
+ */
23
+
24
+ /**
25
+ * One ordered batch receipt inside the shared `{type, data}` success envelope.
26
+ * @template {string} TType
27
+ * @template TResult
28
+ * @template TCandidate
29
+ * @typedef {object} BatchResponse
30
+ * @property {TType} type
31
+ * @property {{count: number; results: BatchRow<TResult, TCandidate>[]}} data
32
+ */
33
+
34
+ export {};
@@ -36,17 +36,16 @@ export const doc = {
36
36
  {
37
37
  value: 'ERR_INVALID_OPTION',
38
38
  description:
39
- 'An unknown flag/option was passed (Commander `unknownOption`).',
39
+ 'An unknown option was passed, --json was given to a command without JSON output, or layout --form got a value other than compact, outline, or auto.',
40
40
  },
41
41
  {
42
42
  value: 'ERR_INVALID_ARGUMENT',
43
43
  description:
44
- "An option/argument had a value Commander's parser rejected.",
44
+ 'An argument or option value is invalid: wrong type, out of range, an unknown choice, an extra argument, or a conflicting combination.',
45
45
  },
46
46
  {
47
47
  value: 'ERR_MISSING_ARGUMENT',
48
- description:
49
- 'A required positional argument was omitted (Commander `missingArgument`).',
48
+ description: 'A required argument or option value was omitted.',
50
49
  },
51
50
  {
52
51
  value: 'ERR_INVALID_LANG',
@@ -134,12 +133,11 @@ export const doc = {
134
133
  },
135
134
  {
136
135
  value: 'ERR_UNKNOWN_PACKAGE',
137
- description: 'No package matched the requested name (discover).',
136
+ description: 'No package matched the requested name.',
138
137
  },
139
138
  {
140
139
  value: 'ERR_UNKNOWN_AGENT',
141
- description:
142
- 'An unrecognized `--agent` value was passed to agent-docs/init.',
140
+ description: 'An unrecognized `--agent` value was passed to init.',
143
141
  },
144
142
  {
145
143
  value: 'ERR_UNKNOWN_FEATURE',
@@ -272,7 +270,7 @@ export const doc = {
272
270
  {
273
271
  value: 'ERR_UNCLASSIFIED_EXIT',
274
272
  description:
275
- 'Recorded in the debug log, never printed: a command exited non-zero without going through cliError/jsonError, so no stable code was available.',
273
+ 'Recorded in the debug log, never printed: a command exited non-zero without reporting an error code.',
276
274
  },
277
275
  {
278
276
  value: 'ERR_SIGNAL_TERMINATED',
@@ -195,9 +195,16 @@ describe('error codes: end-to-end JSON envelopes', () => {
195
195
  // is rejected at the preAction gate with a stable invalid-option code.
196
196
  {
197
197
  name: 'json not supported',
198
- args: ['theme', 'bogus-sub', '--json'],
198
+ args: ['theme', '--json'],
199
199
  code: 'ERR_INVALID_OPTION',
200
200
  },
201
+ // A group given a word it does not have names the unknown subcommand,
202
+ // in JSON as in text.
203
+ {
204
+ name: 'unknown subcommand of a group',
205
+ args: ['theme', 'bogus-sub', '--json'],
206
+ code: 'ERR_UNKNOWN_SUBCOMMAND',
207
+ },
201
208
  ];
202
209
 
203
210
  for (const {name, args, code} of cases) {
@@ -249,13 +256,31 @@ describe('error codes: human mode stays clean', () => {
249
256
  expect(stdout).not.toContain('ERR_UNKNOWN_COMPONENT');
250
257
  });
251
258
 
252
- it('unknown subcommand exits 1 in human mode (code carried internally)', async () => {
253
- // `theme` is not JSON-capable, so this path is human-only; we assert the
254
- // failure surfaces with exit 1 and a helpful message. The stable
255
- // ERR_UNKNOWN_SUBCOMMAND code rides along on the cliError call.
259
+ it('unknown subcommand exits 1, with the code in JSON and not in text', async () => {
260
+ // A group that is not JSON-capable itself still answers an unknown
261
+ // subcommand in JSON, so a JSON caller learns the subcommands it has.
256
262
  const {status, stderr} = await runCli(['theme', 'bogus-sub']);
257
263
  expect(status).toBe(1);
258
264
  expect(stderr).toContain("unknown subcommand 'theme bogus-sub'");
259
265
  expect(stderr).not.toContain('ERR_UNKNOWN_SUBCOMMAND');
266
+ for (const args of [
267
+ ['--json', 'theme', 'bogus-sub'],
268
+ ['theme', 'bogus-sub', '--json'],
269
+ ['--json', 'doctor', 'integration', 'bogus-sub'],
270
+ ]) {
271
+ const json = await runCli(args);
272
+ expect(json.status, args.join(' ')).toBe(1);
273
+ expect(JSON.parse(json.stdout), args.join(' ')).toMatchObject({
274
+ code: 'ERR_UNKNOWN_SUBCOMMAND',
275
+ suggestions: expect.arrayContaining([expect.objectContaining({reason: 'available subcommand'})]),
276
+ });
277
+ }
278
+ // Text and JSON agree for a group that shows help when run bare.
279
+ const text = await runCli(['doctor', 'integration', 'bogus-sub']);
280
+ expect(text.status).toBe(1);
281
+ expect(text.stderr).toContain("unknown subcommand 'doctor integration bogus-sub'");
282
+ const doctor = await runCli(['doctor', 'integrations']);
283
+ expect(doctor.status).toBe(1);
284
+ expect(doctor.stderr).toContain("unknown subcommand 'doctor integrations'");
260
285
  });
261
286
  });
@@ -4,9 +4,10 @@
4
4
  /**
5
5
  * @file EnumDoc for the `type` discriminant carried on every --json success
6
6
  * envelope. The vocabulary mirrors the RESPONSE_TYPES map (each command's
7
- * `jsonOut(...)` call sites) in `clients/cli/lib/manifest.mjs`; a consumer
8
- * switches on `type` to narrow the `data` payload. Descriptions follow the
9
- * currently published response projection, not a future package-version boundary.
7
+ * `jsonOut(...)` call sites) plus ROOT_RESPONSE_TYPES (help, version) in
8
+ * `clients/cli/lib/manifest.mjs`; a consumer switches on `type` to narrow the
9
+ * `data` payload. Descriptions follow the currently published response
10
+ * projection, not a future package-version boundary.
10
11
  *
11
12
  * @input Public response discriminants and their currently released payloads.
12
13
  * @output Generated consumer reference for every typed JSON success response.
@@ -3,9 +3,10 @@
3
3
  /**
4
4
  * @file EnumDoc for the `type` discriminant carried on every --json success
5
5
  * envelope. The vocabulary mirrors the RESPONSE_TYPES map (each command's
6
- * `jsonOut(...)` call sites) in `clients/cli/lib/manifest.mjs`; a consumer
7
- * switches on `type` to narrow the `data` payload. Descriptions follow the
8
- * currently published response projection, not a future package-version boundary.
6
+ * `jsonOut(...)` call sites) plus ROOT_RESPONSE_TYPES (help, version) in
7
+ * `clients/cli/lib/manifest.mjs`; a consumer switches on `type` to narrow the
8
+ * `data` payload. Descriptions follow the currently published response
9
+ * projection, not a future package-version boundary.
9
10
  *
10
11
  * @input Public response discriminants and their currently released payloads.
11
12
  * @output Generated consumer reference for every typed JSON success response.
@@ -35,7 +36,12 @@ export const doc = {
35
36
  {
36
37
  value: 'component.list',
37
38
  description:
38
- 'The component catalog grouped by category: `detail` (the level: names | compact | full) and `components`, the grouped map of names entries ({name, package, and optional canonical import for integrations}), brief entries, or a full ComponentDoc per entry.',
39
+ "The component catalog grouped by component group (each component's group field): `detail` (the level: names | compact | full) and `components`, the grouped map of names entries ({name, package, and optional canonical import for integrations}), brief entries, or a full ComponentDoc per entry.",
40
+ },
41
+ {
42
+ value: 'component.batch',
43
+ description:
44
+ 'The component specialization of the shared `BatchResponse` and `BatchRow` types. An explicit programmatic selector array, or two or more CLI selectors, returns one ordered receipt: `count` plus `results`, one row per selector including duplicates. Every row carries `selector` and `status` (found | not_found | ambiguous | error). A found row carries `result`, the same {type, data} response as one selector. An ambiguous row carries `code`, `error`, and `candidates` ({package, component, kind, installed}). Other failed rows carry `code`, `error`, and optional `suggestions` ({name, reason}).',
39
45
  },
40
46
  {
41
47
  value: 'component.detail',
@@ -104,21 +110,27 @@ export const doc = {
104
110
  {
105
111
  value: 'discover.list',
106
112
  description:
107
- 'The configured external packages (name, category, components, version, description); when empty it carries meta.configured to tell "nothing configured" from "nothing discovered".',
113
+ 'The integrations the project loads (name, category, components, version, a list per other kind they add, and latest when a source knows it); with a discover source, meta.available lists what the project could add and meta.sources reports each source; when empty it carries meta.configured to tell "nothing configured" from "nothing discovered".',
108
114
  },
109
115
  {
110
116
  value: 'discover.detail',
111
- description: 'A single external package entry, for an @scope/name query.',
117
+ description:
118
+ 'One package, for an @scope/name or @scope/name@version query: what the shown version adds, whether the project has it, and, when a source knows the package, its versions, latest release, and the command that adds it.',
112
119
  },
113
120
  {
114
121
  value: 'discover.detail.doc',
115
122
  description:
116
- 'The validated ComponentDoc for one external component: an @scope/name/Component query, or a free-text term resolving to exactly one component.',
123
+ 'The validated ComponentDoc for one installed component, for an @scope/name/Component query.',
124
+ },
125
+ {
126
+ value: 'discover.item',
127
+ description:
128
+ 'One item that is not an installed component, for an @scope/name/<item> query: its kind, name, package, version, and whether the project has the package.',
117
129
  },
118
130
  {
119
131
  value: 'discover.search',
120
132
  description:
121
- 'The echoed query plus the matching {package, component} pairs, when a free-text term matches several components.',
133
+ 'The echoed query plus every matching item and package across all packages, each with its kind and whether the project has it, even when only one matches; total is set when --limit cut the list.',
122
134
  },
123
135
 
124
136
  // search
@@ -149,7 +161,7 @@ export const doc = {
149
161
  {
150
162
  value: 'swizzle.copy',
151
163
  description:
152
- 'An eject receipt: component name, owning package, output directory, files-copied count, the written file names, whether any file uses StyleX, and an optional maintainer note.',
164
+ 'An eject receipt: component name, owning package, output directory, files-copied count, the written file names, whether any file uses StyleX, and, when the owner has an issues URL, feedback ({issuesUrl, ghCommand?}): where to report the gap that led to swizzling.',
153
165
  },
154
166
 
155
167
  // gap reports
@@ -251,6 +263,11 @@ export const doc = {
251
263
  description:
252
264
  'Every available codemod, oldest→newest, as {name, title, version, optional}; returned for --list without running anything.',
253
265
  },
266
+ {
267
+ value: 'upgrade.registry',
268
+ description:
269
+ 'The copied-composition receipt for --registry: applied, ok, the counts (found, current, wouldUpdate, updated, wouldMerge, merged, wouldRefreshReceipt, receiptsRefreshed, conflicts, missing, invalid, failed), and items.',
270
+ },
254
271
  {
255
272
  value: 'upgrade.status',
256
273
  description:
@@ -269,11 +286,24 @@ export const doc = {
269
286
  'The CLI capability manifest: name, version, apiVersion, description, globalOptions, commands (each name, description, arguments, options, json, aliases?, responseTypes?, examples?, exitCodes? as [{code, when}], subcommands?), jsonSupported, and the flat responseTypes index.',
270
287
  },
271
288
 
289
+ // help and version, which no single command owns
290
+ {
291
+ value: 'help',
292
+ description:
293
+ 'Help, in one of two shapes. A bare `astryx --json` returns the root manifest: name, version, commands (the command names), jsonSupported, and manifest (the full payload `astryx manifest --json` returns). ' +
294
+ "`--help --json` on any command, or `astryx help [command] --json`, returns that command's help: command, description, usage, options (each flags, description, and defaultValue and choices when set), and subcommands (each name and description). " +
295
+ 'data.manifest marks the first shape; data.usage marks the second.',
296
+ },
297
+ {
298
+ value: 'version',
299
+ description: 'The CLI version, for `astryx --version --json`: {version}.',
300
+ },
301
+
272
302
  // doctor
273
303
  {
274
304
  value: 'doctor',
275
305
  description:
276
- 'The health-check report: `checks` (each with id, label, status: pass | warn | fail | info, a message, and a fix when not passing) plus a `summary` of counts per status.',
306
+ 'The health-check report: `checks` (each with id, label, status: pass | warn | fail | info, a message, and an optional fix, always present on warn and fail) plus a `summary` of counts per status.',
277
307
  },
278
308
 
279
309
  // integration authoring
@@ -53,6 +53,29 @@ function expectNamed(type, fields) {
53
53
  }
54
54
 
55
55
  describe('response-types EnumDoc names every field', () => {
56
+ it('component.batch names every row field and state', async () => {
57
+ const res = await data(['component', 'Button', 'Badge']);
58
+ expect(res.type).toBe('component.batch');
59
+ expect(describedAs('component.batch')).toMatch(/BatchResponse.*BatchRow/);
60
+ expectNamed('component.batch', [
61
+ 'count',
62
+ 'results',
63
+ 'selector',
64
+ 'status',
65
+ 'result',
66
+ 'code',
67
+ 'error',
68
+ 'candidates',
69
+ 'package',
70
+ 'component',
71
+ 'kind',
72
+ 'installed',
73
+ 'suggestions',
74
+ 'name',
75
+ 'reason',
76
+ ]);
77
+ });
78
+
56
79
  it('component.detail: the ownership fields and parentDoc', async () => {
57
80
  const res = await data(['component', 'HStack']);
58
81
  expect(res.type).toBe('component.detail');
@@ -39,16 +39,13 @@ export const doc = {
39
39
  name: 'type',
40
40
  type: 'string',
41
41
  description:
42
- 'Discriminator naming the payload shape. Each command guarantees ' +
43
- 'its own `type` at its return; there is no central union.',
42
+ 'Names the payload shape. Every value is listed in the response-types enum.',
44
43
  required: true,
45
44
  },
46
45
  {
47
46
  name: 'data',
48
47
  type: 'unknown',
49
- description:
50
- "The command's payload. Structural by design, narrowed by the " +
51
- 'per-command return type, not by a map in the serializer.',
48
+ description: "The command's payload; its shape depends on `type`.",
52
49
  required: true,
53
50
  },
54
51
  {
@@ -64,7 +61,7 @@ export const doc = {
64
61
  type: '{ apiVersion: number; error: string; code: ErrorCode; suggestions?: Suggestion[] }',
65
62
  description:
66
63
  'Emitted for every failure in --json mode, including uncaught throws ' +
67
- 'and Commander parse errors, which are converted to this shape.',
64
+ 'and command-line parse errors, which are converted to this shape.',
68
65
  fields: [
69
66
  {
70
67
  name: 'apiVersion',
@@ -121,7 +118,7 @@ export const doc = {
121
118
  label: 'Success',
122
119
  code: `{
123
120
  "apiVersion": 1,
124
- "type": "component",
121
+ "type": "component.detail",
125
122
  "data": { "name": "Button" }
126
123
  }`,
127
124
  },
@@ -153,9 +150,13 @@ export const doc = {
153
150
  {
154
151
  type: 'prose',
155
152
  text:
156
- 'The process exit code is part of the contract too: successful commands ' +
157
- 'exit 0, and a JSON error envelope is accompanied by a non-zero exit ' +
158
- '(jsonError exits 1).',
153
+ 'The process exit code is part of the contract too. Exit 0 means success, ' +
154
+ 'and every error envelope exits 1. Some commands also exit 1 with a success ' +
155
+ 'envelope when what they report failed: a failed check (layout check, doctor ' +
156
+ 'and its integration subcommands, integration verify, theme build ' +
157
+ '--check), a gap report that was not delivered, an upgrade left incomplete, ' +
158
+ 'or init agent docs refused for a path outside the project. Read the ' +
159
+ 'envelope, not the exit code, to tell them apart.',
159
160
  },
160
161
  ],
161
162
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@astryxdesign/cli",
3
- "version": "0.6.4",
3
+ "version": "0.6.5-canary.031021b",
4
4
  "displayName": "CLI",
5
5
  "description": "Scaffold projects, browse templates, generate themes, and get agent-ready docs from the command line.",
6
6
  "author": "Meta Open Source",
@@ -101,10 +101,10 @@
101
101
  "zod": "^4.4.3"
102
102
  },
103
103
  "peerDependencies": {
104
- "@astryxdesign/charts": "*",
105
- "@astryxdesign/core": "*",
106
- "@astryxdesign/lab": "*",
107
- "@astryxdesign/theme-neutral": "*"
104
+ "@astryxdesign/charts": "0.6.5-canary.031021b",
105
+ "@astryxdesign/core": "0.6.5-canary.031021b",
106
+ "@astryxdesign/lab": "0.6.5-canary.031021b",
107
+ "@astryxdesign/theme-neutral": "0.6.5-canary.031021b"
108
108
  },
109
109
  "peerDependenciesMeta": {
110
110
  "@astryxdesign/charts": {
@@ -121,10 +121,10 @@
121
121
  }
122
122
  },
123
123
  "devDependencies": {
124
- "@astryxdesign/charts": "*",
125
- "@astryxdesign/core": "*",
126
- "@astryxdesign/lab": "*",
127
- "@astryxdesign/theme-neutral": "*",
124
+ "@astryxdesign/charts": "0.6.5-canary.031021b",
125
+ "@astryxdesign/core": "0.6.5-canary.031021b",
126
+ "@astryxdesign/lab": "0.6.5-canary.031021b",
127
+ "@astryxdesign/theme-neutral": "0.6.5-canary.031021b",
128
128
  "@heroicons/react": "^2.2.0",
129
129
  "@stylexjs/stylex": "^0.19.0",
130
130
  "@types/babel__core": "^7.20.5",
@@ -1,243 +0,0 @@
1
- // Copyright (c) Meta Platforms, Inc. and affiliates.
2
-
3
- /**
4
- * @file Dispatcher-level tests for docs() — the argument-shape routing that
5
- * sits above the list/detail/section leaves. The leaves have their own tests;
6
- * this pins the router: docs() -> list, docs(topic) -> detail,
7
- * docs(topic, section) -> section, plus the unknown-topic/section error codes.
8
- * Runs against the real CLI-bundled docs (no cwd/project needed).
9
- */
10
-
11
- import {describe, it, expect} from 'vitest';
12
- import {docs} from './docs.mjs';
13
- import {AstryxError} from '../error.mjs';
14
-
15
- const SLOW = 30_000;
16
-
17
- describe('docs() dispatcher routing', () => {
18
- it('no topic -> docs.list', async () => {
19
- const r = await docs();
20
- expect(r.type).toBe('docs.list');
21
- expect(Array.isArray(r.data)).toBe(true);
22
- expect(r.data.length).toBeGreaterThan(0);
23
- }, SLOW);
24
-
25
- it('empty topic -> docs.list (falsy topic routes to list)', async () => {
26
- expect((await docs('')).type).toBe('docs.list');
27
- }, SLOW);
28
-
29
- it('topic only -> docs.detail, the whole doc', async () => {
30
- const {data} = await docs();
31
- expect((await docs(data[0].topic)).type).toBe('docs.detail');
32
- }, SLOW);
33
-
34
- it('topic + index -> docs.index', async () => {
35
- const {data} = await docs();
36
- const r = await docs(data[0].topic, undefined, {index: true});
37
- expect(r.type).toBe('docs.index');
38
- }, SLOW);
39
-
40
- it('topic + section -> docs.detail.section', async () => {
41
- const {data} = await docs();
42
- let routed = null;
43
- for (const {topic} of data) {
44
- const detail = await docs(topic);
45
- const sections = detail.data.sections;
46
- if (Array.isArray(sections) && sections.length > 0) {
47
- routed = await docs(topic, sections[0].title);
48
- break;
49
- }
50
- }
51
- expect(routed).not.toBeNull();
52
- expect(routed.type).toBe('docs.detail.section');
53
- }, SLOW);
54
-
55
- it('unknown topic -> ERR_UNKNOWN_TOPIC', async () => {
56
- await expect(docs('zzz-not-a-real-topic')).rejects.toBeInstanceOf(AstryxError);
57
- await expect(docs('zzz-not-a-real-topic')).rejects.toMatchObject({
58
- code: 'ERR_UNKNOWN_TOPIC',
59
- });
60
- }, SLOW);
61
-
62
- it('known topic + unknown section -> ERR_UNKNOWN_SECTION', async () => {
63
- const {data} = await docs();
64
- const topic = data[0].topic;
65
- await expect(docs(topic, 'zzz-not-a-real-section')).rejects.toMatchObject({
66
- code: 'ERR_UNKNOWN_SECTION',
67
- });
68
- }, SLOW);
69
-
70
- it("lists the docs tree's namespaces in meta, so every data entry reads as a topic", async () => {
71
- const res = await docs();
72
- expect(res.meta.namespaces.map(entry => entry.topic)).toEqual(['cli', 'unorganized']);
73
- for (const entry of res.data) {
74
- expect((await docs(entry.topic)).type).toBe('docs.detail');
75
- }
76
- }, SLOW);
77
-
78
- it('opens a route typed in another case', async () => {
79
- const r = await docs('CLI/API');
80
- expect(r.type).toBe('docs.node');
81
- expect(r.data).toMatchObject({route: 'cli/api', links: {up: 'astryx docs cli'}});
82
- }, SLOW);
83
-
84
- it('a section of a typed doc -> ERR_UNKNOWN_SECTION, suggesting the doc itself', async () => {
85
- const err = await docs('cli/api/functions/search', 'x').catch(e => e);
86
- expect(err.code).toBe('ERR_UNKNOWN_SECTION');
87
- expect(err.message).toContain('astryx docs cli/api/functions/search');
88
- expect(err.suggestions.map(s => s.name)).toEqual(['cli/api/functions/search']);
89
- }, SLOW);
90
-
91
- it('a namespace route -> docs.node, one level of children', async () => {
92
- const r = await docs('cli/api');
93
- expect(r.type).toBe('docs.node');
94
- expect(r.data).toMatchObject({
95
- id: 'astryx:artifact:v1/%40astryxdesign%2Fcli/namespace/api',
96
- route: 'cli/api',
97
- kind: 'namespace',
98
- package: '@astryxdesign/cli',
99
- breadcrumb: [{route: 'cli', title: 'Astryx CLI'}],
100
- content: [],
101
- });
102
- expect(r.data.slots.flatMap(slot => slot.children.map(c => c.route))).toEqual([
103
- 'cli/api/functions',
104
- 'cli/api/schemas',
105
- 'cli/api/enums',
106
- ]);
107
- }, SLOW);
108
-
109
- it('a typed doc route -> docs.node with its content', async () => {
110
- const r = await docs('cli/api/functions/search');
111
- expect(r.type).toBe('docs.node');
112
- expect(r.data).toMatchObject({
113
- id: 'astryx:artifact:v1/%40astryxdesign%2Fcli/function/search',
114
- kind: 'function',
115
- title: 'search()',
116
- slots: [],
117
- });
118
- expect(r.data.breadcrumb.map(link => link.route)).toEqual([
119
- 'cli',
120
- 'cli/api',
121
- 'cli/api/functions',
122
- ]);
123
- expect(JSON.stringify(r.data.content)).toContain(
124
- '`astryx search` runs it. Read it with `astryx docs cli/commands/search`.',
125
- );
126
- }, SLOW);
127
-
128
- it('a guide the tree places reads like a topic: the whole doc, its index, a section', async () => {
129
- expect((await docs('cli/integrations')).type).toBe('docs.detail');
130
- const index = await docs('cli/integrations', undefined, {index: true});
131
- expect(index).toMatchObject({type: 'docs.index', data: {name: 'cli/integrations'}});
132
- expect(index.data.sections.length).toBeGreaterThan(1);
133
- expect((await docs('cli/integrations', 'components')).type).toBe(
134
- 'docs.detail.section',
135
- );
136
- }, SLOW);
137
-
138
- it('every read carries its moves (spec:AST-047)', async () => {
139
- const root = (await docs('cli')).data;
140
- expect(root.links).toEqual({up: 'astryx docs'});
141
- const leaf = (await docs('cli/api/functions/search')).data;
142
- expect(leaf.links.up).toBe('astryx docs cli/api/functions');
143
- expect(leaf.links.previous).toMatch(/^astryx docs cli\/api\/functions\/[a-z-]+$/);
144
- expect(leaf.links.next).toMatch(/^astryx docs cli\/api\/functions\/[a-z-]+$/);
145
- const index = await docs('cli/integrations', undefined, {index: true});
146
- // A guide moves across its namespace's slot, as any tree node does.
147
- expect(index.data.links).toEqual({
148
- up: 'astryx docs cli',
149
- next: 'astryx docs cli/writing-docs',
150
- });
151
- const first = (await docs('cli/integrations', index.data.sections[0].id)).data;
152
- expect(first.links).toEqual({
153
- up: 'astryx docs cli/integrations --index',
154
- next: `astryx docs cli/integrations ${index.data.sections[1].id}`,
155
- });
156
- const last = index.data.sections.at(-1).id;
157
- const end = (await docs('cli/integrations', last)).data;
158
- expect(end.links.next).toBeUndefined();
159
- expect(end.links.previous).toBe(
160
- `astryx docs cli/integrations ${index.data.sections.at(-2).id}`,
161
- );
162
- // A flat topic's home is the Unorganized level, and it moves across it.
163
- const flat = (await docs('principles')).data.links;
164
- expect(flat.up).toBe('astryx docs unorganized');
165
- expect(flat.previous).toMatch(/^astryx docs [a-z-]+$/);
166
- expect(flat.next).toMatch(/^astryx docs [a-z-]+$/);
167
- const home = (await docs('unorganized')).data;
168
- expect(home).toMatchObject({id: null, kind: 'namespace', links: {up: 'astryx docs'}});
169
- expect(home.slots[0].children.map(child => child.route)).toEqual(
170
- (await docs()).data.map(entry => entry.topic),
171
- );
172
- }, SLOW);
173
-
174
- it('names a node by its doc identity; a generated level has id null', async () => {
175
- const level = (await docs('cli/api/functions')).data;
176
- expect(level).toHaveProperty('id', null);
177
- expect(level.route).toBe('cli/api/functions');
178
- }, SLOW);
179
-
180
- it("offers a typed doc's related docs as moves", async () => {
181
- const fn = (await docs('cli/api/functions/search')).data;
182
- expect(fn.links.related).toContain('astryx docs cli/commands/search');
183
- const cmd = (await docs('cli/commands/search')).data;
184
- expect(cmd.links.related).toContain('astryx docs cli/api/functions/search');
185
- }, SLOW);
186
-
187
- it('a topic read returns the whole doc; index returns its sections', async () => {
188
- expect((await docs('principles')).type).toBe('docs.detail');
189
- const index = await docs('principles', undefined, {index: true});
190
- expect(index.type).toBe('docs.index');
191
- expect(index.data.sections.length).toBeGreaterThan(1);
192
- expect((await docs('principles', undefined, {dense: true})).type).toBe(
193
- 'docs.detail',
194
- );
195
- }, SLOW);
196
-
197
- it("the guide's old flat name is gone, and its error names the new route", async () => {
198
- await expect(docs('cli-integrations')).rejects.toMatchObject({
199
- code: 'ERR_UNKNOWN_TOPIC',
200
- suggestions: [expect.objectContaining({name: 'cli/integrations'})],
201
- });
202
- expect((await docs()).data.map(entry => entry.topic)).not.toContain(
203
- 'cli-integrations',
204
- );
205
- }, SLOW);
206
-
207
- it('a section of a namespace -> ERR_UNKNOWN_SECTION, naming its children', async () => {
208
- const err = await docs('cli', 'commands').catch(e => e);
209
- expect(err).toBeInstanceOf(AstryxError);
210
- expect(err.code).toBe('ERR_UNKNOWN_SECTION');
211
- expect(err.suggestions.map(s => s.name)).toEqual([
212
- 'cli/integrations',
213
- 'cli/writing-docs',
214
- 'cli/commands',
215
- 'cli/api',
216
- ]);
217
- }, SLOW);
218
-
219
- it('an unknown route suggests the children of the deepest namespace it reaches', async () => {
220
- const err = await docs('cli/api/functions/serch').catch(e => e);
221
- expect(err.code).toBe('ERR_UNKNOWN_TOPIC');
222
- expect(err.suggestions.map(s => s.name)).toContain('cli/api/functions/search');
223
- expect(err.suggestions.every(s => s.name.startsWith('cli/api/functions/'))).toBe(true);
224
- }, SLOW);
225
-
226
- it('non-string topic -> ERR_UNKNOWN_TOPIC (not a raw TypeError)', async () => {
227
- for (const bad of [123, {}, ['tokens'], true]) {
228
- const err = await docs(/** @type {any} */ (bad)).catch(e => e);
229
- expect(err).toBeInstanceOf(AstryxError);
230
- expect(err.code).toBe('ERR_UNKNOWN_TOPIC');
231
- }
232
- }, SLOW);
233
-
234
- it('non-string section -> ERR_UNKNOWN_SECTION (not a raw TypeError)', async () => {
235
- const {data} = await docs();
236
- const topic = data[0].topic;
237
- for (const bad of [456, {}, ['x']]) {
238
- const err = await docs(topic, /** @type {any} */ (bad)).catch(e => e);
239
- expect(err).toBeInstanceOf(AstryxError);
240
- expect(err.code).toBe('ERR_UNKNOWN_SECTION');
241
- }
242
- }, SLOW);
243
- });