From 41fad17b9cca63299e147d4d7141f29063e81a84 Mon Sep 17 00:00:00 2001 From: ada Date: Fri, 22 Aug 2025 16:37:23 +0300 Subject: [PATCH] =?UTF-8?q?=D0=A3=D0=BF=D1=80=D0=BE=D1=89=D0=B5=D0=BD?= =?UTF-8?q?=D0=B8=D0=B5=20=D0=B3=D0=B5=D0=BD=D0=B5=D1=80=D0=B0=D1=86=D0=B8?= =?UTF-8?q?=D0=B8=20=D0=B3=D1=80=D0=B0=D1=84=D0=B0=20=D0=B7=D0=B0=D0=BC?= =?UTF-8?q?=D0=B5=D1=82=D0=BE=D0=BA:=20=D1=83=D0=B4=D0=B0=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=D1=8B=20=D0=BD=D0=B5=D0=B8=D1=81=D0=BF=D0=BE=D0=BB=D1=8C?= =?UTF-8?q?=D0=B7=D1=83=D0=B5=D0=BC=D1=8B=D0=B5=20=D0=BC=D0=B5=D1=82=D0=BE?= =?UTF-8?q?=D0=B4=D1=8B=20=D0=B8=20=D1=83=D0=BB=D1=83=D1=87=D1=88=D0=B5?= =?UTF-8?q?=D0=BD=D0=B0=20=D0=BE=D0=B1=D1=80=D0=B0=D0=B1=D0=BE=D1=82=D0=BA?= =?UTF-8?q?=D0=B0=20=D1=83=D0=B7=D0=BB=D0=BE=D0=B2=20=D0=B8=20=D1=80=D1=91?= =?UTF-8?q?=D0=B1=D0=B5=D1=80.=20=D0=9E=D0=B1=D0=BD=D0=BE=D0=B2=D0=BB?= =?UTF-8?q?=D1=91=D0=BD=20=D1=84=D0=BE=D1=80=D0=BC=D0=B0=D1=82=20=D1=81?= =?UTF-8?q?=D0=BE=D1=85=D1=80=D0=B0=D0=BD=D0=B5=D0=BD=D0=B8=D1=8F=20=D0=B4?= =?UTF-8?q?=D0=B0=D0=BD=D0=BD=D1=8B=D1=85=20=D0=B2=20assets/js/graph-data.?= =?UTF-8?q?json.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- _plugins/note_graph.rb | 118 +++++++++++------------------------------ 1 file changed, 30 insertions(+), 88 deletions(-) diff --git a/_plugins/note_graph.rb b/_plugins/note_graph.rb index fa79851..34e8f49 100644 --- a/_plugins/note_graph.rb +++ b/_plugins/note_graph.rb @@ -1,108 +1,50 @@ # _plugins/note_graph.rb -# Генерирует /graph.json с узлами и рёбрами между заметками из коллекции :notes. -# Понимает [[target]], [[target|alias]], вложенные папки, alias'ы во front matter: -# aliases: ["Короткое имя", "Другое имя"] - require "json" -module NoteGraph - class Generator < Jekyll::Generator +module Jekyll + class NoteGraphGenerator < Generator safe true priority :low - WIKI_RX = /\[\[([^\]|#]+)(?:#[^\]|]+)?(?:\|[^\]]+)?\]\]/.freeze - def generate(site) - notes = (site.collections["notes"]&.docs || []) - return if notes.empty? + notes = site.collections["notes"].docs - # Карта идентификаторов заметок -> объект - # 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 - - # Рёбра + nodes = [] links = [] - notes.each do |doc| - src = norm_id(doc.relative_path) - content = doc.content.to_s + notes.each do |note| + # Добавляем узел + nodes << { id: note.data["title"] || note.basename_without_ext } - content.scan(WIKI_RX).each do |m| - raw = m.first # то, что внутри [[ ... ]] - # цель без якоря/алиаса и расширения - target = raw.strip - target = target.sub(/\|.*/, "") # отрезать |alias - target = target.sub(/#.*/, "") # отрезать #heading - 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 } + # Парсим wiki-ссылки [[...]] + content = note.content + content.scan(/\[\[([^\]|]+)(?:\|[^\]]+)?\]\]/).flatten.each do |target| + links << { + source: note.data["title"] || note.basename_without_ext, + target: target + } 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 - # нормализуем «ключ» - def norm_key(s) - s.to_s.downcase.strip.gsub("\\", "/") - end - - # делаем 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 + 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, @content) + true end end end