blog-static/convert.rb
Danila Fedorin 647f47a5f3 Remove KaTeX CSS includes if we don't need them.
Signed-off-by: Danila Fedorin <danila.fedorin@gmail.com>
2025-02-23 14:43:49 -08:00

78 lines
2.0 KiB
Ruby

require "execjs"
require "nokogiri"
require "net/http"
require "json"
require "cgi"
require "optparse"
class KatexRenderer
def initialize(source)
@context = ExecJS.compile(source)
@inline_cache = {}
@display_cache = {}
end
def render(display, string)
cache = display ? @display_cache : @inline_cache
comment = display ? "display" : string
string = CGI.unescapeHTML string
cache.fetch(string) do
puts " Rendering #{comment}"
options = { "throwOnError" => false, "displayMode" => display }
cache[string] = @context.call("katex.renderToString", string, options)
end
end
def substitute(content)
found_any = false
rendered = content.gsub /\\\(((?:[^\\]|\\[^\)])*)\\\)/ do |match|
found_any = true
render(false, $~[1])
end
rendered = rendered.gsub /\$\$((?:[^\$]|$[^\$])*)\$\$/ do |match|
found_any = true
render(true, $~[1])
end
return rendered, found_any
end
end
# Provided via this project's Gemfile
ExecJS.runtime = ExecJS::Runtimes::Duktape
katex = nil
OptionParser.new do |opts|
opts.banner = "Usage: convert.rb [options]"
opts.on("--katex-js-file=FILE", "Use the given KaTeX JS file to process LaTeX") do |f|
katex = f
end
end.parse!
files = ARGV
if katex
katex = File.read(katex)
else
katex = Net::HTTP.get(URI("https://static.danilafe.com/katex/katex.min.js"))
end
renderer = KatexRenderer.new(katex)
files.each do |file|
puts "Rendering file: #{file}"
document = Nokogiri::HTML.parse(File.open(file))
found_any = false
document.search('//*[not(ancestor-or-self::code or ancestor-or-self::script)]/text()').each do |t|
rendered, found_any_in_text = renderer.substitute(t.content)
found_any ||= found_any_in_text
t.replace(rendered)
end
# If we didn't find any mathematical equations, no need to include KaTeX CSS.
unless found_any
document.css('link[href$="katex.css"], link[href$="katex.min.css"]').each(&:remove)
end
File.write(file, document.to_html(encoding: 'UTF-8'))
end