ai-json-fixer
Version:
A simple JSON parser designed to handle malformed JSON from Large Language Models
123 lines • 4.39 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.removeTrailingContent = removeTrailingContent;
/**
* Removes trailing content after valid JSON
*/
function removeTrailingContent(input) {
// Track string state and bracket counts
let inString = false;
let escapeNext = false;
let depth = 0;
let lastValidJsonEnd = -1;
let jsonStarted = false;
let currentQuoteChar = '';
for (let i = 0; i < input.length; i++) {
const char = input[i];
// Handle escape sequences
if (escapeNext) {
escapeNext = false;
continue;
}
if (char === '\\' && inString) {
escapeNext = true;
continue;
}
// Handle string boundaries
if ((char === '"' || char === "'") && !escapeNext) {
if (!inString) {
inString = true;
currentQuoteChar = char;
if (!jsonStarted && char === '"') {
jsonStarted = true;
}
}
else if (char === currentQuoteChar) {
inString = false;
currentQuoteChar = '';
// If this was a standalone string (primitive JSON), mark end
if (depth === 0 && jsonStarted && char === '"') {
lastValidJsonEnd = i + 1;
}
}
continue;
}
// Skip characters inside strings
if (inString) {
continue;
}
// Track depth for objects and arrays
if (char === '{' || char === '[') {
depth++;
jsonStarted = true;
}
else if (char === '}' || char === ']') {
depth--;
// If we've returned to depth 0, we might have a complete JSON structure
if (depth === 0 && jsonStarted) {
lastValidJsonEnd = i + 1;
// Check if there are more JSON objects following
let j = i + 1;
while (j < input.length && /\s/.test(input[j])) {
j++;
}
// If the next non-whitespace character starts a new JSON structure, continue
if (j < input.length && (input[j] === '{' || input[j] === '[' || input[j] === '"')) {
lastValidJsonEnd = -1; // Reset and continue parsing
}
}
}
// Handle primitive JSON values (strings already handled above)
if (!jsonStarted && depth === 0) {
// Check for numbers
if (/\d/.test(char) || (char === '-' && i + 1 < input.length && /\d/.test(input[i + 1]))) {
jsonStarted = true;
// Find end of number
let j = i + 1;
while (j < input.length && /[\d.eE+-]/.test(input[j])) {
j++;
}
lastValidJsonEnd = j;
i = j - 1; // Skip to end of number
continue;
}
// Check for boolean values and null
const remaining = input.substring(i);
if (remaining.startsWith('true')) {
jsonStarted = true;
lastValidJsonEnd = i + 4;
i += 3; // Skip to end of 'true'
continue;
}
else if (remaining.startsWith('false')) {
jsonStarted = true;
lastValidJsonEnd = i + 5;
i += 4; // Skip to end of 'false'
continue;
}
else if (remaining.startsWith('null')) {
jsonStarted = true;
lastValidJsonEnd = i + 4;
i += 3; // Skip to end of 'null'
continue;
}
}
}
// If we found valid JSON, trim to that point
if (lastValidJsonEnd > 0) {
return input.substring(0, lastValidJsonEnd).trimEnd();
}
// If no valid JSON end was found but we're at depth 0, the whole input might be valid
if (depth === 0 && jsonStarted) {
// Try to parse it to verify
try {
JSON.parse(input.trim());
return input.trimEnd();
}
catch {
// Not valid JSON, return as is
}
}
return input;
}
//# sourceMappingURL=trailing-content-removal.js.map