Skip to content

Commit 57bcfaf

Browse files
committed
fix(types): add TypeScript parameter types to test helpers (#588)
Replace JSDoc-only annotations in fixtures.ts with proper TypeScript interfaces and typed parameters. Add interfaces and typed parameters to resolution-benchmark.test.ts helper functions. Eliminates all noExplicitAny warnings in both files. Impact: 22 functions changed, 0 affected
1 parent 04a2e50 commit 57bcfaf

2 files changed

Lines changed: 118 additions & 66 deletions

File tree

tests/benchmarks/resolution/resolution-benchmark.test.ts

Lines changed: 58 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,42 @@ import { afterAll, beforeAll, describe, expect, test } from 'vitest';
1717
import { openReadonlyOrFail } from '../../../src/db/index.js';
1818
import { buildGraph } from '../../../src/domain/graph/builder.js';
1919

20+
// ── Types ─────────────────────────────────────────────────────────────────
21+
22+
interface ResolvedEdge {
23+
source_name: string;
24+
source_file: string;
25+
target_name: string;
26+
target_file: string;
27+
kind: string;
28+
confidence: number;
29+
}
30+
31+
interface ExpectedEdge {
32+
source: { name: string; file: string };
33+
target: { name: string; file: string };
34+
mode?: string;
35+
}
36+
37+
interface ModeMetrics {
38+
expected: number;
39+
resolved: number;
40+
recall?: number;
41+
}
42+
43+
interface BenchmarkMetrics {
44+
precision: number;
45+
recall: number;
46+
truePositives: number;
47+
falsePositives: number;
48+
falseNegatives: number;
49+
totalResolved: number;
50+
totalExpected: number;
51+
byMode: Record<string, ModeMetrics>;
52+
falsePositiveEdges: string[];
53+
falseNegativeEdges: string[];
54+
}
55+
2056
// ── Configuration ────────────────────────────────────────────────────────
2157

2258
const FIXTURES_DIR = path.join(import.meta.dirname, 'fixtures');
@@ -40,7 +76,7 @@ const THRESHOLDS = {
4076
* Copy fixture to a temp directory so buildGraph can write .codegraph/ without
4177
* polluting the repo.
4278
*/
43-
function copyFixture(lang) {
79+
function copyFixture(lang: string): string {
4480
const src = path.join(FIXTURES_DIR, lang);
4581
const tmp = fs.mkdtempSync(path.join(os.tmpdir(), `codegraph-resolution-${lang}-`));
4682
for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
@@ -54,7 +90,7 @@ function copyFixture(lang) {
5490
/**
5591
* Build graph for a fixture directory.
5692
*/
57-
async function buildFixtureGraph(fixtureDir) {
93+
async function buildFixtureGraph(fixtureDir: string): Promise<void> {
5894
await buildGraph(fixtureDir, {
5995
incremental: false,
6096
engine: 'wasm',
@@ -68,7 +104,7 @@ async function buildFixtureGraph(fixtureDir) {
68104
* Extract all call edges from the built graph DB.
69105
* Returns array of { sourceName, sourceFile, targetName, targetFile, kind, confidence }.
70106
*/
71-
function extractResolvedEdges(fixtureDir) {
107+
function extractResolvedEdges(fixtureDir: string) {
72108
const dbPath = path.join(fixtureDir, '.codegraph', 'graph.db');
73109
const db = openReadonlyOrFail(dbPath);
74110
try {
@@ -97,22 +133,30 @@ function extractResolvedEdges(fixtureDir) {
97133
/**
98134
* Normalize a file path to just the basename for comparison.
99135
*/
100-
function normalizeFile(filePath) {
136+
function normalizeFile(filePath: string): string {
101137
return path.basename(filePath);
102138
}
103139

104140
/**
105141
* Build a string key for an edge to enable set-based comparison.
106142
*/
107-
function edgeKey(sourceName, sourceFile, targetName, targetFile) {
143+
function edgeKey(
144+
sourceName: string,
145+
sourceFile: string,
146+
targetName: string,
147+
targetFile: string,
148+
): string {
108149
return `${sourceName}@${normalizeFile(sourceFile)} -> ${targetName}@${normalizeFile(targetFile)}`;
109150
}
110151

111152
/**
112153
* Compare resolved edges against expected edges manifest.
113154
* Returns precision, recall, and detailed breakdown by mode.
114155
*/
115-
function computeMetrics(resolvedEdges, expectedEdges) {
156+
function computeMetrics(
157+
resolvedEdges: ResolvedEdge[],
158+
expectedEdges: ExpectedEdge[],
159+
): BenchmarkMetrics {
116160
// Build sets for overall comparison
117161
const resolvedSet = new Set(
118162
resolvedEdges.map((e) => edgeKey(e.source_name, e.source_file, e.target_name, e.target_file)),
@@ -135,7 +179,7 @@ function computeMetrics(resolvedEdges, expectedEdges) {
135179
const recall = expectedSet.size > 0 ? truePositives.size / expectedSet.size : 0;
136180

137181
// Break down by resolution mode
138-
const byMode = {};
182+
const byMode: Record<string, ModeMetrics> = {};
139183
for (const edge of expectedEdges) {
140184
const mode = edge.mode || 'unknown';
141185
if (!byMode[mode]) byMode[mode] = { expected: 0, resolved: 0 };
@@ -168,7 +212,7 @@ function computeMetrics(resolvedEdges, expectedEdges) {
168212
/**
169213
* Format a metrics report for console output.
170214
*/
171-
function formatReport(lang, metrics) {
215+
function formatReport(lang: string, metrics: BenchmarkMetrics): string {
172216
const lines = [
173217
`\n ── ${lang.toUpperCase()} Resolution Metrics ──`,
174218
` Precision: ${(metrics.precision * 100).toFixed(1)}% (${metrics.truePositives} correct / ${metrics.totalResolved} resolved)`,
@@ -208,9 +252,9 @@ function formatReport(lang, metrics) {
208252
/**
209253
* Discover all fixture languages that have an expected-edges.json manifest.
210254
*/
211-
function discoverFixtures() {
255+
function discoverFixtures(): string[] {
212256
if (!fs.existsSync(FIXTURES_DIR)) return [];
213-
const languages = [];
257+
const languages: string[] = [];
214258
for (const dir of fs.readdirSync(FIXTURES_DIR)) {
215259
const manifestPath = path.join(FIXTURES_DIR, dir, 'expected-edges.json');
216260
if (fs.existsSync(manifestPath)) {
@@ -223,7 +267,7 @@ function discoverFixtures() {
223267
const languages = discoverFixtures();
224268

225269
/** Stores all results for the final summary */
226-
const allResults = {};
270+
const allResults: Record<string, BenchmarkMetrics> = {};
227271

228272
describe('Call Resolution Precision/Recall', () => {
229273
afterAll(() => {
@@ -243,9 +287,9 @@ describe('Call Resolution Precision/Recall', () => {
243287
for (const lang of languages) {
244288
describe(lang, () => {
245289
let fixtureDir: string;
246-
let resolvedEdges: any[];
247-
let expectedEdges: any[];
248-
let metrics: any;
290+
let resolvedEdges: ResolvedEdge[];
291+
let expectedEdges: ExpectedEdge[];
292+
let metrics: BenchmarkMetrics;
249293

250294
beforeAll(async () => {
251295
fixtureDir = copyFixture(lang);

tests/helpers/fixtures.ts

Lines changed: 60 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -10,84 +10,89 @@ import { InMemoryRepository } from '../../src/db/repository/in-memory-repository
1010
* .calls('authMiddleware', 'authenticate')
1111
* .build();
1212
*/
13-
class TestRepoBuilder {
14-
#pending = { nodes: [], edges: [], complexity: [] };
13+
interface PendingNode {
14+
name: string;
15+
kind: string;
16+
file: string;
17+
line: number;
18+
[key: string]: unknown;
19+
}
1520

16-
/**
17-
* Add a function node.
18-
* @param {string} name
19-
* @param {string} file
20-
* @param {number} line
21-
* @param {object} [extra] - Additional node attrs (role, end_line, scope, etc.)
22-
*/
23-
fn(name, file, line, extra = {}) {
21+
interface PendingEdge {
22+
source: string;
23+
target: string;
24+
kind: string;
25+
}
26+
27+
interface PendingComplexity {
28+
name: string;
29+
metrics: Record<string, unknown>;
30+
}
31+
32+
class TestRepoBuilder {
33+
#pending: { nodes: PendingNode[]; edges: PendingEdge[]; complexity: PendingComplexity[] } = {
34+
nodes: [],
35+
edges: [],
36+
complexity: [],
37+
};
38+
39+
/** Add a function node. */
40+
fn(name: string, file: string, line: number, extra: Record<string, unknown> = {}): this {
2441
return this.#addNode(name, 'function', file, line, extra);
2542
}
2643

27-
/**
28-
* Add a method node.
29-
*/
30-
method(name, file, line, extra = {}) {
44+
/** Add a method node. */
45+
method(name: string, file: string, line: number, extra: Record<string, unknown> = {}): this {
3146
return this.#addNode(name, 'method', file, line, extra);
3247
}
3348

34-
/**
35-
* Add a class node.
36-
*/
37-
cls(name, file, line, extra = {}) {
49+
/** Add a class node. */
50+
cls(name: string, file: string, line: number, extra: Record<string, unknown> = {}): this {
3851
return this.#addNode(name, 'class', file, line, extra);
3952
}
4053

41-
/**
42-
* Add a file node.
43-
*/
44-
file(filePath) {
54+
/** Add a file node. */
55+
file(filePath: string): this {
4556
return this.#addNode(filePath, 'file', filePath, 0);
4657
}
4758

48-
/**
49-
* Add an arbitrary node.
50-
*/
51-
node(name, kind, file, line, extra = {}) {
59+
/** Add an arbitrary node. */
60+
node(
61+
name: string,
62+
kind: string,
63+
file: string,
64+
line: number,
65+
extra: Record<string, unknown> = {},
66+
): this {
5267
return this.#addNode(name, kind, file, line, extra);
5368
}
5469

55-
/**
56-
* Add a 'calls' edge between two named nodes.
57-
*/
58-
calls(sourceName, targetName) {
70+
/** Add a 'calls' edge between two named nodes. */
71+
calls(sourceName: string, targetName: string): this {
5972
this.#pending.edges.push({ source: sourceName, target: targetName, kind: 'calls' });
6073
return this;
6174
}
6275

63-
/**
64-
* Add an 'imports' edge.
65-
*/
66-
imports(sourceName, targetName) {
76+
/** Add an 'imports' edge. */
77+
imports(sourceName: string, targetName: string): this {
6778
this.#pending.edges.push({ source: sourceName, target: targetName, kind: 'imports' });
6879
return this;
6980
}
7081

71-
/**
72-
* Add an 'extends' edge.
73-
*/
74-
extends(sourceName, targetName) {
82+
/** Add an 'extends' edge. */
83+
extends(sourceName: string, targetName: string): this {
7584
this.#pending.edges.push({ source: sourceName, target: targetName, kind: 'extends' });
7685
return this;
7786
}
7887

79-
/**
80-
* Add an edge of any kind.
81-
*/
82-
edge(sourceName, targetName, kind) {
88+
/** Add an edge of any kind. */
89+
edge(sourceName: string, targetName: string, kind: string): this {
8390
this.#pending.edges.push({ source: sourceName, target: targetName, kind });
8491
return this;
8592
}
8693

87-
/**
88-
* Add complexity metrics for a named node.
89-
*/
90-
complexity(name, metrics) {
94+
/** Add complexity metrics for a named node. */
95+
complexity(name: string, metrics: Record<string, unknown>): this {
9196
this.#pending.complexity.push({ name, metrics });
9297
return this;
9398
}
@@ -129,16 +134,19 @@ class TestRepoBuilder {
129134
return { repo, ids };
130135
}
131136

132-
#addNode(name, kind, file, line, extra = {}) {
137+
#addNode(
138+
name: string,
139+
kind: string,
140+
file: string,
141+
line: number,
142+
extra: Record<string, unknown> = {},
143+
): this {
133144
this.#pending.nodes.push({ name, kind, file, line, ...extra });
134145
return this;
135146
}
136147
}
137148

138-
/**
139-
* Create a new TestRepoBuilder.
140-
* @returns {TestRepoBuilder}
141-
*/
142-
export function createTestRepo() {
149+
/** Create a new TestRepoBuilder. */
150+
export function createTestRepo(): TestRepoBuilder {
143151
return new TestRepoBuilder();
144152
}

0 commit comments

Comments
 (0)