module GitHubParser extend self class HTMLWithPantsRenderer < Redcarpet::Render::HTML include Redcarpet::Render::SmartyPants end def self.parse(markdown) html = github_parser.render(markdown.to_s) doc = Nokogiri::HTML::DocumentFragment.parse(html) special_blocks(doc) doc end private def self.github_parser @@github_parser ||= Redcarpet::Markdown.new(HTMLWithPantsRenderer, fenced_code_blocks: true, tables: true) end def self.special_blocks(doc) doc.css('blockquote>p:first').each do |node| if match = node.inner_html.match(/\A\W*(callout|warning|note)\W/) node.parent.name = 'div' node.parent['class'] = match[1] new_html = node.inner_html.gsub(/\A\W*(callout|warning|note)\W/, '') # Assigning inner_html directly causes encoding issues in old libxml versions, # workaround from https://github.com/sparklemotion/nokogiri/issues/458#issuecomment-3136620 node.children = Nokogiri::HTML.fragment(new_html, 'utf-8') end end end end