require "pathname" require "set" require "json" def resolve_path(bp, p) path = nil if bp.start_with? "." path = Pathname.new(File.join(bp, p)).cleanpath.to_s elsif p.start_with? "blog/" path = File.join("content", p) else path = File.join("content", "blog", p) end if File.directory? path path = File.join(path, "index.md") elsif !path.end_with? ".md" path += ".md" end path.gsub("blog/blog/", "blog/") end files = Set.new refs = {} Dir['content/blog/**/*.md'].each do |file| file = file.chomp files << file arr = refs[file] || (refs[file] = []) pattern = Regexp.union(/< relref "([^"]+)" >/, /< draftlink "[^"]+" "([^"]+)" >/) File.open(file).read.scan(pattern) do |ref| ref = resolve_path(File.dirname(file), ref[0] || ref[1]) arr << ref files << ref end arr.uniq! end data = {} id = 0 series = {} files.each do |file| id += 1 name = file tags = [] group = 1 draft = false next unless File.exists?(file) value = File.size(file) url = file.gsub(/^content/, "https://danilafe.com").delete_suffix("/index.md").delete_suffix(".md") File.readlines(file).each do |l| if l =~ /^title: (.+)$/ name = $~[1].delete_prefix('"').delete_suffix('"') elsif l =~ /^draft: true$/ draft = true elsif l =~ /^series: (.+)$/ this_series = $~[1] series_list = series.fetch(this_series) do series[this_series] = [] end series_list << file elsif l =~ /^tags: (.+)$/ tags = $~[1].delete_prefix("[").delete_suffix("]").split(/,\s?/).map { |it| it.gsub('"', '') } if tags.include? "Compilers" group = 2 elsif tags.include? "Coq" group = 3 elsif tags.include? "Programming Languages" group = 4 elsif tags.include? "Haskell" group = 5 elsif tags.include? "Crystal" group = 6 elsif tags.include? "Agda" group = 7 elsif tags.include? "Hugo" group = 8 end end end next if draft data[file] = { :id => id, :name => name, :group => group, :tags => tags, :url => url, :value => value } end edges = [] files.each do |file1| # files.each do |file2| # next if file1 == file2 # next unless data[file1][:tags].any? { |t| data[file2][:tags].include? t } # edges << { :from => data[file1][:id], :to => data[file2][:id] } # end next unless frefs = refs[file1] frefs.each do |ref| next unless data[file1] next unless data[ref] edges << { :from => data[file1][:id], :to => data[ref][:id] } end end series.each do |series, files| files.sort.each_cons(2) do |file1, file2| next unless data[file1] next unless data[file2] edges << { :from => data[file1][:id], :to => data[file2][:id] } edges << { :from => data[file2][:id], :to => data[file1][:id] } end end edges.uniq! # edges.filter! { |e| e[:from] < e[:to] } edges.map! { |e| { :from => [e[:from], e[:to]].min, :to => [e[:from], e[:to]].max } }.uniq! puts ("export const nodes = " + JSON.pretty_unparse(data.values) + ";") puts ("export const edges = " + JSON.pretty_unparse(edges) + ";")