From 84dd2a4afd82a5bdd39a83103b57751e3533a4ef Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 13 Nov 2025 15:08:15 +0000 Subject: [PATCH 1/3] Initial plan From aa430dbcbc2b31a64564b7dc5963021f444971aa Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 13 Nov 2025 15:18:07 +0000 Subject: [PATCH 2/3] Add pipe character escaping for markdown table cells Co-authored-by: MaestroError <46760939+MaestroError@users.noreply.github.com> --- src/Services/PropertiesTable.php | 17 ++- tests/Services/PropertiesTableTest.php | 164 +++++++++++++++++++++++++ 2 files changed, 180 insertions(+), 1 deletion(-) diff --git a/src/Services/PropertiesTable.php b/src/Services/PropertiesTable.php index abed15c..decaf25 100644 --- a/src/Services/PropertiesTable.php +++ b/src/Services/PropertiesTable.php @@ -29,7 +29,11 @@ public function convertPropertiesToMarkdownTable(array $properties): string continue; } - $markdown .= "| {$name} | {$value} |\n"; + // Escape pipe characters in property name and value + $escapedName = $this->escapePipeCharacters($name); + $escapedValue = $this->escapePipeCharacters($value); + + $markdown .= "| {$escapedName} | {$escapedValue} |\n"; } return $markdown."\n"; @@ -289,4 +293,15 @@ private function formatUser(?array $user): string return $user['name'] ?? 'Unknown'; } + + /** + * Escape pipe characters in markdown table cells + * + * @param string $text Text to escape + * @return string Escaped text + */ + private function escapePipeCharacters(string $text): string + { + return str_replace('|', '\|', $text); + } } diff --git a/tests/Services/PropertiesTableTest.php b/tests/Services/PropertiesTableTest.php index 474b0fd..2f252e4 100644 --- a/tests/Services/PropertiesTableTest.php +++ b/tests/Services/PropertiesTableTest.php @@ -489,3 +489,167 @@ expect($result)->toContain('| Description | This is a description |'); }); + +test('escapes pipe characters in property names', function () { + $properties = [ + 'Name | Title' => [ + 'id' => 'title', + 'type' => 'title', + 'title' => [ + ['plain_text' => 'Test Page'], + ], + ], + ]; + + $result = $this->propertiesTable->convertPropertiesToMarkdownTable($properties); + + expect($result)->toContain('| Name \| Title | Test Page |'); +}); + +test('escapes pipe characters in property values', function () { + $properties = [ + 'Description' => [ + 'id' => 'rich', + 'type' => 'rich_text', + 'rich_text' => [ + ['plain_text' => 'Value with | pipe'], + ], + ], + ]; + + $result = $this->propertiesTable->convertPropertiesToMarkdownTable($properties); + + expect($result)->toContain('| Description | Value with \| pipe |'); +}); + +test('escapes multiple pipe characters in property names and values', function () { + $properties = [ + 'A | B | C' => [ + 'id' => 'title', + 'type' => 'title', + 'title' => [ + ['plain_text' => 'X | Y | Z'], + ], + ], + ]; + + $result = $this->propertiesTable->convertPropertiesToMarkdownTable($properties); + + expect($result)->toContain('| A \| B \| C | X \| Y \| Z |'); +}); + +test('escapes pipe characters in select property values', function () { + $properties = [ + 'Type' => [ + 'id' => 'select', + 'type' => 'select', + 'select' => [ + 'id' => 'LOQu', + 'name' => 'option-1 | option-2', + 'color' => 'pink', + ], + ], + ]; + + $result = $this->propertiesTable->convertPropertiesToMarkdownTable($properties); + + expect($result)->toContain('| Type | option-1 \| option-2 |'); +}); + +test('escapes pipe characters in multi_select property values', function () { + $properties = [ + 'Tags' => [ + 'id' => 'multi_select', + 'type' => 'multi_select', + 'multi_select' => [ + [ + 'id' => 'tag1', + 'name' => 'tag | 1', + 'color' => 'blue', + ], + [ + 'id' => 'tag2', + 'name' => 'tag | 2', + 'color' => 'green', + ], + ], + ], + ]; + + $result = $this->propertiesTable->convertPropertiesToMarkdownTable($properties); + + expect($result)->toContain('| Tags | tag \| 1, tag \| 2 |'); +}); + +test('escapes pipe characters in people names', function () { + $properties = [ + 'Person' => [ + 'id' => 'people', + 'type' => 'people', + 'people' => [ + ['name' => 'John | Doe'], + ['name' => 'Jane | Smith'], + ], + ], + ]; + + $result = $this->propertiesTable->convertPropertiesToMarkdownTable($properties); + + expect($result)->toContain('| Person | John \| Doe, Jane \| Smith |'); +}); + +test('escapes pipe characters in file names', function () { + $properties = [ + 'Files' => [ + 'id' => 'files', + 'type' => 'files', + 'files' => [ + [ + 'name' => 'file | name.pdf', + 'type' => 'external', + 'external' => [ + 'url' => 'https://example.com/file.pdf', + ], + ], + ], + ], + ]; + + $result = $this->propertiesTable->convertPropertiesToMarkdownTable($properties); + + expect($result)->toContain('| Files | [file \| name.pdf](https://example.com/file.pdf) |'); +}); + +test('escapes pipe characters in user names', function () { + $properties = [ + 'Created By' => [ + 'id' => 'created_by', + 'type' => 'created_by', + 'created_by' => [ + 'id' => 'user-id', + 'name' => 'John | Doe', + ], + ], + ]; + + $result = $this->propertiesTable->convertPropertiesToMarkdownTable($properties); + + expect($result)->toContain('| Created By | John \| Doe |'); +}); + +test('escapes pipe characters in formula string values', function () { + $properties = [ + 'Calculated' => [ + 'id' => 'formula', + 'type' => 'formula', + 'formula' => [ + 'type' => 'string', + 'string' => 'Result | Text', + ], + ], + ]; + + $result = $this->propertiesTable->convertPropertiesToMarkdownTable($properties); + + expect($result)->toContain('| Calculated | Result \| Text |'); +}); From 13b9251be674abf7ef28d89f73bacb769ccadbe9 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 13 Nov 2025 15:45:23 +0000 Subject: [PATCH 3/3] Add newline character handling for markdown table cells Co-authored-by: MaestroError <46760939+MaestroError@users.noreply.github.com> --- src/Services/PropertiesTable.php | 18 ++- tests/Services/PropertiesTableTest.php | 156 +++++++++++++++++++++++++ 2 files changed, 168 insertions(+), 6 deletions(-) diff --git a/src/Services/PropertiesTable.php b/src/Services/PropertiesTable.php index decaf25..30f00a3 100644 --- a/src/Services/PropertiesTable.php +++ b/src/Services/PropertiesTable.php @@ -29,9 +29,9 @@ public function convertPropertiesToMarkdownTable(array $properties): string continue; } - // Escape pipe characters in property name and value - $escapedName = $this->escapePipeCharacters($name); - $escapedValue = $this->escapePipeCharacters($value); + // Escape special characters in property name and value + $escapedName = $this->escapeTableCellCharacters($name); + $escapedValue = $this->escapeTableCellCharacters($value); $markdown .= "| {$escapedName} | {$escapedValue} |\n"; } @@ -295,13 +295,19 @@ private function formatUser(?array $user): string } /** - * Escape pipe characters in markdown table cells + * Escape special characters in markdown table cells * * @param string $text Text to escape * @return string Escaped text */ - private function escapePipeCharacters(string $text): string + private function escapeTableCellCharacters(string $text): string { - return str_replace('|', '\|', $text); + // Escape pipe characters to prevent table structure corruption + $text = str_replace('|', '\|', $text); + + // Replace newline characters with spaces to maintain table structure + $text = str_replace(["\r\n", "\r", "\n"], ' ', $text); + + return $text; } } diff --git a/tests/Services/PropertiesTableTest.php b/tests/Services/PropertiesTableTest.php index 2f252e4..2cda6d0 100644 --- a/tests/Services/PropertiesTableTest.php +++ b/tests/Services/PropertiesTableTest.php @@ -653,3 +653,159 @@ expect($result)->toContain('| Calculated | Result \| Text |'); }); + +test('replaces newline characters with spaces in property values', function () { + $properties = [ + 'Description' => [ + 'id' => 'rich', + 'type' => 'rich_text', + 'rich_text' => [ + ['plain_text' => "Line 1\nLine 2"], + ], + ], + ]; + + $result = $this->propertiesTable->convertPropertiesToMarkdownTable($properties); + + expect($result)->toContain('| Description | Line 1 Line 2 |'); +}); + +test('replaces carriage return with spaces in property values', function () { + $properties = [ + 'Description' => [ + 'id' => 'rich', + 'type' => 'rich_text', + 'rich_text' => [ + ['plain_text' => "Line 1\rLine 2"], + ], + ], + ]; + + $result = $this->propertiesTable->convertPropertiesToMarkdownTable($properties); + + expect($result)->toContain('| Description | Line 1 Line 2 |'); +}); + +test('replaces CRLF with spaces in property values', function () { + $properties = [ + 'Description' => [ + 'id' => 'rich', + 'type' => 'rich_text', + 'rich_text' => [ + ['plain_text' => "Line 1\r\nLine 2"], + ], + ], + ]; + + $result = $this->propertiesTable->convertPropertiesToMarkdownTable($properties); + + expect($result)->toContain('| Description | Line 1 Line 2 |'); +}); + +test('replaces multiple newlines with spaces in property values', function () { + $properties = [ + 'Description' => [ + 'id' => 'rich', + 'type' => 'rich_text', + 'rich_text' => [ + ['plain_text' => "Line 1\n\nLine 2\n\nLine 3"], + ], + ], + ]; + + $result = $this->propertiesTable->convertPropertiesToMarkdownTable($properties); + + expect($result)->toContain('| Description | Line 1 Line 2 Line 3 |'); +}); + +test('replaces newlines in property names', function () { + $properties = [ + "Multi\nLine\nName" => [ + 'id' => 'title', + 'type' => 'title', + 'title' => [ + ['plain_text' => 'Test Value'], + ], + ], + ]; + + $result = $this->propertiesTable->convertPropertiesToMarkdownTable($properties); + + expect($result)->toContain('| Multi Line Name | Test Value |'); +}); + +test('handles both newlines and pipe characters together', function () { + $properties = [ + "Name | Title\nWith Newline" => [ + 'id' => 'rich', + 'type' => 'rich_text', + 'rich_text' => [ + ['plain_text' => "Value | with\npipe and\nnewlines"], + ], + ], + ]; + + $result = $this->propertiesTable->convertPropertiesToMarkdownTable($properties); + + expect($result)->toContain('| Name \| Title With Newline | Value \| with pipe and newlines |'); +}); + +test('replaces newlines in select property values', function () { + $properties = [ + 'Type' => [ + 'id' => 'select', + 'type' => 'select', + 'select' => [ + 'id' => 'LOQu', + 'name' => "Option\nWith\nNewlines", + 'color' => 'pink', + ], + ], + ]; + + $result = $this->propertiesTable->convertPropertiesToMarkdownTable($properties); + + expect($result)->toContain('| Type | Option With Newlines |'); +}); + +test('replaces newlines in multi_select property values', function () { + $properties = [ + 'Tags' => [ + 'id' => 'multi_select', + 'type' => 'multi_select', + 'multi_select' => [ + [ + 'id' => 'tag1', + 'name' => "Tag\n1", + 'color' => 'blue', + ], + [ + 'id' => 'tag2', + 'name' => "Tag\n2", + 'color' => 'green', + ], + ], + ], + ]; + + $result = $this->propertiesTable->convertPropertiesToMarkdownTable($properties); + + expect($result)->toContain('| Tags | Tag 1, Tag 2 |'); +}); + +test('replaces newlines in people names', function () { + $properties = [ + 'Person' => [ + 'id' => 'people', + 'type' => 'people', + 'people' => [ + ['name' => "John\nDoe"], + ['name' => "Jane\nSmith"], + ], + ], + ]; + + $result = $this->propertiesTable->convertPropertiesToMarkdownTable($properties); + + expect($result)->toContain('| Person | John Doe, Jane Smith |'); +});