feat: custom loader

This commit is contained in:
TrèsAbhi committed 2026-01-16 19:28:10 -06:00
1 parent fc4d8b5ad0
commit 369ac113fa
4 files changed
+60 -40

No files matched your search

+38
View File
@@ -0,0 +1,38 @@
import { glob } from "astro/loaders";
import { z } from "astro/zod";
import { defineCollection } from "astro:content";
const api = defineCollection({
loader() {
const globbed = import.meta.glob("./pages/api/**/*.ts", {
eager: true,
query: "?raw",
import: "default",
});
const paths: { id: string; body: string }[] = [];
for (const path in globbed) {
const id = path.replace("./pages/api/", "").replace(".ts", "");
const body = (globbed[path] as string).replaceAll("\r\n", "\n");
const docs = body.match(
/\/\*\*\n((( \*.*)\n)+) \*\/\nexport (async )?function GET\(/
)?[1].spl;
paths.push({ id, body, docs: docs?.[1] ?? undefined });
}
return paths;
},
schema: z.object({
body: z.string(),
docs: z.optional(z.string()),
}),
});
const docs = defineCollection({
loader: glob({ base: "../../docs", pattern: "**/*.md" }),
});
export const collections = { api, docs };
@@ -1,61 +1,32 @@
--- ---
import "@radix-ui/colors/amber-dark.css"; import "@radix-ui/colors/amber-dark.css";
import { import { getCollection } from "astro:content";
createProgram,
displayPartsToString,
forEachChild,
isFunctionDeclaration,
} from "typescript";
import BaseLayout from "../../../layouts/BaseLayout.astro"; import BaseLayout from "../../../layouts/BaseLayout.astro";
export { getStaticPaths } from "../index.astro"; export { getStaticPaths } from "../index.astro";
const { locale } = Astro.props; const { locale } = Astro.props;
const root = `/src/pages/api`; const collection = await getCollection("api");
const globbed = import.meta.glob("/src/pages/api/**/*", {
eager: true, console.log(collection);
query: "?raw",
import: "default",
});
const paths: { const paths: {
path: string; path: string;
documentation: string; documentation: string;
}[] = []; }[] = [];
for (const fullPath in globbed) {
const relativePath = `.${fullPath}`;
const path = fullPath.slice(root.length + 1, -3);
const program = createProgram([relativePath], {});
const source = program.getSourceFile(relativePath);
if (!source) throw new Error(`Could not find source for ${fullPath}`);
const checker = program.getTypeChecker();
const getter = forEachChild(source, (node) => {
if (!isFunctionDeclaration(node) || node.name?.text !== "GET") return;
return checker.getSymbolAtLocation(node.name);
});
const documentationComment = getter?.getDocumentationComment(checker);
if (!documentationComment) continue;
const documentation = displayPartsToString(documentationComment);
if (documentation.length === 0) continue;
paths.push({ path, documentation });
}
paths.sort((a, b) => a.path.localeCompare(b.path)); paths.sort((a, b) => a.path.localeCompare(b.path));
--- ---
<BaseLayout {locale} accent="amber"> <BaseLayout {locale} accent="lime">
<h1>api</h1> <h1>api</h1>
{ {
paths.map(({ path, documentation }) => ( collection.map(({ id, data }) => (
<> <>
<h2>{path}</h2> <h2>{id}</h2>
<pre>{documentation}</pre> <pre style="background-color: red;">{data.docs}</pre>
<pre>{data.body}</pre>
</> </>
)) ))
} }
@@ -9,6 +9,16 @@ export const getStaticPaths = (async () => {
})); }));
}) satisfies GetStaticPaths; }) satisfies GetStaticPaths;
/**
* This is a very long.
* And boring.
*
* But important.
* Developer comment.
*
* Meant to test.
* The **formatting**!
*/
export async function GET({ params }: APIContext<never, { id: string }>) { export async function GET({ params }: APIContext<never, { id: string }>) {
const avatar = await api.avatar(params.id); const avatar = await api.avatar(params.id);
return Response.json(avatar); return Response.json(avatar);
+2 -1
View File
@@ -16,7 +16,8 @@
"isolatedModules": true, "isolatedModules": true,
"paths": { "paths": {
"@protos/*": ["./packages/closed/protos/*"] "@protos/*": ["./packages/closed/protos/*"]
} },
"strictNullChecks": true
}, },
"exclude": ["node_modules/**/*", "dist"] "exclude": ["node_modules/**/*", "dist"]
} }