@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,450 @@
1
+ /**
2
+ * The `openapi` type: an API description, published as reference pages.
3
+ *
4
+ * The second type in the registry, and the first one that answers the questions
5
+ * the registry was built to ask. A changelog is one global history in the
6
+ * language it was written in; a reference is **per version** and **per locale**,
7
+ * and it needs a **layout** the docs chrome does not give it. Those three
8
+ * differences are policies on the type rather than branches in the scaffold,
9
+ * which is exactly what #9 claimed they would be — so this file adds a parser
10
+ * and three declarations, and nothing else.
11
+ *
12
+ * ONE PAGE PER OPERATION, plus an index per tag. Everything the layer can do
13
+ * hangs off pages: the search a reader actually performs is "find this
14
+ * endpoint", `llms.txt` lists pages, the MCP tools read pages, and a deep link
15
+ * to an endpoint has to survive being pasted into a ticket. A single-page
16
+ * reference with client-side routing has none of that.
17
+ *
18
+ * The pages are Markdown carrying MDC components, because that is what the
19
+ * scaffold's `getKeys`/`getItem` seam produces and what makes the result an
20
+ * ordinary collection. The prose — the operation's own description, a tag's,
21
+ * the document's — is written OUTSIDE the component, as the CommonMark the
22
+ * specification says it is, so Content parses it, the search indexes it and
23
+ * `llms-full.txt` carries it. Only what is structural — parameters, schemas,
24
+ * responses, the try-it client — travels as props.
25
+ */
26
+ import { stringify as stringifyYaml } from 'yaml';
27
+ import type {
28
+ DuxtOpenApiOperation,
29
+ DuxtOpenApiSecurity,
30
+ DuxtOpenApiServer,
31
+ DuxtOpenApiSpec,
32
+ DuxtOpenApiTag
33
+ } from './openapi-model';
34
+ import { compactOpenApi, parseOpenApiDocument } from './openapi-parse';
35
+ import type {
36
+ DuxtSectionContext,
37
+ DuxtSectionPage,
38
+ DuxtSectionType
39
+ } from './sections-resolve';
40
+
41
+ /**
42
+ * The layout name this type binds — PUBLIC SURFACE, so renaming it is a
43
+ * `feat!:`. It is the first name to go through the shared slot, which is what
44
+ * makes it the first real test of it.
45
+ */
46
+ export const DUXT_OPENAPI_LAYOUT = 'reference';
47
+
48
+ export const openapiSectionType: DuxtSectionType = {
49
+ parse: parseOpenApiSection,
50
+ /**
51
+ * PER VERSION, like any other page.
52
+ *
53
+ * An API description belongs to the release it describes: `v1` and `v2` have
54
+ * different endpoints, and a reader on `v1` asking what a field means must
55
+ * not be shown `v2`'s answer. Each version collection therefore carries the
56
+ * spec file at its own ref, and the version switcher works on the reference
57
+ * exactly as it works on the prose. This is the opposite answer to the
58
+ * changelog's, and the reason `versioning` is a policy rather than a rule.
59
+ */
60
+ versioning: 'per-version',
61
+ /**
62
+ * PER LOCALE, where a locale ships a spec of its own.
63
+ *
64
+ * A description is written prose as much as it is structure — summaries,
65
+ * descriptions, response meanings — so a translated one is a real artefact
66
+ * rather than the same file relabelled. A locale that declares none builds no
67
+ * collection, and the existing fallback chain then serves the original with
68
+ * `DuxtTranslationBanner` saying so. What stays translatable either way are
69
+ * the LAYER'S OWN labels — the table headers, "Request", "Response", the
70
+ * status names — because those belong to the theme and not to the document.
71
+ */
72
+ localisation: 'per-locale',
73
+ layout: DUXT_OPENAPI_LAYOUT,
74
+ icon: 'lucide:plug'
75
+ };
76
+
77
+ function parseOpenApiSection(
78
+ artefact: string,
79
+ context: DuxtSectionContext
80
+ ): DuxtSectionPage[] {
81
+ let spec: DuxtOpenApiSpec;
82
+
83
+ try {
84
+ spec = parseOpenApiDocument(artefact);
85
+ } catch (error) {
86
+ // Rethrown rather than swallowed into an empty section: the scaffold turns
87
+ // "no pages" into the right severity for local and remote alike, but a
88
+ // message saying WHY reads better than one saying the file held nothing.
89
+ throw new Error(
90
+ `duxt: the generated section "${context.label}" could not read its ` +
91
+ `OpenAPI document — ${(error as Error).message}`
92
+ );
93
+ }
94
+
95
+ // Into the report rather than onto the console: a document is parsed while
96
+ // the config is loading, so a printed warning about a dropped `$ref` has
97
+ // scrolled away before the dev server has finished starting — and what it
98
+ // reports is content silently missing from the reference. See
99
+ // `DuxtSectionContext.warn`.
100
+ for (const warning of spec.warnings) context.warn?.(warning);
101
+
102
+ if (!spec.tags?.length) return [];
103
+
104
+ const groups = spec.tags.map((tag, index) => ({
105
+ tag,
106
+ slug: segment(tag.name),
107
+ order: order(index, spec.tags!.length)
108
+ }));
109
+
110
+ // A tag whose name slugifies to the same segment as another's would serve
111
+ // two groups from one URL, and the later one would win silently.
112
+ const seen = new Set<string>();
113
+ for (const group of groups) {
114
+ let candidate = group.slug || 'group';
115
+ let attempt = 2;
116
+ while (seen.has(candidate)) candidate = `${group.slug}-${attempt++}`;
117
+ seen.add(candidate);
118
+ group.slug = candidate;
119
+ }
120
+
121
+ return [
122
+ overview(spec, groups, context),
123
+ ...groups.flatMap((group) => pagesFor(spec, group, context))
124
+ ];
125
+ }
126
+
127
+ interface Group {
128
+ tag: DuxtOpenApiTag;
129
+ slug: string;
130
+ order: string;
131
+ }
132
+
133
+ /** The section's own page: what the API is, where it is, how to authenticate. */
134
+ function overview(
135
+ spec: DuxtOpenApiSpec,
136
+ groups: Group[],
137
+ context: DuxtSectionContext
138
+ ): DuxtSectionPage {
139
+ const props = {
140
+ version: spec.info.version,
141
+ // NO `summary`: it is this page's `description` below, and the shell draws
142
+ // a description under the title. Handed to the component as well, it was
143
+ // printed a second time under the rule where the body starts.
144
+ servers: spec.servers,
145
+ securitySchemes: spec.securitySchemes,
146
+ security: spec.security,
147
+ contact: spec.info.contact,
148
+ license: spec.info.license,
149
+ termsOfService: spec.info.termsOfService,
150
+ externalDocs: spec.externalDocs,
151
+ groups: groups.map((group) => ({
152
+ name: group.tag.name,
153
+ // One line, and plain: a card is not prose, and a tag description that
154
+ // renders as Markdown on its own page would otherwise show its asterisks
155
+ // here.
156
+ description: firstLine(group.tag.description),
157
+ webhooks: group.tag.webhooks ?? false,
158
+ operations: group.tag.operations?.length ?? 0,
159
+ to: `${context.prefix}/${group.slug}`
160
+ }))
161
+ };
162
+
163
+ return {
164
+ file: 'index.md',
165
+ body: page(
166
+ { title: spec.info.title, description: overviewDescription(spec) },
167
+ // NO `<h1>` OF ITS OWN. The shell draws the docs header — breadcrumb,
168
+ // title, the copy control beside it — for every generated page whose body
169
+ // opens on no heading, and these pages want exactly that: a reference
170
+ // page has a title and a trail like any written one, and the method chip
171
+ // that made this type look different is drawn below the heading anyway.
172
+ [component('open-api-overview', props, spec.info.description)]
173
+ )
174
+ };
175
+ }
176
+
177
+ function overviewDescription(spec: DuxtOpenApiSpec): string {
178
+ return (
179
+ spec.info.summary ??
180
+ firstLine(spec.info.description) ??
181
+ // `version` is optional once the model has been compacted, and a template
182
+ // literal writes an absent one out as the word `undefined`.
183
+ [spec.info.title, spec.info.version].filter(Boolean).join(' ')
184
+ );
185
+ }
186
+
187
+ /** A tag's index page, and one page per operation under it. */
188
+ function pagesFor(
189
+ spec: DuxtOpenApiSpec,
190
+ group: Group,
191
+ context: DuxtSectionContext
192
+ ): DuxtSectionPage[] {
193
+ const operations = group.tag.operations ?? [];
194
+ const slugs = operationSlugs(operations);
195
+ const width = operations.length;
196
+
197
+ const links = operations.map((operation, index) => ({
198
+ method: operation.method,
199
+ path: operation.path,
200
+ kind: operation.kind,
201
+ summary: operation.summary,
202
+ deprecated: operation.deprecated,
203
+ to: `${context.prefix}/${group.slug}/${slugs[index]}`
204
+ }));
205
+
206
+ const index: DuxtSectionPage = {
207
+ file: `${group.order}.${group.slug}/index.md`,
208
+ body: page(
209
+ // No invented description where the tag has none: a count in the
210
+ // layer's own English would be untranslatable text the layer does not
211
+ // own, which `tests/i18n-ownership.test.ts` exists to keep out.
212
+ { title: group.tag.name, description: firstLine(group.tag.description) },
213
+ [
214
+ component(
215
+ 'open-api-operations',
216
+ { operations: links, externalDocs: group.tag.externalDocs },
217
+ group.tag.description
218
+ )
219
+ ]
220
+ )
221
+ };
222
+
223
+ return [
224
+ index,
225
+ ...operations.map((operation, position) =>
226
+ operationPage(
227
+ spec,
228
+ group,
229
+ operation,
230
+ slugs[position]!,
231
+ order(position, width)
232
+ )
233
+ )
234
+ ];
235
+ }
236
+
237
+ function operationPage(
238
+ spec: DuxtOpenApiSpec,
239
+ group: Group,
240
+ operation: DuxtOpenApiOperation,
241
+ slug: string,
242
+ position: string
243
+ ): DuxtSectionPage {
244
+ const title =
245
+ operation.summary?.trim() ||
246
+ `${operation.method.toUpperCase()} ${operation.path}`;
247
+
248
+ // The description travels in the SLOT rather than in the props, so what the
249
+ // document wrote as CommonMark is rendered as CommonMark. `servers` and
250
+ // `security` leave with it: both are RESOLVED against the document below, and
251
+ // an unresolved copy beside the resolved one is two answers to one question.
252
+ // The underscores are what marks them deliberately dropped rather than
253
+ // forgotten — `no-unused-vars` reads the prefix, and this repository denies
254
+ // warnings.
255
+ const {
256
+ description,
257
+ servers: _servers,
258
+ security: _security,
259
+ ...rest
260
+ } = operation;
261
+
262
+ const props = {
263
+ operation: rest,
264
+ servers: serversFor(spec, operation),
265
+ security: securityFor(spec, operation),
266
+ securitySchemes: spec.securitySchemes
267
+ };
268
+
269
+ return {
270
+ file: `${group.order}.${group.slug}/${position}.${slug}.md`,
271
+ body: page(
272
+ {
273
+ title,
274
+ description:
275
+ firstLine(description) ??
276
+ `${operation.method.toUpperCase()} ${operation.path}`
277
+ },
278
+ [component('open-api-operation', props, description)]
279
+ )
280
+ };
281
+ }
282
+
283
+ /**
284
+ * The servers this operation is reachable at.
285
+ *
286
+ * An operation's own list REPLACES the document's rather than adding to it,
287
+ * which is what the specification says and what the try-it client has to obey:
288
+ * offering a server the endpoint is not served from is a request that fails for
289
+ * a reason nothing on the page explains.
290
+ */
291
+ function serversFor(
292
+ spec: DuxtOpenApiSpec,
293
+ operation: DuxtOpenApiOperation
294
+ ): DuxtOpenApiServer[] {
295
+ return operation.servers?.length ? operation.servers : (spec.servers ?? []);
296
+ }
297
+
298
+ /**
299
+ * The security this operation demands.
300
+ *
301
+ * An operation's own `security` replaces the document's, and an EMPTY LIST is a
302
+ * statement rather than an absence: it is how an endpoint opts out of a global
303
+ * requirement, which is why this cannot be a `||`.
304
+ */
305
+ function securityFor(
306
+ spec: DuxtOpenApiSpec,
307
+ operation: DuxtOpenApiOperation
308
+ ): DuxtOpenApiSecurity | undefined {
309
+ return operation.security ?? spec.security;
310
+ }
311
+
312
+ /**
313
+ * A URL segment per operation, unique inside its tag.
314
+ *
315
+ * `operationId` first, because it is the name the document itself gives the
316
+ * endpoint and the one an SDK generator uses — a reader following a link from
317
+ * generated code lands on the right page. Without one the method and path are
318
+ * the only stable identity there is.
319
+ */
320
+ function operationSlugs(operations: DuxtOpenApiOperation[]): string[] {
321
+ const taken = new Set<string>();
322
+
323
+ return operations.map((operation) => {
324
+ const base =
325
+ segment(operation.operationId ?? '') ||
326
+ segment(`${operation.method}-${operation.path}`) ||
327
+ operation.method;
328
+
329
+ let candidate = base;
330
+ let attempt = 2;
331
+ while (taken.has(candidate)) candidate = `${base}-${attempt++}`;
332
+ taken.add(candidate);
333
+
334
+ return candidate;
335
+ });
336
+ }
337
+
338
+ /**
339
+ * A URL segment: lowercase, no dots.
340
+ *
341
+ * The dots matter. Content reads a name made of digits and dots as a version
342
+ * and stops refining it, which would leave the `NN.` ordering prefix in the
343
+ * URL — the same trap `sections-changelog.ts` answers with a leading `v`. An
344
+ * endpoint at `/v1.0/pets` walks straight into it, so the dot goes.
345
+ */
346
+ function segment(value: string): string {
347
+ return value
348
+ .toLowerCase()
349
+ .replace(/[^a-z0-9]+/g, '-')
350
+ .replace(/^-+|-+$/g, '');
351
+ }
352
+
353
+ /** Zero-padded so ten pages still sort the way they read. */
354
+ function order(index: number, total: number): string {
355
+ return String(index + 1).padStart(String(total).length, '0');
356
+ }
357
+
358
+ /**
359
+ * The first paragraph of a description, as one line of PLAIN text.
360
+ *
361
+ * Plain matters because of where this goes: a page's `description`
362
+ * frontmatter, which becomes the meta description, the og tag and the card in
363
+ * a search result, and the summary on a group card. A CommonMark description
364
+ * carrying `*emphasis*` or a `[link](url)` renders as prose everywhere it is
365
+ * rendered as prose — and as its own punctuation everywhere it is not.
366
+ *
367
+ * Deliberately small. It undoes the four inline constructs a one-line summary
368
+ * actually meets — emphasis, code spans, links and images — and leaves
369
+ * everything else alone rather than growing into a second Markdown parser
370
+ * whose disagreements with the first would be invisible.
371
+ */
372
+ function firstLine(value?: string): string | undefined {
373
+ const line = plain(value?.split(/\n\s*\n/)[0] ?? '')
374
+ .replace(/\s+/g, ' ')
375
+ .trim();
376
+
377
+ return line || undefined;
378
+ }
379
+
380
+ /** Inline Markdown, as the text it renders to. */
381
+ function plain(value: string): string {
382
+ return (
383
+ value
384
+ // An image before a link: `![alt](src)` is a link with a `!` in front, and
385
+ // taking the link first would leave the `!` behind.
386
+ .replaceAll(/!\[([^\]]*)\]\([^)]*\)/g, '$1')
387
+ .replaceAll(/\[([^\]]*)\]\([^)]*\)/g, '$1')
388
+ .replaceAll(/`([^`]*)`/g, '$1')
389
+ .replaceAll(/(\*\*|__)(.+?)\1/g, '$2')
390
+ .replaceAll(/(\*|_)(.+?)\1/g, '$2')
391
+ );
392
+ }
393
+
394
+ /**
395
+ * An MDC block component with YAML props and Markdown inside it.
396
+ *
397
+ * The fence LENGTH is computed rather than fixed: a description containing a
398
+ * line of colons would otherwise close the component early and spill its props
399
+ * into the page. Three is the floor — enough that `::callout` inside a
400
+ * description is content rather than a closing fence.
401
+ */
402
+ function component(
403
+ name: string,
404
+ props: Record<string, unknown>,
405
+ slot?: string
406
+ ): string {
407
+ const body = slot?.trim() ?? '';
408
+
409
+ const longest = Math.max(
410
+ 2,
411
+ ...body.split('\n').map((line) => /^\s*(:+)/.exec(line)?.[1]?.length ?? 0)
412
+ );
413
+
414
+ const fence = ':'.repeat(Math.max(3, longest + 1));
415
+
416
+ return [
417
+ `${fence}${name}`,
418
+ '---',
419
+ stringifyYaml(compactOpenApi(props)).trimEnd(),
420
+ '---',
421
+ ...(body ? [body] : []),
422
+ fence
423
+ ].join('\n');
424
+ }
425
+
426
+ /** A page: frontmatter, then the lines. */
427
+ function page(
428
+ fields: Record<string, string | undefined>,
429
+ lines: string[]
430
+ ): string {
431
+ return [frontmatter(fields), '', ...lines, ''].join('\n');
432
+ }
433
+
434
+ /**
435
+ * A frontmatter block YAML can read back.
436
+ *
437
+ * Every value is a JSON string, which is also a YAML double-quoted scalar — so
438
+ * a summary carrying a colon cannot end the mapping early. The rule
439
+ * `tests/frontmatter-yaml.test.ts` exists over, and a title like
440
+ * `GET /pets/{petId}: not found` is exactly the shape that breaks it.
441
+ */
442
+ function frontmatter(fields: Record<string, string | undefined>): string {
443
+ return [
444
+ '---',
445
+ ...Object.entries(fields)
446
+ .filter(([, value]) => value !== undefined && value !== '')
447
+ .map(([key, value]) => `${key}: ${JSON.stringify(value)}`),
448
+ '---'
449
+ ].join('\n');
450
+ }