fix: better error message when config has invalid references (#1874)

This commit is contained in:
Aiden Cline
2025-08-12 19:28:41 -05:00
committed by GitHub
parent 93102dc84b
commit ed5f76d849
2 changed files with 22 additions and 8 deletions

View File

@@ -12,7 +12,7 @@ export function FormatError(input: unknown) {
}
if (Config.InvalidError.isInstance(input))
return [
`Config file at ${input.data.path} is invalid`,
`Config file at ${input.data.path} is invalid` + (input.data.message ? `: ${input.data.message}` : ""),
...(input.data.issues?.map((issue) => "↳ " + issue.message + " " + issue.path.join(".")) ?? []),
].join("\n")

View File

@@ -429,14 +429,14 @@ export namespace Config {
return load(text, filepath)
}
async function load(text: string, filepath: string) {
async function load(text: string, configFilepath: string) {
text = text.replace(/\{env:([^}]+)\}/g, (_, varName) => {
return process.env[varName] || ""
})
const fileMatches = text.match(/\{file:[^}]+\}/g)
if (fileMatches) {
const configDir = path.dirname(filepath)
const configDir = path.dirname(configFilepath)
const lines = text.split("\n")
for (const match of fileMatches) {
@@ -449,7 +449,20 @@ export namespace Config {
filePath = path.join(os.homedir(), filePath.slice(2))
}
const resolvedPath = path.isAbsolute(filePath) ? filePath : path.resolve(configDir, filePath)
const fileContent = (await Bun.file(resolvedPath).text()).trim()
const fileContent = (
await Bun.file(resolvedPath)
.text()
.catch((error) => {
const errMsg = `bad file reference: "${match}"`
if (error.code === "ENOENT") {
throw new InvalidError(
{ path: configFilepath, message: errMsg + ` ${resolvedPath} does not exist` },
{ cause: error },
)
}
throw new InvalidError({ path: configFilepath, message: errMsg }, { cause: error })
})
).trim()
// escape newlines/quotes, strip outer quotes
text = text.replace(match, JSON.stringify(fileContent).slice(1, -1))
}
@@ -474,7 +487,7 @@ export namespace Config {
.join("\n")
throw new JsonError({
path: filepath,
path: configFilepath,
message: `\n--- JSONC Input ---\n${text}\n--- Errors ---\n${errorDetails}\n--- End ---`,
})
}
@@ -483,21 +496,21 @@ export namespace Config {
if (parsed.success) {
if (!parsed.data.$schema) {
parsed.data.$schema = "https://opencode.ai/config.json"
await Bun.write(filepath, JSON.stringify(parsed.data, null, 2))
await Bun.write(configFilepath, JSON.stringify(parsed.data, null, 2))
}
const data = parsed.data
if (data.plugin) {
for (let i = 0; i < data.plugin?.length; i++) {
const plugin = data.plugin[i]
try {
data.plugin[i] = import.meta.resolve(plugin, filepath)
data.plugin[i] = import.meta.resolve(plugin, configFilepath)
} catch (err) {}
}
}
return data
}
throw new InvalidError({ path: filepath, issues: parsed.error.issues })
throw new InvalidError({ path: configFilepath, issues: parsed.error.issues })
}
export const JsonError = NamedError.create(
"ConfigJsonError",
@@ -512,6 +525,7 @@ export namespace Config {
z.object({
path: z.string(),
issues: z.custom<z.ZodIssue[]>().optional(),
message: z.string().optional(),
}),
)