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:
@@ -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>[] = [];
|
||||
|
||||
Reference in New Issue
Block a user