From cbc76e5c312fa936bba3a4c6018ed351372e6689 Mon Sep 17 00:00:00 2001 From: Emanuil <4thmail@gmail.com> Date: Wed, 10 Jul 2013 23:22:16 +0300 Subject: [PATCH] first commit --- .gitignore | 2 + LICENSE.txt | 21 + Parsedown.php | 626 ++++++++++++++++++++++++++ README.md | 6 + composer.json | 18 + tests/.htaccess | 7 + tests/index.css | 51 +++ tests/index.php | 12 + tests/index_controller.php | 46 ++ tests/index_view.php | 54 +++ tests/reset.css | 108 +++++ tests/test.css | 58 +++ tests/test_controller.php | 27 ++ tests/test_view.php | 62 +++ tests/tests/atx_heading.html | 2 + tests/tests/atx_heading.md | 3 + tests/tests/automatic_link.html | 1 + tests/tests/automatic_link.md | 1 + tests/tests/blockquote.html | 25 + tests/tests/blockquote.md | 24 + tests/tests/code_block.html | 9 + tests/tests/code_block.md | 13 + tests/tests/code_span.html | 1 + tests/tests/code_span.md | 1 + tests/tests/compound_list.html | 13 + tests/tests/compound_list.md | 10 + tests/tests/cyrillic.html | 0 tests/tests/cyrillic.md | 0 tests/tests/email.html | 0 tests/tests/email.md | 0 tests/tests/emphasis.html | 5 + tests/tests/emphasis.md | 9 + tests/tests/escaping.html | 6 + tests/tests/escaping.md | 11 + tests/tests/inline_link.html | 0 tests/tests/inline_link.md | 0 tests/tests/ordered_list.html | 16 + tests/tests/ordered_list.md | 16 + tests/tests/paragraph_blockquote.html | 0 tests/tests/paragraph_blockquote.md | 0 tests/tests/paragraph_list.html | 5 + tests/tests/paragraph_list.md | 4 + tests/tests/quote_block.html | 20 + tests/tests/quote_block.md | 19 + tests/tests/reference_link.html | 8 + tests/tests/reference_link.md | 29 ++ tests/tests/regular_list.html | 17 + tests/tests/regular_list.md | 20 + tests/tests/setext_heading.html | 6 + tests/tests/setext_heading.md | 16 + tests/tests/sparse_list.html | 14 + tests/tests/sparse_list.md | 11 + tests/tests/unordered_list.html | 20 + tests/tests/unordered_list.md | 21 + 54 files changed, 1474 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE.txt create mode 100755 Parsedown.php create mode 100644 README.md create mode 100644 composer.json create mode 100644 tests/.htaccess create mode 100644 tests/index.css create mode 100644 tests/index.php create mode 100644 tests/index_controller.php create mode 100644 tests/index_view.php create mode 100644 tests/reset.css create mode 100644 tests/test.css create mode 100644 tests/test_controller.php create mode 100644 tests/test_view.php create mode 100644 tests/tests/atx_heading.html create mode 100644 tests/tests/atx_heading.md create mode 100644 tests/tests/automatic_link.html create mode 100644 tests/tests/automatic_link.md create mode 100644 tests/tests/blockquote.html create mode 100644 tests/tests/blockquote.md create mode 100644 tests/tests/code_block.html create mode 100644 tests/tests/code_block.md create mode 100644 tests/tests/code_span.html create mode 100644 tests/tests/code_span.md create mode 100644 tests/tests/compound_list.html create mode 100644 tests/tests/compound_list.md create mode 100644 tests/tests/cyrillic.html create mode 100644 tests/tests/cyrillic.md create mode 100644 tests/tests/email.html create mode 100644 tests/tests/email.md create mode 100644 tests/tests/emphasis.html create mode 100644 tests/tests/emphasis.md create mode 100644 tests/tests/escaping.html create mode 100644 tests/tests/escaping.md create mode 100644 tests/tests/inline_link.html create mode 100644 tests/tests/inline_link.md create mode 100644 tests/tests/ordered_list.html create mode 100644 tests/tests/ordered_list.md create mode 100644 tests/tests/paragraph_blockquote.html create mode 100644 tests/tests/paragraph_blockquote.md create mode 100644 tests/tests/paragraph_list.html create mode 100644 tests/tests/paragraph_list.md create mode 100644 tests/tests/quote_block.html create mode 100644 tests/tests/quote_block.md create mode 100644 tests/tests/reference_link.html create mode 100644 tests/tests/reference_link.md create mode 100644 tests/tests/regular_list.html create mode 100644 tests/tests/regular_list.md create mode 100644 tests/tests/setext_heading.html create mode 100644 tests/tests/setext_heading.md create mode 100644 tests/tests/sparse_list.html create mode 100644 tests/tests/sparse_list.md create mode 100644 tests/tests/unordered_list.html create mode 100644 tests/tests/unordered_list.md diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..77d3395 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.DS_Store +nbproject \ No newline at end of file diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..1d1a329 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,21 @@ +Copyright 2013 Emanuil Rusev +http://erusev.com + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/Parsedown.php b/Parsedown.php new file mode 100755 index 0000000..733a58a --- /dev/null +++ b/Parsedown.php @@ -0,0 +1,626 @@ +', '\#', '\+', '\-', '\.', '\!'); + + foreach ($escape_sequences as $index => $escape_sequence) + { + if (strpos($text, $escape_sequence) !== FALSE) + { + $code = "\x1A".'\\'.$index; + + $text = str_replace($escape_sequence, $code, $text); + + $this->escape_sequence_map[$code] = $escape_sequence; + } + } + } + + # Extracts link references. + + if (preg_match_all('/^[ ]{0,3}\[(.+)\][ ]?:[ ]*\n?[ ]*(.+)$/m', $text, $matches, PREG_SET_ORDER)) + { + foreach ($matches as $matches) + { + $this->reference_map[$matches[1]] = $matches[2]; + + $text = str_replace($matches[0], '', $text); + } + } + + # ~ + + $text = $this->parse_blocks($text); + + # Decodes escape sequences (leaves out backslashes). + + foreach ($this->escape_sequence_map as $code => $escape_sequence) + { + $text = str_replace($code, $escape_sequence[1], $text); + } + + $text = rtrim($text, "\n"); + + return $text; + } + + # + # Private Methods + # + + private function parse_blocks($text) + { + # Divides text into blocks. + $blocks = preg_split('/\n\s*\n/', $text, -1, PREG_SPLIT_NO_EMPTY); + + # Makes sure compound blocks get rendered. + $blocks []= NULL; + + $markup = ''; + + # Parses blocks. + + foreach ($blocks as $block) + { + if (isset($block) and $block[0] > 'A') + { + $quick_block = $block; + + unset($block); + } + + # List + + if (isset($block) and preg_match('/^([ ]{0,3})(\d+[.]|[*+-])[ ]/', $block, $matches)) # list item + { + if (isset($list)) # subsequent + { + $list .= "\n\n".$block; + } + else # first + { + $list = $block; + $list_indentation = strlen($matches[1]); + + list($list_type, $list_marker_pattern) = ($matches[2] === '-' or $matches[2] === '+' or $matches[2] === '*') + ? array('ul', '[*+-]') + : array('ol', '\d+[.]'); + } + + unset($block); + } + elseif (isset($list) and $block[0] === ' ') # list item block + { + $list .= "\n\n".$block; + + unset($block); + } + elseif (isset($list)) + { + $markup .= '<'.$list_type.'>'."\n"; + + # Of the same type and indentation. + $list_items = preg_split('/^([ ]{'.$list_indentation.'})'.$list_marker_pattern.'[ ]/m', $list, -1, PREG_SPLIT_NO_EMPTY); + + foreach ($list_items as $list_item) + { + $markup .= '
  • '; + + if (strpos($list_item, "\n\n")) # sparse + { + $list_item = trim($list_item, "\n"); + + if (strpos($list_item, "\n\n")) + { + $list_item = preg_replace('/^[ ]{0,4}/m', '', $list_item); + $list_item = $this->parse_blocks($list_item); + } + else + { + $list_item = $this->parse_lines($list_item); + } + + $markup .= "\n".$list_item; + } + else # dense + { + $list_item = trim($list_item, "\n"); + + $list_item = strpos($list_item, "\n") + ? $this->parse_lines($list_item) + : $this->parse_inline_elements($list_item); + + $markup .= $list_item; + } + + $markup .= '
  • '."\n"; + } + + $markup .= ''."\n"; + + unset($list); + } + + # Code Block + + if (isset($block) and strlen($block) > 4 and $block[0] === ' ' and $block[1] === ' ' and $block[2] === ' ' and $block[3] === ' ') + { + if (isset($code_block)) + { + $code_block .= "\n\n".$block; + } + else + { + $code_block = $block; + } + + unset($block); + } + elseif (isset($code_block)) + { + $code_block_text = preg_replace('/^[ ]{4}/m', '', $code_block); + $code_block_text = htmlentities($code_block_text, ENT_NOQUOTES); + + # Decodes encoded escape sequences if present. + strpos($code_block_text, "\x1A\\") !== FALSE and $code_block_text = strtr($code_block_text, $this->escape_sequence_map); + + $markup .= '
    '.$code_block_text.'
    '."\n"; + + unset($code_block); + } + + # Atx Heading + + if (isset($block) and $block[0] === '#' and preg_match('/^(#{1,6})[ ]*(.+?)[ ]*#*$/', $block, $matches)) + { + $level = strlen($matches[1]); + + $heading = $this->parse_inline_elements($matches[2]); + + $markup .= ''.$heading.''."\n"; + + continue; + } + + # Quote Block + + if (isset($block) and preg_match('/^[ ]{0,3}>/', $block)) + { + $block = preg_replace('/^[ ]{0,3}>[ ]?/m', '', $block); + $block = $this->parse_blocks($block); + + $markup .= '
    '."\n".$block.'
    '."\n"; + + continue; + } + + # Horizontal Line + + if (isset($block) and preg_match('/^[ ]{0,3}([-*_])([ ]{0,2}\1){2,}$/', $block)) + { + $markup .= '
    '."\n"; + + continue; + } + + # ~ + + if (isset($quick_block)) + { + $block = $quick_block; + + unset ($quick_block); + } + + # + # Paragraph + + if (isset($block)) + { + if (strpos($block, "\n")) + { + $markup .= $this->parse_lines($block); + } + else + { + $element_text = $this->parse_inline_elements($block); + $element = '

    '.$element_text.'

    '."\n"; + + $markup .= $element; + } + } + } + + return $markup; + } + + private function parse_lines($text) + { + $text = trim($text, "\n"); + + $lines = explode("\n", $text); + + $lines []= NULL; + + $markup = ''; + + foreach ($lines as $line) + { + if (isset($line) and $line === '') + { + unset($line); + } + + # Paragraph + + if (isset($line) and $line[0] > 'A') + { + $quick_line = $line; + + unset($line); + } + + # List + + if (isset($line) and preg_match('/^([ ]*)(\d+[.]|[*+-])[ ](.*)/', $line, $matches)) # list item + { + $list_item_indentation = strlen($matches[1]); + $list_item_type = ($matches[2] === '-' or $matches[2] === '+' or $matches[2] === '*') + ? 'ul' + : 'ol'; + + if (isset($list)) # subsequent + { + if ($list_item_indentation === $list_indentation and $list_item_type === $list_type) + { + # Adds last list item to the list. + $list []= $list_item; + + # Creates a separate list item. + $list_item = $matches[3]; + } + else + { + # Adds line to the current list item. + $list_item .= "\n".$line; + } + } + else # first + { + $list = array(); + $list_indentation = $list_item_indentation; + $list_type = $list_item_type; + + $list_item = $matches[3]; + } + + unset($line); + } + else + { + if (isset($list)) + { + $list []= $list_item; + + $markup .= '<'.$list_type.'>'."\n"; + + foreach ($list as $list_item) + { + $list_item_text = strpos($list_item, "\n") + ? $this->parse_lines($list_item) + : $this->parse_inline_elements($list_item); + + $markup .= '
  • '.$list_item_text.'
  • '."\n"; + } + + $markup .= ''."\n"; + + unset($list); + } + } + + # Quote Block + + if (isset($line) and preg_match('/^[ ]*>[ ]?(.*)/', $line, $matches)) + { + if (isset($quote)) + { + $quote .= "\n".$matches[1]; + } + else + { + $quote = $matches[1]; + } + + unset($line); + } + else + { + if (isset($quote)) + { + $quote = $this->parse_blocks($quote); + + $markup .= '
    '."\n".$quote.'
    '."\n"; + + unset($quote); + } + } + + # Atx Heading + + if (isset($atx_heading)) + { + $markup .= ''.$atx_heading.''."\n"; + + unset($atx_heading); + } + + if (isset($line) and $line[0] === '#' and preg_match('/^(#{1,6})[ ]*(.+?)[ ]*#*$/', $line, $matches)) + { + $atx_heading_level = strlen($matches[1]); + + $atx_heading = $this->parse_inline_elements($matches[2]); + + unset($line); + } + + # Setext Heading + + if (isset($line) and isset($paragraph)) + { + $setext_characters = array('=', '-'); + + foreach ($setext_characters as $index => $setext_character) + { + if ($line[0] === $setext_character and preg_match('/^['.$setext_character.']+[ ]*$/', $line)) + { + $atx_heading_level = $index + 1; + + $markup .= ''.$paragraph.''."\n"; + + unset($paragraph); + unset($line); + + continue 2; + } + } + } + + # Paragraph + + if (isset($quick_line)) + { + $line = $quick_line; + + unset($quick_line); + } + + if (isset($line)) + { + substr($line, -2) === ' ' + and $line = substr($line, 0, -2) + and $line .= '
    '; + + if (isset($paragraph)) + { + $paragraph .= "\n".$line; + } + else + { + $paragraph = $line; + } + } + else + { + if (isset($paragraph)) + { + $element_text = $this->parse_inline_elements($paragraph); + + $markup .= '

    '.$element_text.'

    '."\n"; + + unset($paragraph); + } + } + } + + return $markup; + } + + private function parse_inline_elements($text) + { + $map = array(); + + $index = 0; + + # Code Span + + if (strpos($text, '`') !== FALSE and preg_match_all('/`(.+?)`/', $text, $matches, PREG_SET_ORDER)) + { + foreach ($matches as $matches) + { + $element_text = $matches[1]; + $element_text = htmlentities($element_text, ENT_NOQUOTES); + + # Decodes escape sequences. + + $this->escape_sequence_map + and strpos($element_text, "\x1A") !== FALSE + and $element_text = strtr($element_text, $this->escape_sequence_map); + + # Composes element. + + $element = ''.$element_text.''; + + # Encodes element. + + $code = "\x1A".'$'.$index; + + $text = str_replace($matches[0], $code, $text); + + $map[$code] = $element; + + $index ++; + } + } + + # Reference(d) Link / Image + + if ($this->reference_map and strpos($text, '[') !== FALSE and preg_match_all('/(!?)\[(.+?)\][ ]?\[(.+?)\]/', $text, $matches, PREG_SET_ORDER)) + { + foreach ($matches as $matches) + { + if (array_key_exists($matches[3], $this->reference_map)) + { + $url = $this->reference_map[$matches[3]]; + + if ($matches[1]) # image + { + $element = ''.$matches[2].''; + } + else # anchor + { + $element_text = $this->parse_inline_elements($matches[2]); + + $element = ''.$element_text.''; + } + + # ~ + + $code = "\x1A".'$'.$index; + + $text = str_replace($matches[0], $code, $text); + + $map[$code] = $element; + + $index ++; + } + } + } + + # Inline Link / Image + + if (strpos($text, ']') !== FALSE and preg_match_all('/(!?)\[(.*?)\][ ]?\((.*?)\)/', $text, $matches, PREG_SET_ORDER)) # inline + { + foreach ($matches as $matches) + { + if ($matches[1]) # image + { + $element = ''.$matches[2].''; + } + else + { + $element_text = $this->parse_inline_elements($matches[2]); + + $element = ''.$element_text.''; + } + + $element_text = $this->parse_inline_elements($matches[1]); + + # ~ + + $code = "\x1A".'$'.$index; + + $text = str_replace($matches[0], $code, $text); + + $map[$code] = $element; + + $index ++; + } + } + + if (strpos($text, '<') !== FALSE and preg_match_all('/<((https?|ftp|dict):[^\^\s]+?)>/i', $text, $matches, PREG_SET_ORDER)) + { + foreach ($matches as $matches) + { + $element = ':text'; + $element = str_replace(':text', $matches[1], $element); + $element = str_replace(':href', $matches[1], $element); + + # ~ + + $code = "\x1A".'$'.$index; + + $text = str_replace($matches[0], $code, $text); + + $map[$code] = $element; + + $index ++; + } + } + + if (strpos($text, '*') !== FALSE) + { + $text = preg_replace('/\*{2}(.*?)\*{2}/', '$1', $text); + $text = preg_replace('/\*(.*?)\*/', '$1', $text); + } + + if (strpos($text, '_') !== FALSE) + { + $text = preg_replace('/_{2}(\S.*?\S)_{2}/', '$1', $text); + $text = preg_replace('/_(\S.*?\S)_/', '$1', $text); + } + + $text = strtr($text, $map); + + return $text; + } +} + diff --git a/README.md b/README.md new file mode 100644 index 0000000..893cf00 --- /dev/null +++ b/README.md @@ -0,0 +1,6 @@ +# Parsedown PHP + +Parsedown is a parser for Markdown. It parses Markdown text the way people do. First, it divides texts into blocks. Then it looks at how these blocks start and how they relate to each other. Finally, it looks for special characters to identify inline elements. As a result, Parsedown is (super) fast, predictable and its (open) source code - easy to read. + +[Explorer (demo)](http://parsedown.org/explorer/) +[Tests](http://parsedown.org/tests/) \ No newline at end of file diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..2179190 --- /dev/null +++ b/composer.json @@ -0,0 +1,18 @@ +{ + "name": "erusev/parsedown", + "description": "Parser for Markdown.", + "keywords": ["markdown", "parser"], + "homepage": "http://parsedown.org", + "type": "library", + "license": "MIT", + "authors": [ + { + "name": "Emanuil Rusev", + "email": "hello@erusev.com", + "homepage": "http://erusev.com" + } + ], + "autoload": { + "psr-0": {"Parsedown": ""} + }, +} \ No newline at end of file diff --git a/tests/.htaccess b/tests/.htaccess new file mode 100644 index 0000000..0b95e0f --- /dev/null +++ b/tests/.htaccess @@ -0,0 +1,7 @@ +RewriteEngine on +RewriteBase / + +RewriteCond %{REQUEST_FILENAME} !-f +RewriteCond %{REQUEST_FILENAME} !-d + +RewriteRule ^(.*)$ tests/index.php?$1 [L] \ No newline at end of file diff --git a/tests/index.css b/tests/index.css new file mode 100644 index 0000000..849c5f9 --- /dev/null +++ b/tests/index.css @@ -0,0 +1,51 @@ + + +.page { + margin: 0 auto; + width: 640px; +} + +.header { + background: #555; + color: #fff; +} + +.odd { + background: #fff; +} + +.even { + background: #eee; +} + +div.fail { + background: #f55; +} + +div.pass { + background: #595; +} + +span.fail { + color: #d55; +} + +span.pass { + color: #595; +} + +/* ~ */ + +p { + margin: 10px 0; +} + +th { + font-weight: normal; + text-align: left; +} + +th, td { + border-bottom: 1px solid #ddd; + padding: 5px 10px; +} \ No newline at end of file diff --git a/tests/index.php b/tests/index.php new file mode 100644 index 0000000..dc02dba --- /dev/null +++ b/tests/index.php @@ -0,0 +1,12 @@ +isFile() and $Item->getBasename() != '.DS_Store') + { + if ($Item->getExtension() === 'md') + { + $basename = $Item->getBasename('.md'); + + $markdown = file_get_contents($dir.$basename.'.md'); + $expected_markup = file_get_contents($dir.$basename.'.html'); + + if ( ! $markdown) + continue; + + $Parsedown = Parsedown::instance(); + + $start = microtime(true); + + $actual_markup = $Parsedown->parse($markdown); + + $time = microtime(true) - $start; + $time = $time * 1000; # ms? + $time = round($time, 2); + + $result = $expected_markup === $actual_markup + ? 'pass' + : 'fail'; + + $result === 'fail' and $failed_test_count ++; + + $Tests []= array( + 'basename' => $basename, + 'name' => str_replace('_', ' ', $basename), + 'result' => $result, + 'time' => $time, + ); + } + } +} + diff --git a/tests/index_view.php b/tests/index_view.php new file mode 100644 index 0000000..ba97f2b --- /dev/null +++ b/tests/index_view.php @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + Parsedown Test + + + + + +
    + +

    Parsedown PHP » Tests

    + +
    + + + + + + + + + $Test): ?> + + + + + + +
    TestTime
    - ms
    + +
    + + tests failed. + + All tests passed. + +
    + +
    + + + + \ No newline at end of file diff --git a/tests/reset.css b/tests/reset.css new file mode 100644 index 0000000..fc2625a --- /dev/null +++ b/tests/reset.css @@ -0,0 +1,108 @@ +/* + * + * + * + */ + +a { + color: #159; + outline: none; + text-decoration: none; +} + +a img { + border: none; +} + +abbr { + border-bottom: 1px solid #ddd; + cursor: help; + padding: 2px 3px; +} + +body { + background: #ddd; + color: #333; + font-family: Verdana, Sans-serif; + font-size: 14px; + height: 100%; + line-height: 20px; + margin: 0; + padding: 0; +} + +blockquote { + background: #eee; + margin: 0 0 10px 0; + padding: 10px 10px 1px 10px; +} + +form { + margin: 0; + padding: 0; +} + +h1, h2, h3, h4, h5, h6 { + font-family: Georgia, "Times New Roman", Times, serif; + font-weight: normal; + letter-spacing: 1px; + margin: 20px 0; +} + +h1 { + line-height: 30px; +} + +html { + height: 100%; + margin: 0; + padding: 0; + overflow-y: scroll; +} + +img { + outline: none; +} + +input { + font-family: Verdana, Sans-serif; + font-size: 14px; + line-height: 20px; + margin: 0; +} + +object { + outline: none; +} + +p { + margin-top: 0; + margin-bottom: 10px; +} + +select { + font-family: Verdana, Sans-serif; + font-size: 14px; + /* Makes for the same height as . */ + height: 40px; + margin: 0; +} + +table { + border-spacing: 0; +} + +textarea { + background: #fff; + font-family: Verdana, Sans-serif; + font-size: 14px; + line-height: 20px; + margin: 0; + padding: 9px; + width: 280px; +} + +ul { + list-style-type: square; +} + diff --git a/tests/test.css b/tests/test.css new file mode 100644 index 0000000..ac6aa02 --- /dev/null +++ b/tests/test.css @@ -0,0 +1,58 @@ +/* + * + * ... + * + */ + +tr.header td { + background: #333; + color: #fff; + padding: 20px; +} + +tr.header a { + color: #fff; + text-decoration: underline; +} + +tr.body td { + background: #fff; + padding: 20px; + width: 35%; +} + +tr.footer td { + background: #fff; + border-top: 1px solid #999; + padding: 10px 20px; +} + +/* ~ */ + +tr.fail td { + background: #f55; +} + +tr.pass td { + background: #5d5; +} + +/* ~ */ + +code { + font-family: Source Code Pro, Monaco, monospace; +} + +pre { + margin: 0; + white-space: -moz-pre-wrap; /* Mozilla, supported since 1999 */ + white-space: -pre-wrap; /* Opera */ + white-space: -o-pre-wrap; /* Opera */ + white-space: pre-wrap; /* CSS3 - Text module (Candidate Recommendation) http://www.w3.org/TR/css3-text/#white-space */ + word-wrap: break-word; /* IE 5.5+ */ +} + +span.tag { + color: #b19; +} + diff --git a/tests/test_controller.php b/tests/test_controller.php new file mode 100644 index 0000000..cdd7521 --- /dev/null +++ b/tests/test_controller.php @@ -0,0 +1,27 @@ +parse($md); + +$result = $expected_mu === $actual_mu + ? 'pass' + : 'fail'; + +$md = htmlentities($md, ENT_NOQUOTES); +$expected_mu = htmlentities($expected_mu, ENT_NOQUOTES); +$actual_mu = htmlentities($actual_mu, ENT_NOQUOTES); + +$name = str_replace('_', ' ', $test); +$name = ucwords($name); \ No newline at end of file diff --git a/tests/test_view.php b/tests/test_view.php new file mode 100644 index 0000000..068c843 --- /dev/null +++ b/tests/test_view.php @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + <?= $name ?> « Parsedown Test + + + + + + + + + + + + + + + + + + + + + + + +
    Parsedown PHP » Tests » +
    + + Open in Explorer +
    +
    +
    +
    + + + + + + \ No newline at end of file diff --git a/tests/tests/atx_heading.html b/tests/tests/atx_heading.html new file mode 100644 index 0000000..7d8118e --- /dev/null +++ b/tests/tests/atx_heading.html @@ -0,0 +1,2 @@ +

    This is an h1

    +

    This is an h2

    \ No newline at end of file diff --git a/tests/tests/atx_heading.md b/tests/tests/atx_heading.md new file mode 100644 index 0000000..cede358 --- /dev/null +++ b/tests/tests/atx_heading.md @@ -0,0 +1,3 @@ +# This is an h1 + +## This is an h2 \ No newline at end of file diff --git a/tests/tests/automatic_link.html b/tests/tests/automatic_link.html new file mode 100644 index 0000000..50a94ba --- /dev/null +++ b/tests/tests/automatic_link.html @@ -0,0 +1 @@ +

    http://example.com

    \ No newline at end of file diff --git a/tests/tests/automatic_link.md b/tests/tests/automatic_link.md new file mode 100644 index 0000000..08d3bf4 --- /dev/null +++ b/tests/tests/automatic_link.md @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/tests/tests/blockquote.html b/tests/tests/blockquote.html new file mode 100644 index 0000000..1cd4095 --- /dev/null +++ b/tests/tests/blockquote.html @@ -0,0 +1,25 @@ +

    Here's a regular blockquote:

    +
    +

    This is a blockquote.

    +
    +

    Here's one with no space after the ">":

    +
    +

    This is a blockquote.

    +
    +

    Here's one with multiple paragraphs:

    +
    +

    This is line one.

    +

    This is line two.

    +
    +

    Here's one with multiple types of blocks:

    +
    +

    This is a quoted paragraph.

    + +
    +

    This is a nested quote block.

    +
    +

    This is another paragraph.

    +
    \ No newline at end of file diff --git a/tests/tests/blockquote.md b/tests/tests/blockquote.md new file mode 100644 index 0000000..63e4099 --- /dev/null +++ b/tests/tests/blockquote.md @@ -0,0 +1,24 @@ +Here's a regular blockquote: + +> This is a blockquote. + +Here's one with no space after the ">": + +>This is a blockquote. + +Here's one with multiple paragraphs: + +> This is line one. +> +> This is line two. + +Here's one with multiple types of blocks: + +> This is a quoted paragraph. +> +> - This is a list item of a quoted list. +> - This is another list item. +> +> > This is a nested quote block. +> +> This is another paragraph. \ No newline at end of file diff --git a/tests/tests/code_block.html b/tests/tests/code_block.html new file mode 100644 index 0000000..37b7660 --- /dev/null +++ b/tests/tests/code_block.html @@ -0,0 +1,9 @@ +

    Here's a regular code block:

    +
    <?php
    +
    +echo 'Hello World!'; 
    +
    +?>
    +

    Here's one that holds a list:

    +
    - list item
    +- another list item
    \ No newline at end of file diff --git a/tests/tests/code_block.md b/tests/tests/code_block.md new file mode 100644 index 0000000..bfa4904 --- /dev/null +++ b/tests/tests/code_block.md @@ -0,0 +1,13 @@ +Here's a regular code block: + + + +Here's one that holds a list: + + - list item + - another list item + diff --git a/tests/tests/code_span.html b/tests/tests/code_span.html new file mode 100644 index 0000000..9c03025 --- /dev/null +++ b/tests/tests/code_span.html @@ -0,0 +1 @@ +

    This is a code span.

    \ No newline at end of file diff --git a/tests/tests/code_span.md b/tests/tests/code_span.md new file mode 100644 index 0000000..03d24b5 --- /dev/null +++ b/tests/tests/code_span.md @@ -0,0 +1 @@ +This is a `code span`. \ No newline at end of file diff --git a/tests/tests/compound_list.html b/tests/tests/compound_list.html new file mode 100644 index 0000000..6416c6b --- /dev/null +++ b/tests/tests/compound_list.html @@ -0,0 +1,13 @@ +

    Here's a compound list:

    + \ No newline at end of file diff --git a/tests/tests/compound_list.md b/tests/tests/compound_list.md new file mode 100644 index 0000000..cf556d3 --- /dev/null +++ b/tests/tests/compound_list.md @@ -0,0 +1,10 @@ +Here's a compound list: + +- This is the first paragraph of the list item. + + This is the second one. + +- This is another list item. + + > This is a quote block that belongs to it. + diff --git a/tests/tests/cyrillic.html b/tests/tests/cyrillic.html new file mode 100644 index 0000000..e69de29 diff --git a/tests/tests/cyrillic.md b/tests/tests/cyrillic.md new file mode 100644 index 0000000..e69de29 diff --git a/tests/tests/email.html b/tests/tests/email.html new file mode 100644 index 0000000..e69de29 diff --git a/tests/tests/email.md b/tests/tests/email.md new file mode 100644 index 0000000..e69de29 diff --git a/tests/tests/emphasis.html b/tests/tests/emphasis.html new file mode 100644 index 0000000..2adbd1a --- /dev/null +++ b/tests/tests/emphasis.html @@ -0,0 +1,5 @@ +

    Here's an emphasis.

    +

    Here's a strong one.

    +

    Here's an emphasis that uses underscores.

    +

    Here's a strong emphasis that uses underscores.

    +

    This is _ not an emphasis _.

    \ No newline at end of file diff --git a/tests/tests/emphasis.md b/tests/tests/emphasis.md new file mode 100644 index 0000000..45b57c0 --- /dev/null +++ b/tests/tests/emphasis.md @@ -0,0 +1,9 @@ +Here's *an emphasis*. + +Here's **a strong one**. + +Here's _an emphasis that uses underscores_. + +Here's __a strong emphasis that uses underscores__. + +This is _ not an emphasis _. \ No newline at end of file diff --git a/tests/tests/escaping.html b/tests/tests/escaping.html new file mode 100644 index 0000000..bcb44b4 --- /dev/null +++ b/tests/tests/escaping.html @@ -0,0 +1,6 @@ +

    Here's an emphasis and here's an escaped *emphasis*. Here are also an escaped `code span`, escaped [inline link](http://example.com).

    +

    Here's an escaped \*emphasis\* inside of a code span.

    +

    Here's one inside of a code block:

    +
    An escaped \*emphasis\*.
    +

    Finally, an escaped reference:

    +

    [1]: http://example.com

    \ No newline at end of file diff --git a/tests/tests/escaping.md b/tests/tests/escaping.md new file mode 100644 index 0000000..8bca463 --- /dev/null +++ b/tests/tests/escaping.md @@ -0,0 +1,11 @@ +Here's an *emphasis* and here's an escaped \*emphasis\*. Here are also an escaped \`code span\`, escaped \[inline link](http://example.com). + +Here's `an escaped \*emphasis\* inside of a code span`. + +Here's one inside of a code block: + + An escaped \*emphasis\*. + +Finally, an escaped reference: + +\[1]: http://example.com \ No newline at end of file diff --git a/tests/tests/inline_link.html b/tests/tests/inline_link.html new file mode 100644 index 0000000..e69de29 diff --git a/tests/tests/inline_link.md b/tests/tests/inline_link.md new file mode 100644 index 0000000..e69de29 diff --git a/tests/tests/ordered_list.html b/tests/tests/ordered_list.html new file mode 100644 index 0000000..81652ac --- /dev/null +++ b/tests/tests/ordered_list.html @@ -0,0 +1,16 @@ +

    Here's a regular ordered list:

    +
      +
    1. one
    2. +
    3. two
    4. +
    5. three
    6. +
    +

    Here's one with repeating numbers:

    +
      +
    1. one
    2. +
    3. two
    4. +
    +

    Here's one with large numbers:

    +
      +
    1. one
    2. +
    3. two
    4. +
    \ No newline at end of file diff --git a/tests/tests/ordered_list.md b/tests/tests/ordered_list.md new file mode 100644 index 0000000..e63af9a --- /dev/null +++ b/tests/tests/ordered_list.md @@ -0,0 +1,16 @@ +Here's a regular ordered list: + +1. one +2. two +3. three + +Here's one with repeating numbers: + +1. one +1. two + +Here's one with large numbers: + +123. one +123. two + diff --git a/tests/tests/paragraph_blockquote.html b/tests/tests/paragraph_blockquote.html new file mode 100644 index 0000000..e69de29 diff --git a/tests/tests/paragraph_blockquote.md b/tests/tests/paragraph_blockquote.md new file mode 100644 index 0000000..e69de29 diff --git a/tests/tests/paragraph_list.html b/tests/tests/paragraph_list.html new file mode 100644 index 0000000..53a09dc --- /dev/null +++ b/tests/tests/paragraph_list.html @@ -0,0 +1,5 @@ +

    Here's a list that's "inside" a paragraph:

    + \ No newline at end of file diff --git a/tests/tests/paragraph_list.md b/tests/tests/paragraph_list.md new file mode 100644 index 0000000..341aec3 --- /dev/null +++ b/tests/tests/paragraph_list.md @@ -0,0 +1,4 @@ +Here's a list that's "inside" a paragraph: +- list item +- another list item + diff --git a/tests/tests/quote_block.html b/tests/tests/quote_block.html new file mode 100644 index 0000000..48d240b --- /dev/null +++ b/tests/tests/quote_block.html @@ -0,0 +1,20 @@ +

    Here's a regular quote block:

    +
    +

    Some quoted text. +Here goes some more.

    +
    +

    Here's one with space before lines:

    +
    +

    Some quoted text. +Here goes some more.

    +
    +

    Here's one with no space after >:

    +
    +

    Some quoted text. +Here goes some more.

    +
    +

    Here's one with no > on the second line:

    +
    +

    Some quoted text. +Here goes some more.

    +
    \ No newline at end of file diff --git a/tests/tests/quote_block.md b/tests/tests/quote_block.md new file mode 100644 index 0000000..f01f6ec --- /dev/null +++ b/tests/tests/quote_block.md @@ -0,0 +1,19 @@ +Here's a regular quote block: + +> Some quoted text. +> Here goes some more. + +Here's one with space before lines: + + > Some quoted text. + > Here goes some more. + +Here's one with no space after >: + +>Some quoted text. +>Here goes some more. + +Here's one with no > on the second line: + +> Some quoted text. +Here goes some more. \ No newline at end of file diff --git a/tests/tests/reference_link.html b/tests/tests/reference_link.html new file mode 100644 index 0000000..84ed9e5 --- /dev/null +++ b/tests/tests/reference_link.html @@ -0,0 +1,8 @@ +

    Here's a reference link.

    +

    Here's one with an alternative syntax.

    +

    Here's one on the next line.

    +

    Here's one on 2 lines.

    +

    Here's one with a different URL.

    +

    Here's one with a semantic name.

    +

    Here's [one][404] with no definition.

    +

    Here's an image: Markdown Logo

    \ No newline at end of file diff --git a/tests/tests/reference_link.md b/tests/tests/reference_link.md new file mode 100644 index 0000000..e6fb2b3 --- /dev/null +++ b/tests/tests/reference_link.md @@ -0,0 +1,29 @@ +Here's a [reference link][1]. + +[1]: http://parsedown.org + +Here's [one] [2] with an alternative syntax. + +[2] :http://parsedown.org + +Here's [one][3] on the next line. +[3]: http://parsedown.org + +Here's [one][4] on 2 lines. + +[4]: +http://parsedown.org + +Here's [one][5] with a different URL. + +[5]: http://parsedown.org/tests/ + +Here's [one][the website] with a semantic name. + +[the website]: http://parsedown.org + +Here's [one][404] with no definition. + +Here's an image: ![Markdown Logo][image] + +[image]: https://raw.github.com/dcurtis/markdown-mark/master/png/32x20-solid.png \ No newline at end of file diff --git a/tests/tests/regular_list.html b/tests/tests/regular_list.html new file mode 100644 index 0000000..949b12e --- /dev/null +++ b/tests/tests/regular_list.html @@ -0,0 +1,17 @@ +

    Here's a regular list:

    + +

    Here's one with white space around items:

    + +

    Here's one with too much space before items:

    +
    - list item
    +- another list item
    +

    Here's one with no space after markers:

    +

    -list item +-another list item

    \ No newline at end of file diff --git a/tests/tests/regular_list.md b/tests/tests/regular_list.md new file mode 100644 index 0000000..bde80ee --- /dev/null +++ b/tests/tests/regular_list.md @@ -0,0 +1,20 @@ +Here's a regular list: + +- list item +- another list item +- 3rd list item + +Here's one with white space around items: + + - list item + - another list item + +Here's one with too much space before items: + + - list item + - another list item + +Here's one with no space after markers: + +-list item +-another list item \ No newline at end of file diff --git a/tests/tests/setext_heading.html b/tests/tests/setext_heading.html new file mode 100644 index 0000000..7692278 --- /dev/null +++ b/tests/tests/setext_heading.html @@ -0,0 +1,6 @@ +

    Heading 1

    +

    Heading 2

    +

    Block Heading

    +

    This is the rest of the block.

    +

    Single "="

    +

    Single "-"

    \ No newline at end of file diff --git a/tests/tests/setext_heading.md b/tests/tests/setext_heading.md new file mode 100644 index 0000000..3ccd511 --- /dev/null +++ b/tests/tests/setext_heading.md @@ -0,0 +1,16 @@ +Heading 1 +========= + +Heading 2 +--------- + +Block Heading +------------- +This is the rest of the block. + +Single "=" += + +Single "-" +- + diff --git a/tests/tests/sparse_list.html b/tests/tests/sparse_list.html new file mode 100644 index 0000000..e83f2dc --- /dev/null +++ b/tests/tests/sparse_list.html @@ -0,0 +1,14 @@ +

    Here's a list where items are separated by empty lines:

    + +

    Here's an ordered one:

    +
      +
    1. +

      item one

      +
    2. +
    3. item two
    4. +
    \ No newline at end of file diff --git a/tests/tests/sparse_list.md b/tests/tests/sparse_list.md new file mode 100644 index 0000000..b7f3ea6 --- /dev/null +++ b/tests/tests/sparse_list.md @@ -0,0 +1,11 @@ +Here's a list where items are separated by empty lines: + +- list item + +- another list item + +Here's an ordered one: + +1. item one + +2. item two \ No newline at end of file diff --git a/tests/tests/unordered_list.html b/tests/tests/unordered_list.html new file mode 100644 index 0000000..286feb0 --- /dev/null +++ b/tests/tests/unordered_list.html @@ -0,0 +1,20 @@ +

    Here's a regular unordered list:

    + +

    Here's one with a variety of markers:

    + +

    Here's one with white space around items:

    + +

    Here's one with no space after markers:

    +

    -list item +-another list item

    \ No newline at end of file diff --git a/tests/tests/unordered_list.md b/tests/tests/unordered_list.md new file mode 100644 index 0000000..0e1717d --- /dev/null +++ b/tests/tests/unordered_list.md @@ -0,0 +1,21 @@ +Here's a regular unordered list: + +- list item +- another list item +- 3rd list item + +Here's one with a variety of markers: + +- hyphen ++ plus +* asterisk + +Here's one with white space around items: + + - list item + - another list item + +Here's one with no space after markers: + +-list item +-another list item \ No newline at end of file