blog-static/convert.rb
Danila Fedorin 06ee998d54 Allow executing non-remote JS for KaTeX
Signed-off-by: Danila Fedorin <danila.fedorin@gmail.com>
2024-05-23 21:14:49 -07:00

66 lines
1.6 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)
rendered = content.gsub /\\\(((?:[^\\]|\\[^\)])*)\\\)/ do |match|
render(false, $~[1])
end
rendered = rendered.gsub /\$\$((?:[^\$]|$[^\$])*)\$\$/ do |match|
render(true, $~[1])
end
return rendered
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))
document.search('//*[not(ancestor-or-self::code or ancestor-or-self::script)]/text()').each do |t|
t.replace(renderer.substitute(t.content))
end
File.write(file, document.to_html(encoding: 'UTF-8'))
end