The doc-sniffing dog
1import { assertEquals } from "@std/assert";
2import { analyzeDirectory } from "../core.ts";
3import { join } from "@std/path";
4
5Deno.test("analyzeDirectory - finds exported symbols", async () => {
6 const fixturesPath = join(
7 Deno.cwd(),
8 "tests",
9 "fixtures",
10 "simple",
11 "basic.ts",
12 );
13
14 const result = await analyzeDirectory(fixturesPath);
15
16 assertEquals(result.symbols.length, 4);
17 assertEquals(result.hasDenoJson, false);
18});
19
20Deno.test("analyzeDirectory - detects JSDoc presence", async () => {
21 const fixturesPath = join(
22 Deno.cwd(),
23 "tests",
24 "fixtures",
25 "simple",
26 "basic.ts",
27 );
28
29 const result = await analyzeDirectory(fixturesPath);
30
31 const undocumented = result.symbols.filter((s) => !s.hasJSDoc);
32 assertEquals(undocumented.length, 4);
33});
34
35Deno.test("analyzeDirectory - detects documented symbols", async () => {
36 const fixturesPath = join(
37 Deno.cwd(),
38 "tests",
39 "fixtures",
40 "simple",
41 "documented.ts",
42 );
43
44 const result = await analyzeDirectory(fixturesPath);
45
46 assertEquals(result.symbols.length, 4);
47
48 const documented = result.symbols.filter((s) => s.hasJSDoc);
49 assertEquals(documented.length, 4);
50
51 assertEquals(result.stats.percentage, 100);
52});
53
54Deno.test("analyzeDirectory - calculates stats correctly", async () => {
55 const fixturesPath = join(
56 Deno.cwd(),
57 "tests",
58 "fixtures",
59 "simple",
60 "basic.ts",
61 );
62
63 const result = await analyzeDirectory(fixturesPath);
64
65 assertEquals(result.stats.total, 4);
66 assertEquals(result.stats.documented, 0);
67 assertEquals(result.stats.undocumented, 4);
68 assertEquals(result.stats.percentage, 0);
69});
70
71Deno.test("analyzeDirectory - handles different export types", async () => {
72 const fixturesPath = join(
73 Deno.cwd(),
74 "tests",
75 "fixtures",
76 "export_blocks",
77 "export_block.ts",
78 );
79
80 const result = await analyzeDirectory(fixturesPath);
81
82 assertEquals(result.symbols.length, 3);
83
84 const classSymbol = result.symbols.find((s) => s.name === "MyClass");
85 assertEquals(classSymbol?.type, "class");
86
87 const functionSymbol = result.symbols.find((s) => s.name === "myFunction");
88 assertEquals(functionSymbol?.type, "function");
89
90 const constSymbol = result.symbols.find((s) => s.name === "myConst");
91 assertEquals(constSymbol?.type, "const");
92});
93
94Deno.test("analyzeDirectory - uses deno.json exports field", async () => {
95 const fixturesPath = join(Deno.cwd(), "tests", "fixtures", "with_config");
96
97 const result = await analyzeDirectory(fixturesPath);
98
99 assertEquals(result.hasDenoJson, true);
100 assertEquals(result.hasExports, true);
101 assertEquals(result.exportPath, "./reexport.ts");
102});
103
104Deno.test("analyzeDirectory - traces re-exports", async () => {
105 const fixturesPath = join(Deno.cwd(), "tests", "fixtures", "with_config");
106
107 const result = await analyzeDirectory(fixturesPath);
108
109 const symbolNames = result.symbols.map((s) => s.name).sort();
110
111 assertEquals(symbolNames.includes("documentedFunction"), true);
112 assertEquals(symbolNames.includes("UndocumentedClass"), true);
113 assertEquals(symbolNames.includes("DocumentedInterface"), true);
114 assertEquals(symbolNames.includes("undocumentedConst"), true);
115 assertEquals(symbolNames.includes("renamedFunction"), true);
116});
117
118Deno.test("analyzeDirectory - avoids duplicate exports", async () => {
119 const fixturesPath = join(Deno.cwd(), "tests", "fixtures", "with_config");
120
121 const result = await analyzeDirectory(fixturesPath);
122
123 const symbolNames = result.symbols.map((s) => s.name);
124 const uniqueNames = new Set(symbolNames);
125
126 assertEquals(symbolNames.length, uniqueNames.size);
127});
128
129Deno.test("analyzeDirectory - tracks symbol types correctly", async () => {
130 const fixturesPath = join(
131 Deno.cwd(),
132 "tests",
133 "fixtures",
134 "simple",
135 "basic.ts",
136 );
137
138 const result = await analyzeDirectory(fixturesPath);
139
140 const byType = result.stats.byType;
141
142 assertEquals(byType["function"]?.total, 1);
143 assertEquals(byType["class"]?.total, 1);
144 assertEquals(byType["interface"]?.total, 1);
145 assertEquals(byType["const"]?.total, 1);
146});
147
148Deno.test("analyzeDirectory - correctly matches symbols with prefix names", async () => {
149 const fixturesPath = join(
150 Deno.cwd(),
151 "tests",
152 "fixtures",
153 "prefix_bug",
154 "types.ts",
155 );
156
157 const result = await analyzeDirectory(fixturesPath);
158
159 assertEquals(result.symbols.length, 2);
160
161 const serverSymbol = result.symbols.find((s) => s.name === "Server");
162 assertEquals(serverSymbol?.type, "type");
163 assertEquals(serverSymbol?.line, 6);
164
165 const serverRateLimitSymbol = result.symbols.find((s) => s.name === "ServerRateLimitDescription");
166 assertEquals(serverRateLimitSymbol?.type, "type");
167 assertEquals(serverRateLimitSymbol?.line, 1);
168});