yard-yaml 0.1.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 +7 -0
- checksums.yaml.gz.sig +0 -0
- data/CHANGELOG.md +48 -0
- data/CITATION.cff +20 -0
- data/CODE_OF_CONDUCT.md +134 -0
- data/CONTRIBUTING.md +221 -0
- data/FUNDING.md +74 -0
- data/LICENSE.txt +21 -0
- data/README.md +1340 -0
- data/REEK +0 -0
- data/RUBOCOP.md +71 -0
- data/SECURITY.md +21 -0
- data/lib/yard/yaml/cli.rb +176 -0
- data/lib/yard/yaml/config.rb +122 -0
- data/lib/yard/yaml/converter.rb +118 -0
- data/lib/yard/yaml/discovery.rb +117 -0
- data/lib/yard/yaml/emitter.rb +174 -0
- data/lib/yard/yaml/plugin.rb +60 -0
- data/lib/yard/yaml/tag_renderer.rb +70 -0
- data/lib/yard/yaml/tags.rb +66 -0
- data/lib/yard/yaml/template_helpers.rb +57 -0
- data/lib/yard/yaml/templates.rb +37 -0
- data/lib/yard/yaml/version.rb +10 -0
- data/lib/yard/yaml.rb +128 -0
- data/lib/yard-yaml.rb +6 -0
- data/sig/yard/yaml.rbs +78 -0
- data.tar.gz.sig +0 -0
- metadata +306 -0
- metadata.gz.sig +0 -0
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "fileutils"
|
|
4
|
+
|
|
5
|
+
module Yard
|
|
6
|
+
module Yaml
|
|
7
|
+
# Writes converted YAML pages to the YARD output directory.
|
|
8
|
+
#
|
|
9
|
+
# Phase 4 scope:
|
|
10
|
+
# - Emits per-page HTML files under <output>/<config.out_dir>/
|
|
11
|
+
# - Optionally emits an index.html when config.index is true
|
|
12
|
+
# - Keeps implementation independent of YARD internals; caller passes output_dir
|
|
13
|
+
# - Deterministic filenames and ordering
|
|
14
|
+
#
|
|
15
|
+
# This class purposefully uses a tiny built-in template to keep behavior
|
|
16
|
+
# deterministic for tests. In a later phase, we can wire ERB templates via
|
|
17
|
+
# YARD::Templates::Engine and theme hooks.
|
|
18
|
+
class Emitter
|
|
19
|
+
class << self
|
|
20
|
+
# Emit all pages to disk.
|
|
21
|
+
#
|
|
22
|
+
# @param pages [Array<Hash>] normalized pages with keys :path, :html, :title, :description, :meta
|
|
23
|
+
# @param output_dir [String] the YARD output directory (typically `YARD::Registry.yardoc_file`/`YARD::Templates::Engine.generate` destination)
|
|
24
|
+
# @param config [Yard::Yaml::Config]
|
|
25
|
+
# @return [Array<String>] list of written file paths
|
|
26
|
+
def emit!(pages:, output_dir:, config: Yard::Yaml.config)
|
|
27
|
+
pages = Array(pages)
|
|
28
|
+
written = []
|
|
29
|
+
base = File.join(output_dir.to_s, config.out_dir.to_s)
|
|
30
|
+
FileUtils.mkdir_p(base)
|
|
31
|
+
|
|
32
|
+
# Write per-page files
|
|
33
|
+
pages.each do |page|
|
|
34
|
+
slug = page_slug(page)
|
|
35
|
+
path = File.join(base, "#{slug}.html")
|
|
36
|
+
html = render_page_html(page)
|
|
37
|
+
atomic_write(path, html, strict: config.strict)
|
|
38
|
+
written << path
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Index (optional)
|
|
42
|
+
if config.index
|
|
43
|
+
index_path = File.join(base, "index.html")
|
|
44
|
+
html = render_index_html(pages)
|
|
45
|
+
atomic_write(index_path, html, strict: config.strict)
|
|
46
|
+
written << index_path
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
written
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# Public: derive a stable slug for a page hash. Shared by templates.
|
|
53
|
+
# @param page [Hash]
|
|
54
|
+
# @return [String]
|
|
55
|
+
def slug_for(page)
|
|
56
|
+
page_slug(page)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
private
|
|
60
|
+
|
|
61
|
+
def page_slug(page)
|
|
62
|
+
meta = page[:meta] || {}
|
|
63
|
+
slug = meta["slug"] || meta[:slug]
|
|
64
|
+
return sanitize_slug(slug) if slug && !slug.to_s.empty?
|
|
65
|
+
|
|
66
|
+
title = page[:title].to_s
|
|
67
|
+
return sanitize_slug(title) unless title.empty?
|
|
68
|
+
|
|
69
|
+
if page[:path]
|
|
70
|
+
base = File.basename(page[:path].to_s, File.extname(page[:path].to_s))
|
|
71
|
+
return sanitize_slug(base)
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
"page"
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def sanitize_slug(s)
|
|
78
|
+
s.to_s.strip.downcase.gsub(/[^a-z0-9]+/, "-").gsub(/^-+|-+$/, "")
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def render_page_html(page)
|
|
82
|
+
title = page[:title] || "Untitled"
|
|
83
|
+
desc = page[:description]
|
|
84
|
+
body = page[:html].to_s
|
|
85
|
+
<<~HTML
|
|
86
|
+
<!doctype html>
|
|
87
|
+
<html lang="en">
|
|
88
|
+
<head>
|
|
89
|
+
<meta charset="utf-8" />
|
|
90
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
91
|
+
<title>#{escape_html(title)}</title>
|
|
92
|
+
<style>
|
|
93
|
+
/* minimal, namespaced styles */
|
|
94
|
+
.yyaml-page { font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Helvetica, Arial, sans-serif; }
|
|
95
|
+
.yyaml-title { margin: 0.2em 0 0.4em; font-size: 1.6em; }
|
|
96
|
+
.yyaml-desc { color: #444; margin-bottom: 1em; }
|
|
97
|
+
.yyaml-body { line-height: 1.5; }
|
|
98
|
+
</style>
|
|
99
|
+
</head>
|
|
100
|
+
<body class="yyaml-page">
|
|
101
|
+
<h1 class="yyaml-title">#{escape_html(title)}</h1>
|
|
102
|
+
#{"<p class=\"yyaml-desc\">#{escape_html(desc)}</p>" if desc}
|
|
103
|
+
<div class="yyaml-body">#{body}</div>
|
|
104
|
+
</body>
|
|
105
|
+
</html>
|
|
106
|
+
HTML
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def render_index_html(pages)
|
|
110
|
+
rows = pages.map do |p|
|
|
111
|
+
title = p[:title] || page_slug(p)
|
|
112
|
+
slug = page_slug(p)
|
|
113
|
+
desc = p[:description]
|
|
114
|
+
%(<li><a href="#{escape_html(slug)}.html">#{escape_html(title)}</a>#{" — #{escape_html(desc)}" if desc}</li>)
|
|
115
|
+
end.join("\n")
|
|
116
|
+
|
|
117
|
+
<<~HTML
|
|
118
|
+
<!doctype html>
|
|
119
|
+
<html lang="en">
|
|
120
|
+
<head>
|
|
121
|
+
<meta charset="utf-8" />
|
|
122
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
123
|
+
<title>YAML Index</title>
|
|
124
|
+
<style>
|
|
125
|
+
.yyaml-index { font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Helvetica, Arial, sans-serif; }
|
|
126
|
+
.yyaml-index h1 { font-size: 1.8em; }
|
|
127
|
+
.yyaml-index ul { list-style: disc; padding-left: 1.4em; }
|
|
128
|
+
</style>
|
|
129
|
+
</head>
|
|
130
|
+
<body class="yyaml-index">
|
|
131
|
+
<h1>YAML Documents</h1>
|
|
132
|
+
<ul>
|
|
133
|
+
#{rows}
|
|
134
|
+
</ul>
|
|
135
|
+
</body>
|
|
136
|
+
</html>
|
|
137
|
+
HTML
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
def atomic_write(path, content, strict: false)
|
|
141
|
+
dir = File.dirname(path)
|
|
142
|
+
FileUtils.mkdir_p(dir)
|
|
143
|
+
tmp = File.join(dir, ".#{$$}.#{Time.now.to_i}.tmp")
|
|
144
|
+
File.open(tmp, "wb") { |f| f.write(content.to_s) }
|
|
145
|
+
FileUtils.mv(tmp, path)
|
|
146
|
+
rescue StandardError => e
|
|
147
|
+
message = "write failed for #{path}: #{e.message}"
|
|
148
|
+
if strict
|
|
149
|
+
raise Yard::Yaml::Error, message
|
|
150
|
+
elsif defined?(::Yard) && ::Yard.const_defined?(:Yaml)
|
|
151
|
+
::Yard::Yaml.warn(message)
|
|
152
|
+
else
|
|
153
|
+
Kernel.warn("yard-yaml: #{message}")
|
|
154
|
+
end
|
|
155
|
+
ensure
|
|
156
|
+
begin
|
|
157
|
+
FileUtils.rm_f(tmp) if tmp && File.exist?(tmp)
|
|
158
|
+
rescue StandardError
|
|
159
|
+
# ignore
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
def escape_html(s)
|
|
164
|
+
s.to_s
|
|
165
|
+
.gsub("&", "&")
|
|
166
|
+
.gsub("<", "<")
|
|
167
|
+
.gsub(">", ">")
|
|
168
|
+
.gsub('"', """)
|
|
169
|
+
.gsub("'", "'")
|
|
170
|
+
end
|
|
171
|
+
end
|
|
172
|
+
end
|
|
173
|
+
end
|
|
174
|
+
end
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Yard
|
|
4
|
+
module Yaml
|
|
5
|
+
# Plugin activation for yard-yaml (Phase 3: config + discovery; still no YARD registrations).
|
|
6
|
+
module Plugin
|
|
7
|
+
@activated = false
|
|
8
|
+
|
|
9
|
+
class << self
|
|
10
|
+
# Whether the plugin has been activated for the current process.
|
|
11
|
+
# Activation is explicit; requiring this file does not activate anything.
|
|
12
|
+
#
|
|
13
|
+
# @return [Boolean]
|
|
14
|
+
def activated?
|
|
15
|
+
@activated
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# Activate the plugin.
|
|
19
|
+
#
|
|
20
|
+
# Phase 3 behavior:
|
|
21
|
+
# - Parse argv for `--yard_yaml-*` flags and apply to configuration.
|
|
22
|
+
# - Run discovery to collect YAML pages and mirror to registry store.
|
|
23
|
+
# - Do NOT register tags, templates, or handlers yet.
|
|
24
|
+
#
|
|
25
|
+
# @param argv [Array<String>, nil] optional argument vector to parse
|
|
26
|
+
# @return [void]
|
|
27
|
+
def activate(argv = nil)
|
|
28
|
+
# Parse and apply CLI overrides if provided
|
|
29
|
+
begin
|
|
30
|
+
overrides = Cli.parse(argv || [])
|
|
31
|
+
Yard::Yaml.configure(overrides) unless overrides.empty?
|
|
32
|
+
rescue StandardError
|
|
33
|
+
# Parsing failures should not prevent activation in Phase 3
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# Collect pages via discovery using current config
|
|
37
|
+
begin
|
|
38
|
+
pages = Discovery.collect(Yard::Yaml.config)
|
|
39
|
+
Yard::Yaml.__set_pages__(pages)
|
|
40
|
+
rescue Yard::Yaml::Error
|
|
41
|
+
# strict mode surfaced an error; re-raise to fail activation/build
|
|
42
|
+
raise
|
|
43
|
+
rescue StandardError
|
|
44
|
+
# Non-strict errors are already warned by converter/discovery
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
@activated = true
|
|
48
|
+
nil
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# Test-helper: reset internal activation flag.
|
|
52
|
+
# Not part of public API; used from test teardown to avoid state leakage.
|
|
53
|
+
def __reset_state__
|
|
54
|
+
@activated = false
|
|
55
|
+
nil
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Yard
|
|
4
|
+
module Yaml
|
|
5
|
+
# Renders HTML fragments for @yaml (inline block) and @yaml_file tags
|
|
6
|
+
# found on a YARD code object. This is a small, YARD-agnostic utility
|
|
7
|
+
# that can be called from templates. It does not depend on YARD internals
|
|
8
|
+
# beyond the code object responding to `tags(:name)`.
|
|
9
|
+
#
|
|
10
|
+
# Phase 5: This provides the wiring surface needed by templates. Actual
|
|
11
|
+
# template hook-up can call {TagRenderer.render_for(object, ...)}.
|
|
12
|
+
module TagRenderer
|
|
13
|
+
module_function
|
|
14
|
+
|
|
15
|
+
# Render YAML-related tags on a code object into a single HTML fragment.
|
|
16
|
+
#
|
|
17
|
+
# @param object [#tags] a YARD code object (or duck-typed test double)
|
|
18
|
+
# @param base_dir [String] base directory to resolve @yaml_file paths
|
|
19
|
+
# @param config [Yard::Yaml::Config]
|
|
20
|
+
# @return [String] HTML fragment (may be empty string)
|
|
21
|
+
def render_for(object, base_dir: Dir.pwd, config: Yard::Yaml.config)
|
|
22
|
+
return "" unless object && object.respond_to?(:tags)
|
|
23
|
+
|
|
24
|
+
parts = []
|
|
25
|
+
|
|
26
|
+
# Inline @yaml blocks (text of the tag is treated as YAML)
|
|
27
|
+
fetch_tags(object, :yaml).each do |tag|
|
|
28
|
+
yaml_text = extract_text(tag)
|
|
29
|
+
next if yaml_text.nil? || yaml_text.strip.empty?
|
|
30
|
+
html = Yard::Yaml::TemplateHelpers.render_yaml_block(yaml_text, config: config)
|
|
31
|
+
parts << wrap_section(html, kind: :yaml)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# @yaml_file path
|
|
35
|
+
fetch_tags(object, :yaml_file).each do |tag|
|
|
36
|
+
path = extract_text(tag)
|
|
37
|
+
next if path.nil? || path.strip.empty?
|
|
38
|
+
html = Yard::Yaml::TemplateHelpers.render_yaml_file(path, base_dir: base_dir, config: config)
|
|
39
|
+
parts << wrap_section(html, kind: :yaml_file)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
parts.join("\n")
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# --- internal helpers ---
|
|
46
|
+
|
|
47
|
+
def fetch_tags(object, name)
|
|
48
|
+
object.tags(name) || []
|
|
49
|
+
rescue StandardError
|
|
50
|
+
[]
|
|
51
|
+
end
|
|
52
|
+
module_function :fetch_tags
|
|
53
|
+
|
|
54
|
+
def extract_text(tag)
|
|
55
|
+
return tag.text if tag.respond_to?(:text)
|
|
56
|
+
# Some YARD tags use #name or #to_s; fall back sensibly
|
|
57
|
+
return tag.name.to_s if tag.respond_to?(:name)
|
|
58
|
+
tag.to_s
|
|
59
|
+
end
|
|
60
|
+
module_function :extract_text
|
|
61
|
+
|
|
62
|
+
def wrap_section(html, kind:)
|
|
63
|
+
return "" if html.to_s.empty?
|
|
64
|
+
css = (kind == :yaml) ? "yyaml-inline" : "yyaml-file"
|
|
65
|
+
%(<div class="#{css}">#{html}</div>)
|
|
66
|
+
end
|
|
67
|
+
module_function :wrap_section
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Tag definitions for yard-yaml.
|
|
4
|
+
#
|
|
5
|
+
# Guarded so requiring this file has no side effects when YARD is not loaded.
|
|
6
|
+
# Actual rendering is performed via Yard::Yaml::TemplateHelpers and templates.
|
|
7
|
+
# Registration only occurs when YARD and its tag library are present.
|
|
8
|
+
module Yard
|
|
9
|
+
module Yaml
|
|
10
|
+
module Tags
|
|
11
|
+
module_function
|
|
12
|
+
|
|
13
|
+
def register!
|
|
14
|
+
return unless defined?(::YARD) && ::YARD.const_defined?(:Tags)
|
|
15
|
+
|
|
16
|
+
# Ensure a minimal Library exists under ::YARD::Tags if missing
|
|
17
|
+
unless ::YARD::Tags.const_defined?(:Library, false)
|
|
18
|
+
# If the test provided a top-level ::Library constant, attach it.
|
|
19
|
+
if defined?(::Library) && ::Library.is_a?(Module)
|
|
20
|
+
begin
|
|
21
|
+
::YARD::Tags.const_set(:Library, ::Library)
|
|
22
|
+
rescue StandardError
|
|
23
|
+
return
|
|
24
|
+
end
|
|
25
|
+
else
|
|
26
|
+
# Create a minimal shim that records define_tag calls
|
|
27
|
+
lib = Module.new
|
|
28
|
+
class << lib
|
|
29
|
+
attr_accessor :calls
|
|
30
|
+
def define_tag(*args)
|
|
31
|
+
self.calls ||= []
|
|
32
|
+
self.calls << args
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
begin
|
|
36
|
+
::YARD::Tags.const_set(:Library, lib)
|
|
37
|
+
rescue StandardError
|
|
38
|
+
# if we failed to set, just return silently
|
|
39
|
+
return
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
begin
|
|
45
|
+
::YARD::Tags::Library.define_tag("YAML", :yaml, :with_title_and_text)
|
|
46
|
+
rescue StandardError
|
|
47
|
+
# ignore if already defined or unavailable
|
|
48
|
+
end
|
|
49
|
+
begin
|
|
50
|
+
::YARD::Tags::Library.define_tag("YAML File", :yaml_file, :with_text)
|
|
51
|
+
rescue StandardError
|
|
52
|
+
# ignore if already defined or unavailable
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# Auto-register on load only if the YARD tag library is already available.
|
|
60
|
+
begin
|
|
61
|
+
if defined?(YARD) && YARD.const_defined?(:Tags) && YARD::Tags.const_defined?(:Library)
|
|
62
|
+
Yard::Yaml::Tags.register!
|
|
63
|
+
end
|
|
64
|
+
rescue StandardError
|
|
65
|
+
# ignore in non-YARD or partially loaded contexts
|
|
66
|
+
end
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Yard
|
|
4
|
+
module Yaml
|
|
5
|
+
# View/template helpers for rendering YAML blocks and files.
|
|
6
|
+
#
|
|
7
|
+
# Phase 5 scope:
|
|
8
|
+
# - Provide simple helpers independent of YARD templates so they are unit-testable.
|
|
9
|
+
# - Use Converter with current config and safe defaults.
|
|
10
|
+
# - For files: resolve relative paths against a provided base_dir (default: Dir.pwd).
|
|
11
|
+
module TemplateHelpers
|
|
12
|
+
module_function
|
|
13
|
+
|
|
14
|
+
# Render inline YAML text to HTML via Converter.
|
|
15
|
+
#
|
|
16
|
+
# @param text [String] YAML content
|
|
17
|
+
# @param config [Yard::Yaml::Config]
|
|
18
|
+
# @return [String] HTML fragment
|
|
19
|
+
def render_yaml_block(text, config: Yard::Yaml.config)
|
|
20
|
+
res = Yard::Yaml::Converter.from_string(text.to_s, {}, config: config)
|
|
21
|
+
res[:html].to_s
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# Render a YAML file to HTML via Converter.
|
|
25
|
+
#
|
|
26
|
+
# @param path [String] file path (absolute or relative)
|
|
27
|
+
# @param base_dir [String] base directory to resolve relative paths against (default: Dir.pwd)
|
|
28
|
+
# @param config [Yard::Yaml::Config]
|
|
29
|
+
# @return [String] HTML fragment (empty on non-strict missing file)
|
|
30
|
+
def render_yaml_file(path, base_dir: Dir.pwd, config: Yard::Yaml.config)
|
|
31
|
+
resolved = resolve_path(path, base_dir)
|
|
32
|
+
res = Yard::Yaml::Converter.from_file(resolved, {}, config: config)
|
|
33
|
+
res[:html].to_s
|
|
34
|
+
rescue Yard::Yaml::Error
|
|
35
|
+
# strict mode errors bubble from converter; re-raise
|
|
36
|
+
raise
|
|
37
|
+
rescue StandardError => e
|
|
38
|
+
# Non-strict paths should already be handled by converter; this is a last-resort guard.
|
|
39
|
+
if defined?(::Yard) && ::Yard.const_defined?(:Yaml)
|
|
40
|
+
::Yard::Yaml.warn("#{e.class}: #{e.message} while rendering #{path}")
|
|
41
|
+
else
|
|
42
|
+
Kernel.warn("yard-yaml: #{e.class}: #{e.message} while rendering #{path}")
|
|
43
|
+
end
|
|
44
|
+
""
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# Resolve a path relative to base_dir when necessary.
|
|
48
|
+
# @api private
|
|
49
|
+
def resolve_path(path, base_dir)
|
|
50
|
+
p = path.to_s
|
|
51
|
+
return p if p.start_with?("/") || p.match?(/^[A-Za-z]:[\\\/]?/) # absolute on unix or windows
|
|
52
|
+
File.expand_path(File.join(base_dir.to_s, p))
|
|
53
|
+
end
|
|
54
|
+
private_class_method :resolve_path
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Template path registration for yard-yaml.
|
|
4
|
+
#
|
|
5
|
+
# Phase 5 (part 1): register a templates directory so future template
|
|
6
|
+
# overrides/partials can be discovered by YARD. Actual inline placement and
|
|
7
|
+
# navigation hooks will follow in the next step to keep require-time behavior
|
|
8
|
+
# inert and tests deterministic.
|
|
9
|
+
#
|
|
10
|
+
# This file is safe to require in environments without YARD present; it checks
|
|
11
|
+
# for YARD constants before attempting any registration.
|
|
12
|
+
module Yard
|
|
13
|
+
module Yaml
|
|
14
|
+
module Templates
|
|
15
|
+
module_function
|
|
16
|
+
|
|
17
|
+
# Register the templates path with YARD if available.
|
|
18
|
+
# Idempotent and safe when YARD is not loaded.
|
|
19
|
+
def register!
|
|
20
|
+
return unless defined?(::YARD) && ::YARD.const_defined?(:Templates)
|
|
21
|
+
base = File.expand_path("../../../templates", __dir__)
|
|
22
|
+
begin
|
|
23
|
+
::YARD::Templates::Engine.register_template_path(base)
|
|
24
|
+
rescue StandardError
|
|
25
|
+
# ignore if engine not available or already registered
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Try to register immediately if YARD is present; otherwise remain inert.
|
|
33
|
+
begin
|
|
34
|
+
Yard::Yaml::Templates.register!
|
|
35
|
+
rescue StandardError
|
|
36
|
+
# ignore in non-YARD contexts
|
|
37
|
+
end
|
data/lib/yard/yaml.rb
ADDED
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "yaml/version"
|
|
4
|
+
require_relative "yaml/config"
|
|
5
|
+
require_relative "yaml/cli"
|
|
6
|
+
require_relative "yaml/plugin"
|
|
7
|
+
require_relative "yaml/converter"
|
|
8
|
+
require_relative "yaml/discovery"
|
|
9
|
+
require_relative "yaml/emitter"
|
|
10
|
+
require_relative "yaml/template_helpers"
|
|
11
|
+
require_relative "yaml/tag_renderer"
|
|
12
|
+
require_relative "yaml/tags"
|
|
13
|
+
require_relative "yaml/templates"
|
|
14
|
+
|
|
15
|
+
module Yard
|
|
16
|
+
module Yaml
|
|
17
|
+
# Generic error for yard-yaml
|
|
18
|
+
class Error < StandardError; end
|
|
19
|
+
|
|
20
|
+
@config = nil
|
|
21
|
+
@pages = nil
|
|
22
|
+
|
|
23
|
+
class << self
|
|
24
|
+
# Access the global configuration for yard-yaml.
|
|
25
|
+
#
|
|
26
|
+
# Returns a memoized instance. It is safe to mutate via accessors in
|
|
27
|
+
# controlled contexts (e.g., tests or explicit configuration blocks).
|
|
28
|
+
#
|
|
29
|
+
# @return [Yard::Yaml::Config]
|
|
30
|
+
def config
|
|
31
|
+
@config ||= Config.new
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Access collected pages (Phase 3). Nil until plugin activation performs discovery.
|
|
35
|
+
# Each page is a Hash with keys: :path, :html, :title, :description, :meta
|
|
36
|
+
# @return [Array<Hash>, nil]
|
|
37
|
+
attr_reader :pages
|
|
38
|
+
|
|
39
|
+
# Internal: set collected pages (used by Plugin during activation)
|
|
40
|
+
def __set_pages__(list)
|
|
41
|
+
@pages = Array(list)
|
|
42
|
+
mirror_pages_to_registry(@pages)
|
|
43
|
+
@pages
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Configure the plugin programmatically.
|
|
47
|
+
#
|
|
48
|
+
# @param overrides [Hash,nil] optional overrides to apply
|
|
49
|
+
# @yieldparam cfg [Yard::Yaml::Config] the live config instance
|
|
50
|
+
# @return [Yard::Yaml::Config] the resulting config
|
|
51
|
+
def configure(overrides = nil)
|
|
52
|
+
cfg = config
|
|
53
|
+
cfg.apply(overrides) if overrides && !overrides.empty?
|
|
54
|
+
yield(cfg) if block_given?
|
|
55
|
+
mirror_to_registry(cfg)
|
|
56
|
+
cfg
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# Public: emit a warning message via YARD logger when available, otherwise stderr.
|
|
60
|
+
# Prefix is standardized to "yard-yaml: ".
|
|
61
|
+
# @param message [String]
|
|
62
|
+
def warn(message)
|
|
63
|
+
__warn(message)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# Public: emit an error-level log message (does not raise).
|
|
67
|
+
# Uses YARD::Logger.error if available, else falls back to stderr with prefix.
|
|
68
|
+
# @param message [String]
|
|
69
|
+
def error(message)
|
|
70
|
+
if defined?(::YARD) && ::YARD.const_defined?(:Logger)
|
|
71
|
+
begin
|
|
72
|
+
::YARD::Logger.instance.error("yard-yaml: #{message}")
|
|
73
|
+
return
|
|
74
|
+
rescue StandardError
|
|
75
|
+
# fall back
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
Kernel.warn("yard-yaml: ERROR: #{message}")
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# Test-helper: reset memoized config to defaults (not public API)
|
|
82
|
+
def __reset_state__
|
|
83
|
+
@config = nil
|
|
84
|
+
@pages = nil
|
|
85
|
+
if defined?(::Yard::Yaml::Plugin) && ::Yard::Yaml::Plugin.respond_to?(:__reset_state__)
|
|
86
|
+
::Yard::Yaml::Plugin.__reset_state__
|
|
87
|
+
end
|
|
88
|
+
nil
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
private
|
|
92
|
+
|
|
93
|
+
# Internal: unified warning helper to avoid constants errors when a partial
|
|
94
|
+
# YARD stub is present in tests. Prefer using this helper over direct
|
|
95
|
+
# YARD::Logger usage.
|
|
96
|
+
def __warn(message)
|
|
97
|
+
if defined?(::YARD) && ::YARD.const_defined?(:Logger)
|
|
98
|
+
begin
|
|
99
|
+
::YARD::Logger.instance.warn("yard-yaml: #{message}")
|
|
100
|
+
return
|
|
101
|
+
rescue StandardError
|
|
102
|
+
# fall back
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
Kernel.warn("yard-yaml: #{message}")
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def mirror_to_registry(cfg)
|
|
109
|
+
return unless defined?(::YARD) && ::YARD.const_defined?(:Registry)
|
|
110
|
+
# Registry.store is a Hash-like; avoid raising if unavailable
|
|
111
|
+
begin
|
|
112
|
+
::YARD::Registry.store[:yard_yaml_config] = cfg
|
|
113
|
+
rescue StandardError
|
|
114
|
+
# ignore if registry store not ready
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def mirror_pages_to_registry(pages)
|
|
119
|
+
return unless defined?(::YARD) && ::YARD.const_defined?(:Registry)
|
|
120
|
+
begin
|
|
121
|
+
::YARD::Registry.store[:yard_yaml_pages] = pages
|
|
122
|
+
rescue StandardError
|
|
123
|
+
# ignore if registry store not ready
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
end
|
data/lib/yard-yaml.rb
ADDED
data/sig/yard/yaml.rbs
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
module Yard
|
|
2
|
+
module Yaml
|
|
3
|
+
VERSION: String
|
|
4
|
+
|
|
5
|
+
# Global configuration and pages accessors
|
|
6
|
+
def self.config: () -> Yard::Yaml::Config
|
|
7
|
+
def self.configure: (?Hash[untyped, untyped] overrides) { (Yard::Yaml::Config) -> void } -> Yard::Yaml::Config
|
|
8
|
+
def self.pages: () -> (Array[Hash[untyped, untyped]] | nil)
|
|
9
|
+
def self.__set_pages__: (Array[Hash[untyped, untyped]] list) -> Array[Hash[untyped, untyped]]
|
|
10
|
+
def self.warn: (String message) -> void
|
|
11
|
+
def self.error: (String message) -> void
|
|
12
|
+
|
|
13
|
+
class Config
|
|
14
|
+
DEFAULT_INCLUDE: Array[String]
|
|
15
|
+
DEFAULT_EXCLUDE: Array[String]
|
|
16
|
+
DEFAULT_OUT_DIR: String
|
|
17
|
+
DEFAULT_INDEX: bool
|
|
18
|
+
DEFAULT_TOC: String
|
|
19
|
+
DEFAULT_CONVERTER_OPTIONS: Hash[untyped, untyped]
|
|
20
|
+
DEFAULT_FRONT_MATTER: bool
|
|
21
|
+
DEFAULT_STRICT: bool
|
|
22
|
+
DEFAULT_ALLOW_ERB: bool
|
|
23
|
+
|
|
24
|
+
attr_accessor include: Array[String]
|
|
25
|
+
attr_accessor exclude: Array[String]
|
|
26
|
+
attr_accessor out_dir: String
|
|
27
|
+
attr_accessor index: bool
|
|
28
|
+
attr_accessor toc: String
|
|
29
|
+
attr_accessor converter_options: Hash[untyped, untyped]
|
|
30
|
+
attr_accessor front_matter: bool
|
|
31
|
+
attr_accessor strict: bool
|
|
32
|
+
attr_accessor allow_erb: bool
|
|
33
|
+
|
|
34
|
+
def initialize: (?Hash[untyped, untyped] overrides) -> void
|
|
35
|
+
def apply: (Hash[untyped, untyped]) -> Config
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
module Cli
|
|
39
|
+
def self.parse: (Array[String] argv) -> Hash[untyped, untyped]
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
module Plugin
|
|
43
|
+
def self.activated?: () -> bool
|
|
44
|
+
def self.activate: (?Array[String] argv) -> void
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
module Discovery
|
|
48
|
+
def self.find_files: (Array[String] include_globs, Array[String] exclude_globs) -> Array[String]
|
|
49
|
+
def self.collect: (?Yard::Yaml::Config config) -> Array[Hash[untyped, untyped]]
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
class Converter
|
|
53
|
+
def self.from_string: (String yaml, ?Hash[untyped, untyped] options, ?config: Yard::Yaml::Config) -> Hash[untyped, untyped]
|
|
54
|
+
def self.from_file: (String path, ?Hash[untyped, untyped] options, ?config: Yard::Yaml::Config) -> Hash[untyped, untyped]
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
class Emitter
|
|
58
|
+
def self.emit!: (pages: Array[Hash[untyped, untyped]], output_dir: String, ?config: Yard::Yaml::Config) -> Array[String]
|
|
59
|
+
def self.slug_for: (Hash[untyped, untyped] page) -> String
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
module TemplateHelpers
|
|
63
|
+
def self.render_yaml_block: (String text, ?config: Yard::Yaml::Config) -> String
|
|
64
|
+
def self.render_yaml_file: (String path, ?base_dir: String, ?config: Yard::Yaml::Config) -> String
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
module TagRenderer
|
|
68
|
+
def self.render_for: (untyped object, ?base_dir: String, ?config: Yard::Yaml::Config) -> String
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
module Tags
|
|
72
|
+
def self.register!: () -> void
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
class Error < ::StandardError
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
data.tar.gz.sig
ADDED
|
Binary file
|