a reactive (signals based) hypermedia web framework (wip)
stormlightlabs.github.io/volt/
hypermedia
frontend
signals
1import { getLibSrcPath } from "$utils/paths.js";
2import { readFile } from "node:fs/promises";
3import path from "node:path";
4import { describe, expect, it } from "vitest";
5
6describe("docs generation", () => {
7 it("should extract function documentation", async () => {
8 const srcPath = await getLibSrcPath();
9 const testFile = path.join(srcPath, "core", "signal.ts");
10 const content = await readFile(testFile, "utf8");
11
12 expect(content).toContain("Creates a new signal");
13 expect(content).toContain("@param initialValue");
14 expect(content).toContain("@returns A Signal object");
15 expect(content).toContain("@example");
16 });
17
18 it("should extract interface documentation", async () => {
19 const srcPath = await getLibSrcPath();
20 const typesFile = path.join(srcPath, "types", "volt.d.ts");
21 const content = await readFile(typesFile, "utf8");
22
23 expect(content).toContain("interface Signal");
24 expect(content).toContain("interface ComputedSignal");
25 });
26
27 it("should handle JSDoc with examples", () => {
28 const jsdoc = `/**
29 * Creates a signal
30 * @example
31 * const count = signal(0);
32 * count.set(1);
33 */`;
34
35 const hasExample = jsdoc.includes("@example");
36 expect(hasExample).toBe(true);
37
38 const lines = jsdoc.split("\n");
39 const exampleLines: string[] = [];
40 let inExample = false;
41
42 for (const line of lines) {
43 const trimmed = line.trim().replace(/^\*\s?/, "");
44
45 if (trimmed.startsWith("@example")) {
46 inExample = true;
47 continue;
48 }
49
50 if (trimmed.startsWith("@") && !trimmed.startsWith("@example")) {
51 inExample = false;
52 continue;
53 }
54
55 if (inExample && trimmed !== "" && !trimmed.startsWith("*/")) {
56 exampleLines.push(trimmed);
57 }
58 }
59
60 expect(exampleLines.length).toBeGreaterThan(0);
61 expect(exampleLines.join("\n")).toContain("signal(0)");
62 });
63
64 it("should clean up JSDoc comments", () => {
65 const jsdoc = `/**
66 * This is a description
67 * with multiple lines
68 * @param foo - description
69 */`;
70
71 const lines = jsdoc.split("\n").map((line) => line.trim()).map((line) => line.replace(/^\/\*\*\s?/, "")).map((
72 line,
73 ) => line.replace(/^\*\s?/, "")).map((line) => line.replace(/\*\/\s*$/, "")).filter((line) =>
74 !line.startsWith("@") && line !== ""
75 );
76
77 const description = lines.join("\n").trim();
78
79 expect(description).toContain("This is a description");
80 expect(description).toContain("with multiple lines");
81 expect(description).not.toContain("@param");
82 });
83
84 it("should parse markdown structure", () => {
85 const markdown = `# Module
86
87## Function
88
89Description here
90
91\`\`\`typescript
92function foo(): void
93\`\`\`
94
95**Example:**
96
97\`\`\`typescript
98foo();
99\`\`\`
100`;
101
102 expect(markdown).toContain("# Module");
103 expect(markdown).toContain("## Function");
104 expect(markdown).toContain("**Example:**");
105 expect(markdown).toMatch(/```typescript[\s\S]*?```/);
106 });
107});