commonmarker 0.23.1 → 0.23.5
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 +4 -4
- data/Rakefile +56 -55
- data/bin/commonmarker +2 -7
- data/commonmarker.gemspec +27 -26
- data/ext/commonmarker/blocks.c +13 -2
- data/ext/commonmarker/cmark-gfm_version.h +2 -2
- data/ext/commonmarker/commonmark.c +14 -4
- data/ext/commonmarker/commonmarker.c +30 -44
- data/ext/commonmarker/ext_scanners.c +360 -640
- data/ext/commonmarker/footnotes.c +23 -0
- data/ext/commonmarker/footnotes.h +2 -0
- data/ext/commonmarker/html.c +40 -19
- data/ext/commonmarker/inlines.c +69 -11
- data/ext/commonmarker/node.h +7 -0
- data/ext/commonmarker/scanners.c +2438 -2450
- data/ext/commonmarker/table.c +98 -53
- data/lib/commonmarker/config.rb +1 -1
- data/lib/commonmarker/node/inspect.rb +8 -18
- data/lib/commonmarker/node.rb +6 -6
- data/lib/commonmarker/renderer/html_renderer.rb +37 -37
- data/lib/commonmarker/renderer.rb +5 -5
- data/lib/commonmarker/version.rb +1 -1
- data/lib/commonmarker.rb +9 -11
- metadata +6 -57
- data/test/benchmark.rb +0 -32
- data/test/fixtures/curly.md +0 -1
- data/test/fixtures/dingus.md +0 -10
- data/test/fixtures/strong.md +0 -1
- data/test/fixtures/table.md +0 -10
- data/test/test_attributes.rb +0 -24
- data/test/test_basics.rb +0 -35
- data/test/test_commands.rb +0 -72
- data/test/test_commonmark.rb +0 -36
- data/test/test_doc.rb +0 -130
- data/test/test_encoding.rb +0 -23
- data/test/test_extensions.rb +0 -116
- data/test/test_footnotes.rb +0 -48
- data/test/test_gc.rb +0 -47
- data/test/test_helper.rb +0 -71
- data/test/test_linebreaks.rb +0 -15
- data/test/test_maliciousness.rb +0 -262
- data/test/test_node.rb +0 -89
- data/test/test_options.rb +0 -37
- data/test/test_pathological_inputs.rb +0 -94
- data/test/test_plaintext.rb +0 -46
- data/test/test_renderer.rb +0 -47
- data/test/test_smartpunct.rb +0 -27
- data/test/test_spec.rb +0 -30
- data/test/test_tasklists.rb +0 -43
- data/test/test_xml.rb +0 -107
data/ext/commonmarker/table.c
CHANGED
@@ -114,60 +114,94 @@ static cmark_strbuf *unescape_pipes(cmark_mem *mem, unsigned char *string, bufsi
|
|
114
114
|
static table_row *row_from_string(cmark_syntax_extension *self,
|
115
115
|
cmark_parser *parser, unsigned char *string,
|
116
116
|
int len) {
|
117
|
+
// Parses a single table row. It has the following form:
|
118
|
+
// `delim? table_cell (delim table_cell)* delim? newline`
|
119
|
+
// Note that cells are allowed to be empty.
|
120
|
+
//
|
121
|
+
// From the GitHub-flavored Markdown specification:
|
122
|
+
//
|
123
|
+
// > Each row consists of cells containing arbitrary text, in which inlines
|
124
|
+
// > are parsed, separated by pipes (|). A leading and trailing pipe is also
|
125
|
+
// > recommended for clarity of reading, and if there’s otherwise parsing
|
126
|
+
// > ambiguity.
|
127
|
+
|
117
128
|
table_row *row = NULL;
|
118
129
|
bufsize_t cell_matched = 1, pipe_matched = 1, offset;
|
119
|
-
int
|
130
|
+
int expect_more_cells = 1;
|
131
|
+
int row_end_offset = 0;
|
132
|
+
int int_overflow_abort = 0;
|
120
133
|
|
121
134
|
row = (table_row *)parser->mem->calloc(1, sizeof(table_row));
|
122
135
|
row->n_columns = 0;
|
123
136
|
row->cells = NULL;
|
124
137
|
|
138
|
+
// Scan past the (optional) leading pipe.
|
125
139
|
offset = scan_table_cell_end(string, len, 0);
|
126
140
|
|
127
141
|
// Parse the cells of the row. Stop if we reach the end of the input, or if we
|
128
142
|
// cannot detect any more cells.
|
129
|
-
while (offset < len &&
|
143
|
+
while (offset < len && expect_more_cells) {
|
130
144
|
cell_matched = scan_table_cell(string, len, offset);
|
131
145
|
pipe_matched = scan_table_cell_end(string, len, offset + cell_matched);
|
132
146
|
|
133
147
|
if (cell_matched || pipe_matched) {
|
134
|
-
|
148
|
+
// We are guaranteed to have a cell, since (1) either we found some
|
149
|
+
// content and cell_matched, or (2) we found an empty cell followed by a
|
150
|
+
// pipe.
|
151
|
+
cmark_strbuf *cell_buf = unescape_pipes(parser->mem, string + offset,
|
152
|
+
cell_matched);
|
153
|
+
cmark_strbuf_trim(cell_buf);
|
154
|
+
|
155
|
+
node_cell *cell = (node_cell *)parser->mem->calloc(1, sizeof(*cell));
|
156
|
+
cell->buf = cell_buf;
|
157
|
+
cell->start_offset = offset;
|
158
|
+
cell->end_offset = offset + cell_matched - 1;
|
159
|
+
|
160
|
+
while (cell->start_offset > 0 && string[cell->start_offset - 1] != '|') {
|
161
|
+
--cell->start_offset;
|
162
|
+
++cell->internal_offset;
|
163
|
+
}
|
164
|
+
|
165
|
+
// make sure we never wrap row->n_columns
|
166
|
+
// offset will != len and our exit will clean up as intended
|
167
|
+
if (row->n_columns == UINT16_MAX) {
|
168
|
+
int_overflow_abort = 1;
|
169
|
+
break;
|
170
|
+
}
|
171
|
+
row->n_columns += 1;
|
172
|
+
row->cells = cmark_llist_append(parser->mem, row->cells, cell);
|
173
|
+
}
|
135
174
|
|
136
|
-
|
137
|
-
|
175
|
+
offset += cell_matched + pipe_matched;
|
176
|
+
|
177
|
+
if (pipe_matched) {
|
178
|
+
expect_more_cells = 1;
|
179
|
+
} else {
|
180
|
+
// We've scanned the last cell. Check if we have reached the end of the row
|
181
|
+
row_end_offset = scan_table_row_end(string, len, offset);
|
182
|
+
offset += row_end_offset;
|
183
|
+
|
184
|
+
// If the end of the row is not the end of the input,
|
185
|
+
// the row is not a real row but potentially part of the paragraph
|
186
|
+
// preceding the table.
|
187
|
+
if (row_end_offset && offset != len) {
|
188
|
+
row->paragraph_offset = offset;
|
138
189
|
|
139
190
|
cmark_llist_free_full(parser->mem, row->cells, (cmark_free_func)free_table_cell);
|
140
191
|
row->cells = NULL;
|
141
192
|
row->n_columns = 0;
|
142
|
-
} else {
|
143
|
-
cmark_strbuf *cell_buf = unescape_pipes(parser->mem, string + offset,
|
144
|
-
cell_matched);
|
145
|
-
cmark_strbuf_trim(cell_buf);
|
146
|
-
|
147
|
-
node_cell *cell = (node_cell *)parser->mem->calloc(1, sizeof(*cell));
|
148
|
-
cell->buf = cell_buf;
|
149
|
-
cell->start_offset = offset;
|
150
|
-
cell->end_offset = cell_end_offset;
|
151
|
-
|
152
|
-
while (cell->start_offset > 0 && string[cell->start_offset - 1] != '|') {
|
153
|
-
--cell->start_offset;
|
154
|
-
++cell->internal_offset;
|
155
|
-
}
|
156
193
|
|
157
|
-
|
158
|
-
|
159
|
-
}
|
160
|
-
}
|
161
|
-
|
162
|
-
offset += cell_matched + pipe_matched;
|
194
|
+
// Scan past the (optional) leading pipe.
|
195
|
+
offset += scan_table_cell_end(string, len, offset);
|
163
196
|
|
164
|
-
|
165
|
-
|
166
|
-
|
197
|
+
expect_more_cells = 1;
|
198
|
+
} else {
|
199
|
+
expect_more_cells = 0;
|
200
|
+
}
|
167
201
|
}
|
168
202
|
}
|
169
203
|
|
170
|
-
if (offset != len ||
|
204
|
+
if (offset != len || row->n_columns == 0 || int_overflow_abort) {
|
171
205
|
free_table_row(parser->mem, row);
|
172
206
|
row = NULL;
|
173
207
|
}
|
@@ -199,8 +233,6 @@ static cmark_node *try_opening_table_header(cmark_syntax_extension *self,
|
|
199
233
|
cmark_parser *parser,
|
200
234
|
cmark_node *parent_container,
|
201
235
|
unsigned char *input, int len) {
|
202
|
-
bufsize_t matched =
|
203
|
-
scan_table_start(input, len, cmark_parser_get_first_nonspace(parser));
|
204
236
|
cmark_node *table_header;
|
205
237
|
table_row *header_row = NULL;
|
206
238
|
table_row *marker_row = NULL;
|
@@ -208,41 +240,48 @@ static cmark_node *try_opening_table_header(cmark_syntax_extension *self,
|
|
208
240
|
const char *parent_string;
|
209
241
|
uint16_t i;
|
210
242
|
|
211
|
-
if (!
|
212
|
-
return parent_container;
|
213
|
-
|
214
|
-
parent_string = cmark_node_get_string_content(parent_container);
|
215
|
-
|
216
|
-
cmark_arena_push();
|
217
|
-
|
218
|
-
header_row = row_from_string(self, parser, (unsigned char *)parent_string,
|
219
|
-
(int)strlen(parent_string));
|
220
|
-
|
221
|
-
if (!header_row) {
|
222
|
-
free_table_row(parser->mem, header_row);
|
223
|
-
cmark_arena_pop();
|
243
|
+
if (!scan_table_start(input, len, cmark_parser_get_first_nonspace(parser))) {
|
224
244
|
return parent_container;
|
225
245
|
}
|
226
246
|
|
247
|
+
// Since scan_table_start was successful, we must have a marker row.
|
227
248
|
marker_row = row_from_string(self, parser,
|
228
249
|
input + cmark_parser_get_first_nonspace(parser),
|
229
250
|
len - cmark_parser_get_first_nonspace(parser));
|
230
|
-
|
251
|
+
// assert may be optimized out, don't rely on it for security boundaries
|
252
|
+
if (!marker_row) {
|
253
|
+
return parent_container;
|
254
|
+
}
|
255
|
+
|
231
256
|
assert(marker_row);
|
232
257
|
|
233
|
-
|
234
|
-
|
258
|
+
cmark_arena_push();
|
259
|
+
|
260
|
+
// Check for a matching header row. We call `row_from_string` with the entire
|
261
|
+
// (potentially long) parent container as input, but this should be safe since
|
262
|
+
// `row_from_string` bails out early if it does not find a row.
|
263
|
+
parent_string = cmark_node_get_string_content(parent_container);
|
264
|
+
header_row = row_from_string(self, parser, (unsigned char *)parent_string,
|
265
|
+
(int)strlen(parent_string));
|
266
|
+
if (!header_row || header_row->n_columns != marker_row->n_columns) {
|
235
267
|
free_table_row(parser->mem, marker_row);
|
268
|
+
free_table_row(parser->mem, header_row);
|
236
269
|
cmark_arena_pop();
|
237
270
|
return parent_container;
|
238
271
|
}
|
239
272
|
|
240
273
|
if (cmark_arena_pop()) {
|
274
|
+
marker_row = row_from_string(
|
275
|
+
self, parser, input + cmark_parser_get_first_nonspace(parser),
|
276
|
+
len - cmark_parser_get_first_nonspace(parser));
|
241
277
|
header_row = row_from_string(self, parser, (unsigned char *)parent_string,
|
242
278
|
(int)strlen(parent_string));
|
243
|
-
|
244
|
-
|
245
|
-
|
279
|
+
// row_from_string can return NULL, add additional check to ensure n_columns match
|
280
|
+
if (!marker_row || !header_row || header_row->n_columns != marker_row->n_columns) {
|
281
|
+
free_table_row(parser->mem, marker_row);
|
282
|
+
free_table_row(parser->mem, header_row);
|
283
|
+
return parent_container;
|
284
|
+
}
|
246
285
|
}
|
247
286
|
|
248
287
|
if (!cmark_node_set_type(parent_container, CMARK_NODE_TABLE)) {
|
@@ -257,13 +296,13 @@ static cmark_node *try_opening_table_header(cmark_syntax_extension *self,
|
|
257
296
|
}
|
258
297
|
|
259
298
|
cmark_node_set_syntax_extension(parent_container, self);
|
260
|
-
|
261
299
|
parent_container->as.opaque = parser->mem->calloc(1, sizeof(node_table));
|
262
|
-
|
263
300
|
set_n_table_columns(parent_container, header_row->n_columns);
|
264
301
|
|
302
|
+
// allocate alignments based on marker_row->n_columns
|
303
|
+
// since we populate the alignments array based on marker_row->cells
|
265
304
|
uint8_t *alignments =
|
266
|
-
(uint8_t *)parser->mem->calloc(
|
305
|
+
(uint8_t *)parser->mem->calloc(marker_row->n_columns, sizeof(uint8_t));
|
267
306
|
cmark_llist *it = marker_row->cells;
|
268
307
|
for (i = 0; it; it = it->next, ++i) {
|
269
308
|
node_cell *node = (node_cell *)it->data;
|
@@ -332,6 +371,12 @@ static cmark_node *try_opening_table_row(cmark_syntax_extension *self,
|
|
332
371
|
row = row_from_string(self, parser, input + cmark_parser_get_first_nonspace(parser),
|
333
372
|
len - cmark_parser_get_first_nonspace(parser));
|
334
373
|
|
374
|
+
if (!row) {
|
375
|
+
// clean up the dangling node
|
376
|
+
cmark_node_free(table_row_block);
|
377
|
+
return NULL;
|
378
|
+
}
|
379
|
+
|
335
380
|
{
|
336
381
|
cmark_llist *tmp;
|
337
382
|
int i, table_columns = get_n_table_columns(parent_container);
|
data/lib/commonmarker/config.rb
CHANGED
@@ -30,7 +30,7 @@ module CommonMarker
|
|
30
30
|
TABLE_PREFER_STYLE_ATTRIBUTES: (1 << 15),
|
31
31
|
FULL_INFO_STRING: (1 << 16),
|
32
32
|
}.freeze,
|
33
|
-
format:
|
33
|
+
format: [:html, :xml, :commonmark, :plaintext].freeze,
|
34
34
|
}.freeze
|
35
35
|
|
36
36
|
def self.process_options(option, type)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
3
|
+
require "pp"
|
4
4
|
|
5
5
|
module CommonMarker
|
6
6
|
class Node
|
@@ -8,33 +8,23 @@ 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
14
|
# @param printer [PrettyPrint] pp
|
15
15
|
def pretty_print(printer)
|
16
|
-
printer.group(PP_INDENT_SIZE, "#<#{self.class}(#{type}):",
|
16
|
+
printer.group(PP_INDENT_SIZE, "#<#{self.class}(#{type}):", ">") do
|
17
17
|
printer.breakable
|
18
18
|
|
19
|
-
attrs =
|
20
|
-
sourcepos
|
21
|
-
string_content
|
22
|
-
url
|
23
|
-
title
|
24
|
-
header_level
|
25
|
-
list_type
|
26
|
-
list_start
|
27
|
-
list_tight
|
28
|
-
fence_info
|
29
|
-
].map do |name|
|
19
|
+
attrs = [:sourcepos, :string_content, :url, :title, :header_level, :list_type, :list_start, :list_tight, :fence_info].map do |name|
|
30
20
|
[name, __send__(name)]
|
31
21
|
rescue NodeError
|
32
22
|
nil
|
33
23
|
end.compact
|
34
24
|
|
35
25
|
printer.seplist(attrs) do |name, value|
|
36
|
-
printer.text
|
37
|
-
printer.pp
|
26
|
+
printer.text("#{name}=")
|
27
|
+
printer.pp(value)
|
38
28
|
end
|
39
29
|
|
40
30
|
if first_child
|
@@ -46,8 +36,8 @@ module CommonMarker
|
|
46
36
|
children << node
|
47
37
|
node = node.next
|
48
38
|
end
|
49
|
-
printer.text
|
50
|
-
printer.pp
|
39
|
+
printer.text("children=")
|
40
|
+
printer.pp(children)
|
51
41
|
end
|
52
42
|
end
|
53
43
|
end
|
data/lib/commonmarker/node.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
3
|
+
require "commonmarker/node/inspect"
|
4
4
|
|
5
5
|
module CommonMarker
|
6
6
|
class Node
|
@@ -27,7 +27,7 @@ module CommonMarker
|
|
27
27
|
# Returns a {String}.
|
28
28
|
def to_html(options = :DEFAULT, extensions = [])
|
29
29
|
opts = Config.process_options(options, :render)
|
30
|
-
_render_html(opts, extensions).force_encoding(
|
30
|
+
_render_html(opts, extensions).force_encoding("utf-8")
|
31
31
|
end
|
32
32
|
|
33
33
|
# Public: Convert the node to an XML string.
|
@@ -37,7 +37,7 @@ module CommonMarker
|
|
37
37
|
# Returns a {String}.
|
38
38
|
def to_xml(options = :DEFAULT)
|
39
39
|
opts = Config.process_options(options, :render)
|
40
|
-
_render_xml(opts).force_encoding(
|
40
|
+
_render_xml(opts).force_encoding("utf-8")
|
41
41
|
end
|
42
42
|
|
43
43
|
# Public: Convert the node to a CommonMark string.
|
@@ -48,7 +48,7 @@ module CommonMarker
|
|
48
48
|
# Returns a {String}.
|
49
49
|
def to_commonmark(options = :DEFAULT, width = 120)
|
50
50
|
opts = Config.process_options(options, :render)
|
51
|
-
_render_commonmark(opts, width).force_encoding(
|
51
|
+
_render_commonmark(opts, width).force_encoding("utf-8")
|
52
52
|
end
|
53
53
|
|
54
54
|
# Public: Convert the node to a plain text string.
|
@@ -59,7 +59,7 @@ module CommonMarker
|
|
59
59
|
# Returns a {String}.
|
60
60
|
def to_plaintext(options = :DEFAULT, width = 120)
|
61
61
|
opts = Config.process_options(options, :render)
|
62
|
-
_render_plaintext(opts, width).force_encoding(
|
62
|
+
_render_plaintext(opts, width).force_encoding("utf-8")
|
63
63
|
end
|
64
64
|
|
65
65
|
# Public: Iterate over the children (if any) of the current pointer.
|
@@ -76,7 +76,7 @@ module CommonMarker
|
|
76
76
|
|
77
77
|
# Deprecated: Please use `each` instead
|
78
78
|
def each_child(&block)
|
79
|
-
warn
|
79
|
+
warn("[DEPRECATION] `each_child` is deprecated. Please use `each` instead.")
|
80
80
|
each(&block)
|
81
81
|
end
|
82
82
|
end
|
@@ -9,8 +9,8 @@ module CommonMarker
|
|
9
9
|
|
10
10
|
def header(node)
|
11
11
|
block do
|
12
|
-
out(
|
13
|
-
|
12
|
+
out("<h", node.header_level, "#{sourcepos(node)}>", :children,
|
13
|
+
"</h", node.header_level, ">")
|
14
14
|
end
|
15
15
|
end
|
16
16
|
|
@@ -19,10 +19,10 @@ module CommonMarker
|
|
19
19
|
out(:children)
|
20
20
|
else
|
21
21
|
block do
|
22
|
-
container("<p#{sourcepos(node)}>",
|
22
|
+
container("<p#{sourcepos(node)}>", "</p>") do
|
23
23
|
out(:children)
|
24
24
|
if node.parent.type == :footnote_definition && node.next.nil?
|
25
|
-
out(
|
25
|
+
out(" ")
|
26
26
|
out_footnote_backref
|
27
27
|
end
|
28
28
|
end
|
@@ -36,16 +36,16 @@ module CommonMarker
|
|
36
36
|
|
37
37
|
block do
|
38
38
|
if node.list_type == :bullet_list
|
39
|
-
container("<ul#{sourcepos(node)}>\n",
|
39
|
+
container("<ul#{sourcepos(node)}>\n", "</ul>") do
|
40
40
|
out(:children)
|
41
41
|
end
|
42
42
|
else
|
43
43
|
start = if node.list_start == 1
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
container(start,
|
44
|
+
"<ol#{sourcepos(node)}>\n"
|
45
|
+
else
|
46
|
+
"<ol start=\"#{node.list_start}\"#{sourcepos(node)}>\n"
|
47
|
+
end
|
48
|
+
container(start, "</ol>") do
|
49
49
|
out(:children)
|
50
50
|
end
|
51
51
|
end
|
@@ -57,26 +57,26 @@ module CommonMarker
|
|
57
57
|
def list_item(node)
|
58
58
|
block do
|
59
59
|
tasklist_data = tasklist(node)
|
60
|
-
container("<li#{sourcepos(node)}#{tasklist_data}>#{
|
60
|
+
container("<li#{sourcepos(node)}#{tasklist_data}>#{" " if tasklist?(node)}", "</li>") do
|
61
61
|
out(:children)
|
62
62
|
end
|
63
63
|
end
|
64
64
|
end
|
65
65
|
|
66
66
|
def tasklist(node)
|
67
|
-
return
|
67
|
+
return "" unless tasklist?(node)
|
68
68
|
|
69
69
|
state = if checked?(node)
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
70
|
+
'checked="" disabled=""'
|
71
|
+
else
|
72
|
+
'disabled=""'
|
73
|
+
end
|
74
74
|
"><input type=\"checkbox\" #{state} /"
|
75
75
|
end
|
76
76
|
|
77
77
|
def blockquote(node)
|
78
78
|
block do
|
79
|
-
container("<blockquote#{sourcepos(node)}>\n",
|
79
|
+
container("<blockquote#{sourcepos(node)}>\n", "</blockquote>") do
|
80
80
|
out(:children)
|
81
81
|
end
|
82
82
|
end
|
@@ -93,17 +93,17 @@ module CommonMarker
|
|
93
93
|
if option_enabled?(:GITHUB_PRE_LANG)
|
94
94
|
out("<pre#{sourcepos(node)}")
|
95
95
|
out(' lang="', node.fence_info.split(/\s+/)[0], '"') if node.fence_info && !node.fence_info.empty?
|
96
|
-
out(
|
96
|
+
out("><code>")
|
97
97
|
else
|
98
98
|
out("<pre#{sourcepos(node)}><code")
|
99
99
|
if node.fence_info && !node.fence_info.empty?
|
100
100
|
out(' class="language-', node.fence_info.split(/\s+/)[0], '">')
|
101
101
|
else
|
102
|
-
out(
|
102
|
+
out(">")
|
103
103
|
end
|
104
104
|
end
|
105
105
|
out(escape_html(node.string_content))
|
106
|
-
out(
|
106
|
+
out("</code></pre>")
|
107
107
|
end
|
108
108
|
end
|
109
109
|
|
@@ -112,7 +112,7 @@ module CommonMarker
|
|
112
112
|
if option_enabled?(:UNSAFE)
|
113
113
|
out(tagfilter(node.string_content))
|
114
114
|
else
|
115
|
-
out(
|
115
|
+
out("<!-- raw HTML omitted -->")
|
116
116
|
end
|
117
117
|
end
|
118
118
|
end
|
@@ -121,22 +121,22 @@ module CommonMarker
|
|
121
121
|
if option_enabled?(:UNSAFE)
|
122
122
|
out(tagfilter(node.string_content))
|
123
123
|
else
|
124
|
-
out(
|
124
|
+
out("<!-- raw HTML omitted -->")
|
125
125
|
end
|
126
126
|
end
|
127
127
|
|
128
128
|
def emph(_)
|
129
|
-
out(
|
129
|
+
out("<em>", :children, "</em>")
|
130
130
|
end
|
131
131
|
|
132
132
|
def strong(_)
|
133
|
-
out(
|
133
|
+
out("<strong>", :children, "</strong>")
|
134
134
|
end
|
135
135
|
|
136
136
|
def link(node)
|
137
|
-
out('<a href="', node.url.nil? ?
|
137
|
+
out('<a href="', node.url.nil? ? "" : escape_href(node.url), '"')
|
138
138
|
out(' title="', escape_html(node.title), '"') if node.title && !node.title.empty?
|
139
|
-
out(
|
139
|
+
out(">", :children, "</a>")
|
140
140
|
end
|
141
141
|
|
142
142
|
def image(node)
|
@@ -145,7 +145,7 @@ module CommonMarker
|
|
145
145
|
out(' alt="', :children, '"')
|
146
146
|
end
|
147
147
|
out(' title="', escape_html(node.title), '"') if node.title && !node.title.empty?
|
148
|
-
out(
|
148
|
+
out(" />")
|
149
149
|
end
|
150
150
|
|
151
151
|
def text(node)
|
@@ -153,9 +153,9 @@ module CommonMarker
|
|
153
153
|
end
|
154
154
|
|
155
155
|
def code(node)
|
156
|
-
out(
|
156
|
+
out("<code>")
|
157
157
|
out(escape_html(node.string_content))
|
158
|
-
out(
|
158
|
+
out("</code>")
|
159
159
|
end
|
160
160
|
|
161
161
|
def linebreak(_node)
|
@@ -166,7 +166,7 @@ module CommonMarker
|
|
166
166
|
if option_enabled?(:HARDBREAKS)
|
167
167
|
out("<br />\n")
|
168
168
|
elsif option_enabled?(:NOBREAKS)
|
169
|
-
out(
|
169
|
+
out(" ")
|
170
170
|
else
|
171
171
|
out("\n")
|
172
172
|
end
|
@@ -199,17 +199,17 @@ module CommonMarker
|
|
199
199
|
|
200
200
|
def table_cell(node)
|
201
201
|
align = case @alignments[@column_index]
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
202
|
+
when :left then ' align="left"'
|
203
|
+
when :right then ' align="right"'
|
204
|
+
when :center then ' align="center"'
|
205
|
+
else; ""
|
206
|
+
end
|
207
207
|
out(@in_header ? "<th#{align}#{sourcepos(node)}>" : "<td#{align}#{sourcepos(node)}>", :children, @in_header ? "</th>\n" : "</td>\n")
|
208
208
|
@column_index += 1
|
209
209
|
end
|
210
210
|
|
211
211
|
def strikethrough(_)
|
212
|
-
out(
|
212
|
+
out("<del>", :children, "</del>")
|
213
213
|
end
|
214
214
|
|
215
215
|
def footnote_reference(node)
|
@@ -242,7 +242,7 @@ module CommonMarker
|
|
242
242
|
end
|
243
243
|
|
244
244
|
def tasklist?(node)
|
245
|
-
node.type_string ==
|
245
|
+
node.type_string == "tasklist"
|
246
246
|
end
|
247
247
|
|
248
248
|
def checked?(node)
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
3
|
+
require "set"
|
4
|
+
require "stringio"
|
5
5
|
|
6
6
|
module CommonMarker
|
7
7
|
class Renderer
|
@@ -9,9 +9,9 @@ module CommonMarker
|
|
9
9
|
|
10
10
|
def initialize(options: :DEFAULT, extensions: [])
|
11
11
|
@opts = Config.process_options(options, :render)
|
12
|
-
@stream = StringIO.new(+
|
12
|
+
@stream = StringIO.new(+"")
|
13
13
|
@need_blocksep = false
|
14
|
-
@warnings = Set.new
|
14
|
+
@warnings = Set.new([])
|
15
15
|
@in_tight = false
|
16
16
|
@in_plain = false
|
17
17
|
@tagfilter = extensions.include?(:tagfilter)
|
@@ -121,7 +121,7 @@ module CommonMarker
|
|
121
121
|
end
|
122
122
|
|
123
123
|
def sourcepos(node)
|
124
|
-
return
|
124
|
+
return "" unless option_enabled?(:SOURCEPOS)
|
125
125
|
|
126
126
|
s = node.sourcepos
|
127
127
|
" data-sourcepos=\"#{s[:start_line]}:#{s[:start_column]}-" \
|
data/lib/commonmarker/version.rb
CHANGED
data/lib/commonmarker.rb
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
-
require
|
5
|
-
require
|
6
|
-
require
|
7
|
-
require
|
8
|
-
require
|
9
|
-
require
|
4
|
+
require "commonmarker/commonmarker"
|
5
|
+
require "commonmarker/config"
|
6
|
+
require "commonmarker/node"
|
7
|
+
require "commonmarker/renderer"
|
8
|
+
require "commonmarker/renderer/html_renderer"
|
9
|
+
require "commonmarker/version"
|
10
10
|
|
11
11
|
begin
|
12
|
-
require
|
12
|
+
require "awesome_print"
|
13
13
|
rescue LoadError; end # rubocop:disable Lint/SuppressedException
|
14
14
|
module CommonMarker
|
15
15
|
# Public: Parses a Markdown string into an HTML string.
|
@@ -23,9 +23,7 @@ module CommonMarker
|
|
23
23
|
raise TypeError, "text must be a String; got a #{text.class}!" unless text.is_a?(String)
|
24
24
|
|
25
25
|
opts = Config.process_options(options, :render)
|
26
|
-
text
|
27
|
-
html = Node.markdown_to_html(text, opts, extensions)
|
28
|
-
html.force_encoding('UTF-8')
|
26
|
+
Node.markdown_to_html(text.encode("UTF-8"), opts, extensions)
|
29
27
|
end
|
30
28
|
|
31
29
|
# Public: Parses a Markdown string into a `document` node.
|
@@ -39,7 +37,7 @@ module CommonMarker
|
|
39
37
|
raise TypeError, "text must be a String; got a #{text.class}!" unless text.is_a?(String)
|
40
38
|
|
41
39
|
opts = Config.process_options(options, :parse)
|
42
|
-
text = text.encode(
|
40
|
+
text = text.encode("UTF-8")
|
43
41
|
Node.parse_document(text, text.bytesize, opts, extensions)
|
44
42
|
end
|
45
43
|
end
|