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,135 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'set'
4
+ require 'stringio'
5
+
6
+ module QiitaMarker
7
+ class Renderer
8
+ attr_accessor :in_tight, :warnings, :in_plain
9
+
10
+ def initialize(options: :DEFAULT, extensions: [])
11
+ @opts = Config.process_options(options, :render)
12
+ @stream = StringIO.new(+'')
13
+ @need_blocksep = false
14
+ @warnings = Set.new []
15
+ @in_tight = false
16
+ @in_plain = false
17
+ @tagfilter = extensions.include?(:tagfilter)
18
+ end
19
+
20
+ def out(*args)
21
+ args.each do |arg|
22
+ case arg
23
+ when :children
24
+ @node.each { |child| out(child) }
25
+ when Array
26
+ arg.each { |x| render(x) }
27
+ when Node
28
+ render(arg)
29
+ else
30
+ @stream.write(arg)
31
+ end
32
+ end
33
+ end
34
+
35
+ def render(node)
36
+ @node = node
37
+ if node.type == :document
38
+ document(node)
39
+ @stream.string
40
+ elsif @in_plain && node.type != :text && node.type != :softbreak
41
+ node.each { |child| render(child) }
42
+ else
43
+ begin
44
+ send(node.type, node)
45
+ rescue NoMethodError => e
46
+ @warnings.add("WARNING: #{node.type} not implemented.")
47
+ raise e
48
+ end
49
+ end
50
+ end
51
+
52
+ def document(_node)
53
+ out(:children)
54
+ end
55
+
56
+ def code_block(node)
57
+ code_block(node)
58
+ end
59
+
60
+ def reference_def(_node); end
61
+
62
+ def cr
63
+ return if @stream.string.empty? || @stream.string[-1] == "\n"
64
+
65
+ out("\n")
66
+ end
67
+
68
+ def blocksep
69
+ out("\n")
70
+ end
71
+
72
+ def containersep
73
+ cr unless @in_tight
74
+ end
75
+
76
+ def block
77
+ cr
78
+ yield
79
+ cr
80
+ end
81
+
82
+ def container(starter, ender)
83
+ out(starter)
84
+ yield
85
+ out(ender)
86
+ end
87
+
88
+ def plain
89
+ old_in_plain = @in_plain
90
+ @in_plain = true
91
+ yield
92
+ @in_plain = old_in_plain
93
+ end
94
+
95
+ private
96
+
97
+ def escape_href(str)
98
+ @node.html_escape_href(str)
99
+ end
100
+
101
+ def escape_html(str)
102
+ @node.html_escape_html(str)
103
+ end
104
+
105
+ def tagfilter(str)
106
+ if @tagfilter
107
+ str.gsub(
108
+ %r{
109
+ <
110
+ (
111
+ title|textarea|style|xmp|iframe|
112
+ noembed|noframes|script|plaintext
113
+ )
114
+ (?=\s|>|/>)
115
+ }xi,
116
+ '&lt;\1'
117
+ )
118
+ else
119
+ str
120
+ end
121
+ end
122
+
123
+ def sourcepos(node)
124
+ return '' unless option_enabled?(:SOURCEPOS)
125
+
126
+ s = node.sourcepos
127
+ " data-sourcepos=\"#{s[:start_line]}:#{s[:start_column]}-" \
128
+ "#{s[:end_line]}:#{s[:end_column]}\""
129
+ end
130
+
131
+ def option_enabled?(opt)
132
+ (@opts & QiitaMarker::Config::OPTS.dig(:render, opt)) != 0
133
+ end
134
+ end
135
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module QiitaMarker
4
+ VERSION = '0.23.2.0'
5
+ end
@@ -0,0 +1,45 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'qiita_marker/qiita_marker'
5
+ require 'qiita_marker/config'
6
+ require 'qiita_marker/node'
7
+ require 'qiita_marker/renderer'
8
+ require 'qiita_marker/renderer/html_renderer'
9
+ require 'qiita_marker/version'
10
+
11
+ begin
12
+ require 'awesome_print'
13
+ rescue LoadError; end # rubocop:disable Lint/SuppressedException
14
+ module QiitaMarker
15
+ # Public: Parses a Markdown string into an HTML string.
16
+ #
17
+ # text - A {String} of text
18
+ # option - Either a {Symbol} or {Array of Symbol}s indicating the render options
19
+ # extensions - An {Array of Symbol}s indicating the extensions to use
20
+ #
21
+ # Returns a {String} of converted HTML.
22
+ def self.render_html(text, options = :DEFAULT, extensions = [])
23
+ raise TypeError, "text must be a String; got a #{text.class}!" unless text.is_a?(String)
24
+
25
+ opts = Config.process_options(options, :render)
26
+ text = text.encode('UTF-8')
27
+ html = Node.markdown_to_html(text, opts, extensions)
28
+ html.force_encoding('UTF-8')
29
+ end
30
+
31
+ # Public: Parses a Markdown string into a `document` node.
32
+ #
33
+ # string - {String} to be parsed
34
+ # option - A {Symbol} or {Array of Symbol}s indicating the parse options
35
+ # extensions - An {Array of Symbol}s indicating the extensions to use
36
+ #
37
+ # Returns the `document` node.
38
+ def self.render_doc(text, options = :DEFAULT, extensions = [])
39
+ raise TypeError, "text must be a String; got a #{text.class}!" unless text.is_a?(String)
40
+
41
+ opts = Config.process_options(options, :parse)
42
+ text = text.encode('UTF-8')
43
+ Node.parse_document(text, text.bytesize, opts, extensions)
44
+ end
45
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ lib = File.expand_path('lib', __dir__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+ require 'qiita_marker/version'
6
+
7
+ Gem::Specification.new do |s|
8
+ s.name = 'qiita_marker'
9
+ s.version = QiitaMarker::VERSION
10
+ s.summary = 'Qiita Marker is a Ruby library for Markdown processing, based on CommonMarker.'
11
+ s.description = 'A Ruby library that is the core module of the Qiita-specified markdown processor.'
12
+ s.authors = ['Increments Inc.']
13
+ s.homepage = 'https://github.com/increments/qiita_marker'
14
+ s.license = 'MIT'
15
+
16
+ s.files = %w[LICENSE.txt README.md Rakefile qiita_marker.gemspec bin/qiita_marker]
17
+ s.files += Dir.glob('lib/**/*.rb')
18
+ s.files += Dir.glob('ext/qiita_marker/*.*')
19
+ s.test_files = Dir.glob('test/**/*').reject { |f| f == 'test/benchinput.md' || f.start_with?('test/progit/') }
20
+ s.extensions = ['ext/qiita_marker/extconf.rb']
21
+
22
+ s.executables = ['qiita_marker']
23
+ s.require_paths = %w[lib ext]
24
+ s.required_ruby_version = ['>= 2.6', '< 4.0']
25
+
26
+ s.rdoc_options += ['-x', 'ext/qiita_marker/cmark/.*']
27
+
28
+ s.add_development_dependency 'awesome_print'
29
+ s.add_development_dependency 'json', '~> 2.3'
30
+ s.add_development_dependency 'minitest', '~> 5.6'
31
+ s.add_development_dependency 'minitest-focus', '~> 1.1'
32
+ s.add_development_dependency 'rake'
33
+ s.add_development_dependency 'rake-compiler', '~> 0.9'
34
+ s.add_development_dependency 'rdoc', '~> 6.2'
35
+ s.add_development_dependency 'rubocop'
36
+ s.add_development_dependency 'rubocop-standard'
37
+ s.metadata = {
38
+ 'rubygems_mfa_required' => 'true'
39
+ }
40
+ end
data/test/benchmark.rb ADDED
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'qiita_marker'
4
+ require 'github/markdown'
5
+ require 'redcarpet'
6
+ require 'kramdown'
7
+ require 'benchmark'
8
+
9
+ def dobench(name, &blk)
10
+ puts name
11
+ puts Benchmark.measure(&blk)
12
+ end
13
+
14
+ benchinput = File.open('test/benchinput.md', 'r').read
15
+
16
+ printf("input size = %<bytes>d bytes\n\n", benchinput.bytesize)
17
+
18
+ dobench('redcarpet') do
19
+ Redcarpet::Markdown.new(Redcarpet::Render::HTML, autolink: false, tables: false).render(benchinput)
20
+ end
21
+
22
+ dobench('qiita_marker with to_html') do
23
+ QiitaMarker.render_html(benchinput)
24
+ end
25
+
26
+ dobench('qiita_marker with ruby HtmlRenderer') do
27
+ QiitaMarker::HtmlRenderer.new.render(QiitaMarker.render_doc(benchinput))
28
+ end
29
+
30
+ dobench('kramdown') do
31
+ Kramdown::Document.new(benchinput).to_html(benchinput)
32
+ end
@@ -0,0 +1 @@
1
+ This curly quote “makes qiita_marker throw an exception”.
@@ -0,0 +1,10 @@
1
+ ## Try CommonMark
2
+
3
+ You can try CommonMark here. This dingus is powered by
4
+ [commonmark.js](https://github.com/jgm/commonmark.js), the
5
+ JavaScript reference implementation.
6
+
7
+ 1. item one
8
+ 2. item two
9
+ - sublist
10
+ - sublist
@@ -0,0 +1 @@
1
+ I am **strong**
@@ -0,0 +1,10 @@
1
+ One extension:
2
+
3
+ | a | b |
4
+ | --- | --- |
5
+ | c | d |
6
+ | **x** | |
7
+
8
+ Another extension:
9
+
10
+ ~~hi~~
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'test_helper'
4
+
5
+ class TestAttributes < Minitest::Test
6
+ def setup
7
+ contents = fixtures_file('dingus.md')
8
+ @doc = QiitaMarker.render_doc(contents.strip)
9
+ end
10
+
11
+ def test_sourcepos
12
+ sourcepos = []
13
+
14
+ @doc.walk do |node|
15
+ sourcepos << node.sourcepos
16
+ end
17
+
18
+ sourcepos.delete_if { |h| h.values.all?(&:zero?) }
19
+
20
+ result = [{ start_line: 1, start_column: 1, end_line: 10, end_column: 12 }, { start_line: 1, start_column: 1, end_line: 1, end_column: 17 }, { start_line: 1, start_column: 4, end_line: 1, end_column: 17 }, { start_line: 3, start_column: 1, end_line: 5, end_column: 36 }, { start_line: 3, start_column: 1, end_line: 3, end_column: 55 }, { start_line: 4, start_column: 1, end_line: 4, end_column: 53 }, { start_line: 4, start_column: 2, end_line: 4, end_column: 14 }, { start_line: 4, start_column: 54, end_line: 4, end_column: 58 }, { start_line: 5, start_column: 1, end_line: 5, end_column: 36 }, { start_line: 7, start_column: 1, end_line: 10, end_column: 12 }, { start_line: 7, start_column: 1, end_line: 7, end_column: 11 }, { start_line: 7, start_column: 4, end_line: 7, end_column: 11 }, { start_line: 7, start_column: 4, end_line: 7, end_column: 11 }, { start_line: 8, start_column: 1, end_line: 10, end_column: 12 }, { start_line: 8, start_column: 4, end_line: 8, end_column: 11 }, { start_line: 8, start_column: 4, end_line: 8, end_column: 11 }, { start_line: 9, start_column: 4, end_line: 10, end_column: 12 }, { start_line: 9, start_column: 4, end_line: 9, end_column: 12 }, { start_line: 9, start_column: 6, end_line: 9, end_column: 12 }, { start_line: 9, start_column: 6, end_line: 9, end_column: 12 }, { start_line: 10, start_column: 4, end_line: 10, end_column: 12 }, { start_line: 10, start_column: 6, end_line: 10, end_column: 12 }, { start_line: 10, start_column: 6, end_line: 10, end_column: 12 }]
21
+
22
+ assert_equal result, sourcepos
23
+ end
24
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'test_helper'
4
+
5
+ class TestBasics < Minitest::Test
6
+ def setup
7
+ @doc = QiitaMarker.render_doc('Hi *there*')
8
+ end
9
+
10
+ def test_to_html
11
+ assert_equal "<p>Hi <em>there</em></p>\n", @doc.to_html
12
+ end
13
+
14
+ def test_markdown_to_html
15
+ html = QiitaMarker.render_html('Hi *there*')
16
+ assert_equal "<p>Hi <em>there</em></p>\n", html
17
+ end
18
+
19
+ # basic test that just checks if every option is accepted & no errors are thrown
20
+ def test_accept_every_option
21
+ text = "Hello **world** -- how are _you_ today? I'm ~~fine~~, ~yourself~?"
22
+ parse_opt = %i[SOURCEPOS UNSAFE VALIDATE_UTF8 SMART LIBERAL_HTML_TAG FOOTNOTES STRIKETHROUGH_DOUBLE_TILDE]
23
+ render_opt = parse_opt + %i[HARDBREAKS NOBREAKS GITHUB_PRE_LANG TABLE_PREFER_STYLE_ATTRIBUTES FULL_INFO_STRING]
24
+
25
+ extensions = %i[table tasklist strikethrough autolink tagfilter]
26
+
27
+ assert_equal "<p>Hello <strong>world</strong> – how are <em>you</em> today? I’m <del>fine</del>, ~yourself~?</p>\n", QiitaMarker.render_doc(text, parse_opt, extensions).to_html
28
+
29
+ # NOTE: how tho the doc returned has sourcepos info, by default the renderer
30
+ # won't emit it. for that we need to pass in the render opt
31
+ assert_equal "<p data-sourcepos=\"1:1-1:65\">Hello <strong>world</strong> – how are <em>you</em> today? I’m <del>fine</del>, ~yourself~?</p>\n", QiitaMarker.render_doc(text, parse_opt, extensions).to_html(render_opt, extensions)
32
+
33
+ assert_equal "<p data-sourcepos=\"1:1-1:65\">Hello <strong>world</strong> – how are <em>you</em> today? I’m <del>fine</del>, ~yourself~?</p>\n", QiitaMarker.render_html(text, parse_opt, extensions)
34
+ end
35
+ end
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'test_helper'
4
+
5
+ class TestCommands < Minitest::Test
6
+ def test_basic
7
+ out = make_bin('strong.md')
8
+ assert_equal('<p>I am <strong>strong</strong></p>', out)
9
+ end
10
+
11
+ def test_does_not_have_extensions
12
+ out = make_bin('table.md')
13
+ assert_includes out, '| a'
14
+ refute_includes out, '<p><del>hi</del>'
15
+ refute_includes out, '<table> <tr> <th> a </th> <td> c </td>'
16
+ end
17
+
18
+ def test_understands_extensions
19
+ out = make_bin('table.md', '--extension=table')
20
+ refute_includes out, '| a'
21
+ refute_includes out, '<p><del>hi</del>'
22
+ %w[<table> <tr> <th> a </th> <td> c </td>].each { |html| assert_includes out, html }
23
+ end
24
+
25
+ def test_understands_multiple_extensions
26
+ out = make_bin('table.md', '--extension=table,strikethrough')
27
+ refute_includes out, '| a'
28
+ assert_includes out, '<p><del>hi</del>'
29
+ %w[<table> <tr> <th> a </th> <td> c </td>].each { |html| assert_includes out, html }
30
+ end
31
+
32
+ def test_understands_html_format_with_renderer_and_extensions
33
+ out = make_bin('table.md', '--to=html --extension=table,strikethrough --html-renderer')
34
+ refute_includes out, '| a'
35
+ assert_includes out, '<p><del>hi</del>'
36
+ %w[<table> <tr> <th> a </th> <td> c </td>].each { |html| assert_includes out, html }
37
+ end
38
+
39
+ def test_understands_xml_format
40
+ out = make_bin('strong.md', '--to=xml')
41
+ assert_includes out, '<?xml version="1.0" encoding="UTF-8"?>'
42
+ assert_includes out, '<text xml:space="preserve">strong</text>'
43
+ end
44
+
45
+ def test_understands_commonmark_format
46
+ out = make_bin('strong.md', '--to=commonmark')
47
+ assert_equal('I am **strong**', out)
48
+ end
49
+
50
+ def test_understands_plaintext_format
51
+ out = make_bin('strong.md', '--to=plaintext')
52
+ assert_equal('I am strong', out)
53
+ end
54
+
55
+ def test_aborts_invalid_format
56
+ _out, err = capture_subprocess_io do
57
+ make_bin('strong.md', '--to=unknown')
58
+ end
59
+
60
+ assert_match "format 'unknown' not found", err
61
+ end
62
+
63
+ def test_aborts_format_and_html_renderer_combinations
64
+ (QiitaMarker::Config::OPTS[:format] - [:html]).each do |format|
65
+ _out, err = capture_subprocess_io do
66
+ make_bin('strong.md', "--to=#{format} --html-renderer")
67
+ end
68
+
69
+ assert_match "format '#{format}' does not support using the HtmlRenderer renderer", err
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'test_helper'
4
+
5
+ class TestCommonmark < Minitest::Test
6
+ HTML_COMMENT = /<!--.*?-->\s?/.freeze
7
+
8
+ def setup
9
+ @markdown = <<~MD
10
+ Hi *there*!
11
+
12
+ 1. I am a numeric list.
13
+ 2. I continue the list.
14
+ * Suddenly, an unordered list!
15
+ * What fun!
16
+
17
+ Okay, _enough_.
18
+
19
+ | a | b |
20
+ | --- | --- |
21
+ | c | d |
22
+ MD
23
+ end
24
+
25
+ def render_doc(doc)
26
+ QiitaMarker.render_doc(doc, :DEFAULT, %i[table])
27
+ end
28
+
29
+ def test_to_commonmark
30
+ compare = render_doc(@markdown).to_commonmark
31
+
32
+ assert_equal \
33
+ render_doc(@markdown).to_html.squeeze(' ').gsub(HTML_COMMENT, ''),
34
+ render_doc(compare).to_html.squeeze(' ').gsub(HTML_COMMENT, '')
35
+ end
36
+ end
data/test/test_doc.rb ADDED
@@ -0,0 +1,130 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'test_helper'
4
+
5
+ class TestDocNode < Minitest::Test
6
+ def setup
7
+ @doc = QiitaMarker.render_doc('Hi *there*. This has __many nodes__!')
8
+ @first_child = @doc.first_child
9
+ @last_child = @doc.last_child
10
+ @link = QiitaMarker.render_doc('[GitHub](https://www.github.com)').first_child.first_child
11
+ @image = QiitaMarker.render_doc('![alt text](https://github.com/favicon.ico "Favicon")')
12
+ @image = @image.first_child.first_child
13
+ @header = QiitaMarker.render_doc('### Header Three').first_child
14
+ @ul_list = QiitaMarker.render_doc("* Bullet\n*Bullet").first_child
15
+ @ol_list = QiitaMarker.render_doc("1. One\n2. Two").first_child
16
+ @fence = QiitaMarker.render_doc("``` ruby\nputs 'wow'\n```").first_child
17
+ end
18
+
19
+ def test_get_type
20
+ assert_equal(:document, @doc.type)
21
+ end
22
+
23
+ def test_get_type_string
24
+ assert_equal('document', @doc.type_string)
25
+ end
26
+
27
+ def test_get_first_child
28
+ assert_equal(:paragraph, @first_child.type)
29
+ end
30
+
31
+ def test_get_next
32
+ assert_equal(:emph, @first_child.first_child.next.type)
33
+ end
34
+
35
+ def test_insert_before
36
+ paragraph = Node.new(:paragraph)
37
+ assert(@first_child.insert_before(paragraph))
38
+ assert_match "<p></p>\n<p>Hi <em>there</em>.", @doc.to_html
39
+ end
40
+
41
+ def test_insert_after
42
+ paragraph = Node.new(:paragraph)
43
+ assert(@first_child.insert_after(paragraph))
44
+ assert_match "<strong>many nodes</strong>!</p>\n<p></p>\n", @doc.to_html
45
+ end
46
+
47
+ def test_prepend_child
48
+ code = Node.new(:code)
49
+ assert(@first_child.prepend_child(code))
50
+ assert_match '<p><code></code>Hi <em>there</em>.', @doc.to_html
51
+ end
52
+
53
+ def test_append_child
54
+ strong = Node.new(:strong)
55
+ assert(@first_child.append_child(strong))
56
+ assert_match "!<strong></strong></p>\n", @doc.to_html
57
+ end
58
+
59
+ def test_get_last_child
60
+ assert_equal(:paragraph, @last_child.type)
61
+ end
62
+
63
+ def test_get_parent
64
+ assert_equal(:paragraph, @first_child.first_child.next.parent.type)
65
+ end
66
+
67
+ def test_get_previous
68
+ assert_equal(:text, @first_child.first_child.next.previous.type)
69
+ end
70
+
71
+ def test_get_url
72
+ assert_equal('https://www.github.com', @link.url)
73
+ end
74
+
75
+ def test_set_url
76
+ assert_equal('https://www.mozilla.org', @link.url = 'https://www.mozilla.org')
77
+ end
78
+
79
+ def test_get_title
80
+ assert_equal('Favicon', @image.title)
81
+ end
82
+
83
+ def test_set_title
84
+ assert_equal('Octocat', @image.title = 'Octocat')
85
+ end
86
+
87
+ def test_get_header_level
88
+ assert_equal(3, @header.header_level)
89
+ end
90
+
91
+ def test_set_header_level
92
+ assert_equal(6, @header.header_level = 6)
93
+ end
94
+
95
+ def test_get_list_type
96
+ assert_equal(:bullet_list, @ul_list.list_type)
97
+ assert_equal(:ordered_list, @ol_list.list_type)
98
+ end
99
+
100
+ def test_set_list_type
101
+ assert_equal(:ordered_list, @ul_list.list_type = :ordered_list)
102
+ assert_equal(:bullet_list, @ol_list.list_type = :bullet_list)
103
+ end
104
+
105
+ def test_get_list_start
106
+ assert_equal(1, @ol_list.list_start)
107
+ end
108
+
109
+ def test_set_list_start
110
+ assert_equal(8, @ol_list.list_start = 8)
111
+ end
112
+
113
+ def test_get_list_tight
114
+ assert(@ul_list.list_tight)
115
+ assert(@ol_list.list_tight)
116
+ end
117
+
118
+ def test_set_list_tight
119
+ refute(@ul_list.list_tight = false)
120
+ refute(@ol_list.list_tight = false)
121
+ end
122
+
123
+ def test_get_fence_info
124
+ assert_equal('ruby', @fence.fence_info)
125
+ end
126
+
127
+ def test_set_fence_info
128
+ assert_equal('javascript', @fence.fence_info = 'javascript')
129
+ end
130
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'test_helper'
4
+
5
+ class TestEncoding < Minitest::Test
6
+ # see http://git.io/vq4FR
7
+ def test_encoding
8
+ contents = fixtures_file('curly.md')
9
+ doc = QiitaMarker.render_doc(contents, :SMART)
10
+ render = doc.to_html
11
+ assert_equal('<p>This curly quote “makes qiita_marker throw an exception”.</p>', render.rstrip)
12
+
13
+ render = doc.to_xml
14
+ assert_includes(render, '<text xml:space="preserve">This curly quote “makes qiita_marker throw an exception”.</text>')
15
+ end
16
+
17
+ def test_string_content_is_utf8
18
+ doc = QiitaMarker.render_doc('Hi *there*')
19
+ text = doc.first_child.last_child.first_child
20
+ assert_equal('there', text.string_content)
21
+ assert_equal('UTF-8', text.string_content.encoding.name)
22
+ end
23
+ end