@lupinum/ginko-content 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 (512) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +90 -0
  3. package/compatibility.json +27 -0
  4. package/dist/cli.d.mts +1 -0
  5. package/dist/cli.mjs +690 -0
  6. package/dist/cms-contract/build +1 -0
  7. package/dist/cms-contract/build.d.ts +44 -0
  8. package/dist/cms-contract/build.js +513 -0
  9. package/dist/cms-contract/index +1 -0
  10. package/dist/cms-contract/index.d.ts +25 -0
  11. package/dist/cms-contract/index.js +37 -0
  12. package/dist/cms-contract/mdc +1 -0
  13. package/dist/cms-contract/mdc.d.ts +32 -0
  14. package/dist/cms-contract/mdc.js +52 -0
  15. package/dist/cms-contract/path +1 -0
  16. package/dist/cms-contract/path.d.ts +12 -0
  17. package/dist/cms-contract/path.js +18 -0
  18. package/dist/cms-contract/schema +1 -0
  19. package/dist/cms-contract/schema.d.ts +18 -0
  20. package/dist/cms-contract/schema.js +13 -0
  21. package/dist/cms-contract/types +1 -0
  22. package/dist/cms-contract/types.d.ts +177 -0
  23. package/dist/cms-contract/types.js +0 -0
  24. package/dist/cms-import/index +1 -0
  25. package/dist/cms-import/index.d.ts +21 -0
  26. package/dist/cms-import/index.js +57 -0
  27. package/dist/config.d.mts +3 -0
  28. package/dist/config.mjs +3 -0
  29. package/dist/core/cache +1 -0
  30. package/dist/core/cache-hints +1 -0
  31. package/dist/core/cache-hints.d.ts +3 -0
  32. package/dist/core/cache-hints.js +55 -0
  33. package/dist/core/cache.d.ts +29 -0
  34. package/dist/core/cache.js +0 -0
  35. package/dist/core/content/collection +1 -0
  36. package/dist/core/content/collection.d.ts +3 -0
  37. package/dist/core/content/collection.js +52 -0
  38. package/dist/core/content/graph +1 -0
  39. package/dist/core/content/graph.d.ts +147 -0
  40. package/dist/core/content/graph.js +189 -0
  41. package/dist/core/content/ignore +1 -0
  42. package/dist/core/content/ignore.d.ts +5 -0
  43. package/dist/core/content/ignore.js +10 -0
  44. package/dist/core/content/locale +1 -0
  45. package/dist/core/content/locale.d.ts +61 -0
  46. package/dist/core/content/locale.js +77 -0
  47. package/dist/core/content/path +1 -0
  48. package/dist/core/content/path.d.ts +36 -0
  49. package/dist/core/content/path.js +143 -0
  50. package/dist/core/content/slug +1 -0
  51. package/dist/core/content/slug.d.ts +4 -0
  52. package/dist/core/content/slug.js +41 -0
  53. package/dist/core/content/sources +1 -0
  54. package/dist/core/content/sources.d.ts +2 -0
  55. package/dist/core/content/sources.js +6 -0
  56. package/dist/core/errors +1 -0
  57. package/dist/core/errors.d.ts +15 -0
  58. package/dist/core/errors.js +10 -0
  59. package/dist/core/markdown/tree +1 -0
  60. package/dist/core/markdown/tree.d.ts +9 -0
  61. package/dist/core/markdown/tree.js +47 -0
  62. package/dist/core/query/builder +1 -0
  63. package/dist/core/query/builder.d.ts +18 -0
  64. package/dist/core/query/builder.js +186 -0
  65. package/dist/core/query/execute +1 -0
  66. package/dist/core/query/execute.d.ts +52 -0
  67. package/dist/core/query/execute.js +304 -0
  68. package/dist/core/query/filter +1 -0
  69. package/dist/core/query/filter.d.ts +42 -0
  70. package/dist/core/query/filter.js +118 -0
  71. package/dist/core/query/json +1 -0
  72. package/dist/core/query/json.d.ts +2 -0
  73. package/dist/core/query/json.js +20 -0
  74. package/dist/core/query/lower +1 -0
  75. package/dist/core/query/lower.d.ts +14 -0
  76. package/dist/core/query/lower.js +121 -0
  77. package/dist/core/query/operators +1 -0
  78. package/dist/core/query/operators.d.ts +23 -0
  79. package/dist/core/query/operators.js +126 -0
  80. package/dist/core/query/params +1 -0
  81. package/dist/core/query/params.d.ts +15 -0
  82. package/dist/core/query/params.js +83 -0
  83. package/dist/core/query/plan +1 -0
  84. package/dist/core/query/plan.d.ts +110 -0
  85. package/dist/core/query/plan.js +0 -0
  86. package/dist/core/references/resolve +1 -0
  87. package/dist/core/references/resolve.d.ts +31 -0
  88. package/dist/core/references/resolve.js +121 -0
  89. package/dist/core/references/schema +1 -0
  90. package/dist/core/references/schema.d.ts +8 -0
  91. package/dist/core/references/schema.js +70 -0
  92. package/dist/core/result +1 -0
  93. package/dist/core/result.d.ts +27 -0
  94. package/dist/core/result.js +2 -0
  95. package/dist/features/collections/resolve +1 -0
  96. package/dist/features/collections/resolve.d.ts +63 -0
  97. package/dist/features/collections/resolve.js +76 -0
  98. package/dist/features/localization/config +1 -0
  99. package/dist/features/localization/config.d.ts +18 -0
  100. package/dist/features/localization/config.js +25 -0
  101. package/dist/features/localization/links +1 -0
  102. package/dist/features/localization/links.d.ts +1 -0
  103. package/dist/features/localization/links.js +69 -0
  104. package/dist/features/localization/path +1 -0
  105. package/dist/features/localization/path.d.ts +32 -0
  106. package/dist/features/localization/path.js +80 -0
  107. package/dist/features/localization/results +1 -0
  108. package/dist/features/localization/results.d.ts +42 -0
  109. package/dist/features/localization/results.js +149 -0
  110. package/dist/features/localization/translated-slugs +1 -0
  111. package/dist/features/localization/translated-slugs.d.ts +11 -0
  112. package/dist/features/localization/translated-slugs.js +80 -0
  113. package/dist/features/navigation/build +1 -0
  114. package/dist/features/navigation/build.d.ts +28 -0
  115. package/dist/features/navigation/build.js +104 -0
  116. package/dist/features/navigation/canonical +1 -0
  117. package/dist/features/navigation/canonical.d.ts +33 -0
  118. package/dist/features/navigation/canonical.js +149 -0
  119. package/dist/features/navigation/query +1 -0
  120. package/dist/features/navigation/query.d.ts +19 -0
  121. package/dist/features/navigation/query.js +51 -0
  122. package/dist/features/navigation/resolve +1 -0
  123. package/dist/features/navigation/resolve.d.ts +20 -0
  124. package/dist/features/navigation/resolve.js +79 -0
  125. package/dist/features/navigation/tree +1 -0
  126. package/dist/features/navigation/tree.d.ts +6 -0
  127. package/dist/features/navigation/tree.js +32 -0
  128. package/dist/features/search/navigation +1 -0
  129. package/dist/features/search/navigation.d.ts +6 -0
  130. package/dist/features/search/navigation.js +21 -0
  131. package/dist/features/search/sections +1 -0
  132. package/dist/features/search/sections.d.ts +21 -0
  133. package/dist/features/search/sections.js +98 -0
  134. package/dist/features/sitemap/query +1 -0
  135. package/dist/features/sitemap/query.d.ts +68 -0
  136. package/dist/features/sitemap/query.js +171 -0
  137. package/dist/integrations/nitro/context +1 -0
  138. package/dist/integrations/nitro/context.d.ts +63 -0
  139. package/dist/integrations/nitro/context.js +28 -0
  140. package/dist/integrations/nitro/ingest +1 -0
  141. package/dist/integrations/nitro/ingest.d.ts +18 -0
  142. package/dist/integrations/nitro/ingest.js +120 -0
  143. package/dist/integrations/nitro/preview +1 -0
  144. package/dist/integrations/nitro/preview.d.ts +5 -0
  145. package/dist/integrations/nitro/preview.js +21 -0
  146. package/dist/integrations/nitro/runtime-config +1 -0
  147. package/dist/integrations/nitro/runtime-config.d.ts +1 -0
  148. package/dist/integrations/nitro/runtime-config.js +4 -0
  149. package/dist/integrations/nitro/storage +1 -0
  150. package/dist/integrations/nitro/storage.d.ts +9 -0
  151. package/dist/integrations/nitro/storage.js +113 -0
  152. package/dist/integrations/vue/content-components +1 -0
  153. package/dist/integrations/vue/content-components.d.ts +24 -0
  154. package/dist/integrations/vue/content-components.js +67 -0
  155. package/dist/integrations/vue/html-tags +1 -0
  156. package/dist/integrations/vue/html-tags.d.ts +2 -0
  157. package/dist/integrations/vue/html-tags.js +119 -0
  158. package/dist/integrations/vue/markdown-refs +1 -0
  159. package/dist/integrations/vue/markdown-refs.d.ts +1 -0
  160. package/dist/integrations/vue/markdown-refs.js +1 -0
  161. package/dist/module.d.mts +2044 -0
  162. package/dist/module.json +12 -0
  163. package/dist/module.mjs +1381 -0
  164. package/dist/parsers/csv +1 -0
  165. package/dist/parsers/csv.d.ts +2 -0
  166. package/dist/parsers/csv.js +38 -0
  167. package/dist/parsers/from-csv +1 -0
  168. package/dist/parsers/from-csv.d.ts +20 -0
  169. package/dist/parsers/from-csv.js +85 -0
  170. package/dist/parsers/index +1 -0
  171. package/dist/parsers/index.d.ts +10 -0
  172. package/dist/parsers/index.js +50 -0
  173. package/dist/parsers/json +1 -0
  174. package/dist/parsers/json.d.ts +2 -0
  175. package/dist/parsers/json.js +29 -0
  176. package/dist/parsers/markdown +1 -0
  177. package/dist/parsers/markdown-plugins +1 -0
  178. package/dist/parsers/markdown-plugins.d.ts +3 -0
  179. package/dist/parsers/markdown-plugins.js +58 -0
  180. package/dist/parsers/markdown.d.ts +2 -0
  181. package/dist/parsers/markdown.js +64 -0
  182. package/dist/parsers/path-meta +1 -0
  183. package/dist/parsers/path-meta.d.ts +4 -0
  184. package/dist/parsers/path-meta.js +37 -0
  185. package/dist/parsers/utils +1 -0
  186. package/dist/parsers/utils.d.ts +2 -0
  187. package/dist/parsers/utils.js +3 -0
  188. package/dist/parsers/yaml +1 -0
  189. package/dist/parsers/yaml.d.ts +2 -0
  190. package/dist/parsers/yaml.js +19 -0
  191. package/dist/public/client +1 -0
  192. package/dist/public/client.d.ts +19 -0
  193. package/dist/public/client.js +26 -0
  194. package/dist/public/provider +1 -0
  195. package/dist/public/provider-errors +1 -0
  196. package/dist/public/provider-errors.d.ts +4 -0
  197. package/dist/public/provider-errors.js +28 -0
  198. package/dist/public/provider.d.ts +74 -0
  199. package/dist/public/provider.js +6 -0
  200. package/dist/public/server +1 -0
  201. package/dist/public/server.d.ts +19 -0
  202. package/dist/public/server.js +28 -0
  203. package/dist/runtime/app/components/ContentRenderer.d.vue.ts +62 -0
  204. package/dist/runtime/app/components/ContentRenderer.vue +84 -0
  205. package/dist/runtime/app/components/ContentRenderer.vue.d.ts +62 -0
  206. package/dist/runtime/app/components/ContentRendererInline.d.vue.ts +50 -0
  207. package/dist/runtime/app/components/ContentRendererInline.vue +97 -0
  208. package/dist/runtime/app/components/ContentRendererInline.vue.d.ts +50 -0
  209. package/dist/runtime/app/components/Prose/ProseCode.d.vue.ts +61 -0
  210. package/dist/runtime/app/components/Prose/ProseCode.vue +32 -0
  211. package/dist/runtime/app/components/Prose/ProseCode.vue.d.ts +61 -0
  212. package/dist/runtime/app/components/Prose/ProseCodeInline.d.vue.ts +13 -0
  213. package/dist/runtime/app/components/Prose/ProseCodeInline.vue +3 -0
  214. package/dist/runtime/app/components/Prose/ProseCodeInline.vue.d.ts +13 -0
  215. package/dist/runtime/app/components/Prose/ProseImg.d.vue.ts +59 -0
  216. package/dist/runtime/app/components/Prose/ProseImg.vue +59 -0
  217. package/dist/runtime/app/components/Prose/ProseImg.vue.d.ts +59 -0
  218. package/dist/runtime/app/components/Prose/ProsePre.d.vue.ts +79 -0
  219. package/dist/runtime/app/components/Prose/ProsePre.vue +42 -0
  220. package/dist/runtime/app/components/Prose/ProsePre.vue.d.ts +79 -0
  221. package/dist/runtime/app/components/internal/ContentRendererMarkdown.d.vue.ts +68 -0
  222. package/dist/runtime/app/components/internal/ContentRendererMarkdown.vue +99 -0
  223. package/dist/runtime/app/components/internal/ContentRendererMarkdown.vue.d.ts +68 -0
  224. package/dist/runtime/app/components/internal/MarkdownRenderer +1 -0
  225. package/dist/runtime/app/components/internal/MarkdownRenderer.d.ts +90 -0
  226. package/dist/runtime/app/components/internal/MarkdownRenderer.js +191 -0
  227. package/dist/runtime/app/composables/async-data +1 -0
  228. package/dist/runtime/app/composables/async-data.d.ts +2 -0
  229. package/dist/runtime/app/composables/async-data.js +4 -0
  230. package/dist/runtime/app/composables/content-i18n +1 -0
  231. package/dist/runtime/app/composables/content-i18n.d.ts +5 -0
  232. package/dist/runtime/app/composables/content-i18n.js +1 -0
  233. package/dist/runtime/app/composables/head +1 -0
  234. package/dist/runtime/app/composables/head.d.ts +11 -0
  235. package/dist/runtime/app/composables/head.js +98 -0
  236. package/dist/runtime/app/composables/locale +1 -0
  237. package/dist/runtime/app/composables/locale-context +1 -0
  238. package/dist/runtime/app/composables/locale-context.d.ts +5 -0
  239. package/dist/runtime/app/composables/locale-context.js +8 -0
  240. package/dist/runtime/app/composables/locale.d.ts +8 -0
  241. package/dist/runtime/app/composables/locale.js +15 -0
  242. package/dist/runtime/app/composables/navigation +1 -0
  243. package/dist/runtime/app/composables/navigation.d.ts +3 -0
  244. package/dist/runtime/app/composables/navigation.js +7 -0
  245. package/dist/runtime/app/composables/preview +1 -0
  246. package/dist/runtime/app/composables/preview.d.ts +5 -0
  247. package/dist/runtime/app/composables/preview.js +52 -0
  248. package/dist/runtime/app/composables/query-api +1 -0
  249. package/dist/runtime/app/composables/query-api.d.ts +27 -0
  250. package/dist/runtime/app/composables/query-api.js +46 -0
  251. package/dist/runtime/app/composables/route +1 -0
  252. package/dist/runtime/app/composables/route.d.ts +11 -0
  253. package/dist/runtime/app/composables/route.js +150 -0
  254. package/dist/runtime/app/composables/runtime +1 -0
  255. package/dist/runtime/app/composables/runtime.d.ts +2 -0
  256. package/dist/runtime/app/composables/runtime.js +7 -0
  257. package/dist/runtime/app/composables/search +1 -0
  258. package/dist/runtime/app/composables/search.d.ts +58 -0
  259. package/dist/runtime/app/composables/search.js +321 -0
  260. package/dist/runtime/app/composables/site-data +1 -0
  261. package/dist/runtime/app/composables/site-data.d.ts +12 -0
  262. package/dist/runtime/app/composables/site-data.js +12 -0
  263. package/dist/runtime/app/composables/toc +1 -0
  264. package/dist/runtime/app/composables/toc.d.ts +10 -0
  265. package/dist/runtime/app/composables/toc.js +31 -0
  266. package/dist/runtime/app/composables/use-content +1 -0
  267. package/dist/runtime/app/composables/use-content.d.ts +188 -0
  268. package/dist/runtime/app/composables/use-content.js +307 -0
  269. package/dist/runtime/app/composables/useUnwrap +1 -0
  270. package/dist/runtime/app/composables/useUnwrap.d.ts +8 -0
  271. package/dist/runtime/app/composables/useUnwrap.js +35 -0
  272. package/dist/runtime/app/composables/utils +1 -0
  273. package/dist/runtime/app/composables/utils.d.ts +22 -0
  274. package/dist/runtime/app/composables/utils.js +76 -0
  275. package/dist/runtime/app/composables/web-socket +1 -0
  276. package/dist/runtime/app/composables/web-socket.d.ts +3 -0
  277. package/dist/runtime/app/composables/web-socket.js +65 -0
  278. package/dist/runtime/app/pages/content.d.vue.ts +3 -0
  279. package/dist/runtime/app/pages/content.vue +14 -0
  280. package/dist/runtime/app/pages/content.vue.d.ts +3 -0
  281. package/dist/runtime/app/plugins/markdown-components +1 -0
  282. package/dist/runtime/app/plugins/markdown-components.d.ts +2 -0
  283. package/dist/runtime/app/plugins/markdown-components.js +19 -0
  284. package/dist/runtime/app/plugins/ws +1 -0
  285. package/dist/runtime/app/plugins/ws.d.ts +2 -0
  286. package/dist/runtime/app/plugins/ws.js +7 -0
  287. package/dist/runtime/app.d.vue.ts +3 -0
  288. package/dist/runtime/app.vue +3 -0
  289. package/dist/runtime/app.vue.d.ts +3 -0
  290. package/dist/runtime/markdown/plugins +1 -0
  291. package/dist/runtime/markdown/plugins.d.ts +3 -0
  292. package/dist/runtime/markdown/plugins.js +39 -0
  293. package/dist/runtime/query/public-limits +1 -0
  294. package/dist/runtime/query/public-limits.d.ts +2 -0
  295. package/dist/runtime/query/public-limits.js +2 -0
  296. package/dist/runtime/query/resolve +1 -0
  297. package/dist/runtime/query/resolve.d.ts +5 -0
  298. package/dist/runtime/query/resolve.js +9 -0
  299. package/dist/runtime/query/routes +1 -0
  300. package/dist/runtime/query/routes.d.ts +33 -0
  301. package/dist/runtime/query/routes.js +21 -0
  302. package/dist/runtime/query/unified +1 -0
  303. package/dist/runtime/query/unified.d.ts +94 -0
  304. package/dist/runtime/query/unified.js +473 -0
  305. package/dist/runtime/server/api/cache +1 -0
  306. package/dist/runtime/server/api/cache.d.ts +8 -0
  307. package/dist/runtime/server/api/cache.js +26 -0
  308. package/dist/runtime/server/api/locales +1 -0
  309. package/dist/runtime/server/api/locales.d.ts +6 -0
  310. package/dist/runtime/server/api/locales.js +28 -0
  311. package/dist/runtime/server/api/navigation +1 -0
  312. package/dist/runtime/server/api/navigation.d.ts +2 -0
  313. package/dist/runtime/server/api/navigation.js +21 -0
  314. package/dist/runtime/server/api/query +1 -0
  315. package/dist/runtime/server/api/query.d.ts +2 -0
  316. package/dist/runtime/server/api/query.js +6 -0
  317. package/dist/runtime/server/api/revalidate +1 -0
  318. package/dist/runtime/server/api/revalidate.d.ts +6 -0
  319. package/dist/runtime/server/api/revalidate.js +156 -0
  320. package/dist/runtime/server/api/search +1 -0
  321. package/dist/runtime/server/api/search-index +1 -0
  322. package/dist/runtime/server/api/search-index.d.ts +2 -0
  323. package/dist/runtime/server/api/search-index.js +20 -0
  324. package/dist/runtime/server/api/search.d.ts +2 -0
  325. package/dist/runtime/server/api/search.js +40 -0
  326. package/dist/runtime/server/api/site-data +1 -0
  327. package/dist/runtime/server/api/site-data.d.ts +2 -0
  328. package/dist/runtime/server/api/site-data.js +22 -0
  329. package/dist/runtime/server/api/sitemap +1 -0
  330. package/dist/runtime/server/api/sitemap.d.ts +2 -0
  331. package/dist/runtime/server/api/sitemap.js +11 -0
  332. package/dist/runtime/server/cache-adapter +1 -0
  333. package/dist/runtime/server/cache-adapter.d.ts +2 -0
  334. package/dist/runtime/server/cache-adapter.js +11 -0
  335. package/dist/runtime/server/cache-adapters +1 -0
  336. package/dist/runtime/server/cache-adapters.d.ts +9 -0
  337. package/dist/runtime/server/cache-adapters.js +50 -0
  338. package/dist/runtime/server/cache-hints +1 -0
  339. package/dist/runtime/server/cache-hints.d.ts +5 -0
  340. package/dist/runtime/server/cache-hints.js +17 -0
  341. package/dist/runtime/server/collection-helpers +1 -0
  342. package/dist/runtime/server/collection-helpers.d.ts +13 -0
  343. package/dist/runtime/server/collection-helpers.js +99 -0
  344. package/dist/runtime/server/index +1 -0
  345. package/dist/runtime/server/index.d.ts +9 -0
  346. package/dist/runtime/server/index.js +15 -0
  347. package/dist/runtime/server/manifest +1 -0
  348. package/dist/runtime/server/manifest.d.ts +1 -0
  349. package/dist/runtime/server/manifest.js +1 -0
  350. package/dist/runtime/server/navigation +1 -0
  351. package/dist/runtime/server/navigation-query +1 -0
  352. package/dist/runtime/server/navigation-query.d.ts +4 -0
  353. package/dist/runtime/server/navigation-query.js +80 -0
  354. package/dist/runtime/server/navigation.d.ts +2 -0
  355. package/dist/runtime/server/navigation.js +9 -0
  356. package/dist/runtime/server/pagefind +1 -0
  357. package/dist/runtime/server/pagefind.d.ts +2 -0
  358. package/dist/runtime/server/pagefind.js +30 -0
  359. package/dist/runtime/server/plugins/cache +1 -0
  360. package/dist/runtime/server/plugins/cache.d.ts +2 -0
  361. package/dist/runtime/server/plugins/cache.js +17 -0
  362. package/dist/runtime/server/plugins/sitemap +1 -0
  363. package/dist/runtime/server/plugins/sitemap.d.ts +2 -0
  364. package/dist/runtime/server/plugins/sitemap.js +25 -0
  365. package/dist/runtime/server/preview +1 -0
  366. package/dist/runtime/server/preview.d.ts +1 -0
  367. package/dist/runtime/server/preview.js +1 -0
  368. package/dist/runtime/server/provider-query +1 -0
  369. package/dist/runtime/server/provider-query.d.ts +27 -0
  370. package/dist/runtime/server/provider-query.js +131 -0
  371. package/dist/runtime/server/provider-result +1 -0
  372. package/dist/runtime/server/provider-result.d.ts +10 -0
  373. package/dist/runtime/server/provider-result.js +30 -0
  374. package/dist/runtime/server/providers/filesystem +1 -0
  375. package/dist/runtime/server/providers/filesystem.d.ts +2 -0
  376. package/dist/runtime/server/providers/filesystem.js +47 -0
  377. package/dist/runtime/server/providers/index +1 -0
  378. package/dist/runtime/server/providers/index.d.ts +3 -0
  379. package/dist/runtime/server/providers/index.js +190 -0
  380. package/dist/runtime/server/query-api +1 -0
  381. package/dist/runtime/server/query-api.d.ts +28 -0
  382. package/dist/runtime/server/query-api.js +54 -0
  383. package/dist/runtime/server/query-executor +1 -0
  384. package/dist/runtime/server/query-executor.d.ts +4 -0
  385. package/dist/runtime/server/query-executor.js +121 -0
  386. package/dist/runtime/server/runtime-config +1 -0
  387. package/dist/runtime/server/runtime-config.d.ts +1 -0
  388. package/dist/runtime/server/runtime-config.js +1 -0
  389. package/dist/runtime/server/search +1 -0
  390. package/dist/runtime/server/search.d.ts +18 -0
  391. package/dist/runtime/server/search.js +134 -0
  392. package/dist/runtime/server/sitemap +1 -0
  393. package/dist/runtime/server/sitemap-provider +1 -0
  394. package/dist/runtime/server/sitemap-provider.d.ts +10 -0
  395. package/dist/runtime/server/sitemap-provider.js +11 -0
  396. package/dist/runtime/server/sitemap.d.ts +6 -0
  397. package/dist/runtime/server/sitemap.js +45 -0
  398. package/dist/runtime/server/storage +1 -0
  399. package/dist/runtime/server/storage-access +1 -0
  400. package/dist/runtime/server/storage-access.d.ts +1 -0
  401. package/dist/runtime/server/storage-access.js +9 -0
  402. package/dist/runtime/server/storage.d.ts +2 -0
  403. package/dist/runtime/server/storage.js +2 -0
  404. package/dist/runtime/server/validation +1 -0
  405. package/dist/runtime/server/validation.d.ts +1 -0
  406. package/dist/runtime/server/validation.js +6 -0
  407. package/dist/runtime/shared/search +1 -0
  408. package/dist/runtime/shared/search.d.ts +2 -0
  409. package/dist/runtime/shared/search.js +89 -0
  410. package/dist/runtime/transformers/component-resolver +1 -0
  411. package/dist/runtime/transformers/component-resolver.d.ts +10 -0
  412. package/dist/runtime/transformers/component-resolver.js +30 -0
  413. package/dist/runtime/transformers/csv/from-csv +1 -0
  414. package/dist/runtime/transformers/csv/from-csv.d.ts +1 -0
  415. package/dist/runtime/transformers/csv/from-csv.js +1 -0
  416. package/dist/runtime/transformers/csv/index +1 -0
  417. package/dist/runtime/transformers/csv/index.d.ts +1 -0
  418. package/dist/runtime/transformers/csv/index.js +1 -0
  419. package/dist/runtime/transformers/define +1 -0
  420. package/dist/runtime/transformers/define.d.ts +1 -0
  421. package/dist/runtime/transformers/define.js +1 -0
  422. package/dist/runtime/transformers/index +1 -0
  423. package/dist/runtime/transformers/index.d.ts +1 -0
  424. package/dist/runtime/transformers/index.js +1 -0
  425. package/dist/runtime/transformers/json +1 -0
  426. package/dist/runtime/transformers/json.d.ts +1 -0
  427. package/dist/runtime/transformers/json.js +1 -0
  428. package/dist/runtime/transformers/markdown +1 -0
  429. package/dist/runtime/transformers/markdown.d.ts +1 -0
  430. package/dist/runtime/transformers/markdown.js +1 -0
  431. package/dist/runtime/transformers/path-meta +1 -0
  432. package/dist/runtime/transformers/path-meta.d.ts +2 -0
  433. package/dist/runtime/transformers/path-meta.js +2 -0
  434. package/dist/runtime/transformers/utils +1 -0
  435. package/dist/runtime/transformers/utils.d.ts +1 -0
  436. package/dist/runtime/transformers/utils.js +1 -0
  437. package/dist/runtime/transformers/yaml +1 -0
  438. package/dist/runtime/transformers/yaml.d.ts +1 -0
  439. package/dist/runtime/transformers/yaml.js +1 -0
  440. package/dist/runtime/utils/content-components +1 -0
  441. package/dist/runtime/utils/content-components.d.ts +9 -0
  442. package/dist/runtime/utils/content-components.js +16 -0
  443. package/dist/runtime/utils/query +1 -0
  444. package/dist/runtime/utils/query.d.ts +5 -0
  445. package/dist/runtime/utils/query.js +18 -0
  446. package/dist/runtime/virtual/transformers.d.ts +4 -0
  447. package/dist/runtime/virtual.d.ts +7 -0
  448. package/dist/storage/cache +1 -0
  449. package/dist/storage/cache.d.ts +32 -0
  450. package/dist/storage/cache.js +42 -0
  451. package/dist/storage/content +1 -0
  452. package/dist/storage/content.d.ts +41 -0
  453. package/dist/storage/content.js +86 -0
  454. package/dist/storage/contents +1 -0
  455. package/dist/storage/contents.d.ts +5 -0
  456. package/dist/storage/contents.js +116 -0
  457. package/dist/storage/driver +1 -0
  458. package/dist/storage/driver.d.ts +28 -0
  459. package/dist/storage/driver.js +22 -0
  460. package/dist/storage/graph +1 -0
  461. package/dist/storage/graph.d.ts +3 -0
  462. package/dist/storage/graph.js +14 -0
  463. package/dist/storage/manifest +1 -0
  464. package/dist/storage/manifest.d.ts +18 -0
  465. package/dist/storage/manifest.js +68 -0
  466. package/dist/storage/references +1 -0
  467. package/dist/storage/references.d.ts +13 -0
  468. package/dist/storage/references.js +78 -0
  469. package/dist/storage/validation +1 -0
  470. package/dist/storage/validation.d.ts +46 -0
  471. package/dist/storage/validation.js +341 -0
  472. package/dist/testing/provider-contract +1 -0
  473. package/dist/testing/provider-contract.d.ts +31 -0
  474. package/dist/testing/provider-contract.js +237 -0
  475. package/dist/testing/provider-fixture +1 -0
  476. package/dist/testing/provider-fixture.d.ts +65 -0
  477. package/dist/testing/provider-fixture.js +606 -0
  478. package/dist/types/api +1 -0
  479. package/dist/types/api.d.ts +47 -0
  480. package/dist/types/api.js +1 -0
  481. package/dist/types/config +1 -0
  482. package/dist/types/config.d.ts +281 -0
  483. package/dist/types/config.js +28 -0
  484. package/dist/types/content +1 -0
  485. package/dist/types/content.d.ts +311 -0
  486. package/dist/types/content.js +1 -0
  487. package/dist/types/fields +1 -0
  488. package/dist/types/fields.d.ts +81 -0
  489. package/dist/types/fields.js +146 -0
  490. package/dist/types/index +1 -0
  491. package/dist/types/index.d.ts +6 -0
  492. package/dist/types/index.js +6 -0
  493. package/dist/types/module +1 -0
  494. package/dist/types/module.d.ts +428 -0
  495. package/dist/types/module.js +0 -0
  496. package/dist/types/picomatch.d.ts +8 -0
  497. package/dist/types/query +1 -0
  498. package/dist/types/query.d.ts +862 -0
  499. package/dist/types/query.js +1 -0
  500. package/dist/types/reference +1 -0
  501. package/dist/types/reference.d.ts +1 -0
  502. package/dist/types/reference.js +1 -0
  503. package/dist/types/runtime +1 -0
  504. package/dist/types/runtime.d.ts +45 -0
  505. package/dist/types/runtime.js +1 -0
  506. package/dist/types/search +1 -0
  507. package/dist/types/search.d.ts +64 -0
  508. package/dist/types/search.js +0 -0
  509. package/dist/types/virtual.d.ts +19 -0
  510. package/dist/types.d.mts +11 -0
  511. package/dist/web-types.json +466 -0
  512. package/package.json +135 -0
package/dist/cli.mjs ADDED
@@ -0,0 +1,690 @@
1
+ #!/usr/bin/env node
2
+ import { existsSync } from 'node:fs';
3
+ import { readFile, readdir, stat } from 'node:fs/promises';
4
+ import { join, extname, relative } from 'node:path';
5
+
6
+ const ignoredDirs = /* @__PURE__ */ new Set([
7
+ ".git",
8
+ ".nuxt",
9
+ ".output",
10
+ ".cache",
11
+ "coverage",
12
+ "dist",
13
+ "node_modules"
14
+ ]);
15
+ const sourceExtensions = /* @__PURE__ */ new Set([
16
+ ".cjs",
17
+ ".cts",
18
+ ".js",
19
+ ".json",
20
+ ".jsx",
21
+ ".md",
22
+ ".mjs",
23
+ ".mts",
24
+ ".ts",
25
+ ".tsx",
26
+ ".vue",
27
+ ".yml",
28
+ ".yaml"
29
+ ]);
30
+ const stalePackageNames = ["@nuxt/content", "better-sqlite3", "@standard-schema/spec"];
31
+ const sourceChecks = [
32
+ {
33
+ pattern: /from\s+['"]@nuxt\/content(?:\/[^'"]*)?['"]|import\s*\([^)]*['"]@nuxt\/content(?:\/[^'"]*)?['"][^)]*\)/,
34
+ message: "Direct Nuxt Content import found.",
35
+ suggestion: "Import Ginko helpers from @lupinum/ginko-content/config, /client, or /server."
36
+ },
37
+ {
38
+ pattern: /['"]@nuxt\/content['"]/,
39
+ message: "Nuxt Content module or package reference found.",
40
+ suggestion: "Remove @nuxt/content from Nuxt modules and use @lupinum/ginko-content."
41
+ },
42
+ {
43
+ pattern: /\bqueryCollectionItemSurroundings\s*\(/,
44
+ message: "Nuxt Content v3 surround helper found.",
45
+ suggestion: "Use useContentNeighbors(handle, { by: { route } }) in route page components."
46
+ },
47
+ {
48
+ pattern: /\bqueryCollectionSearchSections\s*\(/,
49
+ message: "Nuxt Content v3 search sections helper found.",
50
+ suggestion: "Use useContentSearchData(collection) for UI search data."
51
+ },
52
+ {
53
+ pattern: /\bqueryCollectionNavigation\s*\(/,
54
+ message: "Nuxt Content v3 navigation helper found.",
55
+ suggestion: "Use useContentTree(handle) for layout navigation."
56
+ },
57
+ {
58
+ pattern: /\bqueryCollection\s*\(/,
59
+ message: "Removed collection query helper found.",
60
+ suggestion: "Use one(handle, options), many(handle, options), paginate(handle, options), or the matching useContent* composable."
61
+ },
62
+ {
63
+ pattern: /\buseContentList\s*\(/,
64
+ message: "Removed content list composable found.",
65
+ suggestion: "Use useContentMany(handle, options) or many(handle, options)."
66
+ },
67
+ {
68
+ pattern: /\buseContentNavigation\s*\(/,
69
+ message: "Removed content navigation composable found.",
70
+ suggestion: "Use useContentTree(handle) for layout navigation."
71
+ },
72
+ {
73
+ pattern: /\bcontent\.(database|preview|build)\b/,
74
+ message: "Nuxt Content v3 runtime config key found.",
75
+ suggestion: "Remove content.database/content.preview/content.build and configure Ginko runtime options instead."
76
+ },
77
+ {
78
+ pattern: /\.editor\s*\(/,
79
+ message: "Nuxt Studio Zod .editor(...) helper found.",
80
+ suggestion: "Remove .editor(...) from runtime Zod schemas or move editor metadata outside the schema."
81
+ },
82
+ {
83
+ pattern: /<ContentRenderer\b[^>]*:value\s*=\s*["'][^"']*\.body["']/,
84
+ message: "ContentRenderer is receiving a document body.",
85
+ suggestion: "Pass the full content document to ContentRenderer, not document.body."
86
+ },
87
+ {
88
+ pattern: /<NuxtLink\b[^>]*:to\s*=\s*["'][^"']+\.path["']/,
89
+ message: "NuxtLink may be using raw query .path.",
90
+ suggestion: "Use useContentMany(handle, options) for route-safe list items, or link route-page payloads with their explicit path field."
91
+ },
92
+ {
93
+ pattern: /<NuxtLink\b[^>]*:to\s*=\s*["'][^"']+\._path["']/,
94
+ message: "NuxtLink is using raw content _path.",
95
+ suggestion: "Use useContentMany(handle, options) for list pages and bind the route-safe item.path field."
96
+ }
97
+ ];
98
+ const lockfileNames = ["pnpm-lock.yaml", "package-lock.json", "yarn.lock", "bun.lockb"];
99
+ const localeCodePattern = /^[a-z]{2}(?:-[A-Z]{2})?$/;
100
+ const toRelativePath = (rootDir, file) => relative(rootDir, file) || ".";
101
+ const countSitemapUrls = (text) => (text.match(/<url>/g) || []).length;
102
+ async function collectFiles(dir, rootDir, files = []) {
103
+ const entries = await readdir(dir, { withFileTypes: true });
104
+ for (const entry of entries) {
105
+ const absolutePath = join(dir, entry.name);
106
+ if (entry.isDirectory()) {
107
+ if (!ignoredDirs.has(entry.name)) {
108
+ await collectFiles(absolutePath, rootDir, files);
109
+ }
110
+ continue;
111
+ }
112
+ if (entry.isFile() && sourceExtensions.has(extname(entry.name))) {
113
+ files.push(absolutePath);
114
+ }
115
+ }
116
+ return files;
117
+ }
118
+ function packageDependencyFindings(rootDir, packageJson) {
119
+ const dependencyBlocks = ["dependencies", "devDependencies", "optionalDependencies", "peerDependencies"];
120
+ const findings = [];
121
+ for (const blockName of dependencyBlocks) {
122
+ const block = packageJson[blockName];
123
+ if (!block || typeof block !== "object") {
124
+ continue;
125
+ }
126
+ for (const packageName of stalePackageNames) {
127
+ if (packageName in block) {
128
+ findings.push({
129
+ severity: "error",
130
+ file: toRelativePath(rootDir, join(rootDir, "package.json")),
131
+ message: `Direct dependency "${packageName}" found in ${blockName}.`,
132
+ suggestion: packageName === "@nuxt/content" ? "Remove @nuxt/content and install @lupinum/ginko-content." : `Remove ${packageName} unless the app imports it directly. If it is only transitive, keep it out of package.json.`
133
+ });
134
+ }
135
+ }
136
+ }
137
+ return findings;
138
+ }
139
+ async function inspectPackageJson(rootDir) {
140
+ const path = join(rootDir, "package.json");
141
+ if (!existsSync(path)) {
142
+ return [];
143
+ }
144
+ try {
145
+ const packageJson = JSON.parse(await readFile(path, "utf8"));
146
+ return packageDependencyFindings(rootDir, packageJson);
147
+ } catch {
148
+ return [{
149
+ severity: "error",
150
+ file: "package.json",
151
+ message: "package.json could not be parsed.",
152
+ suggestion: "Fix package.json before running ginko-content doctor again."
153
+ }];
154
+ }
155
+ }
156
+ async function inspectSourceFiles(rootDir) {
157
+ const files = await collectFiles(rootDir, rootDir);
158
+ const findings = [];
159
+ for (const file of files) {
160
+ if (lockfileNames.includes(file.split("/").pop() || "")) {
161
+ continue;
162
+ }
163
+ const text = await readFile(file, "utf8");
164
+ for (const check of sourceChecks) {
165
+ if (check.pattern.test(text)) {
166
+ findings.push({
167
+ severity: "error",
168
+ file: toRelativePath(rootDir, file),
169
+ message: check.message,
170
+ suggestion: check.suggestion
171
+ });
172
+ }
173
+ }
174
+ }
175
+ return findings;
176
+ }
177
+ async function inspectLockfiles(rootDir) {
178
+ const findings = [];
179
+ for (const lockfileName of lockfileNames) {
180
+ const path = join(rootDir, lockfileName);
181
+ if (!existsSync(path)) {
182
+ continue;
183
+ }
184
+ const text = await readFile(path, "utf8");
185
+ const presentPackages = stalePackageNames.filter((packageName) => text.includes(packageName));
186
+ if (presentPackages.length) {
187
+ findings.push({
188
+ severity: "info",
189
+ file: lockfileName,
190
+ message: `Lockfile still mentions ${presentPackages.join(", ")}.`,
191
+ suggestion: `Run "pnpm why ${presentPackages.join(" ")}" and only act if one is still a direct app dependency.`
192
+ });
193
+ }
194
+ }
195
+ return findings;
196
+ }
197
+ async function readGeneratedSitemaps(rootDir) {
198
+ const outputPublicDir = join(rootDir, ".output/public");
199
+ if (!existsSync(outputPublicDir)) {
200
+ return [];
201
+ }
202
+ const sitemapPaths = [
203
+ join(outputPublicDir, "sitemap.xml"),
204
+ join(outputPublicDir, "sitemap_index.xml")
205
+ ];
206
+ const sitemapDir = join(outputPublicDir, "__sitemap__");
207
+ if (existsSync(sitemapDir)) {
208
+ const entries = await readdir(sitemapDir, { withFileTypes: true });
209
+ for (const entry of entries) {
210
+ if (entry.isFile() && entry.name.endsWith(".xml")) {
211
+ sitemapPaths.push(join(sitemapDir, entry.name));
212
+ }
213
+ }
214
+ }
215
+ const sitemapFiles = [];
216
+ for (const sitemapPath of sitemapPaths) {
217
+ if (!existsSync(sitemapPath)) {
218
+ continue;
219
+ }
220
+ const fileStat = await stat(sitemapPath);
221
+ if (fileStat.isFile()) {
222
+ sitemapFiles.push({
223
+ file: toRelativePath(rootDir, sitemapPath),
224
+ text: await readFile(sitemapPath, "utf8")
225
+ });
226
+ }
227
+ }
228
+ return sitemapFiles;
229
+ }
230
+ async function inspectSitemap(rootDir) {
231
+ const sitemapFiles = await readGeneratedSitemaps(rootDir);
232
+ const sitemapTexts = sitemapFiles.map((file) => file.text);
233
+ if (!sitemapTexts.length) {
234
+ return [];
235
+ }
236
+ const urlCount = sitemapTexts.reduce((total, text) => total + countSitemapUrls(text), 0);
237
+ const hasSitemapIndex = sitemapTexts.some((text) => /<sitemapindex\b/.test(text));
238
+ if (urlCount > 0 || hasSitemapIndex) {
239
+ return [];
240
+ }
241
+ return [{
242
+ severity: "error",
243
+ file: ".output/public/sitemap.xml",
244
+ message: "Generated sitemap contains no <url> entries.",
245
+ suggestion: "Enable content.sitemap, configure site.url, and verify public route collections are sitemap-backed."
246
+ }];
247
+ }
248
+ async function readTextIfPresent(path) {
249
+ if (!existsSync(path)) {
250
+ return "";
251
+ }
252
+ const fileStat = await stat(path);
253
+ if (!fileStat.isFile()) {
254
+ return "";
255
+ }
256
+ return readFile(path, "utf8");
257
+ }
258
+ function extractLocaleCodesFromConfig(text) {
259
+ const locales = /* @__PURE__ */ new Set();
260
+ for (const match of text.matchAll(/\bcode\s*:\s*['"]([^'"]+)['"]/g)) {
261
+ if (localeCodePattern.test(match[1])) {
262
+ locales.add(match[1]);
263
+ }
264
+ }
265
+ for (const match of text.matchAll(/\bdefaultLocale\s*:\s*['"]([^'"]+)['"]/g)) {
266
+ if (localeCodePattern.test(match[1])) {
267
+ locales.add(match[1]);
268
+ }
269
+ }
270
+ for (const match of text.matchAll(/\blocales\s*:\s*\[([\s\S]*?)\]/g)) {
271
+ if (/\bcode\s*:/.test(match[1])) {
272
+ continue;
273
+ }
274
+ for (const localeMatch of match[1].matchAll(/['"]([^'"]+)['"]/g)) {
275
+ if (localeCodePattern.test(localeMatch[1])) {
276
+ locales.add(localeMatch[1]);
277
+ }
278
+ }
279
+ }
280
+ return [...locales];
281
+ }
282
+ async function readPackageJson(rootDir) {
283
+ const path = join(rootDir, "package.json");
284
+ if (!existsSync(path)) {
285
+ return void 0;
286
+ }
287
+ try {
288
+ return JSON.parse(await readFile(path, "utf8"));
289
+ } catch {
290
+ return void 0;
291
+ }
292
+ }
293
+ function hasDependency(packageJson, packageName) {
294
+ if (!packageJson) {
295
+ return false;
296
+ }
297
+ return ["dependencies", "devDependencies", "optionalDependencies", "peerDependencies"].some((blockName) => {
298
+ const block = packageJson[blockName];
299
+ return !!block && typeof block === "object" && packageName in block;
300
+ });
301
+ }
302
+ async function detectI18n(rootDir) {
303
+ const nuxtConfigPath = join(rootDir, "nuxt.config.ts");
304
+ const contentConfigPath = join(rootDir, "content.config.ts");
305
+ const nuxtConfig = await readTextIfPresent(nuxtConfigPath);
306
+ const contentConfig = await readTextIfPresent(contentConfigPath);
307
+ const packageJson = await readPackageJson(rootDir);
308
+ const locales = /* @__PURE__ */ new Set([
309
+ ...extractLocaleCodesFromConfig(nuxtConfig),
310
+ ...extractLocaleCodesFromConfig(contentConfig)
311
+ ]);
312
+ const contentDir = join(rootDir, "content");
313
+ if (existsSync(contentDir)) {
314
+ const entries = await readdir(contentDir, { withFileTypes: true });
315
+ for (const entry of entries) {
316
+ if (entry.isDirectory() && localeCodePattern.test(entry.name)) {
317
+ locales.add(entry.name);
318
+ }
319
+ }
320
+ }
321
+ return {
322
+ locales: [...locales].sort(),
323
+ hasNuxtI18nModule: /['"]@nuxtjs\/i18n['"]/.test(nuxtConfig),
324
+ hasContentI18nConfig: /\bcontent\s*:\s*\{[\s\S]*?\bi18n\s*:/.test(nuxtConfig),
325
+ hasNuxtI18nDependency: hasDependency(packageJson, "@nuxtjs/i18n")
326
+ };
327
+ }
328
+ async function inspectI18nConfig(rootDir, detected) {
329
+ const findings = [];
330
+ if (!detected.locales.length) {
331
+ findings.push({
332
+ severity: "error",
333
+ file: "nuxt.config.ts",
334
+ message: "No i18n locales detected.",
335
+ suggestion: "Configure @nuxtjs/i18n locales and content.i18n.locales, or create content/<locale>/ folders."
336
+ });
337
+ }
338
+ if (!detected.hasNuxtI18nDependency) {
339
+ findings.push({
340
+ severity: "error",
341
+ file: "package.json",
342
+ message: "Direct @nuxtjs/i18n dependency is missing for an i18n app.",
343
+ suggestion: "Install @nuxtjs/i18n directly so Nuxt owns route localization explicitly."
344
+ });
345
+ }
346
+ if (!detected.hasNuxtI18nModule) {
347
+ findings.push({
348
+ severity: "error",
349
+ file: "nuxt.config.ts",
350
+ message: "@nuxtjs/i18n module is not registered.",
351
+ suggestion: "Add @nuxtjs/i18n to modules before relying on localized content routes."
352
+ });
353
+ }
354
+ if (!detected.hasContentI18nConfig) {
355
+ findings.push({
356
+ severity: "error",
357
+ file: "nuxt.config.ts",
358
+ message: "content.i18n runtime config is missing.",
359
+ suggestion: "Add content.i18n with defaultLocale and locales so collections resolve localized documents."
360
+ });
361
+ }
362
+ return findings;
363
+ }
364
+ async function inspectI18nCollections(rootDir) {
365
+ const contentConfigPath = join(rootDir, "content.config.ts");
366
+ const text = await readTextIfPresent(contentConfigPath);
367
+ if (!text) {
368
+ return [{
369
+ severity: "error",
370
+ file: "content.config.ts",
371
+ message: "content.config.ts is missing.",
372
+ suggestion: "Declare i18n collections with defineContentConfig({ collections })."
373
+ }];
374
+ }
375
+ const matches = [...text.matchAll(/([A-Za-z_$][\w$]*)\s*:\s*defineCollection\s*\(\s*\{/g)];
376
+ if (!matches.length) {
377
+ return [];
378
+ }
379
+ const findings = [];
380
+ matches.forEach((match, index) => {
381
+ const collectionName = match[1];
382
+ const start = match.index || 0;
383
+ const end = matches[index + 1]?.index || text.length;
384
+ const collectionBlock = text.slice(start, end);
385
+ if (!/\bi18n\s*:\s*(true|\{)/.test(collectionBlock)) {
386
+ findings.push({
387
+ severity: "error",
388
+ file: "content.config.ts",
389
+ message: `Collection "${collectionName}" is not marked as i18n-aware.`,
390
+ suggestion: `Add i18n: true to the ${collectionName} collection or provide collection-level i18n locales.`
391
+ });
392
+ }
393
+ });
394
+ return findings;
395
+ }
396
+ async function inspectI18nContentFolders(rootDir, locales) {
397
+ const contentDir = join(rootDir, "content");
398
+ if (!existsSync(contentDir) || !locales.length) {
399
+ return [];
400
+ }
401
+ const findings = [];
402
+ for (const locale of locales) {
403
+ const localeDir = join(contentDir, locale);
404
+ if (!existsSync(localeDir) || !(await stat(localeDir)).isDirectory()) {
405
+ findings.push({
406
+ severity: "error",
407
+ file: `content/${locale}`,
408
+ message: `Content locale folder "${locale}" is missing.`,
409
+ suggestion: `Create content/${locale}/ and place translated collection files under that locale root.`
410
+ });
411
+ }
412
+ }
413
+ return findings;
414
+ }
415
+ async function inspectI18nSourceSmells(rootDir, locales) {
416
+ const files = await collectFiles(rootDir, rootDir);
417
+ const findings = [];
418
+ const hardcodedLocalePathPattern = locales.length ? new RegExp(`locale\\.(?:value|code)\\s*={2,3}\\s*['"](?:${locales.join("|")})['"][\\s\\S]{0,160}?['"]/(?:${locales.join("|")})/`) : void 0;
419
+ for (const file of files) {
420
+ const relativeFile = toRelativePath(rootDir, file);
421
+ if (!/^(app|pages|components|layouts|error\.vue)\//.test(relativeFile) && relativeFile !== "error.vue") {
422
+ continue;
423
+ }
424
+ const text = await readFile(file, "utf8");
425
+ if (hardcodedLocalePathPattern?.test(text)) {
426
+ findings.push({
427
+ severity: "error",
428
+ file: relativeFile,
429
+ message: "Hardcoded locale route branch found.",
430
+ suggestion: "Use @nuxtjs/i18n route helpers, useContentTree(handle), or useContentMany(handle, options) item paths instead of branching on locale codes."
431
+ });
432
+ }
433
+ if (/<(?:NuxtLink|U[A-Za-z]+)\b[^>]*:to\s*=\s*["'][^"']+\._path["']/.test(text)) {
434
+ findings.push({
435
+ severity: "error",
436
+ file: relativeFile,
437
+ message: "UI link is bound to raw content _path.",
438
+ suggestion: "Use useContentMany(handle, options) for localized list pages and bind item.path."
439
+ });
440
+ }
441
+ }
442
+ return findings;
443
+ }
444
+ async function inspectI18nDuplicateContentGroups(rootDir, locales) {
445
+ const contentDir = join(rootDir, "content");
446
+ if (!existsSync(contentDir) || !locales.length) {
447
+ return [];
448
+ }
449
+ const findings = [];
450
+ for (const locale of locales) {
451
+ const localeDir = join(contentDir, locale);
452
+ if (!existsSync(localeDir)) {
453
+ continue;
454
+ }
455
+ const entries = await readdir(localeDir, { withFileTypes: true });
456
+ const byOrdinal = /* @__PURE__ */ new Map();
457
+ for (const entry of entries) {
458
+ if (!entry.isDirectory()) {
459
+ continue;
460
+ }
461
+ const ordinal = entry.name.match(/^(\d+)\./)?.[1];
462
+ if (!ordinal) {
463
+ continue;
464
+ }
465
+ const names = byOrdinal.get(ordinal) || [];
466
+ names.push(entry.name);
467
+ byOrdinal.set(ordinal, names);
468
+ }
469
+ for (const [ordinal, names] of byOrdinal) {
470
+ if (names.length > 1) {
471
+ findings.push({
472
+ severity: "error",
473
+ file: `content/${locale}`,
474
+ message: `Locale "${locale}" has multiple content groups with ordinal "${ordinal}": ${names.join(", ")}.`,
475
+ suggestion: "Keep one translated slug group per collection ordinal and delete stale canonical duplicates."
476
+ });
477
+ }
478
+ }
479
+ }
480
+ return findings;
481
+ }
482
+ async function collectOutputFiles(dir, rootDir, files = []) {
483
+ const entries = await readdir(dir, { withFileTypes: true });
484
+ for (const entry of entries) {
485
+ const absolutePath = join(dir, entry.name);
486
+ if (entry.isDirectory()) {
487
+ if (entry.name !== "_nuxt") {
488
+ await collectOutputFiles(absolutePath, rootDir, files);
489
+ }
490
+ continue;
491
+ }
492
+ if (entry.isFile() && [".html", ".json", ".xml"].includes(extname(entry.name))) {
493
+ files.push(absolutePath);
494
+ }
495
+ }
496
+ return files;
497
+ }
498
+ async function inspectRepeatedLocalePrefixes(rootDir, locales) {
499
+ const outputPublicDir = join(rootDir, ".output/public");
500
+ if (!existsSync(outputPublicDir)) {
501
+ return [];
502
+ }
503
+ const files = await collectOutputFiles(outputPublicDir, rootDir);
504
+ const findings = [];
505
+ for (const file of files) {
506
+ const relativeFile = toRelativePath(rootDir, file);
507
+ const text = await readFile(file, "utf8");
508
+ for (const locale of locales) {
509
+ const repeatedPath = `/${locale}/${locale}/`;
510
+ if (relativeFile.includes(repeatedPath) || text.includes(repeatedPath)) {
511
+ findings.push({
512
+ severity: "error",
513
+ file: relativeFile,
514
+ message: `Repeated locale prefix "${repeatedPath}" found in generated output.`,
515
+ suggestion: "Use locale-neutral raw _path values in content links and let Nuxt I18n add the route prefix once."
516
+ });
517
+ break;
518
+ }
519
+ }
520
+ }
521
+ return findings;
522
+ }
523
+ async function inspectI18nSitemaps(rootDir, locales) {
524
+ const sitemapFiles = await readGeneratedSitemaps(rootDir);
525
+ const childSitemaps = sitemapFiles.filter((file) => file.file.includes("__sitemap__/"));
526
+ if (!childSitemaps.length || !locales.length) {
527
+ return [];
528
+ }
529
+ const findings = [];
530
+ for (const locale of locales) {
531
+ const hasLocaleSitemap = childSitemaps.some((file) => {
532
+ const filename = file.file.split("/").pop() || "";
533
+ return filename.startsWith(locale) && countSitemapUrls(file.text) > 0;
534
+ });
535
+ if (!hasLocaleSitemap) {
536
+ findings.push({
537
+ severity: "error",
538
+ file: ".output/public/__sitemap__",
539
+ message: `Generated sitemap is missing non-empty locale sitemap for "${locale}".`,
540
+ suggestion: "Build the app and verify Nuxt Sitemap emits one child sitemap per configured locale."
541
+ });
542
+ }
543
+ }
544
+ return findings;
545
+ }
546
+ async function inspectI18nSitemapSummary(rootDir, locales) {
547
+ const sitemapFiles = await readGeneratedSitemaps(rootDir);
548
+ const index = sitemapFiles.find((file) => file.file === ".output/public/sitemap_index.xml" && /<sitemapindex\b/.test(file.text));
549
+ const childSitemaps = sitemapFiles.filter((file) => file.file.includes("__sitemap__/")).map((file) => ({
550
+ file: file.file,
551
+ urlCount: countSitemapUrls(file.text)
552
+ })).sort((a, b) => a.file.localeCompare(b.file));
553
+ if (!index || !childSitemaps.length || !locales.length) {
554
+ return [];
555
+ }
556
+ const rootSitemapPath = join(rootDir, ".output/public/sitemap.xml");
557
+ const hasRedirectDirectory = existsSync(rootSitemapPath) && (await stat(rootSitemapPath)).isDirectory();
558
+ const childSummary = childSitemaps.map((file) => `${file.file.replace(".output/public/", "")} (${file.urlCount} ${file.urlCount === 1 ? "URL" : "URLs"})`).join(", ");
559
+ const totalUrls = childSitemaps.reduce((total, file) => total + file.urlCount, 0);
560
+ const redirectNote = hasRedirectDirectory ? " Ignore .output/public/sitemap.xml/ when it is a generated redirect directory." : "";
561
+ return [{
562
+ severity: "info",
563
+ file: ".output/public/sitemap_index.xml",
564
+ message: `Sitemap mode: Nuxt Sitemap i18n multi-sitemap (${childSitemaps.length} child sitemaps, ${totalUrls} ${totalUrls === 1 ? "URL" : "URLs"}).`,
565
+ suggestion: `Submit "/sitemap_index.xml". Child sitemaps: ${childSummary}.${redirectNote}`
566
+ }];
567
+ }
568
+ async function inspectI18nSearchIndex(rootDir, locales) {
569
+ const searchIndexPath = join(rootDir, ".output/public/api/_content/search/index.json");
570
+ if (!existsSync(searchIndexPath) || !locales.length) {
571
+ return [];
572
+ }
573
+ try {
574
+ const raw = JSON.parse(await readFile(searchIndexPath, "utf8"));
575
+ const records = Array.isArray(raw) ? raw : raw && typeof raw === "object" && Array.isArray(raw.records) ? raw.records : [];
576
+ const findings = [];
577
+ for (const locale of locales) {
578
+ const hasLocaleRecords = records.some((record) => {
579
+ if (!record || typeof record !== "object") {
580
+ return false;
581
+ }
582
+ const item = record;
583
+ return item.locale === locale || item._locale === locale || typeof item.path === "string" && item.path.startsWith(`/${locale}/`);
584
+ });
585
+ if (!hasLocaleRecords) {
586
+ findings.push({
587
+ severity: "error",
588
+ file: ".output/public/api/_content/search/index.json",
589
+ message: `Search index has no records for locale "${locale}".`,
590
+ suggestion: "Use useContentSearchData() with i18n collections and verify the prerendered search payload includes every locale."
591
+ });
592
+ }
593
+ }
594
+ return findings;
595
+ } catch {
596
+ return [{
597
+ severity: "error",
598
+ file: ".output/public/api/_content/search/index.json",
599
+ message: "Search index JSON could not be parsed.",
600
+ suggestion: "Rebuild the app and inspect the generated search payload."
601
+ }];
602
+ }
603
+ }
604
+ async function inspectI18n(rootDir) {
605
+ const detected = await detectI18n(rootDir);
606
+ return [
607
+ ...await inspectI18nConfig(rootDir, detected),
608
+ ...await inspectI18nCollections(rootDir),
609
+ ...await inspectI18nContentFolders(rootDir, detected.locales),
610
+ ...await inspectI18nDuplicateContentGroups(rootDir, detected.locales),
611
+ ...await inspectI18nSourceSmells(rootDir, detected.locales),
612
+ ...await inspectRepeatedLocalePrefixes(rootDir, detected.locales),
613
+ ...await inspectI18nSitemaps(rootDir, detected.locales),
614
+ ...await inspectI18nSitemapSummary(rootDir, detected.locales),
615
+ ...await inspectI18nSearchIndex(rootDir, detected.locales)
616
+ ];
617
+ }
618
+ async function runDoctor(options = {}) {
619
+ const rootDir = options.rootDir || process.cwd();
620
+ const findings = [
621
+ ...await inspectPackageJson(rootDir),
622
+ ...await inspectSourceFiles(rootDir),
623
+ ...await inspectLockfiles(rootDir),
624
+ ...await inspectSitemap(rootDir),
625
+ ...options.i18n ? await inspectI18n(rootDir) : []
626
+ ].sort((a, b) => `${a.severity}:${a.file}:${a.message}`.localeCompare(`${b.severity}:${b.file}:${b.message}`));
627
+ const exitCode = findings.some((finding) => finding.severity === "error") ? 1 : 0;
628
+ return {
629
+ rootDir,
630
+ findings,
631
+ exitCode
632
+ };
633
+ }
634
+ function formatDoctorResult(result) {
635
+ const errors = result.findings.filter((finding) => finding.severity === "error");
636
+ const infos = result.findings.filter((finding) => finding.severity === "info");
637
+ const lines = [
638
+ `Ginko Content doctor: ${errors.length ? "issues found" : "ok"}`,
639
+ `Root: ${result.rootDir}`
640
+ ];
641
+ if (errors.length) {
642
+ lines.push("", `Errors (${errors.length})`);
643
+ for (const finding of errors) {
644
+ lines.push(`- ${finding.file}: ${finding.message}`);
645
+ lines.push(` Fix: ${finding.suggestion}`);
646
+ }
647
+ }
648
+ if (infos.length) {
649
+ lines.push("", `Info (${infos.length})`);
650
+ for (const finding of infos) {
651
+ lines.push(`- ${finding.file}: ${finding.message}`);
652
+ lines.push(` Check: ${finding.suggestion}`);
653
+ }
654
+ }
655
+ return `${lines.join("\n")}
656
+ `;
657
+ }
658
+
659
+ const [, , command, ...args] = process.argv;
660
+ if (!command || command === "--help" || command === "-h") {
661
+ console.log([
662
+ "Usage: ginko-content <command> [options] [root]",
663
+ "",
664
+ "Commands:",
665
+ " doctor [root] Validate a Nuxt Content v3 to Ginko migration",
666
+ " doctor --i18n [root] Validate i18n migration wiring and generated output"
667
+ ].join("\n"));
668
+ process.exit(0);
669
+ }
670
+ if (command !== "doctor") {
671
+ console.error(`Unknown command: ${command}`);
672
+ console.error('Run "ginko-content --help" for available commands.');
673
+ process.exit(1);
674
+ }
675
+ try {
676
+ const i18n = args.includes("--i18n");
677
+ const rootDirArg = args.find((arg) => !arg.startsWith("-"));
678
+ const unknownFlag = args.find((arg) => arg.startsWith("-") && arg !== "--i18n");
679
+ if (unknownFlag) {
680
+ console.error(`Unknown option: ${unknownFlag}`);
681
+ console.error('Run "ginko-content --help" for available commands.');
682
+ process.exit(1);
683
+ }
684
+ const result = await runDoctor({ rootDir: rootDirArg || process.cwd(), i18n });
685
+ process.stdout.write(formatDoctorResult(result));
686
+ process.exit(result.exitCode);
687
+ } catch (error) {
688
+ console.error(error instanceof Error ? error.message : error);
689
+ process.exit(1);
690
+ }
@@ -0,0 +1 @@
1
+ export * from './build.js'