@kirchdev/duxt 0.1.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 (401) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +151 -0
  3. package/app/app.config.ts +13 -0
  4. package/app/app.vue +122 -0
  5. package/app/assets/css/duxt.css +555 -0
  6. package/app/assets/css/typeset.css +498 -0
  7. package/app/components/DuxtBrand.vue +53 -0
  8. package/app/components/DuxtBreadcrumb.vue +37 -0
  9. package/app/components/DuxtCodeBlock.vue +143 -0
  10. package/app/components/DuxtCopyPage.vue +117 -0
  11. package/app/components/DuxtFooter.vue +86 -0
  12. package/app/components/DuxtHeader.vue +496 -0
  13. package/app/components/DuxtJsonEditor.vue +359 -0
  14. package/app/components/DuxtLandingProse.vue +90 -0
  15. package/app/components/DuxtLandingShowcase.vue +295 -0
  16. package/app/components/DuxtLiveWindow.vue +343 -0
  17. package/app/components/DuxtLocale.vue +86 -0
  18. package/app/components/DuxtMetaList.vue +76 -0
  19. package/app/components/DuxtNavigation.vue +94 -0
  20. package/app/components/DuxtNavigationLink.vue +41 -0
  21. package/app/components/DuxtOpenApiCallbacks.vue +92 -0
  22. package/app/components/DuxtOpenApiClient.vue +1339 -0
  23. package/app/components/DuxtOpenApiMedia.vue +108 -0
  24. package/app/components/DuxtOpenApiMethod.vue +59 -0
  25. package/app/components/DuxtOpenApiParameters.vue +114 -0
  26. package/app/components/DuxtOpenApiResponses.vue +109 -0
  27. package/app/components/DuxtOpenApiSchema.vue +365 -0
  28. package/app/components/DuxtOpenApiSecurity.vue +115 -0
  29. package/app/components/DuxtPageFeedback.vue +56 -0
  30. package/app/components/DuxtPageInfo.vue +194 -0
  31. package/app/components/DuxtPageNav.vue +93 -0
  32. package/app/components/DuxtPreviewSkeleton.vue +262 -0
  33. package/app/components/DuxtProgress.vue +45 -0
  34. package/app/components/DuxtSearch.vue +271 -0
  35. package/app/components/DuxtSections.vue +65 -0
  36. package/app/components/DuxtShortcuts.vue +46 -0
  37. package/app/components/DuxtSkipLink.vue +34 -0
  38. package/app/components/DuxtToc.vue +86 -0
  39. package/app/components/DuxtTranslationBanner.vue +64 -0
  40. package/app/components/DuxtVersion.vue +168 -0
  41. package/app/components/DuxtVersionBanner.vue +109 -0
  42. package/app/components/OgImage/Duxt.satori.vue +82 -0
  43. package/app/components/content/Accordion.vue +37 -0
  44. package/app/components/content/AccordionItem.vue +46 -0
  45. package/app/components/content/Callout.vue +58 -0
  46. package/app/components/content/ChangelogGroup.vue +91 -0
  47. package/app/components/content/ChangelogReleases.vue +520 -0
  48. package/app/components/content/CodeGroup.vue +183 -0
  49. package/app/components/content/DevtoolsPanel.vue +107 -0
  50. package/app/components/content/Field.vue +50 -0
  51. package/app/components/content/FieldGroup.vue +8 -0
  52. package/app/components/content/FileTree.vue +92 -0
  53. package/app/components/content/Mermaid.vue +70 -0
  54. package/app/components/content/OpenApiOperation.vue +185 -0
  55. package/app/components/content/OpenApiOperations.vue +72 -0
  56. package/app/components/content/OpenApiOverview.vue +302 -0
  57. package/app/components/content/PackageManagers.vue +187 -0
  58. package/app/components/content/PageCards.vue +48 -0
  59. package/app/components/content/Partial.vue +65 -0
  60. package/app/components/content/Preview.vue +173 -0
  61. package/app/components/content/ProseA.vue +55 -0
  62. package/app/components/content/ProseH2.vue +53 -0
  63. package/app/components/content/ProseH3.vue +53 -0
  64. package/app/components/content/ProseH4.vue +53 -0
  65. package/app/components/content/ProseImg.vue +87 -0
  66. package/app/components/content/ProsePre.vue +58 -0
  67. package/app/components/content/ProseTable.vue +11 -0
  68. package/app/components/content/Since.vue +21 -0
  69. package/app/components/content/Steps.vue +20 -0
  70. package/app/components/content/Tab.vue +23 -0
  71. package/app/components/content/TabGroup.vue +58 -0
  72. package/app/components/ui/alert/Alert.vue +21 -0
  73. package/app/components/ui/alert/AlertDescription.vue +22 -0
  74. package/app/components/ui/alert/AlertTitle.vue +22 -0
  75. package/app/components/ui/alert/index.ts +24 -0
  76. package/app/components/ui/badge/Badge.vue +28 -0
  77. package/app/components/ui/badge/index.ts +52 -0
  78. package/app/components/ui/breadcrumb/Breadcrumb.vue +13 -0
  79. package/app/components/ui/breadcrumb/BreadcrumbEllipsis.vue +22 -0
  80. package/app/components/ui/breadcrumb/BreadcrumbItem.vue +17 -0
  81. package/app/components/ui/breadcrumb/BreadcrumbLink.vue +24 -0
  82. package/app/components/ui/breadcrumb/BreadcrumbList.vue +22 -0
  83. package/app/components/ui/breadcrumb/BreadcrumbPage.vue +20 -0
  84. package/app/components/ui/breadcrumb/BreadcrumbSeparator.vue +21 -0
  85. package/app/components/ui/breadcrumb/index.ts +7 -0
  86. package/app/components/ui/button/Button.vue +31 -0
  87. package/app/components/ui/button/index.ts +39 -0
  88. package/app/components/ui/card/Card.vue +22 -0
  89. package/app/components/ui/card/CardAction.vue +22 -0
  90. package/app/components/ui/card/CardContent.vue +14 -0
  91. package/app/components/ui/card/CardDescription.vue +17 -0
  92. package/app/components/ui/card/CardFooter.vue +17 -0
  93. package/app/components/ui/card/CardHeader.vue +22 -0
  94. package/app/components/ui/card/CardTitle.vue +17 -0
  95. package/app/components/ui/card/index.ts +7 -0
  96. package/app/components/ui/collapsible/Collapsible.vue +19 -0
  97. package/app/components/ui/collapsible/CollapsibleContent.vue +12 -0
  98. package/app/components/ui/collapsible/CollapsibleTrigger.vue +12 -0
  99. package/app/components/ui/collapsible/index.ts +3 -0
  100. package/app/components/ui/command/Command.vue +98 -0
  101. package/app/components/ui/command/CommandDialog.vue +42 -0
  102. package/app/components/ui/command/CommandEmpty.vue +31 -0
  103. package/app/components/ui/command/CommandGroup.vue +52 -0
  104. package/app/components/ui/command/CommandInput.vue +45 -0
  105. package/app/components/ui/command/CommandItem.vue +85 -0
  106. package/app/components/ui/command/CommandList.vue +32 -0
  107. package/app/components/ui/command/CommandSeparator.vue +23 -0
  108. package/app/components/ui/command/CommandShortcut.vue +19 -0
  109. package/app/components/ui/command/index.ts +29 -0
  110. package/app/components/ui/dialog/Dialog.vue +15 -0
  111. package/app/components/ui/dialog/DialogClose.vue +12 -0
  112. package/app/components/ui/dialog/DialogContent.vue +61 -0
  113. package/app/components/ui/dialog/DialogDescription.vue +25 -0
  114. package/app/components/ui/dialog/DialogFooter.vue +30 -0
  115. package/app/components/ui/dialog/DialogHeader.vue +17 -0
  116. package/app/components/ui/dialog/DialogOverlay.vue +28 -0
  117. package/app/components/ui/dialog/DialogScrollContent.vue +65 -0
  118. package/app/components/ui/dialog/DialogTitle.vue +25 -0
  119. package/app/components/ui/dialog/DialogTrigger.vue +12 -0
  120. package/app/components/ui/dialog/index.ts +10 -0
  121. package/app/components/ui/dropdown-menu/DropdownMenu.vue +19 -0
  122. package/app/components/ui/dropdown-menu/DropdownMenuCheckboxItem.vue +47 -0
  123. package/app/components/ui/dropdown-menu/DropdownMenuContent.vue +47 -0
  124. package/app/components/ui/dropdown-menu/DropdownMenuGroup.vue +12 -0
  125. package/app/components/ui/dropdown-menu/DropdownMenuItem.vue +41 -0
  126. package/app/components/ui/dropdown-menu/DropdownMenuLabel.vue +27 -0
  127. package/app/components/ui/dropdown-menu/DropdownMenuRadioGroup.vue +21 -0
  128. package/app/components/ui/dropdown-menu/DropdownMenuRadioItem.vue +48 -0
  129. package/app/components/ui/dropdown-menu/DropdownMenuSeparator.vue +23 -0
  130. package/app/components/ui/dropdown-menu/DropdownMenuShortcut.vue +19 -0
  131. package/app/components/ui/dropdown-menu/DropdownMenuSub.vue +19 -0
  132. package/app/components/ui/dropdown-menu/DropdownMenuSubContent.vue +34 -0
  133. package/app/components/ui/dropdown-menu/DropdownMenuSubTrigger.vue +34 -0
  134. package/app/components/ui/dropdown-menu/DropdownMenuTrigger.vue +17 -0
  135. package/app/components/ui/dropdown-menu/index.ts +16 -0
  136. package/app/components/ui/input/Input.vue +35 -0
  137. package/app/components/ui/input/index.ts +1 -0
  138. package/app/components/ui/navigation-menu/NavigationMenu.vue +42 -0
  139. package/app/components/ui/navigation-menu/NavigationMenuContent.vue +35 -0
  140. package/app/components/ui/navigation-menu/NavigationMenuIndicator.vue +32 -0
  141. package/app/components/ui/navigation-menu/NavigationMenuItem.vue +23 -0
  142. package/app/components/ui/navigation-menu/NavigationMenuLink.vue +30 -0
  143. package/app/components/ui/navigation-menu/NavigationMenuList.vue +30 -0
  144. package/app/components/ui/navigation-menu/NavigationMenuTrigger.vue +31 -0
  145. package/app/components/ui/navigation-menu/NavigationMenuViewport.vue +30 -0
  146. package/app/components/ui/navigation-menu/index.ts +14 -0
  147. package/app/components/ui/scroll-area/ScrollArea.vue +31 -0
  148. package/app/components/ui/scroll-area/ScrollBar.vue +38 -0
  149. package/app/components/ui/scroll-area/index.ts +2 -0
  150. package/app/components/ui/select/Select.vue +15 -0
  151. package/app/components/ui/select/SelectContent.vue +59 -0
  152. package/app/components/ui/select/SelectGroup.vue +19 -0
  153. package/app/components/ui/select/SelectItem.vue +42 -0
  154. package/app/components/ui/select/SelectItemText.vue +12 -0
  155. package/app/components/ui/select/SelectLabel.vue +16 -0
  156. package/app/components/ui/select/SelectScrollDownButton.vue +28 -0
  157. package/app/components/ui/select/SelectScrollUpButton.vue +28 -0
  158. package/app/components/ui/select/SelectSeparator.vue +20 -0
  159. package/app/components/ui/select/SelectTrigger.vue +32 -0
  160. package/app/components/ui/select/SelectValue.vue +12 -0
  161. package/app/components/ui/select/index.ts +11 -0
  162. package/app/components/ui/separator/Separator.vue +30 -0
  163. package/app/components/ui/separator/index.ts +1 -0
  164. package/app/components/ui/sheet/Sheet.vue +15 -0
  165. package/app/components/ui/sheet/SheetClose.vue +12 -0
  166. package/app/components/ui/sheet/SheetContent.vue +68 -0
  167. package/app/components/ui/sheet/SheetDescription.vue +23 -0
  168. package/app/components/ui/sheet/SheetFooter.vue +15 -0
  169. package/app/components/ui/sheet/SheetHeader.vue +15 -0
  170. package/app/components/ui/sheet/SheetOverlay.vue +28 -0
  171. package/app/components/ui/sheet/SheetTitle.vue +23 -0
  172. package/app/components/ui/sheet/SheetTrigger.vue +12 -0
  173. package/app/components/ui/sheet/index.ts +8 -0
  174. package/app/components/ui/sidebar/Sidebar.vue +110 -0
  175. package/app/components/ui/sidebar/SidebarContent.vue +23 -0
  176. package/app/components/ui/sidebar/SidebarFooter.vue +18 -0
  177. package/app/components/ui/sidebar/SidebarGroup.vue +18 -0
  178. package/app/components/ui/sidebar/SidebarGroupAction.vue +31 -0
  179. package/app/components/ui/sidebar/SidebarGroupContent.vue +18 -0
  180. package/app/components/ui/sidebar/SidebarGroupLabel.vue +30 -0
  181. package/app/components/ui/sidebar/SidebarHeader.vue +18 -0
  182. package/app/components/ui/sidebar/SidebarInput.vue +19 -0
  183. package/app/components/ui/sidebar/SidebarInset.vue +23 -0
  184. package/app/components/ui/sidebar/SidebarMenu.vue +18 -0
  185. package/app/components/ui/sidebar/SidebarMenuAction.vue +42 -0
  186. package/app/components/ui/sidebar/SidebarMenuBadge.vue +28 -0
  187. package/app/components/ui/sidebar/SidebarMenuButton.vue +60 -0
  188. package/app/components/ui/sidebar/SidebarMenuButtonChild.vue +36 -0
  189. package/app/components/ui/sidebar/SidebarMenuItem.vue +18 -0
  190. package/app/components/ui/sidebar/SidebarMenuSkeleton.vue +35 -0
  191. package/app/components/ui/sidebar/SidebarMenuSub.vue +24 -0
  192. package/app/components/ui/sidebar/SidebarMenuSubButton.vue +43 -0
  193. package/app/components/ui/sidebar/SidebarMenuSubItem.vue +18 -0
  194. package/app/components/ui/sidebar/SidebarProvider.vue +109 -0
  195. package/app/components/ui/sidebar/SidebarRail.vue +35 -0
  196. package/app/components/ui/sidebar/SidebarSeparator.vue +19 -0
  197. package/app/components/ui/sidebar/SidebarTrigger.vue +26 -0
  198. package/app/components/ui/sidebar/index.ts +62 -0
  199. package/app/components/ui/sidebar/utils.ts +19 -0
  200. package/app/components/ui/skeleton/Skeleton.vue +17 -0
  201. package/app/components/ui/skeleton/index.ts +1 -0
  202. package/app/components/ui/sonner/Sonner.vue +67 -0
  203. package/app/components/ui/sonner/index.ts +1 -0
  204. package/app/components/ui/tabs/Tabs.vue +26 -0
  205. package/app/components/ui/tabs/TabsContent.vue +23 -0
  206. package/app/components/ui/tabs/TabsList.vue +28 -0
  207. package/app/components/ui/tabs/TabsTrigger.vue +30 -0
  208. package/app/components/ui/tabs/index.ts +4 -0
  209. package/app/components/ui/textarea/Textarea.vue +32 -0
  210. package/app/components/ui/textarea/index.ts +1 -0
  211. package/app/components/ui/tooltip/Tooltip.vue +15 -0
  212. package/app/components/ui/tooltip/TooltipContent.vue +49 -0
  213. package/app/components/ui/tooltip/TooltipProvider.vue +14 -0
  214. package/app/components/ui/tooltip/TooltipTrigger.vue +12 -0
  215. package/app/components/ui/tooltip/index.ts +4 -0
  216. package/app/composables/useActiveHeading.ts +90 -0
  217. package/app/composables/useDuxtAnimatedHeight.ts +155 -0
  218. package/app/composables/useDuxtBreadcrumb.ts +60 -0
  219. package/app/composables/useDuxtChoice.ts +28 -0
  220. package/app/composables/useDuxtCollection.ts +89 -0
  221. package/app/composables/useDuxtConfig.ts +47 -0
  222. package/app/composables/useDuxtNavigation.ts +87 -0
  223. package/app/composables/useDuxtPageFocus.ts +30 -0
  224. package/app/composables/useDuxtPath.ts +42 -0
  225. package/app/composables/useDuxtSearch.ts +208 -0
  226. package/app/composables/useDuxtSection.ts +44 -0
  227. package/app/composables/useDuxtSectionRow.ts +49 -0
  228. package/app/composables/useDuxtShortcuts.ts +58 -0
  229. package/app/composables/useDuxtSiteUrl.ts +27 -0
  230. package/app/composables/useDuxtToast.ts +25 -0
  231. package/app/composables/useDuxtVersion.ts +138 -0
  232. package/app/composables/useFuzzySearch.ts +83 -0
  233. package/app/composables/usePackageManager.ts +4 -0
  234. package/app/composables/useRecentPages.ts +52 -0
  235. package/app/error.vue +133 -0
  236. package/app/layouts/changelog.vue +85 -0
  237. package/app/layouts/default.vue +23 -0
  238. package/app/layouts/docs.vue +62 -0
  239. package/app/layouts/reference.vue +85 -0
  240. package/app/lib/utils.ts +7 -0
  241. package/app/middleware/duxt-section-layout.global.ts +57 -0
  242. package/app/pages/[...slug].vue +441 -0
  243. package/app/pages/index.vue +479 -0
  244. package/app/types/duxt.d.ts +955 -0
  245. package/app/utils/aside.ts +16 -0
  246. package/app/utils/changelog.ts +182 -0
  247. package/app/utils/code-highlight.ts +116 -0
  248. package/app/utils/duxt-config.ts +185 -0
  249. package/app/utils/duxt-text.ts +135 -0
  250. package/app/utils/file-icons.ts +62 -0
  251. package/app/utils/generated-sections.ts +190 -0
  252. package/app/utils/generated-toc.ts +216 -0
  253. package/app/utils/heading-link.ts +32 -0
  254. package/app/utils/locale-path.ts +45 -0
  255. package/app/utils/navigation-tree.ts +206 -0
  256. package/app/utils/nearest-page.ts +72 -0
  257. package/app/utils/openapi.ts +1028 -0
  258. package/app/utils/package-command.ts +162 -0
  259. package/app/utils/request-samples.ts +635 -0
  260. package/app/utils/section-scope.ts +97 -0
  261. package/app/utils/sheet-navigation.ts +100 -0
  262. package/app/utils/source-file.ts +84 -0
  263. package/app/utils/version-choices.ts +68 -0
  264. package/app/utils/version-paths.ts +65 -0
  265. package/bin/duxt-report.mjs +45 -0
  266. package/components.json +19 -0
  267. package/content-cache.ts +193 -0
  268. package/content.config.ts +38 -0
  269. package/duxt-app-config.ts +124 -0
  270. package/highlight-langs.ts +68 -0
  271. package/i18n/i18n.config.ts +16 -0
  272. package/i18n/locales/de/duxt/changelog.json +17 -0
  273. package/i18n/locales/de/duxt/code.json +13 -0
  274. package/i18n/locales/de/duxt/defaults.json +22 -0
  275. package/i18n/locales/de/duxt/devtools.json +7 -0
  276. package/i18n/locales/de/duxt/error.json +10 -0
  277. package/i18n/locales/de/duxt/footer.json +7 -0
  278. package/i18n/locales/de/duxt/locale.json +7 -0
  279. package/i18n/locales/de/duxt/nav.json +17 -0
  280. package/i18n/locales/de/duxt/openapi.json +89 -0
  281. package/i18n/locales/de/duxt/page.json +34 -0
  282. package/i18n/locales/de/duxt/search.json +12 -0
  283. package/i18n/locales/de/duxt/shortcuts.json +11 -0
  284. package/i18n/locales/de/duxt/theme.json +7 -0
  285. package/i18n/locales/de/duxt/toc.json +7 -0
  286. package/i18n/locales/de/duxt/version.json +25 -0
  287. package/i18n/locales/en/duxt/changelog.json +17 -0
  288. package/i18n/locales/en/duxt/code.json +13 -0
  289. package/i18n/locales/en/duxt/defaults.json +22 -0
  290. package/i18n/locales/en/duxt/devtools.json +7 -0
  291. package/i18n/locales/en/duxt/error.json +10 -0
  292. package/i18n/locales/en/duxt/footer.json +7 -0
  293. package/i18n/locales/en/duxt/locale.json +7 -0
  294. package/i18n/locales/en/duxt/nav.json +17 -0
  295. package/i18n/locales/en/duxt/openapi.json +89 -0
  296. package/i18n/locales/en/duxt/page.json +34 -0
  297. package/i18n/locales/en/duxt/search.json +12 -0
  298. package/i18n/locales/en/duxt/shortcuts.json +11 -0
  299. package/i18n/locales/en/duxt/theme.json +7 -0
  300. package/i18n/locales/en/duxt/toc.json +7 -0
  301. package/i18n/locales/en/duxt/version.json +25 -0
  302. package/i18n/locales/es/duxt/changelog.json +17 -0
  303. package/i18n/locales/es/duxt/code.json +13 -0
  304. package/i18n/locales/es/duxt/defaults.json +22 -0
  305. package/i18n/locales/es/duxt/devtools.json +7 -0
  306. package/i18n/locales/es/duxt/error.json +10 -0
  307. package/i18n/locales/es/duxt/footer.json +7 -0
  308. package/i18n/locales/es/duxt/locale.json +7 -0
  309. package/i18n/locales/es/duxt/nav.json +17 -0
  310. package/i18n/locales/es/duxt/openapi.json +89 -0
  311. package/i18n/locales/es/duxt/page.json +34 -0
  312. package/i18n/locales/es/duxt/search.json +12 -0
  313. package/i18n/locales/es/duxt/shortcuts.json +11 -0
  314. package/i18n/locales/es/duxt/theme.json +7 -0
  315. package/i18n/locales/es/duxt/toc.json +7 -0
  316. package/i18n/locales/es/duxt/version.json +25 -0
  317. package/i18n/locales/fr/duxt/changelog.json +17 -0
  318. package/i18n/locales/fr/duxt/code.json +13 -0
  319. package/i18n/locales/fr/duxt/defaults.json +22 -0
  320. package/i18n/locales/fr/duxt/devtools.json +7 -0
  321. package/i18n/locales/fr/duxt/error.json +10 -0
  322. package/i18n/locales/fr/duxt/footer.json +7 -0
  323. package/i18n/locales/fr/duxt/locale.json +7 -0
  324. package/i18n/locales/fr/duxt/nav.json +17 -0
  325. package/i18n/locales/fr/duxt/openapi.json +89 -0
  326. package/i18n/locales/fr/duxt/page.json +34 -0
  327. package/i18n/locales/fr/duxt/search.json +12 -0
  328. package/i18n/locales/fr/duxt/shortcuts.json +11 -0
  329. package/i18n/locales/fr/duxt/theme.json +7 -0
  330. package/i18n/locales/fr/duxt/toc.json +7 -0
  331. package/i18n/locales/fr/duxt/version.json +25 -0
  332. package/i18n/locales/pt/duxt/changelog.json +17 -0
  333. package/i18n/locales/pt/duxt/code.json +13 -0
  334. package/i18n/locales/pt/duxt/defaults.json +22 -0
  335. package/i18n/locales/pt/duxt/devtools.json +7 -0
  336. package/i18n/locales/pt/duxt/error.json +10 -0
  337. package/i18n/locales/pt/duxt/footer.json +7 -0
  338. package/i18n/locales/pt/duxt/locale.json +7 -0
  339. package/i18n/locales/pt/duxt/nav.json +17 -0
  340. package/i18n/locales/pt/duxt/openapi.json +89 -0
  341. package/i18n/locales/pt/duxt/page.json +34 -0
  342. package/i18n/locales/pt/duxt/search.json +12 -0
  343. package/i18n/locales/pt/duxt/shortcuts.json +11 -0
  344. package/i18n/locales/pt/duxt/theme.json +7 -0
  345. package/i18n/locales/pt/duxt/toc.json +7 -0
  346. package/i18n/locales/pt/duxt/version.json +25 -0
  347. package/i18n/locales/pt-BR/duxt/error.json +8 -0
  348. package/i18n/locales/pt-BR/duxt/nav.json +10 -0
  349. package/i18n/locales/pt-BR/duxt/page.json +10 -0
  350. package/i18n/locales/pt-BR/duxt/search.json +11 -0
  351. package/i18n/locales/pt-BR/duxt/version.json +13 -0
  352. package/mdc.config.ts +28 -0
  353. package/modules/config.ts +440 -0
  354. package/modules/devtools.ts +126 -0
  355. package/modules/git-meta.ts +349 -0
  356. package/modules/redirects.ts +152 -0
  357. package/modules/validate.ts +137 -0
  358. package/nuxt.config.ts +530 -0
  359. package/openapi-model.ts +358 -0
  360. package/openapi-parse.ts +1052 -0
  361. package/package.json +161 -0
  362. package/public/devtools/cache.html +318 -0
  363. package/public/devtools/checks.html +309 -0
  364. package/public/devtools/config.html +461 -0
  365. package/public/devtools/i18n.html +309 -0
  366. package/public/devtools/pages.html +348 -0
  367. package/public/devtools/paths.html +315 -0
  368. package/public/devtools/redirects.html +309 -0
  369. package/public/devtools/search.html +324 -0
  370. package/public/devtools/sources.html +309 -0
  371. package/public/devtools/versions.html +318 -0
  372. package/report.ts +303 -0
  373. package/repository-root.ts +26 -0
  374. package/section-reports.ts +55 -0
  375. package/sections-changelog.ts +644 -0
  376. package/sections-openapi.ts +450 -0
  377. package/sections-resolve.ts +711 -0
  378. package/sections.ts +157 -0
  379. package/server/devtools/content.ts +120 -0
  380. package/server/devtools/context.ts +38 -0
  381. package/server/devtools/entry-path.ts +30 -0
  382. package/server/devtools/handler.ts +104 -0
  383. package/server/devtools/preview.ts +461 -0
  384. package/server/devtools/render/content.ts +233 -0
  385. package/server/devtools/render/sources.ts +414 -0
  386. package/server/devtools/render/system.ts +352 -0
  387. package/server/devtools/shell.ts +611 -0
  388. package/server/devtools/sources.ts +122 -0
  389. package/server/devtools/system.ts +178 -0
  390. package/server/mcp/tools/list-pages.ts +52 -0
  391. package/server/mcp/tools/read-page.ts +57 -0
  392. package/server/mcp/tools/search-docs.ts +74 -0
  393. package/server/middleware/raw-markdown.ts +86 -0
  394. package/server/routes/llms-full.txt.get.ts +75 -0
  395. package/server/routes/llms.txt.get.ts +63 -0
  396. package/server/routes/rss.xml.get.ts +125 -0
  397. package/server/utils/duxt-server-text.ts +46 -0
  398. package/sources-git.ts +113 -0
  399. package/sources-resolve.ts +908 -0
  400. package/sources.ts +287 -0
  401. package/validate-report.ts +494 -0
@@ -0,0 +1,635 @@
1
+ /**
2
+ * The request the reader has built, written out in the languages they work in.
3
+ *
4
+ * ONE SAMPLE IS A GENERATOR, not a string, because the request changes on every
5
+ * keystroke: the reader edits a path parameter or a body and every open sample
6
+ * has to follow. That is also why these run in the browser and why
7
+ * `code-highlight.ts` needs a grammar per language they use.
8
+ *
9
+ * TYPESCRIPT RATHER THAN JAVASCRIPT, and one group rather than two. The three
10
+ * clients that take a type parameter get the response's component name —
11
+ * `$fetch<Widget>` is the line somebody writes — and `fetch`, which has none,
12
+ * is identical in both languages. Two groups would therefore have carried one
13
+ * pair that never differs and another that differs only where the document
14
+ * named its response, for double the tabs.
15
+ *
16
+ * WHAT A SAMPLE SHOWS IS THE REQUEST, and nothing after it. The response is
17
+ * already on screen, in the panel below the editor — a sample that fetched it a
18
+ * second time would be showing the reader something they can see, at the cost of
19
+ * `defer resp.Body.Close()` and an error branch in every language that has one.
20
+ * The exception is Go, where `err` is not decoration: without the checks it is
21
+ * not Go, and a snippet that does not compile is worse than a long one.
22
+ *
23
+ * THE REGISTRY IS OPEN. A consumer adds its own entry to `duxt.requestSamples`
24
+ * — the API it documents may be consumed in a language nobody here thought of —
25
+ * which is why `DuxtRequestSample` is declared in `app/types/duxt.d.ts` beside
26
+ * the config key rather than exported from here, and why `language` is a plain
27
+ * Shiki id: `modules/config.ts` reads the list at build time and loads exactly
28
+ * the grammars it names.
29
+ */
30
+
31
+ /** The body as data, where it is JSON. Undefined for anything else. */
32
+ function asJson(body?: string): unknown {
33
+ if (!body?.trim()) return undefined;
34
+
35
+ try {
36
+ return JSON.parse(body) as unknown;
37
+ } catch {
38
+ return undefined;
39
+ }
40
+ }
41
+
42
+ const pad = (depth: number) => ' '.repeat(depth);
43
+
44
+ /**
45
+ * Whether a list is short enough to stay on one line.
46
+ *
47
+ * `tags: ['good']` over three lines is the clearest tell that a snippet was
48
+ * generated rather than written, and a body of scalars is mostly short lists. So
49
+ * an array of primitives that fits stays inline; anything holding a structure
50
+ * breaks, because that is what a person would do too.
51
+ */
52
+ function inlineList(items: unknown[], rendered: string[]): string | undefined {
53
+ const primitive = items.every(
54
+ (item) => item === null || typeof item !== 'object'
55
+ );
56
+ if (!primitive) return undefined;
57
+
58
+ const line = rendered.join(', ');
59
+ return line.length <= 60 ? line : undefined;
60
+ }
61
+
62
+ /** A JavaScript key that needs no quotes. */
63
+ const bareKey = /^[A-Za-z_$][\w$]*$/;
64
+
65
+ /** A value as a JavaScript literal, indented for the depth it sits at. */
66
+ function js(value: unknown, depth = 1): string {
67
+ if (value === null) return 'null';
68
+ if (typeof value === 'string') return `'${value.replaceAll("'", "\\'")}'`;
69
+ if (typeof value === 'number' || typeof value === 'boolean') {
70
+ return String(value);
71
+ }
72
+
73
+ if (Array.isArray(value)) {
74
+ if (!value.length) return '[]';
75
+
76
+ const rendered = value.map((item) => js(item, depth + 1));
77
+ const inline = inlineList(value, rendered);
78
+ if (inline) return `[${inline}]`;
79
+
80
+ const items = rendered
81
+ .map((item) => `${pad(depth + 1)}${item}`)
82
+ .join(',\n');
83
+
84
+ return `[\n${items}\n${pad(depth)}]`;
85
+ }
86
+
87
+ const entries = Object.entries(value as Record<string, unknown>);
88
+ if (!entries.length) return '{}';
89
+
90
+ const written = entries
91
+ .map(([key, item]) => {
92
+ const name = bareKey.test(key) ? key : `'${key}'`;
93
+ return `${pad(depth + 1)}${name}: ${js(item, depth + 1)}`;
94
+ })
95
+ .join(',\n');
96
+
97
+ return `{\n${written}\n${pad(depth)}}`;
98
+ }
99
+
100
+ /** A value as a Python literal. Python indents with four spaces. */
101
+ function py(value: unknown, depth = 1): string {
102
+ const step = (n: number) => ' '.repeat(n);
103
+
104
+ if (value === null) return 'None';
105
+ if (typeof value === 'boolean') return value ? 'True' : 'False';
106
+ if (typeof value === 'number') return String(value);
107
+ if (typeof value === 'string') return `"${value.replaceAll('"', '\\"')}"`;
108
+
109
+ if (Array.isArray(value)) {
110
+ if (!value.length) return '[]';
111
+
112
+ const rendered = value.map((item) => py(item, depth + 1));
113
+ const inline = inlineList(value, rendered);
114
+ if (inline) return `[${inline}]`;
115
+
116
+ const items = rendered
117
+ .map((item) => `${step(depth + 1)}${item}`)
118
+ .join(',\n');
119
+
120
+ return `[\n${items},\n${step(depth)}]`;
121
+ }
122
+
123
+ const entries = Object.entries(value as Record<string, unknown>);
124
+ if (!entries.length) return '{}';
125
+
126
+ const written = entries
127
+ .map(
128
+ ([key, item]) =>
129
+ `${step(depth + 1)}"${key.replaceAll('"', '\\"')}": ${py(item, depth + 1)}`
130
+ )
131
+ .join(',\n');
132
+
133
+ return `{\n${written},\n${step(depth)}}`;
134
+ }
135
+
136
+ /** A value as a PHP literal. PHP arrays are the one shape for both kinds. */
137
+ function php(value: unknown, depth = 1): string {
138
+ const step = (n: number) => ' '.repeat(n);
139
+
140
+ if (value === null) return 'null';
141
+ if (typeof value === 'boolean') return value ? 'true' : 'false';
142
+ if (typeof value === 'number') return String(value);
143
+ if (typeof value === 'string') return `'${value.replaceAll("'", "\\'")}'`;
144
+
145
+ if (Array.isArray(value)) {
146
+ if (!value.length) return '[]';
147
+
148
+ const rendered = value.map((item) => php(item, depth + 1));
149
+ const inline = inlineList(value, rendered);
150
+ if (inline) return `[${inline}]`;
151
+
152
+ const items = rendered
153
+ .map((item) => `${step(depth + 1)}${item}`)
154
+ .join(',\n');
155
+
156
+ return `[\n${items},\n${step(depth)}]`;
157
+ }
158
+
159
+ const entries = Object.entries(value as Record<string, unknown>);
160
+ if (!entries.length) return '[]';
161
+
162
+ const written = entries
163
+ .map(
164
+ ([key, item]) =>
165
+ `${step(depth + 1)}'${key.replaceAll("'", "\\'")}' => ${php(item, depth + 1)}`
166
+ )
167
+ .join(',\n');
168
+
169
+ return `[\n${written},\n${step(depth)}]`;
170
+ }
171
+
172
+ /** One argument, safe inside a POSIX shell's single quotes. */
173
+ function shell(value: string): string {
174
+ return `'${value.replaceAll("'", `'\\''`)}'`;
175
+ }
176
+
177
+ const hasHeaders = (request: DuxtOpenApiRequest) =>
178
+ Object.keys(request.headers).length > 0;
179
+
180
+ /**
181
+ * The request as a `curl` line.
182
+ *
183
+ * Single-quoted with the shell's own escape for an embedded quote, because every
184
+ * part of this — a URL, a header, a JSON body — comes from a document this layer
185
+ * did not write.
186
+ *
187
+ * `-X` ONLY WHERE CURL WOULD NOT GUESS. A bare `curl` is already a GET, and `-d`
188
+ * already makes it a POST, so writing the method out in those two cases is the
189
+ * mark of a generated command rather than one somebody would type.
190
+ */
191
+ export function openApiCurl(request: DuxtOpenApiRequest): string {
192
+ const implied =
193
+ request.method === 'GET' || (request.method === 'POST' && !!request.body);
194
+
195
+ const lines = [
196
+ implied
197
+ ? `curl ${shell(request.url)}`
198
+ : `curl -X ${request.method} ${shell(request.url)}`
199
+ ];
200
+
201
+ for (const [name, value] of Object.entries(request.headers)) {
202
+ lines.push(` -H ${shell(`${name}: ${value}`)}`);
203
+ }
204
+
205
+ if (request.body) lines.push(` -d ${shell(request.body)}`);
206
+
207
+ return lines.join(' \\\n');
208
+ }
209
+
210
+ /**
211
+ * Options shared by the three JavaScript clients that take a `RequestInit`-ish
212
+ * object — `method` omitted for GET, which every one of them defaults to.
213
+ */
214
+ function jsOptions(
215
+ request: DuxtOpenApiRequest,
216
+ body: 'stringify' | 'object'
217
+ ): string[] {
218
+ const options: string[] = [];
219
+
220
+ if (request.method !== 'GET') {
221
+ options.push(` method: '${request.method}'`);
222
+ }
223
+
224
+ if (hasHeaders(request)) {
225
+ options.push(` headers: ${js(request.headers)}`);
226
+ }
227
+
228
+ if (request.body) {
229
+ const data = asJson(request.body);
230
+
231
+ if (data === undefined) {
232
+ options.push(` body: ${js(request.body)}`);
233
+ } else if (body === 'object') {
234
+ options.push(` body: ${js(data)}`);
235
+ } else {
236
+ options.push(` body: JSON.stringify(${js(data)})`);
237
+ }
238
+ }
239
+
240
+ return options;
241
+ }
242
+
243
+ /**
244
+ * A call, with the response type where the client has somewhere to put one.
245
+ *
246
+ * `typed` is what separates the TypeScript samples from the JavaScript they
247
+ * would otherwise be character for character: `$fetch`, `useFetch` and axios all
248
+ * take the response shape as a type parameter, and it is the line somebody
249
+ * actually writes. `fetch` has none — it returns a `Response` whatever the body
250
+ * turns out to be — so its sample is the same in either language, and saying so
251
+ * is more honest than inventing an annotation for it.
252
+ */
253
+ function jsCall(
254
+ call: string,
255
+ request: DuxtOpenApiRequest,
256
+ body: 'stringify' | 'object',
257
+ typed = false
258
+ ): string {
259
+ const generic =
260
+ typed && request.responseType ? `<${request.responseType}>` : '';
261
+
262
+ const options = jsOptions(request, body);
263
+ if (!options.length) return `${call}${generic}('${request.url}');`;
264
+
265
+ return `${call}${generic}('${request.url}', {\n${options.join(',\n')}\n});`;
266
+ }
267
+
268
+ /** The request as a `fetch` call. A JSON body is written as the data it is. */
269
+ export function openApiFetch(request: DuxtOpenApiRequest): string {
270
+ return `await ${jsCall('fetch', request, 'stringify')}`;
271
+ }
272
+
273
+ /** ofetch, which serialises an object body and sets the header itself. */
274
+ export function openApiOfetch(request: DuxtOpenApiRequest): string {
275
+ return `await ${jsCall('$fetch', request, 'object', true)}`;
276
+ }
277
+
278
+ /**
279
+ * `useFetch`, which is a component's data dependency rather than a call.
280
+ *
281
+ * Shown beside `$fetch` rather than instead of it: the two are not spellings of
282
+ * one thing. `$fetch` is what a reader pastes into an event handler; `useFetch`
283
+ * is what they paste into a component that needs the data to render, and it
284
+ * carries the destructuring that makes that the point.
285
+ */
286
+ export function openApiUseFetch(request: DuxtOpenApiRequest): string {
287
+ return `const { data } = await ${jsCall('useFetch', request, 'object', true)}`;
288
+ }
289
+
290
+ /** axios through its uniform form, so the shape does not change per method. */
291
+ export function openApiAxios(request: DuxtOpenApiRequest): string {
292
+ const options = [
293
+ ` method: '${request.method.toLowerCase()}'`,
294
+ ` url: '${request.url}'`
295
+ ];
296
+
297
+ if (hasHeaders(request)) options.push(` headers: ${js(request.headers)}`);
298
+
299
+ if (request.body) {
300
+ const data = asJson(request.body);
301
+ options.push(` data: ${data === undefined ? js(request.body) : js(data)}`);
302
+ }
303
+
304
+ const generic = request.responseType ? `<${request.responseType}>` : '';
305
+
306
+ return `await axios${generic}({\n${options.join(',\n')}\n});`;
307
+ }
308
+
309
+ /** The verb as `requests` and `httpx` spell it, or their generic form. */
310
+ const pyVerbs = new Set(['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'HEAD']);
311
+
312
+ function pyCall(module: string, request: DuxtOpenApiRequest): string {
313
+ const known = pyVerbs.has(request.method);
314
+ const call = known
315
+ ? `${module}.${request.method.toLowerCase()}(`
316
+ : `${module}.request(`;
317
+
318
+ const args = known
319
+ ? [` "${request.url}"`]
320
+ : [` "${request.method}"`, ` "${request.url}"`];
321
+
322
+ if (hasHeaders(request)) args.push(` headers=${py(request.headers)}`);
323
+
324
+ if (request.body) {
325
+ const data = asJson(request.body);
326
+ args.push(
327
+ data === undefined
328
+ ? ` data=${py(request.body)}`
329
+ : ` json=${py(data)}`
330
+ );
331
+ }
332
+
333
+ return `import ${module}\n\n${call}\n${args.join(',\n')},\n)`;
334
+ }
335
+
336
+ /** requests, which is what a Python reader reaches for first. */
337
+ export function openApiRequests(request: DuxtOpenApiRequest): string {
338
+ return pyCall('requests', request);
339
+ }
340
+
341
+ /** httpx, for a reader who wants the same shape with async available. */
342
+ export function openApiHttpx(request: DuxtOpenApiRequest): string {
343
+ return pyCall('httpx', request);
344
+ }
345
+
346
+ /** The standard library, for a snippet that must not add a dependency. */
347
+ export function openApiUrllib(request: DuxtOpenApiRequest): string {
348
+ const imports = request.body
349
+ ? 'import json\nimport urllib.request'
350
+ : 'import urllib.request';
351
+
352
+ const args = [` "${request.url}"`, ` method="${request.method}"`];
353
+
354
+ if (hasHeaders(request)) args.push(` headers=${py(request.headers)}`);
355
+
356
+ if (request.body) {
357
+ const data = asJson(request.body);
358
+ args.push(
359
+ data === undefined
360
+ ? ` data=${py(request.body)}.encode()`
361
+ : ` data=json.dumps(${py(data)}).encode()`
362
+ );
363
+ }
364
+
365
+ return [
366
+ imports,
367
+ '',
368
+ 'request = urllib.request.Request(',
369
+ args.join(',\n') + ',',
370
+ ')',
371
+ '',
372
+ 'urllib.request.urlopen(request)'
373
+ ].join('\n');
374
+ }
375
+
376
+ /**
377
+ * Go's standard library.
378
+ *
379
+ * The one sample that keeps its error branches. `err` is not ceremony in Go —
380
+ * `http.NewRequest` and `Do` both return one, and a snippet that ignores them
381
+ * does not compile, which is a worse thing to hand a reader than four extra
382
+ * lines.
383
+ */
384
+ export function openApiGo(request: DuxtOpenApiRequest): string {
385
+ const lines: string[] = [];
386
+
387
+ if (request.body) {
388
+ lines.push(
389
+ `body := strings.NewReader(\`${request.body.replaceAll('`', '` + "`" + `')}\`)`,
390
+ ''
391
+ );
392
+ }
393
+
394
+ lines.push(
395
+ `req, err := http.NewRequest("${request.method}", "${request.url}", ${request.body ? 'body' : 'nil'})`,
396
+ 'if err != nil {',
397
+ '\treturn err',
398
+ '}'
399
+ );
400
+
401
+ if (hasHeaders(request)) {
402
+ lines.push('');
403
+ for (const [name, value] of Object.entries(request.headers)) {
404
+ lines.push(`req.Header.Set("${name}", "${value}")`);
405
+ }
406
+ }
407
+
408
+ lines.push('', 'resp, err := http.DefaultClient.Do(req)');
409
+
410
+ return lines.join('\n');
411
+ }
412
+
413
+ /** Guzzle, the client a PHP project almost always already has. */
414
+ export function openApiGuzzle(request: DuxtOpenApiRequest): string {
415
+ const options: string[] = [];
416
+
417
+ if (hasHeaders(request)) {
418
+ options.push(` 'headers' => ${php(request.headers, 1)}`);
419
+ }
420
+
421
+ if (request.body) {
422
+ const data = asJson(request.body);
423
+ options.push(
424
+ data === undefined
425
+ ? ` 'body' => ${php(request.body)}`
426
+ : ` 'json' => ${php(data, 1)}`
427
+ );
428
+ }
429
+
430
+ const client = '$client = new \\GuzzleHttp\\Client();';
431
+ const call = options.length
432
+ ? `$client->request('${request.method}', '${request.url}', [\n${options.join(',\n')},\n]);`
433
+ : `$client->request('${request.method}', '${request.url}');`;
434
+
435
+ return `${client}\n\n${call}`;
436
+ }
437
+
438
+ /** Laravel's `Http` facade, which is Guzzle with the ceremony removed. */
439
+ export function openApiLaravelHttp(request: DuxtOpenApiRequest): string {
440
+ const verb = request.method.toLowerCase();
441
+ const data = request.body ? asJson(request.body) : undefined;
442
+
443
+ const head = hasHeaders(request)
444
+ ? `Http::withHeaders(${php(request.headers, 0)})\n ->`
445
+ : 'Http::';
446
+
447
+ const payload = request.body
448
+ ? `, ${data === undefined ? php(request.body) : php(data, 1)}`
449
+ : '';
450
+
451
+ return `${head}${verb}('${request.url}'${payload});`;
452
+ }
453
+
454
+ /** The curl extension, for a project with no HTTP client at all. */
455
+ export function openApiPhpCurl(request: DuxtOpenApiRequest): string {
456
+ const options = [` CURLOPT_CUSTOMREQUEST => '${request.method}'`];
457
+
458
+ if (hasHeaders(request)) {
459
+ const headers = Object.entries(request.headers).map(
460
+ ([name, value]) => `${name}: ${value}`
461
+ );
462
+ options.push(` CURLOPT_HTTPHEADER => ${php(headers, 1)}`);
463
+ }
464
+
465
+ if (request.body) {
466
+ options.push(` CURLOPT_POSTFIELDS => ${php(request.body)}`);
467
+ }
468
+
469
+ options.push(' CURLOPT_RETURNTRANSFER => true');
470
+
471
+ return [
472
+ `$ch = curl_init('${request.url}');`,
473
+ '',
474
+ 'curl_setopt_array($ch, [',
475
+ options.join(',\n') + ',',
476
+ ']);',
477
+ '',
478
+ 'curl_exec($ch);'
479
+ ].join('\n');
480
+ }
481
+
482
+ /**
483
+ * Every sample the layer ships, in the order they are offered when a site takes
484
+ * the default.
485
+ *
486
+ * `group` is the first level of the picker and `label` the second, so a language
487
+ * with three clients costs one control rather than three tabs — which is what
488
+ * makes an open registry survivable at all.
489
+ *
490
+ * The names are proper nouns and stay untranslated, which is why nothing here is
491
+ * an i18n key.
492
+ */
493
+ export const duxtRequestSamples: DuxtRequestSample[] = [
494
+ {
495
+ id: 'curl',
496
+ icon: 'simple-icons:curl',
497
+ group: 'curl',
498
+ label: 'curl',
499
+ language: 'bash',
500
+ generate: openApiCurl
501
+ },
502
+ {
503
+ id: 'fetch',
504
+ icon: 'vscode-icons:file-type-typescript',
505
+ group: 'TypeScript',
506
+ label: 'fetch',
507
+ language: 'typescript',
508
+ generate: openApiFetch
509
+ },
510
+ {
511
+ id: 'ofetch',
512
+ icon: 'vscode-icons:file-type-typescript',
513
+ group: 'TypeScript',
514
+ label: '$fetch',
515
+ language: 'typescript',
516
+ generate: openApiOfetch
517
+ },
518
+ {
519
+ id: 'use-fetch',
520
+ icon: 'vscode-icons:file-type-typescript',
521
+ group: 'TypeScript',
522
+ label: 'useFetch',
523
+ language: 'typescript',
524
+ generate: openApiUseFetch
525
+ },
526
+ {
527
+ id: 'axios',
528
+ icon: 'vscode-icons:file-type-typescript',
529
+ group: 'TypeScript',
530
+ label: 'axios',
531
+ language: 'typescript',
532
+ generate: openApiAxios
533
+ },
534
+ {
535
+ id: 'python-requests',
536
+ icon: 'vscode-icons:file-type-python',
537
+ group: 'Python',
538
+ label: 'requests',
539
+ language: 'python',
540
+ generate: openApiRequests
541
+ },
542
+ {
543
+ id: 'python-httpx',
544
+ icon: 'vscode-icons:file-type-python',
545
+ group: 'Python',
546
+ label: 'httpx',
547
+ language: 'python',
548
+ generate: openApiHttpx
549
+ },
550
+ {
551
+ id: 'python-urllib',
552
+ icon: 'vscode-icons:file-type-python',
553
+ group: 'Python',
554
+ label: 'urllib',
555
+ language: 'python',
556
+ generate: openApiUrllib
557
+ },
558
+ {
559
+ id: 'go',
560
+ icon: 'vscode-icons:file-type-go',
561
+ group: 'Go',
562
+ label: 'net/http',
563
+ language: 'go',
564
+ generate: openApiGo
565
+ },
566
+ {
567
+ id: 'php-guzzle',
568
+ icon: 'vscode-icons:file-type-php',
569
+ group: 'PHP',
570
+ label: 'Guzzle',
571
+ language: 'php',
572
+ generate: openApiGuzzle
573
+ },
574
+ {
575
+ id: 'php-laravel',
576
+ icon: 'vscode-icons:file-type-php',
577
+ group: 'PHP',
578
+ label: 'Laravel Http',
579
+ language: 'php',
580
+ generate: openApiLaravelHttp
581
+ },
582
+ {
583
+ id: 'php-curl',
584
+ icon: 'vscode-icons:file-type-php',
585
+ group: 'PHP',
586
+ label: 'curl extension',
587
+ language: 'php',
588
+ generate: openApiPhpCurl
589
+ }
590
+ ];
591
+
592
+ /**
593
+ * What a site shows without saying otherwise.
594
+ *
595
+ * Seven of the twelve. `useFetch`, `axios`, `httpx`, `urllib` and PHP's curl
596
+ * extension are shipped but off: they are the second client for a language that
597
+ * already has one on screen, and a picker is for choosing, not for listing
598
+ * everything that exists.
599
+ */
600
+ export const duxtDefaultRequestSamples = [
601
+ 'curl',
602
+ 'fetch',
603
+ 'ofetch',
604
+ 'python-requests',
605
+ 'go',
606
+ 'php-guzzle',
607
+ 'php-laravel'
608
+ ];
609
+
610
+ /**
611
+ * The samples a site offers, resolved from what it configured.
612
+ *
613
+ * ONE KEY DOES BOTH JOBS, because they are the same sentence. A string picks a
614
+ * shipped sample by id; an object adds one of the site's own, or replaces a
615
+ * shipped one by reusing its id. So a PHP API writes
616
+ * `['curl', 'php-guzzle', 'php-laravel']` and a site with a Ruby client writes
617
+ * its generator inline, in the one list that also fixes the order.
618
+ *
619
+ * Unset means the default seven. Arrays REPLACE rather than concatenate here,
620
+ * the same rule the rest of `duxtDefaults` follows: a configured list is the
621
+ * list, or a consumer could never drop `curl`.
622
+ */
623
+ export function resolveRequestSamples(
624
+ configured?: (string | DuxtRequestSample)[]
625
+ ): DuxtRequestSample[] {
626
+ const shipped = new Map(
627
+ duxtRequestSamples.map((sample) => [sample.id, sample])
628
+ );
629
+
630
+ const wanted = configured ?? duxtDefaultRequestSamples;
631
+
632
+ return wanted
633
+ .map((entry) => (typeof entry === 'string' ? shipped.get(entry) : entry))
634
+ .filter((sample): sample is DuxtRequestSample => sample !== undefined);
635
+ }