45 lines
1.4 KiB
TypeScript
45 lines
1.4 KiB
TypeScript
export * as ConfigParse from "./parse"
|
|
|
|
import { type ParseError as JsoncParseError, parse as parseJsoncImpl, printParseErrorCode } from "jsonc-parser"
|
|
import z from "zod"
|
|
import { InvalidError, JsonError } from "./error"
|
|
|
|
type Schema<T> = z.ZodType<T>
|
|
|
|
export function jsonc(text: string, filepath: string): unknown {
|
|
const errors: JsoncParseError[] = []
|
|
const data = parseJsoncImpl(text, errors, { allowTrailingComma: true })
|
|
if (errors.length) {
|
|
const lines = text.split("\n")
|
|
const issues = errors
|
|
.map((e) => {
|
|
const beforeOffset = text.substring(0, e.offset).split("\n")
|
|
const line = beforeOffset.length
|
|
const column = beforeOffset[beforeOffset.length - 1].length + 1
|
|
const problemLine = lines[line - 1]
|
|
|
|
const error = `${printParseErrorCode(e.error)} at line ${line}, column ${column}`
|
|
if (!problemLine) return error
|
|
|
|
return `${error}\n Line ${line}: ${problemLine}\n${"".padStart(column + 9)}^`
|
|
})
|
|
.join("\n")
|
|
throw new JsonError({
|
|
path: filepath,
|
|
message: `\n--- JSONC Input ---\n${text}\n--- Errors ---\n${issues}\n--- End ---`,
|
|
})
|
|
}
|
|
|
|
return data
|
|
}
|
|
|
|
export function schema<T>(schema: Schema<T>, data: unknown, source: string): T {
|
|
const parsed = schema.safeParse(data)
|
|
if (parsed.success) return parsed.data
|
|
|
|
throw new InvalidError({
|
|
path: source,
|
|
issues: parsed.error.issues,
|
|
})
|
|
}
|