mirror of
https://github.com/logancyang/obsidian-copilot.git
synced 2026-07-22 07:50:24 +00:00
chore(lint): enable 4 type-aware quick-win rules and fix violations (#2424)
Turns on no-unsafe-enum-comparison, no-base-to-string, no-redundant-type-constituents, and restrict-template-expressions. Fixes all 24 violations across 13 source files.
This commit is contained in:
parent
f901343583
commit
8658282aa9
14 changed files with 43 additions and 38 deletions
|
|
@ -96,11 +96,6 @@ export default [
|
|||
"@typescript-eslint/unbound-method": "off", // 68 violations
|
||||
// Enabled in the TS-only block below.
|
||||
|
||||
// --- Quick wins: small enough to fix and enable in a single PR ---
|
||||
"@typescript-eslint/no-unsafe-enum-comparison": "off", // 11 violations
|
||||
"@typescript-eslint/no-base-to-string": "off", // 7 violations
|
||||
"@typescript-eslint/no-redundant-type-constituents": "off", // 5 violations
|
||||
"@typescript-eslint/restrict-template-expressions": "off", // 1 violation
|
||||
// no-deprecated: defer — surface the warnings, but don't fail CI yet
|
||||
"@typescript-eslint/no-deprecated": "off",
|
||||
|
||||
|
|
|
|||
|
|
@ -398,7 +398,7 @@ export class BedrockChatModel extends BaseChatModel<BedrockChatModelCallOptions>
|
|||
}
|
||||
}
|
||||
|
||||
private safeJsonParse(value: string): any | null {
|
||||
private safeJsonParse(value: string): any {
|
||||
try {
|
||||
return JSON.parse(value);
|
||||
} catch {
|
||||
|
|
|
|||
|
|
@ -38,7 +38,9 @@ export function buildGitHubCopilotAuthedFetch(
|
|||
? input
|
||||
: typeof Request !== "undefined" && input instanceof Request
|
||||
? input.url
|
||||
: input.toString();
|
||||
: input instanceof URL
|
||||
? input.href
|
||||
: input.url;
|
||||
|
||||
const doRequest = async (token: string): Promise<Response> => {
|
||||
const copilotHeaders = provider.buildCopilotRequestHeaders(token);
|
||||
|
|
|
|||
|
|
@ -69,7 +69,8 @@ export default class ProjectManager {
|
|||
const settings = getSettings();
|
||||
const shouldAutoIndex =
|
||||
settings.enableSemanticSearchV3 &&
|
||||
settings.indexVaultToVectorStore === VAULT_VECTOR_STORE_STRATEGY.ON_MODE_SWITCH &&
|
||||
(settings.indexVaultToVectorStore as VAULT_VECTOR_STORE_STRATEGY) ===
|
||||
VAULT_VECTOR_STORE_STRATEGY.ON_MODE_SWITCH &&
|
||||
(getChainType() === ChainType.VAULT_QA_CHAIN ||
|
||||
getChainType() === ChainType.COPILOT_PLUS_CHAIN);
|
||||
void this.getCurrentChainManager().createChainWithNewModel({
|
||||
|
|
@ -936,7 +937,7 @@ modified: ${stat ? new Date(stat.mtime).toISOString() : "unknown"}`;
|
|||
await this.retryNonMarkdownFile(project, failedItem.path);
|
||||
break;
|
||||
default:
|
||||
logWarn(`[retryFailedItem] Unknown item type: ${failedItem.type}`);
|
||||
logWarn(`[retryFailedItem] Unknown item type: ${String(failedItem.type)}`);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -47,7 +47,8 @@ export function ModelParametersEditor({
|
|||
onReset,
|
||||
showTokenLimit = true,
|
||||
}: ModelParametersEditorProps) {
|
||||
const isOllamaModel = model.provider === ChatModelProviders.OLLAMA;
|
||||
const provider = model.provider as ChatModelProviders;
|
||||
const isOllamaModel = provider === ChatModelProviders.OLLAMA;
|
||||
|
||||
// Parameter values: model.xxx ?? settings.xxx
|
||||
const temperature = model.temperature ?? settings.temperature;
|
||||
|
|
@ -66,7 +67,7 @@ export function ModelParametersEditor({
|
|||
model.name.startsWith("o3") ||
|
||||
model.name.startsWith("o4") ||
|
||||
model.name.startsWith("gpt-5")) &&
|
||||
model.provider === ChatModelProviders.OPENAI;
|
||||
provider === ChatModelProviders.OPENAI;
|
||||
|
||||
// Check if model has REASONING capability enabled
|
||||
const hasReasoningCapability = model.capabilities?.includes(ModelCapability.REASONING) ?? false;
|
||||
|
|
@ -74,12 +75,11 @@ export function ModelParametersEditor({
|
|||
// Show reasoning effort for: OpenAI reasoning models, OpenRouter, LM Studio, or any model with REASONING capability
|
||||
const showReasoningEffort =
|
||||
isOpenAIReasoningModel ||
|
||||
model.provider === ChatModelProviders.OPENROUTERAI ||
|
||||
provider === ChatModelProviders.OPENROUTERAI ||
|
||||
model.provider === "lm_studio" ||
|
||||
model.provider === ChatModelProviders.LM_STUDIO ||
|
||||
provider === ChatModelProviders.LM_STUDIO ||
|
||||
hasReasoningCapability;
|
||||
const showVerbosity =
|
||||
model.name.startsWith("gpt-5") && model.provider === ChatModelProviders.OPENAI;
|
||||
const showVerbosity = model.name.startsWith("gpt-5") && provider === ChatModelProviders.OPENAI;
|
||||
|
||||
return (
|
||||
<div className="tw-space-y-4">
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ jest.mock("@/utils", () => ({
|
|||
.join("");
|
||||
}
|
||||
if (content && typeof content === "object" && "text" in content) {
|
||||
return String((content as { text?: unknown }).text ?? "");
|
||||
return String((content as { text?: string }).text ?? "");
|
||||
}
|
||||
return String(content ?? "");
|
||||
}),
|
||||
|
|
|
|||
|
|
@ -848,6 +848,15 @@ ${chatContent}`;
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert an unknown error to a safe lowercase string for substring matching.
|
||||
*/
|
||||
private errorToMessage(error: unknown): string {
|
||||
if (error instanceof Error) return error.message;
|
||||
if (typeof error === "string") return error;
|
||||
return JSON.stringify(error);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether an error corresponds to an ENAMETOOLONG filesystem failure.
|
||||
* @param error - The thrown error.
|
||||
|
|
@ -858,8 +867,7 @@ ${chatContent}`;
|
|||
return false;
|
||||
}
|
||||
|
||||
const message = error instanceof Error ? error.message : String(error);
|
||||
const normalized = message.toLowerCase();
|
||||
const normalized = this.errorToMessage(error).toLowerCase();
|
||||
return normalized.includes("enametoolong") || normalized.includes("name too long");
|
||||
}
|
||||
|
||||
|
|
@ -870,8 +878,7 @@ ${chatContent}`;
|
|||
if (!error) {
|
||||
return false;
|
||||
}
|
||||
const message = error instanceof Error ? error.message : String(error);
|
||||
return message.toLowerCase().includes("already exists");
|
||||
return this.errorToMessage(error).toLowerCase().includes("already exists");
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
import { type CopilotSettings } from "@/settings/model";
|
||||
import { Platform } from "obsidian";
|
||||
|
||||
// @ts-ignore
|
||||
let safeStorageInternal: Electron.SafeStorage | null = null;
|
||||
let safeStorageInternal: any = null;
|
||||
|
||||
function getSafeStorage() {
|
||||
if (Platform.isDesktop && safeStorageInternal) {
|
||||
|
|
|
|||
|
|
@ -324,9 +324,8 @@ export async function migrateProjectsFromSettingsToVault(app: App): Promise<void
|
|||
if (fmMatch) {
|
||||
const parsed = parseYaml(fmMatch[1]);
|
||||
if (parsed && typeof parsed === "object") {
|
||||
existingId = String(
|
||||
(parsed as Record<string, unknown>)[COPILOT_PROJECT_ID] ?? ""
|
||||
).trim();
|
||||
const raw = (parsed as Record<string, unknown>)[COPILOT_PROJECT_ID];
|
||||
existingId = (typeof raw === "string" ? raw : "").trim();
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
|
|
|
|||
|
|
@ -368,7 +368,7 @@ export class DBOperations {
|
|||
};
|
||||
}
|
||||
|
||||
async upsert(docToSave: any): Promise<any | undefined> {
|
||||
async upsert(docToSave: any): Promise<any> {
|
||||
if (!this.oramaDb) throw new Error("DB not initialized");
|
||||
const db = this.oramaDb;
|
||||
|
||||
|
|
|
|||
|
|
@ -29,11 +29,7 @@ export class ScoreNormalizer {
|
|||
/**
|
||||
* Update explanation with normalized scores
|
||||
*/
|
||||
private updateExplanation(
|
||||
explanation: any | undefined,
|
||||
originalScore: number,
|
||||
normalizedScore: number
|
||||
): any | undefined {
|
||||
private updateExplanation(explanation: any, originalScore: number, normalizedScore: number): any {
|
||||
if (!explanation) return undefined;
|
||||
|
||||
return {
|
||||
|
|
|
|||
|
|
@ -37,7 +37,11 @@ export function toStringSafe(value: unknown): string {
|
|||
if (value === null || value === undefined) return "";
|
||||
try {
|
||||
if (typeof value === "object") return JSON.stringify(value);
|
||||
return String(value);
|
||||
if (typeof value === "function") return value.toString();
|
||||
if (typeof value === "symbol") return value.toString();
|
||||
if (typeof value === "bigint") return value.toString();
|
||||
if (typeof value === "number" || typeof value === "boolean") return String(value);
|
||||
return "";
|
||||
} catch {
|
||||
return "";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -123,7 +123,7 @@ export async function verifyAndAddModel(
|
|||
|
||||
// Check if model already exists
|
||||
const existingModel = activeModels.find(
|
||||
(m) => m.name === model.name && m.provider === model.provider
|
||||
(m) => m.name === model.name && (m.provider as SettingKeyProviders) === model.provider
|
||||
);
|
||||
|
||||
const alreadyExists = Boolean(existingModel);
|
||||
|
|
|
|||
12
src/utils.ts
12
src/utils.ts
|
|
@ -823,7 +823,8 @@ export async function safeFetch(
|
|||
contentType: "application/json",
|
||||
headers: headers,
|
||||
method: method,
|
||||
...(methodsWithBody.includes(method) && { body: options.body?.toString() }),
|
||||
...(methodsWithBody.includes(method) &&
|
||||
typeof options.body === "string" && { body: options.body }),
|
||||
throw: false, // Don't throw so we can get the response body
|
||||
});
|
||||
|
||||
|
|
@ -1194,7 +1195,7 @@ export function isCodexModel(model: BaseChatModel | string): boolean {
|
|||
export function shouldUseGitHubCopilotResponsesApi(
|
||||
model: Pick<CustomModel, "provider" | "name" | "useResponsesApi">
|
||||
): boolean {
|
||||
if (model.provider !== ChatModelProviders.GITHUB_COPILOT) {
|
||||
if ((model.provider as ChatModelProviders) !== ChatModelProviders.GITHUB_COPILOT) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -1264,7 +1265,8 @@ export function checkModelApiKey(
|
|||
hasApiKey: boolean;
|
||||
errorNotice?: string;
|
||||
} {
|
||||
if (model.provider === ChatModelProviders.AMAZON_BEDROCK) {
|
||||
const provider = model.provider as ChatModelProviders;
|
||||
if (provider === ChatModelProviders.AMAZON_BEDROCK) {
|
||||
const apiKey = model.apiKey || settings.amazonBedrockApiKey;
|
||||
if (!apiKey) {
|
||||
return {
|
||||
|
|
@ -1279,7 +1281,7 @@ export function checkModelApiKey(
|
|||
}
|
||||
|
||||
// GitHub Copilot uses OAuth, not API key
|
||||
if (model.provider === ChatModelProviders.GITHUB_COPILOT) {
|
||||
if (provider === ChatModelProviders.GITHUB_COPILOT) {
|
||||
const hasAuth = Boolean(
|
||||
model.apiKey || settings.githubCopilotToken || settings.githubCopilotAccessToken
|
||||
);
|
||||
|
|
@ -1293,7 +1295,7 @@ export function checkModelApiKey(
|
|||
return { hasApiKey: true };
|
||||
}
|
||||
|
||||
const needSetKeyPath = !!getNeedSetKeyProvider().find((provider) => provider === model.provider);
|
||||
const needSetKeyPath = !!getNeedSetKeyProvider().find((p) => p === provider);
|
||||
const hasNoApiKey = !getApiKeyForProvider(model.provider as SettingKeyProviders, model);
|
||||
|
||||
// For Providers that require setting a key in the dialog, an inspection is necessary.
|
||||
|
|
|
|||
Loading…
Reference in a new issue