mirror of
https://github.com/morluto/rea.git
synced 2026-10-26 17:35:11 +00:00
fix(cli): format arrays of empty objects without keys as JSON (#7058)
When formatting arrays of objects that have no own enumerable keys as Markdown, formatObjectTable derives empty headers and outputs a malformed table with an invalid delimiter row. Require at least one item with keys in isObjectArray and fall back to JSON serialization when headers are empty. Fixes #7057
This commit is contained in:
1 parent
75e0d620bf
commit
4ed33efb0c
3 files changed
+21
-1
No files matched your search
@@ -40,7 +40,8 @@ const isObjectArray = (value: unknown): value is Record<string, unknown>[] =>
|
||||
value.length > 0 &&
|
||||
value.every(
|
||||
(item) => typeof item === "object" && item !== null && !Array.isArray(item),
|
||||
);
|
||||
) &&
|
||||
value.some((item) => Object.keys(item).length > 0);
|
||||
|
||||
const escapeTableCell = (value: string): string =>
|
||||
value
|
||||
@@ -55,6 +56,7 @@ const renderTable = (
|
||||
headers: readonly string[],
|
||||
rows: readonly string[][],
|
||||
): string => {
|
||||
if (headers.length === 0) return "";
|
||||
const escapedHeaders = headers.map(escapeTableCell);
|
||||
const widths = escapedHeaders.map((header) => header.length);
|
||||
for (const row of rows) {
|
||||
@@ -105,6 +107,7 @@ const formatObjectTable = (
|
||||
seen.add(key);
|
||||
headers.push(key);
|
||||
}
|
||||
if (headers.length === 0) return markdownCell(items);
|
||||
return renderTable(
|
||||
headers,
|
||||
items.map((item) =>
|
||||
|
||||
@@ -34,6 +34,14 @@ describe("CLI output argument boundary", () => {
|
||||
expect(JSON.parse(renderCliDocument(value, "json", false))).toEqual(value);
|
||||
});
|
||||
|
||||
it("formats arrays of empty objects without column keys as JSON in Markdown", () => {
|
||||
expect(renderCliDocument([{}], "md", false)).toBe("[{}]\n");
|
||||
expect(renderCliDocument([{}, {}], "md", false)).toBe("[{},{}]\n");
|
||||
expect(renderCliDocument({ empty: [{}] }, "md", false)).toBe(
|
||||
"## empty\n\n[{}]\n",
|
||||
);
|
||||
});
|
||||
|
||||
it("rejects token windows that would corrupt structured output", () => {
|
||||
for (const format of ["json", "jsonl", "yaml"] as const) {
|
||||
const validation = parseCliOutputArguments([
|
||||
|
||||
@@ -91,6 +91,15 @@ it("renders only each record's own fields in heterogeneous Markdown tables", asy
|
||||
]);
|
||||
});
|
||||
|
||||
it("formats arrays of empty objects without columns as JSON in Markdown", async () => {
|
||||
const value: unknown = [{}, {}];
|
||||
freezeRecursively(value);
|
||||
const json = await runFilteredCli(value, "json");
|
||||
expect(JSON.parse(json)).toEqual(value);
|
||||
const markdown = await runFilteredCli(value, "md");
|
||||
expect(markdown).toBe("[{},{}]\n");
|
||||
});
|
||||
|
||||
it.each(
|
||||
(["json", "jsonl"] as const).flatMap((format) =>
|
||||
[false, true].map((full) => ({ format, full })),
|
||||
|
||||
Reference in new issue
Block a user