Module: HunkReviewChanges::Markdown

Defined in:
lib/hunk_review_changes/markdown.rb

Overview

Renders the prose fields (what/why/framing/flags) as GitHub-flavored Markdown.

Constant Summary collapse

SAFE_SCHEMES =

Schemes allowed on rendered links and images. Kramdown does not sanitize URLs, so anything else (javascript:, data:, vbscript:, file:, ...) is neutralized to keep bundle prose from running script in the local app origin.

%w[http https mailto tel].freeze

Class Method Summary collapse

Class Method Details

.html(text) ⇒ Object



16
17
18
19
20
21
22
23
24
25
26
27
28
# File 'lib/hunk_review_changes/markdown.rb', line 16

def html(text)
  return "" if text.nil? || text.to_s.strip.empty?

  rendered = Kramdown::Document.new(
    text.to_s,
    input: "GFM",
    hard_wrap: true,
    auto_ids: false,
    parse_block_html: false,
    parse_span_html: false
  ).to_html.strip
  sanitize_urls(rendered)
end

.inline(text) ⇒ Object

Unwrap a single top-level

so the prose can sit inline after a bold lead-in label ("What it does — ..."); multi-paragraph / list output is returned as-is.



32
33
34
35
36
37
38
39
# File 'lib/hunk_review_changes/markdown.rb', line 32

def inline(text)
  rendered = html(text)
  if rendered.start_with?("<p>") && rendered.end_with?("</p>") && !rendered[3..-5].include?("<p")
    rendered[3..-5]
  else
    rendered
  end
end

.safe_url?(url) ⇒ Boolean

Returns:

  • (Boolean)


52
53
54
55
# File 'lib/hunk_review_changes/markdown.rb', line 52

def safe_url?(url)
  scheme = url_scheme(url)
  scheme.nil? || SAFE_SCHEMES.include?(scheme)
end

.sanitize_urls(html) ⇒ Object

Replace the value of any href/src whose scheme is not allowlisted with "#", so a link like x renders inert while safe URLs pass untouched.



43
44
45
46
47
48
49
50
# File 'lib/hunk_review_changes/markdown.rb', line 43

def sanitize_urls(html)
  html.gsub(/(\s(?:href|src)=)(["'])(.*?)\2/im) do
    attr = Regexp.last_match(1)
    quote = Regexp.last_match(2)
    url = Regexp.last_match(3)
    "#{attr}#{quote}#{safe_url?(url) ? url : "#"}#{quote}"
  end
end

.url_scheme(url) ⇒ Object

The scheme a browser would act on: it decodes numeric entities and ignores control/whitespace characters before parsing the scheme, so normalize the same way. Returns nil for relative/fragment/protocol-relative URLs (which are safe).



60
61
62
63
64
65
66
67
# File 'lib/hunk_review_changes/markdown.rb', line 60

def url_scheme(url)
  candidate = url
              .gsub(/&#x([0-9a-f]+);/i) { [Regexp.last_match(1).to_i(16)].pack("U") }
              .gsub(/&#(\d+);/) { [Regexp.last_match(1).to_i].pack("U") }
              .gsub(/&amp;/i, "&")
              .gsub(/[[:cntrl:][:space:]]/, "")
  candidate[/\A([a-z][a-z0-9+.-]*):/i, 1]&.downcase
end