Skip to content

Commit 2ff821a

Browse files
committed
fix(formatters): address second round of Seer/BugBot review feedback
- escapeMarkdownCell: replace newlines with space to prevent multi-line values from splitting a markdown table row across multiple lines (affects log messages, breadcrumb messages, tag values, any user content) - formatLogTable / formatTraceTable: wire into the non-follow batch list paths (log/list.ts executeSingleFetch, trace/list.ts) — replaces the formatLogsHeader + formatLogRow loop so batch mode gets proper Unicode-bordered table rendering, streaming/follow mode still uses rows - project/view.ts: restore muted() styling on the multi-project divider by importing and calling divider(60) instead of bare "─".repeat(60)
1 parent 3ecf278 commit 2ff821a

5 files changed

Lines changed: 17 additions & 14 deletions

File tree

src/commands/log/list.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import { AuthError, stringifyUnknown } from "../../lib/errors.js";
1414
import {
1515
formatLogRow,
1616
formatLogsHeader,
17+
formatLogTable,
1718
writeFooter,
1819
writeJson,
1920
} from "../../lib/formatters/index.js";
@@ -115,10 +116,7 @@ async function executeSingleFetch(
115116
// Reverse for chronological order (API returns newest first, tail shows oldest first)
116117
const chronological = [...logs].reverse();
117118

118-
stdout.write(formatLogsHeader());
119-
for (const log of chronological) {
120-
stdout.write(formatLogRow(log));
121-
}
119+
stdout.write(`${formatLogTable(chronological)}\n`);
122120

123121
// Show footer with tip if we hit the limit
124122
const hasMore = logs.length >= flags.limit;

src/commands/project/view.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import { openInBrowser } from "../../lib/browser.js";
1515
import { buildCommand } from "../../lib/command.js";
1616
import { AuthError, ContextError } from "../../lib/errors.js";
1717
import {
18+
divider,
1819
formatProjectDetails,
1920
writeJson,
2021
writeOutput,
@@ -182,7 +183,7 @@ function writeMultipleProjects(
182183
const target = targets[i];
183184

184185
if (i > 0) {
185-
stdout.write(`\n${"─".repeat(60)}\n\n`);
186+
stdout.write(`\n${divider(60)}\n\n`);
186187
}
187188

188189
if (project) {

src/commands/trace/list.ts

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,7 @@ import type { SentryContext } from "../../context.js";
88
import { listTransactions } from "../../lib/api-client.js";
99
import { validateLimit } from "../../lib/arg-parsing.js";
1010
import {
11-
formatTraceRow,
12-
formatTracesHeader,
11+
formatTraceTable,
1312
writeFooter,
1413
writeJson,
1514
} from "../../lib/formatters/index.js";
@@ -152,10 +151,7 @@ export const listCommand = buildListCommand("trace", {
152151
}
153152

154153
stdout.write(`Recent traces in ${org}/${project}:\n\n`);
155-
stdout.write(formatTracesHeader());
156-
for (const trace of traces) {
157-
stdout.write(formatTraceRow(trace));
158-
}
154+
stdout.write(`${formatTraceTable(traces)}\n`);
159155

160156
// Show footer with tip
161157
const hasMore = traces.length >= flags.limit;

src/lib/formatters/markdown.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -122,14 +122,17 @@ export function isPlainOutput(): boolean {
122122
/**
123123
* Escape a string for safe use inside a markdown table cell.
124124
*
125-
* Escapes backslashes first (so the escape character itself is not
126-
* double-interpreted), then pipe characters (the table cell delimiter).
125+
* - Escapes backslashes first (so the escape character itself is not
126+
* double-interpreted)
127+
* - Escapes pipe characters (the table cell delimiter)
128+
* - Replaces newlines with a space so multi-line values don't break the
129+
* single-row structure of a markdown table
127130
*
128131
* @param value - Raw cell content
129132
* @returns Markdown-safe string suitable for embedding in `| cell |` syntax
130133
*/
131134
export function escapeMarkdownCell(value: string): string {
132-
return value.replace(/\\/g, "\\\\").replace(/\|/g, "\\|");
135+
return value.replace(/\n/g, " ").replace(/\\/g, "\\\\").replace(/\|/g, "\\|");
133136
}
134137

135138
/**

test/lib/formatters/markdown.test.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,11 @@ describe("escapeMarkdownCell", () => {
300300
expect(escapeMarkdownCell("")).toBe("");
301301
});
302302

303+
test("replaces newlines with a space to preserve row structure", () => {
304+
expect(escapeMarkdownCell("line1\nline2")).toBe("line1 line2");
305+
expect(escapeMarkdownCell("a\nb\nc")).toBe("a b c");
306+
});
307+
303308
test("handles multiple pipes", () => {
304309
const result = escapeMarkdownCell("a|b|c");
305310
expect(result).toBe("a\\|b\\|c");

0 commit comments

Comments
 (0)