@geenius/docs 0.4.1 → 0.5.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.
@@ -0,0 +1,564 @@
1
+ import { calcWordCount, extractToc, highlightMatch, slugify } from './chunk-BR2XBF64.js';
2
+ import matter from 'gray-matter';
3
+
4
+ function sectionTitle(sectionId) {
5
+ return sectionId.split(/[-_/]/).filter(Boolean).map((part) => `${part[0]?.toUpperCase() ?? ""}${part.slice(1)}`).join(" ") || "General";
6
+ }
7
+ function asString(value) {
8
+ return typeof value === "string" && value.trim().length > 0 ? value.trim() : void 0;
9
+ }
10
+ function asNumber(value) {
11
+ if (typeof value === "number" && Number.isFinite(value)) {
12
+ return value;
13
+ }
14
+ if (typeof value === "string") {
15
+ const parsed = Number.parseInt(value, 10);
16
+ if (Number.isFinite(parsed)) {
17
+ return parsed;
18
+ }
19
+ }
20
+ return 0;
21
+ }
22
+ function asAccess(value) {
23
+ if (value === "team" || value === "admin") {
24
+ return value;
25
+ }
26
+ return "public";
27
+ }
28
+ function asStatus(value) {
29
+ if (value === "draft" || value === "archived") {
30
+ return value;
31
+ }
32
+ return "published";
33
+ }
34
+ function asTags(value) {
35
+ if (Array.isArray(value)) {
36
+ return value.filter((entry) => typeof entry === "string");
37
+ }
38
+ if (typeof value === "string") {
39
+ return value.split(",").map((entry) => entry.trim()).filter(Boolean);
40
+ }
41
+ return [];
42
+ }
43
+ function createSidebar(pages) {
44
+ const sections = /* @__PURE__ */ new Map();
45
+ for (const page of pages.filter((entry) => entry.status === "published")) {
46
+ const title = sectionTitle(page.sectionId);
47
+ const existing = sections.get(page.sectionId) ?? {
48
+ id: page.sectionId,
49
+ title,
50
+ slug: slugify(title),
51
+ pages: []
52
+ };
53
+ existing.pages.push({ slug: page.slug, title: page.title });
54
+ sections.set(page.sectionId, existing);
55
+ }
56
+ return [...sections.values()];
57
+ }
58
+ var AstroDocsProvider = class {
59
+ pages = [];
60
+ /**
61
+ * Loads docs from an Astro-style `import.meta.glob()` result.
62
+ *
63
+ * @param globResult - Lazy or eager Astro content loaders keyed by path.
64
+ * @returns Nothing. The provider page set is replaced in memory.
65
+ */
66
+ async loadFromGlob(globResult) {
67
+ const parsed = await Promise.all(
68
+ Object.entries(globResult).map(async ([path, loader]) => {
69
+ const raw = typeof loader === "function" ? await loader() : loader;
70
+ return this.parseDoc(path, raw);
71
+ })
72
+ );
73
+ this.pages = this.linkPages(parsed);
74
+ }
75
+ /**
76
+ * Loads docs from already-read file contents.
77
+ *
78
+ * @param files - File path and content pairs to normalise.
79
+ * @returns Nothing. The provider page set is replaced in memory.
80
+ */
81
+ async loadFromFiles(files) {
82
+ this.pages = this.linkPages(
83
+ files.map((file) => this.parseDoc(file.path, file.content))
84
+ );
85
+ }
86
+ parseDoc(path, raw) {
87
+ const parsed = matter(raw);
88
+ const pathParts = path.replace(/.*content\/docs\//, "").replace(/\.(mdx?|md)$/, "").split("/").filter(Boolean);
89
+ const slug = pathParts.join("/");
90
+ const sectionId = pathParts[0] ?? "general";
91
+ const titleFromPath = pathParts[pathParts.length - 1] ?? slug;
92
+ const { wordCount, readingTime } = calcWordCount(parsed.content);
93
+ const authorName = asString(parsed.data.author) ?? "Geenius";
94
+ const now = (/* @__PURE__ */ new Date()).toISOString();
95
+ const status = parsed.data.draft === true ? "draft" : asStatus(parsed.data.status);
96
+ return {
97
+ id: asString(parsed.data.id) ?? slug,
98
+ title: asString(parsed.data.title) ?? sectionTitle(titleFromPath),
99
+ slug,
100
+ content: parsed.content,
101
+ excerpt: asString(parsed.data.description),
102
+ sectionId,
103
+ order: asNumber(parsed.data.order),
104
+ author: {
105
+ name: authorName,
106
+ avatar: asString(parsed.data.avatar)
107
+ },
108
+ lastEditedBy: asString(parsed.data.lastEditedBy) ? {
109
+ name: asString(parsed.data.lastEditedBy) ?? authorName,
110
+ editedAt: asString(parsed.data.lastEditedAt) ?? now
111
+ } : void 0,
112
+ version: asString(parsed.data.version),
113
+ access: asAccess(parsed.data.access),
114
+ tags: asTags(parsed.data.tags),
115
+ status,
116
+ createdAt: asString(parsed.data.createdAt) ?? now,
117
+ updatedAt: asString(parsed.data.updatedAt) ?? now,
118
+ wordCount,
119
+ readingTime,
120
+ viewCount: asNumber(parsed.data.viewCount)
121
+ };
122
+ }
123
+ linkPages(pages) {
124
+ const sorted = [...pages].sort((left, right) => left.order - right.order);
125
+ return sorted.map((page, index) => {
126
+ const prev = sorted[index - 1];
127
+ const next = sorted[index + 1];
128
+ const prevLink = prev ? { slug: prev.slug, title: prev.title } : null;
129
+ const nextLink = next ? { slug: next.slug, title: next.title } : null;
130
+ return {
131
+ ...page,
132
+ prev: prevLink,
133
+ next: nextLink,
134
+ toc: extractToc(page.content)
135
+ };
136
+ });
137
+ }
138
+ /**
139
+ * Loads the sidebar structure derived from the parsed Astro pages.
140
+ *
141
+ * @returns Sidebar navigation entries derived from the published pages.
142
+ */
143
+ async getSidebar() {
144
+ return createSidebar(this.pages);
145
+ }
146
+ /**
147
+ * Resolves a linked docs page by slug.
148
+ *
149
+ * @param slug - Target page slug.
150
+ * @returns The linked page or `null` when no page matches the slug.
151
+ */
152
+ async getPage(slug) {
153
+ return this.pages.find((page) => page.slug === slug) ?? null;
154
+ }
155
+ /**
156
+ * Returns all published pages managed by the provider.
157
+ *
158
+ * @returns Published pages in their linked navigation order.
159
+ */
160
+ async getAllPages() {
161
+ return this.pages.filter((page) => page.status === "published");
162
+ }
163
+ /**
164
+ * Searches the parsed Astro page set.
165
+ *
166
+ * @param query - User-entered search query.
167
+ * @returns Ranked search results derived from the published pages.
168
+ */
169
+ async search(query) {
170
+ const normalizedQuery = query.trim().toLowerCase();
171
+ if (!normalizedQuery) {
172
+ return [];
173
+ }
174
+ return this.pages.filter((page) => page.status === "published").map((page) => {
175
+ let score = 0;
176
+ if (page.title.toLowerCase().includes(normalizedQuery)) {
177
+ score += 10;
178
+ }
179
+ if (page.tags.some((tag) => tag.toLowerCase().includes(normalizedQuery))) {
180
+ score += 4;
181
+ }
182
+ if (page.content.toLowerCase().includes(normalizedQuery)) {
183
+ score += 2;
184
+ }
185
+ if (score === 0) {
186
+ return null;
187
+ }
188
+ return {
189
+ pageId: page.id,
190
+ pageTitle: page.title,
191
+ sectionTitle: sectionTitle(page.sectionId),
192
+ slug: page.slug,
193
+ highlight: highlightMatch(page.excerpt ?? page.content, query),
194
+ score
195
+ };
196
+ }).filter((result) => result !== null).sort((left, right) => right.score - left.score);
197
+ }
198
+ /**
199
+ * Resolves previous and next pages for a slug.
200
+ *
201
+ * @param slug - Target page slug.
202
+ * @returns Linked previous and next page records when available.
203
+ */
204
+ async getNavigation(slug) {
205
+ const page = this.pages.find((entry) => entry.slug === slug);
206
+ if (!page) {
207
+ return { prev: null, next: null };
208
+ }
209
+ return {
210
+ prev: page.prev ? this.pages.find((entry) => entry.slug === page.prev?.slug) ?? null : null,
211
+ next: page.next ? this.pages.find((entry) => entry.slug === page.next?.slug) ?? null : null
212
+ };
213
+ }
214
+ };
215
+
216
+ // src/providers/fumadocs.ts
217
+ function sectionTitle2(sectionId) {
218
+ return sectionId.split(/[-_/]/).filter(Boolean).map((part) => `${part[0]?.toUpperCase() ?? ""}${part.slice(1)}`).join(" ") || "General";
219
+ }
220
+ function asString2(value) {
221
+ return typeof value === "string" && value.trim().length > 0 ? value.trim() : void 0;
222
+ }
223
+ function asAccess2(value) {
224
+ if (value === "team" || value === "admin") {
225
+ return value;
226
+ }
227
+ return "public";
228
+ }
229
+ function asStatus2(value) {
230
+ if (value === "draft" || value === "archived") {
231
+ return value;
232
+ }
233
+ return "published";
234
+ }
235
+ function asTags2(value) {
236
+ if (Array.isArray(value)) {
237
+ return value.filter((entry) => typeof entry === "string");
238
+ }
239
+ if (typeof value === "string") {
240
+ return value.split(",").map((entry) => entry.trim()).filter(Boolean);
241
+ }
242
+ return [];
243
+ }
244
+ function createSidebar2(pages) {
245
+ const sections = /* @__PURE__ */ new Map();
246
+ for (const page of pages.filter((entry) => entry.status === "published")) {
247
+ const title = sectionTitle2(page.sectionId);
248
+ const existing = sections.get(page.sectionId) ?? {
249
+ id: page.sectionId,
250
+ title,
251
+ slug: slugify(title),
252
+ pages: []
253
+ };
254
+ existing.pages.push({ slug: page.slug, title: page.title });
255
+ sections.set(page.sectionId, existing);
256
+ }
257
+ return [...sections.values()];
258
+ }
259
+ var FumadocsDocsProvider = class {
260
+ pages = [];
261
+ tree = [];
262
+ /**
263
+ * Loads pages and an optional page tree from Fumadocs.
264
+ *
265
+ * @param pages - Source pages supplied by Fumadocs.
266
+ * @param tree - Optional source page tree for nested sidebar rendering.
267
+ * @returns Nothing. The provider page set is replaced in memory.
268
+ */
269
+ loadFromSource(pages, tree = []) {
270
+ this.tree = tree;
271
+ this.pages = this.linkPages(pages.map((page) => this.normalizePage(page)));
272
+ }
273
+ normalizePage(page) {
274
+ const slugParts = page.slugs ?? page.slug?.split("/") ?? [];
275
+ const slug = slugParts.join("/");
276
+ const sectionId = slugParts[0] ?? "general";
277
+ const title = page.data.title ?? slugParts[slugParts.length - 1] ?? slug;
278
+ const content = page.data.body ?? "";
279
+ const { wordCount, readingTime } = calcWordCount(content);
280
+ const now = (/* @__PURE__ */ new Date()).toISOString();
281
+ return {
282
+ id: slug,
283
+ title,
284
+ slug,
285
+ content,
286
+ excerpt: page.data.description,
287
+ sectionId,
288
+ order: page.data.order ?? 0,
289
+ author: {
290
+ name: page.data.author ?? "Geenius",
291
+ avatar: asString2(page.data.avatar)
292
+ },
293
+ lastEditedBy: asString2(page.data.lastModified ?? page.data.lastUpdated) ? {
294
+ name: page.data.author ?? "Geenius",
295
+ editedAt: asString2(page.data.lastModified ?? page.data.lastUpdated) ?? now
296
+ } : void 0,
297
+ version: asString2(page.data.version),
298
+ access: asAccess2(page.data.access),
299
+ tags: asTags2(page.data.tags),
300
+ status: page.data.draft === true ? "draft" : asStatus2(page.data.status),
301
+ createdAt: now,
302
+ updatedAt: asString2(page.data.lastModified ?? page.data.lastUpdated) ?? now,
303
+ wordCount,
304
+ readingTime,
305
+ viewCount: 0,
306
+ toc: page.data.toc ?? extractToc(content)
307
+ };
308
+ }
309
+ linkPages(pages) {
310
+ const sorted = [...pages].sort((left, right) => left.order - right.order);
311
+ return sorted.map((page, index) => {
312
+ const prev = sorted[index - 1];
313
+ const next = sorted[index + 1];
314
+ const prevLink = prev ? { slug: prev.slug, title: prev.title } : null;
315
+ const nextLink = next ? { slug: next.slug, title: next.title } : null;
316
+ return {
317
+ ...page,
318
+ prev: prevLink,
319
+ next: nextLink
320
+ };
321
+ });
322
+ }
323
+ treeToSidebar(nodes) {
324
+ return nodes.filter((node) => node.type === "folder").map((folder) => {
325
+ const title = folder.name ?? "Section";
326
+ const children = folder.children ?? [];
327
+ const pages = children.filter((child) => child.type === "page").map((child) => ({
328
+ slug: child.slug ?? "",
329
+ title: child.name ?? child.slug ?? "Untitled"
330
+ }));
331
+ const nestedChildren = this.treeToSidebar(
332
+ children.filter((child) => child.type === "folder")
333
+ );
334
+ return {
335
+ id: folder.slug ?? slugify(title),
336
+ title,
337
+ slug: folder.slug ?? slugify(title),
338
+ icon: folder.icon,
339
+ pages,
340
+ children: nestedChildren.length > 0 ? nestedChildren : void 0
341
+ };
342
+ });
343
+ }
344
+ /**
345
+ * Loads the sidebar structure derived from the Fumadocs tree or grouped pages.
346
+ *
347
+ * @returns Sidebar navigation entries derived from the published pages.
348
+ */
349
+ async getSidebar() {
350
+ if (this.tree.length > 0) {
351
+ return this.treeToSidebar(this.tree);
352
+ }
353
+ return createSidebar2(this.pages);
354
+ }
355
+ /**
356
+ * Resolves a linked docs page by slug.
357
+ *
358
+ * @param slug - Target page slug.
359
+ * @returns The linked page or `null` when no page matches the slug.
360
+ */
361
+ async getPage(slug) {
362
+ return this.pages.find((page) => page.slug === slug) ?? null;
363
+ }
364
+ /**
365
+ * Returns all published pages managed by the provider.
366
+ *
367
+ * @returns Published pages in their linked navigation order.
368
+ */
369
+ async getAllPages() {
370
+ return this.pages.filter((page) => page.status === "published");
371
+ }
372
+ /**
373
+ * Searches the provider-backed page set.
374
+ *
375
+ * @param query - User-entered search query.
376
+ * @returns Ranked search results derived from the published pages.
377
+ */
378
+ async search(query) {
379
+ const normalizedQuery = query.trim().toLowerCase();
380
+ if (!normalizedQuery) {
381
+ return [];
382
+ }
383
+ return this.pages.filter((page) => page.status === "published").map((page) => {
384
+ let score = 0;
385
+ if (page.title.toLowerCase().includes(normalizedQuery)) {
386
+ score += 10;
387
+ }
388
+ if (page.tags.some((tag) => tag.toLowerCase().includes(normalizedQuery))) {
389
+ score += 4;
390
+ }
391
+ if (page.content.toLowerCase().includes(normalizedQuery)) {
392
+ score += 2;
393
+ }
394
+ if (page.excerpt?.toLowerCase().includes(normalizedQuery)) {
395
+ score += 1;
396
+ }
397
+ if (score === 0) {
398
+ return null;
399
+ }
400
+ return {
401
+ pageId: page.id,
402
+ pageTitle: page.title,
403
+ sectionTitle: sectionTitle2(page.sectionId),
404
+ slug: page.slug,
405
+ highlight: highlightMatch(page.excerpt ?? page.content, query),
406
+ score
407
+ };
408
+ }).filter((result) => result !== null).sort((left, right) => right.score - left.score);
409
+ }
410
+ /**
411
+ * Resolves previous and next pages for a slug.
412
+ *
413
+ * @param slug - Target page slug.
414
+ * @returns Linked previous and next page records when available.
415
+ */
416
+ async getNavigation(slug) {
417
+ const page = this.pages.find((entry) => entry.slug === slug);
418
+ if (!page) {
419
+ return { prev: null, next: null };
420
+ }
421
+ return {
422
+ prev: page.prev ? this.pages.find((entry) => entry.slug === page.prev?.slug) ?? null : null,
423
+ next: page.next ? this.pages.find((entry) => entry.slug === page.next?.slug) ?? null : null
424
+ };
425
+ }
426
+ };
427
+
428
+ // src/providers/internal.ts
429
+ function sectionTitle3(sectionId) {
430
+ return sectionId.split(/[-_/]/).filter(Boolean).map((part) => `${part[0]?.toUpperCase() ?? ""}${part.slice(1)}`).join(" ") || "General";
431
+ }
432
+ function createSidebar3(pages) {
433
+ const sections = /* @__PURE__ */ new Map();
434
+ for (const page of pages.filter((entry) => entry.status === "published")) {
435
+ const title = sectionTitle3(page.sectionId);
436
+ const entry = sections.get(page.sectionId) ?? {
437
+ id: page.sectionId,
438
+ title,
439
+ slug: slugify(title),
440
+ pages: []
441
+ };
442
+ entry.pages.push({ slug: page.slug, title: page.title });
443
+ sections.set(page.sectionId, entry);
444
+ }
445
+ return [...sections.values()].map((entry) => ({
446
+ ...entry,
447
+ pages: [...entry.pages].sort(
448
+ (left, right) => left.title.localeCompare(right.title)
449
+ )
450
+ }));
451
+ }
452
+ var InternalDocsProvider = class {
453
+ pages = [];
454
+ /**
455
+ * @param pages - Optional initial page records to seed the provider with.
456
+ */
457
+ constructor(pages = []) {
458
+ this.pages = this.linkPages(pages);
459
+ }
460
+ /**
461
+ * Replaces the provider's page set.
462
+ *
463
+ * @param pages - Fresh page records to seed into the provider.
464
+ * @returns Nothing. The provider page set is replaced in memory.
465
+ */
466
+ setPages(pages) {
467
+ this.pages = this.linkPages(pages);
468
+ }
469
+ linkPages(pages) {
470
+ const sorted = [...pages].sort((left, right) => left.order - right.order);
471
+ return sorted.map((page, index) => {
472
+ const prev = sorted[index - 1];
473
+ const next = sorted[index + 1];
474
+ const prevLink = prev ? { slug: prev.slug, title: prev.title } : null;
475
+ const nextLink = next ? { slug: next.slug, title: next.title } : null;
476
+ return {
477
+ ...page,
478
+ prev: prevLink,
479
+ next: nextLink,
480
+ toc: extractToc(page.content)
481
+ };
482
+ });
483
+ }
484
+ /**
485
+ * Loads the sidebar structure derived from the current page set.
486
+ *
487
+ * @returns Sidebar navigation entries derived from the published pages.
488
+ */
489
+ async getSidebar() {
490
+ return createSidebar3(this.pages);
491
+ }
492
+ /**
493
+ * Resolves a linked docs page by slug.
494
+ *
495
+ * @param slug - Target page slug.
496
+ * @returns The linked page or `null` when no page matches the slug.
497
+ */
498
+ async getPage(slug) {
499
+ return this.pages.find((page) => page.slug === slug) ?? null;
500
+ }
501
+ /**
502
+ * Returns all published pages managed by the provider.
503
+ *
504
+ * @returns Published pages in their linked navigation order.
505
+ */
506
+ async getAllPages() {
507
+ return this.pages.filter((page) => page.status === "published");
508
+ }
509
+ /**
510
+ * Searches the provider-backed page set.
511
+ *
512
+ * @param query - User-entered search query.
513
+ * @returns Ranked search results derived from the published pages.
514
+ */
515
+ async search(query) {
516
+ const normalizedQuery = query.trim().toLowerCase();
517
+ if (!normalizedQuery) {
518
+ return [];
519
+ }
520
+ return this.pages.filter((page) => page.status === "published").map((page) => {
521
+ let score = 0;
522
+ if (page.title.toLowerCase().includes(normalizedQuery)) {
523
+ score += 10;
524
+ }
525
+ if (page.tags.some((tag) => tag.toLowerCase().includes(normalizedQuery))) {
526
+ score += 4;
527
+ }
528
+ if (page.content.toLowerCase().includes(normalizedQuery)) {
529
+ score += 2;
530
+ }
531
+ if (score === 0) {
532
+ return null;
533
+ }
534
+ return {
535
+ pageId: page.id,
536
+ pageTitle: page.title,
537
+ sectionTitle: sectionTitle3(page.sectionId),
538
+ slug: page.slug,
539
+ highlight: highlightMatch(page.excerpt ?? page.content, query),
540
+ score
541
+ };
542
+ }).filter((result) => result !== null).sort((left, right) => right.score - left.score);
543
+ }
544
+ /**
545
+ * Resolves previous and next pages for a slug.
546
+ *
547
+ * @param slug - Target page slug.
548
+ * @returns Linked previous and next page records when available.
549
+ */
550
+ async getNavigation(slug) {
551
+ const page = this.pages.find((entry) => entry.slug === slug);
552
+ if (!page) {
553
+ return { prev: null, next: null };
554
+ }
555
+ return {
556
+ prev: page.prev ? this.pages.find((entry) => entry.slug === page.prev?.slug) ?? null : null,
557
+ next: page.next ? this.pages.find((entry) => entry.slug === page.next?.slug) ?? null : null
558
+ };
559
+ }
560
+ };
561
+
562
+ export { AstroDocsProvider, FumadocsDocsProvider, InternalDocsProvider };
563
+ //# sourceMappingURL=providers.js.map
564
+ //# sourceMappingURL=providers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/providers/astro.ts","../src/providers/fumadocs.ts","../src/providers/internal.ts"],"names":["sectionTitle","asString","asAccess","asStatus","asTags","createSidebar"],"mappings":"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","file":"providers.js","sourcesContent":["/**\n * @module astroDocsProvider\n * @package @geenius/docs-shared\n * @description Implements the Astro-oriented provider used to normalise Markdown\n * and MDX files discovered from Astro content collections into the shared docs\n * contract consumed by the framework variants.\n */\n\nimport matter from 'gray-matter'\n\nimport type {\n DocAccess,\n DocNavigationLink,\n DocPage,\n DocStatus,\n DocsPage,\n DocsProvider,\n DocsSearchResult,\n DocsSidebar,\n DocsSidebarItem,\n} from '../types'\nimport { calcWordCount, extractToc, highlightMatch, slugify } from '../utilities'\n\nfunction sectionTitle(sectionId: string): string {\n return sectionId\n .split(/[-_/]/)\n .filter(Boolean)\n .map((part) => `${part[0]?.toUpperCase() ?? ''}${part.slice(1)}`)\n .join(' ') || 'General'\n}\n\nfunction asString(value: unknown): string | undefined {\n return typeof value === 'string' && value.trim().length > 0\n ? value.trim()\n : undefined\n}\n\nfunction asNumber(value: unknown): number {\n if (typeof value === 'number' && Number.isFinite(value)) {\n return value\n }\n\n if (typeof value === 'string') {\n const parsed = Number.parseInt(value, 10)\n if (Number.isFinite(parsed)) {\n return parsed\n }\n }\n\n return 0\n}\n\nfunction asAccess(value: unknown): DocAccess {\n if (value === 'team' || value === 'admin') {\n return value\n }\n\n return 'public'\n}\n\nfunction asStatus(value: unknown): DocStatus {\n if (value === 'draft' || value === 'archived') {\n return value\n }\n\n return 'published'\n}\n\nfunction asTags(value: unknown): string[] {\n if (Array.isArray(value)) {\n return value.filter((entry): entry is string => typeof entry === 'string')\n }\n\n if (typeof value === 'string') {\n return value\n .split(',')\n .map((entry) => entry.trim())\n .filter(Boolean)\n }\n\n return []\n}\n\nfunction createSidebar(pages: DocsPage[]): DocsSidebar {\n const sections = new Map<string, DocsSidebarItem>()\n\n for (const page of pages.filter((entry) => entry.status === 'published')) {\n const title = sectionTitle(page.sectionId)\n const existing = sections.get(page.sectionId) ?? {\n id: page.sectionId,\n title,\n slug: slugify(title),\n pages: [],\n }\n\n existing.pages.push({ slug: page.slug, title: page.title })\n sections.set(page.sectionId, existing)\n }\n\n return [...sections.values()]\n}\n\n/**\n * Normalises Astro Markdown and MDX files into the shared docs contract.\n */\nexport class AstroDocsProvider implements DocsProvider {\n private pages: DocsPage[] = []\n\n /**\n * Loads docs from an Astro-style `import.meta.glob()` result.\n *\n * @param globResult - Lazy or eager Astro content loaders keyed by path.\n * @returns Nothing. The provider page set is replaced in memory.\n */\n async loadFromGlob(\n globResult: Record<string, (() => Promise<string>) | string>,\n ): Promise<void> {\n const parsed = await Promise.all(\n Object.entries(globResult).map(async ([path, loader]) => {\n const raw = typeof loader === 'function' ? await loader() : loader\n return this.parseDoc(path, raw)\n }),\n )\n\n this.pages = this.linkPages(parsed)\n }\n\n /**\n * Loads docs from already-read file contents.\n *\n * @param files - File path and content pairs to normalise.\n * @returns Nothing. The provider page set is replaced in memory.\n */\n async loadFromFiles(\n files: Array<{ path: string; content: string }>,\n ): Promise<void> {\n this.pages = this.linkPages(\n files.map((file) => this.parseDoc(file.path, file.content)),\n )\n }\n\n private parseDoc(path: string, raw: string): DocPage {\n const parsed = matter(raw)\n const pathParts = path\n .replace(/.*content\\/docs\\//, '')\n .replace(/\\.(mdx?|md)$/, '')\n .split('/')\n .filter(Boolean)\n const slug = pathParts.join('/')\n const sectionId = pathParts[0] ?? 'general'\n const titleFromPath = pathParts[pathParts.length - 1] ?? slug\n const { wordCount, readingTime } = calcWordCount(parsed.content)\n const authorName = asString(parsed.data.author) ?? 'Geenius'\n const now = new Date().toISOString()\n const status = parsed.data.draft === true\n ? 'draft'\n : asStatus(parsed.data.status)\n\n return {\n id: asString(parsed.data.id) ?? slug,\n title: asString(parsed.data.title) ?? sectionTitle(titleFromPath),\n slug,\n content: parsed.content,\n excerpt: asString(parsed.data.description),\n sectionId,\n order: asNumber(parsed.data.order),\n author: {\n name: authorName,\n avatar: asString(parsed.data.avatar),\n },\n lastEditedBy: asString(parsed.data.lastEditedBy)\n ? {\n name: asString(parsed.data.lastEditedBy) ?? authorName,\n editedAt: asString(parsed.data.lastEditedAt) ?? now,\n }\n : undefined,\n version: asString(parsed.data.version),\n access: asAccess(parsed.data.access),\n tags: asTags(parsed.data.tags),\n status,\n createdAt: asString(parsed.data.createdAt) ?? now,\n updatedAt: asString(parsed.data.updatedAt) ?? now,\n wordCount,\n readingTime,\n viewCount: asNumber(parsed.data.viewCount),\n }\n }\n\n private linkPages(pages: DocPage[]): DocsPage[] {\n const sorted = [...pages].sort((left, right) => left.order - right.order)\n\n return sorted.map((page, index) => {\n const prev = sorted[index - 1]\n const next = sorted[index + 1]\n const prevLink: DocNavigationLink | null = prev\n ? { slug: prev.slug, title: prev.title }\n : null\n const nextLink: DocNavigationLink | null = next\n ? { slug: next.slug, title: next.title }\n : null\n\n return {\n ...page,\n prev: prevLink,\n next: nextLink,\n toc: extractToc(page.content),\n }\n })\n }\n\n /**\n * Loads the sidebar structure derived from the parsed Astro pages.\n *\n * @returns Sidebar navigation entries derived from the published pages.\n */\n async getSidebar(): Promise<DocsSidebar> {\n return createSidebar(this.pages)\n }\n\n /**\n * Resolves a linked docs page by slug.\n *\n * @param slug - Target page slug.\n * @returns The linked page or `null` when no page matches the slug.\n */\n async getPage(slug: string): Promise<DocsPage | null> {\n return this.pages.find((page) => page.slug === slug) ?? null\n }\n\n /**\n * Returns all published pages managed by the provider.\n *\n * @returns Published pages in their linked navigation order.\n */\n async getAllPages(): Promise<DocsPage[]> {\n return this.pages.filter((page) => page.status === 'published')\n }\n\n /**\n * Searches the parsed Astro page set.\n *\n * @param query - User-entered search query.\n * @returns Ranked search results derived from the published pages.\n */\n async search(query: string): Promise<DocsSearchResult[]> {\n const normalizedQuery = query.trim().toLowerCase()\n\n if (!normalizedQuery) {\n return []\n }\n\n return this.pages\n .filter((page) => page.status === 'published')\n .map((page) => {\n let score = 0\n\n if (page.title.toLowerCase().includes(normalizedQuery)) {\n score += 10\n }\n if (page.tags.some((tag) => tag.toLowerCase().includes(normalizedQuery))) {\n score += 4\n }\n if (page.content.toLowerCase().includes(normalizedQuery)) {\n score += 2\n }\n if (score === 0) {\n return null\n }\n\n return {\n pageId: page.id,\n pageTitle: page.title,\n sectionTitle: sectionTitle(page.sectionId),\n slug: page.slug,\n highlight: highlightMatch(page.excerpt ?? page.content, query),\n score,\n }\n })\n .filter((result): result is DocsSearchResult => result !== null)\n .sort((left, right) => right.score - left.score)\n }\n\n /**\n * Resolves previous and next pages for a slug.\n *\n * @param slug - Target page slug.\n * @returns Linked previous and next page records when available.\n */\n async getNavigation(\n slug: string,\n ): Promise<{ prev: DocsPage | null; next: DocsPage | null }> {\n const page = this.pages.find((entry) => entry.slug === slug)\n\n if (!page) {\n return { prev: null, next: null }\n }\n\n return {\n prev: page.prev\n ? this.pages.find((entry) => entry.slug === page.prev?.slug) ?? null\n : null,\n next: page.next\n ? this.pages.find((entry) => entry.slug === page.next?.slug) ?? null\n : null,\n }\n }\n}\n","/**\n * @module fumadocsProvider\n * @package @geenius/docs-shared\n * @description Implements the Fumadocs-backed provider used to normalise\n * source pages and page-tree metadata from Fumadocs into the shared docs\n * contract consumed by the framework variants.\n */\n\nimport type {\n DocAccess,\n DocNavigationLink,\n DocStatus,\n DocsPage,\n DocsProvider,\n DocsSearchResult,\n DocsSidebar,\n DocsSidebarItem,\n TocItem,\n} from '../types'\nimport { calcWordCount, extractToc, highlightMatch, slugify } from '../utilities'\n\nfunction sectionTitle(sectionId: string): string {\n return sectionId\n .split(/[-_/]/)\n .filter(Boolean)\n .map((part) => `${part[0]?.toUpperCase() ?? ''}${part.slice(1)}`)\n .join(' ') || 'General'\n}\n\nfunction asString(value: unknown): string | undefined {\n return typeof value === 'string' && value.trim().length > 0\n ? value.trim()\n : undefined\n}\n\nfunction _asNumber(value: unknown): number {\n if (typeof value === 'number' && Number.isFinite(value)) {\n return value\n }\n\n return 0\n}\n\nfunction asAccess(value: unknown): DocAccess {\n if (value === 'team' || value === 'admin') {\n return value\n }\n\n return 'public'\n}\n\nfunction asStatus(value: unknown): DocStatus {\n if (value === 'draft' || value === 'archived') {\n return value\n }\n\n return 'published'\n}\n\nfunction asTags(value: unknown): string[] {\n if (Array.isArray(value)) {\n return value.filter((entry): entry is string => typeof entry === 'string')\n }\n\n if (typeof value === 'string') {\n return value\n .split(',')\n .map((entry) => entry.trim())\n .filter(Boolean)\n }\n\n return []\n}\n\nfunction createSidebar(pages: DocsPage[]): DocsSidebar {\n const sections = new Map<string, DocsSidebarItem>()\n\n for (const page of pages.filter((entry) => entry.status === 'published')) {\n const title = sectionTitle(page.sectionId)\n const existing = sections.get(page.sectionId) ?? {\n id: page.sectionId,\n title,\n slug: slugify(title),\n pages: [],\n }\n\n existing.pages.push({ slug: page.slug, title: page.title })\n sections.set(page.sectionId, existing)\n }\n\n return [...sections.values()]\n}\n\n/**\n * Fumadocs source-page shape accepted by the provider.\n */\nexport interface FumadocsSourcePage {\n slug?: string\n slugs?: string[]\n url?: string\n data: {\n title?: string\n description?: string\n body?: string\n icon?: string\n order?: number\n toc?: TocItem[]\n draft?: boolean\n status?: DocStatus\n access?: DocAccess\n author?: string\n avatar?: string\n tags?: string[] | string\n version?: string\n lastModified?: string\n lastUpdated?: string\n [key: string]: unknown\n }\n}\n\n/**\n * Fumadocs tree-node shape accepted by the provider.\n */\nexport interface FumadocsTreeNode {\n type: 'page' | 'folder' | 'separator'\n name?: string\n slug?: string\n icon?: string\n children?: FumadocsTreeNode[]\n}\n\n/**\n * Fumadocs provider that bridges source pages and trees into the shared docs contract.\n */\nexport class FumadocsDocsProvider implements DocsProvider {\n private pages: DocsPage[] = []\n private tree: FumadocsTreeNode[] = []\n\n /**\n * Loads pages and an optional page tree from Fumadocs.\n *\n * @param pages - Source pages supplied by Fumadocs.\n * @param tree - Optional source page tree for nested sidebar rendering.\n * @returns Nothing. The provider page set is replaced in memory.\n */\n loadFromSource(\n pages: FumadocsSourcePage[],\n tree: FumadocsTreeNode[] = [],\n ): void {\n this.tree = tree\n this.pages = this.linkPages(pages.map((page) => this.normalizePage(page)))\n }\n\n private normalizePage(page: FumadocsSourcePage): DocsPage {\n const slugParts = page.slugs ?? page.slug?.split('/') ?? []\n const slug = slugParts.join('/')\n const sectionId = slugParts[0] ?? 'general'\n const title = page.data.title ?? slugParts[slugParts.length - 1] ?? slug\n const content = page.data.body ?? ''\n const { wordCount, readingTime } = calcWordCount(content)\n const now = new Date().toISOString()\n\n return {\n id: slug,\n title,\n slug,\n content,\n excerpt: page.data.description,\n sectionId,\n order: page.data.order ?? 0,\n author: {\n name: page.data.author ?? 'Geenius',\n avatar: asString(page.data.avatar),\n },\n lastEditedBy: asString(page.data.lastModified ?? page.data.lastUpdated)\n ? {\n name: page.data.author ?? 'Geenius',\n editedAt: asString(page.data.lastModified ?? page.data.lastUpdated) ?? now,\n }\n : undefined,\n version: asString(page.data.version),\n access: asAccess(page.data.access),\n tags: asTags(page.data.tags),\n status: page.data.draft === true\n ? 'draft'\n : asStatus(page.data.status),\n createdAt: now,\n updatedAt: asString(page.data.lastModified ?? page.data.lastUpdated) ?? now,\n wordCount,\n readingTime,\n viewCount: 0,\n toc: page.data.toc ?? extractToc(content),\n }\n }\n\n private linkPages(pages: DocsPage[]): DocsPage[] {\n const sorted = [...pages].sort((left, right) => left.order - right.order)\n\n return sorted.map((page, index) => {\n const prev = sorted[index - 1]\n const next = sorted[index + 1]\n const prevLink: DocNavigationLink | null = prev\n ? { slug: prev.slug, title: prev.title }\n : null\n const nextLink: DocNavigationLink | null = next\n ? { slug: next.slug, title: next.title }\n : null\n\n return {\n ...page,\n prev: prevLink,\n next: nextLink,\n }\n })\n }\n\n private treeToSidebar(nodes: FumadocsTreeNode[]): DocsSidebar {\n return nodes\n .filter((node) => node.type === 'folder')\n .map((folder) => {\n const title = folder.name ?? 'Section'\n const children = folder.children ?? []\n const pages = children\n .filter((child) => child.type === 'page')\n .map((child) => ({\n slug: child.slug ?? '',\n title: child.name ?? child.slug ?? 'Untitled',\n }))\n const nestedChildren = this.treeToSidebar(\n children.filter((child) => child.type === 'folder'),\n )\n\n return {\n id: folder.slug ?? slugify(title),\n title,\n slug: folder.slug ?? slugify(title),\n icon: folder.icon,\n pages,\n children: nestedChildren.length > 0 ? nestedChildren : undefined,\n }\n })\n }\n\n /**\n * Loads the sidebar structure derived from the Fumadocs tree or grouped pages.\n *\n * @returns Sidebar navigation entries derived from the published pages.\n */\n async getSidebar(): Promise<DocsSidebar> {\n if (this.tree.length > 0) {\n return this.treeToSidebar(this.tree)\n }\n\n return createSidebar(this.pages)\n }\n\n /**\n * Resolves a linked docs page by slug.\n *\n * @param slug - Target page slug.\n * @returns The linked page or `null` when no page matches the slug.\n */\n async getPage(slug: string): Promise<DocsPage | null> {\n return this.pages.find((page) => page.slug === slug) ?? null\n }\n\n /**\n * Returns all published pages managed by the provider.\n *\n * @returns Published pages in their linked navigation order.\n */\n async getAllPages(): Promise<DocsPage[]> {\n return this.pages.filter((page) => page.status === 'published')\n }\n\n /**\n * Searches the provider-backed page set.\n *\n * @param query - User-entered search query.\n * @returns Ranked search results derived from the published pages.\n */\n async search(query: string): Promise<DocsSearchResult[]> {\n const normalizedQuery = query.trim().toLowerCase()\n\n if (!normalizedQuery) {\n return []\n }\n\n return this.pages\n .filter((page) => page.status === 'published')\n .map((page) => {\n let score = 0\n\n if (page.title.toLowerCase().includes(normalizedQuery)) {\n score += 10\n }\n if (page.tags.some((tag) => tag.toLowerCase().includes(normalizedQuery))) {\n score += 4\n }\n if (page.content.toLowerCase().includes(normalizedQuery)) {\n score += 2\n }\n if (page.excerpt?.toLowerCase().includes(normalizedQuery)) {\n score += 1\n }\n if (score === 0) {\n return null\n }\n\n return {\n pageId: page.id,\n pageTitle: page.title,\n sectionTitle: sectionTitle(page.sectionId),\n slug: page.slug,\n highlight: highlightMatch(page.excerpt ?? page.content, query),\n score,\n }\n })\n .filter((result): result is DocsSearchResult => result !== null)\n .sort((left, right) => right.score - left.score)\n }\n\n /**\n * Resolves previous and next pages for a slug.\n *\n * @param slug - Target page slug.\n * @returns Linked previous and next page records when available.\n */\n async getNavigation(\n slug: string,\n ): Promise<{ prev: DocsPage | null; next: DocsPage | null }> {\n const page = this.pages.find((entry) => entry.slug === slug)\n\n if (!page) {\n return { prev: null, next: null }\n }\n\n return {\n prev: page.prev\n ? this.pages.find((entry) => entry.slug === page.prev?.slug) ?? null\n : null,\n next: page.next\n ? this.pages.find((entry) => entry.slug === page.next?.slug) ?? null\n : null,\n }\n }\n}\n","/**\n * @module internalDocsProvider\n * @package @geenius/docs-shared\n * @description Implements the in-memory docs provider used by local fixtures,\n * tests, and apps that already have page records loaded in process memory.\n */\n\nimport type {\n DocNavigationLink,\n DocPage,\n DocsPage,\n DocsProvider,\n DocsSearchResult,\n DocsSidebar,\n DocsSidebarItem,\n} from '../types'\nimport { extractToc, highlightMatch, slugify } from '../utilities'\n\nfunction sectionTitle(sectionId: string): string {\n return sectionId\n .split(/[-_/]/)\n .filter(Boolean)\n .map((part) => `${part[0]?.toUpperCase() ?? ''}${part.slice(1)}`)\n .join(' ') || 'General'\n}\n\nfunction createSidebar(pages: DocsPage[]): DocsSidebar {\n const sections = new Map<string, DocsSidebarItem>()\n\n for (const page of pages.filter((entry) => entry.status === 'published')) {\n const title = sectionTitle(page.sectionId)\n const entry = sections.get(page.sectionId) ?? {\n id: page.sectionId,\n title,\n slug: slugify(title),\n pages: [],\n }\n\n entry.pages.push({ slug: page.slug, title: page.title })\n sections.set(page.sectionId, entry)\n }\n\n return [...sections.values()].map((entry) => ({\n ...entry,\n pages: [...entry.pages].sort((left, right) =>\n left.title.localeCompare(right.title),\n ),\n }))\n}\n\n/**\n * In-memory provider for already-hydrated docs pages.\n */\nexport class InternalDocsProvider implements DocsProvider {\n private pages: DocsPage[] = []\n\n /**\n * @param pages - Optional initial page records to seed the provider with.\n */\n constructor(pages: DocPage[] = []) {\n this.pages = this.linkPages(pages)\n }\n\n /**\n * Replaces the provider's page set.\n *\n * @param pages - Fresh page records to seed into the provider.\n * @returns Nothing. The provider page set is replaced in memory.\n */\n setPages(pages: DocPage[]): void {\n this.pages = this.linkPages(pages)\n }\n\n private linkPages(pages: DocPage[]): DocsPage[] {\n const sorted = [...pages].sort((left, right) => left.order - right.order)\n\n return sorted.map((page, index) => {\n const prev = sorted[index - 1]\n const next = sorted[index + 1]\n const prevLink: DocNavigationLink | null = prev\n ? { slug: prev.slug, title: prev.title }\n : null\n const nextLink: DocNavigationLink | null = next\n ? { slug: next.slug, title: next.title }\n : null\n\n return {\n ...page,\n prev: prevLink,\n next: nextLink,\n toc: extractToc(page.content),\n }\n })\n }\n\n /**\n * Loads the sidebar structure derived from the current page set.\n *\n * @returns Sidebar navigation entries derived from the published pages.\n */\n async getSidebar(): Promise<DocsSidebar> {\n return createSidebar(this.pages)\n }\n\n /**\n * Resolves a linked docs page by slug.\n *\n * @param slug - Target page slug.\n * @returns The linked page or `null` when no page matches the slug.\n */\n async getPage(slug: string): Promise<DocsPage | null> {\n return this.pages.find((page) => page.slug === slug) ?? null\n }\n\n /**\n * Returns all published pages managed by the provider.\n *\n * @returns Published pages in their linked navigation order.\n */\n async getAllPages(): Promise<DocsPage[]> {\n return this.pages.filter((page) => page.status === 'published')\n }\n\n /**\n * Searches the provider-backed page set.\n *\n * @param query - User-entered search query.\n * @returns Ranked search results derived from the published pages.\n */\n async search(query: string): Promise<DocsSearchResult[]> {\n const normalizedQuery = query.trim().toLowerCase()\n\n if (!normalizedQuery) {\n return []\n }\n\n return this.pages\n .filter((page) => page.status === 'published')\n .map((page) => {\n let score = 0\n\n if (page.title.toLowerCase().includes(normalizedQuery)) {\n score += 10\n }\n if (page.tags.some((tag) => tag.toLowerCase().includes(normalizedQuery))) {\n score += 4\n }\n if (page.content.toLowerCase().includes(normalizedQuery)) {\n score += 2\n }\n if (score === 0) {\n return null\n }\n\n return {\n pageId: page.id,\n pageTitle: page.title,\n sectionTitle: sectionTitle(page.sectionId),\n slug: page.slug,\n highlight: highlightMatch(page.excerpt ?? page.content, query),\n score,\n }\n })\n .filter((result): result is DocsSearchResult => result !== null)\n .sort((left, right) => right.score - left.score)\n }\n\n /**\n * Resolves previous and next pages for a slug.\n *\n * @param slug - Target page slug.\n * @returns Linked previous and next page records when available.\n */\n async getNavigation(\n slug: string,\n ): Promise<{ prev: DocsPage | null; next: DocsPage | null }> {\n const page = this.pages.find((entry) => entry.slug === slug)\n\n if (!page) {\n return { prev: null, next: null }\n }\n\n return {\n prev: page.prev\n ? this.pages.find((entry) => entry.slug === page.prev?.slug) ?? null\n : null,\n next: page.next\n ? this.pages.find((entry) => entry.slug === page.next?.slug) ?? null\n : null,\n }\n }\n}\n"]}