app/helpers/about_helper.rb
Rama develop · réplica de lectura del repositorio original.
require 'commonmarker'
module AboutHelper
PROSE_CLASSES = {
'h3' => 'text-base-content mt-8 mb-3 text-base font-semibold tracking-tight first:mt-0',
'p' => 'text-base-content/80 mb-4 leading-relaxed',
'ul' => 'text-base-content/80 mb-4 list-disc space-y-1.5 pl-5',
'li' => 'leading-relaxed',
'code' => 'bg-base-content/10 rounded px-1.5 py-0.5 font-mono text-[0.85em]',
}.freeze
private_constant :PROSE_CLASSES
SAFE_LINK_SCHEMES = %w[http:// https:// #].freeze
private_constant :SAFE_LINK_SCHEMES
def render_markdown(markdown)
return ''.html_safe if markdown.blank?
html = Commonmarker.to_html(
markdown.to_s,
options: {
# Disable heading anchors/ids; we render clean prose without them.
extension: { header_ids: nil },
render: { escape: true, unsafe: false },
},
)
transform_html(html).html_safe # rubocop:disable Rails/OutputSafety
end
def parse_components(markdown)
parse_tables(markdown).filter_map { |section| build_group(section) }
end
private
# Markdown heading of a table in THIRD_PARTY_LICENSES.md → i18n label key and
# component category. A nil category means no license text ships for those
# packages, so their rows render as plain text instead of a link.
COMPONENT_GROUPS = {
'Base Image' => { key: :base_image, category: nil },
'Ruby Gems' => { key: :gems, category: 'gem' },
'JavaScript Packages' => { key: :js, category: 'js' },
}.freeze
private_constant :COMPONENT_GROUPS
def transform_html(html)
fragment = Nokogiri::HTML5.fragment(html)
# Drop the first H1 entirely — the surrounding section already has one.
fragment.at_css('h1')&.remove
# Demote ## headings one level since the page already has h1 + h2.
fragment.css('h2').each { |node| node.name = 'h3' }
PROSE_CLASSES.each do |tag, css_class|
fragment.css(tag).each { |node| node['class'] = css_class }
end
fragment.css('a').each { |node| transform_link(node) }
fragment.to_html
end
def transform_link(node)
href = node['href'].to_s
if href.end_with?('.md')
# Same-repo *.md references would 404 — point at the components list.
node['href'] = '#components'
elsif SAFE_LINK_SCHEMES.none? { |scheme| href.start_with?(scheme) }
node.replace(Nokogiri::XML::Text.new(node.content, node.document))
return
end
node['class'] = 'link link-primary'
return if node['href'].start_with?('#')
node['target'] = '_blank'
node['rel'] = 'noopener noreferrer'
end
def build_group(section)
group = COMPONENT_GROUPS[section[:heading]]
return nil unless group
components = section[:rows].map do |name, license|
{ category: group[:category], name: name.to_s.delete('`'), license: license }
end
group.merge(components: components.sort_by { |component| component[:name].downcase })
end
def parse_tables(markdown)
return [] if markdown.blank?
sections = []
current = nil
markdown.each_line do |raw|
line = raw.chomp
if line.start_with?('## ')
current = { heading: line[3..], rows: [] }
sections << current
elsif current && table_row?(line)
cells = parse_row(line)
current[:rows] << cells if cells
end
end
sections
end
def table_row?(line)
line.start_with?('|') && !table_separator_row?(line)
end
def table_separator_row?(line)
line.match?(/\|[\s\-:|]+\|/)
end
def parse_row(line)
cells = line.split('|').map(&:strip).reject(&:empty?)
return nil if cells.size != 2 || cells.first == 'Package'
cells
end
end