forked from CopilotKit/CopilotKit
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathreference-items.ts
More file actions
134 lines (122 loc) · 4.36 KB
/
Copy pathreference-items.ts
File metadata and controls
134 lines (122 loc) · 4.36 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
// Shared helpers for walking the `src/content/reference/` tree. Used by
// both /reference (index page) and /reference/[...slug] so the two stay
// in sync: same subdirs, same recursive traversal, same gray-matter
// handling, same caching behavior.
import fs from "fs";
import path from "path";
import matter from "gray-matter";
export const REFERENCE_CONTENT_DIR = path.join(
process.cwd(),
"src/content/reference",
);
// Top-level reference categories we index. Anything outside this list is
// ignored (e.g. a stray snippet file at the root).
export const REFERENCE_SUBDIRS = ["components", "hooks"] as const;
export type ReferenceSubdir = (typeof REFERENCE_SUBDIRS)[number];
export type ReferenceItem = {
/** subdir-relative slug, e.g. `components/chat` or `components/inputs/textarea`. */
slug: string;
title: string;
description?: string;
category: "Components" | "Hooks";
};
function categoryFor(subdir: ReferenceSubdir): "Components" | "Hooks" {
return subdir === "components" ? "Components" : "Hooks";
}
/**
* Recursively collect all `.mdx` files under `dir` and return their paths
* relative to `dir` (without the `.mdx` extension). Silently skips
* unreadable subdirectories so a single EACCES doesn't break the build.
*/
function walkMdx(dir: string, prefix: string = ""): string[] {
let entries: fs.Dirent[];
try {
entries = fs.readdirSync(dir, { withFileTypes: true });
} catch (err) {
console.error(`[reference-items] Failed to read dir ${dir}:`, err);
return [];
}
const out: string[] = [];
for (const entry of entries) {
if (entry.name.startsWith(".")) continue;
const childAbs = path.join(dir, entry.name);
const childRel = prefix ? `${prefix}/${entry.name}` : entry.name;
if (entry.isDirectory()) {
out.push(...walkMdx(childAbs, childRel));
} else if (entry.isFile() && entry.name.endsWith(".mdx")) {
out.push(childRel.replace(/\.mdx$/, ""));
}
}
return out;
}
/**
* Load items from a single reference subdir, recursing into subfolders.
* Malformed frontmatter on any file is logged and skipped — we never
* crash the whole index just because one page has a bad YAML block.
*/
function loadSubdirItems(subdir: ReferenceSubdir): ReferenceItem[] {
const dir = path.join(REFERENCE_CONTENT_DIR, subdir);
if (!fs.existsSync(dir)) return [];
const items: ReferenceItem[] = [];
for (const relSlug of walkMdx(dir)) {
const filePath = path.join(dir, `${relSlug}.mdx`);
let raw: string;
try {
raw = fs.readFileSync(filePath, "utf-8");
} catch (err) {
console.error(`[reference-items] Failed to read ${filePath}:`, err);
continue;
}
let data: Record<string, unknown> = {};
try {
({ data } = matter(raw));
} catch (err) {
console.error(
`[reference-items] Failed to parse frontmatter in ${filePath}:`,
err,
);
continue;
}
const fallbackTitle = relSlug.split("/").pop() ?? relSlug;
items.push({
slug: `${subdir}/${relSlug}`,
title:
typeof data.title === "string" && data.title.length > 0
? data.title
: fallbackTitle,
description:
typeof data.description === "string" ? data.description : undefined,
category: categoryFor(subdir),
});
}
return items;
}
// In-memory cache — keyed by subdir, rebuilt once per process in prod. In
// dev we skip the cache so MDX edits show up without a server restart.
const __itemsCache = new Map<ReferenceSubdir, ReferenceItem[]>();
function isProd(): boolean {
return process.env.NODE_ENV === "production";
}
export function loadReferenceItems(subdir: ReferenceSubdir): ReferenceItem[] {
if (isProd()) {
const cached = __itemsCache.get(subdir);
if (cached) return cached;
}
const items = loadSubdirItems(subdir);
if (isProd()) __itemsCache.set(subdir, items);
return items;
}
export function loadAllReferenceItems(): ReferenceItem[] {
return REFERENCE_SUBDIRS.flatMap((s) => loadReferenceItems(s));
}
/**
* For `generateStaticParams`: return every reference page as its Next.js
* catch-all slug array. Recursive (unlike the previous one-level-only
* implementation), so subfolder docs like `components/inputs/textarea`
* are statically generated too.
*/
export function referenceStaticParams(): { slug: string[] }[] {
return loadAllReferenceItems().map((item) => ({
slug: item.slug.split("/"),
}));
}