Skip to content

Commit 8a31006

Browse files
authored
Merge pull request #2059 from github/dependabot/bundler/commonmarker-v2.8.2
chore(deps): bump commonmarker from v0.18.3 to v2.8.2
2 parents be33798 + 35f0083 commit 8a31006

4 files changed

Lines changed: 200 additions & 17 deletions

File tree

Gemfile

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,7 @@ gemspec
44
gem "redcarpet", :platforms => :ruby
55
gem "kramdown", :platforms => :jruby
66
gem "RedCloth"
7-
# using a tag version here because 0.18.3 was not published by the author to encourage users to upgrade.
8-
# however we want to bump up to this version since this has a security patch
9-
gem "commonmarker", git: "https://github.com/gjtorikian/commonmarker.git", tag: "v0.18.3"
7+
gem "commonmarker", "~> 2.8.2"
108
gem "rdoc", "~> 7.2.0"
119
gem "org-ruby", "0.9.12"
1210
gem "creole", "~>0.5.0"

Gemfile.lock

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,3 @@
1-
GIT
2-
remote: https://github.com/gjtorikian/commonmarker.git
3-
revision: 2838ebaa83ee0081d481c21f3bc0e4cb3e8de9da
4-
tag: v0.18.3
5-
specs:
6-
commonmarker (0.18.3)
7-
ruby-enum (~> 0.5)
8-
91
PATH
102
remote: .
113
specs:
@@ -34,6 +26,13 @@ GEM
3426
builder (3.3.0)
3527
cgi (0.5.1)
3628
charlock_holmes (0.7.9)
29+
commonmarker (2.8.2)
30+
rb_sys (~> 0.9)
31+
commonmarker (2.8.2-aarch64-linux)
32+
commonmarker (2.8.2-arm-linux)
33+
commonmarker (2.8.2-arm64-darwin)
34+
commonmarker (2.8.2-x86_64-darwin)
35+
commonmarker (2.8.2-x86_64-linux)
3736
concurrent-ruby (1.3.6)
3837
connection_pool (3.0.2)
3938
crass (1.0.6)
@@ -85,14 +84,15 @@ GEM
8584
stringio
8685
racc (1.8.1)
8786
rake (13.4.2)
87+
rake-compiler-dock (1.12.0)
88+
rb_sys (0.9.128)
89+
rake-compiler-dock (= 1.12.0)
8890
rdoc (7.2.0)
8991
erb
9092
psych (>= 4.0.0)
9193
tsort
9294
redcarpet (3.6.1)
9395
rexml (3.4.4)
94-
ruby-enum (0.9.0)
95-
i18n
9696
rubypants (0.7.1)
9797
rugged (1.9.0)
9898
sanitize (6.1.3)
@@ -135,7 +135,7 @@ DEPENDENCIES
135135
RedCloth
136136
activesupport (~> 8.1.3)
137137
asciidoctor (~> 2.0.26)
138-
commonmarker!
138+
commonmarker (~> 2.8.2)
139139
creole (~> 0.5.0)
140140
github-linguist (>= 7.1.3)
141141
github-markup!

lib/github/markup/markdown.rb

Lines changed: 84 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,90 @@ module Markup
55
class Markdown < Implementation
66
MARKDOWN_GEMS = {
77
"commonmarker" => proc { |content, options: {}|
8-
commonmarker_opts = [:GITHUB_PRE_LANG].concat(options.fetch(:commonmarker_opts, []))
9-
commonmarker_exts = options.fetch(:commonmarker_exts, [:tagfilter, :autolink, :table, :strikethrough])
10-
CommonMarker.render_html(content, commonmarker_opts, commonmarker_exts)
8+
legacy_opts = options.fetch(:commonmarker_opts, [])
9+
legacy_exts = options.fetch(
10+
:commonmarker_exts,
11+
[:tagfilter, :autolink, :table, :strikethrough],
12+
)
13+
14+
parse_options = {}
15+
# commonmarker 2.x changes several render defaults that diverge from cmark-gfm 0.x:
16+
# - hardbreaks defaults to true in 2.x but was false in 0.x.
17+
# - escaped_char_spans defaults to true in 2.x and wraps backslash-escaped chars in
18+
# <span data-escaped-char>; 0.x emitted bare characters.
19+
# - gfm_quirks defaults to false in 2.x; 0.x (cmark-gfm) always had the quirk on,
20+
# which collapses ****foo**** to <strong>foo</strong> instead of nesting.
21+
# - github_pre_lang defaults to true in 2.x; set explicitly to match the legacy contract.
22+
render_options = {
23+
github_pre_lang: true,
24+
hardbreaks: false,
25+
escaped_char_spans: false,
26+
gfm_quirks: true,
27+
}
28+
extension_options = {}
29+
30+
legacy_opts.each do |opt|
31+
case opt
32+
when :DEFAULT then nil
33+
when :SOURCEPOS then render_options[:sourcepos] = true
34+
when :HARDBREAKS then render_options[:hardbreaks] = true
35+
when :NOBREAKS then render_options[:hardbreaks] = false
36+
when :SMART then parse_options[:smart] = true
37+
when :GITHUB_PRE_LANG then render_options[:github_pre_lang] = true
38+
when :UNSAFE then render_options[:unsafe] = true
39+
when :FOOTNOTES then extension_options[:footnotes] = true
40+
when :FULL_INFO_STRING then render_options[:full_info_string] = true
41+
# The legacy options below existed in cmark-gfm 0.x but have no direct commonmarker
42+
# 2.x equivalent. Accept them so existing callers don't break, but they have no effect:
43+
# :VALIDATE_UTF8 / :LIBERAL_HTML_TAG - enforced at the Rust type layer in 2.x.
44+
# :TABLE_PREFER_STYLE_ATTRIBUTES - no 2.x render knob for inline table styles.
45+
# :STRIKETHROUGH_DOUBLE_TILDE - 2.x always accepts both single and double tilde.
46+
when :VALIDATE_UTF8, :LIBERAL_HTML_TAG,
47+
:TABLE_PREFER_STYLE_ATTRIBUTES, :STRIKETHROUGH_DOUBLE_TILDE
48+
nil
49+
else
50+
raise ArgumentError, "unknown commonmarker option: #{opt.inspect}"
51+
end
52+
end
53+
54+
legacy_exts.each do |ext|
55+
case ext
56+
when :strikethrough, :tagfilter, :autolink, :table, :tasklist,
57+
:shortcodes, :footnotes, :multiline_block_quotes,
58+
:math_dollars, :math_code, :wikilinks_title_after_pipe,
59+
:wikilinks_title_before_pipe, :underline, :subscript, :spoiler,
60+
:greentext, :alerts, :description_lists
61+
extension_options[ext] = true
62+
when :header_ids
63+
# header_ids takes a string prefix in 2.x rather than a boolean. The legacy contract
64+
# only passed it as a symbol, so use an empty prefix to enable anchor generation.
65+
extension_options[:header_ids] = ""
66+
else
67+
raise ArgumentError, "unknown commonmarker extension: #{ext.inspect}"
68+
end
69+
end
70+
71+
# Several extensions (tagfilter, autolink, table, strikethrough, tasklist, shortcodes)
72+
# are enabled by default in commonmarker 2.x but were strictly opt-in in 0.x. Explicitly
73+
# disable any extension the caller did not request so behavior matches the legacy contract.
74+
[:strikethrough, :tagfilter, :autolink, :table, :tasklist, :shortcodes].each do |ext|
75+
extension_options[ext] = false unless extension_options[ext]
76+
end
77+
78+
# header_ids is enabled by default in commonmarker 2.x (it injects anchor tags inside
79+
# every heading). The legacy 0.x wrapper never enabled it implicitly, so disable it
80+
# unless the caller explicitly requested it.
81+
extension_options[:header_ids] = nil unless extension_options.key?(:header_ids)
82+
83+
Commonmarker.to_html(
84+
content,
85+
options: {
86+
parse: parse_options,
87+
render: render_options,
88+
extension: extension_options,
89+
},
90+
plugins: {syntax_highlighter: nil},
91+
)
1192
},
1293
"github/markdown" => proc { |content, options: {}|
1394
GitHub::Markdown.render(content)

test/coverage_test.rb

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,8 +241,112 @@ def test_command_raises_when_subprocess_exits_non_zero
241241
assert_raises(GitHub::Markup::CommandError) { impl.render('README.covfail', 'payload') }
242242
end
243243

244+
# --- commonmarker proc legacy option/extension mapping -----------------
245+
246+
def test_commonmarker_default_option_is_a_noop
247+
capture = capture_commonmarker_call(commonmarker_opts: [:DEFAULT])
248+
refute capture[:render].key?(:sourcepos)
249+
refute capture[:parse].key?(:smart)
250+
refute capture[:extension].key?(:footnotes)
251+
end
252+
253+
def test_commonmarker_sourcepos_option_sets_render_sourcepos
254+
capture = capture_commonmarker_call(commonmarker_opts: [:SOURCEPOS])
255+
assert_equal true, capture[:render][:sourcepos]
256+
end
257+
258+
def test_commonmarker_hardbreaks_option_enables_render_hardbreaks
259+
capture = capture_commonmarker_call(commonmarker_opts: [:HARDBREAKS])
260+
assert_equal true, capture[:render][:hardbreaks]
261+
end
262+
263+
def test_commonmarker_nobreaks_option_disables_render_hardbreaks
264+
# Combine with :HARDBREAKS so the assertion observes a transition true -> false
265+
capture = capture_commonmarker_call(commonmarker_opts: [:HARDBREAKS, :NOBREAKS])
266+
assert_equal false, capture[:render][:hardbreaks]
267+
end
268+
269+
def test_commonmarker_smart_option_sets_parse_smart
270+
capture = capture_commonmarker_call(commonmarker_opts: [:SMART])
271+
assert_equal true, capture[:parse][:smart]
272+
end
273+
274+
def test_commonmarker_github_pre_lang_option_sets_render_github_pre_lang
275+
capture = capture_commonmarker_call(commonmarker_opts: [:GITHUB_PRE_LANG])
276+
assert_equal true, capture[:render][:github_pre_lang]
277+
end
278+
279+
def test_commonmarker_unsafe_option_enables_render_unsafe
280+
capture = capture_commonmarker_call(commonmarker_opts: [:UNSAFE])
281+
assert_equal true, capture[:render][:unsafe]
282+
end
283+
284+
def test_commonmarker_footnotes_option_enables_extension_footnotes
285+
capture = capture_commonmarker_call(commonmarker_opts: [:FOOTNOTES])
286+
assert_equal true, capture[:extension][:footnotes]
287+
end
288+
289+
def test_commonmarker_full_info_string_option_sets_render_full_info_string
290+
capture = capture_commonmarker_call(commonmarker_opts: [:FULL_INFO_STRING])
291+
assert_equal true, capture[:render][:full_info_string]
292+
end
293+
294+
def test_commonmarker_accepts_legacy_no_op_options_without_raising
295+
[
296+
:VALIDATE_UTF8,
297+
:LIBERAL_HTML_TAG,
298+
:TABLE_PREFER_STYLE_ATTRIBUTES,
299+
:STRIKETHROUGH_DOUBLE_TILDE,
300+
].each do |opt|
301+
capture = capture_commonmarker_call(commonmarker_opts: [opt])
302+
refute capture[:render].key?(:sourcepos), "#{opt} should not alter render options"
303+
refute capture[:parse].key?(:smart), "#{opt} should not alter parse options"
304+
end
305+
end
306+
307+
def test_commonmarker_unknown_option_raises_argument_error
308+
err = assert_raises(ArgumentError) do
309+
capture_commonmarker_call(commonmarker_opts: [:TOTALLY_FAKE_OPT])
310+
end
311+
assert_match(/unknown commonmarker option:.*TOTALLY_FAKE_OPT/, err.message)
312+
end
313+
314+
def test_commonmarker_header_ids_extension_sets_empty_string_prefix
315+
capture = capture_commonmarker_call(commonmarker_exts: [:header_ids])
316+
assert_equal "", capture[:extension][:header_ids]
317+
end
318+
319+
def test_commonmarker_unknown_extension_raises_argument_error
320+
err = assert_raises(ArgumentError) do
321+
capture_commonmarker_call(commonmarker_exts: [:not_a_real_ext])
322+
end
323+
assert_match(/unknown commonmarker extension:.*not_a_real_ext/, err.message)
324+
end
325+
244326
private
245327

328+
# Invokes the commonmarker MARKDOWN_GEMS proc against a stubbed Commonmarker
329+
# constant and returns the parse/render/extension options the proc passed to
330+
# Commonmarker.to_html.
331+
def capture_commonmarker_call(options)
332+
captured = {}
333+
fake = Module.new
334+
fake.define_singleton_method(:to_html) do |content, **kwargs|
335+
captured[:content] = content
336+
opts = kwargs.fetch(:options, {})
337+
captured[:parse] = opts[:parse] || {}
338+
captured[:render] = opts[:render] || {}
339+
captured[:extension] = opts[:extension] || {}
340+
"stub-html"
341+
end
342+
with_stub_const("Commonmarker", fake) do
343+
GitHub::Markup::Markdown::MARKDOWN_GEMS
344+
.fetch("commonmarker")
345+
.call("payload", options: options)
346+
end
347+
captured
348+
end
349+
246350
def with_stub_const(path, value)
247351
parts = path.split("::")
248352
name = parts.pop

0 commit comments

Comments
 (0)