qiita_marker 0.23.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (111) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.txt +21 -0
  3. data/README.md +50 -0
  4. data/Rakefile +113 -0
  5. data/bin/qiita_marker +123 -0
  6. data/ext/qiita_marker/arena.c +103 -0
  7. data/ext/qiita_marker/autolink.c +425 -0
  8. data/ext/qiita_marker/autolink.h +8 -0
  9. data/ext/qiita_marker/blocks.c +1596 -0
  10. data/ext/qiita_marker/buffer.c +278 -0
  11. data/ext/qiita_marker/buffer.h +116 -0
  12. data/ext/qiita_marker/case_fold_switch.inc +4327 -0
  13. data/ext/qiita_marker/chunk.h +135 -0
  14. data/ext/qiita_marker/cmark-gfm-core-extensions.h +54 -0
  15. data/ext/qiita_marker/cmark-gfm-extension_api.h +736 -0
  16. data/ext/qiita_marker/cmark-gfm-extensions_export.h +42 -0
  17. data/ext/qiita_marker/cmark-gfm.h +817 -0
  18. data/ext/qiita_marker/cmark-gfm_export.h +42 -0
  19. data/ext/qiita_marker/cmark-gfm_version.h +7 -0
  20. data/ext/qiita_marker/cmark.c +55 -0
  21. data/ext/qiita_marker/cmark_ctype.c +44 -0
  22. data/ext/qiita_marker/cmark_ctype.h +33 -0
  23. data/ext/qiita_marker/commonmark.c +529 -0
  24. data/ext/qiita_marker/config.h +76 -0
  25. data/ext/qiita_marker/core-extensions.c +27 -0
  26. data/ext/qiita_marker/entities.inc +2138 -0
  27. data/ext/qiita_marker/ext_scanners.c +879 -0
  28. data/ext/qiita_marker/ext_scanners.h +24 -0
  29. data/ext/qiita_marker/extconf.rb +7 -0
  30. data/ext/qiita_marker/footnotes.c +63 -0
  31. data/ext/qiita_marker/footnotes.h +27 -0
  32. data/ext/qiita_marker/houdini.h +57 -0
  33. data/ext/qiita_marker/houdini_href_e.c +100 -0
  34. data/ext/qiita_marker/houdini_html_e.c +66 -0
  35. data/ext/qiita_marker/houdini_html_u.c +149 -0
  36. data/ext/qiita_marker/html.c +486 -0
  37. data/ext/qiita_marker/html.h +27 -0
  38. data/ext/qiita_marker/inlines.c +1691 -0
  39. data/ext/qiita_marker/inlines.h +29 -0
  40. data/ext/qiita_marker/iterator.c +159 -0
  41. data/ext/qiita_marker/iterator.h +26 -0
  42. data/ext/qiita_marker/latex.c +466 -0
  43. data/ext/qiita_marker/linked_list.c +37 -0
  44. data/ext/qiita_marker/man.c +278 -0
  45. data/ext/qiita_marker/map.c +122 -0
  46. data/ext/qiita_marker/map.h +41 -0
  47. data/ext/qiita_marker/node.c +979 -0
  48. data/ext/qiita_marker/node.h +125 -0
  49. data/ext/qiita_marker/parser.h +58 -0
  50. data/ext/qiita_marker/plaintext.c +235 -0
  51. data/ext/qiita_marker/plugin.c +36 -0
  52. data/ext/qiita_marker/plugin.h +34 -0
  53. data/ext/qiita_marker/qiita_marker.c +1321 -0
  54. data/ext/qiita_marker/qiita_marker.h +16 -0
  55. data/ext/qiita_marker/references.c +42 -0
  56. data/ext/qiita_marker/references.h +26 -0
  57. data/ext/qiita_marker/registry.c +63 -0
  58. data/ext/qiita_marker/registry.h +24 -0
  59. data/ext/qiita_marker/render.c +205 -0
  60. data/ext/qiita_marker/render.h +62 -0
  61. data/ext/qiita_marker/scanners.c +10520 -0
  62. data/ext/qiita_marker/scanners.h +62 -0
  63. data/ext/qiita_marker/scanners.re +341 -0
  64. data/ext/qiita_marker/strikethrough.c +167 -0
  65. data/ext/qiita_marker/strikethrough.h +9 -0
  66. data/ext/qiita_marker/syntax_extension.c +149 -0
  67. data/ext/qiita_marker/syntax_extension.h +34 -0
  68. data/ext/qiita_marker/table.c +822 -0
  69. data/ext/qiita_marker/table.h +12 -0
  70. data/ext/qiita_marker/tagfilter.c +60 -0
  71. data/ext/qiita_marker/tagfilter.h +8 -0
  72. data/ext/qiita_marker/tasklist.c +156 -0
  73. data/ext/qiita_marker/tasklist.h +8 -0
  74. data/ext/qiita_marker/utf8.c +317 -0
  75. data/ext/qiita_marker/utf8.h +35 -0
  76. data/ext/qiita_marker/xml.c +181 -0
  77. data/lib/qiita_marker/config.rb +52 -0
  78. data/lib/qiita_marker/node/inspect.rb +57 -0
  79. data/lib/qiita_marker/node.rb +83 -0
  80. data/lib/qiita_marker/renderer/html_renderer.rb +252 -0
  81. data/lib/qiita_marker/renderer.rb +135 -0
  82. data/lib/qiita_marker/version.rb +5 -0
  83. data/lib/qiita_marker.rb +45 -0
  84. data/qiita_marker.gemspec +40 -0
  85. data/test/benchmark.rb +32 -0
  86. data/test/fixtures/curly.md +1 -0
  87. data/test/fixtures/dingus.md +10 -0
  88. data/test/fixtures/strong.md +1 -0
  89. data/test/fixtures/table.md +10 -0
  90. data/test/test_attributes.rb +24 -0
  91. data/test/test_basics.rb +35 -0
  92. data/test/test_commands.rb +72 -0
  93. data/test/test_commonmark.rb +36 -0
  94. data/test/test_doc.rb +130 -0
  95. data/test/test_encoding.rb +23 -0
  96. data/test/test_extensions.rb +116 -0
  97. data/test/test_footnotes.rb +60 -0
  98. data/test/test_gc.rb +47 -0
  99. data/test/test_helper.rb +71 -0
  100. data/test/test_linebreaks.rb +15 -0
  101. data/test/test_maliciousness.rb +262 -0
  102. data/test/test_node.rb +89 -0
  103. data/test/test_options.rb +37 -0
  104. data/test/test_pathological_inputs.rb +94 -0
  105. data/test/test_plaintext.rb +46 -0
  106. data/test/test_renderer.rb +47 -0
  107. data/test/test_smartpunct.rb +27 -0
  108. data/test/test_spec.rb +30 -0
  109. data/test/test_tasklists.rb +43 -0
  110. data/test/test_xml.rb +107 -0
  111. metadata +313 -0
@@ -0,0 +1,94 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'test_helper'
4
+ require 'minitest/benchmark' if ENV['BENCH']
5
+
6
+ def markdown(str)
7
+ QiitaMarker.render_doc(str).to_html
8
+ end
9
+
10
+ # list of pairs consisting of input and a regex that must match the output.
11
+ pathological = {
12
+ 'nested strong emph' =>
13
+ ["#{'*a **a ' * 65_000}b#{' a** a*' * 65_000}",
14
+ Regexp.compile('(<em>a <strong>a ){65_000}b( a</strong> a</em>){65_000}')],
15
+ 'many emph closers with no openers' =>
16
+ [('a_ ' * 65_000),
17
+ Regexp.compile('(a[_] ){64999}a_')],
18
+ 'many emph openers with no closers' =>
19
+ [('_a ' * 65_000),
20
+ Regexp.compile('(_a ){64999}_a')],
21
+ 'many link closers with no openers' =>
22
+ [('a]' * 65_000),
23
+ Regexp.compile('(a\]){65_000}')],
24
+ 'many link openers with no closers' =>
25
+ [('[a' * 65_000),
26
+ Regexp.compile('(\[a){65_000}')],
27
+ 'mismatched openers and closers' =>
28
+ [('*a_ ' * 50_000),
29
+ Regexp.compile('([*]a[_] ){49999}[*]a_')],
30
+ 'link openers and emph closers' =>
31
+ [('[ a_' * 50_000),
32
+ Regexp.compile('(\[ a_){50000}')],
33
+ 'hard link/emph case' =>
34
+ ['**x [a*b**c*](d)',
35
+ Regexp.compile('\\*\\*x <a href=\'d\'>a<em>b</em><em>c</em></a>')],
36
+ 'nested brackets' =>
37
+ ["#{'[' * 50_000}a#{']' * 50_000}",
38
+ Regexp.compile('\[{50000}a\]{50000}')],
39
+ 'nested block quotes' =>
40
+ ["#{'> ' * 50_000}a",
41
+ Regexp.compile('(<blockquote>\n){50000}')],
42
+ 'U+0000 in input' =>
43
+ ['abc\u0000de\u0000',
44
+ Regexp.compile('abc\ufffd?de\ufffd?')]
45
+ }
46
+
47
+ pathological.each_pair do |name, description|
48
+ define_method("test_#{name}") do
49
+ input, = description
50
+ assert markdown(input)
51
+ end
52
+ end
53
+
54
+ if ENV['BENCH']
55
+ class PathologicalInputsPerformanceTest < Minitest::Benchmark
56
+ def test_bench_pathological_one
57
+ assert_performance_linear 0.99 do |n|
58
+ star = '*' * (n * 10)
59
+ markdown("#{star}#{star}hi#{star}#{star}")
60
+ end
61
+ end
62
+
63
+ def test_bench_pathological_two
64
+ assert_performance_linear 0.99 do |n|
65
+ c = '`t`t`t`t`t`t' * (n * 10)
66
+ markdown(c)
67
+ end
68
+ end
69
+
70
+ def test_bench_pathological_three
71
+ assert_performance_linear 0.99 do |n|
72
+ markdown(" [a]: #{'A' * n}\n\n#{'[a][]' * n}\n")
73
+ end
74
+ end
75
+
76
+ def test_bench_pathological_four
77
+ assert_performance_linear 0.5 do |n|
78
+ markdown("#{'[' * n}a#{']' * n}")
79
+ end
80
+ end
81
+
82
+ def test_bench_pathological_five
83
+ assert_performance_linear 0.99 do |n|
84
+ markdown("#{'**a *a ' * n}#{'a* a**' * n}")
85
+ end
86
+ end
87
+
88
+ def test_bench_unbound_recursion
89
+ assert_performance_linear 0.99 do |n|
90
+ markdown("#{'[' * n}foo#{'](bar)' * n}")
91
+ end
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'test_helper'
4
+
5
+ class TestPlaintext < Minitest::Test
6
+ def setup
7
+ @markdown = <<~MD
8
+ Hi *there*!
9
+
10
+ 1. I am a numeric list.
11
+ 2. I continue the list.
12
+ * Suddenly, an unordered list!
13
+ * What fun!
14
+
15
+ Okay, _enough_.
16
+
17
+ | a | b |
18
+ | --- | --- |
19
+ | c | d |
20
+ MD
21
+ end
22
+
23
+ def render_doc(doc)
24
+ QiitaMarker.render_doc(doc, :DEFAULT, %i[table])
25
+ end
26
+
27
+ def test_to_commonmark
28
+ compare = render_doc(@markdown).to_plaintext
29
+
30
+ assert_equal <<~PLAINTEXT, compare
31
+ Hi there!
32
+
33
+ 1. I am a numeric list.
34
+ 2. I continue the list.
35
+
36
+ - Suddenly, an unordered list!
37
+ - What fun!
38
+
39
+ Okay, enough.
40
+
41
+ | a | b |
42
+ | --- | --- |
43
+ | c | d |
44
+ PLAINTEXT
45
+ end
46
+ end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'test_helper'
4
+
5
+ class TestRenderer < Minitest::Test
6
+ def setup
7
+ @doc = QiitaMarker.render_doc('Hi *there*')
8
+ end
9
+
10
+ def test_html_renderer
11
+ renderer = HtmlRenderer.new
12
+ result = renderer.render(@doc)
13
+ assert_equal "<p>Hi <em>there</em></p>\n", result
14
+ end
15
+
16
+ def test_multiple_tables
17
+ content = <<~DOC
18
+ | Input | Expected | Actual |
19
+ | ----------- | ---------------- | --------- |
20
+ | One | Two | Three |
21
+
22
+ | Header | Row | Example |
23
+ | :------: | ---: | :------ |
24
+ | Foo | Bar | Baz |
25
+ DOC
26
+ doc = QiitaMarker.render_doc(content, :DEFAULT, %i[autolink table tagfilter])
27
+ results = QiitaMarker::HtmlRenderer.new.render(doc)
28
+ assert_equal 2, results.scan(/<tbody>/).size
29
+ end
30
+
31
+ def test_escape_html_encoding
32
+ my_renderer = Class.new(HtmlRenderer) do
33
+ attr_reader :input_encoding, :output_encoding
34
+
35
+ def text(node)
36
+ @input_encoding = node.string_content.encoding
37
+ escape_html(node.string_content).tap do |escaped|
38
+ @output_encoding = escaped.encoding
39
+ end
40
+ end
41
+ end
42
+
43
+ renderer = my_renderer.new
44
+ assert_equal Encoding::UTF_8, renderer.render(@doc).encoding
45
+ assert_equal renderer.input_encoding, renderer.output_encoding
46
+ end
47
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'test_helper'
4
+
5
+ class SmartPunctTest < Minitest::Test
6
+ smart_punct = open_spec_file('smart_punct.txt')
7
+
8
+ smart_punct.each do |testcase|
9
+ doc = QiitaMarker.render_doc(testcase[:markdown], :SMART)
10
+ html = QiitaMarker.render_html(testcase[:markdown], :SMART)
11
+
12
+ define_method("test_smart_punct_example_#{testcase[:example]}") do
13
+ doc_rendered = doc.to_html.strip
14
+ html_rendered = html.strip
15
+
16
+ assert_equal testcase[:html], doc_rendered, testcase[:markdown]
17
+ assert_equal testcase[:html], html_rendered, testcase[:markdown]
18
+ end
19
+ end
20
+
21
+ def test_smart_hardbreak_no_spaces_render_doc
22
+ markdown = "\"foo\"\nbaz"
23
+ result = "<p>“foo”<br />\nbaz</p>\n"
24
+ doc = QiitaMarker.render_doc(markdown, :SMART)
25
+ assert_equal result, doc.to_html([:HARDBREAKS])
26
+ end
27
+ end
data/test/test_spec.rb ADDED
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'test_helper'
4
+ require 'json'
5
+
6
+ class TestSpec < Minitest::Test
7
+ spec = open_spec_file('spec.txt')
8
+
9
+ spec.each do |testcase|
10
+ next if testcase[:extensions].include?(:disabled)
11
+
12
+ doc = QiitaMarker.render_doc(testcase[:markdown], :DEFAULT, testcase[:extensions])
13
+
14
+ define_method("test_to_html_example_#{testcase[:example]}") do
15
+ actual = doc.to_html(:UNSAFE, testcase[:extensions]).rstrip
16
+ assert_equal testcase[:html], actual, testcase[:markdown]
17
+ end
18
+
19
+ define_method("test_html_renderer_example_#{testcase[:example]}") do
20
+ actual = HtmlRenderer.new(options: :UNSAFE, extensions: testcase[:extensions]).render(doc).rstrip
21
+ assert_equal testcase[:html], actual, testcase[:markdown]
22
+ end
23
+
24
+ define_method("test_sourcepos_example_#{testcase[:example]}") do
25
+ lhs = doc.to_html(%i[UNSAFE SOURCEPOS], testcase[:extensions]).rstrip
26
+ rhs = HtmlRenderer.new(options: %i[UNSAFE SOURCEPOS], extensions: testcase[:extensions]).render(doc).rstrip
27
+ assert_equal lhs, rhs, testcase[:markdown]
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'test_helper'
4
+
5
+ class TestTasklists < Minitest::Test
6
+ def setup
7
+ text = <<-MD
8
+ - [x] Add task list
9
+ - [ ] Define task list
10
+ MD
11
+ @doc = QiitaMarker.render_doc(text, :DEFAULT, %i[tasklist])
12
+ @expected = <<~HTML
13
+ <ul>
14
+ <li><input type="checkbox" checked="" disabled="" /> Add task list</li>
15
+ <li><input type="checkbox" disabled="" /> Define task list</li>
16
+ </ul>
17
+ HTML
18
+ end
19
+
20
+ def test_to_html
21
+ assert_equal @expected, @doc.to_html
22
+ end
23
+
24
+ def test_html_renderer
25
+ assert_equal @expected, QiitaMarker::HtmlRenderer.new.render(@doc)
26
+ end
27
+
28
+ def test_tasklist_state
29
+ list = @doc.first_child
30
+ assert_equal 'checked', list.first_child.tasklist_state
31
+ assert list.first_child.tasklist_item_checked?
32
+ assert_equal 'unchecked', list.first_child.next.tasklist_state
33
+ refute list.first_child.next.tasklist_item_checked?
34
+ end
35
+
36
+ def test_set_tasklist_state
37
+ list = @doc.first_child
38
+ list.first_child.tasklist_item_checked = false
39
+ refute list.first_child.tasklist_item_checked?
40
+ list.first_child.next.tasklist_item_checked = true
41
+ assert list.first_child.next.tasklist_item_checked?
42
+ end
43
+ end
data/test/test_xml.rb ADDED
@@ -0,0 +1,107 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'test_helper'
4
+
5
+ class TestXml < Minitest::Test
6
+ def setup
7
+ @markdown = <<~MD
8
+ Hi *there*!
9
+
10
+ 1. I am a numeric list.
11
+ 2. I continue the list.
12
+ * Suddenly, an unordered list!
13
+ * What fun!
14
+
15
+ Okay, _enough_.
16
+
17
+ | a | b |
18
+ | --- | --- |
19
+ | c | d |
20
+ MD
21
+ end
22
+
23
+ def render_doc(doc)
24
+ QiitaMarker.render_doc(doc, :DEFAULT, [:table])
25
+ end
26
+
27
+ def test_to_xml
28
+ compare = render_doc(@markdown).to_xml(:SOURCEPOS)
29
+
30
+ assert_equal <<~XML, compare
31
+ <?xml version="1.0" encoding="UTF-8"?>
32
+ <!DOCTYPE document SYSTEM "CommonMark.dtd">
33
+ <document sourcepos="1:1-12:13" xmlns="http://commonmark.org/xml/1.0">
34
+ <paragraph sourcepos="1:1-1:11">
35
+ <text sourcepos="1:1-1:3" xml:space="preserve">Hi </text>
36
+ <emph sourcepos="1:4-1:10">
37
+ <text sourcepos="1:5-1:9" xml:space="preserve">there</text>
38
+ </emph>
39
+ <text sourcepos="1:11-1:11" xml:space="preserve">!</text>
40
+ </paragraph>
41
+ <list sourcepos="3:1-4:23" type="ordered" start="1" delim="period" tight="true">
42
+ <item sourcepos="3:1-3:23">
43
+ <paragraph sourcepos="3:4-3:23">
44
+ <text sourcepos="3:4-3:23" xml:space="preserve">I am a numeric list.</text>
45
+ </paragraph>
46
+ </item>
47
+ <item sourcepos="4:1-4:23">
48
+ <paragraph sourcepos="4:4-4:23">
49
+ <text sourcepos="4:4-4:23" xml:space="preserve">I continue the list.</text>
50
+ </paragraph>
51
+ </item>
52
+ </list>
53
+ <list sourcepos="5:1-7:0" type="bullet" tight="true">
54
+ <item sourcepos="5:1-5:30">
55
+ <paragraph sourcepos="5:3-5:30">
56
+ <text sourcepos="5:3-5:30" xml:space="preserve">Suddenly, an unordered list!</text>
57
+ </paragraph>
58
+ </item>
59
+ <item sourcepos="6:1-7:0">
60
+ <paragraph sourcepos="6:3-6:11">
61
+ <text sourcepos="6:3-6:11" xml:space="preserve">What fun!</text>
62
+ </paragraph>
63
+ </item>
64
+ </list>
65
+ <paragraph sourcepos="8:1-8:15">
66
+ <text sourcepos="8:1-8:6" xml:space="preserve">Okay, </text>
67
+ <emph sourcepos="8:7-8:14">
68
+ <text sourcepos="8:8-8:13" xml:space="preserve">enough</text>
69
+ </emph>
70
+ <text sourcepos="8:15-8:15" xml:space="preserve">.</text>
71
+ </paragraph>
72
+ <table sourcepos="10:1-12:13">
73
+ <table_header sourcepos="10:1-10:13">
74
+ <table_cell sourcepos="10:2-10:6">
75
+ <text sourcepos="10:3-10:3" xml:space="preserve">a</text>
76
+ </table_cell>
77
+ <table_cell sourcepos="10:8-10:12">
78
+ <text sourcepos="10:9-10:9" xml:space="preserve">b</text>
79
+ </table_cell>
80
+ </table_header>
81
+ <table_row sourcepos="12:1-12:13">
82
+ <table_cell sourcepos="12:2-12:6">
83
+ <text sourcepos="12:3-12:3" xml:space="preserve">c</text>
84
+ </table_cell>
85
+ <table_cell sourcepos="12:8-12:12">
86
+ <text sourcepos="12:9-12:9" xml:space="preserve">d</text>
87
+ </table_cell>
88
+ </table_row>
89
+ </table>
90
+ </document>
91
+ XML
92
+ end
93
+
94
+ def test_to_xml_with_quotes
95
+ compare = render_doc('"quotes" should be escaped').to_xml(:DEFAULT)
96
+
97
+ assert_equal <<~XML, compare
98
+ <?xml version="1.0" encoding="UTF-8"?>
99
+ <!DOCTYPE document SYSTEM "CommonMark.dtd">
100
+ <document xmlns="http://commonmark.org/xml/1.0">
101
+ <paragraph>
102
+ <text xml:space="preserve">&quot;quotes&quot; should be escaped</text>
103
+ </paragraph>
104
+ </document>
105
+ XML
106
+ end
107
+ end