Refactor: Eliminate no-unsafe-return suppressions via strict type validation (#20668)

Signed-off-by: M-DEV-1 <mahadevankizhakkedathu@gmail.com>
Co-authored-by: Tommaso Sciortino <sciortino@gmail.com>
This commit is contained in:
mahadevan
2026-05-13 05:15:58 +05:30
committed by GitHub
parent 8f03aa320e
commit 31d5947d37
23 changed files with 184 additions and 115 deletions
+7 -2
View File
@@ -679,8 +679,13 @@ async function fetchCachedCredentials(): Promise<
for (const keyFile of pathsToTry) {
try {
const keyFileString = await fs.readFile(keyFile, 'utf-8');
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
return JSON.parse(keyFileString);
const parsed: unknown = JSON.parse(keyFileString);
const isOAuthCreds = (val: unknown): val is Credentials | JWTInput =>
typeof val === 'object' && val !== null;
if (isOAuthCreds(parsed)) {
return parsed;
}
throw new Error('Invalid credentials format');
} catch (error) {
// Log specific error for debugging, but continue trying other paths
debugLogger.debug(
+1 -1
View File
@@ -76,7 +76,7 @@ export class ProjectRegistry {
if (isNodeError(error) && error.code === 'ENOENT') {
return { projects: {} }; // Normal first run
}
if (error instanceof SyntaxError) {
if (error instanceof SyntaxError || error instanceof z.ZodError) {
debugLogger.warn(
'Failed to load registry (JSON corrupted), resetting to empty: ',
error,
+7 -2
View File
@@ -177,10 +177,15 @@ export class BaseLlmClient {
);
// If we are here, the content is valid (not empty and parsable).
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
return JSON.parse(
const parsed: unknown = JSON.parse(
this.cleanJsonResponse(getResponseText(result)!.trim(), model),
);
const isRecord = (val: unknown): val is Record<string, unknown> =>
typeof val === 'object' && val !== null && !Array.isArray(val);
if (isRecord(parsed)) {
return parsed;
}
throw new Error('Invalid JSON response format from LLM');
}
async generateEmbedding(texts: string[]): Promise<number[][]> {
+12 -10
View File
@@ -84,11 +84,12 @@ export class FakeContentGenerator implements ContentGenerator {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
role: LlmRole,
): Promise<GenerateContentResponse> {
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
return Object.setPrototypeOf(
this.getNextResponse('generateContent', request),
GenerateContentResponse.prototype,
);
const response: unknown = this.getNextResponse('generateContent', request);
Object.setPrototypeOf(response, GenerateContentResponse.prototype);
if (response instanceof GenerateContentResponse) {
return response;
}
throw new Error('Failed to create GenerateContentResponse');
}
async generateContentStream(
@@ -118,10 +119,11 @@ export class FakeContentGenerator implements ContentGenerator {
async embedContent(
request: EmbedContentParameters,
): Promise<EmbedContentResponse> {
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
return Object.setPrototypeOf(
this.getNextResponse('embedContent', request),
EmbedContentResponse.prototype,
);
const response: unknown = this.getNextResponse('embedContent', request);
Object.setPrototypeOf(response, EmbedContentResponse.prototype);
if (response instanceof EmbedContentResponse) {
return response;
}
throw new Error('Failed to create EmbedContentResponse');
}
}
@@ -84,8 +84,13 @@ export class LocalLiteRtLmClient {
);
}
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
return JSON.parse(result.text);
const parsed: unknown = JSON.parse(result.text);
const isRecord = (val: unknown): val is Record<string, unknown> =>
typeof val === 'object' && val !== null && !Array.isArray(val);
if (isRecord(parsed)) {
return parsed;
}
throw new Error('Invalid JSON response format from Local LLM');
} catch (error) {
debugLogger.error(
`[LocalLiteRtLmClient] Failed to generate content:`,
+5 -3
View File
@@ -348,9 +348,11 @@ export class IdeClient {
try {
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
const parsedJson = JSON.parse(textPart.text);
if (parsedJson && typeof parsedJson.content === 'string') {
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
return parsedJson.content;
if (parsedJson) {
const content: unknown = parsedJson.content;
if (typeof content === 'string') {
return content;
}
}
if (parsedJson && parsedJson.content === null) {
return undefined;
+52 -27
View File
@@ -123,8 +123,17 @@ export async function getConnectionConfigFromFile(
`gemini-ide-server-${pid}.json`,
);
const portFileContents = await fs.promises.readFile(portFile, 'utf8');
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
return JSON.parse(portFileContents);
const parsed: unknown = JSON.parse(portFileContents);
type ConfigType = ConnectionConfig & {
workspacePath?: string;
ideInfo?: IdeInfo;
};
const isConfig = (val: unknown): val is ConfigType =>
typeof val === 'object' && val !== null;
if (isConfig(parsed)) {
return parsed;
}
throw new Error('Invalid connection config format');
} catch {
// For newer extension versions, the file name matches the pattern
// /^gemini-ide-server-${pid}-\d+\.json$/. If multiple IDE
@@ -166,39 +175,59 @@ export async function getConnectionConfigFromFile(
logger.debug('Failed to read IDE connection config file(s):', e);
return undefined;
}
const parsedContents = fileContents.map((content) => {
try {
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
return JSON.parse(content);
} catch (e) {
logger.debug('Failed to parse JSON from config file: ', e);
return undefined;
}
});
const parsedContents = fileContents.map(
(
content,
):
| (ConnectionConfig & { workspacePath?: string; ideInfo?: IdeInfo })
| undefined => {
try {
const parsed: unknown = JSON.parse(content);
type ConfigType = ConnectionConfig & {
workspacePath?: string;
ideInfo?: IdeInfo;
};
const isConfig = (val: unknown): val is ConfigType =>
typeof val === 'object' && val !== null;
if (isConfig(parsed)) {
return parsed;
}
return undefined;
} catch (e) {
logger.debug('Failed to parse JSON from config file: ', e);
return undefined;
}
},
);
const validWorkspaces = parsedContents.filter((content) => {
if (!content) {
return false;
}
const { isValid } = validateWorkspacePath(
content.workspacePath,
process.cwd(),
);
return isValid;
});
const validWorkspaces = parsedContents.filter(
(
content,
): content is ConnectionConfig & {
workspacePath?: string;
ideInfo?: IdeInfo;
} => {
if (!content) {
return false;
}
const { isValid } = validateWorkspacePath(
content.workspacePath,
process.cwd(),
);
return isValid;
},
);
if (validWorkspaces.length === 0) {
return undefined;
}
if (validWorkspaces.length === 1) {
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
const selected = validWorkspaces[0];
const fileIndex = parsedContents.indexOf(selected);
if (fileIndex !== -1) {
logger.debug(`Selected IDE connection file: ${matchingFiles[fileIndex]}`);
}
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
return selected;
}
@@ -208,7 +237,6 @@ export async function getConnectionConfigFromFile(
(content) => String(content.port) === portFromEnv,
);
if (matchingPortIndex !== -1) {
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
const selected = validWorkspaces[matchingPortIndex];
const fileIndex = parsedContents.indexOf(selected);
if (fileIndex !== -1) {
@@ -216,12 +244,10 @@ export async function getConnectionConfigFromFile(
`Selected IDE connection file (matched port from env): ${matchingFiles[fileIndex]}`,
);
}
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
return selected;
}
}
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
const selected = validWorkspaces[0];
const fileIndex = parsedContents.indexOf(selected);
if (fileIndex !== -1) {
@@ -229,7 +255,6 @@ export async function getConnectionConfigFromFile(
`Selected first valid IDE connection file: ${matchingFiles[fileIndex]}`,
);
}
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
return selected;
}
@@ -9,7 +9,7 @@ import picomatch from 'picomatch';
import { loadIgnoreRules, type Ignore } from './ignore.js';
import { ResultCache } from './result-cache.js';
import { crawl } from './crawler.js';
import { AsyncFzf, type FzfResultItem } from 'fzf';
import { AsyncFzf } from 'fzf';
import { unescapePath } from '../paths.js';
import type { FileDiscoveryService } from '../../services/fileDiscoveryService.js';
import { FileWatcher, type FileWatcherEvent } from './fileWatcher.js';
@@ -270,7 +270,7 @@ class RecursiveFileSearch implements FileSearch {
pattern = unescapePath(pattern) || '*';
let filteredCandidates;
let filteredCandidates: string[];
const { files: candidates, isExactMatch } =
await this.resultCache.get(pattern);
@@ -282,17 +282,27 @@ class RecursiveFileSearch implements FileSearch {
if (pattern.includes('*') || !this.fzf) {
filteredCandidates = await filter(candidates, pattern, options.signal);
} else {
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
filteredCandidates = await this.fzf
.find(pattern)
.then((results: Array<FzfResultItem<string>>) =>
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
results.map((entry: FzfResultItem<string>) => entry.item),
)
.catch(() => {
try {
const fzfResult: unknown = await this.fzf.find(pattern);
if (Array.isArray(fzfResult)) {
filteredCandidates = fzfResult.map((entry: unknown) => {
if (
typeof entry === 'object' &&
entry !== null &&
'item' in entry
) {
return String((entry as { item: unknown }).item);
}
return String(entry);
});
} else {
shouldCache = false;
return [];
});
filteredCandidates = [];
}
} catch {
shouldCache = false;
filteredCandidates = [];
}
}
if (shouldCache) {
+2 -4
View File
@@ -27,8 +27,7 @@ export function safeJsonStringify(
}
seen.add(value);
}
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
return value;
return value as unknown;
},
space,
);
@@ -61,8 +60,7 @@ export function safeJsonStringifyBooleanValuesOnly(obj: any): string {
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
if ((value as Config) !== null && !configSeen) {
configSeen = true;
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
return value;
return value as unknown;
}
if (typeof value === 'boolean') {
return value;