commonmarker 0.17.13 → 0.23.4
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of commonmarker might be problematic. Click here for more details.
- checksums.yaml +5 -5
- data/README.md +94 -18
- data/Rakefile +24 -5
- data/bin/commonmarker +107 -47
- data/commonmarker.gemspec +18 -15
- data/ext/commonmarker/autolink.c +10 -6
- data/ext/commonmarker/blocks.c +102 -31
- data/ext/commonmarker/buffer.c +0 -1
- data/ext/commonmarker/chunk.h +0 -1
- data/ext/commonmarker/cmark-gfm-core-extensions.h +29 -0
- data/ext/commonmarker/cmark-gfm-extension_api.h +19 -2
- data/ext/commonmarker/cmark-gfm.h +19 -5
- data/ext/commonmarker/cmark-gfm_version.h +2 -2
- data/ext/commonmarker/commonmark.c +33 -12
- data/ext/commonmarker/commonmarker.c +209 -100
- data/ext/commonmarker/core-extensions.c +2 -0
- data/ext/commonmarker/ext_scanners.c +622 -684
- data/ext/commonmarker/ext_scanners.h +2 -0
- data/ext/commonmarker/extconf.rb +3 -1
- data/ext/commonmarker/footnotes.c +23 -0
- data/ext/commonmarker/footnotes.h +2 -0
- data/ext/commonmarker/houdini_href_e.c +1 -1
- data/ext/commonmarker/html.c +46 -25
- data/ext/commonmarker/inlines.c +127 -30
- data/ext/commonmarker/iterator.h +0 -1
- data/ext/commonmarker/map.h +0 -1
- data/ext/commonmarker/node.c +17 -3
- data/ext/commonmarker/node.h +9 -0
- data/ext/commonmarker/parser.h +2 -1
- data/ext/commonmarker/plaintext.c +22 -0
- data/ext/commonmarker/render.c +18 -15
- data/ext/commonmarker/render.h +0 -1
- data/ext/commonmarker/scanners.c +779 -953
- data/ext/commonmarker/scanners.h +0 -2
- data/ext/commonmarker/strikethrough.c +4 -1
- data/ext/commonmarker/syntax_extension.c +10 -0
- data/ext/commonmarker/syntax_extension.h +2 -0
- data/ext/commonmarker/table.c +178 -31
- data/ext/commonmarker/tasklist.c +156 -0
- data/ext/commonmarker/tasklist.h +8 -0
- data/ext/commonmarker/xml.c +9 -2
- data/lib/commonmarker/config.rb +41 -38
- data/lib/commonmarker/errors.rb +12 -0
- data/lib/commonmarker/node/inspect.rb +15 -17
- data/lib/commonmarker/node.rb +14 -2
- data/lib/commonmarker/renderer/html_renderer.rb +45 -36
- data/lib/commonmarker/renderer.rb +16 -10
- data/lib/commonmarker/version.rb +3 -1
- data/lib/commonmarker.rb +8 -7
- data/test/benchmark.rb +26 -21
- data/test/fixtures/strong.md +1 -0
- data/test/fixtures/table.md +10 -0
- data/test/test_attributes.rb +5 -3
- data/test/test_basics.rb +19 -0
- data/test/test_commands.rb +72 -0
- data/test/test_commonmark.rb +15 -13
- data/test/test_doc.rb +31 -29
- data/test/test_encoding.rb +9 -5
- data/test/test_extensions.rb +66 -73
- data/test/test_footnotes.rb +47 -12
- data/test/test_gc.rb +6 -2
- data/test/test_helper.rb +25 -15
- data/test/test_linebreaks.rb +2 -0
- data/test/test_maliciousness.rb +189 -190
- data/test/test_node.rb +12 -12
- data/test/test_options.rb +17 -15
- data/test/test_pathological_inputs.rb +14 -12
- data/test/test_plaintext.rb +23 -21
- data/test/test_renderer.rb +29 -10
- data/test/test_smartpunct.rb +7 -2
- data/test/test_spec.rb +7 -4
- data/test/test_tasklists.rb +43 -0
- data/test/test_xml.rb +107 -0
- metadata +74 -30
data/lib/commonmarker/config.rb
CHANGED
@@ -1,49 +1,52 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
2
3
|
module CommonMarker
|
3
4
|
# For Ruby::Enum, these must be classes, not modules
|
4
5
|
module Config
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
6
|
+
# See https://github.com/github/cmark-gfm/blob/master/src/cmark-gfm.h#L673
|
7
|
+
OPTS = {
|
8
|
+
parse: {
|
9
|
+
DEFAULT: 0,
|
10
|
+
SOURCEPOS: (1 << 1),
|
11
|
+
UNSAFE: (1 << 17),
|
12
|
+
VALIDATE_UTF8: (1 << 9),
|
13
|
+
SMART: (1 << 10),
|
14
|
+
LIBERAL_HTML_TAG: (1 << 12),
|
15
|
+
FOOTNOTES: (1 << 13),
|
16
|
+
STRIKETHROUGH_DOUBLE_TILDE: (1 << 14)
|
17
|
+
}.freeze,
|
18
|
+
render: {
|
19
|
+
DEFAULT: 0,
|
20
|
+
SOURCEPOS: (1 << 1),
|
21
|
+
HARDBREAKS: (1 << 2),
|
22
|
+
UNSAFE: (1 << 17),
|
23
|
+
NOBREAKS: (1 << 4),
|
24
|
+
VALIDATE_UTF8: (1 << 9),
|
25
|
+
SMART: (1 << 10),
|
26
|
+
GITHUB_PRE_LANG: (1 << 11),
|
27
|
+
LIBERAL_HTML_TAG: (1 << 12),
|
28
|
+
FOOTNOTES: (1 << 13),
|
29
|
+
STRIKETHROUGH_DOUBLE_TILDE: (1 << 14),
|
30
|
+
TABLE_PREFER_STYLE_ATTRIBUTES: (1 << 15),
|
31
|
+
FULL_INFO_STRING: (1 << 16)
|
32
|
+
}.freeze,
|
33
|
+
format: %i[html xml commonmark plaintext].freeze
|
34
|
+
}.freeze
|
28
35
|
|
29
36
|
def self.process_options(option, type)
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
37
|
+
case option
|
38
|
+
when Symbol
|
39
|
+
OPTS.fetch(type).fetch(option)
|
40
|
+
when Array
|
41
|
+
raise TypeError if option.none?
|
42
|
+
|
36
43
|
# neckbearding around. the map will both check the opts and then bitwise-OR it
|
37
|
-
|
44
|
+
OPTS.fetch(type).fetch_values(*option).inject(0, :|)
|
38
45
|
else
|
39
|
-
raise TypeError,
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
def self.check_option(option, type)
|
44
|
-
unless type.keys.include?(option)
|
45
|
-
raise TypeError, "option ':#{option}' does not exist for #{type}"
|
46
|
+
raise TypeError, "option type must be a valid symbol or array of symbols within the #{name}::OPTS[:#{type}] context"
|
46
47
|
end
|
48
|
+
rescue KeyError => e
|
49
|
+
raise TypeError, "option ':#{e.key}' does not exist for #{name}::OPTS[:#{type}]"
|
47
50
|
end
|
48
51
|
end
|
49
52
|
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'commonmarker/node/inspect'
|
4
|
+
|
5
|
+
module CommonMarker
|
6
|
+
class RenderError < StandardError
|
7
|
+
PREAMBLE = 'There was an error rendering'
|
8
|
+
def initialize(error)
|
9
|
+
super("#{PREAMBLE}: #{error.class} #{error.message}")
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -8,13 +8,13 @@ module CommonMarker
|
|
8
8
|
PP_INDENT_SIZE = 2
|
9
9
|
|
10
10
|
def inspect
|
11
|
-
PP.pp(self,
|
11
|
+
PP.pp(self, +'', Float::INFINITY)
|
12
12
|
end
|
13
13
|
|
14
|
-
# @param [PrettyPrint] pp
|
15
|
-
def pretty_print(
|
16
|
-
|
17
|
-
|
14
|
+
# @param printer [PrettyPrint] pp
|
15
|
+
def pretty_print(printer)
|
16
|
+
printer.group(PP_INDENT_SIZE, "#<#{self.class}(#{type}):", '>') do
|
17
|
+
printer.breakable
|
18
18
|
|
19
19
|
attrs = %i[
|
20
20
|
sourcepos
|
@@ -27,29 +27,27 @@ module CommonMarker
|
|
27
27
|
list_tight
|
28
28
|
fence_info
|
29
29
|
].map do |name|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
nil
|
34
|
-
end
|
30
|
+
[name, __send__(name)]
|
31
|
+
rescue NodeError
|
32
|
+
nil
|
35
33
|
end.compact
|
36
34
|
|
37
|
-
|
38
|
-
|
39
|
-
|
35
|
+
printer.seplist(attrs) do |name, value|
|
36
|
+
printer.text "#{name}="
|
37
|
+
printer.pp value
|
40
38
|
end
|
41
39
|
|
42
40
|
if first_child
|
43
|
-
|
44
|
-
|
41
|
+
printer.breakable
|
42
|
+
printer.group(PP_INDENT_SIZE) do
|
45
43
|
children = []
|
46
44
|
node = first_child
|
47
45
|
while node
|
48
46
|
children << node
|
49
47
|
node = node.next
|
50
48
|
end
|
51
|
-
|
52
|
-
|
49
|
+
printer.text 'children='
|
50
|
+
printer.pp children
|
53
51
|
end
|
54
52
|
end
|
55
53
|
end
|
data/lib/commonmarker/node.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'commonmarker/node/inspect'
|
2
4
|
|
3
5
|
module CommonMarker
|
@@ -9,7 +11,7 @@ module CommonMarker
|
|
9
11
|
#
|
10
12
|
# blk - A {Proc} representing the action to take for each child
|
11
13
|
def walk(&block)
|
12
|
-
return enum_for(:walk) unless
|
14
|
+
return enum_for(:walk) unless block
|
13
15
|
|
14
16
|
yield self
|
15
17
|
each do |child|
|
@@ -28,6 +30,16 @@ module CommonMarker
|
|
28
30
|
_render_html(opts, extensions).force_encoding('utf-8')
|
29
31
|
end
|
30
32
|
|
33
|
+
# Public: Convert the node to an XML string.
|
34
|
+
#
|
35
|
+
# options - A {Symbol} or {Array of Symbol}s indicating the render options
|
36
|
+
#
|
37
|
+
# Returns a {String}.
|
38
|
+
def to_xml(options = :DEFAULT)
|
39
|
+
opts = Config.process_options(options, :render)
|
40
|
+
_render_xml(opts).force_encoding('utf-8')
|
41
|
+
end
|
42
|
+
|
31
43
|
# Public: Convert the node to a CommonMark string.
|
32
44
|
#
|
33
45
|
# options - A {Symbol} or {Array of Symbol}s indicating the render options
|
@@ -51,7 +63,7 @@ module CommonMarker
|
|
51
63
|
end
|
52
64
|
|
53
65
|
# Public: Iterate over the children (if any) of the current pointer.
|
54
|
-
def each
|
66
|
+
def each
|
55
67
|
return enum_for(:each) unless block_given?
|
56
68
|
|
57
69
|
child = first_child
|
@@ -1,14 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module CommonMarker
|
2
4
|
class HtmlRenderer < Renderer
|
3
|
-
def render(node)
|
4
|
-
super(node)
|
5
|
-
end
|
6
|
-
|
7
5
|
def document(_)
|
8
6
|
super
|
9
|
-
if @written_footnote_ix
|
10
|
-
out("</ol>\n</section>\n")
|
11
|
-
end
|
7
|
+
out("</ol>\n</section>\n") if @written_footnote_ix
|
12
8
|
end
|
13
9
|
|
14
10
|
def header(node)
|
@@ -26,7 +22,7 @@ module CommonMarker
|
|
26
22
|
container("<p#{sourcepos(node)}>", '</p>') do
|
27
23
|
out(:children)
|
28
24
|
if node.parent.type == :footnote_definition && node.next.nil?
|
29
|
-
out(
|
25
|
+
out(' ')
|
30
26
|
out_footnote_backref
|
31
27
|
end
|
32
28
|
end
|
@@ -60,12 +56,24 @@ module CommonMarker
|
|
60
56
|
|
61
57
|
def list_item(node)
|
62
58
|
block do
|
63
|
-
|
59
|
+
tasklist_data = tasklist(node)
|
60
|
+
container("<li#{sourcepos(node)}#{tasklist_data}>#{' ' if tasklist?(node)}", '</li>') do
|
64
61
|
out(:children)
|
65
62
|
end
|
66
63
|
end
|
67
64
|
end
|
68
65
|
|
66
|
+
def tasklist(node)
|
67
|
+
return '' unless tasklist?(node)
|
68
|
+
|
69
|
+
state = if checked?(node)
|
70
|
+
'checked="" disabled=""'
|
71
|
+
else
|
72
|
+
'disabled=""'
|
73
|
+
end
|
74
|
+
"><input type=\"checkbox\" #{state} /"
|
75
|
+
end
|
76
|
+
|
69
77
|
def blockquote(node)
|
70
78
|
block do
|
71
79
|
container("<blockquote#{sourcepos(node)}>\n", '</blockquote>') do
|
@@ -84,9 +92,7 @@ module CommonMarker
|
|
84
92
|
block do
|
85
93
|
if option_enabled?(:GITHUB_PRE_LANG)
|
86
94
|
out("<pre#{sourcepos(node)}")
|
87
|
-
if node.fence_info && !node.fence_info.empty?
|
88
|
-
out(' lang="', node.fence_info.split(/\s+/)[0], '"')
|
89
|
-
end
|
95
|
+
out(' lang="', node.fence_info.split(/\s+/)[0], '"') if node.fence_info && !node.fence_info.empty?
|
90
96
|
out('><code>')
|
91
97
|
else
|
92
98
|
out("<pre#{sourcepos(node)}><code")
|
@@ -103,19 +109,19 @@ module CommonMarker
|
|
103
109
|
|
104
110
|
def html(node)
|
105
111
|
block do
|
106
|
-
if option_enabled?(:
|
107
|
-
out('<!-- raw HTML omitted -->')
|
108
|
-
else
|
112
|
+
if option_enabled?(:UNSAFE)
|
109
113
|
out(tagfilter(node.string_content))
|
114
|
+
else
|
115
|
+
out('<!-- raw HTML omitted -->')
|
110
116
|
end
|
111
117
|
end
|
112
118
|
end
|
113
119
|
|
114
120
|
def inline_html(node)
|
115
|
-
if option_enabled?(:
|
116
|
-
out('<!-- raw HTML omitted -->')
|
117
|
-
else
|
121
|
+
if option_enabled?(:UNSAFE)
|
118
122
|
out(tagfilter(node.string_content))
|
123
|
+
else
|
124
|
+
out('<!-- raw HTML omitted -->')
|
119
125
|
end
|
120
126
|
end
|
121
127
|
|
@@ -129,9 +135,7 @@ module CommonMarker
|
|
129
135
|
|
130
136
|
def link(node)
|
131
137
|
out('<a href="', node.url.nil? ? '' : escape_href(node.url), '"')
|
132
|
-
if node.title && !node.title.empty?
|
133
|
-
out(' title="', escape_html(node.title), '"')
|
134
|
-
end
|
138
|
+
out(' title="', escape_html(node.title), '"') if node.title && !node.title.empty?
|
135
139
|
out('>', :children, '</a>')
|
136
140
|
end
|
137
141
|
|
@@ -140,9 +144,7 @@ module CommonMarker
|
|
140
144
|
plain do
|
141
145
|
out(' alt="', :children, '"')
|
142
146
|
end
|
143
|
-
if node.title && !node.title.empty?
|
144
|
-
out(' title="', escape_html(node.title), '"')
|
145
|
-
end
|
147
|
+
out(' title="', escape_html(node.title), '"') if node.title && !node.title.empty?
|
146
148
|
out(' />')
|
147
149
|
end
|
148
150
|
|
@@ -156,7 +158,7 @@ module CommonMarker
|
|
156
158
|
out('</code>')
|
157
159
|
end
|
158
160
|
|
159
|
-
def linebreak(
|
161
|
+
def linebreak(_node)
|
160
162
|
out("<br />\n")
|
161
163
|
end
|
162
164
|
|
@@ -197,9 +199,9 @@ module CommonMarker
|
|
197
199
|
|
198
200
|
def table_cell(node)
|
199
201
|
align = case @alignments[@column_index]
|
200
|
-
when :left
|
201
|
-
when :right
|
202
|
-
when :center
|
202
|
+
when :left then ' align="left"'
|
203
|
+
when :right then ' align="right"'
|
204
|
+
when :center then ' align="center"'
|
203
205
|
else; ''
|
204
206
|
end
|
205
207
|
out(@in_header ? "<th#{align}#{sourcepos(node)}>" : "<td#{align}#{sourcepos(node)}>", :children, @in_header ? "</th>\n" : "</td>\n")
|
@@ -215,29 +217,36 @@ module CommonMarker
|
|
215
217
|
end
|
216
218
|
|
217
219
|
def footnote_definition(_)
|
218
|
-
|
220
|
+
unless @footnote_ix
|
219
221
|
out("<section class=\"footnotes\">\n<ol>\n")
|
220
222
|
@footnote_ix = 0
|
221
223
|
end
|
222
224
|
|
223
225
|
@footnote_ix += 1
|
224
|
-
out("<li id=\"fn
|
225
|
-
if out_footnote_backref
|
226
|
-
out("\n")
|
227
|
-
end
|
226
|
+
out("<li id=\"fn#{@footnote_ix}\">\n", :children)
|
227
|
+
out("\n") if out_footnote_backref
|
228
228
|
out("</li>\n")
|
229
|
-
|
230
|
-
|
229
|
+
# </ol>
|
230
|
+
# </section>
|
231
231
|
end
|
232
232
|
|
233
233
|
private
|
234
234
|
|
235
235
|
def out_footnote_backref
|
236
236
|
return false if @written_footnote_ix == @footnote_ix
|
237
|
+
|
237
238
|
@written_footnote_ix = @footnote_ix
|
238
239
|
|
239
|
-
out("<a href=\"#fnref
|
240
|
+
out("<a href=\"#fnref#{@footnote_ix}\" class=\"footnote-backref\">↩</a>")
|
240
241
|
true
|
241
242
|
end
|
243
|
+
|
244
|
+
def tasklist?(node)
|
245
|
+
node.type_string == 'tasklist'
|
246
|
+
end
|
247
|
+
|
248
|
+
def checked?(node)
|
249
|
+
node.tasklist_item_checked?
|
250
|
+
end
|
242
251
|
end
|
243
252
|
end
|
@@ -1,12 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'set'
|
2
4
|
require 'stringio'
|
3
5
|
|
4
6
|
module CommonMarker
|
5
7
|
class Renderer
|
6
8
|
attr_accessor :in_tight, :warnings, :in_plain
|
9
|
+
|
7
10
|
def initialize(options: :DEFAULT, extensions: [])
|
8
11
|
@opts = Config.process_options(options, :render)
|
9
|
-
@stream = StringIO.new(
|
12
|
+
@stream = StringIO.new(+'')
|
10
13
|
@need_blocksep = false
|
11
14
|
@warnings = Set.new []
|
12
15
|
@in_tight = false
|
@@ -16,11 +19,12 @@ module CommonMarker
|
|
16
19
|
|
17
20
|
def out(*args)
|
18
21
|
args.each do |arg|
|
19
|
-
|
22
|
+
case arg
|
23
|
+
when :children
|
20
24
|
@node.each { |child| out(child) }
|
21
|
-
|
25
|
+
when Array
|
22
26
|
arg.each { |x| render(x) }
|
23
|
-
|
27
|
+
when Node
|
24
28
|
render(arg)
|
25
29
|
else
|
26
30
|
@stream.write(arg)
|
@@ -32,7 +36,7 @@ module CommonMarker
|
|
32
36
|
@node = node
|
33
37
|
if node.type == :document
|
34
38
|
document(node)
|
35
|
-
|
39
|
+
@stream.string
|
36
40
|
elsif @in_plain && node.type != :text && node.type != :softbreak
|
37
41
|
node.each { |child| render(child) }
|
38
42
|
else
|
@@ -53,11 +57,11 @@ module CommonMarker
|
|
53
57
|
code_block(node)
|
54
58
|
end
|
55
59
|
|
56
|
-
def reference_def(_node)
|
57
|
-
end
|
60
|
+
def reference_def(_node); end
|
58
61
|
|
59
62
|
def cr
|
60
63
|
return if @stream.string.empty? || @stream.string[-1] == "\n"
|
64
|
+
|
61
65
|
out("\n")
|
62
66
|
end
|
63
67
|
|
@@ -109,21 +113,23 @@ module CommonMarker
|
|
109
113
|
)
|
110
114
|
(?=\s|>|/>)
|
111
115
|
}xi,
|
112
|
-
'<\1'
|
116
|
+
'<\1'
|
117
|
+
)
|
113
118
|
else
|
114
119
|
str
|
115
120
|
end
|
116
121
|
end
|
117
122
|
|
118
123
|
def sourcepos(node)
|
119
|
-
return
|
124
|
+
return '' unless option_enabled?(:SOURCEPOS)
|
125
|
+
|
120
126
|
s = node.sourcepos
|
121
127
|
" data-sourcepos=\"#{s[:start_line]}:#{s[:start_column]}-" \
|
122
128
|
"#{s[:end_line]}:#{s[:end_column]}\""
|
123
129
|
end
|
124
130
|
|
125
131
|
def option_enabled?(opt)
|
126
|
-
(@opts & CommonMarker::Config::
|
132
|
+
(@opts & CommonMarker::Config::OPTS.dig(:render, opt)) != 0
|
127
133
|
end
|
128
134
|
end
|
129
135
|
end
|
data/lib/commonmarker/version.rb
CHANGED
data/lib/commonmarker.rb
CHANGED
@@ -1,4 +1,6 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
2
4
|
require 'commonmarker/commonmarker'
|
3
5
|
require 'commonmarker/config'
|
4
6
|
require 'commonmarker/node'
|
@@ -8,8 +10,7 @@ require 'commonmarker/version'
|
|
8
10
|
|
9
11
|
begin
|
10
12
|
require 'awesome_print'
|
11
|
-
rescue LoadError; end
|
12
|
-
|
13
|
+
rescue LoadError; end # rubocop:disable Lint/SuppressedException
|
13
14
|
module CommonMarker
|
14
15
|
# Public: Parses a Markdown string into an HTML string.
|
15
16
|
#
|
@@ -19,11 +20,10 @@ module CommonMarker
|
|
19
20
|
#
|
20
21
|
# Returns a {String} of converted HTML.
|
21
22
|
def self.render_html(text, options = :DEFAULT, extensions = [])
|
22
|
-
|
23
|
+
raise TypeError, "text must be a String; got a #{text.class}!" unless text.is_a?(String)
|
24
|
+
|
23
25
|
opts = Config.process_options(options, :render)
|
24
|
-
text
|
25
|
-
html = Node.markdown_to_html(text, opts, extensions)
|
26
|
-
html.force_encoding('UTF-8')
|
26
|
+
Node.markdown_to_html(text.encode('UTF-8'), opts, extensions)
|
27
27
|
end
|
28
28
|
|
29
29
|
# Public: Parses a Markdown string into a `document` node.
|
@@ -34,7 +34,8 @@ module CommonMarker
|
|
34
34
|
#
|
35
35
|
# Returns the `document` node.
|
36
36
|
def self.render_doc(text, options = :DEFAULT, extensions = [])
|
37
|
-
|
37
|
+
raise TypeError, "text must be a String; got a #{text.class}!" unless text.is_a?(String)
|
38
|
+
|
38
39
|
opts = Config.process_options(options, :parse)
|
39
40
|
text = text.encode('UTF-8')
|
40
41
|
Node.parse_document(text, text.bytesize, opts, extensions)
|
data/test/benchmark.rb
CHANGED
@@ -1,34 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'benchmark/ips'
|
1
4
|
require 'commonmarker'
|
2
|
-
require 'github/markdown'
|
3
5
|
require 'redcarpet'
|
4
6
|
require 'kramdown'
|
5
7
|
require 'benchmark'
|
6
8
|
|
7
|
-
|
8
|
-
puts name
|
9
|
-
puts Benchmark.measure(&blk)
|
10
|
-
end
|
9
|
+
benchinput = File.read('test/benchinput.md').freeze
|
11
10
|
|
12
|
-
|
11
|
+
printf("input size = %<bytes>d bytes\n\n", { bytes: benchinput.bytesize })
|
13
12
|
|
14
|
-
|
13
|
+
Benchmark.ips do |x|
|
14
|
+
x.report('redcarpet') do
|
15
|
+
Redcarpet::Markdown.new(Redcarpet::Render::HTML, autolink: false, tables: false).render(benchinput)
|
16
|
+
end
|
15
17
|
|
16
|
-
|
17
|
-
|
18
|
-
end
|
18
|
+
x.report('commonmarker with to_html') do
|
19
|
+
CommonMarker.render_html(benchinput)
|
20
|
+
end
|
19
21
|
|
20
|
-
|
21
|
-
|
22
|
-
end
|
22
|
+
x.report('commonmarker with to_xml') do
|
23
|
+
CommonMarker.render_html(benchinput)
|
24
|
+
end
|
23
25
|
|
24
|
-
|
25
|
-
|
26
|
-
end
|
26
|
+
x.report('commonmarker with ruby HtmlRenderer') do
|
27
|
+
CommonMarker::HtmlRenderer.new.render(CommonMarker.render_doc(benchinput))
|
28
|
+
end
|
27
29
|
|
28
|
-
|
29
|
-
|
30
|
-
end
|
30
|
+
x.report('commonmarker with render_doc.to_html') do
|
31
|
+
CommonMarker.render_doc(benchinput, :DEFAULT, [:autolink]).to_html(:DEFAULT, [:autolink])
|
32
|
+
end
|
33
|
+
|
34
|
+
x.report('kramdown') do
|
35
|
+
Kramdown::Document.new(benchinput).to_html(benchinput)
|
36
|
+
end
|
31
37
|
|
32
|
-
|
33
|
-
Kramdown::Document.new(benchinput).to_html(benchinput)
|
38
|
+
x.compare!
|
34
39
|
end
|
@@ -0,0 +1 @@
|
|
1
|
+
I am **strong**
|
data/test/test_attributes.rb
CHANGED
@@ -1,8 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'test_helper'
|
2
4
|
|
3
5
|
class TestAttributes < Minitest::Test
|
4
6
|
def setup
|
5
|
-
contents =
|
7
|
+
contents = fixtures_file('dingus.md')
|
6
8
|
@doc = CommonMarker.render_doc(contents.strip)
|
7
9
|
end
|
8
10
|
|
@@ -13,9 +15,9 @@ class TestAttributes < Minitest::Test
|
|
13
15
|
sourcepos << node.sourcepos
|
14
16
|
end
|
15
17
|
|
16
|
-
sourcepos.delete_if { |h| h.values.all?
|
18
|
+
sourcepos.delete_if { |h| h.values.all?(&:zero?) }
|
17
19
|
|
18
|
-
result = [{:
|
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 }]
|
19
21
|
|
20
22
|
assert_equal result, sourcepos
|
21
23
|
end
|
data/test/test_basics.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'test_helper'
|
2
4
|
|
3
5
|
class TestBasics < Minitest::Test
|
@@ -13,4 +15,21 @@ class TestBasics < Minitest::Test
|
|
13
15
|
html = CommonMarker.render_html('Hi *there*')
|
14
16
|
assert_equal "<p>Hi <em>there</em></p>\n", html
|
15
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", CommonMarker.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", CommonMarker.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", CommonMarker.render_html(text, parse_opt, extensions)
|
34
|
+
end
|
16
35
|
end
|