UNPKG

@agentica/core

Version:

Agentic AI Library specialized in LLM Function Calling

226 lines 9.08 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.JsonUtil = void 0; const es_jsonkit_1 = require("es-jsonkit"); const jsonrepair_1 = require("jsonrepair"); const Escaper_1 = require("typia/lib/utils/Escaper"); exports.JsonUtil = { parse, stringifyValidateFailure, }; const pipe = (...fns) => (str) => fns.reduce((acc, fn) => fn(acc), str); function parse(str) { str = pipe(es_jsonkit_1.removeEmptyObjectPrefix, es_jsonkit_1.addMissingBraces, es_jsonkit_1.removeTrailingCommas, jsonrepair_1.jsonrepair)(str); return JSON.parse(str); } function stringifyValidateFailure(failure) { const usedErrors = new Set(); const jsonOutput = stringify({ value: failure.data, errors: failure.errors, path: "$input", tab: 0, inArray: false, inToJson: false, usedErrors, }); // Find errors that couldn't be embedded const unmappableErrors = failure.errors.filter(e => !usedErrors.has(e)); // If there are unmappable errors, append them as a separate block if (unmappableErrors.length > 0) { return `\`\`\`json\n${jsonOutput}\n\`\`\`\n\n**Unmappable validation errors:**\n\n\`\`\`json\n${JSON.stringify(unmappableErrors, null, 2)}\n\`\`\``; } return `\`\`\`json\n${jsonOutput}\n\`\`\``; } function stringify(props) { var _a; const { value, errors, path, tab, inArray, inToJson, usedErrors } = props; const indent = " ".repeat(tab); const errorComment = getErrorComment(path, errors, usedErrors); // Handle undefined in arrays if (inArray && value === undefined) { return `${indent}undefined${errorComment}`; } // Array if (Array.isArray(value)) { if (value.length === 0) { return `${indent}[]${errorComment}`; } const lines = []; lines.push(`${indent}[${errorComment}`); value.forEach((item, index) => { const itemPath = `${path}[${index}]`; let itemStr = stringify({ value: item, errors, path: itemPath, tab: tab + 1, inArray: true, inToJson: false, usedErrors, }); // Add comma before the error comment if not the last element if (index < value.length - 1) { const itemLines = itemStr.split("\n"); const lastLine = itemLines[itemLines.length - 1]; const commentIndex = lastLine.indexOf(" //"); if (commentIndex !== -1) { itemLines[itemLines.length - 1] = `${lastLine.slice(0, commentIndex)},${lastLine.slice(commentIndex)}`; } else { itemLines[itemLines.length - 1] += ","; } itemStr = itemLines.join("\n"); } lines.push(itemStr); }); lines.push(`${indent}]`); return lines.join("\n"); } // Object if (typeof value === "object" && value !== null) { // Check for toJSON method if (!inToJson && typeof value.toJSON === "function") { const jsonValue = value.toJSON(); return stringify({ value: jsonValue, errors, path, tab, inArray, inToJson: true, usedErrors, }); } // Get existing entries (filter out undefined values from actual data) const existingEntries = Object.entries(value).filter(([_, val]) => val !== undefined); // Find missing properties that have validation errors const missingKeys = getMissingProperties(path, value, errors); // Combine existing and missing properties const allKeys = [ ...existingEntries.map(([key]) => key), ...missingKeys, ]; if (allKeys.length === 0) { return `${indent}{}${errorComment}`; } const lines = []; lines.push(`${indent}{${errorComment}`); allKeys.forEach((key, index, array) => { const propPath = Escaper_1.Escaper.variable(key) ? `${path}.${key}` : `${path}[${JSON.stringify(key)}]`; const propIndent = " ".repeat(tab + 1); // Get the value (undefined for missing properties) const val = missingKeys.includes(key) ? undefined : value[key]; // Primitive property value (including undefined for missing properties) if (val === undefined || val === null || typeof val === "boolean" || typeof val === "number" || typeof val === "string") { const propErrorComment = getErrorComment(propPath, errors, usedErrors); const valueStr = val === undefined ? `${propIndent}"${key}": undefined` : `${propIndent}"${key}": ${JSON.stringify(val)}`; const withComma = index < array.length - 1 ? `${valueStr},` : valueStr; const line = withComma + propErrorComment; lines.push(line); } // Complex property value (object or array) else { const keyLine = `${propIndent}"${key}": `; let valStr = stringify({ value: val, errors, path: propPath, tab: tab + 1, inArray: false, inToJson: false, usedErrors, }); const valStrWithoutIndent = valStr.trimStart(); // Add comma before the error comment if not the last property if (index < array.length - 1) { const valLines = valStrWithoutIndent.split("\n"); const lastLine = valLines[valLines.length - 1]; const commentIndex = lastLine.indexOf(" //"); if (commentIndex !== -1) { valLines[valLines.length - 1] = `${lastLine.slice(0, commentIndex)},${lastLine.slice(commentIndex)}`; } else { valLines[valLines.length - 1] += ","; } valStr = valLines.join("\n"); } else { valStr = valStrWithoutIndent; } const combined = keyLine + valStr; lines.push(combined); } }); lines.push(`${indent}}`); return lines.join("\n"); } // Primitive types (null, boolean, number, string, undefined, etc.) const valStr = value === undefined ? "undefined" : ((_a = JSON.stringify(value)) !== null && _a !== void 0 ? _a : String(value)); return `${indent}${valStr}${errorComment}`; } /** Get error comment for a given path */ function getErrorComment(path, errors, usedErrors) { const pathErrors = errors.filter((e) => e.path === path); if (pathErrors.length === 0) { return ""; } // Mark these errors as used pathErrors.forEach(e => usedErrors.add(e)); return ` // ❌ ${JSON.stringify(pathErrors.map(e => ({ path: e.path, expected: e.expected, description: e.description, })))}`; } /** * Find missing properties that have validation errors but don't exist in the data * Returns array of property keys that should be displayed as undefined */ function getMissingProperties(path, value, errors) { const missingKeys = new Set(); for (const e of errors) { // Check if error.path is a direct child of current path const childKey = extractDirectChildKey(path, e.path); if (childKey !== null) { // Check if this property actually exists in the value if (!(childKey in value)) { missingKeys.add(childKey); } } } return Array.from(missingKeys); } /** * Extract direct child property key if errorPath is a direct child of parentPath * Returns null if not a direct child * * Examples: * - extractDirectChildKey("$input", "$input.email") => "email" * - extractDirectChildKey("$input", "$input.user.email") => null (grandchild) * - extractDirectChildKey("$input.user", "$input.user.email") => "email" * - extractDirectChildKey("$input", "$input[0]") => null (array index, not object property) */ function extractDirectChildKey(parentPath, errorPath) { if (!errorPath.startsWith(parentPath)) { return null; } const suffix = errorPath.slice(parentPath.length); // Match ".propertyName" pattern (direct child property) // Should not contain additional dots or brackets after the property name const match = suffix.match(/^\.([^.[\]]+)$/); return match !== null ? match[1] : null; } //# sourceMappingURL=JsonUtil.js.map