@geenius/docs 0.1.0 → 0.4.1

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 (158) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/README.md +53 -1
  3. package/package.json +101 -13
  4. package/packages/convex/dist/index.d.ts +503 -0
  5. package/packages/convex/dist/index.js +482 -0
  6. package/packages/convex/dist/index.js.map +1 -0
  7. package/packages/react/dist/index.d.ts +439 -0
  8. package/packages/react/dist/index.js +4954 -0
  9. package/packages/react/dist/index.js.map +1 -0
  10. package/packages/react-css/{src/styles.css → dist/index.css} +183 -223
  11. package/packages/react-css/dist/index.css.map +1 -0
  12. package/packages/react-css/dist/index.d.ts +443 -0
  13. package/packages/react-css/dist/index.js +5058 -0
  14. package/packages/react-css/dist/index.js.map +1 -0
  15. package/packages/shared/dist/index.d.ts +684 -0
  16. package/packages/shared/dist/index.js +788 -0
  17. package/packages/shared/dist/index.js.map +1 -0
  18. package/packages/solidjs/dist/index.d.ts +435 -0
  19. package/packages/solidjs/dist/index.js +4584 -0
  20. package/packages/solidjs/dist/index.js.map +1 -0
  21. package/packages/solidjs-css/{src/styles.css → dist/index.css} +183 -223
  22. package/packages/solidjs-css/dist/index.css.map +1 -0
  23. package/packages/solidjs-css/dist/index.d.ts +432 -0
  24. package/packages/solidjs-css/dist/index.js +4934 -0
  25. package/packages/solidjs-css/dist/index.js.map +1 -0
  26. package/.changeset/config.json +0 -11
  27. package/.github/CODEOWNERS +0 -1
  28. package/.github/ISSUE_TEMPLATE/bug_report.md +0 -16
  29. package/.github/ISSUE_TEMPLATE/feature_request.md +0 -11
  30. package/.github/PULL_REQUEST_TEMPLATE.md +0 -10
  31. package/.github/dependabot.yml +0 -11
  32. package/.github/workflows/ci.yml +0 -23
  33. package/.github/workflows/release.yml +0 -29
  34. package/.nvmrc +0 -1
  35. package/.project/ACCOUNT.yaml +0 -4
  36. package/.project/IDEAS.yaml +0 -7
  37. package/.project/PROJECT.yaml +0 -11
  38. package/.project/ROADMAP.yaml +0 -15
  39. package/CODE_OF_CONDUCT.md +0 -16
  40. package/CONTRIBUTING.md +0 -26
  41. package/SECURITY.md +0 -15
  42. package/SUPPORT.md +0 -8
  43. package/packages/convex/README.md +0 -1
  44. package/packages/convex/package.json +0 -12
  45. package/packages/convex/src/convex.config.ts +0 -3
  46. package/packages/convex/src/index.ts +0 -3
  47. package/packages/convex/src/mutations.ts +0 -270
  48. package/packages/convex/src/queries.ts +0 -175
  49. package/packages/convex/src/schema.ts +0 -55
  50. package/packages/react/README.md +0 -1
  51. package/packages/react/package.json +0 -36
  52. package/packages/react/src/DocsLayout.tsx +0 -116
  53. package/packages/react/src/DocsProvider.tsx +0 -93
  54. package/packages/react/src/RouterDocsContent.tsx +0 -148
  55. package/packages/react/src/RouterDocsLayout.tsx +0 -161
  56. package/packages/react/src/components/Breadcrumbs.tsx +0 -34
  57. package/packages/react/src/components/DocPage.tsx +0 -191
  58. package/packages/react/src/components/DocSearch.tsx +0 -140
  59. package/packages/react/src/components/DocSidebar.tsx +0 -86
  60. package/packages/react/src/components/DocsLayout.tsx +0 -62
  61. package/packages/react/src/components/EditButton.tsx +0 -26
  62. package/packages/react/src/components/PageNavigation.tsx +0 -45
  63. package/packages/react/src/components/TableOfContents.tsx +0 -46
  64. package/packages/react/src/components/VersionSelector.tsx +0 -60
  65. package/packages/react/src/components/index.ts +0 -9
  66. package/packages/react/src/hooks/index.ts +0 -8
  67. package/packages/react/src/hooks/useDocSearch.ts +0 -55
  68. package/packages/react/src/hooks/useDocs.ts +0 -57
  69. package/packages/react/src/hooks/useDocsAdmin.ts +0 -151
  70. package/packages/react/src/hooks/useTableOfContents.ts +0 -66
  71. package/packages/react/src/index.ts +0 -38
  72. package/packages/react/src/pages/DocSearchPage.tsx +0 -129
  73. package/packages/react/src/pages/DocViewPage.tsx +0 -158
  74. package/packages/react/src/pages/DocsAdminPage.tsx +0 -330
  75. package/packages/react/src/pages/DocsIndexPage.tsx +0 -172
  76. package/packages/react/src/pages/index.ts +0 -4
  77. package/packages/react/src/useDocs.ts +0 -58
  78. package/packages/react/tsup.config.ts +0 -12
  79. package/packages/react-css/README.md +0 -1
  80. package/packages/react-css/package.json +0 -37
  81. package/packages/react-css/src/DocsLayout.tsx +0 -117
  82. package/packages/react-css/src/DocsProvider.tsx +0 -93
  83. package/packages/react-css/src/RouterDocsContent.tsx +0 -60
  84. package/packages/react-css/src/RouterDocsLayout.tsx +0 -101
  85. package/packages/react-css/src/components/DocPage.tsx +0 -21
  86. package/packages/react-css/src/components/DocSearch.tsx +0 -55
  87. package/packages/react-css/src/components/DocSidebar.tsx +0 -56
  88. package/packages/react-css/src/components/DocsLayout.tsx +0 -28
  89. package/packages/react-css/src/components/common.tsx +0 -93
  90. package/packages/react-css/src/components/index.ts +0 -5
  91. package/packages/react-css/src/hooks/index.ts +0 -2
  92. package/packages/react-css/src/index.ts +0 -6
  93. package/packages/react-css/src/index.tsx +0 -3
  94. package/packages/react-css/src/pages/DocViewPage.tsx +0 -78
  95. package/packages/react-css/src/pages/DocsAdminPage.tsx +0 -101
  96. package/packages/react-css/src/pages/DocsIndexPage.tsx +0 -68
  97. package/packages/react-css/src/pages/index.ts +0 -3
  98. package/packages/react-css/src/useDocs.ts +0 -58
  99. package/packages/react-css/tsconfig.json +0 -19
  100. package/packages/react-css/tsup.config.ts +0 -10
  101. package/packages/shared/README.md +0 -1
  102. package/packages/shared/package.json +0 -31
  103. package/packages/shared/src/__tests__/docs.test.ts +0 -69
  104. package/packages/shared/src/config.ts +0 -80
  105. package/packages/shared/src/index.ts +0 -179
  106. package/packages/shared/src/providers/astro.ts +0 -94
  107. package/packages/shared/src/providers/fumadocs.ts +0 -116
  108. package/packages/shared/src/providers/internal.ts +0 -80
  109. package/packages/shared/src/types.ts +0 -73
  110. package/packages/shared/tsconfig.json +0 -18
  111. package/packages/shared/tsup.config.ts +0 -12
  112. package/packages/shared/vitest.config.ts +0 -4
  113. package/packages/solidjs/README.md +0 -1
  114. package/packages/solidjs/package.json +0 -33
  115. package/packages/solidjs/src/DocsLayout.tsx +0 -87
  116. package/packages/solidjs/src/DocsProvider.tsx +0 -95
  117. package/packages/solidjs/src/RouterDocsContent.tsx +0 -147
  118. package/packages/solidjs/src/RouterDocsLayout.tsx +0 -161
  119. package/packages/solidjs/src/components/Breadcrumbs.tsx +0 -27
  120. package/packages/solidjs/src/components/DocPage.tsx +0 -110
  121. package/packages/solidjs/src/components/DocSearch.tsx +0 -81
  122. package/packages/solidjs/src/components/DocSidebar.tsx +0 -92
  123. package/packages/solidjs/src/components/DocsLayout.tsx +0 -38
  124. package/packages/solidjs/src/components/EditButton.tsx +0 -15
  125. package/packages/solidjs/src/components/PageNavigation.tsx +0 -31
  126. package/packages/solidjs/src/components/TableOfContents.tsx +0 -41
  127. package/packages/solidjs/src/components/VersionSelector.tsx +0 -30
  128. package/packages/solidjs/src/components/index.ts +0 -9
  129. package/packages/solidjs/src/createDocs.ts +0 -62
  130. package/packages/solidjs/src/index.ts +0 -28
  131. package/packages/solidjs/src/pages/DocSearchPage.tsx +0 -72
  132. package/packages/solidjs/src/pages/DocViewPage.tsx +0 -80
  133. package/packages/solidjs/src/pages/DocsAdminPage.tsx +0 -123
  134. package/packages/solidjs/src/pages/DocsIndexPage.tsx +0 -85
  135. package/packages/solidjs/src/pages/index.ts +0 -4
  136. package/packages/solidjs/src/primitives/createDocSearch.ts +0 -42
  137. package/packages/solidjs/src/primitives/createDocs.ts +0 -35
  138. package/packages/solidjs/src/primitives/createDocsAdmin.ts +0 -63
  139. package/packages/solidjs/src/primitives/createTableOfContents.ts +0 -51
  140. package/packages/solidjs/src/primitives/index.ts +0 -4
  141. package/packages/solidjs/tsup.config.ts +0 -12
  142. package/packages/solidjs-css/README.md +0 -1
  143. package/packages/solidjs-css/package.json +0 -36
  144. package/packages/solidjs-css/src/DocsLayout.tsx +0 -106
  145. package/packages/solidjs-css/src/DocsProvider.tsx +0 -95
  146. package/packages/solidjs-css/src/RouterDocsContent.tsx +0 -54
  147. package/packages/solidjs-css/src/RouterDocsLayout.tsx +0 -104
  148. package/packages/solidjs-css/src/createDocs.ts +0 -62
  149. package/packages/solidjs-css/src/index.ts +0 -7
  150. package/packages/solidjs-css/src/index.tsx +0 -17
  151. package/packages/solidjs-css/src/pages/DocViewPage.tsx +0 -111
  152. package/packages/solidjs-css/src/pages/DocsAdminPage.tsx +0 -332
  153. package/packages/solidjs-css/src/pages/DocsIndexPage.tsx +0 -116
  154. package/packages/solidjs-css/src/pages/index.ts +0 -3
  155. package/packages/solidjs-css/src/primitives/index.ts +0 -1
  156. package/packages/solidjs-css/tsconfig.json +0 -20
  157. package/packages/solidjs-css/tsup.config.ts +0 -10
  158. package/pnpm-workspace.yaml +0 -2
@@ -0,0 +1,788 @@
1
+ import { GeeniusError, ErrorCode } from '@geenius/tools/errors';
2
+ import matter from 'gray-matter';
3
+
4
+ // src/config.ts
5
+ var DocsError = class _DocsError extends GeeniusError {
6
+ constructor(options) {
7
+ super(options);
8
+ this.name = "DocsError";
9
+ Object.setPrototypeOf(this, _DocsError.prototype);
10
+ }
11
+ };
12
+ var DocsConfigurationError = class _DocsConfigurationError extends DocsError {
13
+ constructor(options) {
14
+ super({
15
+ ...options,
16
+ code: options.code ?? ErrorCode.INVALID_CONFIG
17
+ });
18
+ this.name = "DocsConfigurationError";
19
+ Object.setPrototypeOf(this, _DocsConfigurationError.prototype);
20
+ }
21
+ };
22
+ var DocsProviderError = class _DocsProviderError extends DocsError {
23
+ constructor(options) {
24
+ super({
25
+ ...options,
26
+ code: options.code ?? ErrorCode.INTERNAL_ERROR
27
+ });
28
+ this.name = "DocsProviderError";
29
+ Object.setPrototypeOf(this, _DocsProviderError.prototype);
30
+ }
31
+ };
32
+
33
+ // src/config.ts
34
+ var _config = null;
35
+ function configureDocs(config) {
36
+ _config = config;
37
+ }
38
+ function getDocsConfig() {
39
+ if (!_config) {
40
+ throw new DocsConfigurationError({
41
+ code: ErrorCode.MISSING_CONFIG,
42
+ message: "Docs not configured. Call configureDocs() first.",
43
+ context: { function: "getDocsConfig" }
44
+ });
45
+ }
46
+ return _config;
47
+ }
48
+ function isDocsConfigured() {
49
+ return _config !== null;
50
+ }
51
+ function resetDocsConfig() {
52
+ _config = null;
53
+ }
54
+ function defineDocsConfig(overrides) {
55
+ return {
56
+ baseUrl: "/docs",
57
+ defaultAccess: "public",
58
+ versionsEnabled: false,
59
+ cmdKEnabled: true,
60
+ showReadingTime: true,
61
+ showLastEdited: true,
62
+ printModeEnabled: true,
63
+ ...overrides
64
+ };
65
+ }
66
+ function mergeDocsConfig(base, overrides) {
67
+ return {
68
+ ...base,
69
+ ...overrides
70
+ };
71
+ }
72
+
73
+ // src/utilities.ts
74
+ function toTocLevel(level) {
75
+ if (level === 2 || level === 3 || level === 4) {
76
+ return level;
77
+ }
78
+ return 4;
79
+ }
80
+ function extractToc(mdxContent) {
81
+ const headingRegex = /^(#{2,4})\s+(.+)$/gm;
82
+ const items = [];
83
+ let match = headingRegex.exec(mdxContent);
84
+ while (match !== null) {
85
+ const text = match[2].trim();
86
+ items.push({
87
+ id: slugify(text),
88
+ text,
89
+ level: toTocLevel(match[1].length),
90
+ children: []
91
+ });
92
+ match = headingRegex.exec(mdxContent);
93
+ }
94
+ const nested = [];
95
+ let currentH2 = null;
96
+ let currentH3 = null;
97
+ for (const item of items) {
98
+ if (item.level === 2) {
99
+ currentH2 = item;
100
+ currentH3 = null;
101
+ nested.push(item);
102
+ continue;
103
+ }
104
+ if (item.level === 3) {
105
+ currentH3 = item;
106
+ if (currentH2) {
107
+ currentH2.children.push(item);
108
+ } else {
109
+ nested.push(item);
110
+ }
111
+ continue;
112
+ }
113
+ if (currentH3) {
114
+ currentH3.children.push(item);
115
+ } else if (currentH2) {
116
+ currentH2.children.push(item);
117
+ } else {
118
+ nested.push(item);
119
+ }
120
+ }
121
+ return nested;
122
+ }
123
+ function calcWordCount(content) {
124
+ const stripped = content.replace(/```[\s\S]*?```/g, "").replace(/`[^`]+`/g, "").replace(/!\[.*?\]\(.*?\)/g, "").replace(/\[([^\]]+)\]\(.*?\)/g, "$1").replace(/[#*_~>|-]/g, "").trim();
125
+ const words = stripped.split(/\s+/).filter(Boolean);
126
+ return {
127
+ wordCount: words.length,
128
+ readingTime: Math.max(1, Math.ceil(words.length / 225))
129
+ };
130
+ }
131
+ function buildBreadcrumbs(sections, sectionId, slug) {
132
+ const crumbs = [{ title: "Docs", href: "/docs" }];
133
+ const sectionMap = new Map(sections.map((section) => [section.id, section]));
134
+ const trail = [];
135
+ let current = sectionMap.get(sectionId);
136
+ while (current) {
137
+ trail.unshift(current);
138
+ current = current.parentId ? sectionMap.get(current.parentId) : void 0;
139
+ }
140
+ for (const section of trail) {
141
+ crumbs.push({ title: section.title, href: `/docs/${section.slug}` });
142
+ }
143
+ if (slug) {
144
+ const parentSlug = trail[trail.length - 1]?.slug ?? "";
145
+ crumbs.push({ title: slug, href: `/docs/${parentSlug}/${slug}` });
146
+ }
147
+ return crumbs;
148
+ }
149
+ function buildDocsIndex(pages, sections) {
150
+ const sectionMap = new Map(sections.map((section) => [section.id, section]));
151
+ return pages.filter((page) => page.status === "published").map((page) => {
152
+ const section = sectionMap.get(page.sectionId);
153
+ return {
154
+ pageId: page.id,
155
+ pageTitle: page.title,
156
+ sectionTitle: section?.title ?? "",
157
+ sectionSlug: section?.slug ?? "",
158
+ slug: page.slug,
159
+ highlight: page.excerpt ?? page.content.slice(0, 160),
160
+ score: 0,
161
+ tags: page.tags
162
+ };
163
+ });
164
+ }
165
+ function searchDocs(query, index) {
166
+ if (!query.trim()) {
167
+ return [];
168
+ }
169
+ const terms = query.toLowerCase().split(/\s+/).filter(Boolean);
170
+ return index.map((entry) => {
171
+ let score = 0;
172
+ const titleLower = entry.pageTitle.toLowerCase();
173
+ const highlightLower = entry.highlight.toLowerCase();
174
+ const sectionLower = entry.sectionTitle.toLowerCase();
175
+ const tagsLower = entry.tags.map((tag) => tag.toLowerCase());
176
+ for (const term of terms) {
177
+ if (titleLower.includes(term)) {
178
+ score += 10;
179
+ }
180
+ if (tagsLower.some((tag) => tag.includes(term))) {
181
+ score += 5;
182
+ }
183
+ if (sectionLower.includes(term)) {
184
+ score += 3;
185
+ }
186
+ if (highlightLower.includes(term)) {
187
+ score += 2;
188
+ }
189
+ }
190
+ return { ...entry, score };
191
+ }).filter((entry) => entry.score > 0).sort((left, right) => right.score - left.score).slice(0, 20);
192
+ }
193
+ function slugify(title) {
194
+ return title.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/(^-|-$)/g, "");
195
+ }
196
+ function highlightMatch(text, query, maxLen = 160) {
197
+ if (!query.trim()) {
198
+ return text.slice(0, maxLen);
199
+ }
200
+ const lowerText = text.toLowerCase();
201
+ const lowerQuery = query.toLowerCase();
202
+ const index = lowerText.indexOf(lowerQuery);
203
+ if (index === -1) {
204
+ return text.slice(0, maxLen);
205
+ }
206
+ const start = Math.max(0, index - 40);
207
+ const end = Math.min(text.length, index + query.length + (maxLen - 80));
208
+ let snippet = text.slice(start, end);
209
+ if (start > 0) {
210
+ snippet = `\u2026${snippet}`;
211
+ }
212
+ if (end < text.length) {
213
+ snippet = `${snippet}\u2026`;
214
+ }
215
+ return snippet;
216
+ }
217
+ var defaultDocsConfig = {
218
+ siteName: "Docs",
219
+ cmdKEnabled: true,
220
+ showReadingTime: true,
221
+ showLastEdited: true,
222
+ versionsEnabled: false,
223
+ defaultAccess: "public",
224
+ printModeEnabled: true
225
+ };
226
+
227
+ // src/providers/astro.ts
228
+ function sectionTitle(sectionId) {
229
+ return sectionId.split(/[-_/]/).filter(Boolean).map((part) => `${part[0]?.toUpperCase() ?? ""}${part.slice(1)}`).join(" ") || "General";
230
+ }
231
+ function asString(value) {
232
+ return typeof value === "string" && value.trim().length > 0 ? value.trim() : void 0;
233
+ }
234
+ function asNumber(value) {
235
+ if (typeof value === "number" && Number.isFinite(value)) {
236
+ return value;
237
+ }
238
+ if (typeof value === "string") {
239
+ const parsed = Number.parseInt(value, 10);
240
+ if (Number.isFinite(parsed)) {
241
+ return parsed;
242
+ }
243
+ }
244
+ return 0;
245
+ }
246
+ function asAccess(value) {
247
+ if (value === "team" || value === "admin") {
248
+ return value;
249
+ }
250
+ return "public";
251
+ }
252
+ function asStatus(value) {
253
+ if (value === "draft" || value === "archived") {
254
+ return value;
255
+ }
256
+ return "published";
257
+ }
258
+ function asTags(value) {
259
+ if (Array.isArray(value)) {
260
+ return value.filter((entry) => typeof entry === "string");
261
+ }
262
+ if (typeof value === "string") {
263
+ return value.split(",").map((entry) => entry.trim()).filter(Boolean);
264
+ }
265
+ return [];
266
+ }
267
+ function createSidebar(pages) {
268
+ const sections = /* @__PURE__ */ new Map();
269
+ for (const page of pages.filter((entry) => entry.status === "published")) {
270
+ const title = sectionTitle(page.sectionId);
271
+ const existing = sections.get(page.sectionId) ?? {
272
+ id: page.sectionId,
273
+ title,
274
+ slug: slugify(title),
275
+ pages: []
276
+ };
277
+ existing.pages.push({ slug: page.slug, title: page.title });
278
+ sections.set(page.sectionId, existing);
279
+ }
280
+ return [...sections.values()];
281
+ }
282
+ var AstroDocsProvider = class {
283
+ pages = [];
284
+ /**
285
+ * Loads docs from an Astro-style `import.meta.glob()` result.
286
+ *
287
+ * @param globResult - Lazy or eager Astro content loaders keyed by path.
288
+ * @returns Nothing. The provider page set is replaced in memory.
289
+ */
290
+ async loadFromGlob(globResult) {
291
+ const parsed = await Promise.all(
292
+ Object.entries(globResult).map(async ([path, loader]) => {
293
+ const raw = typeof loader === "function" ? await loader() : loader;
294
+ return this.parseDoc(path, raw);
295
+ })
296
+ );
297
+ this.pages = this.linkPages(parsed);
298
+ }
299
+ /**
300
+ * Loads docs from already-read file contents.
301
+ *
302
+ * @param files - File path and content pairs to normalise.
303
+ * @returns Nothing. The provider page set is replaced in memory.
304
+ */
305
+ async loadFromFiles(files) {
306
+ this.pages = this.linkPages(
307
+ files.map((file) => this.parseDoc(file.path, file.content))
308
+ );
309
+ }
310
+ parseDoc(path, raw) {
311
+ const parsed = matter(raw);
312
+ const pathParts = path.replace(/.*content\/docs\//, "").replace(/\.(mdx?|md)$/, "").split("/").filter(Boolean);
313
+ const slug = pathParts.join("/");
314
+ const sectionId = pathParts[0] ?? "general";
315
+ const titleFromPath = pathParts[pathParts.length - 1] ?? slug;
316
+ const { wordCount, readingTime } = calcWordCount(parsed.content);
317
+ const authorName = asString(parsed.data.author) ?? "Geenius";
318
+ const now = (/* @__PURE__ */ new Date()).toISOString();
319
+ const status = parsed.data.draft === true ? "draft" : asStatus(parsed.data.status);
320
+ return {
321
+ id: asString(parsed.data.id) ?? slug,
322
+ title: asString(parsed.data.title) ?? sectionTitle(titleFromPath),
323
+ slug,
324
+ content: parsed.content,
325
+ excerpt: asString(parsed.data.description),
326
+ sectionId,
327
+ order: asNumber(parsed.data.order),
328
+ author: {
329
+ name: authorName,
330
+ avatar: asString(parsed.data.avatar)
331
+ },
332
+ lastEditedBy: asString(parsed.data.lastEditedBy) ? {
333
+ name: asString(parsed.data.lastEditedBy) ?? authorName,
334
+ editedAt: asString(parsed.data.lastEditedAt) ?? now
335
+ } : void 0,
336
+ version: asString(parsed.data.version),
337
+ access: asAccess(parsed.data.access),
338
+ tags: asTags(parsed.data.tags),
339
+ status,
340
+ createdAt: asString(parsed.data.createdAt) ?? now,
341
+ updatedAt: asString(parsed.data.updatedAt) ?? now,
342
+ wordCount,
343
+ readingTime,
344
+ viewCount: asNumber(parsed.data.viewCount)
345
+ };
346
+ }
347
+ linkPages(pages) {
348
+ const sorted = [...pages].sort((left, right) => left.order - right.order);
349
+ return sorted.map((page, index) => {
350
+ const prev = sorted[index - 1];
351
+ const next = sorted[index + 1];
352
+ const prevLink = prev ? { slug: prev.slug, title: prev.title } : null;
353
+ const nextLink = next ? { slug: next.slug, title: next.title } : null;
354
+ return {
355
+ ...page,
356
+ prev: prevLink,
357
+ next: nextLink,
358
+ toc: extractToc(page.content)
359
+ };
360
+ });
361
+ }
362
+ /**
363
+ * Loads the sidebar structure derived from the parsed Astro pages.
364
+ *
365
+ * @returns Sidebar navigation entries derived from the published pages.
366
+ */
367
+ async getSidebar() {
368
+ return createSidebar(this.pages);
369
+ }
370
+ /**
371
+ * Resolves a linked docs page by slug.
372
+ *
373
+ * @param slug - Target page slug.
374
+ * @returns The linked page or `null` when no page matches the slug.
375
+ */
376
+ async getPage(slug) {
377
+ return this.pages.find((page) => page.slug === slug) ?? null;
378
+ }
379
+ /**
380
+ * Returns all published pages managed by the provider.
381
+ *
382
+ * @returns Published pages in their linked navigation order.
383
+ */
384
+ async getAllPages() {
385
+ return this.pages.filter((page) => page.status === "published");
386
+ }
387
+ /**
388
+ * Searches the parsed Astro page set.
389
+ *
390
+ * @param query - User-entered search query.
391
+ * @returns Ranked search results derived from the published pages.
392
+ */
393
+ async search(query) {
394
+ const normalizedQuery = query.trim().toLowerCase();
395
+ if (!normalizedQuery) {
396
+ return [];
397
+ }
398
+ return this.pages.filter((page) => page.status === "published").map((page) => {
399
+ let score = 0;
400
+ if (page.title.toLowerCase().includes(normalizedQuery)) {
401
+ score += 10;
402
+ }
403
+ if (page.tags.some((tag) => tag.toLowerCase().includes(normalizedQuery))) {
404
+ score += 4;
405
+ }
406
+ if (page.content.toLowerCase().includes(normalizedQuery)) {
407
+ score += 2;
408
+ }
409
+ if (score === 0) {
410
+ return null;
411
+ }
412
+ return {
413
+ pageId: page.id,
414
+ pageTitle: page.title,
415
+ sectionTitle: sectionTitle(page.sectionId),
416
+ slug: page.slug,
417
+ highlight: highlightMatch(page.excerpt ?? page.content, query),
418
+ score
419
+ };
420
+ }).filter((result) => result !== null).sort((left, right) => right.score - left.score);
421
+ }
422
+ /**
423
+ * Resolves previous and next pages for a slug.
424
+ *
425
+ * @param slug - Target page slug.
426
+ * @returns Linked previous and next page records when available.
427
+ */
428
+ async getNavigation(slug) {
429
+ const page = this.pages.find((entry) => entry.slug === slug);
430
+ if (!page) {
431
+ return { prev: null, next: null };
432
+ }
433
+ return {
434
+ prev: page.prev ? this.pages.find((entry) => entry.slug === page.prev?.slug) ?? null : null,
435
+ next: page.next ? this.pages.find((entry) => entry.slug === page.next?.slug) ?? null : null
436
+ };
437
+ }
438
+ };
439
+
440
+ // src/providers/fumadocs.ts
441
+ function sectionTitle2(sectionId) {
442
+ return sectionId.split(/[-_/]/).filter(Boolean).map((part) => `${part[0]?.toUpperCase() ?? ""}${part.slice(1)}`).join(" ") || "General";
443
+ }
444
+ function asString2(value) {
445
+ return typeof value === "string" && value.trim().length > 0 ? value.trim() : void 0;
446
+ }
447
+ function asAccess2(value) {
448
+ if (value === "team" || value === "admin") {
449
+ return value;
450
+ }
451
+ return "public";
452
+ }
453
+ function asStatus2(value) {
454
+ if (value === "draft" || value === "archived") {
455
+ return value;
456
+ }
457
+ return "published";
458
+ }
459
+ function asTags2(value) {
460
+ if (Array.isArray(value)) {
461
+ return value.filter((entry) => typeof entry === "string");
462
+ }
463
+ if (typeof value === "string") {
464
+ return value.split(",").map((entry) => entry.trim()).filter(Boolean);
465
+ }
466
+ return [];
467
+ }
468
+ function createSidebar2(pages) {
469
+ const sections = /* @__PURE__ */ new Map();
470
+ for (const page of pages.filter((entry) => entry.status === "published")) {
471
+ const title = sectionTitle2(page.sectionId);
472
+ const existing = sections.get(page.sectionId) ?? {
473
+ id: page.sectionId,
474
+ title,
475
+ slug: slugify(title),
476
+ pages: []
477
+ };
478
+ existing.pages.push({ slug: page.slug, title: page.title });
479
+ sections.set(page.sectionId, existing);
480
+ }
481
+ return [...sections.values()];
482
+ }
483
+ var FumadocsDocsProvider = class {
484
+ pages = [];
485
+ tree = [];
486
+ /**
487
+ * Loads pages and an optional page tree from Fumadocs.
488
+ *
489
+ * @param pages - Source pages supplied by Fumadocs.
490
+ * @param tree - Optional source page tree for nested sidebar rendering.
491
+ * @returns Nothing. The provider page set is replaced in memory.
492
+ */
493
+ loadFromSource(pages, tree = []) {
494
+ this.tree = tree;
495
+ this.pages = this.linkPages(pages.map((page) => this.normalizePage(page)));
496
+ }
497
+ normalizePage(page) {
498
+ const slugParts = page.slugs ?? page.slug?.split("/") ?? [];
499
+ const slug = slugParts.join("/");
500
+ const sectionId = slugParts[0] ?? "general";
501
+ const title = page.data.title ?? slugParts[slugParts.length - 1] ?? slug;
502
+ const content = page.data.body ?? "";
503
+ const { wordCount, readingTime } = calcWordCount(content);
504
+ const now = (/* @__PURE__ */ new Date()).toISOString();
505
+ return {
506
+ id: slug,
507
+ title,
508
+ slug,
509
+ content,
510
+ excerpt: page.data.description,
511
+ sectionId,
512
+ order: page.data.order ?? 0,
513
+ author: {
514
+ name: page.data.author ?? "Geenius",
515
+ avatar: asString2(page.data.avatar)
516
+ },
517
+ lastEditedBy: asString2(page.data.lastModified ?? page.data.lastUpdated) ? {
518
+ name: page.data.author ?? "Geenius",
519
+ editedAt: asString2(page.data.lastModified ?? page.data.lastUpdated) ?? now
520
+ } : void 0,
521
+ version: asString2(page.data.version),
522
+ access: asAccess2(page.data.access),
523
+ tags: asTags2(page.data.tags),
524
+ status: page.data.draft === true ? "draft" : asStatus2(page.data.status),
525
+ createdAt: now,
526
+ updatedAt: asString2(page.data.lastModified ?? page.data.lastUpdated) ?? now,
527
+ wordCount,
528
+ readingTime,
529
+ viewCount: 0,
530
+ toc: page.data.toc ?? extractToc(content)
531
+ };
532
+ }
533
+ linkPages(pages) {
534
+ const sorted = [...pages].sort((left, right) => left.order - right.order);
535
+ return sorted.map((page, index) => {
536
+ const prev = sorted[index - 1];
537
+ const next = sorted[index + 1];
538
+ const prevLink = prev ? { slug: prev.slug, title: prev.title } : null;
539
+ const nextLink = next ? { slug: next.slug, title: next.title } : null;
540
+ return {
541
+ ...page,
542
+ prev: prevLink,
543
+ next: nextLink
544
+ };
545
+ });
546
+ }
547
+ treeToSidebar(nodes) {
548
+ return nodes.filter((node) => node.type === "folder").map((folder) => {
549
+ const title = folder.name ?? "Section";
550
+ const children = folder.children ?? [];
551
+ const pages = children.filter((child) => child.type === "page").map((child) => ({
552
+ slug: child.slug ?? "",
553
+ title: child.name ?? child.slug ?? "Untitled"
554
+ }));
555
+ const nestedChildren = this.treeToSidebar(
556
+ children.filter((child) => child.type === "folder")
557
+ );
558
+ return {
559
+ id: folder.slug ?? slugify(title),
560
+ title,
561
+ slug: folder.slug ?? slugify(title),
562
+ icon: folder.icon,
563
+ pages,
564
+ children: nestedChildren.length > 0 ? nestedChildren : void 0
565
+ };
566
+ });
567
+ }
568
+ /**
569
+ * Loads the sidebar structure derived from the Fumadocs tree or grouped pages.
570
+ *
571
+ * @returns Sidebar navigation entries derived from the published pages.
572
+ */
573
+ async getSidebar() {
574
+ if (this.tree.length > 0) {
575
+ return this.treeToSidebar(this.tree);
576
+ }
577
+ return createSidebar2(this.pages);
578
+ }
579
+ /**
580
+ * Resolves a linked docs page by slug.
581
+ *
582
+ * @param slug - Target page slug.
583
+ * @returns The linked page or `null` when no page matches the slug.
584
+ */
585
+ async getPage(slug) {
586
+ return this.pages.find((page) => page.slug === slug) ?? null;
587
+ }
588
+ /**
589
+ * Returns all published pages managed by the provider.
590
+ *
591
+ * @returns Published pages in their linked navigation order.
592
+ */
593
+ async getAllPages() {
594
+ return this.pages.filter((page) => page.status === "published");
595
+ }
596
+ /**
597
+ * Searches the provider-backed page set.
598
+ *
599
+ * @param query - User-entered search query.
600
+ * @returns Ranked search results derived from the published pages.
601
+ */
602
+ async search(query) {
603
+ const normalizedQuery = query.trim().toLowerCase();
604
+ if (!normalizedQuery) {
605
+ return [];
606
+ }
607
+ return this.pages.filter((page) => page.status === "published").map((page) => {
608
+ let score = 0;
609
+ if (page.title.toLowerCase().includes(normalizedQuery)) {
610
+ score += 10;
611
+ }
612
+ if (page.tags.some((tag) => tag.toLowerCase().includes(normalizedQuery))) {
613
+ score += 4;
614
+ }
615
+ if (page.content.toLowerCase().includes(normalizedQuery)) {
616
+ score += 2;
617
+ }
618
+ if (page.excerpt?.toLowerCase().includes(normalizedQuery)) {
619
+ score += 1;
620
+ }
621
+ if (score === 0) {
622
+ return null;
623
+ }
624
+ return {
625
+ pageId: page.id,
626
+ pageTitle: page.title,
627
+ sectionTitle: sectionTitle2(page.sectionId),
628
+ slug: page.slug,
629
+ highlight: highlightMatch(page.excerpt ?? page.content, query),
630
+ score
631
+ };
632
+ }).filter((result) => result !== null).sort((left, right) => right.score - left.score);
633
+ }
634
+ /**
635
+ * Resolves previous and next pages for a slug.
636
+ *
637
+ * @param slug - Target page slug.
638
+ * @returns Linked previous and next page records when available.
639
+ */
640
+ async getNavigation(slug) {
641
+ const page = this.pages.find((entry) => entry.slug === slug);
642
+ if (!page) {
643
+ return { prev: null, next: null };
644
+ }
645
+ return {
646
+ prev: page.prev ? this.pages.find((entry) => entry.slug === page.prev?.slug) ?? null : null,
647
+ next: page.next ? this.pages.find((entry) => entry.slug === page.next?.slug) ?? null : null
648
+ };
649
+ }
650
+ };
651
+
652
+ // src/providers/internal.ts
653
+ function sectionTitle3(sectionId) {
654
+ return sectionId.split(/[-_/]/).filter(Boolean).map((part) => `${part[0]?.toUpperCase() ?? ""}${part.slice(1)}`).join(" ") || "General";
655
+ }
656
+ function createSidebar3(pages) {
657
+ const sections = /* @__PURE__ */ new Map();
658
+ for (const page of pages.filter((entry) => entry.status === "published")) {
659
+ const title = sectionTitle3(page.sectionId);
660
+ const entry = sections.get(page.sectionId) ?? {
661
+ id: page.sectionId,
662
+ title,
663
+ slug: slugify(title),
664
+ pages: []
665
+ };
666
+ entry.pages.push({ slug: page.slug, title: page.title });
667
+ sections.set(page.sectionId, entry);
668
+ }
669
+ return [...sections.values()].map((entry) => ({
670
+ ...entry,
671
+ pages: [...entry.pages].sort(
672
+ (left, right) => left.title.localeCompare(right.title)
673
+ )
674
+ }));
675
+ }
676
+ var InternalDocsProvider = class {
677
+ pages = [];
678
+ /**
679
+ * @param pages - Optional initial page records to seed the provider with.
680
+ */
681
+ constructor(pages = []) {
682
+ this.pages = this.linkPages(pages);
683
+ }
684
+ /**
685
+ * Replaces the provider's page set.
686
+ *
687
+ * @param pages - Fresh page records to seed into the provider.
688
+ * @returns Nothing. The provider page set is replaced in memory.
689
+ */
690
+ setPages(pages) {
691
+ this.pages = this.linkPages(pages);
692
+ }
693
+ linkPages(pages) {
694
+ const sorted = [...pages].sort((left, right) => left.order - right.order);
695
+ return sorted.map((page, index) => {
696
+ const prev = sorted[index - 1];
697
+ const next = sorted[index + 1];
698
+ const prevLink = prev ? { slug: prev.slug, title: prev.title } : null;
699
+ const nextLink = next ? { slug: next.slug, title: next.title } : null;
700
+ return {
701
+ ...page,
702
+ prev: prevLink,
703
+ next: nextLink,
704
+ toc: extractToc(page.content)
705
+ };
706
+ });
707
+ }
708
+ /**
709
+ * Loads the sidebar structure derived from the current page set.
710
+ *
711
+ * @returns Sidebar navigation entries derived from the published pages.
712
+ */
713
+ async getSidebar() {
714
+ return createSidebar3(this.pages);
715
+ }
716
+ /**
717
+ * Resolves a linked docs page by slug.
718
+ *
719
+ * @param slug - Target page slug.
720
+ * @returns The linked page or `null` when no page matches the slug.
721
+ */
722
+ async getPage(slug) {
723
+ return this.pages.find((page) => page.slug === slug) ?? null;
724
+ }
725
+ /**
726
+ * Returns all published pages managed by the provider.
727
+ *
728
+ * @returns Published pages in their linked navigation order.
729
+ */
730
+ async getAllPages() {
731
+ return this.pages.filter((page) => page.status === "published");
732
+ }
733
+ /**
734
+ * Searches the provider-backed page set.
735
+ *
736
+ * @param query - User-entered search query.
737
+ * @returns Ranked search results derived from the published pages.
738
+ */
739
+ async search(query) {
740
+ const normalizedQuery = query.trim().toLowerCase();
741
+ if (!normalizedQuery) {
742
+ return [];
743
+ }
744
+ return this.pages.filter((page) => page.status === "published").map((page) => {
745
+ let score = 0;
746
+ if (page.title.toLowerCase().includes(normalizedQuery)) {
747
+ score += 10;
748
+ }
749
+ if (page.tags.some((tag) => tag.toLowerCase().includes(normalizedQuery))) {
750
+ score += 4;
751
+ }
752
+ if (page.content.toLowerCase().includes(normalizedQuery)) {
753
+ score += 2;
754
+ }
755
+ if (score === 0) {
756
+ return null;
757
+ }
758
+ return {
759
+ pageId: page.id,
760
+ pageTitle: page.title,
761
+ sectionTitle: sectionTitle3(page.sectionId),
762
+ slug: page.slug,
763
+ highlight: highlightMatch(page.excerpt ?? page.content, query),
764
+ score
765
+ };
766
+ }).filter((result) => result !== null).sort((left, right) => right.score - left.score);
767
+ }
768
+ /**
769
+ * Resolves previous and next pages for a slug.
770
+ *
771
+ * @param slug - Target page slug.
772
+ * @returns Linked previous and next page records when available.
773
+ */
774
+ async getNavigation(slug) {
775
+ const page = this.pages.find((entry) => entry.slug === slug);
776
+ if (!page) {
777
+ return { prev: null, next: null };
778
+ }
779
+ return {
780
+ prev: page.prev ? this.pages.find((entry) => entry.slug === page.prev?.slug) ?? null : null,
781
+ next: page.next ? this.pages.find((entry) => entry.slug === page.next?.slug) ?? null : null
782
+ };
783
+ }
784
+ };
785
+
786
+ export { AstroDocsProvider, DocsConfigurationError, DocsError, DocsProviderError, FumadocsDocsProvider, InternalDocsProvider, buildBreadcrumbs, buildDocsIndex, calcWordCount, configureDocs, defaultDocsConfig, defineDocsConfig, extractToc, getDocsConfig, highlightMatch, isDocsConfigured, mergeDocsConfig, resetDocsConfig, searchDocs, slugify };
787
+ //# sourceMappingURL=index.js.map
788
+ //# sourceMappingURL=index.js.map