fix: prevent embedded JSON examples from rendering as result cards

Only parse full-message generated JSON results
Keep markdown prose with JSON examples rendered normally
Add regression coverage for embedded JSON examples
This commit is contained in:
Bohdan Triapitsyn
2026-06-29 12:19:28 +03:00
parent a1fddd2542
commit 9c1eb755f9
2 changed files with 46 additions and 12 deletions
@@ -0,0 +1,40 @@
import { describe, expect, test } from 'bun:test';
import { parseGeneratedJsonResult } from './generatedJsonResult';
describe('parseGeneratedJsonResult', () => {
test('parses a full pull request JSON result', () => {
expect(parseGeneratedJsonResult('{"title":"Side task","body":"Details"}')).toEqual({
kind: 'pr',
title: 'Side task',
body: 'Details',
raw: JSON.stringify({ title: 'Side task', body: 'Details' }, null, 2),
});
});
test('parses a full fenced JSON result', () => {
expect(parseGeneratedJsonResult('```json\n{"subject":"Fix parser","highlights":["Narrow detection"]}\n```')).toEqual({
kind: 'commit',
subject: 'Fix parser',
highlights: ['Narrow detection'],
raw: JSON.stringify({ subject: 'Fix parser', highlights: ['Narrow detection'] }, null, 2),
});
});
test('ignores JSON examples embedded in markdown prose', () => {
const markdown = [
'Recommended endpoint:',
'',
'```json',
'{',
' "title": "Side task",',
' "prompt": "Investigate X"',
'}',
'```',
'',
'This should stay markdown.',
].join('\n');
expect(parseGeneratedJsonResult(markdown)).toBeNull();
});
});
@@ -16,21 +16,15 @@ export type GeneratedResult = GeneratedCommitResult | GeneratedPrResult;
const parseJsonObjects = (value: string): Record<string, unknown>[] => {
const text = value.trim();
const candidates = new Set<string>();
const candidates: string[] = [];
const fencedMatches = text.matchAll(/```(?:json)?\s*([\s\S]*?)```/gi);
for (const match of fencedMatches) {
if (match[1]) candidates.add(match[1].trim());
const fencedMatch = text.match(/^```(?:json)?\s*([\s\S]*?)```$/i);
if (fencedMatch?.[1]) {
candidates.push(fencedMatch[1].trim());
}
const firstObjectStart = text.indexOf('{');
if (firstObjectStart >= 0) {
for (let end = text.length; end > firstObjectStart; end -= 1) {
if (text[end - 1] === '}') {
candidates.add(text.slice(firstObjectStart, end));
break;
}
}
if (text.startsWith('{') && text.endsWith('}')) {
candidates.push(text);
}
const parsed: Record<string, unknown>[] = [];