Created
May 17, 2025 05:40
-
-
Save synth/9e6fc4182a56c1a2c5791d83a71858b3 to your computer and use it in GitHub Desktop.
Html to Slack Markdown Converter
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'nokogiri' | |
class SlackMarkdownConverter | |
class << self | |
def convert(html, options = {}) | |
converter = new(options) | |
converter.convert(html) | |
end | |
end | |
def initialize(options = {}) | |
@options = options | |
@include_images = options.fetch(:include_images, false) | |
end | |
def convert(html) | |
return '' if html.nil? || html.empty? | |
doc = Nokogiri::HTML.fragment(html) | |
process_node(doc) | |
end | |
private | |
def process_node(node) | |
result = '' | |
node.children.each do |child| | |
result += process_element(child) | |
end | |
# Clean up extra whitespace | |
result.gsub(/\n{3,}/, "\n\n").strip | |
end | |
def process_element(element) | |
case element.name | |
when 'text' | |
element.text | |
when 'br' | |
"\n" | |
when 'p' | |
process_node(element) + "\n\n" | |
when 'strong', 'b', 'em', 'i', 'code' | |
process_formatting_element(element) | |
when 'pre' | |
"```\n#{process_node(element)}\n```" | |
when 'blockquote' | |
process_blockquote(element) | |
when 'a' | |
process_link(element) | |
when 'ul', 'ol' | |
process_list_container(element) | |
when 'li' | |
process_node(element) + "\n" | |
when 'h1', 'h2', 'h3', 'h4', 'h5', 'h6' | |
"*#{process_node(element)}*\n\n" | |
when 'img' | |
@include_images ? process_image(element) : '' | |
when 'div', 'span' | |
process_node(element) | |
when 'hr' | |
"---\n" | |
else | |
# For any other tags, just process their contents | |
process_node(element) | |
end | |
end | |
def process_formatting_element(element) | |
case element.name | |
when 'strong', 'b' | |
"*#{process_node(element)}*" | |
when 'em', 'i' | |
"_#{process_node(element)}_" | |
when 'code' | |
"`#{process_node(element)}`" | |
end | |
end | |
def process_list_container(element) | |
marker = element.name == 'ul' ? '• ' : lambda { |i| "#{i + 1}. " } | |
process_list(element, marker) | |
end | |
def process_blockquote(node) | |
content = process_node(node) | |
lines = content.split("\n") | |
quoted_lines = lines.map { |line| "> #{line}" } | |
quoted_lines.join("\n") + "\n\n" | |
end | |
def process_link(node) | |
text = process_node(node) | |
href = node['href'] | |
# If text is the same as href or just a basic placeholder, show href only | |
if text.strip == href || text.strip.downcase == 'link' | |
"<#{href}>" | |
else | |
"<#{href}|#{text}>" | |
end | |
end | |
def process_list(node, marker) | |
result = "\n" | |
node.children.each_with_index do |child, i| | |
next unless child.name == 'li' | |
prefix = marker.is_a?(Proc) ? marker.call(i) : marker | |
content = process_node(child).strip | |
result += "#{prefix}#{content}\n" | |
end | |
result + "\n" | |
end | |
def process_image(node) | |
alt_text = node['alt'] || 'image' | |
src = node['src'] | |
"<#{src}|#{alt_text}>" | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment