-
Notifications
You must be signed in to change notification settings - Fork 11
/
Copy pathconvert.rb
executable file
·150 lines (124 loc) · 3.22 KB
/
convert.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
#!/usr/bin/env ruby
require 'optparse'
require 'ostruct'
require 'sqlite3'
require 'pathname'
require 'pandoc-ruby'
require 'pry'
require 'shellwords'
DB_PATH = './input/org-roam.db'.freeze
class Note
attr_reader :content
def initialize(row, debug: false)
r = sanitize(row)
@row = OpenStruct.new(r)
@debug = debug
end
def id
@row.id
end
def roam_file
@roam_file ||= "#{@row.file.partition('roam/').last}"
end
def input_file
@input_file ||= "input/roam/#{roam_file}"
end
def title
@row.title.gsub(%r{[\x00\/\\:\*\?\"<>\|]}, '-')
end
def input_title
@row.title
end
def output_file
Pathname(@roam_file).dirname + "#{title}.md"
end
def content
input_file_to_md
end
private
def input_file_to_md
PandocRuby.new([(Shellwords.escape input_file)], :standalone, from: 'org', wrap: 'none').to_gfm
end
def sanitize(row)
r = row.map do |k, v|
key = k.to_s.to_sym
if v.is_a? String
[key, v.gsub('"', '')]
else
[key, v]
end
end
r.to_h
end
end
class Converter
def initialize(debug: false)
@debug = debug
@notes = {}
db = SQLite3::Database.open(DB_PATH)
db.results_as_hash = true
results = db.execute('SELECT * FROM nodes ORDER BY id DESC')
if @debug
puts "Warn: no nodes found in database" if results.length == 0
end
results.each do |result|
note = Note.new(result)
if File.extname(note.input_file) != '.org'
# Skipping encrypted notes
puts "Skipping (unsupported file extension): #{note.input_title}"
if @debug
puts "\tinput file: #{note.input_file}"
puts "\tfile relative to roam dir: #{note.roam_file}"
puts "\textension: #{File.extname(note.input_file)}"
end
next
end
puts "Loading: #{note.input_title}"
@notes[note.id] = note
end
puts '✅ Done loading.'
end
def convert
@notes.each_key { |key| convert_and_write_note(@notes[key]) }
puts '✅ Done converting.'
end
def convert_and_write_note(note)
begin
puts "Converting: #{note.input_title}"
content = convert_links(note)
out_path = Pathname("output/#{note.output_file}")
out_path.dirname.mkpath
out_path.write(content)
rescue StandardError => e
puts "Failed to convert and write note: #{note.input_title}"
puts "\tError: #{e.message}"
puts e.backtrace if @debug
end
end
def convert_links(note)
note.content.gsub(/\[([^\]]+)\]\(([^)]+)\)/) do |_match|
link_text = ::Regexp.last_match(1)
link_target = ::Regexp.last_match(2)
if link_target.start_with?('id:')
target_note_id = link_target.sub('id:', '')
target_note = @notes[target_note_id]
if target_note.nil?
"[Note not found: #{link_text}](#{link_target})"
else
"[[#{target_note.title}]]"
end
else
"[#{link_text}](#{link_target})"
end
end
end
end
options = {}
OptionParser.new do |opts|
opts.banner = "Usage: convert.rb [options]"
opts.on('--debug', 'Run with debug output') do
options[:debug] = true
puts "Running with DEBUG output"
end
end.parse!
Converter.new(debug: options[:debug]).convert