convex 1.40.0 → 1.41.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (290) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/dist/browser.bundle.js +1 -1
  3. package/dist/browser.bundle.js.map +1 -1
  4. package/dist/cjs/cli/aiFiles.js +2 -2
  5. package/dist/cjs/cli/aiFiles.js.map +1 -1
  6. package/dist/cjs/cli/configure.js +1 -4
  7. package/dist/cjs/cli/configure.js.map +2 -2
  8. package/dist/cjs/cli/convexExport.js +3 -3
  9. package/dist/cjs/cli/convexExport.js.map +1 -1
  10. package/dist/cjs/cli/convexImport.js +2 -2
  11. package/dist/cjs/cli/convexImport.js.map +1 -1
  12. package/dist/cjs/cli/dashboard.js +19 -6
  13. package/dist/cjs/cli/dashboard.js.map +3 -3
  14. package/dist/cjs/cli/data.js +2 -2
  15. package/dist/cjs/cli/data.js.map +1 -1
  16. package/dist/cjs/cli/deploy.js +5 -5
  17. package/dist/cjs/cli/deploy.js.map +2 -2
  18. package/dist/cjs/cli/deploymentCreate.js +11 -5
  19. package/dist/cjs/cli/deploymentCreate.js.map +2 -2
  20. package/dist/cjs/cli/deploymentSelect.js +5 -5
  21. package/dist/cjs/cli/deploymentSelect.js.map +1 -1
  22. package/dist/cjs/cli/deploymentTokenCreate.js +5 -13
  23. package/dist/cjs/cli/deploymentTokenCreate.js.map +2 -2
  24. package/dist/cjs/cli/deploymentTokenDelete.js +4 -11
  25. package/dist/cjs/cli/deploymentTokenDelete.js.map +2 -2
  26. package/dist/cjs/cli/dev.js +6 -5
  27. package/dist/cjs/cli/dev.js.map +2 -2
  28. package/dist/cjs/cli/env.js +16 -16
  29. package/dist/cjs/cli/env.js.map +2 -2
  30. package/dist/cjs/cli/envDefault.js +10 -10
  31. package/dist/cjs/cli/envDefault.js.map +1 -1
  32. package/dist/cjs/cli/insights.js +3 -3
  33. package/dist/cjs/cli/insights.js.map +1 -1
  34. package/dist/cjs/cli/lib/aiFiles/skills.js +2 -2
  35. package/dist/cjs/cli/lib/aiFiles/skills.js.map +2 -2
  36. package/dist/cjs/cli/lib/command.js +1 -1
  37. package/dist/cjs/cli/lib/command.js.map +1 -1
  38. package/dist/cjs/cli/lib/deployment.js.map +1 -1
  39. package/dist/cjs/cli/lib/deploymentSelection.js +39 -0
  40. package/dist/cjs/cli/lib/deploymentSelection.js.map +2 -2
  41. package/dist/cjs/cli/lib/dev.js +31 -0
  42. package/dist/cjs/cli/lib/dev.js.map +2 -2
  43. package/dist/cjs/cli/lib/generateDocs.js +256 -0
  44. package/dist/cjs/cli/lib/generateDocs.js.map +7 -0
  45. package/dist/cjs/cli/lib/localDeployment/anonymous.js +24 -49
  46. package/dist/cjs/cli/lib/localDeployment/anonymous.js.map +3 -3
  47. package/dist/cjs/cli/lib/localDeployment/bigBrain.js +0 -9
  48. package/dist/cjs/cli/lib/localDeployment/bigBrain.js.map +2 -2
  49. package/dist/cjs/cli/lib/localDeployment/dashboard.js +30 -68
  50. package/dist/cjs/cli/lib/localDeployment/dashboard.js.map +2 -2
  51. package/dist/cjs/cli/lib/localDeployment/download.js +14 -1
  52. package/dist/cjs/cli/lib/localDeployment/download.js.map +2 -2
  53. package/dist/cjs/cli/lib/localDeployment/filePaths.js +33 -4
  54. package/dist/cjs/cli/lib/localDeployment/filePaths.js.map +2 -2
  55. package/dist/cjs/cli/lib/localDeployment/localDeployment.js +37 -126
  56. package/dist/cjs/cli/lib/localDeployment/localDeployment.js.map +3 -3
  57. package/dist/cjs/cli/lib/localDeployment/secrets.js +91 -0
  58. package/dist/cjs/cli/lib/localDeployment/secrets.js.map +7 -0
  59. package/dist/cjs/cli/lib/localDeployment/upgrade.js +43 -28
  60. package/dist/cjs/cli/lib/localDeployment/upgrade.js.map +3 -3
  61. package/dist/cjs/cli/lib/localDeployment/utils.js +0 -19
  62. package/dist/cjs/cli/lib/localDeployment/utils.js.map +3 -3
  63. package/dist/cjs/cli/lib/runTestFunction.js +3 -3
  64. package/dist/cjs/cli/lib/runTestFunction.js.map +1 -1
  65. package/dist/cjs/cli/run.js +5 -5
  66. package/dist/cjs/cli/run.js.map +1 -1
  67. package/dist/cjs/index.js +1 -1
  68. package/dist/cjs/index.js.map +1 -1
  69. package/dist/cjs/server/impl/registration_impl.js +0 -1
  70. package/dist/cjs/server/impl/registration_impl.js.map +2 -2
  71. package/dist/cjs/server/index.js.map +2 -2
  72. package/dist/cjs/server/meta.js.map +1 -1
  73. package/dist/cjs/server/registration.js.map +1 -1
  74. package/dist/cjs-types/cli/configure.d.ts +3 -2
  75. package/dist/cjs-types/cli/configure.d.ts.map +1 -1
  76. package/dist/cjs-types/cli/dashboard.d.ts.map +1 -1
  77. package/dist/cjs-types/cli/deploymentCreate.d.ts.map +1 -1
  78. package/dist/cjs-types/cli/deploymentTokenCreate.d.ts.map +1 -1
  79. package/dist/cjs-types/cli/deploymentTokenDelete.d.ts.map +1 -1
  80. package/dist/cjs-types/cli/dev.d.ts.map +1 -1
  81. package/dist/cjs-types/cli/lib/deployApi/definitionConfig.d.ts +4 -4
  82. package/dist/cjs-types/cli/lib/deployApi/startPush.d.ts +16 -16
  83. package/dist/cjs-types/cli/lib/deployment.d.ts +0 -2
  84. package/dist/cjs-types/cli/lib/deployment.d.ts.map +1 -1
  85. package/dist/cjs-types/cli/lib/deploymentSelection.d.ts +7 -0
  86. package/dist/cjs-types/cli/lib/deploymentSelection.d.ts.map +1 -1
  87. package/dist/cjs-types/cli/lib/dev.d.ts +2 -1
  88. package/dist/cjs-types/cli/lib/dev.d.ts.map +1 -1
  89. package/dist/cjs-types/cli/lib/generateDocs.d.ts +20 -0
  90. package/dist/cjs-types/cli/lib/generateDocs.d.ts.map +1 -0
  91. package/dist/cjs-types/cli/lib/generateDocs.test.d.ts +2 -0
  92. package/dist/cjs-types/cli/lib/generateDocs.test.d.ts.map +1 -0
  93. package/dist/cjs-types/cli/lib/localDeployment/anonymous.d.ts +1 -1
  94. package/dist/cjs-types/cli/lib/localDeployment/anonymous.d.ts.map +1 -1
  95. package/dist/cjs-types/cli/lib/localDeployment/bigBrain.d.ts +2 -4
  96. package/dist/cjs-types/cli/lib/localDeployment/bigBrain.d.ts.map +1 -1
  97. package/dist/cjs-types/cli/lib/localDeployment/dashboard.d.ts +9 -4
  98. package/dist/cjs-types/cli/lib/localDeployment/dashboard.d.ts.map +1 -1
  99. package/dist/cjs-types/cli/lib/localDeployment/download.d.ts +11 -1
  100. package/dist/cjs-types/cli/lib/localDeployment/download.d.ts.map +1 -1
  101. package/dist/cjs-types/cli/lib/localDeployment/filePaths.d.ts +16 -5
  102. package/dist/cjs-types/cli/lib/localDeployment/filePaths.d.ts.map +1 -1
  103. package/dist/cjs-types/cli/lib/localDeployment/localDeployment.d.ts +1 -9
  104. package/dist/cjs-types/cli/lib/localDeployment/localDeployment.d.ts.map +1 -1
  105. package/dist/cjs-types/cli/lib/localDeployment/secrets.d.ts +31 -0
  106. package/dist/cjs-types/cli/lib/localDeployment/secrets.d.ts.map +1 -0
  107. package/dist/cjs-types/cli/lib/localDeployment/secrets.test.d.ts +2 -0
  108. package/dist/cjs-types/cli/lib/localDeployment/secrets.test.d.ts.map +1 -0
  109. package/dist/cjs-types/cli/lib/localDeployment/upgrade.d.ts +6 -3
  110. package/dist/cjs-types/cli/lib/localDeployment/upgrade.d.ts.map +1 -1
  111. package/dist/cjs-types/cli/lib/localDeployment/utils.d.ts +0 -2
  112. package/dist/cjs-types/cli/lib/localDeployment/utils.d.ts.map +1 -1
  113. package/dist/cjs-types/cli/lib/versionApi.d.ts +2 -2
  114. package/dist/cjs-types/index.d.ts +1 -1
  115. package/dist/cjs-types/server/impl/registration_impl.d.ts.map +1 -1
  116. package/dist/cjs-types/server/index.d.ts +1 -1
  117. package/dist/cjs-types/server/index.d.ts.map +1 -1
  118. package/dist/cjs-types/server/meta.d.ts +16 -0
  119. package/dist/cjs-types/server/meta.d.ts.map +1 -1
  120. package/dist/cjs-types/server/registration.d.ts +11 -5
  121. package/dist/cjs-types/server/registration.d.ts.map +1 -1
  122. package/dist/cli.bundle.cjs +66405 -67923
  123. package/dist/cli.bundle.cjs.map +4 -4
  124. package/dist/esm/cli/aiFiles.js +2 -2
  125. package/dist/esm/cli/aiFiles.js.map +1 -1
  126. package/dist/esm/cli/configure.js +1 -4
  127. package/dist/esm/cli/configure.js.map +2 -2
  128. package/dist/esm/cli/convexExport.js +3 -3
  129. package/dist/esm/cli/convexExport.js.map +1 -1
  130. package/dist/esm/cli/convexImport.js +2 -2
  131. package/dist/esm/cli/convexImport.js.map +1 -1
  132. package/dist/esm/cli/dashboard.js +16 -3
  133. package/dist/esm/cli/dashboard.js.map +2 -2
  134. package/dist/esm/cli/data.js +2 -2
  135. package/dist/esm/cli/data.js.map +1 -1
  136. package/dist/esm/cli/deploy.js +5 -5
  137. package/dist/esm/cli/deploy.js.map +2 -2
  138. package/dist/esm/cli/deploymentCreate.js +13 -9
  139. package/dist/esm/cli/deploymentCreate.js.map +2 -2
  140. package/dist/esm/cli/deploymentSelect.js +5 -5
  141. package/dist/esm/cli/deploymentSelect.js.map +1 -1
  142. package/dist/esm/cli/deploymentTokenCreate.js +9 -15
  143. package/dist/esm/cli/deploymentTokenCreate.js.map +2 -2
  144. package/dist/esm/cli/deploymentTokenDelete.js +8 -16
  145. package/dist/esm/cli/deploymentTokenDelete.js.map +2 -2
  146. package/dist/esm/cli/dev.js +6 -5
  147. package/dist/esm/cli/dev.js.map +2 -2
  148. package/dist/esm/cli/env.js +16 -16
  149. package/dist/esm/cli/env.js.map +2 -2
  150. package/dist/esm/cli/envDefault.js +10 -10
  151. package/dist/esm/cli/envDefault.js.map +1 -1
  152. package/dist/esm/cli/insights.js +3 -3
  153. package/dist/esm/cli/insights.js.map +1 -1
  154. package/dist/esm/cli/lib/aiFiles/skills.js +2 -2
  155. package/dist/esm/cli/lib/aiFiles/skills.js.map +2 -2
  156. package/dist/esm/cli/lib/command.js +1 -1
  157. package/dist/esm/cli/lib/command.js.map +1 -1
  158. package/dist/esm/cli/lib/deployment.js.map +1 -1
  159. package/dist/esm/cli/lib/deploymentSelection.js +38 -0
  160. package/dist/esm/cli/lib/deploymentSelection.js.map +2 -2
  161. package/dist/esm/cli/lib/dev.js +31 -0
  162. package/dist/esm/cli/lib/dev.js.map +2 -2
  163. package/dist/esm/cli/lib/generateDocs.js +233 -0
  164. package/dist/esm/cli/lib/generateDocs.js.map +7 -0
  165. package/dist/esm/cli/lib/localDeployment/anonymous.js +30 -61
  166. package/dist/esm/cli/lib/localDeployment/anonymous.js.map +3 -3
  167. package/dist/esm/cli/lib/localDeployment/bigBrain.js +0 -8
  168. package/dist/esm/cli/lib/localDeployment/bigBrain.js.map +2 -2
  169. package/dist/esm/cli/lib/localDeployment/dashboard.js +36 -69
  170. package/dist/esm/cli/lib/localDeployment/dashboard.js.map +2 -2
  171. package/dist/esm/cli/lib/localDeployment/download.js +15 -2
  172. package/dist/esm/cli/lib/localDeployment/download.js.map +2 -2
  173. package/dist/esm/cli/lib/localDeployment/filePaths.js +29 -2
  174. package/dist/esm/cli/lib/localDeployment/filePaths.js.map +2 -2
  175. package/dist/esm/cli/lib/localDeployment/localDeployment.js +40 -134
  176. package/dist/esm/cli/lib/localDeployment/localDeployment.js.map +3 -3
  177. package/dist/esm/cli/lib/localDeployment/secrets.js +57 -0
  178. package/dist/esm/cli/lib/localDeployment/secrets.js.map +7 -0
  179. package/dist/esm/cli/lib/localDeployment/upgrade.js +45 -28
  180. package/dist/esm/cli/lib/localDeployment/upgrade.js.map +3 -3
  181. package/dist/esm/cli/lib/localDeployment/utils.js +0 -7
  182. package/dist/esm/cli/lib/localDeployment/utils.js.map +2 -2
  183. package/dist/esm/cli/lib/runTestFunction.js +3 -3
  184. package/dist/esm/cli/lib/runTestFunction.js.map +1 -1
  185. package/dist/esm/cli/run.js +5 -5
  186. package/dist/esm/cli/run.js.map +1 -1
  187. package/dist/esm/index.js +1 -1
  188. package/dist/esm/index.js.map +1 -1
  189. package/dist/esm/server/impl/registration_impl.js +0 -1
  190. package/dist/esm/server/impl/registration_impl.js.map +2 -2
  191. package/dist/esm/server/index.js.map +2 -2
  192. package/dist/esm-types/cli/configure.d.ts +3 -2
  193. package/dist/esm-types/cli/configure.d.ts.map +1 -1
  194. package/dist/esm-types/cli/dashboard.d.ts.map +1 -1
  195. package/dist/esm-types/cli/deploymentCreate.d.ts.map +1 -1
  196. package/dist/esm-types/cli/deploymentTokenCreate.d.ts.map +1 -1
  197. package/dist/esm-types/cli/deploymentTokenDelete.d.ts.map +1 -1
  198. package/dist/esm-types/cli/dev.d.ts.map +1 -1
  199. package/dist/esm-types/cli/lib/deployApi/definitionConfig.d.ts +4 -4
  200. package/dist/esm-types/cli/lib/deployApi/startPush.d.ts +16 -16
  201. package/dist/esm-types/cli/lib/deployment.d.ts +0 -2
  202. package/dist/esm-types/cli/lib/deployment.d.ts.map +1 -1
  203. package/dist/esm-types/cli/lib/deploymentSelection.d.ts +7 -0
  204. package/dist/esm-types/cli/lib/deploymentSelection.d.ts.map +1 -1
  205. package/dist/esm-types/cli/lib/dev.d.ts +2 -1
  206. package/dist/esm-types/cli/lib/dev.d.ts.map +1 -1
  207. package/dist/esm-types/cli/lib/generateDocs.d.ts +20 -0
  208. package/dist/esm-types/cli/lib/generateDocs.d.ts.map +1 -0
  209. package/dist/esm-types/cli/lib/generateDocs.test.d.ts +2 -0
  210. package/dist/esm-types/cli/lib/generateDocs.test.d.ts.map +1 -0
  211. package/dist/esm-types/cli/lib/localDeployment/anonymous.d.ts +1 -1
  212. package/dist/esm-types/cli/lib/localDeployment/anonymous.d.ts.map +1 -1
  213. package/dist/esm-types/cli/lib/localDeployment/bigBrain.d.ts +2 -4
  214. package/dist/esm-types/cli/lib/localDeployment/bigBrain.d.ts.map +1 -1
  215. package/dist/esm-types/cli/lib/localDeployment/dashboard.d.ts +9 -4
  216. package/dist/esm-types/cli/lib/localDeployment/dashboard.d.ts.map +1 -1
  217. package/dist/esm-types/cli/lib/localDeployment/download.d.ts +11 -1
  218. package/dist/esm-types/cli/lib/localDeployment/download.d.ts.map +1 -1
  219. package/dist/esm-types/cli/lib/localDeployment/filePaths.d.ts +16 -5
  220. package/dist/esm-types/cli/lib/localDeployment/filePaths.d.ts.map +1 -1
  221. package/dist/esm-types/cli/lib/localDeployment/localDeployment.d.ts +1 -9
  222. package/dist/esm-types/cli/lib/localDeployment/localDeployment.d.ts.map +1 -1
  223. package/dist/esm-types/cli/lib/localDeployment/secrets.d.ts +31 -0
  224. package/dist/esm-types/cli/lib/localDeployment/secrets.d.ts.map +1 -0
  225. package/dist/esm-types/cli/lib/localDeployment/secrets.test.d.ts +2 -0
  226. package/dist/esm-types/cli/lib/localDeployment/secrets.test.d.ts.map +1 -0
  227. package/dist/esm-types/cli/lib/localDeployment/upgrade.d.ts +6 -3
  228. package/dist/esm-types/cli/lib/localDeployment/upgrade.d.ts.map +1 -1
  229. package/dist/esm-types/cli/lib/localDeployment/utils.d.ts +0 -2
  230. package/dist/esm-types/cli/lib/localDeployment/utils.d.ts.map +1 -1
  231. package/dist/esm-types/cli/lib/versionApi.d.ts +2 -2
  232. package/dist/esm-types/index.d.ts +1 -1
  233. package/dist/esm-types/server/impl/registration_impl.d.ts.map +1 -1
  234. package/dist/esm-types/server/index.d.ts +1 -1
  235. package/dist/esm-types/server/index.d.ts.map +1 -1
  236. package/dist/esm-types/server/meta.d.ts +16 -0
  237. package/dist/esm-types/server/meta.d.ts.map +1 -1
  238. package/dist/esm-types/server/registration.d.ts +11 -5
  239. package/dist/esm-types/server/registration.d.ts.map +1 -1
  240. package/dist/react.bundle.js +1 -1
  241. package/dist/react.bundle.js.map +1 -1
  242. package/package.json +4 -2
  243. package/src/browser/sync/request_manager.test.ts +2 -2
  244. package/src/cli/aiFiles.ts +2 -2
  245. package/src/cli/configure.ts +4 -6
  246. package/src/cli/convexExport.ts +3 -3
  247. package/src/cli/convexImport.ts +2 -2
  248. package/src/cli/dashboard.ts +29 -3
  249. package/src/cli/data.ts +2 -2
  250. package/src/cli/deploy.ts +5 -5
  251. package/src/cli/deploymentCreate.test.ts +151 -24
  252. package/src/cli/deploymentCreate.ts +21 -11
  253. package/src/cli/deploymentSelect.ts +5 -5
  254. package/src/cli/deploymentSelection.test.ts +0 -3
  255. package/src/cli/deploymentToken.test.ts +34 -23
  256. package/src/cli/deploymentTokenCreate.ts +9 -21
  257. package/src/cli/deploymentTokenDelete.ts +8 -23
  258. package/src/cli/dev.ts +5 -4
  259. package/src/cli/env.ts +16 -16
  260. package/src/cli/envDefault.ts +10 -10
  261. package/src/cli/insights.ts +3 -3
  262. package/src/cli/lib/aiFiles/integration.test.ts +2 -0
  263. package/src/cli/lib/aiFiles/skills.ts +3 -3
  264. package/src/cli/lib/command.ts +2 -2
  265. package/src/cli/lib/deployment.ts +0 -5
  266. package/src/cli/lib/deploymentSelection.ts +67 -0
  267. package/src/cli/lib/dev.ts +39 -0
  268. package/src/cli/lib/generateDocs.test.ts +326 -0
  269. package/src/cli/lib/generateDocs.ts +393 -0
  270. package/src/cli/lib/localDeployment/anonymous.ts +48 -72
  271. package/src/cli/lib/localDeployment/bigBrain.ts +7 -15
  272. package/src/cli/lib/localDeployment/dashboard.ts +48 -80
  273. package/src/cli/lib/localDeployment/download.ts +34 -3
  274. package/src/cli/lib/localDeployment/filePaths.ts +66 -6
  275. package/src/cli/lib/localDeployment/localDeployment.ts +46 -184
  276. package/src/cli/lib/localDeployment/run.test.ts +6 -6
  277. package/src/cli/lib/localDeployment/secrets.test.ts +53 -0
  278. package/src/cli/lib/localDeployment/secrets.ts +93 -0
  279. package/src/cli/lib/localDeployment/tests/keygenFailure.mjs +9 -0
  280. package/src/cli/lib/localDeployment/tests/keygenSuccess.mjs +31 -0
  281. package/src/cli/lib/localDeployment/upgrade.ts +52 -38
  282. package/src/cli/lib/localDeployment/utils.ts +0 -10
  283. package/src/cli/lib/runTestFunction.ts +3 -3
  284. package/src/cli/run.ts +5 -5
  285. package/src/index.ts +1 -1
  286. package/src/server/impl/registration_impl.ts +0 -2
  287. package/src/server/index.ts +1 -0
  288. package/src/server/meta.ts +17 -0
  289. package/src/server/registration.test.ts +2 -35
  290. package/src/server/registration.ts +10 -19
@@ -0,0 +1,326 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { Command } from "@commander-js/extra-typings";
3
+ import { generateDocs, replaceBullets } from "./generateDocs.js";
4
+
5
+ function makeFakeRoot() {
6
+ const greet = new Command("greet")
7
+ .description("Print a greeting")
8
+ .argument("<name>", "Who to greet")
9
+ .option("-l, --loud", "Shout the greeting");
10
+
11
+ const itemAdd = new Command("add")
12
+ .description("Add an item")
13
+ .argument("<name>", "Item name")
14
+ .option("--qty <n>", "Quantity");
15
+
16
+ const itemList = new Command("list").alias("ls").description("List items");
17
+
18
+ // A sub-subcommand whose leaf name (`create`) collides with `item add`'s
19
+ // sibling group leaf — exercises unique anchor generation for nesting.
20
+ const tokenCreate = new Command("create").description("Create a token");
21
+ const token = new Command("token")
22
+ .description("Manage tokens")
23
+ .addCommand(tokenCreate);
24
+
25
+ const itemCreate = new Command("create").description("Create an item");
26
+
27
+ const item = new Command("item")
28
+ .description("Manage items")
29
+ .addCommand(itemAdd)
30
+ .addCommand(itemList)
31
+ .addCommand(itemCreate)
32
+ .addCommand(token);
33
+
34
+ // A description whose body is an indented numbered list, like `convex dev`.
35
+ // These steps must render as a real ordered list, not bullets wrapping
36
+ // ordered-list items (which renders as roman numerals).
37
+ const steps = new Command("steps")
38
+ // Has no registered arguments, so its custom `.usage()` is preserved
39
+ // verbatim in the generated Usage line.
40
+ .usage("<command> [options]")
41
+ .description(
42
+ "Do things in order\n\n" + " 1. First step\n" + " 2. Second step\n",
43
+ );
44
+
45
+ // Mixes a code-span placeholder (must stay literal, no backslash) with a
46
+ // bare prose placeholder (must be escaped so MDX doesn't parse it as JSX).
47
+ const escape = new Command("escape").description(
48
+ "The positional `<nameOrToken>` is set by --team <team_slug>",
49
+ );
50
+
51
+ // Exercises rendering `npx convex ...` code spans in list items as copy
52
+ // buttons, while leaving code spans in plain prose lines untouched.
53
+ const envLike = new Command("envLike").description(
54
+ "- Set a variable: `npx convex env set NAME 'value'`\n" +
55
+ "Unrelated span: `npx convex run foo`",
56
+ );
57
+
58
+ // A description with a 3-level nested bullet list followed by a prose-led
59
+ // numbered list, like `convex deploy`. The nested sub-items (indented 2 and 4
60
+ // spaces) must keep their nesting, while the prose-led numbered list must be
61
+ // dedented to the left margin so it interrupts the paragraph.
62
+ const nested = new Command("nested").description(
63
+ [
64
+ "Pick a target like this:",
65
+ "- If FOO is set, use the default.",
66
+ "- If BAR is set, use its deployment.",
67
+ " - When it's a preview key, deploy to a preview deployment:",
68
+ " - with the current Git branch name in CI",
69
+ " - or with the name from `--preview-name`",
70
+ "",
71
+ "Then it will:",
72
+ " 1. Typecheck your functions.",
73
+ " 2. Push to the deployment.",
74
+ ].join("\n"),
75
+ );
76
+
77
+ const secret = new Command("secret").description("Hidden command");
78
+
79
+ // Overrides `.usage()` to show its args as required (for nicer `--help`)
80
+ // even though they're registered as optional. The docs must reflect the
81
+ // registered optionality, not the override.
82
+ const config = new Command("config")
83
+ .description("Set config")
84
+ .usage("[options] <key> <value>")
85
+ .argument("[key]", "The config key")
86
+ .argument("[value]", "The value; omit to set interactively");
87
+
88
+ return new Command("fake")
89
+ .description("A fake CLI for testing generateDocs")
90
+ .usage("<command> [options]")
91
+ .addCommand(greet)
92
+ .addCommand(item)
93
+ .addCommand(config)
94
+ .addCommand(steps)
95
+ .addCommand(escape)
96
+ .addCommand(envLike)
97
+ .addCommand(nested)
98
+ .addCommand(secret, { hidden: true });
99
+ }
100
+
101
+ describe("generateDocs", () => {
102
+ it("creates one file per visible main command and no root index", () => {
103
+ const docs = generateDocs(makeFakeRoot());
104
+ const paths = Object.keys(docs).sort();
105
+ expect(paths).toEqual([
106
+ "config.mdx",
107
+ "envLike.mdx",
108
+ "escape.mdx",
109
+ "greet.mdx",
110
+ "item.mdx",
111
+ "nested.mdx",
112
+ "steps.mdx",
113
+ ]);
114
+ expect(docs["index.mdx"]).toBeUndefined();
115
+ });
116
+
117
+ it("does not emit a file for hidden subcommands", () => {
118
+ const docs = generateDocs(makeFakeRoot());
119
+ expect(docs["secret.mdx"]).toBeUndefined();
120
+ });
121
+
122
+ it("renders the command name as a heading with the npx prefix", () => {
123
+ const docs = generateDocs(makeFakeRoot());
124
+ expect(docs["greet.mdx"]).toContain("# `npx fake greet`");
125
+ expect(docs["greet.mdx"]).toContain("Print a greeting");
126
+ });
127
+
128
+ it("includes a @generated marker comment in every file", () => {
129
+ const docs = generateDocs(makeFakeRoot());
130
+ for (const md of Object.values(docs)) {
131
+ expect(md).toContain(
132
+ "{/* @generated from the command definitions, do not edit manually (run `just regenerate-cli-docs` to regenerate) */}",
133
+ );
134
+ }
135
+ });
136
+
137
+ it("emits sidebar_position frontmatter matching command definition order", () => {
138
+ const docs = generateDocs(makeFakeRoot());
139
+ expect(docs["greet.mdx"]).toMatch(/^---\nsidebar_position: 1\n/);
140
+ expect(docs["item.mdx"]).toMatch(/^---\nsidebar_position: 2\n/);
141
+ });
142
+
143
+ it("emits a title frontmatter with the full npx command so the page <title> isn't just the file name", () => {
144
+ const docs = generateDocs(makeFakeRoot());
145
+ expect(docs["greet.mdx"]).toMatch(/\ntitle: "npx fake greet"\n/);
146
+ expect(docs["item.mdx"]).toMatch(/\ntitle: "npx fake item"\n/);
147
+ });
148
+
149
+ it("emits a description frontmatter carrying the command summary", () => {
150
+ const docs = generateDocs(makeFakeRoot());
151
+ expect(docs["greet.mdx"]).toMatch(/\ndescription: "Print a greeting"\n/);
152
+ expect(docs["item.mdx"]).toMatch(/\ndescription: "Manage items"\n/);
153
+ });
154
+
155
+ it("uses `npx` in usage lines", () => {
156
+ const md = generateDocs(makeFakeRoot())["greet.mdx"];
157
+ expect(md).toMatch(/```sh\nnpx fake greet/);
158
+ });
159
+
160
+ it("documents arguments and options", () => {
161
+ const md = generateDocs(makeFakeRoot())["greet.mdx"];
162
+ expect(md).toContain("## Arguments");
163
+ expect(md).toContain("<name>");
164
+ expect(md).toContain("Who to greet");
165
+ expect(md).toContain("## Options");
166
+ expect(md).toContain("-l, --loud");
167
+ });
168
+
169
+ it("renders descendant subcommands as h2 sections with an id matching the leaf name", () => {
170
+ const md = generateDocs(makeFakeRoot())["item.mdx"];
171
+ expect(md).toContain("## `npx fake item add` \\{#add}");
172
+ expect(md).toContain("## `npx fake item list` \\{#list}");
173
+ expect(md).toContain("### Usage");
174
+ });
175
+
176
+ it("documents aliases for nested subcommands inside the main command file", () => {
177
+ const md = generateDocs(makeFakeRoot())["item.mdx"];
178
+ expect(md).toContain("### Aliases");
179
+ expect(md).toContain("`ls`");
180
+ });
181
+
182
+ it("links nested subcommand list entries to in-page anchors", () => {
183
+ const md = generateDocs(makeFakeRoot())["item.mdx"];
184
+ expect(md).toContain("## Subcommands");
185
+ expect(md).toContain("[`npx fake item add`](#add)");
186
+ expect(md).toContain("[`npx fake item list`](#list)");
187
+ });
188
+
189
+ it("gives sub-subcommands a path-based anchor so leaf names don't collide", () => {
190
+ const md = generateDocs(makeFakeRoot())["item.mdx"];
191
+ // `item create` keeps the bare leaf anchor...
192
+ expect(md).toContain("## `npx fake item create` \\{#create}");
193
+ // ...while `item token create` is namespaced to avoid a duplicate `#create`.
194
+ expect(md).toContain("### `npx fake item token create` \\{#token-create}");
195
+ expect(md).not.toContain("`npx fake item token create` \\{#create}");
196
+ });
197
+
198
+ it("renders sub-subcommands at a deeper heading level than their parent group", () => {
199
+ const md = generateDocs(makeFakeRoot())["item.mdx"];
200
+ // `item token` is a direct subcommand (h2)...
201
+ expect(md).toContain("## `npx fake item token` \\{#token}");
202
+ // ...and its child `item token create` nests one level deeper (h3).
203
+ expect(md).toContain("### `npx fake item token create` \\{#token-create}");
204
+ });
205
+
206
+ it("produces unique heading anchor ids within a file", () => {
207
+ const md = generateDocs(makeFakeRoot())["item.mdx"];
208
+ const anchors = [...md.matchAll(/\\\{#([\w-]+)}/g)].map((m) => m[1]);
209
+ expect(new Set(anchors).size).toBe(anchors.length);
210
+ });
211
+
212
+ it("links sub-subcommand list entries to their path-based anchors", () => {
213
+ const md = generateDocs(makeFakeRoot())["item.mdx"];
214
+ // `token` is a direct child of `item`, listed in item's Subcommands.
215
+ expect(md).toContain("[`npx fake item token`](#token)");
216
+ });
217
+
218
+ it("derives the usage line from registered argument optionality, ignoring a conflicting .usage() override", () => {
219
+ const md = generateDocs(makeFakeRoot())["config.mdx"];
220
+ // The command overrides .usage() with `<key> <value>`, but the args are
221
+ // registered as optional, so the Usage line must match the Arguments
222
+ // section (`[key]`/`[value]`) rather than the override.
223
+ expect(md).toContain("```sh\nnpx fake config [options] [key] [value]\n```");
224
+ expect(md).not.toContain("<key> <value>");
225
+ expect(md).toContain("`[key]`");
226
+ expect(md).toContain("`[value]`");
227
+ });
228
+
229
+ it("keeps the .usage() override for commands with no registered arguments", () => {
230
+ // `steps` has no positional args, so its custom `<command> [options]`
231
+ // usage is preserved verbatim.
232
+ const md = generateDocs(makeFakeRoot())["steps.mdx"];
233
+ expect(md).toContain("```sh\nnpx fake steps <command> [options]\n```");
234
+ });
235
+
236
+ it("renders an indented numbered description as an ordered list, not bullets", () => {
237
+ const md = generateDocs(makeFakeRoot())["steps.mdx"];
238
+ expect(md).toContain("1. First step");
239
+ expect(md).toContain("2. Second step");
240
+ // Must not wrap the ordered-list items in bullets (renders as roman numerals).
241
+ expect(md).not.toContain("- 1. First step");
242
+ });
243
+
244
+ it("preserves the nesting of a multi-level list that follows list items", () => {
245
+ const md = generateDocs(makeFakeRoot())["nested.mdx"];
246
+ // Top-level items stay at the left margin.
247
+ expect(md).toContain("\n- If BAR is set, use its deployment.\n");
248
+ // The 2-space sub-item stays nested under its parent (not flattened to the
249
+ // left margin, which was the bug when deeper-indented lines flushed early).
250
+ expect(md).toContain(
251
+ "\n - When it's a preview key, deploy to a preview deployment:\n",
252
+ );
253
+ expect(md).not.toContain("\n- When it's a preview key");
254
+ // The 4-space sub-sub-items keep their deeper nesting.
255
+ expect(md).toContain("\n - with the current Git branch name in CI\n");
256
+ expect(md).toContain("\n - or with the name from `--preview-name`\n");
257
+ });
258
+
259
+ it("dedents a prose-led numbered list to the left margin so it interrupts the paragraph", () => {
260
+ const md = generateDocs(makeFakeRoot())["nested.mdx"];
261
+ // The numbered list follows prose ("Then it will:"), so it must be dedented
262
+ // to the left margin to render as an ordered list rather than collapsing
263
+ // into the preceding paragraph.
264
+ expect(md).toContain("\n1. Typecheck your functions.\n");
265
+ expect(md).toContain("\n2. Push to the deployment.\n");
266
+ expect(md).not.toContain(" 1. Typecheck your functions.");
267
+ });
268
+
269
+ it("escapes JSX-like placeholders in prose but leaves inline code spans alone", () => {
270
+ const md = generateDocs(makeFakeRoot())["escape.mdx"];
271
+ // Inside backticks `<nameOrToken>` is already literal — no backslash.
272
+ expect(md).toContain("`<nameOrToken>`");
273
+ expect(md).not.toContain("`\\<nameOrToken>`");
274
+ // In prose, the bare placeholder is escaped so MDX won't parse it as a tag.
275
+ expect(md).toContain("--team \\<team_slug>");
276
+ });
277
+
278
+ it("renders `npx convex ...` code spans in list items as CodeWithCopyButton, leaving prose spans as code", () => {
279
+ const md = generateDocs(makeFakeRoot())["envLike.mdx"];
280
+ // Commands in list items become copy buttons.
281
+ expect(md).toContain(
282
+ `<CodeWithCopyButton text={"npx convex env set NAME 'value'"} />`,
283
+ );
284
+ // Code spans outside of list items stay as inline code.
285
+ expect(md).toContain("`npx convex run foo`");
286
+ expect(md).not.toContain(`text={"npx convex run foo"}`);
287
+ });
288
+ });
289
+
290
+ describe("replaceBullets", () => {
291
+ it("replaces a leading `• ` bullet with `- `", () => {
292
+ expect(replaceBullets("• an item")).toBe("- an item");
293
+ });
294
+
295
+ it("preserves leading indentation", () => {
296
+ expect(replaceBullets(" • an item")).toBe(" - an item");
297
+ expect(replaceBullets(" • a deeper item")).toBe(" - a deeper item");
298
+ });
299
+
300
+ it("replaces bullets on every line of a multi-line string", () => {
301
+ const input = "• first\n• second\n • nested";
302
+ expect(replaceBullets(input)).toBe("- first\n- second\n - nested");
303
+ });
304
+
305
+ it("leaves lines without a `• ` bullet untouched", () => {
306
+ const input = "Plain prose\nAnother line";
307
+ expect(replaceBullets(input)).toBe(input);
308
+ });
309
+
310
+ it("only replaces bullets at the start of a line, not mid-line", () => {
311
+ expect(replaceBullets("a • b")).toBe("a • b");
312
+ });
313
+
314
+ it("requires a space after the bullet", () => {
315
+ expect(replaceBullets("•noSpace")).toBe("•noSpace");
316
+ });
317
+
318
+ it("collapses only the single space following the bullet", () => {
319
+ // Extra spaces after the `• ` are preserved.
320
+ expect(replaceBullets("• two spaces")).toBe("- two spaces");
321
+ });
322
+
323
+ it("returns an empty string unchanged", () => {
324
+ expect(replaceBullets("")).toBe("");
325
+ });
326
+ });