mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-05-13 13:22:35 -07:00
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:
@@ -60,8 +60,11 @@ export class AcpFileSystemService implements FileSystemService {
|
||||
sessionId: this.sessionId,
|
||||
});
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
||||
return response.content;
|
||||
const content: unknown = response.content;
|
||||
if (typeof content !== 'string') {
|
||||
throw new Error('content must be a string'); // replace with other response type formats when modified in the future
|
||||
}
|
||||
return content;
|
||||
} catch (err: unknown) {
|
||||
this.normalizeFileSystemError(err);
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ export interface ConfigLogger {
|
||||
|
||||
export type RequestSettingCallback = (
|
||||
setting: ExtensionSetting,
|
||||
) => Promise<string>;
|
||||
) => Promise<string | undefined>;
|
||||
export type RequestConfirmationCallback = (message: string) => Promise<boolean>;
|
||||
|
||||
const defaultLogger: ConfigLogger = {
|
||||
@@ -47,8 +47,7 @@ const defaultRequestConfirmation: RequestConfirmationCallback = async (
|
||||
message,
|
||||
initial: false,
|
||||
});
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
||||
return response.confirm;
|
||||
return typeof response.confirm === 'boolean' ? response.confirm : false;
|
||||
};
|
||||
|
||||
export async function getExtensionManager() {
|
||||
|
||||
@@ -88,7 +88,9 @@ interface ExtensionManagerParams {
|
||||
enabledExtensionOverrides?: string[];
|
||||
settings: MergedSettings;
|
||||
requestConsent: (consent: string) => Promise<boolean>;
|
||||
requestSetting: ((setting: ExtensionSetting) => Promise<string>) | null;
|
||||
requestSetting:
|
||||
| ((setting: ExtensionSetting) => Promise<string | undefined>)
|
||||
| null;
|
||||
workspaceDir: string;
|
||||
eventEmitter?: EventEmitter<ExtensionEvents>;
|
||||
clientVersion?: string;
|
||||
@@ -106,7 +108,7 @@ export class ExtensionManager extends ExtensionLoader {
|
||||
private settings: MergedSettings;
|
||||
private requestConsent: (consent: string) => Promise<boolean>;
|
||||
private requestSetting:
|
||||
| ((setting: ExtensionSetting) => Promise<string>)
|
||||
| ((setting: ExtensionSetting) => Promise<string | undefined>)
|
||||
| undefined;
|
||||
private telemetryConfig: Config;
|
||||
private workspaceDir: string;
|
||||
@@ -161,7 +163,7 @@ export class ExtensionManager extends ExtensionLoader {
|
||||
}
|
||||
|
||||
setRequestSetting(
|
||||
requestSetting?: (setting: ExtensionSetting) => Promise<string>,
|
||||
requestSetting?: (setting: ExtensionSetting) => Promise<string | undefined>,
|
||||
): void {
|
||||
this.requestSetting = requestSetting;
|
||||
}
|
||||
|
||||
@@ -94,9 +94,8 @@ export class ExtensionRegistryClient {
|
||||
fuzzy: true,
|
||||
});
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
||||
const results = await fzf.find(query);
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
||||
return results.map((r: { item: RegistryExtension }) => r.item);
|
||||
const results: Array<{ item: RegistryExtension }> = await fzf.find(query);
|
||||
return results.map((r) => r.item);
|
||||
}
|
||||
|
||||
async getExtension(id: string): Promise<RegistryExtension | undefined> {
|
||||
|
||||
@@ -8,6 +8,7 @@ import fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
import { coreEvents, type GeminiCLIExtension } from '@google/gemini-cli-core';
|
||||
import { ExtensionStorage } from './storage.js';
|
||||
import { z } from 'zod';
|
||||
|
||||
export interface ExtensionEnablementConfig {
|
||||
overrides: string[];
|
||||
@@ -179,8 +180,12 @@ export class ExtensionEnablementManager {
|
||||
readConfig(): AllExtensionsEnablementConfig {
|
||||
try {
|
||||
const content = fs.readFileSync(this.configFilePath, 'utf-8');
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
||||
return JSON.parse(content);
|
||||
const parsed: unknown = JSON.parse(content);
|
||||
const schema = z.record(
|
||||
z.string(),
|
||||
z.object({ overrides: z.array(z.string()) }),
|
||||
);
|
||||
return schema.parse(parsed);
|
||||
} catch (error) {
|
||||
if (
|
||||
error instanceof Error &&
|
||||
|
||||
@@ -62,7 +62,7 @@ export const getEnvFilePath = (
|
||||
export async function maybePromptForSettings(
|
||||
extensionConfig: ExtensionConfig,
|
||||
extensionId: string,
|
||||
requestSetting: (setting: ExtensionSetting) => Promise<string>,
|
||||
requestSetting: (setting: ExtensionSetting) => Promise<string | undefined>,
|
||||
previousExtensionConfig?: ExtensionConfig,
|
||||
previousSettings?: Record<string, string>,
|
||||
): Promise<void> {
|
||||
@@ -106,7 +106,9 @@ export async function maybePromptForSettings(
|
||||
settingsChanges.promptForEnv,
|
||||
)) {
|
||||
const answer = await requestSetting(setting);
|
||||
allSettings[setting.envVar] = answer;
|
||||
if (answer !== undefined) {
|
||||
allSettings[setting.envVar] = answer;
|
||||
}
|
||||
}
|
||||
|
||||
const nonSensitiveSettings: Record<string, string> = {};
|
||||
@@ -159,14 +161,13 @@ function formatEnvContent(settings: Record<string, string>): string {
|
||||
|
||||
export async function promptForSetting(
|
||||
setting: ExtensionSetting,
|
||||
): Promise<string> {
|
||||
): Promise<string | undefined> {
|
||||
const response = await prompts({
|
||||
type: setting.sensitive ? 'password' : 'text',
|
||||
name: 'value',
|
||||
message: `${setting.name}\n${setting.description}`,
|
||||
});
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
||||
return response.value;
|
||||
return typeof response.value === 'string' ? response.value : undefined;
|
||||
}
|
||||
|
||||
export async function getScopedEnvContents(
|
||||
@@ -230,7 +231,7 @@ export async function updateSetting(
|
||||
extensionConfig: ExtensionConfig,
|
||||
extensionId: string,
|
||||
settingKey: string,
|
||||
requestSetting: (setting: ExtensionSetting) => Promise<string>,
|
||||
requestSetting: (setting: ExtensionSetting) => Promise<string | undefined>,
|
||||
scope: ExtensionSettingScope,
|
||||
workspaceDir: string,
|
||||
): Promise<void> {
|
||||
@@ -250,6 +251,10 @@ export async function updateSetting(
|
||||
}
|
||||
|
||||
const newValue = await requestSetting(settingToUpdate);
|
||||
if (newValue === undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
const keychain = new KeychainTokenStorage(
|
||||
getKeychainStorageName(extensionName, extensionId, scope, workspaceDir),
|
||||
);
|
||||
|
||||
@@ -67,8 +67,7 @@ export function recursivelyHydrateStrings<T>(
|
||||
}
|
||||
if (Array.isArray(obj)) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
return obj.map((item) =>
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
||||
return (obj as unknown[]).map((item) =>
|
||||
recursivelyHydrateStrings(item, values),
|
||||
) as unknown as T;
|
||||
}
|
||||
|
||||
@@ -112,5 +112,11 @@ export const createMockCommandContext = (
|
||||
return output;
|
||||
};
|
||||
|
||||
return merge(defaultMocks, overrides);
|
||||
const merged: unknown = merge(defaultMocks, overrides);
|
||||
const isCommandContext = (val: unknown): val is CommandContext =>
|
||||
typeof val === 'object' && val !== null;
|
||||
if (isCommandContext(merged)) {
|
||||
return merged;
|
||||
}
|
||||
throw new Error('Unreachable');
|
||||
};
|
||||
|
||||
@@ -170,13 +170,13 @@ async function searchResourceCandidates(
|
||||
selector: (candidate: ResourceSuggestionCandidate) => candidate.searchKey,
|
||||
});
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
||||
const results = await fzf.find(normalizedPattern, {
|
||||
limit: MAX_SUGGESTIONS_TO_SHOW * 3,
|
||||
});
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
||||
return results.map(
|
||||
(result: { item: ResourceSuggestionCandidate }) => result.item.suggestion,
|
||||
const results: Array<{ item: ResourceSuggestionCandidate }> = await fzf.find(
|
||||
normalizedPattern,
|
||||
{
|
||||
limit: MAX_SUGGESTIONS_TO_SHOW * 3,
|
||||
},
|
||||
);
|
||||
return results.map((result) => result.item.suggestion);
|
||||
}
|
||||
|
||||
async function searchAgentCandidates(
|
||||
@@ -194,11 +194,13 @@ async function searchAgentCandidates(
|
||||
selector: (s: Suggestion) => s.label,
|
||||
});
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
||||
const results = await fzf.find(normalizedPattern, {
|
||||
limit: MAX_SUGGESTIONS_TO_SHOW,
|
||||
});
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
||||
return results.map((r: { item: Suggestion }) => r.item);
|
||||
const results: Array<{ item: Suggestion }> = await fzf.find(
|
||||
normalizedPattern,
|
||||
{
|
||||
limit: MAX_SUGGESTIONS_TO_SHOW,
|
||||
},
|
||||
);
|
||||
return results.map((r) => r.item);
|
||||
}
|
||||
|
||||
export function useAtCompletion(props: UseAtCompletionProps): void {
|
||||
|
||||
@@ -174,7 +174,10 @@ export const TableRenderer: React.FC<TableRendererProps> = ({
|
||||
}
|
||||
|
||||
// --- Pre-wrap and Optimize Widths ---
|
||||
const actualColumnWidths = new Array(numColumns).fill(0);
|
||||
const actualColumnWidths: number[] = [];
|
||||
for (let i = 0; i < numColumns; i++) {
|
||||
actualColumnWidths.push(0);
|
||||
}
|
||||
|
||||
const wrapAndProcessRow = (row: StyledLine[]) => {
|
||||
const rowResult: ProcessedLine[][] = [];
|
||||
@@ -208,11 +211,7 @@ export const TableRenderer: React.FC<TableRendererProps> = ({
|
||||
const wrappedRows = styledRows.map((row) => wrapAndProcessRow(row));
|
||||
|
||||
// Use the TIGHTEST widths that fit the wrapped content + padding
|
||||
const adjustedWidths = actualColumnWidths.map(
|
||||
(w) =>
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
||||
w + COLUMN_PADDING,
|
||||
);
|
||||
const adjustedWidths = actualColumnWidths.map((w) => w + COLUMN_PADDING);
|
||||
|
||||
return { wrappedHeaders, wrappedRows, adjustedWidths };
|
||||
}, [styledHeaders, styledRows, terminalWidth]);
|
||||
@@ -263,7 +262,6 @@ export const TableRenderer: React.FC<TableRendererProps> = ({
|
||||
isHeader = false,
|
||||
): React.ReactNode => {
|
||||
const renderedCells = cells.map((cell, index) => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
||||
const width = adjustedWidths[index] || 0;
|
||||
return renderCell(cell, width, isHeader);
|
||||
});
|
||||
|
||||
@@ -111,18 +111,20 @@ function resolveEnvVarsInObjectInternal<T>(
|
||||
// Check for circular reference
|
||||
if (visited.has(obj)) {
|
||||
// Return a shallow copy to break the cycle
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
return [...obj] as unknown as T;
|
||||
const copy: unknown = [...obj];
|
||||
const isTArray = (val: unknown): val is T => Array.isArray(val);
|
||||
if (isTArray(copy)) return copy;
|
||||
throw new Error('Unreachable');
|
||||
}
|
||||
|
||||
visited.add(obj);
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
const result = obj.map((item) =>
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
||||
const mapped: unknown = obj.map((item: unknown) =>
|
||||
resolveEnvVarsInObjectInternal(item, visited, customEnv),
|
||||
) as unknown as T;
|
||||
);
|
||||
visited.delete(obj);
|
||||
return result;
|
||||
const isTArray = (val: unknown): val is T => Array.isArray(val);
|
||||
if (isTArray(mapped)) return mapped;
|
||||
throw new Error('Unreachable');
|
||||
}
|
||||
|
||||
if (typeof obj === 'object') {
|
||||
|
||||
@@ -83,8 +83,7 @@ export const getLatestGitHubRelease = async (
|
||||
if (!releaseTag) {
|
||||
throw new Error(`Response did not include tag_name field`);
|
||||
}
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
||||
return releaseTag;
|
||||
return typeof releaseTag === 'string' ? releaseTag : '';
|
||||
} catch (error) {
|
||||
debugLogger.debug(
|
||||
`Failed to determine latest run-gemini-cli release:`,
|
||||
|
||||
@@ -29,8 +29,7 @@ export function tryParseJSON(input: string): object | null {
|
||||
if (!checkInput(input)) return null;
|
||||
const trimmed = input.trim();
|
||||
try {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
||||
const parsed = JSON.parse(trimmed);
|
||||
const parsed: unknown = JSON.parse(trimmed);
|
||||
if (parsed === null || typeof parsed !== 'object') {
|
||||
return null;
|
||||
}
|
||||
@@ -40,7 +39,6 @@ export function tryParseJSON(input: string): object | null {
|
||||
|
||||
if (!Array.isArray(parsed) && Object.keys(parsed).length === 0) return null;
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
||||
return parsed;
|
||||
} catch {
|
||||
return null;
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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[][]> {
|
||||
|
||||
@@ -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:`,
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user