From f4646a2e08b4530696f72c740a3c81810ba97c9e Mon Sep 17 00:00:00 2001 From: Kazuyuki Hayashi Date: Wed, 7 Aug 2013 23:34:43 +0900 Subject: [PATCH] triggers syntax error when number of table cells in header/body are not the same (on strict mode) #4 --- src/Ciconia/Extension/Gfm/TableExtension.php | 108 +++++++++++++----- test/Ciconia/CiconiaTest.php | 2 + .../core/strict/table-invalid-body.md | 3 + .../core/strict/table-invalid-body.out | 3 + .../core/strict/table-invalid-header.md | 3 + .../core/strict/table-invalid-header.out | 3 + 6 files changed, 93 insertions(+), 29 deletions(-) create mode 100644 test/Ciconia/Resources/core/strict/table-invalid-body.md create mode 100644 test/Ciconia/Resources/core/strict/table-invalid-body.out create mode 100644 test/Ciconia/Resources/core/strict/table-invalid-header.md create mode 100644 test/Ciconia/Resources/core/strict/table-invalid-header.out diff --git a/src/Ciconia/Extension/Gfm/TableExtension.php b/src/Ciconia/Extension/Gfm/TableExtension.php index a7be088..784aa58 100644 --- a/src/Ciconia/Extension/Gfm/TableExtension.php +++ b/src/Ciconia/Extension/Gfm/TableExtension.php @@ -5,6 +5,7 @@ use Ciconia\Common\Collection; use Ciconia\Common\Tag; use Ciconia\Common\Text; +use Ciconia\Exception\SyntaxError; use Ciconia\Extension\ExtensionInterface; use Ciconia\Markdown; use Ciconia\Renderer\HtmlRenderer; @@ -83,38 +84,19 @@ public function processTable(Text $text, array $options = array()) $this->escapePipes($rule); $this->escapePipes($body); - $baseTags = $this->createBaseTags($rule->split('/\|/')); + try { + $baseTags = $this->createBaseTags($rule->split('/\|/')); + $headerCells = $this->parseHeader($header, $baseTags); + $bodyRows = $this->parseBody($body, $baseTags); + } catch (SyntaxError $e) { + if ($options['strict']) { + throw $e; + } - $headerCells = new Collection(); - $bodyRows = new Collection(); - - $header->split('/\|/')->each(function (Text $cell, $index) use ($baseTags, &$headerCells) { - /* @var Tag $tag */ - $tag = clone $baseTags->get($index); - $tag->setName('th'); - $this->markdown->emit('inline', array($cell)); - $tag->setText($cell->trim()); - - $headerCells->add($tag); - }); - - $body->split('/\n/')->each(function (Text $row) use ($baseTags, &$bodyRows) { - $row->trim()->trim('|'); - $cells = new Collection(); - $row->split('/\|/')->each(function (Text $cell, $index) use (&$baseTags, &$cells) { - /* @var Tag $tag */ - $tag = clone $baseTags->get($index); - $this->markdown->emit('inline', array($cell)); - $tag->setText($cell->trim()); - - $cells->add($tag); - }); - - $bodyRows->add($cells); - }); + return $w; + } $html = $this->createView($headerCells, $bodyRows); - $this->unescapePipes($html); return $html . "\n\n"; @@ -178,6 +160,74 @@ protected function createBaseTags(Collection $rules) return $baseTags; } + /** + * @param Text $header + * @param Collection $baseTags + * + * @throws \Ciconia\Exception\SyntaxError + * + * @return Collection + */ + protected function parseHeader(Text $header, Collection $baseTags) + { + $cells = new Collection(); + + $header->split('/\|/')->each(function (Text $cell, $index) use ($baseTags, &$cells) { + /* @var Tag $tag */ + $tag = clone $baseTags->get($index); + $tag->setName('th'); + $this->markdown->emit('inline', array($cell)); + $tag->setText($cell->trim()); + + $cells->add($tag); + }); + + if ($baseTags->count() != $cells->count()) { + throw new SyntaxError( + 'Unexpected number of table cells in header.', + $this, $header, $this->markdown + ); + } + + return $cells; + } + + /** + * @param Text $body + * @param Collection $baseTags + * + * @return Collection + */ + protected function parseBody(Text $body, Collection $baseTags) + { + $rows = new Collection(); + + $body->split('/\n/')->each(function (Text $row) use ($baseTags, &$rows) { + $row->trim()->trim('|'); + + $cells = new Collection(); + $row->split('/\|/')->each(function (Text $cell, $index) use (&$baseTags, &$cells) { + /* @var Tag $tag */ + $tag = clone $baseTags->get($index); + $this->markdown->emit('inline', array($cell)); + $tag->setText($cell->trim()); + + $cells->add($tag); + }); + + if ($baseTags->count() != $cells->count()) { + throw new SyntaxError( + 'Unexpected number of table cells in body.', + $this, $row, $this->markdown + ); + } + + $rows->add($cells); + }); + + return $rows; + } + /** * @param Text $text */ diff --git a/test/Ciconia/CiconiaTest.php b/test/Ciconia/CiconiaTest.php index 1d170fc..99028c1 100644 --- a/test/Ciconia/CiconiaTest.php +++ b/test/Ciconia/CiconiaTest.php @@ -214,6 +214,7 @@ public function strictModeProvider() public function testStrictModeDisabled($name, $markdown, $expected) { $md = new \Ciconia\Ciconia(); + $md->addExtension(new \Ciconia\Extension\Gfm\TableExtension()); $expected = str_replace("\r\n", "\n", $expected); $expected = str_replace("\r", "\n", $expected); @@ -228,6 +229,7 @@ public function testStrictModeDisabled($name, $markdown, $expected) public function testReferenceLinkHasInvalidIdOnStrictMode($name, $markdown, $expected) { $md = new \Ciconia\Ciconia(); + $md->addExtension(new \Ciconia\Extension\Gfm\TableExtension()); $md->render($markdown, array('strict' => true)); } diff --git a/test/Ciconia/Resources/core/strict/table-invalid-body.md b/test/Ciconia/Resources/core/strict/table-invalid-body.md new file mode 100644 index 0000000..b9b6779 --- /dev/null +++ b/test/Ciconia/Resources/core/strict/table-invalid-body.md @@ -0,0 +1,3 @@ +th | th | th +---|----|---- +td | td \ No newline at end of file diff --git a/test/Ciconia/Resources/core/strict/table-invalid-body.out b/test/Ciconia/Resources/core/strict/table-invalid-body.out new file mode 100644 index 0000000..e414849 --- /dev/null +++ b/test/Ciconia/Resources/core/strict/table-invalid-body.out @@ -0,0 +1,3 @@ +

th | th | th +---|----|---- +td | td

\ No newline at end of file diff --git a/test/Ciconia/Resources/core/strict/table-invalid-header.md b/test/Ciconia/Resources/core/strict/table-invalid-header.md new file mode 100644 index 0000000..0245cf9 --- /dev/null +++ b/test/Ciconia/Resources/core/strict/table-invalid-header.md @@ -0,0 +1,3 @@ +th | th +---|----|---- +td | td | td \ No newline at end of file diff --git a/test/Ciconia/Resources/core/strict/table-invalid-header.out b/test/Ciconia/Resources/core/strict/table-invalid-header.out new file mode 100644 index 0000000..53037ef --- /dev/null +++ b/test/Ciconia/Resources/core/strict/table-invalid-header.out @@ -0,0 +1,3 @@ +

th | th +---|----|---- +td | td | td

\ No newline at end of file