contract-kit / src /json.ts
edgemindroboticslabs's picture
Initial contract-kit library
6dec997 verified
export function parseJsonObject(rawText: string): unknown {
const trimmed = stripCodeFence(rawText.trim());
try {
return JSON.parse(trimmed);
} catch {
const extracted = extractFirstJsonValue(trimmed);
if (extracted === undefined) {
throw new SyntaxError("No JSON value found in model response.");
}
return JSON.parse(extracted);
}
}
function stripCodeFence(value: string): string {
const match = value.match(/^```(?:json)?\s*([\s\S]*?)\s*```$/i);
return match?.[1]?.trim() ?? value;
}
function extractFirstJsonValue(value: string): string | undefined {
const start = findFirstJsonStart(value);
if (start === -1) {
return undefined;
}
const opener = value[start];
const closer = opener === "{" ? "}" : "]";
let depth = 0;
let inString = false;
let escaping = false;
for (let index = start; index < value.length; index += 1) {
const char = value[index];
if (inString) {
if (escaping) {
escaping = false;
} else if (char === "\\") {
escaping = true;
} else if (char === "\"") {
inString = false;
}
continue;
}
if (char === "\"") {
inString = true;
} else if (char === opener) {
depth += 1;
} else if (char === closer) {
depth -= 1;
if (depth === 0) {
return value.slice(start, index + 1);
}
}
}
return undefined;
}
function findFirstJsonStart(value: string): number {
const objectStart = value.indexOf("{");
const arrayStart = value.indexOf("[");
if (objectStart === -1) {
return arrayStart;
}
if (arrayStart === -1) {
return objectStart;
}
return Math.min(objectStart, arrayStart);
}