Skip to content

Commit 9843dd1

Browse files
committed
Escape pipe characters in deployment summary table cells
1 parent e3f615d commit 9843dd1

3 files changed

Lines changed: 16 additions & 3 deletions

File tree

__tests__/DeploymentSummary.test.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,11 @@ describe('DeploymentSummary tests', () => {
6767
expect(markdown).toContain('| `[dbo].[Reactions]` | Table |');
6868
});
6969

70+
it('escapes pipe characters in object names so the table is not broken', () => {
71+
const markdown = buildSummary({ ...baseContext, report: { operations: [{ operation: 'Create', object: '[dbo].[Odd|Name]', type: 'Table' }], alerts: [] } });
72+
expect(markdown).toContain('[dbo].[Odd\\|Name]');
73+
});
74+
7075
it('renders a data-loss callout when alerts are present', () => {
7176
const markdown = buildSummary({ ...baseContext, report });
7277
expect(markdown).toContain('### ⚠️ Possible data loss (1)');

lib/main.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/DeploymentSummary.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ function renderMetadataTable(context: SummaryContext): string[] {
129129
rows.push(['Commit', `\`${context.commit}\``]);
130130
}
131131
if (context.options) {
132-
rows.push(['Options', `\`${context.options}\``]);
132+
rows.push(['Options', `\`${escapeCell(context.options)}\``]);
133133
}
134134

135135
const lines: string[] = ['| | |', '|---|---|'];
@@ -221,7 +221,7 @@ function renderSection(title: string, items: DeploymentOperation[], open: boolea
221221

222222
const shown = items.slice(0, MAX_ROWS_PER_SECTION);
223223
for (const item of shown) {
224-
lines.push(`| \`${item.object}\` | ${item.type} |`);
224+
lines.push(`| \`${escapeCell(item.object)}\` | ${escapeCell(item.type)} |`);
225225
}
226226
const remaining = items.length - shown.length;
227227
if (remaining > 0) {
@@ -363,6 +363,14 @@ function formatCounts(counts: Array<[string, number]>): string {
363363
return counts.map(([key, count]) => `${key} ×${count}`).join(' · ');
364364
}
365365

366+
/**
367+
* Escapes a value so it can be safely placed in a Markdown table cell, where an
368+
* unescaped pipe would otherwise be interpreted as a column separator.
369+
*/
370+
function escapeCell(value: string): string {
371+
return value.replace(/\|/g, '\\|');
372+
}
373+
366374
/**
367375
* Formats a duration in milliseconds as a compact, human-readable string.
368376
*/

0 commit comments

Comments
 (0)