--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+module markdown2
+
+import markdown_block_parsing
+import markdown_html_rendering
+
+redef class String
+ fun md_to_html2: String do
+ var parser = new MdParser
+ var doc = parser.parse(self)
+ var renderer = new HtmlRenderer
+ return renderer.render(doc)
+ end
+end
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# HTML rendering of Markdown documents
+module markdown_html_rendering
+
+import markdown_rendering
+
+# Markdown document renderer to HTML
+class HtmlRenderer
+ super MdRenderer
+
+ # HTML output under construction
+ private var html: Buffer is noinit
+
+ # Render `document` as HTML
+ redef fun render(document) do
+ reset
+ enter_visit(document)
+ return html.write_to_string
+ end
+
+ redef fun visit(node) do node.render_html(self)
+
+ # Reset `headings` and internal state
+ fun reset do
+ html = new Buffer
+ if enable_heading_ids then headings.clear
+ end
+
+ # Last char visited
+ #
+ # Used to avoid double blank lines.
+ private var last_char: nullable Char = null
+
+ # Add `string` to `html`
+ private fun add(string: String) do
+ html.append(string)
+ if not html.is_empty then
+ last_char = html.last
+ end
+ end
+
+ # Add a raw `html` string to the output
+ #
+ # Raw means that the string will not be escaped.
+ fun add_raw(html: String) do add html
+
+ # Add `text` string to the output
+ #
+ # The string will be escaped.
+ fun add_text(text: String) do add html_escape(text, true)
+
+ # Add a blank line to the output
+ fun add_line do
+ if last_char != null and last_char != '\n' then
+ add "\n"
+ end
+ end
+
+ # Escape `string` to HTML
+ #
+ # When `keep_entities`, HTML entities will not be escaped.
+ fun html_escape(string: String, keep_entities: Bool): String do
+ var buf: nullable Buffer = null
+ for i in [0..string.length[ do
+ var c = string.chars[i]
+ var sub = null
+ if c == '&' and (not keep_entities or string.search_from(re_entity, i) == null) then
+ sub = "&"
+ else if c == '<' then
+ sub = "<"
+ else if c == '>' then
+ sub = ">"
+ else if c == '"' then
+ sub = """
+ else
+ if buf != null then buf.add c
+ continue
+ end
+ if buf == null then
+ buf = new Buffer
+ for j in [0..i[ do buf.add string.chars[j]
+ end
+ buf.append sub
+ end
+
+ if buf == null then return string
+ return buf.to_s
+ end
+
+ # HTML entity pattern
+ private var re_entity: Regex = "^&(#x[a-f0-9]\{1,8\}|#[0-9]\{1,8\}|[a-z][a-z0-9]\{1,31\});".to_re
+
+ # Encode the `uri` string
+ fun encode_uri(uri: String): String do
+ var buf = new Buffer
+
+ var i = 0
+ while i < uri.length do
+ var c = uri.chars[i]
+ if (c >= '0' and c <= '9') or
+ (c >= 'a' and c <= 'z') or
+ (c >= 'A' and c <= 'Z') or
+ c == ';' or c == ',' or c == '/' or c == '?' or
+ c == ':' or c == '@' or c == '=' or c == '+' or
+ c == '$' or c == '-' or c == '_' or c == '.' or
+ c == '!' or c == '~' or c == '*' or c == '(' or
+ c == ')' or c == '#' or c == '\''
+ then
+ buf.add c
+ else if c == '&' then
+ buf.append "&"
+ else if c == '%' and uri.search_from(re_uri_code, i) != null then
+ buf.append uri.substring(i, 3)
+ i += 2
+ else
+ var bytes = c.to_s.bytes
+ for b in bytes do buf.append "%{b.to_i.to_hex}".to_upper
+ end
+ i += 1
+ end
+
+ return buf.to_s
+ end
+
+ # URI encode pattern
+ private var re_uri_code: Regex = "^%[a-zA-Z0-9]\{2\}".to_re
+
+ # Add `id` tags to headings
+ var enable_heading_ids = false is optional, writable
+
+ # Associate headings ids to blocks
+ var headings = new ArrayMap[String, MdHeading]
+
+ # Strip heading id
+ fun strip_id(text: String): String do
+ # strip id
+ var b = new FlatBuffer
+ for c in text do
+ if c == ' ' then
+ b.add '_'
+ else
+ if not c.is_letter and
+ not c.is_digit and
+ not allowed_id_chars.has(c) then continue
+ b.add c
+ end
+ end
+ var res = b.to_s
+ if res.is_empty then res = "_"
+ var key = res
+ # check for multiple id definitions
+ if headings.has_key(key) then
+ var i = 1
+ key = "{res}_{i}"
+ while headings.has_key(key) do
+ i += 1
+ key = "{res}_{i}"
+ end
+ end
+ return key
+ end
+
+ # Allowed characters in ids
+ var allowed_id_chars: Array[Char] = ['-', '_', ':', '.']
+end
+
+redef class MdNode
+
+ # Render `self` as HTML
+ fun render_html(v: HtmlRenderer) do visit_all(v)
+end
+
+# Blocks
+
+redef class MdBlockQuote
+ redef fun render_html(v) do
+ v.add_line
+ v.add_raw "<blockquote>"
+ v.add_line
+ visit_all(v)
+ v.add_line
+ v.add_raw "</blockquote>"
+ v.add_line
+ end
+end
+
+redef class MdCodeBlock
+ redef fun render_html(v) do
+ var info = self.info
+ v.add_line
+ v.add_raw "<pre>"
+ v.add_raw "<code"
+ if info != null and not info.is_empty then
+ v.add_raw " class=\"language-{info.split(" ").first}\""
+ end
+ v.add_raw ">"
+ var literal = self.literal or else ""
+ var lines = literal.split("\n")
+ for i in [0..lines.length[ do
+ var line = lines[i]
+ v.add_raw v.html_escape(line, false)
+ if i < lines.length - 1 then
+ v.add_raw "\n"
+ end
+ end
+ v.add_raw "</code>"
+ v.add_raw "</pre>"
+ v.add_line
+ end
+end
+
+redef class MdHeading
+ redef fun render_html(v) do
+ v.add_line
+ if v.enable_heading_ids then
+ var id = self.id
+ if id == null then
+ id = v.strip_id(title)
+ v.headings[id] = self
+ self.id = id
+ end
+ v.add_raw "<h{level} id=\"{id}\">"
+ else
+ v.add_raw "<h{level}>"
+ end
+ visit_all(v)
+ v.add_raw "</h{level}>"
+ v.add_line
+ end
+
+ #
+ var id: nullable String = null
+
+ #
+ fun title: String do
+ var v = new RawTextVisitor
+ return v.render(self)
+ end
+end
+
+redef class MdUnorderedList
+ redef fun render_html(v) do
+ v.add_line
+ v.add_raw "<ul>"
+ v.add_line
+ visit_all(v)
+ v.add_line
+ v.add_raw "</ul>"
+ v.add_line
+ end
+end
+
+redef class MdOrderedList
+ redef fun render_html(v) do
+ var start = self.start_number
+ v.add_line
+ v.add_raw "<ol"
+ if start != 1 then
+ v.add_raw " start=\"{start}\""
+ end
+ v.add_raw ">"
+ v.add_line
+ visit_all(v)
+ v.add_line
+ v.add_raw "</ol>"
+ v.add_line
+ end
+end
+
+redef class MdListItem
+ redef fun render_html(v) do
+ v.add_raw "<li>"
+ visit_all(v)
+ v.add_raw "</li>"
+ v.add_line
+ end
+end
+
+redef class MdParagraph
+ redef fun render_html(v) do
+ var is_tight = is_in_tight_list
+ if not is_tight then
+ v.add_line
+ v.add_raw "<p>"
+ end
+ visit_all(v)
+ if not is_tight then
+ v.add_raw "</p>"
+ v.add_line
+ end
+ end
+end
+
+redef class MdThematicBreak
+ redef fun render_html(v) do
+ v.add_line
+ v.add_raw "<hr />"
+ v.add_line
+ end
+end
+
+redef class MdHtmlBlock
+ redef fun render_html(v) do
+ v.add_line
+ var literal = self.literal or else ""
+ var lines = literal.split("\n")
+ for i in [0..lines.length[ do
+ var line = lines[i]
+ if not line.trim.is_empty then
+ v.add_raw line
+ end
+ if i < lines.length - 1 then
+ v.add_raw "\n"
+ end
+ end
+ v.add_line
+ end
+end
+
+# Inlines
+
+redef class MdHardLineBreak
+ redef fun render_html(v) do
+ v.add_raw "<br />"
+ v.add_line
+ end
+end
+
+redef class MdSoftLineBreak
+ redef fun render_html(v) do
+ v.add_raw "\n"
+ end
+end
+
+redef class MdCode
+ redef fun render_html(v) do
+ v.add_raw "<code>"
+ v.add_raw v.html_escape(literal, false)
+ v.add_raw "</code>"
+ end
+end
+
+redef class MdEmphasis
+ redef fun render_html(v) do
+ v.add_raw "<em>"
+ visit_all(v)
+ v.add_raw "</em>"
+ end
+end
+
+redef class MdStrongEmphasis
+ redef fun render_html(v) do
+ v.add_raw "<strong>"
+ visit_all(v)
+ v.add_raw "</strong>"
+ end
+end
+
+redef class MdHtmlInline
+ redef fun render_html(v) do
+ v.add_raw literal
+ end
+end
+
+redef class MdImage
+ redef fun render_html(v) do
+ var url = self.destination
+ var title = self.title
+ v.add_raw "<img"
+ v.add_raw " src=\"{v.encode_uri(url)}\""
+
+ var alt_text = self.alt_text
+ v.add_raw " alt=\"{alt_text}\""
+
+ if title != null and not title.is_empty then
+ v.add_raw " title=\""
+ v.add_text title
+ v.add_raw "\""
+ end
+
+ v.add_raw " />"
+ end
+
+ private fun alt_text: String do
+ var v = new RawTextVisitor
+ return v.render(self)
+ end
+end
+
+redef class MdLink
+ redef fun render_html(v) do
+ var url = self.destination
+ var title = self.title
+ v.add_raw "<a"
+ v.add_raw " href=\"{v.encode_uri(url)}\""
+ if title != null and not title.is_empty then
+ v.add_raw " title=\""
+ v.add_text title
+ v.add_raw "\""
+ end
+ v.add_raw ">"
+ visit_all(v)
+ v.add_raw "</a>"
+ end
+end
+
+redef class MdText
+ redef fun render_html(v) do
+ v.add_text literal
+ end
+end
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either htmlress or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Test for markdown blocks parsing
+module test_markdown_blocks is test
+
+import test_markdown
+
+class TestMarkdownBlocks
+ super TestMarkdownHtml
+ test
+
+ fun test_blocks_empty is test do
+ var md = ""
+ var html = ""
+ assert md_to_html(md) == html
+ end
+
+ fun test_blocks_tabs is test do
+ var md = """\tsome code\n"""
+ var html = """<pre><code>some code\n</code></pre>\n"""
+ assert md_to_html(md) == html
+ end
+
+ fun test_blocks_pagraph1 is test do
+ var md = "test\n"
+ var html = "<p>test</p>\n"
+ assert md_to_html(md) == html
+ end
+
+ fun test_blocks_pagraph2 is test do
+ var md = """line1\nline2\n\nline3 line4\n\nline5\n"""
+ var html = """<p>line1\nline2</p>\n<p>line3 line4</p>\n<p>line5</p>\n"""
+ assert md_to_html(md) == html
+ end
+
+ fun test_blocks_pagraph3 is test do
+ var md = """
+Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
+Aliquam hendrerit mi posuere lectus.
+Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus.
+
+Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse
+id sem consectetuer libero luctus adipiscing.
+"""
+ var html = """
+<p>Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
+Aliquam hendrerit mi posuere lectus.
+Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus.</p>
+<p>Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse
+id sem consectetuer libero luctus adipiscing.</p>
+"""
+ assert md_to_html(md) == html
+ end
+
+ fun test_blocks_headings_1 is test do
+ var md = """
+This is a H1
+=============
+
+This is a H2
+-------------
+"""
+ var html = """
+<h1>This is a H1</h1>
+<h2>This is a H2</h2>
+"""
+ assert md_to_html(md) == html
+ end
+
+ fun test_blocks_headings_2 is test do
+ var md = """
+# This is a H1
+
+## This is a H2
+###### This is a H6
+"""
+ var html = """
+<h1>This is a H1</h1>
+<h2>This is a H2</h2>
+<h6>This is a H6</h6>
+"""
+ assert md_to_html(md) == html
+ end
+
+ fun test_blocks_headings_3 is test do
+ var md = """
+# This is a H1 #
+
+## This is a H2 ##
+
+### This is a H3 ######
+"""
+ var html = """
+<h1>This is a H1</h1>
+<h2>This is a H2</h2>
+<h3>This is a H3</h3>
+"""
+ assert md_to_html(md) == html
+ end
+
+ fun test_blocks_hr1 is test do
+ var md = """
+* * *
+
+***
+
+*****
+
+- - -
+
+---------------------------------------
+"""
+ var html = "<hr />\n<hr />\n<hr />\n<hr />\n<hr />\n"
+ assert md_to_html(md) == html
+ end
+
+ fun test_blocks_bquote1 is test do
+ var md = """
+> This is a blockquote with two paragraphs. Lorem ipsum dolor sit amet,
+> consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus.
+> Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus.
+>
+> Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse
+> id sem consectetuer libero luctus adipiscing.
+"""
+ var html = """<blockquote>
+<p>This is a blockquote with two paragraphs. Lorem ipsum dolor sit amet,
+consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus.
+Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus.</p>
+<p>Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse
+id sem consectetuer libero luctus adipiscing.</p>
+</blockquote>
+"""
+ assert md_to_html(md) == html
+ end
+
+ fun test_blocks_bquote2 is test do
+ var md = """
+> This is a blockquote with two paragraphs. Lorem ipsum dolor sit amet,
+consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus.
+Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus.
+
+> Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse
+id sem consectetuer libero luctus adipiscing.
+"""
+ var html = """<blockquote>
+<p>This is a blockquote with two paragraphs. Lorem ipsum dolor sit amet,
+consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus.
+Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus.</p>
+</blockquote>
+<blockquote>
+<p>Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse
+id sem consectetuer libero luctus adipiscing.</p>
+</blockquote>
+"""
+ assert md_to_html(md) == html
+ end
+
+ fun test_blocks_bquote3 is test do
+ var md = """
+> This is the first level of quoting.
+>
+> > This is nested blockquote.
+>
+> Back to the first level.
+"""
+ var html = """<blockquote>
+<p>This is the first level of quoting.</p>
+<blockquote>
+<p>This is nested blockquote.</p>
+</blockquote>
+<p>Back to the first level.</p>
+</blockquote>
+"""
+ assert md_to_html(md) == html
+ end
+
+ fun test_blocks_list1 is test do
+ var md = """
+* Red
+* Green
+* Blue
+"""
+ var html = """<ul>
+<li>Red</li>
+<li>Green</li>
+<li>Blue</li>
+</ul>
+"""
+ assert md_to_html(md) == html
+ end
+
+ fun test_blocks_list2 is test do
+ var md = """
++ Red
++ Green
++ Blue
+"""
+ var html = """<ul>
+<li>Red</li>
+<li>Green</li>
+<li>Blue</li>
+</ul>
+"""
+ assert md_to_html(md) == html
+ end
+
+ fun test_blocks_list3 is test do
+ var md = """
+- Red
+- Green
+- Blue
+"""
+ var html = """<ul>
+<li>Red</li>
+<li>Green</li>
+<li>Blue</li>
+</ul>
+"""
+ assert md_to_html(md) == html
+ end
+
+ fun test_blocks_list4 is test do
+ var md = """
+1. Bird
+2. McHale
+3. Parish
+"""
+ var html = """<ol>
+<li>Bird</li>
+<li>McHale</li>
+<li>Parish</li>
+</ol>
+"""
+ assert md_to_html(md) == html
+ end
+
+ fun test_blocks_list5 is test do
+ var md = """
+3. Bird
+1. McHale
+8. Parish
+"""
+ var html = """<ol start=\"3\">
+<li>Bird</li>
+<li>McHale</li>
+<li>Parish</li>
+</ol>
+"""
+ assert md_to_html(md) == html
+ end
+
+ fun test_blocks_list6 is test do
+ var md = """
+* Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
+ Aliquam hendrerit mi posuere lectus. Vestibulum enim wisi,
+ viverra nec, fringilla in, laoreet vitae, risus.
+* Donec sit amet nisl. Aliquam semper ipsum sit amet velit.
+ Suspendisse id sem consectetuer libero luctus adipiscing.
+"""
+ var html = """
+<ul>
+<li>Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
+Aliquam hendrerit mi posuere lectus. Vestibulum enim wisi,
+viverra nec, fringilla in, laoreet vitae, risus.</li>
+<li>Donec sit amet nisl. Aliquam semper ipsum sit amet velit.
+Suspendisse id sem consectetuer libero luctus adipiscing.</li>
+</ul>
+"""
+ assert md_to_html(md) == html
+ end
+
+ fun test_blocks_list7 is test do
+ var md = """
+* Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
+Aliquam hendrerit mi posuere lectus. Vestibulum enim wisi,
+viverra nec, fringilla in, laoreet vitae, risus.
+* Donec sit amet nisl. Aliquam semper ipsum sit amet velit.
+Suspendisse id sem consectetuer libero luctus adipiscing.
+"""
+ var html = """
+<ul>
+<li>Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
+Aliquam hendrerit mi posuere lectus. Vestibulum enim wisi,
+viverra nec, fringilla in, laoreet vitae, risus.</li>
+<li>Donec sit amet nisl. Aliquam semper ipsum sit amet velit.
+Suspendisse id sem consectetuer libero luctus adipiscing.</li>
+</ul>
+"""
+ assert md_to_html(md) == html
+ end
+
+ fun test_blocks_list8 is test do
+ var md = """
+* Bird
+
+* Magic
+"""
+ var html = """
+<ul>
+<li>
+<p>Bird</p>
+</li>
+<li>
+<p>Magic</p>
+</li>
+</ul>
+"""
+ assert md_to_html(md) == html
+ end
+
+ fun test_blocks_list9 is test do
+ var md = """
+1. This is a list item with two paragraphs. Lorem ipsum dolor
+ sit amet, consectetuer adipiscing elit. Aliquam hendrerit
+ mi posuere lectus.
+
+ Vestibulum enim wisi, viverra nec, fringilla in, laoreet
+ vitae, risus. Donec sit amet nisl. Aliquam semper ipsum
+ sit amet velit.
+
+2. Suspendisse id sem consectetuer libero luctus adipiscing.
+"""
+ var html = """
+<ol>
+<li>
+<p>This is a list item with two paragraphs. Lorem ipsum dolor
+sit amet, consectetuer adipiscing elit. Aliquam hendrerit
+mi posuere lectus.</p>
+<p>Vestibulum enim wisi, viverra nec, fringilla in, laoreet
+vitae, risus. Donec sit amet nisl. Aliquam semper ipsum
+sit amet velit.</p>
+</li>
+<li>
+<p>Suspendisse id sem consectetuer libero luctus adipiscing.</p>
+</li>
+</ol>
+"""
+ assert md_to_html(md) == html
+ end
+
+ fun test_blocks_list10 is test do
+ var md = """
+* This is a list item with two paragraphs.
+
+ This is the second paragraph in the list item. You're
+only required to indent the first line. Lorem ipsum dolor
+sit amet, consectetuer adipiscing elit.
+
+* Another item in the same list.
+"""
+ var html = """
+<ul>
+<li>
+<p>This is a list item with two paragraphs.</p>
+<p>This is the second paragraph in the list item. You're
+only required to indent the first line. Lorem ipsum dolor
+sit amet, consectetuer adipiscing elit.</p>
+</li>
+<li>
+<p>Another item in the same list.</p>
+</li>
+</ul>
+"""
+ assert md_to_html(md) == html
+ end
+
+ fun test_blocks_list_ext is test do
+ var md = """
+This is a paragraph
+* and this is a list
+"""
+ var html = """
+<p>This is a paragraph</p>
+<ul>
+<li>and this is a list</li>
+</ul>
+"""
+ assert md_to_html(md) == html
+ end
+
+ fun test_blocks_indented_code1 is test do
+ var md = """
+This is a normal paragraph:
+
+ This is a code block.
+"""
+ var html = """<p>This is a normal paragraph:</p>
+<pre><code>This is a code block.
+</code></pre>
+"""
+ assert md_to_html(md) == html
+ end
+
+ fun test_blocks_indented_code2 is test do
+ var md = """
+Here is an example of AppleScript:
+
+ tell application "Foo"
+ beep
+ end tell
+
+ <div class="footer">
+ © 2004 Foo Corporation
+ </div>
+"""
+ var html = """
+<p>Here is an example of AppleScript:</p>
+<pre><code>tell application "Foo"
+ beep
+end tell
+
+<div class="footer">
+ &copy; 2004 Foo Corporation
+</div>
+</code></pre>
+"""
+ assert md_to_html(md) == html
+ end
+
+ fun test_blocks_indented_code3 is test do
+ var md = """
+Here is an example of AppleScript:
+
+ beep
+"""
+ var html = """
+<p>Here is an example of AppleScript:</p>
+<pre><code>beep
+</code></pre>
+"""
+ assert md_to_html(md) == html
+ end
+
+ fun test_blocks_fenced_code1 is test do
+ var md = """
+Here is an example of AppleScript:
+~~~
+tell application "Foo"
+ beep
+end tell
+
+<div class="footer">
+ © 2004 Foo Corporation
+</div>
+~~~
+"""
+ var html = """
+<p>Here is an example of AppleScript:</p>
+<pre><code>tell application "Foo"
+ beep
+end tell
+
+<div class="footer">
+ &copy; 2004 Foo Corporation
+</div>
+</code></pre>
+"""
+ assert md_to_html(md) == html
+ end
+
+ fun test_blocks_fenced_code2 is test do
+ var md = """
+Here is an example of AppleScript:
+```
+tell application "Foo"
+ beep
+end tell
+
+<div class="footer">
+ © 2004 Foo Corporation
+</div>
+```
+"""
+ var html = """
+<p>Here is an example of AppleScript:</p>
+<pre><code>tell application "Foo"
+ beep
+end tell
+
+<div class="footer">
+ &copy; 2004 Foo Corporation
+</div>
+</code></pre>
+"""
+ assert md_to_html(md) == html
+ end
+
+ fun test_blocks_fenced_code3 is test do
+ var md = """
+```nit
+print "Hello World!"
+```
+"""
+ var html = """
+<pre><code class="language-nit">print "Hello World!"
+</code></pre>
+"""
+ assert md_to_html(md) == html
+ end
+
+ fun test_blocks_fenced_code4 is test do
+ var md = """
+~~~
+print "Hello"
+~~~
+~~~
+print "World"
+~~~
+"""
+ var html = """
+<pre><code>print "Hello"
+</code></pre>
+<pre><code>print "World"
+</code></pre>
+"""
+ assert md_to_html(md) == html
+ end
+
+ fun test_blocks_fenced_code5 is test do
+ var md = """
+~~~
+print "Hello"
+~~~
+~~~
+print "World"
+~~~
+"""
+ var html = """
+<pre><code>print "Hello"
+</code></pre>
+<pre><code>print "World"
+</code></pre>
+"""
+ assert md_to_html(md) == html
+ end
+
+ fun test_blocks_nesting1 is test do
+ var md = """
+> ## This is a header.
+>
+> 1. This is the first list item.
+> 2. This is the second list item.
+>
+> Here's some example code:
+>
+> return shell_exec("echo $input | $markdown_script");
+"""
+ var html = """
+<blockquote>
+<h2>This is a header.</h2>
+<ol>
+<li>This is the first list item.</li>
+<li>This is the second list item.</li>
+</ol>
+<p>Here's some example code:</p>
+<pre><code>return shell_exec("echo $input | $markdown_script");
+</code></pre>
+</blockquote>
+"""
+ assert md_to_html(md) == html
+ end
+
+ fun test_blocks_nesting2 is test do
+ var md = """
+* A list item with a blockquote:
+
+ > This is a blockquote
+ > inside a list item.
+"""
+ var html = """
+<ul>
+<li>
+<p>A list item with a blockquote:</p>
+<blockquote>
+<p>This is a blockquote
+inside a list item.</p>
+</blockquote>
+</li>
+</ul>
+"""
+ assert md_to_html(md) == html
+ end
+
+ fun test_blocks_nesting3 is test do
+ var md = """
+* A list item with a code block:
+
+ <code goes here>
+"""
+ var html = """
+<ul>
+<li>
+<p>A list item with a code block:</p>
+<pre><code><code goes here>
+</code></pre>
+</li>
+</ul>
+"""
+ assert md_to_html(md) == html
+ end
+
+ fun test_blocks_nesting4 is test do
+ var md = """
+* Tab
+ * Tab
+ * Tab
+"""
+ var html = """
+<ul>
+<li>Tab
+<ul>
+<li>Tab
+<ul>
+<li>Tab</li>
+</ul>
+</li>
+</ul>
+</li>
+</ul>
+"""
+ assert md_to_html(md) == html
+ end
+
+ fun test_blocks_nesting5 is test do
+ var md = """
+* this
+
+ * sub
+
+ that
+"""
+ var html = """
+<ul>
+<li>
+<p>this</p>
+<ul>
+<li>
+<p>sub</p>
+<p>that</p>
+</li>
+</ul>
+</li>
+</ul>
+"""
+ assert md_to_html(md) == html
+ end
+end
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Test for markdown headings id generation
+module test_markdown_headings_id is test
+
+import test_markdown
+
+class TestMarkdownHeadingsId
+ super TestMarkdownHtml
+ test
+
+ redef var html_renderer = new HtmlRenderer(true)
+
+ fun test_multiple_ids is test do
+ var md = """# foo\n## foo\n### foo\n#### foo\n##### foo\n###### foo\n"""
+ var html = """<h1 id="foo">foo</h1>\n<h2 id="foo_1">foo</h2>\n<h3 id="foo_2">foo</h3>\n<h4 id="foo_3">foo</h4>\n<h5 id="foo_4">foo</h5>\n<h6 id="foo_5">foo</h6>\n"""
+ assert md_to_html(md) == html
+ end
+
+ fun test_escape_ids is test do
+ var md = """# foo *bar* \\*baz\\*\n"""
+ var html = """<h1 id="foo_bar_baz">foo <em>bar</em> *baz*</h1>\n"""
+ assert md_to_html(md) == html
+ end
+
+ fun test_escape_ids2 is test do
+ var md = """# foo#\n"""
+ var html = """<h1 id="foo">foo#</h1>\n"""
+ assert md_to_html(md) == html
+ end
+
+ fun test_avoid_spaces is test do
+ var md = """# foo \n"""
+ var html = """<h1 id="foo">foo</h1>\n"""
+ assert md_to_html(md) == html
+ end
+
+ fun test_remove_atx_trailing is test do
+ var md = """## foo ##\n ### bar ###\n"""
+ var html = """<h2 id="foo">foo</h2>\n<h3 id="bar">bar</h3>\n"""
+ assert md_to_html(md) == html
+ end
+
+ fun test_avoid_escaped_chars is test do
+ var md = """### foo \\###\n## foo #\\##\n# foo \\#\n"""
+ var html = """<h3 id="foo_">foo ###</h3>\n<h2 id="foo__1">foo ###</h2>\n<h1 id="foo__2">foo #</h1>\n"""
+ assert md_to_html(md) == html
+ end
+end
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either htmlress or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Tests for markdown inline constructs
+module test_markdown_inlines is test
+
+import test_markdown
+
+class TestMarkdownInlines
+ super TestMarkdownHtml
+ test
+
+ fun test_inlines_emph1 is test do
+ var md = """
+*single asterisks*
+
+_single underscores_
+
+**double asterisks**
+
+__double underscores__
+"""
+ var html = """<p><em>single asterisks</em></p>
+<p><em>single underscores</em></p>
+<p><strong>double asterisks</strong></p>
+<p><strong>double underscores</strong></p>
+"""
+ assert md_to_html(md) == html
+ end
+
+ fun test_inlines_emph2 is test do
+ var md = "un*frigging*believable"
+ var html = "<p>un<em>frigging</em>believable</p>\n"
+ assert md_to_html(md) == html
+ end
+
+ fun test_inlines_emph3 is test do
+ var md = "Con _cat_ this"
+ var html = "<p>Con <em>cat</em> this</p>\n"
+ assert md_to_html(md) == html
+ end
+
+ fun test_inlines_emph_ext is test do
+ var md = "Con_cat_this"
+ var html = "<p>Con_cat_this</p>\n"
+ assert md_to_html(md) == html
+ end
+
+ fun test_inlines_xml1 is test do
+ var md = """
+This is a regular paragraph.
+
+<table>
+ <tr>
+ <td>Foo</td>
+ </tr>
+</table>
+
+This is another regular paragraph.
+"""
+ var html = """
+<p>This is a regular paragraph.</p>
+<table>
+ <tr>
+ <td>Foo</td>
+ </tr>
+</table>
+<p>This is another regular paragraph.</p>
+"""
+ assert md_to_html(md) == html
+ end
+
+ fun test_inlines_xml2 is test do
+ var md = """
+This is an image <img src="foo/bar" alt="baz"/> in a regular paragraph.
+"""
+ var html = """
+<p>This is an image <img src="foo/bar" alt="baz"/> in a regular paragraph.</p>
+"""
+ assert md_to_html(md) == html
+ end
+
+ fun test_inlines_xml3 is test do
+ var md = """
+<div style=">"/>
+"""
+ var html = """
+<div style=">"/>
+"""
+ assert md_to_html(md) == html
+ end
+
+ fun test_inlines_xml4 is test do
+ var md = """
+<p>This is an example of a block element that should be escaped.</p>
+<p>Idem for the second paragraph.</p>
+"""
+ assert md_to_html(md) == md
+ end
+
+ fun test_inlines_xml5 is test do
+ var md = """
+# Some more XML tests
+
+<p>This is an example of a block element that should be escaped.</p>
+<p>Idem for the second paragraph.</p>
+
+With a *md paragraph*!
+"""
+ var html = """
+<h1>Some more XML tests</h1>
+<p>This is an example of a block element that should be escaped.</p>
+<p>Idem for the second paragraph.</p>
+<p>With a <em>md paragraph</em>!</p>
+"""
+ assert md_to_html(md) == html
+ end
+
+ fun test_escape_bad_html is test do
+ var md = "-1 if < , +1 if > and 0 otherwise"
+ var html = "<p>-1 if < , +1 if > and 0 otherwise</p>\n"
+ assert md_to_html(md) == html
+ end
+
+ fun test_inlines_span_code1 is test do
+ var md = "Use the `printf()` function."
+ var html = "<p>Use the <code>printf()</code> function.</p>\n"
+ assert md_to_html(md) == html
+ end
+
+ fun test_inlines_span_code2 is test do
+ var md = "``There is a literal backtick (`) here.``"
+ var html = "<p><code>There is a literal backtick (`) here.</code></p>\n"
+ assert md_to_html(md) == html
+ end
+
+ fun test_inlines_span_code3 is test do
+ var md = """
+A single backtick in a code span: `` ` ``
+
+A backtick-delimited string in a code span: `` `foo` ``
+"""
+ var html = """
+<p>A single backtick in a code span: <code>`</code></p>
+<p>A backtick-delimited string in a code span: <code>`foo`</code></p>
+"""
+ assert md_to_html(md) == html
+ end
+
+ fun test_inlines_span_code4 is test do
+ var md = "Please don't use any `<blink>` tags."
+ var html = "<p>Please don't use any <code><blink></code> tags.</p>\n"
+ assert md_to_html(md) == html
+ end
+
+ fun test_inlines_span_code5 is test do
+ var md = "`—` is the decimal-encoded equivalent of `—`."
+ var html = "<p><code>&#8212;</code> is the decimal-encoded equivalent of <code>&mdash;</code>.</p>\n"
+ assert md_to_html(md) == html
+ end
+
+ fun test_inlines_escape1 is test do
+ var md = "\\*this text is surrounded by literal asterisks\\*"
+ var html = "<p>*this text is surrounded by literal asterisks*</p>\n"
+ assert md_to_html(md) == html
+ end
+
+ fun test_inlines_escape2 is test do
+ var md = "1986\\. What a great season."
+ var html = "<p>1986. What a great season.</p>\n"
+ assert md_to_html(md) == html
+ end
+
+ fun test_inlines_escape3 is test do
+ var md = "Ben & Lux"
+ var html = "<p>Ben & Lux</p>\n"
+ assert md_to_html(md) == html
+ end
+
+ fun test_inlines_link1 is test do
+ var md = """
+This is [an example](http://example.com/ "Title") inline link.
+
+[This link](http://example.net/) has no title attribute.
+"""
+ var html = """<p>This is <a href="http://example.com/" title="Title">an example</a> inline link.</p>
+<p><a href="http://example.net/">This link</a> has no title attribute.</p>
+"""
+ assert md_to_html(md) == html
+ end
+
+ fun test_inlines_link2 is test do
+ var md = "See my [About](/about/) page for details."
+ var html = "<p>See my <a href=\"/about/\">About</a> page for details.</p>\n"
+ assert md_to_html(md) == html
+ end
+
+ fun test_inlines_link3 is test do
+ var md = """
+This is [an example][id] reference-style link.
+
+Some lorem ipsum
+
+[id]: http://example.com/ "Optional Title Here"
+
+Some other lipsum
+"""
+ var html = """
+<p>This is <a href="http://example.com/" title="Optional Title Here">an example</a> reference-style link.</p>
+<p>Some lorem ipsum</p>
+<p>Some other lipsum</p>
+"""
+ assert md_to_html(md) == html
+ end
+
+ fun test_inlines_link4 is test do
+ var md = """
+This is multiple examples: [foo][1], [bar][2], [baz][3].
+
+[1]: http://example.com/ "Optional Title Here"
+[2]: http://example.com/ 'Optional Title Here'
+[3]: http://example.com/ (Optional Title Here)
+"""
+ var html = """
+<p>This is multiple examples: <a href="http://example.com/" title="Optional Title Here">foo</a>, <a href="http://example.com/" title="Optional Title Here">bar</a>, <a href="http://example.com/" title="Optional Title Here">baz</a>.</p>
+"""
+ assert md_to_html(md) == html
+ end
+
+ fun test_inlines_link5 is test do
+ var md = """
+This is multiple examples: [foo][a], [bar][A], [a].
+
+[a]: http://example.com/ "Optional Title Here"
+"""
+ var html = """<p>This is multiple examples: <a href="http://example.com/" title="Optional Title Here">foo</a>, <a href="http://example.com/" title="Optional Title Here">bar</a>, <a href="http://example.com/" title="Optional Title Here">a</a>.</p>
+"""
+ assert md_to_html(md) == html
+ end
+
+ fun test_inlines_link6 is test do
+ var md = """
+I get 10 times more traffic from [Google][] than from [Yahoo][] or [MSN][].
+
+[Google]: http://google.com/ "Google"
+[Yahoo]: http://search.yahoo.com/ "Yahoo Search"
+[MSN]: http://search.msn.com/ "MSN Search"
+"""
+ var html = """<p>I get 10 times more traffic from <a href="http://google.com/" title="Google">Google</a> than from <a href="http://search.yahoo.com/" title="Yahoo Search">Yahoo</a> or <a href="http://search.msn.com/" title="MSN Search">MSN</a>.</p>
+"""
+ assert md_to_html(md) == html
+ end
+
+ fun test_inlines_link7 is test do
+ var md = """
+Visit [Daring Fireball][] for more information.
+
+[Daring Fireball]: http://daringfireball.net/
+"""
+ var html = """<p>Visit <a href="http://daringfireball.net/">Daring Fireball</a> for more information.</p>
+"""
+ assert md_to_html(md) == html
+ end
+
+ fun test_inlines_link8 is test do
+ var md = """
+This one has a [line
+break].
+
+This one has a [line
+break] with a line-ending space.
+
+[line break]: /foo
+"""
+ var html = """
+<p>This one has a <a href="/foo">line
+break</a>.</p>
+<p>This one has a <a href="/foo">line
+break</a> with a line-ending space.</p>
+"""
+ assert md_to_html(md) == html
+ end
+
+ fun test_inlines_link9 is test do
+ var md = """
+Foo [bar][].
+
+Foo [bar](/url/ "Title with \\"quotes\\" inside").
+
+
+[bar]: /url/ "Title with \\"quotes\\" inside"
+"""
+ var html = """
+<p>Foo <a href="/url/" title="Title with "quotes" inside">bar</a>.</p>
+<p>Foo <a href="/url/" title="Title with "quotes" inside">bar</a>.</p>
+"""
+ assert md_to_html(md) == html
+ end
+
+ fun test_inlines_img1 is test do
+ var md = """
+![Alt text](/path/to/img.jpg)
+
+![Alt text](/path/to/img.jpg "Optional title")
+"""
+ var html = """
+<p><img src="/path/to/img.jpg" alt="Alt text" /></p>
+<p><img src="/path/to/img.jpg" alt="Alt text" title="Optional title" /></p>
+"""
+ assert md_to_html(md) == html
+ end
+
+ fun test_inlines_img2 is test do
+ var md = """
+![Alt text][id]
+
+[id]: url/to/image "Optional title attribute"
+"""
+ var html = """
+<p><img src="url/to/image" alt="Alt text" title="Optional title attribute" /></p>
+"""
+ assert md_to_html(md) == html
+ end
+end