refactor(vscode): reduce validateCustomProvider complexity by extracting helpers

Extract checkModel, checkVariant, checkHeader, checkProviderID, serializeModel,
serializeVariant, and resolveEnv from validateCustomProvider to bring it under
the ESLint complexity limit of 20. Also remove the now-unnecessary complexity
exception for CustomProviderDialog.tsx.
This commit is contained in:
kiloconnect[bot]
2026-04-20 15:00:43 +00:00
parent 8d49b48d79
commit 5ec01e00b2
2 changed files with 95 additions and 96 deletions
-4
View File
@@ -79,10 +79,6 @@ export default [
],
rules: { complexity: ["error", 27] },
},
{
files: ["webview-ui/src/components/settings/CustomProviderDialog.tsx"],
rules: { complexity: ["error", 26] },
},
{
files: ["src/agent-manager/WorktreeStateManager.ts"],
rules: { complexity: ["error", 24] },
@@ -1,4 +1,4 @@
import type { ModelEntry } from "./CustomProviderModelCard"
import type { ModelEntry, VariantEntry } from "./CustomProviderModelCard"
type Translator = (key: string, params?: Record<string, string>) => string
@@ -54,22 +54,95 @@ type ValidateResult = {
const PROVIDER_ID = /^[a-z0-9][a-z0-9-_]*$/
const OPENAI_COMPATIBLE = "@ai-sdk/openai-compatible"
function checkVariant(v: VariantEntry, seen: Set<string>, t: Translator) {
const n = v.name.trim()
if (!n) return { name: t("provider.custom.error.required") }
if (seen.has(n)) return { name: t("provider.custom.error.duplicate") }
seen.add(n)
return { name: undefined }
}
function checkModel(m: ModelEntry, seenModels: Set<string>, t: Translator) {
const id = m.id.trim()
let idErr: string | undefined
if (!id) idErr = t("provider.custom.error.required")
else if (seenModels.has(id)) idErr = t("provider.custom.error.duplicate")
else seenModels.add(id)
const nameErr = !m.name.trim() ? t("provider.custom.error.required") : undefined
const seen = new Set<string>()
const variants = m.reasoning ? m.variants.map((v) => checkVariant(v, seen, t)) : []
return { id: idErr, name: nameErr, variants }
}
function checkHeader(h: HeaderRow, seenKeys: Set<string>, t: Translator) {
const key = h.key.trim()
const value = h.value.trim()
if (!key && !value) return {}
let keyErr: string | undefined
if (!key) keyErr = t("provider.custom.error.required")
else if (seenKeys.has(key.toLowerCase())) keyErr = t("provider.custom.error.duplicate")
else seenKeys.add(key.toLowerCase())
const valueErr = !value ? t("provider.custom.error.required") : undefined
return { key: keyErr, value: valueErr }
}
function checkProviderID(id: string, editing: boolean, disabled: string[], existing: Set<string>, t: Translator) {
const idErr = !id
? t("provider.custom.error.providerID.required")
: !PROVIDER_ID.test(id)
? t("provider.custom.error.providerID.format")
: undefined
const existsErr =
idErr || editing || !existing.has(id) || disabled.includes(id)
? undefined
: t("provider.custom.error.providerID.exists")
return { idErr, existsErr }
}
function serializeVariant(v: VariantEntry): [string, Record<string, unknown>] {
const cfg: Record<string, unknown> = {}
if (v.enableThinking !== undefined) cfg.enable_thinking = v.enableThinking
if (v.thinking !== undefined) cfg.thinking = { type: v.thinking }
if (v.reasoningEffort !== undefined) cfg.reasoningEffort = v.reasoningEffort
if (v.chatTemplateArgs !== undefined) cfg.chat_template_args = { enable_thinking: v.chatTemplateArgs }
return [v.name.trim(), cfg]
}
function serializeModel(m: ModelEntry): [string, Record<string, unknown>] {
const ventries = m.reasoning ? m.variants.filter((v) => v.name.trim()).map(serializeVariant) : []
const entry: Record<string, unknown> = { name: m.name.trim() }
if (m.reasoning) entry.reasoning = true
if (ventries.length > 0) entry.variants = Object.fromEntries(ventries)
return [m.id.trim(), entry]
}
function resolveEnv(rawEnv: string | undefined, savedEnv: string[] | undefined) {
if (rawEnv) return { env: [rawEnv] }
if (savedEnv) return { env: savedEnv }
return {}
}
export function validateCustomProvider(input: ValidateArgs): ValidateResult {
const providerID = input.form.providerID.trim()
const name = input.form.name.trim()
const baseURL = input.form.baseURL.trim()
const apiKey = input.form.apiKey.trim()
const env = apiKey.match(/^\{env:([^}]+)\}$/)?.[1]?.trim()
const rawEnv = apiKey.match(/^\{env:([^}]+)\}$/)?.[1]?.trim()
// When editing and apiKey is empty, preserve existing env from the original config
const existingEnv = input.editing && !apiKey ? input.existingEnv : undefined
const key = apiKey && !env ? apiKey : undefined
const savedEnv = input.editing && !apiKey ? input.existingEnv : undefined
const key = apiKey && !rawEnv ? apiKey : undefined
const idError = !providerID
? input.t("provider.custom.error.providerID.required")
: !PROVIDER_ID.test(providerID)
? input.t("provider.custom.error.providerID.format")
: undefined
const { idErr, existsErr } = checkProviderID(
providerID,
input.editing,
input.disabledProviders,
input.existingProviderIDs,
input.t,
)
const nameError = !name ? input.t("provider.custom.error.name.required") : undefined
const urlError = !baseURL
@@ -78,102 +151,32 @@ export function validateCustomProvider(input: ValidateArgs): ValidateResult {
? input.t("provider.custom.error.baseURL.format")
: undefined
const disabled = input.disabledProviders.includes(providerID)
const existsError = idError
? undefined
: input.editing
? undefined
: input.existingProviderIDs.has(providerID) && !disabled
? input.t("provider.custom.error.providerID.exists")
: undefined
const seenModels = new Set<string>()
const modelErrors = input.form.models.map((m) => {
const id = m.id.trim()
const modelIdError = !id
? input.t("provider.custom.error.required")
: seenModels.has(id)
? input.t("provider.custom.error.duplicate")
: (() => {
seenModels.add(id)
return undefined
})()
const modelNameError = !m.name.trim() ? input.t("provider.custom.error.required") : undefined
const seen = new Set<string>()
const verrs = m.reasoning
? m.variants.map((v) => {
const n = v.name.trim()
const vErr = !n
? input.t("provider.custom.error.required")
: seen.has(n)
? input.t("provider.custom.error.duplicate")
: (() => {
seen.add(n)
return undefined
})()
return { name: vErr }
})
: []
return { id: modelIdError, name: modelNameError, variants: verrs }
})
const modelErrors = input.form.models.map((m) => checkModel(m, seenModels, input.t))
const modelsValid = modelErrors.every((m) => !m.id && !m.name && m.variants.every((v) => !v.name))
const models = Object.fromEntries(
input.form.models.map((m) => {
const ventries = m.reasoning
? m.variants
.filter((v) => v.name.trim())
.map((v) => {
const cfg: Record<string, unknown> = {}
if (v.enableThinking !== undefined) cfg.enable_thinking = v.enableThinking
if (v.thinking !== undefined) cfg.thinking = { type: v.thinking }
if (v.reasoningEffort !== undefined) cfg.reasoningEffort = v.reasoningEffort
if (v.chatTemplateArgs !== undefined) cfg.chat_template_args = { enable_thinking: v.chatTemplateArgs }
return [v.name.trim(), cfg]
})
: []
const entry: Record<string, unknown> = { name: m.name.trim() }
if (m.reasoning) entry.reasoning = true
if (ventries.length > 0) entry.variants = Object.fromEntries(ventries)
return [m.id.trim(), entry]
}),
)
const seenHeaders = new Set<string>()
const headerErrors = input.form.headers.map((h) => {
const hKey = h.key.trim()
const value = h.value.trim()
if (!hKey && !value) return {}
const keyError = !hKey
? input.t("provider.custom.error.required")
: seenHeaders.has(hKey.toLowerCase())
? input.t("provider.custom.error.duplicate")
: (() => {
seenHeaders.add(hKey.toLowerCase())
return undefined
})()
const valueError = !value ? input.t("provider.custom.error.required") : undefined
return { key: keyError, value: valueError }
})
const headerErrors = input.form.headers.map((h) => checkHeader(h, seenHeaders, input.t))
const headersValid = headerErrors.every((h) => !h.key && !h.value)
const headers = Object.fromEntries(
input.form.headers
.map((h) => ({ key: h.key.trim(), value: h.value.trim() }))
.filter((h) => !!h.key && !!h.value)
.map((h) => [h.key, h.value]),
)
const errors: FormErrors = {
providerID: idError ?? existsError,
providerID: idErr ?? existsErr,
name: nameError,
baseURL: urlError,
models: modelErrors,
headers: headerErrors,
}
const ok = !idError && !existsError && !nameError && !urlError && modelsValid && headersValid
const ok = !idErr && !existsErr && !nameError && !urlError && modelsValid && headersValid
if (!ok) return { errors }
const headers = Object.fromEntries(
input.form.headers
.map((h) => ({ key: h.key.trim(), value: h.value.trim() }))
.filter((h) => !!h.key && !!h.value)
.map((h) => [h.key, h.value]),
)
const options = {
baseURL,
...(Object.keys(headers).length ? { headers } : {}),
@@ -188,9 +191,9 @@ export function validateCustomProvider(input: ValidateArgs): ValidateResult {
config: {
npm: OPENAI_COMPATIBLE,
name,
...(env ? { env: [env] } : existingEnv ? { env: existingEnv } : {}),
...resolveEnv(rawEnv, savedEnv),
options,
models,
models: Object.fromEntries(input.form.models.map(serializeModel)),
},
},
}