conductor-tasks
Version:
Task Manager for AI Development
212 lines • 10.8 kB
JavaScript
import logger from './logger.js';
export class JsonUtils {
static extractJsonArray(text, fallbackToEmpty = false) {
if (!text || typeof text !== 'string') {
logger.debug('JsonUtils.extractJsonArray: Input is empty or not a string');
return fallbackToEmpty ? [] : null;
}
logger.debug(`JsonUtils.extractJsonArray: Processing text (${text.length} chars): ${text.substring(0, 100)}...`);
try {
const trimmedText = text.trim();
const parsed = JSON.parse(trimmedText);
if (Array.isArray(parsed)) {
logger.debug(`JsonUtils.extractJsonArray: Successfully parsed as array with ${parsed.length} items`);
return parsed;
}
else {
if (typeof parsed === 'object' && parsed !== null) {
logger.debug('JsonUtils.extractJsonArray: Parsed as object, wrapping in array');
return [parsed];
}
logger.debug(`JsonUtils.extractJsonArray: Parsed as non-array, non-object type: ${typeof parsed}`);
return fallbackToEmpty ? [] : null;
}
}
catch (error) {
logger.debug(`JsonUtils.extractJsonArray: Direct parsing failed: ${error instanceof Error ? error.message : String(error)}`);
}
const textWithoutMarkdown = text
.replace(/```json/g, '')
.replace(/```/g, '')
.trim();
try {
const parsed = JSON.parse(textWithoutMarkdown);
if (Array.isArray(parsed)) {
logger.debug(`JsonUtils.extractJsonArray: Successfully parsed without markdown as array with ${parsed.length} items`);
return parsed;
}
else if (typeof parsed === 'object' && parsed !== null) {
logger.debug('JsonUtils.extractJsonArray: Parsed without markdown as object, wrapping in array');
return [parsed];
}
}
catch (error) {
logger.debug(`JsonUtils.extractJsonArray: Parsing without markdown failed: ${error instanceof Error ? error.message : String(error)}`);
}
try {
let jsonMatch = text.match(/\[\s*\{[\s\S]*\}\s*\]/s);
if (jsonMatch && jsonMatch[0]) {
logger.debug(`JsonUtils.extractJsonArray: Found array pattern, attempting to parse match of length ${jsonMatch[0].length}`);
const parsed = JSON.parse(jsonMatch[0]);
if (Array.isArray(parsed)) {
logger.debug(`JsonUtils.extractJsonArray: Successfully parsed array pattern with ${parsed.length} items`);
return parsed;
}
}
else {
logger.debug('JsonUtils.extractJsonArray: No array pattern match found with regex');
}
}
catch (error) {
logger.debug(`JsonUtils.extractJsonArray: Array pattern parsing failed: ${error instanceof Error ? error.message : String(error)}`);
}
try {
const startIdx = text.indexOf('[');
const endIdx = text.lastIndexOf(']');
if (startIdx !== -1 && endIdx !== -1 && startIdx < endIdx) {
const jsonCandidate = text.substring(startIdx, endIdx + 1);
logger.debug(`JsonUtils.extractJsonArray: Found potential JSON array from index ${startIdx} to ${endIdx}, length: ${jsonCandidate.length}`);
const parsed = JSON.parse(jsonCandidate);
if (Array.isArray(parsed)) {
logger.debug(`JsonUtils.extractJsonArray: Successfully parsed bracket-extracted array with ${parsed.length} items`);
return parsed;
}
}
else {
logger.debug(`JsonUtils.extractJsonArray: Could not find valid [ and ] pair. Start index: ${startIdx}, End index: ${endIdx}`);
}
}
catch (error) {
logger.debug(`JsonUtils.extractJsonArray: Bracket extraction parsing failed: ${error instanceof Error ? error.message : String(error)}`);
}
try {
let jsonMatch = text.match(/\{\s*"[\s\S]*"\s*:[\s\S]*\}/s);
if (jsonMatch && jsonMatch[0]) {
logger.debug(`JsonUtils.extractJsonArray: Found object pattern, attempting to parse match of length ${jsonMatch[0].length}`);
const parsed = JSON.parse(jsonMatch[0]);
if (typeof parsed === 'object' && parsed !== null) {
logger.debug('JsonUtils.extractJsonArray: Successfully parsed object pattern, wrapping in array');
return [parsed];
}
}
else {
logger.debug('JsonUtils.extractJsonArray: No object pattern match found with regex');
}
}
catch (error) {
logger.debug(`JsonUtils.extractJsonArray: Object pattern parsing failed: ${error instanceof Error ? error.message : String(error)}`);
}
try {
const startMarkers = [
"===== START LLM RESPONSE =====",
"START JSON",
"JSON RESPONSE:",
"JSON_RESPONSE:",
"JSON START"
];
const endMarkers = [
"===== END LLM RESPONSE =====",
"END JSON",
"END OF JSON",
"JSON END"
];
let cleanedText = text;
for (const startMarker of startMarkers) {
const startIdx = text.indexOf(startMarker);
if (startIdx !== -1) {
cleanedText = text.substring(startIdx + startMarker.length);
logger.debug(`JsonUtils.extractJsonArray: Found start marker "${startMarker}" at position ${startIdx}`);
break;
}
}
for (const endMarker of endMarkers) {
const endIdx = cleanedText.indexOf(endMarker);
if (endIdx !== -1) {
cleanedText = cleanedText.substring(0, endIdx);
logger.debug(`JsonUtils.extractJsonArray: Found end marker "${endMarker}"`);
break;
}
}
if (cleanedText !== text) {
logger.debug(`JsonUtils.extractJsonArray: Extracted content between markers, length: ${cleanedText.length}`);
const trimmed = cleanedText.trim();
if ((trimmed.startsWith('[') && trimmed.endsWith(']')) ||
(trimmed.startsWith('{') && trimmed.endsWith('}'))) {
try {
const parsed = JSON.parse(trimmed);
if (Array.isArray(parsed)) {
logger.debug(`JsonUtils.extractJsonArray: Successfully parsed marker-extracted array with ${parsed.length} items`);
return parsed;
}
else if (typeof parsed === 'object' && parsed !== null) {
logger.debug('JsonUtils.extractJsonArray: Successfully parsed marker-extracted object, wrapping in array');
return [parsed];
}
}
catch (error) {
logger.debug(`JsonUtils.extractJsonArray: Marker extraction parsing failed: ${error instanceof Error ? error.message : String(error)}`);
}
}
}
}
catch (error) {
logger.debug(`JsonUtils.extractJsonArray: Log marker extraction failed: ${error instanceof Error ? error.message : String(error)}`);
}
try {
let cleanText = text
.replace(/^[\s\S]*?(\[)/m, '[')
.replace(/(\])[\s\S]*$/m, ']')
.replace(/```json/g, '')
.replace(/```/g, '')
.replace(/\n/g, ' ')
.replace(/,\s*]/g, ']')
.replace(/,\s*}/g, '}')
.replace(/'/g, '"')
.replace(/([{,])\s*([a-zA-Z0-9_]+)\s*:/g, '$1"$2":');
logger.debug(`JsonUtils.extractJsonArray: Attempting aggressive cleaning, cleaned text length: ${cleanText.length}`);
const parsed = JSON.parse(cleanText);
if (Array.isArray(parsed)) {
logger.debug(`JsonUtils.extractJsonArray: Successfully parsed aggressively cleaned array with ${parsed.length} items`);
return parsed;
}
else if (typeof parsed === 'object' && parsed !== null) {
logger.debug('JsonUtils.extractJsonArray: Successfully parsed aggressively cleaned object, wrapping in array');
return [parsed];
}
}
catch (error) {
logger.debug(`JsonUtils.extractJsonArray: Aggressive cleaning parsing failed: ${error instanceof Error ? error.message : String(error)}`);
}
try {
let extremeCleanText = text
.replace(/[\u0000-\u001F\u007F-\u009F]/g, '')
.replace(/[^\[\]\{\}",:.\w\s-]/g, ' ')
.replace(/\s+/g, ' ')
.trim();
logger.debug(`JsonUtils.extractJsonArray: Attempting extreme cleaning, cleaned text length: ${extremeCleanText.length}`);
const objMatch = extremeCleanText.match(/\{[^{}]*"[^{}]*"[^{}]*:[^{}]*("[^{}]*"|[0-9]+)[^{}]*\}/g);
if (objMatch && objMatch.length > 0) {
const arrayStr = '[' + objMatch.join(',') + ']';
logger.debug(`JsonUtils.extractJsonArray: Found ${objMatch.length} object patterns, attempting to construct array`);
const parsed = JSON.parse(arrayStr);
if (Array.isArray(parsed) && parsed.length > 0) {
logger.debug(`JsonUtils.extractJsonArray: Successfully parsed array from ${parsed.length} extracted objects`);
return parsed;
}
}
else {
logger.debug('JsonUtils.extractJsonArray: No valid object patterns found in extreme cleaning');
}
}
catch (error) {
logger.debug(`JsonUtils.extractJsonArray: Extreme cleaning parsing failed: ${error instanceof Error ? error.message : String(error)}`);
}
logger.debug(`JsonUtils.extractJsonArray: All extraction attempts failed, returning ${fallbackToEmpty ? 'empty array' : 'null'}`);
return fallbackToEmpty ? [] : null;
}
static ensureJsonArray(text) {
const result = this.extractJsonArray(text, true);
return result || [];
}
}
//# sourceMappingURL=jsonUtils.js.map