mirror of
https://github.com/erusev/parsedown.git
synced 2023-08-10 21:13:06 +03:00
Compare commits
33 Commits
Author | SHA1 | Date | |
---|---|---|---|
f5451a9eff | |||
849a89b121 | |||
28064a63b3 | |||
800aac5b56 | |||
b15d40e8a3 | |||
ddc5b7e2dd | |||
5a563008aa | |||
b6f795962f | |||
cdb2646063 | |||
e3b8026e39 | |||
d96f668c42 | |||
96bf75bd91 | |||
67b51794d8 | |||
a9d6232705 | |||
b91629ad94 | |||
24d300ea5d | |||
d54712b989 | |||
6ef043ba7d | |||
fe27b70bdb | |||
18d3dbf4f6 | |||
4758f58f73 | |||
5fa3eb1b2f | |||
38300323a6 | |||
96609329b9 | |||
e497acb6dc | |||
30e436ec7d | |||
3972f18881 | |||
4fb12be60a | |||
f8b07611d3 | |||
21d7f75f5b | |||
a4fb0651d5 | |||
50a58eab16 | |||
1f347e17eb |
@ -4,8 +4,4 @@ php:
|
||||
- 5.5
|
||||
- 5.4
|
||||
- 5.3
|
||||
- 5.2
|
||||
|
||||
matrix:
|
||||
allow_failures:
|
||||
- php: 5.2
|
||||
- 5.2
|
771
Parsedown.php
771
Parsedown.php
@ -46,17 +46,17 @@ class Parsedown
|
||||
|
||||
function parse($text)
|
||||
{
|
||||
# Removes UTF-8 BOM and marker characters.
|
||||
# removes UTF-8 BOM and marker characters
|
||||
$text = preg_replace('{^\xEF\xBB\xBF|\x1A}', '', $text);
|
||||
|
||||
# Removes \r characters.
|
||||
# removes \r characters
|
||||
$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);
|
||||
|
||||
# Encodes escape sequences.
|
||||
# encodes escape sequences
|
||||
|
||||
if (strpos($text, '\\') !== FALSE)
|
||||
{
|
||||
@ -66,7 +66,7 @@ class Parsedown
|
||||
{
|
||||
if (strpos($text, $escape_sequence) !== FALSE)
|
||||
{
|
||||
$code = "\x1A".'\\'.$index;
|
||||
$code = "\x1A".'\\'.$index.';';
|
||||
|
||||
$text = str_replace($escape_sequence, $code, $text);
|
||||
|
||||
@ -84,7 +84,7 @@ class Parsedown
|
||||
|
||||
$text = $this->parse_block_elements($lines);
|
||||
|
||||
# Decodes escape sequences (leaves out backslashes).
|
||||
# decodes escape sequences
|
||||
|
||||
foreach ($this->escape_sequence_map as $code => $escape_sequence)
|
||||
{
|
||||
@ -110,28 +110,56 @@ class Parsedown
|
||||
|
||||
foreach ($lines as $line)
|
||||
{
|
||||
# Block-Level HTML
|
||||
#
|
||||
# fenced elements
|
||||
|
||||
if ($element['type'] === 'block' and ! isset($element['closed']))
|
||||
switch ($element['type'])
|
||||
{
|
||||
if (preg_match('{<'.$element['subtype'].'>$}', $line)) # <open>
|
||||
{
|
||||
$element['depth']++;
|
||||
}
|
||||
case 'fenced_code_block':
|
||||
|
||||
if (preg_match('{</'.$element['subtype'].'>$}', $line)) # </close>
|
||||
{
|
||||
$element['depth'] > 0
|
||||
? $element['depth']--
|
||||
: $element['closed'] = true;
|
||||
}
|
||||
if ( ! isset($element['closed']))
|
||||
{
|
||||
if (preg_match('/^[ ]*'.$element['fence'][0].'{3,}[ ]*$/', $line))
|
||||
{
|
||||
$element['closed'] = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
$element['text'] !== '' and $element['text'] .= "\n";
|
||||
|
||||
$element['text'] .= "\n".$line;
|
||||
$element['text'] .= $line;
|
||||
}
|
||||
|
||||
continue;
|
||||
continue 2;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'markup':
|
||||
|
||||
if ( ! isset($element['closed']))
|
||||
{
|
||||
if (preg_match('{<'.$element['subtype'].'>$}', $line)) # opening tag
|
||||
{
|
||||
$element['depth']++;
|
||||
}
|
||||
|
||||
if (preg_match('{</'.$element['subtype'].'>$}', $line)) # closing tag
|
||||
{
|
||||
$element['depth'] > 0
|
||||
? $element['depth']--
|
||||
: $element['closed'] = true;
|
||||
}
|
||||
|
||||
$element['text'] .= "\n".$line;
|
||||
|
||||
continue 2;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
# Empty
|
||||
# *
|
||||
|
||||
if ($line === '')
|
||||
{
|
||||
@ -140,269 +168,330 @@ class Parsedown
|
||||
continue;
|
||||
}
|
||||
|
||||
# Lazy Blockquote
|
||||
#
|
||||
# composite elements
|
||||
|
||||
if ($element['type'] === 'blockquote' and ! isset($element['interrupted']))
|
||||
switch ($element['type'])
|
||||
{
|
||||
$line = preg_replace('/^[ ]*>[ ]?/', '', $line);
|
||||
case 'blockquote':
|
||||
|
||||
$element['lines'] []= $line;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
# Lazy List Item
|
||||
|
||||
if ($element['type'] === 'li')
|
||||
{
|
||||
if (preg_match('/^([ ]{0,3})(\d+[.]|[*+-])[ ](.*)/', $line, $matches))
|
||||
{
|
||||
if ($element['indentation'] !== $matches[1])
|
||||
if ( ! isset($element['interrupted']))
|
||||
{
|
||||
$line = preg_replace('/^[ ]*>[ ]?/', '', $line);
|
||||
|
||||
$element['lines'] []= $line;
|
||||
|
||||
continue 2;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'li':
|
||||
|
||||
if (preg_match('/^([ ]{0,3})(\d+[.]|[*+-])[ ](.*)/', $line, $matches))
|
||||
{
|
||||
if ($element['indentation'] !== $matches[1])
|
||||
{
|
||||
$element['lines'] []= $line;
|
||||
}
|
||||
else
|
||||
{
|
||||
unset($element['last']);
|
||||
|
||||
$elements []= $element;
|
||||
|
||||
$element = array(
|
||||
'type' => 'li',
|
||||
'indentation' => $matches[1],
|
||||
'last' => true,
|
||||
'lines' => array(
|
||||
preg_replace('/^[ ]{0,4}/', '', $matches[3]),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
continue 2;
|
||||
}
|
||||
|
||||
if (isset($element['interrupted']))
|
||||
{
|
||||
if ($line[0] === ' ')
|
||||
{
|
||||
$element['lines'] []= '';
|
||||
|
||||
$line = preg_replace('/^[ ]{0,4}/', '', $line);
|
||||
|
||||
$element['lines'] []= $line;
|
||||
|
||||
continue 2;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
unset($element['last']);
|
||||
$line = preg_replace('/^[ ]{0,4}/', '', $line);
|
||||
|
||||
$element['lines'] []= $line;
|
||||
|
||||
continue 2;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
#
|
||||
# indentation sensitive types
|
||||
|
||||
$deindented_line = $line;
|
||||
|
||||
switch ($line[0])
|
||||
{
|
||||
case ' ':
|
||||
|
||||
# ~
|
||||
|
||||
$deindented_line = ltrim($line);
|
||||
|
||||
if ($deindented_line === '')
|
||||
{
|
||||
continue 2;
|
||||
}
|
||||
|
||||
# code block
|
||||
|
||||
if (preg_match('/^[ ]{4}(.*)/', $line, $matches))
|
||||
{
|
||||
if ($element['type'] === 'code_block')
|
||||
{
|
||||
if (isset($element['interrupted']))
|
||||
{
|
||||
$element['text'] .= "\n";
|
||||
|
||||
unset ($element['interrupted']);
|
||||
}
|
||||
|
||||
$element['text'] .= "\n".$matches[1];
|
||||
}
|
||||
else
|
||||
{
|
||||
$elements []= $element;
|
||||
|
||||
$element = array(
|
||||
'type' => 'code_block',
|
||||
'text' => $matches[1],
|
||||
);
|
||||
}
|
||||
|
||||
continue 2;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case '#':
|
||||
|
||||
# atx heading (#)
|
||||
|
||||
if (preg_match('/^(#{1,6})[ ]*(.+?)[ ]*#*$/', $line, $matches))
|
||||
{
|
||||
$elements []= $element;
|
||||
|
||||
$level = strlen($matches[1]);
|
||||
|
||||
$element = array(
|
||||
'type' => 'h.',
|
||||
'text' => $matches[2],
|
||||
'level' => $level,
|
||||
);
|
||||
|
||||
continue 2;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case '-':
|
||||
|
||||
# setext heading (---)
|
||||
|
||||
if ($line[0] === '-' and $element['type'] === 'p' and ! isset($element['interrupted']) and preg_match('/^[-]+[ ]*$/', $line))
|
||||
{
|
||||
$element['type'] = 'h.';
|
||||
$element['level'] = 2;
|
||||
|
||||
continue 2;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case '=':
|
||||
|
||||
# setext heading (===)
|
||||
|
||||
if ($line[0] === '=' and $element['type'] === 'p' and ! isset($element['interrupted']) and preg_match('/^[=]+[ ]*$/', $line))
|
||||
{
|
||||
$element['type'] = 'h.';
|
||||
$element['level'] = 1;
|
||||
|
||||
continue 2;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
#
|
||||
# indentation insensitive types
|
||||
|
||||
switch ($deindented_line[0])
|
||||
{
|
||||
case '<':
|
||||
|
||||
# self-closing tag
|
||||
|
||||
if (preg_match('{^<.+?/>$}', $deindented_line))
|
||||
{
|
||||
$elements []= $element;
|
||||
|
||||
$element = array(
|
||||
'type' => '',
|
||||
'text' => $deindented_line,
|
||||
);
|
||||
|
||||
continue 2;
|
||||
}
|
||||
|
||||
# opening tag
|
||||
|
||||
if (preg_match('{^<(\w+)(?:[ ].*?)?>}', $deindented_line, $matches))
|
||||
{
|
||||
$elements []= $element;
|
||||
|
||||
$element = array(
|
||||
'type' => 'markup',
|
||||
'subtype' => strtolower($matches[1]),
|
||||
'text' => $deindented_line,
|
||||
'depth' => 0,
|
||||
);
|
||||
|
||||
preg_match('{</'.$matches[1].'>\s*$}', $deindented_line) and $element['closed'] = true;
|
||||
|
||||
continue 2;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case '>':
|
||||
|
||||
# quote
|
||||
|
||||
if (preg_match('/^>[ ]?(.*)/', $deindented_line, $matches))
|
||||
{
|
||||
$elements []= $element;
|
||||
|
||||
$element = array(
|
||||
'type' => 'blockquote',
|
||||
'lines' => array(
|
||||
$matches[1],
|
||||
),
|
||||
);
|
||||
|
||||
continue 2;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case '[':
|
||||
|
||||
# reference
|
||||
|
||||
if (preg_match('/^\[(.+?)\]:[ ]*([^ ]+)/', $deindented_line, $matches))
|
||||
{
|
||||
$label = strtolower($matches[1]);
|
||||
|
||||
$this->reference_map[$label] = trim($matches[2], '<>');;
|
||||
|
||||
continue 2;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case '`':
|
||||
case '~':
|
||||
|
||||
# fenced code block
|
||||
|
||||
if (preg_match('/^([`]{3,}|[~]{3,})[ ]*(\S+)?[ ]*$/', $deindented_line, $matches))
|
||||
{
|
||||
$elements []= $element;
|
||||
|
||||
$element = array(
|
||||
'type' => 'fenced_code_block',
|
||||
'text' => '',
|
||||
'fence' => $matches[1],
|
||||
);
|
||||
|
||||
isset($matches[2]) and $element['language'] = $matches[2];
|
||||
|
||||
continue 2;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case '*':
|
||||
case '+':
|
||||
case '-':
|
||||
case '_':
|
||||
|
||||
# hr
|
||||
|
||||
if (preg_match('/^([-*_])([ ]{0,2}\1){2,}[ ]*$/', $deindented_line))
|
||||
{
|
||||
$elements []= $element;
|
||||
|
||||
$element = array(
|
||||
'type' => 'hr',
|
||||
);
|
||||
|
||||
continue 2;
|
||||
}
|
||||
|
||||
# li
|
||||
|
||||
if (preg_match('/^([ ]*)[*+-][ ](.*)/', $line, $matches))
|
||||
{
|
||||
$elements []= $element;
|
||||
|
||||
$element = array(
|
||||
'type' => 'li',
|
||||
'ordered' => false,
|
||||
'indentation' => $matches[1],
|
||||
'last' => true,
|
||||
'lines' => array(
|
||||
preg_replace('/^[ ]{0,4}/', '', $matches[3]),
|
||||
preg_replace('/^[ ]{0,4}/', '', $matches[2]),
|
||||
),
|
||||
);
|
||||
|
||||
continue 2;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isset($element['interrupted']))
|
||||
{
|
||||
if ($line[0] === ' ')
|
||||
{
|
||||
$element['lines'] []= '';
|
||||
|
||||
$line = preg_replace('/^[ ]{0,4}/', '', $line);;
|
||||
|
||||
$element['lines'] []= $line;
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$line = preg_replace('/^[ ]{0,4}/', '', $line);;
|
||||
|
||||
$element['lines'] []= $line;
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
# Quick Paragraph
|
||||
# li
|
||||
|
||||
if ($line[0] >= 'a' or $line[0] >= 'A' and $line[0] <= 'Z')
|
||||
{
|
||||
goto paragraph;
|
||||
}
|
||||
|
||||
# Code Block
|
||||
|
||||
if ($line[0] === ' ' and preg_match('/^[ ]{4}(.*)/', $line, $matches))
|
||||
{
|
||||
if (trim($line) === '')
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($element['type'] === 'code')
|
||||
{
|
||||
if (isset($element['interrupted']))
|
||||
{
|
||||
$element['text'] .= "\n";
|
||||
|
||||
unset ($element['interrupted']);
|
||||
}
|
||||
|
||||
$element['text'] .= "\n".$matches[1];
|
||||
}
|
||||
else
|
||||
{
|
||||
$elements []= $element;
|
||||
|
||||
$element = array(
|
||||
'type' => 'code',
|
||||
'text' => $matches[1],
|
||||
);
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
# Setext Header (---)
|
||||
|
||||
if ($line[0] === '-' and $element['type'] === 'p' and ! isset($element['interrupted']) and preg_match('/^[-]+[ ]*$/', $line))
|
||||
{
|
||||
$element['type'] = 'h.';
|
||||
$element['level'] = 2;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
# Atx Header (#)
|
||||
|
||||
if ($line[0] === '#' and preg_match('/^(#{1,6})[ ]*(.+?)[ ]*#*$/', $line, $matches))
|
||||
{
|
||||
$elements []= $element;
|
||||
|
||||
$level = strlen($matches[1]);
|
||||
|
||||
$element = array(
|
||||
'type' => 'h.',
|
||||
'text' => $matches[2],
|
||||
'level' => $level,
|
||||
);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
# Setext Header (===)
|
||||
|
||||
if ($line[0] === '=' and $element['type'] === 'p' and ! isset($element['interrupted']) and preg_match('/^[=]+[ ]*$/', $line))
|
||||
{
|
||||
$element['type'] = 'h.';
|
||||
$element['level'] = 1;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
# ~
|
||||
|
||||
$pure_line = $line[0] !== ' ' ? $line : ltrim($line);
|
||||
|
||||
if ($pure_line === '')
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
# Link Reference
|
||||
|
||||
if ($pure_line[0] === '[' and preg_match('/^\[(.+?)\]:[ ]*([^ ]+)/', $pure_line, $matches))
|
||||
{
|
||||
$label = strtolower($matches[1]);
|
||||
$url = trim($matches[2], '<>');
|
||||
|
||||
$this->reference_map[$label] = $url;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
# Blockquote
|
||||
|
||||
if ($pure_line[0] === '>' and preg_match('/^>[ ]?(.*)/', $pure_line, $matches))
|
||||
{
|
||||
if ($element['type'] === 'blockquote')
|
||||
{
|
||||
if (isset($element['interrupted']))
|
||||
{
|
||||
$element['lines'] []= '';
|
||||
|
||||
unset($element['interrupted']);
|
||||
}
|
||||
|
||||
$element['lines'] []= $matches[1];
|
||||
}
|
||||
else
|
||||
{
|
||||
$elements []= $element;
|
||||
|
||||
$element = array(
|
||||
'type' => 'blockquote',
|
||||
'lines' => array(
|
||||
$matches[1],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
# HTML
|
||||
|
||||
if ($pure_line[0] === '<')
|
||||
{
|
||||
# Block-Level HTML <self-closing/>
|
||||
|
||||
if (preg_match('{^<.+?/>$}', $pure_line))
|
||||
{
|
||||
$elements []= $element;
|
||||
|
||||
$element = array(
|
||||
'type' => '',
|
||||
'text' => $pure_line,
|
||||
);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
# Block-Level HTML <open>
|
||||
|
||||
if (preg_match('{^<(\w+)(?:[ ].*?)?>}', $pure_line, $matches))
|
||||
{
|
||||
$elements []= $element;
|
||||
|
||||
$element = array(
|
||||
'type' => 'block',
|
||||
'subtype' => strtolower($matches[1]),
|
||||
'text' => $pure_line,
|
||||
'depth' => 0,
|
||||
);
|
||||
|
||||
preg_match('{</'.$matches[1].'>\s*$}', $pure_line) and $element['closed'] = true;
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
# Horizontal Rule
|
||||
|
||||
if (preg_match('/^([-*_])([ ]{0,2}\1){2,}[ ]*$/', $pure_line))
|
||||
{
|
||||
$elements []= $element;
|
||||
|
||||
$element = array(
|
||||
'type' => 'hr',
|
||||
);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
# List Item
|
||||
|
||||
if (preg_match('/^([ ]*)(\d+[.]|[*+-])[ ](.*)/', $line, $matches))
|
||||
if ($deindented_line[0] <= '9' and $deindented_line >= '0' and preg_match('/^([ ]*)\d+[.][ ](.*)/', $line, $matches))
|
||||
{
|
||||
$elements []= $element;
|
||||
|
||||
$element = array(
|
||||
'type' => 'li',
|
||||
'ordered' => isset($matches[2][1]),
|
||||
'ordered' => true,
|
||||
'indentation' => $matches[1],
|
||||
'last' => true,
|
||||
'lines' => array(
|
||||
preg_replace('/^[ ]{0,4}/', '', $matches[3]),
|
||||
preg_replace('/^[ ]{0,4}/', '', $matches[2]),
|
||||
),
|
||||
);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
# ~
|
||||
|
||||
paragraph:
|
||||
# paragraph
|
||||
|
||||
if ($element['type'] === 'p')
|
||||
{
|
||||
@ -432,7 +521,7 @@ class Parsedown
|
||||
|
||||
$elements []= $element;
|
||||
|
||||
array_shift($elements);
|
||||
unset($elements[0]);
|
||||
|
||||
#
|
||||
# ~
|
||||
@ -440,10 +529,67 @@ class Parsedown
|
||||
|
||||
$markup = '';
|
||||
|
||||
foreach ($elements as $index => $element)
|
||||
foreach ($elements as $element)
|
||||
{
|
||||
switch ($element['type'])
|
||||
{
|
||||
case 'p':
|
||||
|
||||
$text = $this->parse_span_elements($element['text']);
|
||||
|
||||
$text = preg_replace('/[ ]{2}\n/', '<br />'."\n", $text);
|
||||
|
||||
if ($context === 'li' and $markup === '')
|
||||
{
|
||||
if (isset($element['interrupted']))
|
||||
{
|
||||
$markup .= "\n".'<p>'.$text.'</p>'."\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
$markup .= $text;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$markup .= '<p>'.$text.'</p>'."\n";
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'blockquote':
|
||||
|
||||
$text = $this->parse_block_elements($element['lines']);
|
||||
|
||||
$markup .= '<blockquote>'."\n".$text.'</blockquote>'."\n";
|
||||
|
||||
break;
|
||||
|
||||
case 'code_block':
|
||||
case 'fenced_code_block':
|
||||
|
||||
$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";
|
||||
|
||||
break;
|
||||
|
||||
case 'h.':
|
||||
|
||||
$text = $this->parse_span_elements($element['text']);
|
||||
|
||||
$markup .= '<h'.$element['level'].'>'.$text.'</h'.$element['level'].'>'."\n";
|
||||
|
||||
break;
|
||||
|
||||
case 'hr':
|
||||
|
||||
$markup .= '<hr />'."\n";
|
||||
|
||||
break;
|
||||
|
||||
case 'li':
|
||||
|
||||
if (isset($element['ordered'])) # first
|
||||
@ -466,62 +612,6 @@ class Parsedown
|
||||
|
||||
break;
|
||||
|
||||
case 'p':
|
||||
|
||||
$text = $this->parse_inline_elements($element['text']);
|
||||
|
||||
$text = preg_replace('/[ ]{2}\n/', '<br />'."\n", $text);
|
||||
|
||||
if ($context === 'li' and $index === 0)
|
||||
{
|
||||
if (isset($element['interrupted']))
|
||||
{
|
||||
$markup .= "\n".'<p>'.$text.'</p>'."\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
$markup .= $text;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$markup .= '<p>'.$text.'</p>'."\n";
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'code':
|
||||
|
||||
$text = htmlentities($element['text'], ENT_NOQUOTES);
|
||||
|
||||
strpos($text, "\x1A\\") !== FALSE and $text = strtr($text, $this->escape_sequence_map);
|
||||
|
||||
$markup .= '<pre><code>'.$text.'</code></pre>'."\n";
|
||||
|
||||
break;
|
||||
|
||||
case 'blockquote':
|
||||
|
||||
$text = $this->parse_block_elements($element['lines']);
|
||||
|
||||
$markup .= '<blockquote>'."\n".$text.'</blockquote>'."\n";
|
||||
|
||||
break;
|
||||
|
||||
case 'h.':
|
||||
|
||||
$text = $this->parse_inline_elements($element['text']);
|
||||
|
||||
$markup .= '<h'.$element['level'].'>'.$text.'</h'.$element['level'].'>'."\n";
|
||||
|
||||
break;
|
||||
|
||||
case 'hr':
|
||||
|
||||
$markup .= '<hr />'."\n";
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
$markup .= $element['text']."\n";
|
||||
@ -531,32 +621,32 @@ class Parsedown
|
||||
return $markup;
|
||||
}
|
||||
|
||||
private function parse_inline_elements($text)
|
||||
private function parse_span_elements($text)
|
||||
{
|
||||
$map = array();
|
||||
|
||||
$index = 0;
|
||||
|
||||
# Code Span
|
||||
# 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);
|
||||
$element_text = htmlspecialchars($element_text, ENT_NOQUOTES, 'UTF-8');
|
||||
|
||||
# Decodes escape sequences.
|
||||
# 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.
|
||||
# composes element
|
||||
|
||||
$element = '<code>'.$element_text.'</code>';
|
||||
|
||||
# Encodes element.
|
||||
# encodes element
|
||||
|
||||
$code = "\x1A".'$'.$index;
|
||||
|
||||
@ -568,7 +658,7 @@ class Parsedown
|
||||
}
|
||||
}
|
||||
|
||||
# Inline Link / Image
|
||||
# inline link or image
|
||||
|
||||
if (strpos($text, '](') !== FALSE and preg_match_all('/(!?)(\[((?:[^\[\]]|(?2))*)\])\((.*?)\)/', $text, $matches, PREG_SET_ORDER)) # inline
|
||||
{
|
||||
@ -584,7 +674,7 @@ class Parsedown
|
||||
}
|
||||
else
|
||||
{
|
||||
$element_text = $this->parse_inline_elements($matches[3]);
|
||||
$element_text = $this->parse_span_elements($matches[3]);
|
||||
|
||||
$element = '<a href="'.$url.'">'.$element_text.'</a>';
|
||||
}
|
||||
@ -601,7 +691,7 @@ class Parsedown
|
||||
}
|
||||
}
|
||||
|
||||
# Reference(d) Link / Image
|
||||
# reference link or image
|
||||
|
||||
if ($this->reference_map and strpos($text, '[') !== FALSE and preg_match_all('/(!?)\[(.+?)\](?:\n?[ ]?\[(.*?)\])?/ms', $text, $matches, PREG_SET_ORDER))
|
||||
{
|
||||
@ -625,7 +715,7 @@ class Parsedown
|
||||
}
|
||||
else # anchor
|
||||
{
|
||||
$element_text = $this->parse_inline_elements($matches[2]);
|
||||
$element_text = $this->parse_span_elements($matches[2]);
|
||||
|
||||
$element = '<a href="'.$url.'">'.$element_text.'</a>';
|
||||
}
|
||||
@ -643,29 +733,35 @@ class Parsedown
|
||||
}
|
||||
}
|
||||
|
||||
# Automatic Links
|
||||
|
||||
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+;)/', '&', $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+;)/', '&', $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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -676,20 +772,25 @@ 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)__/', '<strong>$1</strong>', $text);
|
||||
$text = preg_replace('/_(?=\S)(.+?)(?<=\S)_/', '<em>$1</em>', $text);
|
||||
$text = preg_replace('/__(?=\S)(.+?)(?<=\S)__(?!_)/s', '<strong>$1</strong>', $text);
|
||||
$text = preg_replace('/\b_(?=\S)(.+?)(?<=\S)_\b/s', '<em>$1</em>', $text);
|
||||
}
|
||||
|
||||
if (strpos($text, '*') !== FALSE)
|
||||
{
|
||||
$text = preg_replace('/\*\*(?=\S)(.+?)(?<=\S)\*\*/', '<strong>$1</strong>', $text);
|
||||
$text = preg_replace('/\*(?=\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 = strtr($text, $map);
|
||||
|
||||
return $text;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
11
README.md
11
README.md
@ -1,9 +1,8 @@
|
||||
## Parsedown PHP
|
||||
## Parsedown
|
||||
|
||||
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.
|
||||
Fast, consistent and easy to use [Markdown][1] parser for PHP.
|
||||
|
||||
[Explorer (demo)](http://parsedown.org/explorer/)
|
||||
[Tests](http://parsedown.org/tests/)
|
||||
[Home](http://parsedown.org) · [Demo](http://parsedown.org/explorer/) · [Tests](http://parsedown.org/tests/)
|
||||
|
||||
### Installation
|
||||
|
||||
@ -17,4 +16,6 @@ $text = 'Hello **Parsedown**!';
|
||||
$result = Parsedown::instance()->parse($text);
|
||||
|
||||
echo $result; # prints: <p>Hello <strong>Parsedown</strong>!</p>
|
||||
```
|
||||
```
|
||||
|
||||
[1]: http://daringfireball.net/projects/markdown/
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
<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>h1</h1>
|
||||
<h2>h2</h2>
|
||||
<h3>h3</h3>
|
||||
<h4>h4</h4>
|
||||
<h5>h5</h5>
|
||||
<h6>h6</h6>
|
||||
<h1>closed h1</h1>
|
@ -1,11 +1,13 @@
|
||||
# This is an h1
|
||||
# h1
|
||||
|
||||
## This is an h2
|
||||
## h2
|
||||
|
||||
### This is an h3
|
||||
### h3
|
||||
|
||||
#### This is an h4
|
||||
#### h4
|
||||
|
||||
##### This is an h5
|
||||
##### h5
|
||||
|
||||
###### This is an h6
|
||||
###### h6
|
||||
|
||||
# closed h1 #
|
@ -1,6 +0,0 @@
|
||||
<h1>h1</h1>
|
||||
<h2>h2</h2>
|
||||
<h3>h3</h3>
|
||||
<h4>h4</h4>
|
||||
<h5>h5</h5>
|
||||
<h6>h6</h6>
|
@ -1,11 +0,0 @@
|
||||
# h1 #
|
||||
|
||||
## h2 ##
|
||||
|
||||
### h3 ###
|
||||
|
||||
#### h4 ####
|
||||
|
||||
##### h5 #####
|
||||
|
||||
###### h6 ######
|
9
tests/data/block-level_html.html
Normal file
9
tests/data/block-level_html.html
Normal file
@ -0,0 +1,9 @@
|
||||
<div>content</div>
|
||||
<hr style="background: #eaa;" />
|
||||
<p>nested elements:</p>
|
||||
<div>
|
||||
parent
|
||||
<div>
|
||||
child
|
||||
</div>
|
||||
</div>
|
12
tests/data/block-level_html.md
Normal file
12
tests/data/block-level_html.md
Normal file
@ -0,0 +1,12 @@
|
||||
<div>content</div>
|
||||
|
||||
<hr style="background: #eaa;" />
|
||||
|
||||
nested elements:
|
||||
|
||||
<div>
|
||||
parent
|
||||
<div>
|
||||
child
|
||||
</div>
|
||||
</div>
|
@ -1,9 +0,0 @@
|
||||
<p>Here's a blockquote:</p>
|
||||
<blockquote>
|
||||
<p>blockquote</p>
|
||||
</blockquote>
|
||||
<p>Here's one on multiple lines:</p>
|
||||
<blockquote>
|
||||
<p>line 1
|
||||
line 2</p>
|
||||
</blockquote>
|
@ -1,8 +0,0 @@
|
||||
Here's a blockquote:
|
||||
|
||||
> blockquote
|
||||
|
||||
Here's one on multiple lines:
|
||||
|
||||
> line 1
|
||||
> line 2
|
@ -1,16 +0,0 @@
|
||||
<p>Here's one with multiple paragraphs:</p>
|
||||
<blockquote>
|
||||
<p>This is line one.</p>
|
||||
<p>This is line two.</p>
|
||||
</blockquote>
|
||||
<p>Here's one with multiple types of blocks:</p>
|
||||
<blockquote>
|
||||
<p>This is a quoted paragraph.</p>
|
||||
<ul>
|
||||
<li>This is a list item of a quoted list.</li>
|
||||
<li>This is another list item.</li>
|
||||
</ul>
|
||||
<blockquote>
|
||||
<p>This is a nested quote block.</p>
|
||||
</blockquote>
|
||||
</blockquote>
|
@ -1,14 +0,0 @@
|
||||
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.
|
@ -1,11 +0,0 @@
|
||||
<p>Here's a lazy blockquote:</p>
|
||||
<blockquote>
|
||||
<p>line
|
||||
line</p>
|
||||
</blockquote>
|
||||
<p>Here's one with multiple lines:</p>
|
||||
<blockquote>
|
||||
<p>line
|
||||
line
|
||||
line</p>
|
||||
</blockquote>
|
@ -1,10 +0,0 @@
|
||||
Here's a lazy blockquote:
|
||||
|
||||
> line
|
||||
line
|
||||
|
||||
Here's one with multiple lines:
|
||||
|
||||
> line
|
||||
line
|
||||
line
|
@ -1,12 +0,0 @@
|
||||
<p>Here's a blockquote with no space after the ">":</p>
|
||||
<blockquote>
|
||||
<p>blockquote</p>
|
||||
</blockquote>
|
||||
<p>Here's a blockquote with leading space:</p>
|
||||
<blockquote>
|
||||
<p>blockquote</p>
|
||||
</blockquote>
|
||||
<p>Here's a blockquote on the next line:</p>
|
||||
<blockquote>
|
||||
<p>blockquote</p>
|
||||
</blockquote>
|
@ -1,10 +0,0 @@
|
||||
Here's a blockquote with no space after the ">":
|
||||
|
||||
>blockquote
|
||||
|
||||
Here's a blockquote with leading space:
|
||||
|
||||
> blockquote
|
||||
|
||||
Here's a blockquote on the next line:
|
||||
> blockquote
|
@ -1,5 +1,8 @@
|
||||
<p>Here's a code block:</p>
|
||||
<pre><code><?php
|
||||
|
||||
$message = 'Hello World!';
|
||||
echo $message;</code></pre>
|
||||
echo $message;</code></pre>
|
||||
<hr />
|
||||
<pre><code>> not a quote
|
||||
- not a list item
|
||||
[not a reference]: http://foo.com</code></pre>
|
@ -1,6 +1,11 @@
|
||||
Here's a code block:
|
||||
|
||||
<?php
|
||||
|
||||
$message = 'Hello World!';
|
||||
echo $message;
|
||||
echo $message;
|
||||
|
||||
---
|
||||
|
||||
> not a quote
|
||||
- not a list item
|
||||
[not a reference]: http://foo.com
|
||||
|
@ -1 +1 @@
|
||||
<p>This is a <code>code span</code>.</p>
|
||||
<p>a <code>code span</code></p>
|
@ -1 +1 @@
|
||||
This is a `code span`.
|
||||
a `code span`
|
9
tests/data/compound_blockquote.html
Normal file
9
tests/data/compound_blockquote.html
Normal file
@ -0,0 +1,9 @@
|
||||
<blockquote>
|
||||
<h2>header</h2>
|
||||
<p>paragraph</p>
|
||||
<ul>
|
||||
<li>li</li>
|
||||
</ul>
|
||||
<hr />
|
||||
<p>paragraph</p>
|
||||
</blockquote>
|
10
tests/data/compound_blockquote.md
Normal file
10
tests/data/compound_blockquote.md
Normal file
@ -0,0 +1,10 @@
|
||||
> header
|
||||
> ------
|
||||
>
|
||||
> paragraph
|
||||
>
|
||||
> - li
|
||||
>
|
||||
> ---
|
||||
>
|
||||
> paragraph
|
12
tests/data/compound_list.html
Normal file
12
tests/data/compound_list.html
Normal file
@ -0,0 +1,12 @@
|
||||
<ul>
|
||||
<li>
|
||||
<p>paragraph</p>
|
||||
<p>paragraph</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>paragraph</p>
|
||||
<blockquote>
|
||||
<p>quote</p>
|
||||
</blockquote>
|
||||
</li>
|
||||
</ul>
|
7
tests/data/compound_list.md
Normal file
7
tests/data/compound_list.md
Normal file
@ -0,0 +1,7 @@
|
||||
- paragraph
|
||||
|
||||
paragraph
|
||||
|
||||
- paragraph
|
||||
|
||||
> quote
|
5
tests/data/em_strong.html
Normal file
5
tests/data/em_strong.html
Normal file
@ -0,0 +1,5 @@
|
||||
<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>
|
9
tests/data/em_strong.md
Normal file
9
tests/data/em_strong.md
Normal file
@ -0,0 +1,9 @@
|
||||
___em strong___
|
||||
|
||||
___one_ at the start__
|
||||
|
||||
__one at the _end___
|
||||
|
||||
__one _in the_ middle__
|
||||
|
||||
**one with *asterisks***
|
@ -1,7 +1,6 @@
|
||||
<p>Here's <em>an emphasis</em>.</p>
|
||||
<p>A short one <em>a</em> <em>b</em> .</p>
|
||||
<p>Here's <strong>a strong one</strong>. </p>
|
||||
<p>Here's <em>one that uses underscores</em>. </p>
|
||||
<p>Here's <strong>a strong one that uses underscores</strong>.</p>
|
||||
<p>This is not _ one _ neither is * this * neither is _ this_ neither is _this _.</p>
|
||||
<p>An empty emphasis ** is not __ an emphasis.</p>
|
||||
<p><em>underscore</em>, <em>asterisk</em>, <em>one two</em>, <em>three four</em>, <em>a</em>, <em>b</em></p>
|
||||
<p><em>multiline
|
||||
emphasis</em></p>
|
||||
<p>_ this _ is not an emphasis, neither is _ this_, _this _, or _this*</p>
|
||||
<p>this_is_not_an_emphasis</p>
|
||||
<p>an empty emphasis __ ** is not an emphasis</p>
|
@ -1,13 +1,10 @@
|
||||
Here's *an emphasis*.
|
||||
_underscore_, *asterisk*, _one two_, *three four*, _a_, *b*
|
||||
|
||||
A short one _a_ *b* .
|
||||
_multiline
|
||||
emphasis_
|
||||
|
||||
Here's **a strong one**.
|
||||
_ this _ is not an emphasis, neither is _ this_, _this _, or _this*
|
||||
|
||||
Here's _one that uses underscores_.
|
||||
this_is_not_an_emphasis
|
||||
|
||||
Here's __a strong one that uses underscores__.
|
||||
|
||||
This is not _ one _ neither is * this * neither is _ this_ neither is _this _.
|
||||
|
||||
An empty emphasis ** is not __ an emphasis.
|
||||
an empty emphasis __ ** is not an emphasis
|
@ -1,2 +1,4 @@
|
||||
<p>Here's an <em>emphasis</em> and here's an escaped *emphasis*. Here are also an escaped `code span`, an escaped [inline link](http://example.com) and an escaped <code>\*emphasis\*</code> inside of a code span.</p>
|
||||
<pre><code>An escaped \*emphasis\* inside of a code block.</code></pre>
|
||||
<p>escaped *emphasis*.</p>
|
||||
<p><code>escaped \*emphasis\* in a code span</code></p>
|
||||
<pre><code>escaped \*emphasis\* in a code block</code></pre>
|
||||
<p>\ ` * _ { } [ ] ( ) > # + - . !</p>
|
@ -1,3 +1,7 @@
|
||||
Here's an *emphasis* and here's an escaped \*emphasis\*. Here are also an escaped \`code span\`, an escaped \[inline link](http://example.com) and an escaped `\*emphasis\*` inside of a code span.
|
||||
escaped \*emphasis\*.
|
||||
|
||||
An escaped \*emphasis\* inside of a code block.
|
||||
`escaped \*emphasis\* in a code span`
|
||||
|
||||
escaped \*emphasis\* in a code block
|
||||
|
||||
\\ \` \* \_ \{ \} \[ \] \( \) \> \# \+ \- \. \!
|
5
tests/data/fenced_code_block.html
Normal file
5
tests/data/fenced_code_block.html
Normal file
@ -0,0 +1,5 @@
|
||||
<pre><code><?php
|
||||
|
||||
$message = 'fenced code block';
|
||||
echo $message;</code></pre>
|
||||
<pre><code>tilde</code></pre>
|
10
tests/data/fenced_code_block.md
Normal file
10
tests/data/fenced_code_block.md
Normal file
@ -0,0 +1,10 @@
|
||||
```
|
||||
<?php
|
||||
|
||||
$message = 'fenced code block';
|
||||
echo $message;
|
||||
```
|
||||
|
||||
~~~
|
||||
tilde
|
||||
~~~
|
@ -1,10 +1,5 @@
|
||||
<p>Dashes:</p>
|
||||
<hr />
|
||||
<hr />
|
||||
<hr />
|
||||
<p>Asterisks:</p>
|
||||
<hr />
|
||||
<p>Underscores:</p>
|
||||
<hr />
|
||||
<p>On the next line:</p>
|
||||
<hr />
|
@ -1,18 +1,9 @@
|
||||
Dashes:
|
||||
|
||||
---
|
||||
|
||||
- - -
|
||||
|
||||
- - -
|
||||
|
||||
Asterisks:
|
||||
|
||||
***
|
||||
|
||||
Underscores:
|
||||
|
||||
___
|
||||
|
||||
On the next line:
|
||||
___
|
@ -1,15 +0,0 @@
|
||||
<p>A self-closing tag:</p>
|
||||
<hr/>
|
||||
<p>One with attributes:</p>
|
||||
<hr style="background: #eaa" />
|
||||
<p>A bare element:</p>
|
||||
<div>content</div>
|
||||
<p>One with attributes:</p>
|
||||
<a href="http://example.com">link</a>
|
||||
<p>Nested elements:</p>
|
||||
<div>
|
||||
parent
|
||||
<div>
|
||||
child
|
||||
</div>
|
||||
</div>
|
@ -1,24 +0,0 @@
|
||||
A self-closing tag:
|
||||
|
||||
<hr/>
|
||||
|
||||
One with attributes:
|
||||
|
||||
<hr style="background: #eaa" />
|
||||
|
||||
A bare element:
|
||||
|
||||
<div>content</div>
|
||||
|
||||
One with attributes:
|
||||
|
||||
<a href="http://example.com">link</a>
|
||||
|
||||
Nested elements:
|
||||
|
||||
<div>
|
||||
parent
|
||||
<div>
|
||||
child
|
||||
</div>
|
||||
</div>
|
1
tests/data/image_reference.html
Normal file
1
tests/data/image_reference.html
Normal file
@ -0,0 +1 @@
|
||||
<p><img alt="Markdown Logo" src="/md.png"></p>
|
3
tests/data/image_reference.md
Normal file
3
tests/data/image_reference.md
Normal file
@ -0,0 +1,3 @@
|
||||
![Markdown Logo][image]
|
||||
|
||||
[image]: /md.png
|
2
tests/data/implicit_reference.html
Normal file
2
tests/data/implicit_reference.html
Normal file
@ -0,0 +1,2 @@
|
||||
<p>an <a href="http://example.com">implicit</a> reference link</p>
|
||||
<p>an <a href="http://example.com">implicit</a> reference link with an empty link definition</p>
|
5
tests/data/implicit_reference.md
Normal file
5
tests/data/implicit_reference.md
Normal file
@ -0,0 +1,5 @@
|
||||
an [implicit] reference link
|
||||
|
||||
[implicit]: http://example.com
|
||||
|
||||
an [implicit][] reference link with an empty link definition
|
@ -1,2 +1,2 @@
|
||||
<p>Here's a <a href="http://example.com">link</a>.</p>
|
||||
<p>Here's one that is based on an image: <a href="http://daringfireball.net/projects/markdown/"><img alt="MD Logo" src="http://parsedown.org/md.png"></a>.</p>
|
||||
<p><a href="http://example.com">link</a></p>
|
||||
<p><a href="http://example.com"><img alt="MD Logo" src="http://parsedown.org/md.png"></a></p>
|
@ -1,3 +1,3 @@
|
||||
Here's a [link](http://example.com).
|
||||
[link](http://example.com)
|
||||
|
||||
Here's one that is based on an image: [](http://daringfireball.net/projects/markdown/).
|
||||
[](http://example.com)
|
4
tests/data/lazy_blockquote.html
Normal file
4
tests/data/lazy_blockquote.html
Normal file
@ -0,0 +1,4 @@
|
||||
<blockquote>
|
||||
<p>quote
|
||||
the rest of it</p>
|
||||
</blockquote>
|
2
tests/data/lazy_blockquote.md
Normal file
2
tests/data/lazy_blockquote.md
Normal file
@ -0,0 +1,2 @@
|
||||
> quote
|
||||
the rest of it
|
4
tests/data/lazy_list.html
Normal file
4
tests/data/lazy_list.html
Normal file
@ -0,0 +1,4 @@
|
||||
<ul>
|
||||
<li>li
|
||||
the rest of it</li>
|
||||
</ul>
|
2
tests/data/lazy_list.md
Normal file
2
tests/data/lazy_list.md
Normal file
@ -0,0 +1,2 @@
|
||||
- li
|
||||
the rest of it
|
@ -1,5 +0,0 @@
|
||||
<p>Here's a list:</p>
|
||||
<ul>
|
||||
<li>li</li>
|
||||
<li>li</li>
|
||||
</ul>
|
@ -1,4 +0,0 @@
|
||||
Here's a list:
|
||||
|
||||
- li
|
||||
- li
|
@ -1,13 +0,0 @@
|
||||
<p>Here's a compound list:</p>
|
||||
<ul>
|
||||
<li>
|
||||
<p>This is the first paragraph of the list item.</p>
|
||||
<p>This is the second one.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>This is another list item.</p>
|
||||
<blockquote>
|
||||
<p>This is a quote block that belongs to it.</p>
|
||||
</blockquote>
|
||||
</li>
|
||||
</ul>
|
@ -1,9 +0,0 @@
|
||||
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.
|
@ -1,4 +0,0 @@
|
||||
<ul>
|
||||
<li>li
|
||||
more text</li>
|
||||
</ul>
|
@ -1,2 +0,0 @@
|
||||
- li
|
||||
more text
|
@ -1,14 +0,0 @@
|
||||
<p>Here's a regular ordered list:</p>
|
||||
<ol>
|
||||
<li>one</li>
|
||||
<li>two</li>
|
||||
</ol>
|
||||
<p>Here's one with repeating numbers:</p>
|
||||
<ol>
|
||||
<li>one</li>
|
||||
<li>two</li>
|
||||
</ol>
|
||||
<p>Here's one with large numbers:</p>
|
||||
<ol>
|
||||
<li>one</li>
|
||||
</ol>
|
@ -1,13 +0,0 @@
|
||||
Here's a regular ordered list:
|
||||
|
||||
1. one
|
||||
2. two
|
||||
|
||||
Here's one with repeating numbers:
|
||||
|
||||
1. one
|
||||
1. two
|
||||
|
||||
Here's one with large numbers:
|
||||
|
||||
123. one
|
@ -1,16 +0,0 @@
|
||||
<p>Here's a sparse list:</p>
|
||||
<ul>
|
||||
<li>
|
||||
<p>list item</p>
|
||||
</li>
|
||||
<li>another list item</li>
|
||||
</ul>
|
||||
<p>Here's one with an indented list item:</p>
|
||||
<ul>
|
||||
<li>
|
||||
<p>li</p>
|
||||
<ul>
|
||||
<li>li</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
@ -1,11 +0,0 @@
|
||||
Here's a sparse list:
|
||||
|
||||
- list item
|
||||
|
||||
- another list item
|
||||
|
||||
Here's one with an indented list item:
|
||||
|
||||
- li
|
||||
|
||||
- li
|
@ -1,10 +0,0 @@
|
||||
Here's an unordered list:
|
||||
|
||||
- li
|
||||
- li
|
||||
|
||||
Here's one with mixed markers:
|
||||
|
||||
- li
|
||||
+ li
|
||||
* li
|
@ -1,5 +0,0 @@
|
||||
<p>Here's one with white space around items:</p>
|
||||
<ul>
|
||||
<li>li </li>
|
||||
<li>li </li>
|
||||
</ul>
|
@ -1,4 +0,0 @@
|
||||
Here's one with white space around items:
|
||||
|
||||
- li
|
||||
- li
|
13
tests/data/ordered_list.html
Normal file
13
tests/data/ordered_list.html
Normal file
@ -0,0 +1,13 @@
|
||||
<ol>
|
||||
<li>one</li>
|
||||
<li>two</li>
|
||||
</ol>
|
||||
<p>repeating numbers:</p>
|
||||
<ol>
|
||||
<li>one</li>
|
||||
<li>two</li>
|
||||
</ol>
|
||||
<p>large numbers:</p>
|
||||
<ol>
|
||||
<li>one</li>
|
||||
</ol>
|
11
tests/data/ordered_list.md
Normal file
11
tests/data/ordered_list.md
Normal file
@ -0,0 +1,11 @@
|
||||
1. one
|
||||
2. two
|
||||
|
||||
repeating numbers:
|
||||
|
||||
1. one
|
||||
1. two
|
||||
|
||||
large numbers:
|
||||
|
||||
123. one
|
@ -1,7 +0,0 @@
|
||||
<p>Here's a <a href="http://example.com">reference link</a>.</p>
|
||||
<p>Here's <a href="http://example.com">one</a> with a semantic name.</p>
|
||||
<p>Here's <a href="http://example.com">one</a> with an upper case label definition.</p>
|
||||
<p>Here's <a href="http://example.com">one</a> with definition name on the next line.</p>
|
||||
<p>Here's [one][404] with no definition.</p>
|
||||
<p>Here's a <a href="http://example.com">multiline
|
||||
one</a> defined on 2 lines.</p>
|
@ -1,19 +0,0 @@
|
||||
Here's a [reference link][1].
|
||||
|
||||
[1]: http://example.com
|
||||
|
||||
Here's [one][website] with a semantic name.
|
||||
|
||||
[website]: http://example.com
|
||||
|
||||
Here's [one][case] with an upper case label definition.
|
||||
|
||||
[CASE]: http://example.com
|
||||
|
||||
Here's [one]
|
||||
[website] with definition name on the next line.
|
||||
|
||||
Here's [one][404] with no definition.
|
||||
|
||||
Here's a [multiline
|
||||
one][website] defined on 2 lines.
|
@ -1 +0,0 @@
|
||||
<p>Here's an image: <img alt="Markdown Logo" src="/md.png"></p>
|
@ -1,3 +0,0 @@
|
||||
Here's an image: ![Markdown Logo][image]
|
||||
|
||||
[image]: /md.png
|
@ -1,2 +0,0 @@
|
||||
<p>Here's an <a href="http://example.com">implicit</a> reference link.</p>
|
||||
<p>Here's an <a href="http://example.com">implicit</a> one with an empty link definition.</p>
|
@ -1,5 +0,0 @@
|
||||
Here's an [implicit] reference link.
|
||||
|
||||
[implicit]: http://example.com
|
||||
|
||||
Here's an [implicit][] one with an empty link definition.
|
@ -1 +0,0 @@
|
||||
<p>Here's a <a href="http://example.com">reference link</a> with a definition on the next line.</p>
|
@ -1,2 +0,0 @@
|
||||
Here's a [reference link][2] with a definition on the next line.
|
||||
[2]: http://example.com
|
11
tests/data/simple_blockquote.html
Normal file
11
tests/data/simple_blockquote.html
Normal file
@ -0,0 +1,11 @@
|
||||
<blockquote>
|
||||
<p>quote</p>
|
||||
</blockquote>
|
||||
<p>indented:</p>
|
||||
<blockquote>
|
||||
<p>quote</p>
|
||||
</blockquote>
|
||||
<p>no space after <code>></code>:</p>
|
||||
<blockquote>
|
||||
<p>quote</p>
|
||||
</blockquote>
|
7
tests/data/simple_blockquote.md
Normal file
7
tests/data/simple_blockquote.md
Normal file
@ -0,0 +1,7 @@
|
||||
> quote
|
||||
|
||||
indented:
|
||||
> quote
|
||||
|
||||
no space after `>`:
|
||||
>quote
|
3
tests/data/span-level_html.html
Normal file
3
tests/data/span-level_html.html
Normal file
@ -0,0 +1,3 @@
|
||||
<p>an <b>important</b> <a href=''>link</a></p>
|
||||
<p>broken<br/>
|
||||
line</p>
|
4
tests/data/span-level_html.md
Normal file
4
tests/data/span-level_html.md
Normal file
@ -0,0 +1,4 @@
|
||||
an <b>important</b> <a href=''>link</a>
|
||||
|
||||
broken<br/>
|
||||
line
|
@ -1 +0,0 @@
|
||||
<p>Here's an <b>important</b> <a href=''>link</a>.</p>
|
@ -1 +0,0 @@
|
||||
Here's an <b>important</b> <a href=''>link</a>.
|
15
tests/data/sparse_list.html
Normal file
15
tests/data/sparse_list.html
Normal file
@ -0,0 +1,15 @@
|
||||
<ul>
|
||||
<li>
|
||||
<p>li</p>
|
||||
</li>
|
||||
<li>li</li>
|
||||
</ul>
|
||||
<hr />
|
||||
<ul>
|
||||
<li>
|
||||
<p>li</p>
|
||||
<ul>
|
||||
<li>indented li</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
9
tests/data/sparse_list.md
Normal file
9
tests/data/sparse_list.md
Normal file
@ -0,0 +1,9 @@
|
||||
- li
|
||||
|
||||
- li
|
||||
|
||||
---
|
||||
|
||||
- li
|
||||
|
||||
- indented li
|
@ -1,7 +1,8 @@
|
||||
<p>AT&T has an ampersand in their name.</p>
|
||||
<p>AT&T is another way to write it.</p>
|
||||
<p>This & that.</p>
|
||||
<p>4 < 5 and 6 > 5.</p>
|
||||
<p>Here's an autolink <a href="http://example.com/autolink?a=1&b=2">http://example.com/autolink?a=1&b=2</a></p>
|
||||
<p>Here's an inline <a href="/script?a=1&b=2">link</a>.</p>
|
||||
<p>Here's a reference <a href="http://example.com/?a=1&b=2">link</a> with an ampersand in the URL.</p>
|
||||
<p>AT&T has an ampersand in their name</p>
|
||||
<pre><code>Let's play some cards ♠ ♣ ♥ ♦</code></pre>
|
||||
<p>AT&T is another way to write it</p>
|
||||
<p>this & that</p>
|
||||
<p>4 < 5 and 6 > 5</p>
|
||||
<p><a href="http://example.com/autolink?a=1&b=2">http://example.com/autolink?a=1&b=2</a> </p>
|
||||
<p><a href="/script?a=1&b=2">inline link</a></p>
|
||||
<p><a href="http://example.com/?a=1&b=2">reference link</a></p>
|
@ -1,15 +1,17 @@
|
||||
AT&T has an ampersand in their name.
|
||||
AT&T has an ampersand in their name
|
||||
|
||||
AT&T is another way to write it.
|
||||
Let's play some cards ♠ ♣ ♥ ♦
|
||||
|
||||
This & that.
|
||||
AT&T is another way to write it
|
||||
|
||||
4 < 5 and 6 > 5.
|
||||
this & that
|
||||
|
||||
Here's an autolink <http://example.com/autolink?a=1&b=2>
|
||||
4 < 5 and 6 > 5
|
||||
|
||||
Here's an inline [link](/script?a=1&b=2).
|
||||
<http://example.com/autolink?a=1&b=2>
|
||||
|
||||
Here's a reference [link] [1] with an ampersand in the URL.
|
||||
[inline link](/script?a=1&b=2)
|
||||
|
||||
[reference link][1]
|
||||
|
||||
[1]: http://example.com/?a=1&b=2
|
3
tests/data/strikethrough.html
Normal file
3
tests/data/strikethrough.html
Normal 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>
|
5
tests/data/strikethrough.md
Normal file
5
tests/data/strikethrough.md
Normal file
@ -0,0 +1,5 @@
|
||||
~~strikethrough~~
|
||||
|
||||
in the ~~middle~~ of a sentence
|
||||
|
||||
in the middle of a w~~or~~d
|
6
tests/data/text_reference.html
Normal file
6
tests/data/text_reference.html
Normal file
@ -0,0 +1,6 @@
|
||||
<p><a href="http://example.com">reference link</a></p>
|
||||
<p><a href="http://example.com">one</a> with a semantic name</p>
|
||||
<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>
|
16
tests/data/text_reference.md
Normal file
16
tests/data/text_reference.md
Normal file
@ -0,0 +1,16 @@
|
||||
[reference link][1]
|
||||
|
||||
[1]: http://example.com
|
||||
|
||||
[one][website] with a semantic name
|
||||
|
||||
[website]: http://example.com
|
||||
|
||||
[one][404] with no definition
|
||||
|
||||
[multiline
|
||||
one][website] defined on 2 lines
|
||||
|
||||
[one][label] with an upper case label
|
||||
|
||||
[LABEL]: http://example.com
|
@ -1,9 +1,8 @@
|
||||
<p>Here's an unordered list:</p>
|
||||
<ul>
|
||||
<li>li</li>
|
||||
<li>li</li>
|
||||
</ul>
|
||||
<p>Here's one with mixed markers:</p>
|
||||
<p>mixed markers:</p>
|
||||
<ul>
|
||||
<li>li</li>
|
||||
<li>li</li>
|
8
tests/data/unordered_list.md
Normal file
8
tests/data/unordered_list.md
Normal file
@ -0,0 +1,8 @@
|
||||
- li
|
||||
- li
|
||||
|
||||
mixed markers:
|
||||
|
||||
* li
|
||||
+ li
|
||||
- li
|
1
tests/data/url_autolinking.html
Normal file
1
tests/data/url_autolinking.html
Normal file
@ -0,0 +1 @@
|
||||
<p>Here's an autolink <a href="http://example.com">http://example.com</a>.</p>
|
1
tests/data/url_autolinking.md
Normal file
1
tests/data/url_autolinking.md
Normal file
@ -0,0 +1 @@
|
||||
Here's an autolink http://example.com.
|
@ -1 +1 @@
|
||||
<pre><code>This text starts with a line that consists of 4 spaces and it ends with one. This is a code block to make sure that leading spaces don't get trimmed.</code></pre>
|
||||
<pre><code>code</code></pre>
|
@ -1,5 +1,5 @@
|
||||
|
||||
|
||||
This text starts with a line that consists of 4 spaces and it ends with one. This is a code block to make sure that leading spaces don't get trimmed.
|
||||
code
|
||||
|
||||
|
Reference in New Issue
Block a user