yaml-converter 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.
@@ -0,0 +1,114 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "date"
4
+
5
+ module Yaml
6
+ module Converter
7
+ # Simple state machine to transform {Parser::Token} sequences into
8
+ # Markdown lines. Produces:
9
+ # - Title lines as plain paragraphs
10
+ # - A validation status line (formatted with date)
11
+ # - Fenced YAML blocks for YAML content
12
+ # - Blockquoted notes (outside fences)
13
+ class StateMachine
14
+ START_YAML = "```yaml"
15
+ END_YAML = "```"
16
+
17
+ # @param options [Hash]
18
+ # @option options [Symbol] :validation_status (:ok) Injected validation result (:ok or :fail)
19
+ # @option options [Integer] :max_line_length (70)
20
+ # @option options [Boolean] :truncate (true)
21
+ # @option options [Symbol] :margin_notes (:auto)
22
+ # @option options [Date] :current_date (Date.today)
23
+ def initialize(options = {})
24
+ @options = options
25
+ @validate_status = options.fetch(:validation_status, :ok)
26
+ @max_len = options.fetch(:max_line_length, 70)
27
+ @truncate = options.fetch(:truncate, true)
28
+ @margin_notes = options.fetch(:margin_notes, :auto)
29
+ @current_date = options[:current_date] || Date.today
30
+ end
31
+
32
+ # Apply stateful transformations to tokens and emit Markdown lines.
33
+ #
34
+ # @param tokens [Array<Parser::Token>]
35
+ # @return [Array<String>] Output lines (without trailing newlines)
36
+ def apply(tokens)
37
+ out = []
38
+ state = :text
39
+ tokens.each do |t|
40
+ case t.type
41
+ when :blank
42
+ out << ""
43
+ when :title
44
+ close_yaml(out, state)
45
+ out << t.text
46
+ out << ""
47
+ state = :text
48
+ when :validation
49
+ close_yaml(out, state)
50
+ date = @current_date.strftime("%d/%m/%Y")
51
+ status_str = ((@validate_status == :ok) ? "OK" : "Fail")
52
+ out << "YAML validation:*#{status_str}* on #{date}"
53
+ out << ""
54
+ state = :text
55
+ when :separator
56
+ # ignore
57
+ when :dash_heading
58
+ close_yaml(out, state)
59
+ out << "# #{t.text}".strip
60
+ out << ""
61
+ state = :text
62
+ when :yaml_line
63
+ state = open_yaml(out, state)
64
+ line = t.text
65
+ if @truncate && line.length > @max_len
66
+ line = line[0...(@max_len - 2)] + ".."
67
+ end
68
+ out << line
69
+ when :note
70
+ if @margin_notes != :ignore
71
+ was_yaml = (state == :yaml)
72
+ close_yaml(out, state)
73
+ out << "" if out.last && out.last != ""
74
+ out << "> NOTE: #{t.text}"
75
+ out << ""
76
+ state = was_yaml ? open_yaml(out, :text) : :text
77
+ end
78
+ else
79
+ # unknown token type: ignore gracefully
80
+ end
81
+ end
82
+ close_yaml(out, state)
83
+ out
84
+ end
85
+
86
+ private
87
+
88
+ # Open a fenced YAML block if not already inside one.
89
+ # @param out [Array<String>]
90
+ # @param state [Symbol]
91
+ # @return [Symbol] new state
92
+ def open_yaml(out, state)
93
+ if state != :yaml
94
+ out << "" if out.last && out.last != ""
95
+ out << START_YAML
96
+ :yaml
97
+ else
98
+ state
99
+ end
100
+ end
101
+
102
+ # Close a fenced YAML block if currently inside one.
103
+ # @param out [Array<String>]
104
+ # @param state [Symbol]
105
+ # @return [void]
106
+ def close_yaml(out, state)
107
+ if state == :yaml
108
+ out << END_YAML
109
+ # removed trailing blank line to keep legacy expected output pattern
110
+ end
111
+ end
112
+ end
113
+ end
114
+ end
@@ -0,0 +1,146 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "date"
4
+ require_relative "parser"
5
+
6
+ module Yaml
7
+ module Converter
8
+ # StreamingEmitter converts YAML to Markdown incrementally.
9
+ # It mirrors MarkdownEmitter + StateMachine behavior while writing to an IO target.
10
+ # Intended for very large inputs to avoid building all output in memory.
11
+ class StreamingEmitter
12
+ START_YAML = "```yaml"
13
+ END_YAML = "```"
14
+
15
+ # @param options [Hash] same normalized options as Config.resolve
16
+ # @param io [#<<] destination IO (e.g., File) that receives lines with "\n"
17
+ def initialize(options, io)
18
+ @options = options
19
+ @io = io
20
+ @validation_status = :ok
21
+ @state = :text
22
+ @_last_line_blank = nil
23
+ end
24
+
25
+ # Set the validation status used when injecting the validation status line.
26
+ # @param status [Symbol] :ok or :fail
27
+ # @return [void]
28
+ def set_validation_status(status)
29
+ @validation_status = status
30
+ end
31
+
32
+ # Stream-convert an input file path to the configured IO.
33
+ # @param input_path [String]
34
+ # @return [void]
35
+ def emit_file(input_path)
36
+ File.open(input_path, "r") do |f|
37
+ f.each_line do |raw|
38
+ emit_line(raw)
39
+ end
40
+ end
41
+ close_yaml
42
+ emit_footer if @options[:emit_footer]
43
+ end
44
+
45
+ private
46
+
47
+ def max_len
48
+ @options.fetch(:max_line_length)
49
+ end
50
+
51
+ def truncate?
52
+ @options.fetch(:truncate)
53
+ end
54
+
55
+ def margin_notes
56
+ @options.fetch(:margin_notes)
57
+ end
58
+
59
+ def current_date
60
+ @options[:current_date] || Date.today
61
+ end
62
+
63
+ def emit_line(raw)
64
+ # Reuse Parser for correctness on a per-line basis
65
+ parser = (@_parser ||= Parser.new(@options))
66
+ tokens = parser.tokenize([raw])
67
+ tokens.each { |t| handle_token(t) }
68
+ end
69
+
70
+ def handle_token(t)
71
+ case t.type
72
+ when :blank
73
+ write_line("")
74
+ when :title
75
+ close_yaml
76
+ write_line(t.text)
77
+ write_line("")
78
+ when :validation
79
+ close_yaml
80
+ date = current_date.strftime("%d/%m/%Y")
81
+ status_str = ((@validation_status == :ok) ? "OK" : "Fail")
82
+ write_line("YAML validation:*#{status_str}* on #{date}")
83
+ write_line("")
84
+ when :separator
85
+ # ignore
86
+ when :dash_heading
87
+ close_yaml
88
+ write_line("# #{t.text}".strip)
89
+ write_line("")
90
+ when :yaml_line
91
+ open_yaml
92
+ line = t.text
93
+ if truncate? && line.length > max_len
94
+ line = line[0...(
95
+ max_len - 2
96
+ )] + ".."
97
+ end
98
+ write_line(line)
99
+ when :note
100
+ return if margin_notes == :ignore
101
+ was_yaml = (@state == :yaml)
102
+ close_yaml
103
+ write_line("") if last_line_not_blank?
104
+ write_line("> NOTE: #{t.text}")
105
+ write_line("")
106
+ open_yaml if was_yaml
107
+ else
108
+ # ignore unknown types
109
+ end
110
+ end
111
+
112
+ def open_yaml
113
+ return if @state == :yaml
114
+ write_line("") if last_line_not_blank?
115
+ write_line(START_YAML)
116
+ @state = :yaml
117
+ end
118
+
119
+ def close_yaml
120
+ if @state == :yaml
121
+ write_line(END_YAML)
122
+ @state = :text
123
+ end
124
+ end
125
+
126
+ def emit_footer
127
+ write_line("---- ")
128
+ write_line("")
129
+ write_line("Produced by [yaml-converter](https://github.com/kettle-rb/yaml-converter)")
130
+ end
131
+
132
+ def write_line(s)
133
+ if @wrote_any_line
134
+ @io << "\n"
135
+ end
136
+ @io << s
137
+ @wrote_any_line = true
138
+ @_last_line_blank = (s == "")
139
+ end
140
+
141
+ def last_line_not_blank?
142
+ @_last_line_blank == false
143
+ end
144
+ end
145
+ end
146
+ end
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "yaml"
4
+
5
+ module Yaml
6
+ module Converter
7
+ # YAML validation helpers.
8
+ #
9
+ # This module provides simple validation by attempting to parse input using
10
+ # Psych.safe_load with a minimal, safe set of options. It does not raise on
11
+ # failure; instead it returns a structured Hash indicating status and error.
12
+ #
13
+ # @see .validate_string
14
+ # @see .validate_file
15
+ module Validation
16
+ module_function
17
+
18
+ # Validate a YAML string by attempting to load it safely via Psych.
19
+ #
20
+ # Uses Psych.safe_load with:
21
+ # - permitted_classes: []
22
+ # - permitted_symbols: []
23
+ # - aliases: true
24
+ #
25
+ # @param yaml_string [String] the YAML content to validate
26
+ # @return [Hash] a result hash
27
+ # @return [Hash] [
28
+ # { status: :ok, error: nil } when parsing succeeds,
29
+ # { status: :fail, error: Exception } when parsing fails
30
+ # ]
31
+ # @example Success
32
+ # Yaml::Converter::Validation.validate_string("foo: bar")
33
+ # #=> { status: :ok, error: nil }
34
+ # @example Failure
35
+ # Yaml::Converter::Validation.validate_string(": : :")
36
+ # #=> { status: :fail, error: #<Psych::SyntaxError ...> }
37
+ def validate_string(yaml_string)
38
+ # Psych.safe_load requires permitted classes for complex YAML; for our purposes,
39
+ # allow basic types and symbols off.
40
+ Psych.safe_load(
41
+ yaml_string,
42
+ permitted_classes: [],
43
+ permitted_symbols: [],
44
+ aliases: true,
45
+ )
46
+ {status: :ok, error: nil}
47
+ rescue StandardError => e
48
+ {status: :fail, error: e}
49
+ end
50
+
51
+ # Validate a YAML file by reading it and delegating to {.validate_string}.
52
+ #
53
+ # @param path [String] filesystem path to a YAML file
54
+ # @return [Hash] see {.validate_string}
55
+ # @example
56
+ # Yaml::Converter::Validation.validate_file("config.yml")
57
+ # #=> { status: :ok, error: nil }
58
+ def validate_file(path)
59
+ content = File.read(path)
60
+ validate_string(content)
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Yaml
4
+ module Converter
5
+ # Namespace for version information.
6
+ module Version
7
+ # The gem version.
8
+ # @return [String]
9
+ VERSION = "0.1.0"
10
+ end
11
+ # The gem version, exposed at the root of the Yaml::Converter namespace.
12
+ # @return [String]
13
+ VERSION = Version::VERSION
14
+ end
15
+ end
@@ -0,0 +1,213 @@
1
+ # frozen_string_literal: true
2
+
3
+ # External dependencies
4
+ require "version_gem"
5
+
6
+ # This library
7
+ require_relative "converter/version"
8
+ require_relative "converter/config"
9
+ require_relative "converter/validation"
10
+ require_relative "converter/markdown_emitter"
11
+ require_relative "converter/streaming_emitter"
12
+
13
+ module Yaml
14
+ module Converter
15
+ # Base error class for all yaml-converter specific exceptions.
16
+ class Error < StandardError; end
17
+ # Raised when provided arguments (paths, extensions, etc.) are invalid.
18
+ class InvalidArgumentsError < Error; end
19
+ # Raised when a requested renderer is not available or implemented.
20
+ class RendererUnavailableError < Error; end
21
+ # Raised when pandoc rendering is requested but pandoc cannot be located.
22
+ class PandocNotFoundError < Error; end
23
+
24
+ module_function
25
+
26
+ # Convert a YAML string into Markdown with optional validation & notes extraction.
27
+ #
28
+ # @param yaml_string [String] Raw YAML content (with optional inline `#note:` annotations or validation marker line)
29
+ # @param options [Hash, Config::DEFAULTS] User overrides for configuration (see {Yaml::Converter::Config::DEFAULTS})
30
+ # @option options [Boolean] :validate (true) Whether to attempt YAML parsing and inject validation status.
31
+ # @option options [Integer] :max_line_length (70) Maximum line length before truncation.
32
+ # @option options [Boolean] :truncate (true) Whether to truncate overly long lines.
33
+ # @option options [Symbol] :margin_notes (:auto) How to handle notes (:auto, :inline, :ignore).
34
+ # @option options [Date] :current_date (Date.today) Deterministic date injection for specs.
35
+ # @return [String] Markdown document including fenced YAML and extracted notes.
36
+ # @example Simple conversion
37
+ # Yaml::Converter.to_markdown("foo: 1 #note: first")
38
+ def to_markdown(yaml_string, options: {})
39
+ opts = Config.resolve(options)
40
+ emitter = MarkdownEmitter.new(opts)
41
+ if opts[:validate]
42
+ validation = Validation.validate_string(yaml_string)
43
+ status = (validation && validation[:status] == :ok) ? :ok : :fail
44
+ emitter.set_validation_status(status)
45
+ end
46
+ emitter.emit(yaml_string.lines).join("\n")
47
+ end
48
+
49
+ # Stream a YAML file to Markdown into an IO target.
50
+ # Automatically injects validation status if enabled.
51
+ # @param input_path [String]
52
+ # @param io [#<<]
53
+ # @param options [Hash]
54
+ # @return [void]
55
+ def to_markdown_streaming(input_path, io, options: {})
56
+ opts = Config.resolve(options)
57
+ emitter = StreamingEmitter.new(opts, io)
58
+ if opts[:validate]
59
+ validation = Validation.validate_file(input_path)
60
+ status = (validation && validation[:status] == :ok) ? :ok : :fail
61
+ emitter.set_validation_status(status)
62
+ end
63
+ emitter.emit_file(input_path)
64
+ nil
65
+ end
66
+
67
+ # Validate a YAML string returning a structured status.
68
+ #
69
+ # @param yaml_string [String]
70
+ # @return [Hash{Symbol=>Object}] Hash with :status (:ok|:fail) and :error (Exception or nil)
71
+ # @example
72
+ # Yaml::Converter.validate("foo: bar") #=> { status: :ok, error: nil }
73
+ def validate(yaml_string)
74
+ Validation.validate_string(yaml_string)
75
+ end
76
+
77
+ # Convert a YAML file to a target format determined by the output extension.
78
+ #
79
+ # Supported extensions (Phase 1): .md, .html, .pdf (native), .docx (pandoc).
80
+ # Other formats may be produced via pandoc when :use_pandoc is true.
81
+ #
82
+ # @param input_path [String] Path to existing .yaml source file.
83
+ # @param output_path [String] Destination file (extension decides rendering strategy).
84
+ # @param options [Hash] See {#to_markdown} plus pandoc/pdf specific keys.
85
+ # @option options [Boolean] :use_pandoc (false) Enable pandoc for non-native conversions.
86
+ # @option options [Array<String>] :pandoc_args (["-N", "--toc"]) Extra pandoc CLI args.
87
+ # @option options [String,nil] :pandoc_path (nil) Explicit pandoc binary path (auto-detected if nil).
88
+ # @option options [Boolean] :pdf_two_column_notes (false) Layout notes beside YAML in PDF.
89
+ # @option options [Boolean] :streaming (false) Force streaming mode for markdown conversion.
90
+ # @option options [Integer] :streaming_threshold_bytes (5_000_000) Auto-enable streaming over this size when not forced.
91
+ # @return [Hash] { status: Symbol, output_path: String, validation: Hash }
92
+ # @raise [InvalidArgumentsError] if input is missing or an invalid extension is requested.
93
+ # @raise [PandocNotFoundError] when pandoc rendering requested & missing.
94
+ # @raise [RendererUnavailableError] for unsupported formats.
95
+ # @example HTML conversion
96
+ # Yaml::Converter.convert(input_path: "blueprint.yaml", output_path: "blueprint.html", options: {})
97
+ def convert(input_path:, output_path:, options: {})
98
+ raise InvalidArgumentsError, "input file not found: #{input_path}" unless File.exist?(input_path)
99
+
100
+ ext = File.extname(output_path)
101
+ if ext == ".yaml"
102
+ raise InvalidArgumentsError, "Output must not be .yaml"
103
+ end
104
+
105
+ opts = Config.resolve(options)
106
+ yaml_string = nil
107
+
108
+ if File.exist?(output_path) && ENV["KETTLE_TEST_SILENT"] != "true"
109
+ warn("Overwriting existing file: #{output_path}")
110
+ end
111
+
112
+ auto_stream = !opts[:streaming] && File.size?(input_path) && File.size(input_path) >= opts[:streaming_threshold_bytes]
113
+
114
+ if ext == ".md" || ext == ""
115
+ # Direct markdown output path: stream to file for large inputs
116
+ File.open(output_path, "w") do |io|
117
+ if opts[:streaming] || auto_stream
118
+ to_markdown_streaming(input_path, io, options: opts)
119
+ else
120
+ yaml_string = File.read(input_path)
121
+ io.write(to_markdown(yaml_string, options: opts))
122
+ end
123
+ end
124
+ validation_result = if opts[:validate]
125
+ yaml_string ? Validation.validate_string(yaml_string) : Validation.validate_file(input_path)
126
+ else
127
+ {status: :ok, error: nil}
128
+ end
129
+ return {status: :ok, output_path: output_path, validation: validation_result}
130
+ end
131
+
132
+ # For non-markdown outputs, we still produce an intermediate markdown string.
133
+ yaml_string = File.read(input_path) if yaml_string.nil?
134
+ markdown = to_markdown(yaml_string, options: opts)
135
+
136
+ # Helper lambda to build standard success response
137
+ success = lambda do
138
+ {status: :ok, output_path: output_path, validation: (opts[:validate] ? Validation.validate_string(yaml_string) : {status: :ok, error: nil})}
139
+ end
140
+
141
+ case ext
142
+ when ".html"
143
+ require "kramdown"
144
+ require "kramdown-parser-gfm"
145
+
146
+ body_html = Kramdown::Document.new(markdown, input: "GFM").to_html
147
+ note_style = ""
148
+ if markdown.include?("> NOTE:")
149
+ note_style = "<style>.yaml-note{font-style:italic;color:#555;margin-left:1em;}</style>\n"
150
+ body_html = body_html.gsub("<blockquote>", '<blockquote class="yaml-note">')
151
+ end
152
+ html = <<~HTML
153
+ <!DOCTYPE html>
154
+ <html>
155
+ <head>
156
+ <meta charset="utf-8">
157
+ #{note_style}</head>
158
+ <body>
159
+ #{body_html}
160
+ </body>
161
+ </html>
162
+ HTML
163
+ File.write(output_path, html)
164
+ success.call
165
+ when ".pdf"
166
+ if opts[:use_pandoc]
167
+ tmp_md = output_path + ".md"
168
+ File.write(tmp_md, markdown)
169
+ require_relative "converter/renderer/pandoc_shell"
170
+ ok = Renderer::PandocShell.render(md_path: tmp_md, out_path: output_path, pandoc_path: opts[:pandoc_path], args: opts[:pandoc_args])
171
+ File.delete(tmp_md) if File.exist?(tmp_md)
172
+ raise PandocNotFoundError, "pandoc not found in PATH" unless ok
173
+ else
174
+ require_relative "converter/renderer/pdf_prawn"
175
+ ok = Renderer::PdfPrawn.render(markdown: markdown, out_path: output_path, options: opts)
176
+ raise RendererUnavailableError, "PDF rendering failed" unless ok
177
+ end
178
+ success.call
179
+ when ".docx"
180
+ tmp_md = output_path + ".md"
181
+ File.write(tmp_md, markdown)
182
+ require_relative "converter/renderer/pandoc_shell"
183
+ pandoc_path = Renderer::PandocShell.which("pandoc")
184
+ if pandoc_path
185
+ ok = Renderer::PandocShell.render(md_path: tmp_md, out_path: output_path, pandoc_path: pandoc_path, args: [])
186
+ File.delete(tmp_md) if File.exist?(tmp_md)
187
+ raise RendererUnavailableError, "pandoc failed to generate DOCX" unless ok
188
+ success.call
189
+ else
190
+ File.delete(tmp_md) if File.exist?(tmp_md)
191
+ raise RendererUnavailableError, "DOCX requires pandoc; install pandoc or use .md/.html/.pdf"
192
+ end
193
+ else
194
+ tmp_md = output_path + ".md"
195
+ File.write(tmp_md, markdown)
196
+ if opts[:use_pandoc]
197
+ require_relative "converter/renderer/pandoc_shell"
198
+ ok = Renderer::PandocShell.render(md_path: tmp_md, out_path: output_path, pandoc_path: opts[:pandoc_path], args: opts[:pandoc_args])
199
+ File.delete(tmp_md) if File.exist?(tmp_md)
200
+ raise PandocNotFoundError, "pandoc not found in PATH" unless ok
201
+ success.call
202
+ else
203
+ raise RendererUnavailableError, "Renderer for #{ext} not implemented. Pass use_pandoc: true or use .md/.html/.pdf."
204
+ end
205
+ end
206
+ end
207
+ end
208
+ end
209
+
210
+ # Extend the Version with VersionGem::Basic to provide semantic version helpers.
211
+ Yaml::Converter::Version.class_eval do
212
+ extend VersionGem::Basic
213
+ end
@@ -0,0 +1,13 @@
1
+ module Yaml
2
+ module Converter
3
+ module Config
4
+ DEFAULTS: { max_line_length: Integer, truncate: bool, margin_notes: Symbol, validate: bool, use_pandoc: bool, pandoc_args: Array[String], pandoc_path: String? , html_theme: Symbol, pdf_page_size: String, pdf_margin: Array[Integer], pdf_title_font_size: Integer, pdf_body_font_size: Integer, pdf_yaml_font_size: Integer, pdf_two_column_notes: bool, current_date: untyped, emit_footer: bool, streaming: bool, streaming_threshold_bytes: Integer }
5
+ ENV_MAP: { max_line_length: String, truncate: String, margin_notes: String, validate: String, use_pandoc: String, pdf_page_size: String, pdf_title_font_size: String, pdf_body_font_size: String, pdf_yaml_font_size: String, pdf_two_column_notes: String, emit_footer: String, streaming: String, streaming_threshold_bytes: String }
6
+ BOOLEAN_KEYS: Array[Symbol]
7
+
8
+ def self.resolve: (?Hash[Symbol, untyped]) -> Hash[Symbol, untyped]
9
+ def self.normalize: (Hash[Symbol, untyped]) -> Hash[Symbol, untyped]
10
+ def self.coerce_env_value: (Symbol, String) -> untyped
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,14 @@
1
+ module Yaml
2
+ module Converter
3
+ class MarkdownEmitter
4
+ START_YAML: String
5
+ END_YAML: String
6
+ VALIDATED_STR: String
7
+ NOTE_STR: String
8
+
9
+ def initialize: (Yaml::Converter::options options) -> void
10
+ def set_validation_status: (Symbol) -> void
11
+ def emit: (Array[String]) -> Array[String]
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,13 @@
1
+ module Yaml
2
+ module Converter
3
+ class StreamingEmitter
4
+ START_YAML: String
5
+ END_YAML: String
6
+
7
+ def initialize: (Yaml::Converter::options options, untyped io) -> void
8
+ def set_validation_status: (Symbol) -> void
9
+ def emit_file: (String input_path) -> void
10
+ end
11
+ end
12
+ end
13
+
@@ -0,0 +1,9 @@
1
+ module Yaml
2
+ module Converter
3
+ module Validation
4
+ def self.validate_string: (String) -> { status: Symbol, error: Exception? }
5
+ def self.validate_file: (String) -> { status: Symbol, error: Exception? }
6
+ end
7
+ end
8
+ end
9
+
@@ -0,0 +1,43 @@
1
+ module Yaml
2
+ module Converter
3
+ VERSION: String
4
+
5
+ class Error < ::StandardError
6
+ end
7
+
8
+ class InvalidArgumentsError < Error
9
+ end
10
+
11
+ class RendererUnavailableError < Error
12
+ end
13
+
14
+ class PandocNotFoundError < Error
15
+ end
16
+
17
+ type options = {
18
+ max_line_length: Integer,
19
+ truncate: bool,
20
+ margin_notes: Symbol,
21
+ validate: bool,
22
+ use_pandoc: bool,
23
+ pandoc_args: Array[String],
24
+ pandoc_path: String?,
25
+ html_theme: Symbol,
26
+ pdf_page_size: String,
27
+ pdf_margin: Array[Integer],
28
+ pdf_title_font_size: Integer,
29
+ pdf_body_font_size: Integer,
30
+ pdf_yaml_font_size: Integer,
31
+ pdf_two_column_notes: bool,
32
+ current_date: untyped,
33
+ emit_footer: bool,
34
+ streaming: bool,
35
+ streaming_threshold_bytes: Integer
36
+ }
37
+
38
+ def self.to_markdown: (String yaml_string, ?options: options) -> String
39
+ def self.to_markdown_streaming: (String input_path, untyped io, ?options: options) -> void
40
+ def self.validate: (String yaml_string) -> { status: Symbol, error: Exception? }
41
+ def self.convert: (input_path: String, output_path: String, ?options: options) -> { status: Symbol, output_path: String, validation: { status: Symbol, error: Exception? } }
42
+ end
43
+ end
data.tar.gz.sig ADDED
Binary file