1
0
mirror of https://github.com/erusev/parsedown.git synced 2023-08-10 21:13:06 +03:00

Compare commits

..

27 Commits
0.5.0 ... 0.7.6

Author SHA1 Message Date
51a08fad85 improve parsing of emphasis 2013-12-07 17:21:36 +02:00
7fb08f334a improve comments 2013-12-07 10:54:05 +02:00
85ad014f74 parse code span after recursive types to resolve #44 2013-12-06 01:43:55 +02:00
22336a1bcc simplify special characters test 2013-12-06 00:45:26 +02:00
f713e380ee add comment for automatic link 2013-12-06 00:29:51 +02:00
5b01915a63 interrupted list items should not add nonexistent empty lines 2013-12-06 00:15:17 +02:00
18d112a614 improve readme 2013-12-03 23:19:50 +02:00
1b9641ad03 improve readme 2013-12-03 22:49:50 +02:00
8baf537c12 resolve #40 2013-12-02 23:26:43 +02:00
05823567bc simplify comments 2013-12-02 23:02:15 +02:00
b7029ab176 improve readme 2013-12-01 00:10:30 +02:00
102a947c7a improve readme 2013-11-23 15:58:58 +02:00
7bb70186c1 simplify test for em strong 2013-11-23 13:35:15 +02:00
3225c66863 ***strong em** inside of em* should produce valid markup 2013-11-23 13:19:06 +02:00
d6dc5ba25b update introduction text to match website 2013-11-23 09:26:44 +02:00
f5451a9eff Merge pull request #37 from hkdobrev/htmlspecialshars-utf8 2013-11-22 13:23:21 -08:00
849a89b121 Use UTF-8 encoding for htmlspecialchars. See #36.
Prior to PHP 5.4.0 the default encoding for `htmlentities()`
and `htmlspecialchars` is "ISO-8859-1". For PHP 5.4+ is "UTF-8".

This ensures always the right encoding is used no matter the PHP version
and the locale settings.
2013-11-22 23:06:20 +02:00
28064a63b3 simplify encoding of special characters 2013-11-22 21:57:21 +02:00
800aac5b56 Merge pull request #36 from josephok/patch-1 2013-11-22 11:21:38 -08:00
b15d40e8a3 Update Parsedown.php
Changes the htmlentities() to htmlspecialchars(). The htmlentities() has some problems encoding non-english words(like Chinese)
2013-11-22 23:05:26 +08:00
ddc5b7e2dd implement URL auto-linking 2013-11-22 00:20:45 +02:00
5a563008aa implement GFM strikethrough 2013-11-21 13:39:00 +02:00
b6f795962f resolve #21 2013-11-21 00:59:30 +02:00
cdb2646063 update readme to match website 2013-11-20 23:10:03 +02:00
e3b8026e39 build should no longer allow failures 2013-11-18 22:39:44 +02:00
d96f668c42 update test case to make it run on PHP 5.2 2013-11-18 22:29:15 +02:00
96bf75bd91 remove goto to provide support for PHP 5.2 2013-11-18 21:42:00 +02:00
20 changed files with 223 additions and 148 deletions

View File

@ -4,8 +4,4 @@ php:
- 5.5
- 5.4
- 5.3
- 5.2
matrix:
allow_failures:
- php: 5.2
- 5.2

View File

@ -110,7 +110,6 @@ class Parsedown
foreach ($lines as $line)
{
#
# fenced elements
switch ($element['type'])
@ -168,7 +167,6 @@ class Parsedown
continue;
}
#
# composite elements
switch ($element['type'])
@ -223,6 +221,8 @@ class Parsedown
$element['lines'] []= $line;
unset($element['interrupted']);
continue 2;
}
}
@ -238,20 +238,10 @@ class Parsedown
break;
}
# ~
if ($line[0] >= 'a' and $line[0] !== '~' or $line[0] >= 'A' and $line[0] <= 'Z')
{
goto paragraph;
}
# ~
# indentation sensitive types
$deindented_line = $line;
#
# indentation sensitive types
switch ($line[0])
{
case ' ':
@ -345,7 +335,6 @@ class Parsedown
break;
}
#
# indentation insensitive types
switch ($deindented_line[0])
@ -500,9 +489,7 @@ class Parsedown
continue;
}
# ~
paragraph:
# paragraph
if ($element['type'] === 'p')
{
@ -579,11 +566,15 @@ class Parsedown
case 'code_block':
case 'fenced_code_block':
$text = htmlentities($element['text'], ENT_NOQUOTES);
$text = htmlspecialchars($element['text'], ENT_NOQUOTES, 'UTF-8');
strpos($text, "\x1A\\") !== FALSE and $text = strtr($text, $this->escape_sequence_map);
$markup .= '<pre><code>'.$text.'</code></pre>'."\n";
$markup .= isset($element['language'])
? '<pre><code class="language-'.$element['language'].'">'.$text.'</code></pre>'
: '<pre><code>'.$text.'</code></pre>';
$markup .= "\n";
break;
@ -638,6 +629,81 @@ class Parsedown
$index = 0;
# inline link / inline image (recursive)
if (strpos($text, '](') !== FALSE and preg_match_all('/(!?)(\[((?:[^\[\]]|(?2))*)\])\((.*?)\)/', $text, $matches, PREG_SET_ORDER))
{
foreach ($matches as $matches)
{
$url = $matches[4];
strpos($url, '&') !== FALSE and $url = preg_replace('/&(?!#?\w+;)/', '&amp;', $url);
if ($matches[1]) # image
{
$element = '<img alt="'.$matches[3].'" src="'.$url.'">';
}
else # link
{
$element_text = $this->parse_span_elements($matches[3]);
$element = '<a href="'.$url.'">'.$element_text.'</a>';
}
# ~
$code = "\x1A".'$'.$index;
$text = str_replace($matches[0], $code, $text);
$map[$code] = $element;
$index ++;
}
}
# reference link / reference image (recursive)
if ($this->reference_map and strpos($text, '[') !== FALSE and preg_match_all('/(!?)\[(.+?)\](?:\n?[ ]?\[(.*?)\])?/ms', $text, $matches, PREG_SET_ORDER))
{
foreach ($matches as $matches)
{
$link_definition = isset($matches[3]) && $matches[3]
? $matches[3]
: $matches[2]; # implicit
$link_definition = strtolower($link_definition);
if (isset($this->reference_map[$link_definition]))
{
$url = $this->reference_map[$link_definition];
strpos($url, '&') !== FALSE and $url = preg_replace('/&(?!#?\w+;)/', '&amp;', $url);
if ($matches[1]) # image
{
$element = '<img alt="'.$matches[2].'" src="'.$url.'">';
}
else # link
{
$element_text = $this->parse_span_elements($matches[2]);
$element = '<a href="'.$url.'">'.$element_text.'</a>';
}
# ~
$code = "\x1A".'$'.$index;
$text = str_replace($matches[0], $code, $text);
$map[$code] = $element;
$index ++;
}
}
}
# code span
if (strpos($text, '`') !== FALSE and preg_match_all('/`(.+?)`/', $text, $matches, PREG_SET_ORDER))
@ -645,7 +711,7 @@ class Parsedown
foreach ($matches as $matches)
{
$element_text = $matches[1];
$element_text = htmlentities($element_text, ENT_NOQUOTES);
$element_text = htmlspecialchars($element_text, ENT_NOQUOTES, 'UTF-8');
# decodes escape sequences
@ -669,104 +735,37 @@ class Parsedown
}
}
# inline link or image
if (strpos($text, '](') !== FALSE and preg_match_all('/(!?)(\[((?:[^\[\]]|(?2))*)\])\((.*?)\)/', $text, $matches, PREG_SET_ORDER)) # inline
{
foreach ($matches as $matches)
{
$url = $matches[4];
strpos($url, '&') !== FALSE and $url = preg_replace('/&(?!#?\w+;)/', '&amp;', $url);
if ($matches[1]) # image
{
$element = '<img alt="'.$matches[3].'" src="'.$url.'">';
}
else
{
$element_text = $this->parse_span_elements($matches[3]);
$element = '<a href="'.$url.'">'.$element_text.'</a>';
}
# ~
$code = "\x1A".'$'.$index;
$text = str_replace($matches[0], $code, $text);
$map[$code] = $element;
$index ++;
}
}
# reference link or image
if ($this->reference_map and strpos($text, '[') !== FALSE and preg_match_all('/(!?)\[(.+?)\](?:\n?[ ]?\[(.*?)\])?/ms', $text, $matches, PREG_SET_ORDER))
{
foreach ($matches as $matches)
{
$link_definition = isset($matches[3]) && $matches[3]
? $matches[3]
: $matches[2]; # implicit
$link_definition = strtolower($link_definition);
if (isset($this->reference_map[$link_definition]))
{
$url = $this->reference_map[$link_definition];
strpos($url, '&') !== FALSE and $url = preg_replace('/&(?!#?\w+;)/', '&amp;', $url);
if ($matches[1]) # image
{
$element = '<img alt="'.$matches[2].'" src="'.$url.'">';
}
else # anchor
{
$element_text = $this->parse_span_elements($matches[2]);
$element = '<a href="'.$url.'">'.$element_text.'</a>';
}
# ~
$code = "\x1A".'$'.$index;
$text = str_replace($matches[0], $code, $text);
$map[$code] = $element;
$index ++;
}
}
}
# automatic link
if (strpos($text, '<') !== FALSE and preg_match_all('/<((https?|ftp|dict):[^\^\s]+?)>/i', $text, $matches, PREG_SET_ORDER))
if (strpos($text, '://') !== FALSE)
{
foreach ($matches as $matches)
switch (TRUE)
{
$url = $matches[1];
case preg_match_all('{<(https?:[/]{2}[^\s]+)>}i', $text, $matches, PREG_SET_ORDER):
case preg_match_all('{\b(https?:[/]{2}[^\s]+)\b}i', $text, $matches, PREG_SET_ORDER):
strpos($url, '&') !== FALSE and $url = preg_replace('/&(?!#?\w+;)/', '&amp;', $url);
foreach ($matches as $matches)
{
$url = $matches[1];
$element = '<a href=":href">:text</a>';
$element = str_replace(':text', $url, $element);
$element = str_replace(':href', $url, $element);
strpos($url, '&') !== FALSE and $url = preg_replace('/&(?!#?\w+;)/', '&amp;', $url);
# ~
$element = '<a href=":href">:text</a>';
$element = str_replace(':text', $url, $element);
$element = str_replace(':href', $url, $element);
$code = "\x1A".'$'.$index;
# ~
$text = str_replace($matches[0], $code, $text);
$code = "\x1A".'$'.$index;
$map[$code] = $element;
$text = str_replace($matches[0], $code, $text);
$index ++;
$map[$code] = $element;
$index ++;
}
break;
}
}
@ -777,20 +776,27 @@ class Parsedown
# ~
if (strpos($text, '~~') !== FALSE)
{
$text = preg_replace('/~~(?=\S)(.+?)(?<=\S)~~/s', '<del>$1</del>', $text);
}
if (strpos($text, '_') !== FALSE)
{
$text = preg_replace('/__(?=\S)(.+?)(?<=\S)__(?!_)/s', '<strong>$1</strong>', $text);
$text = preg_replace('/_(?=\S)(.+?)(?<=\S)_/s', '<em>$1</em>', $text);
$text = preg_replace('/__(?=\S)([^_]+?)(?<=\S)__/s', '<strong>$1</strong>', $text, -1, $count);
$text = preg_replace('/(\b|_)_(?=\S)([^_]+?)(?<=\S)_(\b|_)/s', '$1<em>$2</em>$3', $text);
$text = preg_replace('/__(?=\S)([^_]+?)(?<=\S)__/s', '<strong>$1</strong>', $text, -1, $count);
}
if (strpos($text, '*') !== FALSE)
{
$text = preg_replace('/\*\*(?=\S)(.+?)(?<=\S)\*\*(?!\*)/s', '<strong>$1</strong>', $text);
$text = preg_replace('/\*(?=\S)(.+?)(?<=\S)\*/s', '<em>$1</em>', $text);
$text = preg_replace('/\*\*(?=\S)([^*]+?)(?<=\S)\*\*/s', '<strong>$1</strong>', $text);
$text = preg_replace('/\*(?=\S)([^*]+?)(?<=\S)\*/s', '<em>$1</em>', $text);
$text = preg_replace('/\*\*(?=\S)([^*]+?)(?<=\S)\*\*/s', '<strong>$1</strong>', $text);
}
$text = strtr($text, $map);
return $text;
}
}
}

View File

@ -1,8 +1,20 @@
## Parsedown
Parsedown is a Markdown parser for PHP. It is fast, consistent and easy to use.
Better [Markdown](http://daringfireball.net/projects/markdown/) parser for PHP.
[Home](http://parsedown.org) &middot; [Demo](http://parsedown.org/explorer/) &middot; [Tests](http://parsedown.org/tests/)
***
[demo](http://parsedown.org/demo) &middot; [tests](http://parsedown.org/tests/)
***
### Features
* [fast](http://parsedown.org/speed)
* [consistent](http://parsedown.org/consistency)
* [GitHub Flavored](https://help.github.com/articles/github-flavored-markdown)
* [tested](https://travis-ci.org/erusev/parsedown) in PHP 5.2, 5.3, 5.4 and 5.5
* friendly to international input
### Installation

View File

@ -5,7 +5,7 @@ include 'Parsedown.php';
class Test extends PHPUnit_Framework_TestCase
{
const provider_dir = 'data/';
/**
* @dataProvider provider
*/
@ -15,33 +15,41 @@ class Test extends PHPUnit_Framework_TestCase
$this->assertEquals($expected_markup, $actual_markup);
}
function provider()
{
$provider = array();
$DirectoryIterator = new DirectoryIterator(__DIR__ . '/' . self::provider_dir);
$path = dirname(__FILE__).'/';
$DirectoryIterator = new DirectoryIterator($path . '/' . self::provider_dir);
foreach ($DirectoryIterator as $Item)
{
if ($Item->isFile() and $Item->getExtension() === 'md')
if ($Item->isFile())
{
$filename = $Item->getFilename();
$extension = pathinfo($filename, PATHINFO_EXTENSION);
if ($extension !== 'md')
continue;
$basename = $Item->getBasename('.md');
$markdown = file_get_contents(__DIR__ . '/' . self::provider_dir . $basename . '.md');
$markdown = file_get_contents($path . '/' . self::provider_dir . $basename . '.md');
if (!$markdown)
continue;
$expected_markup = file_get_contents(__DIR__ . '/' . self::provider_dir . $basename . '.html');
$expected_markup = file_get_contents($path . '/' . 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;
}
}
}

View File

@ -1,5 +1,6 @@
<p><strong><em>em strong</em></strong></p>
<p><strong><em>one</em> at the start</strong></p>
<p><strong>one at the <em>end</em></strong></p>
<p><strong>one <em>in the</em> middle</strong></p>
<p><strong>one with <em>asterisks</em></strong></p>
<p><strong><em>em strong</em> strong</strong></p>
<p><strong>strong <em>em strong</em></strong></p>
<p><strong>strong <em>em strong</em> strong</strong></p>
<p><strong><em>em strong</em> strong</strong></p>
<p><strong>strong <em>em strong</em></strong></p>
<p><strong>strong <em>em strong</em> strong</strong></p>

View File

@ -1,9 +1,11 @@
___em strong___
___em strong_ strong__
___one_ at the start__
__strong _em strong___
__one at the _end___
__strong _em strong_ strong__
__one _in the_ middle__
***em strong* strong**
**one with *asterisks***
**strong *em strong***
**strong *em strong* strong**

View File

@ -2,4 +2,6 @@
<p><em>multiline
emphasis</em></p>
<p>_ this _ is not an emphasis, neither is _ this_, _this _, or _this*</p>
<p>an empty emphasis __ ** is not an emphasis</p>
<p>this_is_not_an_emphasis</p>
<p>an empty emphasis __ ** is not an emphasis</p>
<p>*mixed *<em>double and</em> single asterisk** spans</p>

View File

@ -5,4 +5,8 @@ emphasis_
_ this _ is not an emphasis, neither is _ this_, _this _, or _this*
an empty emphasis __ ** is not an emphasis
this_is_not_an_emphasis
an empty emphasis __ ** is not an emphasis
*mixed **double and* single asterisk** spans

View File

@ -1,2 +1,3 @@
<p><a href="http://example.com">link</a></p>
<p><a href="http://example.com"><code>link</code></a></p>
<p><a href="http://example.com"><img alt="MD Logo" src="http://parsedown.org/md.png"></a></p>

View File

@ -1,3 +1,5 @@
[link](http://example.com)
[`link`](http://example.com)
[![MD Logo](http://parsedown.org/md.png)](http://example.com)

View File

@ -0,0 +1,7 @@
<ul>
<li>
<p>li</p>
<p>line
line</p>
</li>
</ul>

View File

@ -0,0 +1,4 @@
- li
line
line

View File

@ -0,0 +1,3 @@
<p><del>strikethrough</del></p>
<p>in the <del>middle</del> of a sentence</p>
<p>in the middle of a w<del>or</del>d</p>

View File

@ -0,0 +1,5 @@
~~strikethrough~~
in the ~~middle~~ of a sentence
in the middle of a w~~or~~d

View File

@ -0,0 +1,6 @@
<p><em><strong>strong em</strong></em> </p>
<p><em>em <strong>strong em</strong></em></p>
<p><em><strong>strong em</strong> em</em></p>
<p><em><strong>strong em</strong></em></p>
<p><em>em <strong>strong em</strong></em></p>
<p><em><strong>strong em</strong> em</em></p>

11
tests/data/strong_em.md Normal file
View File

@ -0,0 +1,11 @@
***strong em***
*em **strong em***
***strong em** em*
___strong em___
_em __strong em___
___strong em__ em_

View File

@ -3,4 +3,5 @@
<p>[one][404] with no definition</p>
<p><a href="http://example.com">multiline
one</a> defined on 2 lines</p>
<p><a href="http://example.com">one</a> with an upper case label</p>
<p><a href="http://example.com">one</a> with an upper case label</p>
<p><a href="http://example.com"><code>link</code></a></p>

View File

@ -13,4 +13,6 @@ one][website] defined on 2 lines
[one][label] with an upper case label
[LABEL]: http://example.com
[LABEL]: http://example.com
[`link`][website]

View File

@ -0,0 +1 @@
<p>Here's an autolink <a href="http://example.com">http://example.com</a>.</p>

View File

@ -0,0 +1 @@
Here's an autolink http://example.com.