| import { logger } from './logger.js'; |
|
|
| |
| |
| |
| export function extractCodeBlocks(markdown: string): Array<{ language: string; code: string }> { |
| const regex = /```(\w*)\n([\s\S]*?)```/g; |
| const blocks: Array<{ language: string; code: string }> = []; |
| let match; |
| while ((match = regex.exec(markdown)) !== null) { |
| blocks.push({ language: match[1] || 'plaintext', code: match[2].trim() }); |
| } |
| return blocks; |
| } |
|
|
| |
| |
| |
| |
| export function parseJSONSafe<T>(raw: string, fallback: T): T { |
| |
| try { |
| return JSON.parse(raw) as T; |
| } catch { |
| |
| } |
|
|
| |
| const jsonFence = raw.match(/```(?:json)?\s*\n?([\s\S]*?)```/); |
| if (jsonFence) { |
| try { |
| return JSON.parse(jsonFence[1].trim()) as T; |
| } catch { |
| |
| } |
| } |
|
|
| |
| const firstBrace = raw.indexOf('{'); |
| const lastBrace = raw.lastIndexOf('}'); |
| if (firstBrace !== -1 && lastBrace > firstBrace) { |
| try { |
| return JSON.parse(raw.substring(firstBrace, lastBrace + 1)) as T; |
| } catch { |
| |
| } |
| } |
|
|
| |
| const firstBracket = raw.indexOf('['); |
| const lastBracket = raw.lastIndexOf(']'); |
| if (firstBracket !== -1 && lastBracket > firstBracket) { |
| try { |
| return JSON.parse(raw.substring(firstBracket, lastBracket + 1)) as T; |
| } catch { |
| |
| } |
| } |
|
|
| logger.warn('Failed to parse JSON from AI response, using fallback'); |
| return fallback; |
| } |
|
|
| |
| |
| |
| export function stripCodeFences(text: string): string { |
| return text.replace(/^```\w*\n?/, '').replace(/\n?```$/, '').trim(); |
| } |
|
|