Упрощение генерации графа заметок: удалены неиспользуемые методы и улучшена обработка узлов и рёбер. Обновлён формат сохранения данных в assets/js/graph-data.json.

This commit is contained in:
ada
2025-08-22 16:37:23 +03:00
parent fe3931393b
commit 41fad17b9c
+30 -88
View File
@@ -1,108 +1,50 @@
# _plugins/note_graph.rb # _plugins/note_graph.rb
# Генерирует /graph.json с узлами и рёбрами между заметками из коллекции :notes.
# Понимает [[target]], [[target|alias]], вложенные папки, alias'ы во front matter:
# aliases: ["Короткое имя", "Другое имя"]
require "json" require "json"
module NoteGraph module Jekyll
class Generator < Jekyll::Generator class NoteGraphGenerator < Generator
safe true safe true
priority :low priority :low
WIKI_RX = /\[\[([^\]|#]+)(?:#[^\]|]+)?(?:\|[^\]]+)?\]\]/.freeze
def generate(site) def generate(site)
notes = (site.collections["notes"]&.docs || []) notes = site.collections["notes"].docs
return if notes.empty?
# Карта идентификаторов заметок -> объект nodes = []
# id = относительный путь внутри _notes без расширения, в нижнем регистре
index = {}
aliases = {}
notes.each do |doc|
id = norm_id(doc.relative_path) # напр. "it-school/04-auto"
index[id] = {
"id" => id,
"title" => (doc.data["title"] || File.basename(id)),
"url" => doc.url
}
# поддержка front matter aliases
Array(doc.data["aliases"]).each do |al|
aliases[norm_key(al)] = id
end
# ещё можно сопоставлять обычное название файла без папок
base = File.basename(id)
aliases[norm_key(base)] = id
end
# Узлы
nodes = index.values
# Рёбра
links = [] links = []
notes.each do |doc| notes.each do |note|
src = norm_id(doc.relative_path) # Добавляем узел
content = doc.content.to_s nodes << { id: note.data["title"] || note.basename_without_ext }
content.scan(WIKI_RX).each do |m| # Парсим wiki-ссылки [[...]]
raw = m.first # то, что внутри [[ ... ]] content = note.content
# цель без якоря/алиаса и расширения content.scan(/\[\[([^\]|]+)(?:\|[^\]]+)?\]\]/).flatten.each do |target|
target = raw.strip links << {
target = target.sub(/\|.*/, "") # отрезать |alias source: note.data["title"] || note.basename_without_ext,
target = target.sub(/#.*/, "") # отрезать #heading target: target
target = target.sub(/\.md$/i, "") # убрать .md }
# 1) прямое совпадение по относительному пути
dst = index[norm_id("_notes/#{target}.md")]&.dig("id")
# 2) совпадение по alias/названию файла
dst ||= aliases[norm_key(target)]
next unless dst && index[dst]
links << { "source" => src, "target" => dst }
end end
end end
data = { "nodes" => nodes, "links" => links } graph_hash = { nodes: nodes, links: links }
json_str = JSON.pretty_generate(graph_hash)
site.static_files << GeneratedJson.new(site, data) site.static_files << GeneratedJson.new(site, json_str)
end
end
class GeneratedJson < Jekyll::StaticFile
def initialize(site, content)
@site = site
@content = content
super(site, site.dest, "assets/js", "graph-data.json", nil)
end end
# нормализуем «ключ» def write(_dest)
def norm_key(s) out_path = @site.in_dest_dir("assets/js/graph-data.json")
s.to_s.downcase.strip.gsub("\\", "/") FileUtils.mkdir_p(File.dirname(out_path))
end File.write(out_path, @content)
true
# делаем id из относительного пути документа
# "_notes/IT-School/04-auto.md" -> "it-school/04-auto"
def norm_id(relative_path)
p = relative_path.to_s
p = p.sub(%r!^_notes/!i, "")
p = p.sub(/\.md$/i, "")
p.downcase
end
# Объект статического файла, который кладём в _site/graph.json
class GeneratedJson < Jekyll::StaticFile
def initialize(site, data)
@site = site
@base = site.source
@dir = "/"
@name = "graph.json"
@data = data
super(site, @base, @dir, @name, nil)
end
def write(dest)
out_path = @site.in_dest_dir('assets/js/graph-data.json')
FileUtils.mkdir_p(File.dirname(out_path))
File.write(out_path, json)
true
end
end end
end end
end end