raindown 0.9.1 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/raindown/actions.rb +14 -8
- data/lib/raindown/bare_directives.rb +14 -0
- data/lib/raindown/cli.rb +54 -11
- data/lib/raindown/directives.rb +7 -3
- data/lib/raindown/editing.rb +24 -0
- data/lib/raindown/endpoint/curl.rb +60 -27
- data/lib/raindown/endpoint/curl_response.rb +35 -0
- data/lib/raindown/endpoint/endpoint_args.rb +66 -0
- data/lib/raindown/endpoint/endpoint_runner.rb +68 -26
- data/lib/raindown/endpoint/endpoint_variables.rb +111 -0
- data/lib/raindown/endpoint/schema_block.rb +82 -0
- data/lib/raindown/markdown_nodes.rb +67 -0
- data/lib/raindown/node_blocks.rb +25 -12
- data/lib/raindown/nodes.rb +6 -3
- data/lib/raindown/projects.rb +2 -1
- data/lib/raindown/server.rb +73 -0
- data/lib/raindown/tui/project.rb +4 -2
- data/lib/raindown/variables.rb +7 -3
- data/lib/raindown/watcher/file_watcher.rb +3 -1
- data/lib/raindown/watcher/project.rb +2 -0
- data/lib/raindown/wiki_links.rb +66 -0
- data/lib/raindown.rb +2 -0
- data/lib/version.rb +1 -1
- metadata +29 -7
data/lib/raindown/variables.rb
CHANGED
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require 'antlers/api'
|
|
4
|
+
|
|
3
5
|
module Raindown
|
|
4
6
|
# The front matter values that Antlers variables like {title} and <{ title }> render.
|
|
5
7
|
# Antlers reads a variable from the binding's locals, then by sending it to the binding's receiver, which is this.
|
|
6
8
|
# It's a BasicObject so a key like "hash" or "display" isn't shadowed by a method, and unknown names render nothing.
|
|
7
|
-
# Nested values
|
|
9
|
+
# Nested values are hashes and arrays like {author.name}, {tags.0} or <{ for: name, url in: links }>.
|
|
8
10
|
class Variables < BasicObject
|
|
9
11
|
# Braces in a value become the placeholders that render as braces, so Antlers doesn't read them as a variable.
|
|
10
12
|
def self.wrap(value)
|
|
11
13
|
case value
|
|
12
|
-
when ::Hash then
|
|
14
|
+
when ::Hash then value.transform_values { |item| wrap(item) }
|
|
13
15
|
when ::Array then value.map { |item| wrap(item) }
|
|
14
16
|
when ::String then value.gsub(/[{}]/, CODE_BRACES)
|
|
15
17
|
else value
|
|
@@ -20,6 +22,7 @@ module Raindown
|
|
|
20
22
|
def self.unwrap(value)
|
|
21
23
|
case value
|
|
22
24
|
when Variables then value.to_h
|
|
25
|
+
when ::Hash then value.transform_values { |item| unwrap(item) }
|
|
23
26
|
when ::Array then value.map { |item| unwrap(item) }
|
|
24
27
|
when ::String then value.tr(CODE_BRACES.values.join, CODE_BRACES.keys.join)
|
|
25
28
|
else value
|
|
@@ -28,7 +31,8 @@ module Raindown
|
|
|
28
31
|
|
|
29
32
|
# A variable's value, like author.name, read the way {author.name} reads it, unwrapped. Unknown names are nil.
|
|
30
33
|
def self.value(variables, name)
|
|
31
|
-
|
|
34
|
+
first, *path = name.split('.')
|
|
35
|
+
unwrap(::Antlers::Queries.read_path(value: variables.send(first), path:))
|
|
32
36
|
end
|
|
33
37
|
|
|
34
38
|
def initialize(values)
|
|
@@ -51,7 +51,9 @@ module Raindown
|
|
|
51
51
|
|
|
52
52
|
# The files' metadata is loaded again each time, so new and renamed files are listed.
|
|
53
53
|
def rewrite
|
|
54
|
-
Rewriter.update(path:, bare:, execute:, metadata: Pages.for(path))
|
|
54
|
+
changed = Rewriter.update(path:, bare:, execute:, metadata: Pages.for(path))
|
|
55
|
+
EndpointRunner.failures(content: Utils.read_markdown(path), path:, bare:).each { warn "Endpoint check failed: #{it}" }
|
|
56
|
+
changed
|
|
55
57
|
end
|
|
56
58
|
end
|
|
57
59
|
end
|
|
@@ -30,6 +30,8 @@ module Raindown
|
|
|
30
30
|
def update(path)
|
|
31
31
|
changed = Rewriter.update(path:, bare: @bare, execute: @execute, metadata: Pages.for(path))
|
|
32
32
|
puts "[#{name}] Updated #{relative(path)}" if changed
|
|
33
|
+
EndpointRunner.failures(content: Utils.read_markdown(path), path:, bare: @bare)
|
|
34
|
+
.each { warn "[#{name}] Endpoint check failed: #{it}" }
|
|
33
35
|
rescue StandardError => e
|
|
34
36
|
raise if ENV['RAINDOWN_DEBUG']
|
|
35
37
|
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'code'
|
|
4
|
+
require_relative 'front_matter'
|
|
5
|
+
|
|
6
|
+
module Raindown
|
|
7
|
+
# Obsidian's links between notes, which render as Markdown links to the file they name, by its path in the project,
|
|
8
|
+
# like files: links, while the file keeps them as they are:
|
|
9
|
+
# [[Reading list]] [Reading list](<notes/Reading list.md>)
|
|
10
|
+
# [[Reading list|books]] [books](<notes/Reading list.md>)
|
|
11
|
+
# [[Reading list#To read]] [Reading list > To read](<notes/Reading list.md#to-read>)
|
|
12
|
+
# A name matches a file's name, or the end of its path, like [[notes/Reading list]], without its extension and
|
|
13
|
+
# whatever its case. One that matches no file, and ones in code or front matter, are left as they are, as are
|
|
14
|
+
# embeds, like ![[photo.png]].
|
|
15
|
+
module WikiLinks
|
|
16
|
+
LINK = /(?<!!)\[\[([^\[\]|#\n]+)(?:#([^\[\]|\n]+))?(?:\|([^\[\]\n]+))?\]\]/
|
|
17
|
+
|
|
18
|
+
module_function
|
|
19
|
+
|
|
20
|
+
def to_markdown(markdown, metadata:)
|
|
21
|
+
return markdown unless markdown.include?('[[')
|
|
22
|
+
|
|
23
|
+
pages = metadata.list
|
|
24
|
+
links(markdown).reverse_each.with_object(markdown.b) do |link, bytes|
|
|
25
|
+
page = page_for(link[1], pages)
|
|
26
|
+
bytes[link.byteoffset(0)[0]...link.byteoffset(0)[1]] = markdown_link(link, page).b if page
|
|
27
|
+
end.force_encoding('UTF-8')
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# The links in the Markdown, outside its code and front matter, as matches.
|
|
31
|
+
def links(markdown)
|
|
32
|
+
start = markdown.bytesize - FrontMatter.parse(markdown).last.bytesize
|
|
33
|
+
code = Code.ranges(markdown)
|
|
34
|
+
found = []
|
|
35
|
+
|
|
36
|
+
markdown.scan(LINK) do
|
|
37
|
+
link = ::Regexp.last_match
|
|
38
|
+
offset = link.byteoffset(0)[0]
|
|
39
|
+
found << link if offset >= start && code.none? { it.cover?(offset) }
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
found
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# The page a name links to: one whose path without its extension is the name, or ends with it.
|
|
46
|
+
def page_for(name, pages)
|
|
47
|
+
name = name.strip.downcase.sub(/\.(?:md|rd|markdown|raindown)\z/, '')
|
|
48
|
+
stems = pages.to_h { [it, it.path.to_s.downcase.sub(%r{\.[^./]+\z}, '')] }
|
|
49
|
+
|
|
50
|
+
pages.find { stems[it] == name } || pages.find { stems[it].end_with?("/#{name}") }
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def markdown_link(link, page)
|
|
54
|
+
name, heading, label = link.captures.map { it&.strip }
|
|
55
|
+
label ||= [name, heading].compact.join(' > ')
|
|
56
|
+
anchor = "##{anchor(heading)}" if heading
|
|
57
|
+
|
|
58
|
+
"[#{label.gsub(/[\[\]]/) { "\\#{it}" }}](<#{page.path}#{anchor}>)"
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# A heading's id, the way Commonmarker makes it, like to-read for "To read".
|
|
62
|
+
def anchor(heading)
|
|
63
|
+
heading.downcase.gsub(/[^\p{Word}\- ]/, '').tr(' ', '-')
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
data/lib/raindown.rb
CHANGED
|
@@ -17,6 +17,7 @@ require_relative 'raindown/pages'
|
|
|
17
17
|
require_relative 'raindown/pre_renderer'
|
|
18
18
|
require_relative 'raindown/utils'
|
|
19
19
|
require_relative 'raindown/variables'
|
|
20
|
+
require_relative 'raindown/wiki_links'
|
|
20
21
|
|
|
21
22
|
module Raindown
|
|
22
23
|
# Antlers evaluates any braces in the HTML, so braces in code are swapped for placeholders
|
|
@@ -83,6 +84,7 @@ module Raindown
|
|
|
83
84
|
# The document's HTML from Commonmarker, after nodes and the template pass, with components as fragments.
|
|
84
85
|
def html(markdown:, variables:, metadata: NoMetadata, bare: false)
|
|
85
86
|
markdown = NodeBlocks.to_rendered(markdown.dup.force_encoding('UTF-8'), metadata:, bare:)
|
|
87
|
+
markdown = WikiLinks.to_markdown(markdown, metadata:)
|
|
86
88
|
commonmark(PreRenderer.render(markdown, variables:, metadata:, bare:))
|
|
87
89
|
end
|
|
88
90
|
|
data/lib/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: raindown
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.11.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- maedi
|
|
8
8
|
bindir: bin
|
|
9
9
|
cert_chain: []
|
|
10
|
-
date: 2026-11-
|
|
10
|
+
date: 2026-11-04 00:00:00.000000000 Z
|
|
11
11
|
dependencies:
|
|
12
12
|
- !ruby/object:Gem::Dependency
|
|
13
13
|
name: antlers
|
|
@@ -15,14 +15,14 @@ dependencies:
|
|
|
15
15
|
requirements:
|
|
16
16
|
- - ">="
|
|
17
17
|
- !ruby/object:Gem::Version
|
|
18
|
-
version: 1.
|
|
18
|
+
version: 1.4.0
|
|
19
19
|
type: :runtime
|
|
20
20
|
prerelease: false
|
|
21
21
|
version_requirements: !ruby/object:Gem::Requirement
|
|
22
22
|
requirements:
|
|
23
23
|
- - ">="
|
|
24
24
|
- !ruby/object:Gem::Version
|
|
25
|
-
version: 1.
|
|
25
|
+
version: 1.4.0
|
|
26
26
|
- !ruby/object:Gem::Dependency
|
|
27
27
|
name: commonmarker
|
|
28
28
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -121,6 +121,20 @@ dependencies:
|
|
|
121
121
|
- - ">="
|
|
122
122
|
- !ruby/object:Gem::Version
|
|
123
123
|
version: '0'
|
|
124
|
+
- !ruby/object:Gem::Dependency
|
|
125
|
+
name: lowtype
|
|
126
|
+
requirement: !ruby/object:Gem::Requirement
|
|
127
|
+
requirements:
|
|
128
|
+
- - ">="
|
|
129
|
+
- !ruby/object:Gem::Version
|
|
130
|
+
version: '1.7'
|
|
131
|
+
type: :runtime
|
|
132
|
+
prerelease: false
|
|
133
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
134
|
+
requirements:
|
|
135
|
+
- - ">="
|
|
136
|
+
- !ruby/object:Gem::Version
|
|
137
|
+
version: '1.7'
|
|
124
138
|
- !ruby/object:Gem::Dependency
|
|
125
139
|
name: plugs
|
|
126
140
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -211,8 +225,13 @@ files:
|
|
|
211
225
|
- lib/raindown/config.rb
|
|
212
226
|
- lib/raindown/directives.rb
|
|
213
227
|
- lib/raindown/document.rb
|
|
228
|
+
- lib/raindown/editing.rb
|
|
214
229
|
- lib/raindown/endpoint/curl.rb
|
|
230
|
+
- lib/raindown/endpoint/curl_response.rb
|
|
231
|
+
- lib/raindown/endpoint/endpoint_args.rb
|
|
215
232
|
- lib/raindown/endpoint/endpoint_runner.rb
|
|
233
|
+
- lib/raindown/endpoint/endpoint_variables.rb
|
|
234
|
+
- lib/raindown/endpoint/schema_block.rb
|
|
216
235
|
- lib/raindown/files.rb
|
|
217
236
|
- lib/raindown/fragments.rb
|
|
218
237
|
- lib/raindown/front_matter.rb
|
|
@@ -220,6 +239,7 @@ files:
|
|
|
220
239
|
- lib/raindown/heading_ids.rb
|
|
221
240
|
- lib/raindown/js/host.mjs
|
|
222
241
|
- lib/raindown/js/js_nodes.rb
|
|
242
|
+
- lib/raindown/markdown_nodes.rb
|
|
223
243
|
- lib/raindown/node.rb
|
|
224
244
|
- lib/raindown/node_blocks.rb
|
|
225
245
|
- lib/raindown/node_injector.rb
|
|
@@ -229,6 +249,7 @@ files:
|
|
|
229
249
|
- lib/raindown/pre_renderer.rb
|
|
230
250
|
- lib/raindown/projects.rb
|
|
231
251
|
- lib/raindown/rewriter.rb
|
|
252
|
+
- lib/raindown/server.rb
|
|
232
253
|
- lib/raindown/stat.rb
|
|
233
254
|
- lib/raindown/table_formatter.rb
|
|
234
255
|
- lib/raindown/toc.rb
|
|
@@ -304,14 +325,15 @@ files:
|
|
|
304
325
|
- lib/raindown/watcher/file_watcher.rb
|
|
305
326
|
- lib/raindown/watcher/project.rb
|
|
306
327
|
- lib/raindown/watcher/supervisor.rb
|
|
328
|
+
- lib/raindown/wiki_links.rb
|
|
307
329
|
- lib/raindown/workers/worker.rb
|
|
308
330
|
- lib/raindown/workers/workers.rb
|
|
309
331
|
- lib/version.rb
|
|
310
|
-
homepage: https://github.com/
|
|
332
|
+
homepage: https://github.com/rainpour/raindown
|
|
311
333
|
licenses: []
|
|
312
334
|
metadata:
|
|
313
|
-
homepage_uri: https://github.com/
|
|
314
|
-
source_code_uri: https://github.com/
|
|
335
|
+
homepage_uri: https://github.com/rainpour/raindown
|
|
336
|
+
source_code_uri: https://github.com/rainpour/raindown/tree/main
|
|
315
337
|
rdoc_options: []
|
|
316
338
|
require_paths:
|
|
317
339
|
- lib
|