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 parseJsonObjects = (value: string): Record<string, unknown>[] => {
|
||||||
const text = value.trim();
|
const text = value.trim();
|
||||||
const candidates = new Set<string>();
|
const candidates: string[] = [];
|
||||||
|
|
||||||
const fencedMatches = text.matchAll(/```(?:json)?\s*([\s\S]*?)```/gi);
|
const fencedMatch = text.match(/^```(?:json)?\s*([\s\S]*?)```$/i);
|
||||||
for (const match of fencedMatches) {
|
if (fencedMatch?.[1]) {
|
||||||
if (match[1]) candidates.add(match[1].trim());
|
candidates.push(fencedMatch[1].trim());
|
||||||
}
|
}
|
||||||
|
|
||||||
const firstObjectStart = text.indexOf('{');
|
if (text.startsWith('{') && text.endsWith('}')) {
|
||||||
if (firstObjectStart >= 0) {
|
candidates.push(text);
|
||||||
for (let end = text.length; end > firstObjectStart; end -= 1) {
|
|
||||||
if (text[end - 1] === '}') {
|
|
||||||
candidates.add(text.slice(firstObjectStart, end));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const parsed: Record<string, unknown>[] = [];
|
const parsed: Record<string, unknown>[] = [];
|
||||||
|
|||||||
Reference in New Issue
Block a user