mirror of
https://github.com/erusev/parsedown.git
synced 2023-08-10 21:13:06 +03:00
Compare commits
34 Commits
Author | SHA1 | Date | |
---|---|---|---|
0352f01c7e | |||
40c2dcfac7 | |||
097ec5e8a5 | |||
8ac52a2f30 | |||
4a6bb88239 | |||
609ad47c38 | |||
7d7e89f5c3 | |||
5aad1d42d2 | |||
3ff5c623f2 | |||
637b516694 | |||
31b811d3fe | |||
8954b94516 | |||
4e64695055 | |||
b29c2459e0 | |||
15f20fb59e | |||
69a620110a | |||
e4f9620e98 | |||
8c59d05478 | |||
26c02dafed | |||
5de50f101a | |||
7ace421f6d | |||
78cad3964c | |||
8ed3b3d484 | |||
41bf9733b0 | |||
99bf0d4bba | |||
f29981d0a3 | |||
2f051b821c | |||
85dd9fd965 | |||
69de4c46d5 | |||
5bbbabe8aa | |||
ec5f2c6f31 | |||
66f9baf013 | |||
7b091b8915 | |||
0a0a126827 |
6
.travis.yml
Normal file
6
.travis.yml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
language: php
|
||||||
|
|
||||||
|
php:
|
||||||
|
- 5.5
|
||||||
|
- 5.4
|
||||||
|
- 5.3
|
35
LICENSE.txt
35
LICENSE.txt
@ -1,21 +1,20 @@
|
|||||||
Copyright 2013 Emanuil Rusev
|
The MIT License (MIT)
|
||||||
http://erusev.com
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining
|
Copyright (c) 2013 Emanuil Rusev, erusev.com
|
||||||
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
|
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
included in all copies or substantial portions of the Software.
|
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 SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
The above copyright notice and this permission notice shall be included in all
|
||||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
copies or substantial portions of the Software.
|
||||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
||||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
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.
|
@ -50,7 +50,8 @@ class Parsedown
|
|||||||
$text = preg_replace('{^\xEF\xBB\xBF|\x1A}', '', $text);
|
$text = preg_replace('{^\xEF\xBB\xBF|\x1A}', '', $text);
|
||||||
|
|
||||||
# Removes \r characters.
|
# Removes \r characters.
|
||||||
$text = str_replace("\r", '', $text);
|
$text = str_replace("\r\n", "\n", $text);
|
||||||
|
$text = str_replace("\r", "\n", $text);
|
||||||
|
|
||||||
# Replaces tabs with spaces.
|
# Replaces tabs with spaces.
|
||||||
$text = str_replace("\t", ' ', $text);
|
$text = str_replace("\t", ' ', $text);
|
||||||
@ -80,7 +81,7 @@ class Parsedown
|
|||||||
{
|
{
|
||||||
foreach ($matches as $matches)
|
foreach ($matches as $matches)
|
||||||
{
|
{
|
||||||
$this->reference_map[$matches[1]] = $matches[2];
|
$this->reference_map[strtolower($matches[1])] = $matches[2];
|
||||||
|
|
||||||
$text = str_replace($matches[0], '', $text);
|
$text = str_replace($matches[0], '', $text);
|
||||||
}
|
}
|
||||||
@ -108,8 +109,10 @@ class Parsedown
|
|||||||
|
|
||||||
private function parse_blocks($text)
|
private function parse_blocks($text)
|
||||||
{
|
{
|
||||||
|
$text = trim($text, "\n");
|
||||||
|
|
||||||
# Divides text into blocks.
|
# Divides text into blocks.
|
||||||
$blocks = preg_split('/\n\s*\n/', $text, -1, PREG_SPLIT_NO_EMPTY);
|
$blocks = preg_split('/\n\s*\n/', $text);
|
||||||
|
|
||||||
# Makes sure compound blocks get rendered.
|
# Makes sure compound blocks get rendered.
|
||||||
$blocks []= NULL;
|
$blocks []= NULL;
|
||||||
@ -120,7 +123,7 @@ class Parsedown
|
|||||||
|
|
||||||
foreach ($blocks as $block)
|
foreach ($blocks as $block)
|
||||||
{
|
{
|
||||||
if (isset($block) and $block[0] > 'A')
|
if (isset($block) and $block[0] >= 'A')
|
||||||
{
|
{
|
||||||
$quick_block = $block;
|
$quick_block = $block;
|
||||||
|
|
||||||
@ -147,7 +150,7 @@ class Parsedown
|
|||||||
|
|
||||||
unset($block);
|
unset($block);
|
||||||
}
|
}
|
||||||
elseif (isset($list) and $block[0] === ' ') # list item block
|
elseif (isset($block) and isset($list) and $block[0] === ' ') # list item block
|
||||||
{
|
{
|
||||||
$list .= "\n\n".$block;
|
$list .= "\n\n".$block;
|
||||||
|
|
||||||
@ -157,7 +160,6 @@ class Parsedown
|
|||||||
{
|
{
|
||||||
$markup .= '<'.$list_type.'>'."\n";
|
$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);
|
$list_items = preg_split('/^([ ]{'.$list_indentation.'})'.$list_marker_pattern.'[ ]/m', $list, -1, PREG_SPLIT_NO_EMPTY);
|
||||||
|
|
||||||
foreach ($list_items as $list_item)
|
foreach ($list_items as $list_item)
|
||||||
@ -175,7 +177,7 @@ class Parsedown
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
$list_item = $this->parse_lines($list_item);
|
$list_item = $this->parse_lines($list_item, TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
$markup .= "\n".$list_item;
|
$markup .= "\n".$list_item;
|
||||||
@ -277,7 +279,7 @@ class Parsedown
|
|||||||
{
|
{
|
||||||
if (strpos($block, "\n"))
|
if (strpos($block, "\n"))
|
||||||
{
|
{
|
||||||
$markup .= $this->parse_lines($block);
|
$markup .= $this->parse_lines($block, TRUE);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -292,7 +294,7 @@ class Parsedown
|
|||||||
return $markup;
|
return $markup;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function parse_lines($text)
|
private function parse_lines($text, $paragraph_based = FALSE)
|
||||||
{
|
{
|
||||||
$text = trim($text, "\n");
|
$text = trim($text, "\n");
|
||||||
|
|
||||||
@ -311,7 +313,7 @@ class Parsedown
|
|||||||
|
|
||||||
# Paragraph
|
# Paragraph
|
||||||
|
|
||||||
if (isset($line) and $line[0] > 'A')
|
if (isset($line) and $line[0] >= 'A')
|
||||||
{
|
{
|
||||||
$quick_line = $line;
|
$quick_line = $line;
|
||||||
|
|
||||||
@ -432,12 +434,13 @@ class Parsedown
|
|||||||
{
|
{
|
||||||
if ($line[0] === $setext_character and preg_match('/^['.$setext_character.']+[ ]*$/', $line))
|
if ($line[0] === $setext_character and preg_match('/^['.$setext_character.']+[ ]*$/', $line))
|
||||||
{
|
{
|
||||||
$atx_heading_level = $index + 1;
|
$setext_heading_level = $index + 1;
|
||||||
|
|
||||||
$markup .= '<h'.$atx_heading_level.'>'.$paragraph.'</h'.$atx_heading_level.'>'."\n";
|
$setext_heading_text = $this->parse_inline_elements($paragraph);
|
||||||
|
|
||||||
unset($paragraph);
|
$markup .= '<h'.$setext_heading_level.'>'.$setext_heading_text.'</h'.$setext_heading_level.'>'."\n";
|
||||||
unset($line);
|
|
||||||
|
unset($paragraph, $line);
|
||||||
|
|
||||||
continue 2;
|
continue 2;
|
||||||
}
|
}
|
||||||
@ -472,9 +475,11 @@ class Parsedown
|
|||||||
{
|
{
|
||||||
if (isset($paragraph))
|
if (isset($paragraph))
|
||||||
{
|
{
|
||||||
$element_text = $this->parse_inline_elements($paragraph);
|
$paragraph_text = $this->parse_inline_elements($paragraph);
|
||||||
|
|
||||||
$markup .= '<p>'.$element_text.'</p>'."\n";
|
$markup .= $markup === '' && $paragraph_based === FALSE
|
||||||
|
? $paragraph_text
|
||||||
|
: '<p>'.$paragraph_text.'</p>'."\n";
|
||||||
|
|
||||||
unset($paragraph);
|
unset($paragraph);
|
||||||
}
|
}
|
||||||
@ -523,13 +528,19 @@ class Parsedown
|
|||||||
|
|
||||||
# Reference(d) Link / Image
|
# Reference(d) Link / Image
|
||||||
|
|
||||||
if ($this->reference_map and strpos($text, '[') !== FALSE and preg_match_all('/(!?)\[(.+?)\][ ]?\[(.+?)\]/', $text, $matches, PREG_SET_ORDER))
|
if ($this->reference_map and strpos($text, '[') !== FALSE and preg_match_all('/(!?)\[(.+?)\](?:[ ]?\[(.*?)\])?/ms', $text, $matches, PREG_SET_ORDER))
|
||||||
{
|
{
|
||||||
foreach ($matches as $matches)
|
foreach ($matches as $matches)
|
||||||
{
|
{
|
||||||
if (array_key_exists($matches[3], $this->reference_map))
|
$link_difinition = isset($matches[3]) && $matches[3]
|
||||||
|
? $matches[3]
|
||||||
|
: $matches[2]; # implicit
|
||||||
|
|
||||||
|
$link_difinition = strtolower($link_difinition);
|
||||||
|
|
||||||
|
if (isset($this->reference_map[$link_difinition]))
|
||||||
{
|
{
|
||||||
$url = $this->reference_map[$matches[3]];
|
$url = $this->reference_map[$link_difinition];
|
||||||
|
|
||||||
if ($matches[1]) # image
|
if ($matches[1]) # image
|
||||||
{
|
{
|
||||||
@ -557,19 +568,19 @@ class Parsedown
|
|||||||
|
|
||||||
# Inline Link / Image
|
# Inline Link / Image
|
||||||
|
|
||||||
if (strpos($text, ']') !== FALSE and preg_match_all('/(!?)\[(.*?)\][ ]?\((.*?)\)/', $text, $matches, PREG_SET_ORDER)) # inline
|
if (strpos($text, '](') !== FALSE and preg_match_all('/(!?)(\[((?:[^][]+|(?2))*)\])\((.*?)\)/', $text, $matches, PREG_SET_ORDER)) # inline
|
||||||
{
|
{
|
||||||
foreach ($matches as $matches)
|
foreach ($matches as $matches)
|
||||||
{
|
{
|
||||||
if ($matches[1]) # image
|
if ($matches[1]) # image
|
||||||
{
|
{
|
||||||
$element = '<img alt="'.$matches[2].'" src="'.$matches[3].'">';
|
$element = '<img alt="'.$matches[3].'" src="'.$matches[4].'">';
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
$element_text = $this->parse_inline_elements($matches[2]);
|
$element_text = $this->parse_inline_elements($matches[3]);
|
||||||
|
|
||||||
$element = '<a href="'.$matches[3].'">'.$element_text.'</a>';
|
$element = '<a href="'.$matches[4].'">'.$element_text.'</a>';
|
||||||
}
|
}
|
||||||
|
|
||||||
$element_text = $this->parse_inline_elements($matches[1]);
|
$element_text = $this->parse_inline_elements($matches[1]);
|
||||||
@ -606,16 +617,10 @@ class Parsedown
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strpos($text, '*') !== FALSE)
|
if (strpos($text, '*') !== FALSE or strpos($text, '_') !== FALSE)
|
||||||
{
|
{
|
||||||
$text = preg_replace('/\*{2}(.*?)\*{2}/', '<strong>$1</strong>', $text);
|
$text = preg_replace('/(\*\*|__)(.+?[*_]*)(?<=\S)\1/', '<strong>$2</strong>', $text);
|
||||||
$text = preg_replace('/\*(.*?)\*/', '<em>$1</em>', $text);
|
$text = preg_replace('/(\*|_)(.+?)(?<=\S)\1/', '<em>$2</em>', $text);
|
||||||
}
|
|
||||||
|
|
||||||
if (strpos($text, '_') !== FALSE)
|
|
||||||
{
|
|
||||||
$text = preg_replace('/_{2}(\S.*?\S)_{2}/', '<strong>$1</strong>', $text);
|
|
||||||
$text = preg_replace('/_(\S.*?\S)_/', '<em>$1</em>', $text);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$text = strtr($text, $map);
|
$text = strtr($text, $map);
|
||||||
|
18
README.md
18
README.md
@ -1,4 +1,20 @@
|
|||||||
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.
|
## 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, consistent and clean.
|
||||||
|
|
||||||
[Explorer (demo)](http://parsedown.org/explorer/)
|
[Explorer (demo)](http://parsedown.org/explorer/)
|
||||||
[Tests](http://parsedown.org/tests/)
|
[Tests](http://parsedown.org/tests/)
|
||||||
|
|
||||||
|
### Installation
|
||||||
|
|
||||||
|
Include `Parsedown.php` or install [the composer package](https://packagist.org/packages/erusev/parsedown).
|
||||||
|
|
||||||
|
### Example
|
||||||
|
|
||||||
|
```php
|
||||||
|
$text = 'Hello **Parsedown**!';
|
||||||
|
|
||||||
|
$result = Parsedown::instance()->parse($text);
|
||||||
|
|
||||||
|
echo $result; # prints: <p>Hello <strong>Parsedown</strong>!</p>
|
||||||
|
```
|
8
phpunit.xml.dist
Normal file
8
phpunit.xml.dist
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<phpunit colors="true">
|
||||||
|
<testsuites>
|
||||||
|
<testsuite>
|
||||||
|
<file>tests/Test.php</file>
|
||||||
|
</testsuite>
|
||||||
|
</testsuites>
|
||||||
|
</phpunit>
|
@ -1,7 +0,0 @@
|
|||||||
RewriteEngine on
|
|
||||||
RewriteBase /
|
|
||||||
|
|
||||||
RewriteCond %{REQUEST_FILENAME} !-f
|
|
||||||
RewriteCond %{REQUEST_FILENAME} !-d
|
|
||||||
|
|
||||||
RewriteRule ^(.*)$ tests/index.php?$1 [L]
|
|
47
tests/Test.php
Normal file
47
tests/Test.php
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
include 'Parsedown.php';
|
||||||
|
|
||||||
|
class Test extends PHPUnit_Framework_TestCase
|
||||||
|
{
|
||||||
|
const provider_dir = 'data/';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider provider
|
||||||
|
*/
|
||||||
|
function test_($markdown, $expected_markup)
|
||||||
|
{
|
||||||
|
$actual_markup = Parsedown::instance()->parse($markdown);
|
||||||
|
|
||||||
|
$this->assertEquals($expected_markup, $actual_markup);
|
||||||
|
}
|
||||||
|
|
||||||
|
function provider()
|
||||||
|
{
|
||||||
|
$provider = array();
|
||||||
|
|
||||||
|
$DirectoryIterator = new DirectoryIterator(__DIR__ . '/' . self::provider_dir);
|
||||||
|
|
||||||
|
foreach ($DirectoryIterator as $Item)
|
||||||
|
{
|
||||||
|
if ($Item->isFile() and $Item->getExtension() === 'md')
|
||||||
|
{
|
||||||
|
$basename = $Item->getBasename('.md');
|
||||||
|
|
||||||
|
$markdown = file_get_contents(__DIR__ . '/' . self::provider_dir . $basename . '.md');
|
||||||
|
|
||||||
|
if (!$markdown)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
$expected_markup = file_get_contents(__DIR__ . '/' . self::provider_dir . $basename . '.html');
|
||||||
|
$expected_markup = str_replace("\r\n", "\n", $expected_markup);
|
||||||
|
$expected_markup = str_replace("\r", "\n", $expected_markup);
|
||||||
|
|
||||||
|
$provider [] = array($markdown, $expected_markup);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $provider;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
14
tests/data/atx_heading.html
Normal file
14
tests/data/atx_heading.html
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
<h1>This is an h1</h1>
|
||||||
|
<h2>This is an h2</h2>
|
||||||
|
<h3>This is an h3</h3>
|
||||||
|
<h4>This is an h4</h4>
|
||||||
|
<h5>This is an h5</h5>
|
||||||
|
<h6>This is an h6</h6>
|
||||||
|
<h1>This is a closed h1</h1>
|
||||||
|
<h2>This is a closed h2</h2>
|
||||||
|
<h3>This is a closed h3</h3>
|
||||||
|
<h4>This is a closed h4</h4>
|
||||||
|
<h5>This is a closed h5</h5>
|
||||||
|
<h6>This is a closed h6</h6>
|
||||||
|
<h1>This is an irregularly closed h1</h1>
|
||||||
|
<h4>This is an irregularly closed h4</h4>
|
27
tests/data/atx_heading.md
Normal file
27
tests/data/atx_heading.md
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
# This is an h1
|
||||||
|
|
||||||
|
## This is an h2
|
||||||
|
|
||||||
|
### This is an h3
|
||||||
|
|
||||||
|
#### This is an h4
|
||||||
|
|
||||||
|
##### This is an h5
|
||||||
|
|
||||||
|
###### This is an h6
|
||||||
|
|
||||||
|
# This is a closed h1 #
|
||||||
|
|
||||||
|
## This is a closed h2 ##
|
||||||
|
|
||||||
|
### This is a closed h3 ###
|
||||||
|
|
||||||
|
#### This is a closed h4 ####
|
||||||
|
|
||||||
|
##### This is a closed h5 #####
|
||||||
|
|
||||||
|
###### This is a closed h6 ######
|
||||||
|
|
||||||
|
# This is an irregularly closed h1 ###
|
||||||
|
|
||||||
|
#### This is an irregularly closed h4 ##
|
@ -15,3 +15,10 @@
|
|||||||
<p>Here's one with no space after markers:</p>
|
<p>Here's one with no space after markers:</p>
|
||||||
<p>-list item
|
<p>-list item
|
||||||
-another list item</p>
|
-another list item</p>
|
||||||
|
<p>Here's one where items contain line breaks:</p>
|
||||||
|
<ul>
|
||||||
|
<li>list
|
||||||
|
item</li>
|
||||||
|
<li>another
|
||||||
|
list item</li>
|
||||||
|
</ul>
|
@ -18,3 +18,10 @@ Here's one with no space after markers:
|
|||||||
|
|
||||||
-list item
|
-list item
|
||||||
-another list item
|
-another list item
|
||||||
|
|
||||||
|
Here's one where items contain line breaks:
|
||||||
|
|
||||||
|
- list
|
||||||
|
item
|
||||||
|
- another
|
||||||
|
list item
|
8
tests/data/emphasis.html
Normal file
8
tests/data/emphasis.html
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<p>Here's <em>an emphasis</em>.</p>
|
||||||
|
<p>A short emphasis <em>a</em> <em>b</em> .</p>
|
||||||
|
<p>Here's <strong>a strong one</strong>. </p>
|
||||||
|
<p>Here's <em>an emphasis that uses underscores</em>. </p>
|
||||||
|
<p>Here's <strong>a strong emphasis that uses underscores</strong>.</p>
|
||||||
|
<p>This is _ not an emphasis _ neither is * that * .</p>
|
||||||
|
<p>Empty emphasis ** is not __ an emphasis.</p>
|
||||||
|
<p>Three asterisks are an emphasized asterisk <em>*</em> .</p>
|
15
tests/data/emphasis.md
Normal file
15
tests/data/emphasis.md
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
Here's *an emphasis*.
|
||||||
|
|
||||||
|
A short emphasis _a_ *b* .
|
||||||
|
|
||||||
|
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 _ neither is * that * .
|
||||||
|
|
||||||
|
Empty emphasis ** is not __ an emphasis.
|
||||||
|
|
||||||
|
Three asterisks are an emphasized asterisk *** .
|
2
tests/data/inline_link.html
Normal file
2
tests/data/inline_link.html
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
<p>Here's a <a href="http://parsedown.org">link</a>.</p>
|
||||||
|
<p>Here's an image link: <a href="http://daringfireball.net/projects/markdown/"><img alt="MD Logo" src="http://parsedown.org/md.png"></a>.</p>
|
3
tests/data/inline_link.md
Normal file
3
tests/data/inline_link.md
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
Here's a [link](http://parsedown.org).
|
||||||
|
|
||||||
|
Here's an image link: [](http://daringfireball.net/projects/markdown/).
|
@ -6,3 +6,8 @@
|
|||||||
<p>Here's <a href="http://parsedown.org">one</a> with a semantic name.</p>
|
<p>Here's <a href="http://parsedown.org">one</a> with a semantic name.</p>
|
||||||
<p>Here's [one][404] with no definition.</p>
|
<p>Here's [one][404] with no definition.</p>
|
||||||
<p>Here's an image: <img alt="Markdown Logo" src="https://raw.github.com/dcurtis/markdown-mark/master/png/32x20-solid.png"></p>
|
<p>Here's an image: <img alt="Markdown Logo" src="https://raw.github.com/dcurtis/markdown-mark/master/png/32x20-solid.png"></p>
|
||||||
|
<p>Here's an <a href="http://google.com">implicit one</a>.</p>
|
||||||
|
<p>Here's an <a href="http://google.com">implicit one</a>.</p>
|
||||||
|
<p>Here's an <a href="http://google.com">implicit one</a> with an empty link definition.</p>
|
||||||
|
<p>Here's a <a href="http://parsedown.org">multiline
|
||||||
|
one</a> defined on 2 lines.</p>
|
@ -18,12 +18,23 @@ Here's [one][5] with a different URL.
|
|||||||
|
|
||||||
[5]: http://parsedown.org/tests/
|
[5]: http://parsedown.org/tests/
|
||||||
|
|
||||||
Here's [one][the website] with a semantic name.
|
Here's [one][website] with a semantic name.
|
||||||
|
|
||||||
[the website]: http://parsedown.org
|
[website]: http://parsedown.org
|
||||||
|
|
||||||
Here's [one][404] with no definition.
|
Here's [one][404] with no definition.
|
||||||
|
|
||||||
Here's an image: ![Markdown Logo][image]
|
Here's an image: ![Markdown Logo][image]
|
||||||
|
|
||||||
[image]: https://raw.github.com/dcurtis/markdown-mark/master/png/32x20-solid.png
|
[image]: https://raw.github.com/dcurtis/markdown-mark/master/png/32x20-solid.png
|
||||||
|
|
||||||
|
Here's an [implicit one].
|
||||||
|
|
||||||
|
Here's an [implicit one].
|
||||||
|
|
||||||
|
[implicit one]: http://google.com
|
||||||
|
|
||||||
|
Here's an [implicit one][] with an empty link definition.
|
||||||
|
|
||||||
|
Here's a [multiline
|
||||||
|
one][website] defined on 2 lines.
|
@ -1,51 +0,0 @@
|
|||||||
|
|
||||||
|
|
||||||
.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;
|
|
||||||
}
|
|
@ -1,12 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
include '../Parsedown.php';
|
|
||||||
|
|
||||||
$page = $_SERVER['QUERY_STRING']
|
|
||||||
? 'test'
|
|
||||||
: 'index';
|
|
||||||
|
|
||||||
$dir = 'tests/';
|
|
||||||
|
|
||||||
include $page.'_controller.php';
|
|
||||||
include $page.'_view.php';
|
|
@ -1,46 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
$DirectoryIterator = new DirectoryIterator($dir);
|
|
||||||
|
|
||||||
$failed_test_count = 0;
|
|
||||||
|
|
||||||
foreach ($DirectoryIterator as $Item)
|
|
||||||
{
|
|
||||||
if ($Item->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,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,54 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
|
|
||||||
<!-- (c) 2009 - 2013 Emanuil Rusev, All rights reserved. -->
|
|
||||||
|
|
||||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
|
||||||
|
|
||||||
<head>
|
|
||||||
|
|
||||||
<meta content="text/html; charset=UTF-8" http-equiv="Content-Type" />
|
|
||||||
|
|
||||||
<link href="reset.css" rel="stylesheet" type="text/css" />
|
|
||||||
<link href="index.css" rel="stylesheet" type="text/css" />
|
|
||||||
|
|
||||||
<title>Parsedown Test</title>
|
|
||||||
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
|
|
||||||
<div style="padding: 50px; width: 500px;">
|
|
||||||
|
|
||||||
<h1 style="margin: 0;"><a href="/">Parsedown PHP</a> » Tests</h1>
|
|
||||||
|
|
||||||
<br/>
|
|
||||||
|
|
||||||
<table>
|
|
||||||
|
|
||||||
<tr class="header">
|
|
||||||
<th style="width: 480px;">Test</th>
|
|
||||||
<th style="text-align: right; width: 120px">Time</th>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<?php foreach ($Tests as $index => $Test): ?>
|
|
||||||
<tr class="<?= $index % 2 ? 'even' : 'odd' ?>">
|
|
||||||
<td><a href="/tests/<?= $Test['basename'] ?>"><?= $Test['name'] ?></a> - <span class="<?= $Test['result'] ?>"><?= $Test['result'] ?></span></td>
|
|
||||||
<td style="text-align: right;"><?= $Test['time'] ?> ms</td>
|
|
||||||
</tr>
|
|
||||||
<?php endforeach ?>
|
|
||||||
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<div class="<?= $failed_test_count ? 'fail' : 'pass' ?>" style="border-top: 1px solid #555; color: #fff; margin-top: 1px; padding:5px 10px;">
|
|
||||||
<?php if ($failed_test_count): ?>
|
|
||||||
<?= $failed_test_count ?> tests failed.
|
|
||||||
<?php else: ?>
|
|
||||||
All <?= count($Tests) ?> tests passed.
|
|
||||||
<?php endif ?>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</body>
|
|
||||||
|
|
||||||
</html>
|
|
108
tests/reset.css
108
tests/reset.css
@ -1,108 +0,0 @@
|
|||||||
/*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
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 <input>. */
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
@ -1,58 +0,0 @@
|
|||||||
/*
|
|
||||||
*
|
|
||||||
* ...
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
@ -1,27 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
$test = $_SERVER['QUERY_STRING'];
|
|
||||||
|
|
||||||
preg_match('/^\w+$/', $test) or die('illegal test name');
|
|
||||||
|
|
||||||
$md_file = $dir.$test.'.md';
|
|
||||||
$mu_file = $dir.$test.'.html';
|
|
||||||
|
|
||||||
file_exists($md_file) or die("$md_file not found");
|
|
||||||
file_exists($mu_file) or die("$mu_file not found");
|
|
||||||
|
|
||||||
$md = file_get_contents($md_file);
|
|
||||||
|
|
||||||
$expected_mu = file_get_contents($mu_file);
|
|
||||||
$actual_mu = Parsedown::instance()->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);
|
|
@ -1,62 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
|
|
||||||
<!-- (c) 2009 - 2013 Emanuil Rusev, All rights reserved. -->
|
|
||||||
|
|
||||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
|
||||||
|
|
||||||
<head>
|
|
||||||
|
|
||||||
<meta content="text/html; charset=UTF-8" http-equiv="Content-Type" />
|
|
||||||
|
|
||||||
<link href="reset.css" rel="stylesheet" type="text/css" />
|
|
||||||
<link href="test.css" rel="stylesheet" type="text/css" />
|
|
||||||
|
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/prettify/r224/prettify.js" type="text/javascript"></script>
|
|
||||||
<script src="http://code.jquery.com/jquery-2.0.0.min.js" type="text/javascript"></script>
|
|
||||||
|
|
||||||
<title><?= $name ?> « Parsedown Test</title>
|
|
||||||
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body onload="prettyPrint();">
|
|
||||||
|
|
||||||
<table style="width: 100%; height: 100%;">
|
|
||||||
<tr class="<?= $result ?>">
|
|
||||||
<td colspan="3"></td>
|
|
||||||
</tr>
|
|
||||||
<tr class="header">
|
|
||||||
<td colspan="2"><a href="/">Parsedown PHP</a> » <a href=".">Tests</a> » <?= $name ?></td>
|
|
||||||
<td style="text-align: right;">
|
|
||||||
<form action="http://parsedown.org<?= $_SERVER['SERVER_NAME'] === 'parsedown.org.local' ? '.local' : '' ?>/explorer/" method="post">
|
|
||||||
<input type="hidden" name="text" />
|
|
||||||
<a id="explorer" href="">Open in Explorer</a>
|
|
||||||
</form>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr class="body" style="height: 100%; vertical-align: top;">
|
|
||||||
<td style="background: #eee; width: 30%;">
|
|
||||||
<pre id="md" style="word-wrap: break-word;"><?= $md ?></pre>
|
|
||||||
</td>
|
|
||||||
<td><pre class="prettyprint"><code><?= $expected_mu ?></code></pre></td>
|
|
||||||
<td><pre class="prettyprint"><code><?= $actual_mu ?></code></pre></td>
|
|
||||||
</tr>
|
|
||||||
<tr class="footer">
|
|
||||||
<td style="background: #eee;">Markdown</td>
|
|
||||||
<td>Expected Markup</td>
|
|
||||||
<td>Actual Markup</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<script type="text/javascript">
|
|
||||||
|
|
||||||
$('#explorer').click(function(e) {
|
|
||||||
$('input[name=text]').val($('#md').text());
|
|
||||||
$('form').submit();
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
|
|
||||||
</script>
|
|
||||||
|
|
||||||
</body>
|
|
||||||
|
|
||||||
</html>
|
|
@ -1,2 +0,0 @@
|
|||||||
<h1>This is an h1</h1>
|
|
||||||
<h2>This is an h2</h2>
|
|
@ -1,3 +0,0 @@
|
|||||||
# This is an h1
|
|
||||||
|
|
||||||
## This is an h2
|
|
@ -1,5 +0,0 @@
|
|||||||
<p>Here's <em>an emphasis</em>.</p>
|
|
||||||
<p>Here's <strong>a strong one</strong>. </p>
|
|
||||||
<p>Here's <em>an emphasis that uses underscores</em>. </p>
|
|
||||||
<p>Here's <strong>a strong emphasis that uses underscores</strong>.</p>
|
|
||||||
<p>This is _ not an emphasis _.</p>
|
|
@ -1,9 +0,0 @@
|
|||||||
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 _.
|
|
Reference in New Issue
Block a user