53 lines
1.7 KiB
TypeScript
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;
|
|
}
|
|
}
|