UNPKG

ai-json-fixer

Version:

A simple JSON parser designed to handle malformed JSON from Large Language Models

123 lines 4.94 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.addMissingCommas = addMissingCommas; /** * Adds missing commas between array elements and object properties */ function addMissingCommas(input) { // Check if this is single-line JSON that needs special handling if (input.indexOf('\n') === -1) { return handleSingleLineJson(input); } const lines = input.split('\n'); const result = []; let depth = 0; for (let lineIndex = 0; lineIndex < lines.length; lineIndex++) { const line = lines[lineIndex]; let processedLine = ''; // Reset string state for each line (this is a simplification) // In practice, strings can span multiple lines, but for typical JSON they don't let lineInString = false; let lineEscapeNext = false; for (let i = 0; i < line.length; i++) { const char = line[i]; // Handle escape sequences if (lineEscapeNext) { processedLine += char; lineEscapeNext = false; continue; } if (char === '\\' && lineInString) { processedLine += char; lineEscapeNext = true; continue; } // Handle string boundaries if (char === '"' && !lineEscapeNext) { lineInString = !lineInString; processedLine += char; continue; } // Skip processing inside strings if (lineInString) { processedLine += char; continue; } // Track depth if (char === '{' || char === '[') { depth++; } else if (char === '}' || char === ']') { depth--; } processedLine += char; } // Check if this line needs a comma at the end const trimmedLine = processedLine.trim(); // Skip empty lines and lines that already end with comma, colon, or are container starts if (trimmedLine === '' || trimmedLine.endsWith(',') || trimmedLine.endsWith(':') || trimmedLine.endsWith('{') || trimmedLine.endsWith('[')) { result.push(processedLine); continue; } // Check if we need to add a comma let needsComma = false; if (depth > 0 && lineIndex < lines.length - 1) { // Look at the next non-empty line let nextLineIndex = lineIndex + 1; while (nextLineIndex < lines.length && lines[nextLineIndex].trim() === '') { nextLineIndex++; } if (nextLineIndex < lines.length) { const nextLine = lines[nextLineIndex].trim(); // We need a comma if the next line starts a new value or key // and doesn't start with a container closer if (nextLine !== '' && !nextLine.startsWith('}') && !nextLine.startsWith(']')) { // Check if this line ends with a complete value const endsWithValue = /["\d}\]]$/.test(trimmedLine) || /\b(true|false|null)$/.test(trimmedLine); if (endsWithValue) { needsComma = true; } } } } if (needsComma) { // Add comma to the end of the line, preserving whitespace const match = processedLine.match(/^(\s*)(.*?)(\s*)$/); if (match && match[1] !== undefined && match[2] !== undefined && match[3] !== undefined) { const [, leadingWhitespace, content, trailingWhitespace] = match; result.push(leadingWhitespace + content + ',' + trailingWhitespace); } else { result.push(processedLine + ','); } } else { result.push(processedLine); } } return result.join('\n'); } /** * Handles single-line JSON comma insertion using regex patterns */ function handleSingleLineJson(input) { let result = input; // Apply fixes iteratively until no more changes let changed = true; while (changed) { const before = result; // Pattern 1: Object properties - value followed by quote (new key) // Match: number/string/boolean/null followed by space and quote result = result.replace(/(["\d}\]]|true|false|null)\s+(")/g, '$1, $2'); // Pattern 2: Array elements - value followed by value // Match: number/string/boolean/null followed by space and number/quote/bracket/negative result = result.replace(/(["\d}\]]|true|false|null)\s+(["\d[{-]|true|false|null)/g, '$1, $2'); changed = result !== before; } return result; } //# sourceMappingURL=missing-comma-detection.js.map