raindown 0.8.1 → 0.9.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 +1 -1
- data/lib/raindown/document.rb +1 -1
- data/lib/raindown/js/host.mjs +51 -0
- data/lib/raindown/js/js_nodes.rb +91 -0
- data/lib/raindown/nodes.rb +8 -5
- data/lib/raindown/page.rb +1 -1
- data/lib/raindown/pages.rb +2 -1
- data/lib/raindown/projects.rb +3 -1
- data/lib/raindown/rewriter.rb +2 -1
- data/lib/raindown/tui/project.rb +2 -2
- data/lib/raindown/tui/terminal/input.rb +11 -4
- data/lib/raindown/utils.rb +21 -0
- data/lib/raindown.rb +2 -1
- data/lib/version.rb +1 -1
- metadata +5 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ad54482b1bd78c23942aefb02bc8a8b9cce56e369ecbb67366668187ed521323
|
|
4
|
+
data.tar.gz: 9d8475c719c52063424a6215c762a926e67641700981b6834dd56e07d410d535
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 8789f0135781bfe782ae2af47f2bd537cafef9d55a522ba592bbcc1c8f27e0364cfbb860cb0aa106617af0bd6e82d2bd0174084ca4bd3ca7779b82e2e284ff79
|
|
7
|
+
data.tar.gz: 88237d0429270a0651434511d462b0051b9a752a2e8aae315e4d2bafc0ef833fa1818d8424cf5e025b12655c9df3de6a22e6eab7e23e1b40ec0063d7fe4f3396
|
data/lib/raindown/actions.rb
CHANGED
|
@@ -31,7 +31,7 @@ module Raindown
|
|
|
31
31
|
raise NotAnEndpoint, "#{directive.name} on line #{directive.line} isn't an endpoint" unless directive.endpoint?
|
|
32
32
|
raise NotAnEndpoint, "The endpoint on line #{directive.line} only renders, so put it in comments to run it" unless directive.writes
|
|
33
33
|
|
|
34
|
-
content =
|
|
34
|
+
content = Utils.read_markdown(path)
|
|
35
35
|
rewritten = EndpointRunner.new(content:, bare: BareDirectives.enabled?(path:, content:), only: directive.line - 1).rewrite
|
|
36
36
|
return false if rewritten == content
|
|
37
37
|
|
data/lib/raindown/document.rb
CHANGED
|
@@ -39,7 +39,7 @@ module Raindown
|
|
|
39
39
|
# they're allowed, like with --bare.
|
|
40
40
|
# A project's own nodes are only directives once they're loaded, like with Nodes.load(path), the same as when the file renders.
|
|
41
41
|
def self.read(path, bare: false)
|
|
42
|
-
new(markdown:
|
|
42
|
+
new(markdown: Utils.read_markdown(path), bare: bare || BareDirectives.file?(path))
|
|
43
43
|
end
|
|
44
44
|
|
|
45
45
|
def initialize(markdown:, bare: false)
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
// Runs a project's JavaScript Components for Raindown, which starts it with node -e, since inside Raindown's package
|
|
2
|
+
// the script is where NodeJS can't read it. Each line on stdin is a request, answered by one line of JSON on stdout:
|
|
3
|
+
// { op: 'load', folder } → { nodes: [{ name, render }] }
|
|
4
|
+
// { op: 'new', id, name, args, props } → {}
|
|
5
|
+
// { op: 'call', id, method, context } → { value }
|
|
6
|
+
// A request that throws is answered with { error }.
|
|
7
|
+
import { readdirSync } from 'node:fs'
|
|
8
|
+
import { join } from 'node:path'
|
|
9
|
+
import { createInterface } from 'node:readline'
|
|
10
|
+
import { pathToFileURL } from 'node:url'
|
|
11
|
+
|
|
12
|
+
// stdout carries the replies, so what nodes log goes to stderr.
|
|
13
|
+
console.log = console.info = console.error
|
|
14
|
+
|
|
15
|
+
const classes = {}
|
|
16
|
+
const nodes = {}
|
|
17
|
+
|
|
18
|
+
const requests = {
|
|
19
|
+
// Every exported class with replace is a node, named by its export, or by its class for a default export.
|
|
20
|
+
async load({ folder }) {
|
|
21
|
+
for (const file of readdirSync(folder).filter((file) => /\.m?js$/.test(file))) {
|
|
22
|
+
const exports = await import(pathToFileURL(join(folder, file)).href)
|
|
23
|
+
|
|
24
|
+
for (const [name, value] of Object.entries(exports)) {
|
|
25
|
+
if (typeof value?.prototype?.replace === 'function') classes[name === 'default' ? value.name : name] = value
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const nodes = Object.entries(classes).map(([name, node]) => ({ name, render: typeof node.prototype.render === 'function' }))
|
|
30
|
+
return { nodes }
|
|
31
|
+
},
|
|
32
|
+
|
|
33
|
+
new({ id, name, args, props }) {
|
|
34
|
+
nodes[id] = new classes[name](props, ...args)
|
|
35
|
+
return {}
|
|
36
|
+
},
|
|
37
|
+
|
|
38
|
+
async call({ id, method, context }) {
|
|
39
|
+
return { value: await nodes[id][method](context) }
|
|
40
|
+
},
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
for await (const line of createInterface({ input: process.stdin })) {
|
|
44
|
+
const request = JSON.parse(line)
|
|
45
|
+
|
|
46
|
+
try {
|
|
47
|
+
process.stdout.write(`${JSON.stringify(await requests[request.op](request))}\n`)
|
|
48
|
+
} catch (error) {
|
|
49
|
+
process.stdout.write(`${JSON.stringify({ error: String(error?.message ?? error) })}\n`)
|
|
50
|
+
}
|
|
51
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'json'
|
|
4
|
+
require 'open3'
|
|
5
|
+
|
|
6
|
+
require_relative '../node'
|
|
7
|
+
|
|
8
|
+
module Raindown
|
|
9
|
+
# JavaScript Components, the .js and .mjs files in a project's .raindown folder, which export classes with replace and
|
|
10
|
+
# optionally render, like Ruby nodes. They run in a NodeJS process of Raindown's own, started when a folder has them,
|
|
11
|
+
# so only projects with JavaScript Components need NodeJS.
|
|
12
|
+
module JSNodes
|
|
13
|
+
EXTENSIONS = %w[.js .mjs].freeze
|
|
14
|
+
SCRIPT = File.join(__dir__, 'host.mjs')
|
|
15
|
+
|
|
16
|
+
class Error < StandardError; end
|
|
17
|
+
|
|
18
|
+
# The NodeJS process running the nodes, which answers each request with a line of JSON. NodeJS can't read the script
|
|
19
|
+
# inside Raindown's package, so it's passed to node -e.
|
|
20
|
+
class Host
|
|
21
|
+
def initialize
|
|
22
|
+
@input, @output, = Open3.popen2('node', '--input-type=module', '-e', File.read(SCRIPT))
|
|
23
|
+
rescue Errno::ENOENT
|
|
24
|
+
raise Error, 'JavaScript Components need NodeJS 22 or later on your PATH'
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def request(**message)
|
|
28
|
+
@input.puts(JSON.generate(message))
|
|
29
|
+
reply = JSON.parse(@output.gets || raise(Error, 'NodeJS stopped running the JavaScript Components'))
|
|
30
|
+
raise Error, reply['error'] if reply['error']
|
|
31
|
+
|
|
32
|
+
reply
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
module_function
|
|
37
|
+
|
|
38
|
+
# Loads the JavaScript Components in a .raindown folder, starting NodeJS the first time a folder has any.
|
|
39
|
+
def load(folder)
|
|
40
|
+
return if Dir.glob(EXTENSIONS.map { "*#{it}" }, base: folder).empty?
|
|
41
|
+
|
|
42
|
+
host.request(op: 'load', folder:).fetch('nodes').each do |node|
|
|
43
|
+
node_classes[node['name']] ||= JSNode.for(name: node['name'], render: node['render'])
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def node_class(name)
|
|
48
|
+
node_classes[name]
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def host
|
|
52
|
+
@host ||= Host.new
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def node_classes
|
|
56
|
+
@node_classes ||= {}
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# A JavaScript Component, made in the NodeJS process with its props, where its replace and render are sent.
|
|
61
|
+
class JSNode < Node
|
|
62
|
+
# A class for each JavaScript Component, which renders its own HTML when the component has render.
|
|
63
|
+
def self.for(name:, render:)
|
|
64
|
+
Class.new(self) do
|
|
65
|
+
define_singleton_method(:name) { name }
|
|
66
|
+
define_method(:render) { |**context| js_output(:render, context) } if render
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def initialize(*args, **props)
|
|
71
|
+
super()
|
|
72
|
+
JSNodes.host.request(op: 'new', id: object_id, name: self.class.name, args:, props:)
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def replace(**context)
|
|
76
|
+
js_output(:replace, context)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
private
|
|
80
|
+
|
|
81
|
+
def js_output(method, context)
|
|
82
|
+
JSNodes.host.request(op: 'call', id: object_id, method:, context: json_context(**context)).fetch('value').to_s
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
# JSON can't hold Pages, so the metadata is its root and each file's front matter and path.
|
|
86
|
+
def json_context(metadata: NoMetadata, **context)
|
|
87
|
+
root = metadata.root if metadata.respond_to?(:root)
|
|
88
|
+
{ **context, metadata: { root:, files: metadata.list.map(&:metadata) } }
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|
data/lib/raindown/nodes.rb
CHANGED
|
@@ -2,13 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
require_relative 'chart/chart'
|
|
4
4
|
require_relative 'files'
|
|
5
|
+
require_relative 'js/js_nodes'
|
|
5
6
|
require_relative 'node'
|
|
6
7
|
require_relative 'stat'
|
|
7
8
|
require_relative 'toc'
|
|
8
9
|
|
|
9
10
|
module Raindown
|
|
10
11
|
# Nodes are LowNodes that a node block writes into the Markdown and renders into the HTML.
|
|
11
|
-
# A project keeps them in a .raindown folder, which is loaded with Dirload.
|
|
12
|
+
# A project keeps them in a .raindown folder, which is loaded with Dirload, beside its JavaScript Components, if any.
|
|
12
13
|
# A node writes Markdown with #replace, and HTML with #render if it has one. Either can take the keywords
|
|
13
14
|
# document: (the Markdown being rendered), metadata: and bare:, and gets the ones it asks for.
|
|
14
15
|
module Nodes
|
|
@@ -29,6 +30,7 @@ module Raindown
|
|
|
29
30
|
require 'dirload'
|
|
30
31
|
loaded << folder
|
|
31
32
|
dirload(folder)
|
|
33
|
+
JSNodes.load(folder)
|
|
32
34
|
end
|
|
33
35
|
|
|
34
36
|
def find_folder(directory)
|
|
@@ -54,11 +56,12 @@ module Raindown
|
|
|
54
56
|
loaded_class(BUILT_INS[name]) || Raindown.const_get(BUILT_INS[name])
|
|
55
57
|
end
|
|
56
58
|
|
|
59
|
+
# A Ruby node of the name, or else a JavaScript one.
|
|
57
60
|
def loaded_class(name)
|
|
58
|
-
klass = Object.const_get(name)
|
|
59
|
-
klass if node?(klass)
|
|
60
|
-
|
|
61
|
-
|
|
61
|
+
klass = Object.const_get(name) if Object.const_defined?(name)
|
|
62
|
+
return klass if node?(klass)
|
|
63
|
+
|
|
64
|
+
JSNodes.node_class(name)
|
|
62
65
|
end
|
|
63
66
|
|
|
64
67
|
# A LowNode, or one of Raindown's own nodes, that writes Markdown. In an app, LowNodes are also routes and pages,
|
data/lib/raindown/page.rb
CHANGED
|
@@ -17,7 +17,7 @@ module Raindown
|
|
|
17
17
|
# It follows the file's project config, like render_file, unless the render options say otherwise.
|
|
18
18
|
def content
|
|
19
19
|
@content ||= begin
|
|
20
|
-
markdown =
|
|
20
|
+
markdown = Utils.read_markdown(file_path)
|
|
21
21
|
|
|
22
22
|
if FrontMatter.parse(markdown).last.strip.empty? then ''
|
|
23
23
|
else Raindown.render(markdown:, bare: BareDirectives.file?(file_path), **Config.render_options(file_path).merge(@render_options))
|
data/lib/raindown/pages.rb
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
require_relative 'front_matter'
|
|
4
4
|
require_relative 'page'
|
|
5
|
+
require_relative 'utils'
|
|
5
6
|
|
|
6
7
|
module Raindown
|
|
7
8
|
# The metadata of a project's Markdown files, which list: and files: list by tag.
|
|
@@ -62,7 +63,7 @@ module Raindown
|
|
|
62
63
|
end
|
|
63
64
|
|
|
64
65
|
def process(file_path:)
|
|
65
|
-
metadata = implicit_metadata(file_path:).merge(FrontMatter.parse(
|
|
66
|
+
metadata = implicit_metadata(file_path:).merge(FrontMatter.parse(Utils.read_markdown(file_path)).first)
|
|
66
67
|
@metadata[file_path] = metadata
|
|
67
68
|
metadata.each { |type, tag| Array(tag).each { |item| tag(type:, tag: item, file_path:) } }
|
|
68
69
|
end
|
data/lib/raindown/projects.rb
CHANGED
|
@@ -10,6 +10,8 @@ module Raindown
|
|
|
10
10
|
module Projects
|
|
11
11
|
# Folders of dependencies, builds and tooling, which aren't searched for projects or watched, nor are hidden folders.
|
|
12
12
|
IGNORED = %w[node_modules vendor tmp pkg build dist coverage].freeze
|
|
13
|
+
# Ruby nodes and JavaScript Components.
|
|
14
|
+
NODE_EXTENSIONS = ['.rb', '.rbx', *JSNodes::EXTENSIONS].freeze
|
|
13
15
|
|
|
14
16
|
module_function
|
|
15
17
|
|
|
@@ -61,7 +63,7 @@ module Raindown
|
|
|
61
63
|
|
|
62
64
|
# Whether a file is one of a project's own nodes, which load when its watcher starts.
|
|
63
65
|
def node?(path, root:)
|
|
64
|
-
File.expand_path(path).start_with?(File.join(root, Nodes::FOLDER, '')) &&
|
|
66
|
+
File.expand_path(path).start_with?(File.join(root, Nodes::FOLDER, '')) && NODE_EXTENSIONS.include?(File.extname(path))
|
|
65
67
|
end
|
|
66
68
|
|
|
67
69
|
def project?(folder)
|
data/lib/raindown/rewriter.rb
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
require_relative 'node_injector'
|
|
4
4
|
require_relative 'endpoint/endpoint_runner'
|
|
5
5
|
require_relative 'table_formatter'
|
|
6
|
+
require_relative 'utils'
|
|
6
7
|
|
|
7
8
|
module Raindown
|
|
8
9
|
# Rewrites the generated parts of a Markdown file in place before it's rendered:
|
|
@@ -21,7 +22,7 @@ module Raindown
|
|
|
21
22
|
|
|
22
23
|
# Returns true when the file changed.
|
|
23
24
|
def update(path:, bare: false, execute: false, metadata: NoMetadata)
|
|
24
|
-
content =
|
|
25
|
+
content = Utils.read_markdown(path)
|
|
25
26
|
rewritten = rewrite(content:, path:, bare:, execute:, metadata:)
|
|
26
27
|
return false if rewritten == content
|
|
27
28
|
|
data/lib/raindown/tui/project.rb
CHANGED
|
@@ -65,7 +65,7 @@ module Raindown
|
|
|
65
65
|
# the ones whose snippet can't be read.
|
|
66
66
|
def endpoints
|
|
67
67
|
Projects.files(root).flat_map do |path|
|
|
68
|
-
lines =
|
|
68
|
+
lines = Utils.read_markdown(path).lines
|
|
69
69
|
runnable = Document.read(path, bare: @bare).directives.select { it.endpoint? && it.writes }
|
|
70
70
|
runnable.filter_map { |directive| endpoint(path, lines, directive) }
|
|
71
71
|
rescue StandardError
|
|
@@ -94,7 +94,7 @@ module Raindown
|
|
|
94
94
|
end
|
|
95
95
|
|
|
96
96
|
def charts_in(path)
|
|
97
|
-
content =
|
|
97
|
+
content = Utils.read_markdown(path)
|
|
98
98
|
bare = @bare || BareDirectives.enabled?(path:, content:)
|
|
99
99
|
lines = content.lines
|
|
100
100
|
headings = Document.parse(content, bare:).headings
|
|
@@ -34,7 +34,7 @@ module Raindown
|
|
|
34
34
|
Curses.stdscr.timeout = timeout
|
|
35
35
|
key = Curses.stdscr.getch
|
|
36
36
|
return :tick if key.nil?
|
|
37
|
-
return mouse(zones) if key == Curses::KEY_MOUSE
|
|
37
|
+
return mouse(zones) if MOUSE && key == Curses::KEY_MOUSE
|
|
38
38
|
|
|
39
39
|
Curses.stdscr.clear if key == Curses::KEY_RESIZE
|
|
40
40
|
key_event(key, typing:)
|
|
@@ -60,22 +60,27 @@ module Raindown
|
|
|
60
60
|
TYPING_KEYS.fetch(key) { Type.new(text: key) if key.is_a?(String) && key.match?(/\A[[:print:]]\z/) }
|
|
61
61
|
end
|
|
62
62
|
|
|
63
|
+
# Windows' curses has no mouse, so the curses gem leaves out its constants and the mouse does nothing there.
|
|
64
|
+
MOUSE = Curses.respond_to?(:mousemask)
|
|
65
|
+
|
|
63
66
|
# The mouse buttons that click, which are the left button's. Scrolling does nothing, and since older ncurses,
|
|
64
67
|
# like macOS's, has no button for scrolling down, it can't be mistaken for a click.
|
|
65
|
-
CLICKS = Curses::BUTTON1_PRESSED | Curses::BUTTON1_CLICKED
|
|
68
|
+
CLICKS = MOUSE && Curses::BUTTON1_PRESSED | Curses::BUTTON1_CLICKED
|
|
66
69
|
|
|
67
70
|
# Letting go of the button, which older ncurses, like macOS's, also reports for each move while it's held, as it
|
|
68
71
|
# doesn't know the moves terminals send then.
|
|
69
|
-
RELEASE = Curses::BUTTON1_RELEASED
|
|
72
|
+
RELEASE = MOUSE && Curses::BUTTON1_RELEASED
|
|
70
73
|
|
|
71
74
|
# Moving the mouse, which terminals report once they're asked to, with any motion tracking.
|
|
72
|
-
MOTION = Curses::REPORT_MOUSE_POSITION
|
|
75
|
+
MOTION = MOUSE && Curses::REPORT_MOUSE_POSITION
|
|
73
76
|
ANY_MOTION = "\e[?1003h"
|
|
74
77
|
NO_MOTION = "\e[?1003l"
|
|
75
78
|
|
|
76
79
|
# The terminal sends the app its mouse events, clicks and moves, so scrolling doesn't scroll the terminal either.
|
|
77
80
|
# ncurses only asks some terminals to report every move, so it's asked directly too, until untrack_mouse.
|
|
78
81
|
def track_mouse
|
|
82
|
+
return unless MOUSE
|
|
83
|
+
|
|
79
84
|
Curses.mousemask(CLICKS | RELEASE | MOTION)
|
|
80
85
|
Curses.mouseinterval(0)
|
|
81
86
|
$stdout.write(ANY_MOTION)
|
|
@@ -83,6 +88,8 @@ module Raindown
|
|
|
83
88
|
end
|
|
84
89
|
|
|
85
90
|
def untrack_mouse
|
|
91
|
+
return unless MOUSE
|
|
92
|
+
|
|
86
93
|
$stdout.write(NO_MOTION)
|
|
87
94
|
$stdout.flush
|
|
88
95
|
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Raindown
|
|
4
|
+
module Utils
|
|
5
|
+
module_function
|
|
6
|
+
|
|
7
|
+
# A Markdown file's text, with its line endings as LF, "\n", whatever they are in the file.
|
|
8
|
+
#
|
|
9
|
+
# Windows ends lines with CRLF, "\r\n", and Git for Windows checks files out that way, so a file written or cloned on
|
|
10
|
+
# Windows can reach Raindown with them on any platform. Raindown finds directives, like a bare toc:, front matter
|
|
11
|
+
# and code fences line by line, with patterns that end at "\n", so a "\r" left at the end of a line stops them
|
|
12
|
+
# matching: toc: would be left as text instead of writing its table of contents.
|
|
13
|
+
#
|
|
14
|
+
# Text mode ("rt") reads CRLF as LF on every platform, as Ruby does on Windows by default, so the rest of Raindown
|
|
15
|
+
# only ever sees "\n". Writing a file back then gives it LF line endings, except on Windows, where text mode writes
|
|
16
|
+
# CRLF again.
|
|
17
|
+
def read_markdown(path)
|
|
18
|
+
File.read(path, mode: 'rt', encoding: Encoding::UTF_8)
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
data/lib/raindown.rb
CHANGED
|
@@ -15,6 +15,7 @@ require_relative 'raindown/heading_ids'
|
|
|
15
15
|
require_relative 'raindown/node_blocks'
|
|
16
16
|
require_relative 'raindown/pages'
|
|
17
17
|
require_relative 'raindown/pre_renderer'
|
|
18
|
+
require_relative 'raindown/utils'
|
|
18
19
|
require_relative 'raindown/variables'
|
|
19
20
|
|
|
20
21
|
module Raindown
|
|
@@ -40,7 +41,7 @@ module Raindown
|
|
|
40
41
|
# Code is highlighted, unless the file's project changes it in .raindown/config.yml.
|
|
41
42
|
def render_file(path:, metadata: NoMetadata, bare: false, **options)
|
|
42
43
|
options = Config.render_options(path).merge(options)
|
|
43
|
-
render(markdown:
|
|
44
|
+
render(markdown: Utils.read_markdown(path), metadata:, bare: bare || BareDirectives.file?(path), **options)
|
|
44
45
|
end
|
|
45
46
|
|
|
46
47
|
# Front matter keys are variables, like {title} or <{ title }>.
|
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.9.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-03 00:00:00.000000000 Z
|
|
11
11
|
dependencies:
|
|
12
12
|
- !ruby/object:Gem::Dependency
|
|
13
13
|
name: antlers
|
|
@@ -217,6 +217,8 @@ files:
|
|
|
217
217
|
- lib/raindown/fragments.rb
|
|
218
218
|
- lib/raindown/front_matter.rb
|
|
219
219
|
- lib/raindown/heading_ids.rb
|
|
220
|
+
- lib/raindown/js/host.mjs
|
|
221
|
+
- lib/raindown/js/js_nodes.rb
|
|
220
222
|
- lib/raindown/node.rb
|
|
221
223
|
- lib/raindown/node_blocks.rb
|
|
222
224
|
- lib/raindown/node_injector.rb
|
|
@@ -295,6 +297,7 @@ files:
|
|
|
295
297
|
- lib/raindown/tui/views/endpoint_view.rb
|
|
296
298
|
- lib/raindown/tui/views/list_view.rb
|
|
297
299
|
- lib/raindown/tui/views/outline_view.rb
|
|
300
|
+
- lib/raindown/utils.rb
|
|
298
301
|
- lib/raindown/variables.rb
|
|
299
302
|
- lib/raindown/watcher/changes.rb
|
|
300
303
|
- lib/raindown/watcher/file_watcher.rb
|