Files
aurak/server/src/common/json-utils.ts
T

53 lines
1.7 KiB
TypeScript

import { Logger } from '@nestjs/common';
const logger = new Logger('JsonUtils');
/**
* Safely parses JSON from a string, handling markdown code blocks and leading/trailing text.
*/
export function safeParseJson<T = any>(text: string): T | null {
if (!text) return null;
let jsonStr = text.trim();
// 1. Try to extract JSON from markdown code blocks if they exist
// Matches ```json ... ``` or just ``` ... ```
const codeBlockRegex = /```(?:json)?\s*([\s\S]*?)\s*```/i;
const match = jsonStr.match(codeBlockRegex);
if (match && match[1]) {
jsonStr = match[1].trim();
} else {
// 2. If no markdown block, try to find the start and end of JSON characters
// This handles cases where the AI adds introductory or concluding text outside the block
const firstOpenBrace = jsonStr.indexOf('{');
const firstOpenBracket = jsonStr.indexOf('[');
let startIndex = -1;
if (firstOpenBrace !== -1 && (firstOpenBracket === -1 || firstOpenBrace < firstOpenBracket)) {
startIndex = firstOpenBrace;
} else if (firstOpenBracket !== -1) {
startIndex = firstOpenBracket;
}
if (startIndex !== -1) {
const lastCloseBrace = jsonStr.lastIndexOf('}');
const lastCloseBracket = jsonStr.lastIndexOf(']');
const endIndex = Math.max(lastCloseBrace, lastCloseBracket);
if (endIndex !== -1 && endIndex > startIndex) {
jsonStr = jsonStr.substring(startIndex, endIndex + 1);
}
}
}
try {
return JSON.parse(jsonStr) as T;
} catch (error) {
logger.error('[safeParseJson] Failed to parse JSON:', error);
logger.error('[safeParseJson] Original text:', text);
logger.error('[safeParseJson] Extracted string:', jsonStr);
return null;
}
}