Skip to content

Commit 6f4f6a4

Browse files
committed
fix: Resolve ESLint issues in server (empty function, unsafe body access)
1 parent 7100a43 commit 6f4f6a4

File tree

3 files changed

+35
-3
lines changed

3 files changed

+35
-3
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
9797
+ - Resolved runtime error `TypeError: vi.mocked(...).mockReturnValue is not a function` in `src/tests/server.test.ts` by directly casting `http.createServer` to `vi.Mock` and calling `mockReturnValue` on it, bypassing issues with `vi.mocked()`.
9898
+ - Fixed TypeScript error `TS2345` for `process.exit` mock in `src/tests/server.test.ts` by casting `vi.fn()` to the expected `(code?: number) => never` signature.
9999
- Addressed TypeScript error `TS2345` concerning `http.Server` type compatibility in `src/tests/server.test.ts` by enhancing the `mockHttpServer` object with more properties common to `http.Server` and using a type assertion (`as unknown as http.Server`).
100+
- **ESLint Fixes (server.ts - Empty Function & Unsafe Access) (Git Commit ID: [GIT_COMMIT_ID_PLACEHOLDER]):**
101+
- Resolved ESLint warning `@typescript-eslint/no-empty-function` in `src/lib/server.ts` for `httpServerSetupReject` initialization by adding an `eslint-disable-next-line` comment, as this is a valid pattern for initializing promise reject functions.
102+
- Addressed ESLint errors `@typescript-eslint/no-unsafe-assignment` and `@typescript-eslint/no-unsafe-member-access` related to `req.body.id` access in MCP error responses. Introduced a `RequestBodyWithId` interface and type-safe checks before accessing `req.body.id` to ensure `req.body` is an object and contains the `id` property.
100103
- **Linting Finalization & Build Stability (Git Commit ID: [GIT_COMMIT_ID_PLACEHOLDER]):**
101104
- Resolved all ESLint errors in `src/tests/server.test.ts`.
102105
- The primary fix involved ensuring that `eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion` directives are present and preserved before all `await importOriginal() as typeof import(...)` type assertions in mock factories. These assertions are essential for ESLint's subsequent type-checking rules (`no-unsafe-return`, `no-unsafe-assignment`) to function correctly, even if `tsc` alone might not strictly require the disable.

RETROSPECTION.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -767,3 +767,24 @@
767767
- Continue to use `eslint-disable-next-line @typescript-eslint/require-await` with justification for functions that are intentionally `async` without current `await` expressions for API consistency or future-proofing.
768768

769769
---
770+
# Retrospection for ESLint Fixes (server.ts - Empty Function & Unsafe Access) (Git Commit ID: [GIT_COMMIT_ID_PLACEHOLDER])
771+
772+
## What went well?
773+
- ESLint clearly identified the specific lines and rules causing the warnings and errors.
774+
- The `no-empty-function` warning was correctly identified as a case where disabling the rule for a specific pattern (promise rejector initialization) is appropriate.
775+
- The `no-unsafe-assignment` and `no-unsafe-member-access` errors highlighted a genuine type safety concern with accessing `req.body.id` without proper checks.
776+
777+
## What could be improved?
778+
- **Type Safety for `req.body`:** While `express.json()` middleware parses the body, its type remains `any` by default. Consistently applying type guards or casting to a known interface (like `RequestBodyWithId`) for `req.body` access improves type safety throughout the Express route handlers.
779+
- **ESLint Rule Configuration:** For `no-empty-function`, if this pattern of initializing promise rejectors is common, a more global ESLint configuration (e.g., allowing empty functions with specific names or in specific contexts) could be considered, though targeted disables are also fine.
780+
781+
## What did we learn?
782+
- **`no-empty-function`:** This rule is generally useful but has valid exceptions, such as initializing placeholder functions that will be reassigned. `eslint-disable` is appropriate here.
783+
- **`no-unsafe-assignment` / `no-unsafe-member-access`:** These rules are crucial for maintaining type safety when dealing with `any` types. Accessing properties on `req.body` (which is often `any` after middleware parsing) requires careful type checking or casting to a more specific type.
784+
- **Type Guards/Checks for `req.body`:** Before accessing properties like `id` on `req.body`, it's important to verify that `req.body` is an object and actually contains the property. This prevents runtime errors and satisfies ESLint's safety rules.
785+
786+
## Action Items / Follow-ups
787+
- Review other instances of `req.body` access in Express route handlers to ensure similar type safety measures (type guards or casting with checks) are applied.
788+
- Consider if a project-wide helper type or type guard for Express request bodies that might contain an `id` would be beneficial for consistency.
789+
790+
---

src/lib/server.ts

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,11 @@ import { VERSION } from "./version";
3636
import { getOrCreateSession, addQuery, addSuggestion, updateContext, getRecentQueries, getRelevantResults } from "./state";
3737

3838
// Define this interface at the top level of the file, e.g., after imports
39+
interface RequestBodyWithId {
40+
id?: unknown; // id can be string, number, or null
41+
[key: string]: unknown; // Allow other properties
42+
}
43+
3944
interface PingResponseData {
4045
service?: string;
4146
status?: string;
@@ -359,7 +364,8 @@ export async function startServer(repoPath: string): Promise<void> {
359364

360365
logger.info("Starting CodeCompass MCP server...");
361366

362-
let httpServerSetupReject: (reason?: unknown) => void = () => {}; // Initialize with a no-op
367+
// eslint-disable-next-line @typescript-eslint/no-empty-function -- Initializing with a no-op, will be reassigned.
368+
let httpServerSetupReject: (reason?: unknown) => void = () => {};
363369
const httpServerSetupPromise = new Promise<void>((_resolve, reject) => {
364370
httpServerSetupReject = reject;
365371
});
@@ -490,10 +496,11 @@ export async function startServer(repoPath: string): Promise<void> {
490496
transport = newTransport;
491497
} else {
492498
logger.warn(`MCP POST: Bad Request. No valid session ID and not an init request.`);
499+
const bodyWithId = req.body as RequestBodyWithId;
493500
res.status(400).json({
494501
jsonrpc: '2.0',
495502
error: { code: -32000, message: 'Bad Request: No valid session ID or not an init request.' },
496-
id: req.body?.id || null,
503+
id: (typeof bodyWithId === 'object' && bodyWithId !== null && 'id' in bodyWithId) ? bodyWithId.id : null,
497504
});
498505
return;
499506
}
@@ -502,8 +509,9 @@ export async function startServer(repoPath: string): Promise<void> {
502509
} catch (transportError) {
503510
logger.error("Error handling MCP POST request via transport:", transportError);
504511
if (!res.headersSent) {
512+
const bodyWithId = req.body as RequestBodyWithId;
505513
res.status(500).json({
506-
jsonrpc: '2.0', error: { code: -32000, message: 'Internal MCP transport error.' }, id: req.body?.id || null,
514+
jsonrpc: '2.0', error: { code: -32000, message: 'Internal MCP transport error.' }, id: (typeof bodyWithId === 'object' && bodyWithId !== null && 'id' in bodyWithId) ? bodyWithId.id : null,
507515
});
508516
}
509517
}

0 commit comments

Comments
 (0)