Class: MaquinaStream::Renderer
- Inherits:
-
Object
- Object
- MaquinaStream::Renderer
- Defined in:
- lib/maquina_stream/renderer.rb,
lib/maquina_stream/renderer/fence.rb,
lib/maquina_stream/renderer/post_pass.rb,
lib/maquina_stream/renderer/tag_blocks.rb,
lib/maquina_stream/renderer/view_context.rb
Overview
Markdown in, sanitized HTML out.
MaquinaStream::Renderer.call(markdown, mode: :streaming) # => SafeBuffer
Pure: no request, no controller, no stubbing. The same function serves the
live stream, a page reload, a replay and an export, and mode changes
nothing but whether the reveal attributes are emitted. If this ever starts
needing request context, that is a design error rather than a plumbing one.
The pipeline
MaquinaRemend.callrepairs the unterminated markdown a half-written buffer always ends in — an open bold run, an unclosed fence.- Renderer::TagBlocks puts blank lines around the opening and closing tags
of a registered tag, so a block-level
<thinking>is its own HTML block rather than a closing tag stranded inside a paragraph. - Commonmarker parses it, with source positions.
- Renderer::PostPass rewrites elements: fences, custom tags, registered element overrides, text direction, block indices.
- Sanitizer runs, unconditionally, last.
Renderer returns one HTML string for the whole buffer. It does not split it into blocks or stamp ids and digests on them — that is Document, and without it a page cannot be repaired at all. Host code almost always wants MaquinaStream.render or Document rather than this.
Defined Under Namespace
Classes: Fence, PostPass, TagBlocks, ViewContext
Constant Summary collapse
- MODES =
The two render modes. Both produce the same document byte for byte; the mode is carried so the post-pass knows whether the message is still being written.
%i[streaming static].freeze
- COMMONMARKER_OPTIONS =
unsafe: true lets registered custom tags through the parser. It is not a relaxation: the sanitizer is the gate, it runs unconditionally, and it runs last. Model output is assumed hostile at every step before it.
{ parse: {sourcepos_chars: true}, render: {sourcepos: true, unsafe: true, github_pre_lang: false}, extension: { table: true, strikethrough: true, autolink: true, tasklist: true, footnotes: true } }.freeze
- COMMONMARKER_PLUGINS =
commonmarker highlights with syntect by default, which would ship a second highlighter's inline styles into a pipeline that already owns highlighting (Rouge, at fence close only) and forbids inline colour. Confirmed against commonmarker 2.10.0 in test/sourcepos_test.rb.
{syntax_highlighter: nil}.freeze
Instance Attribute Summary collapse
-
#config ⇒ Object
readonly
The Configuration this renderer reads.
-
#mode ⇒ Object
readonly
The mode this renderer was built with, one of MODES.
Class Method Summary collapse
-
.call(markdown, mode: :streaming, config: MaquinaStream.config) ⇒ Object
Renders
markdownin one call. -
.prepare(markdown) ⇒ Object
The buffer as commonmarker will see it: repaired, then normalised so a registered block-level tag stands on its own.
Instance Method Summary collapse
-
#call(markdown) ⇒ Object
Renders one markdown string to sanitized HTML.
-
#initialize(mode: :streaming, config: MaquinaStream.config) ⇒ Renderer
constructor
Builds a reusable renderer.
Constructor Details
#initialize(mode: :streaming, config: MaquinaStream.config) ⇒ Renderer
Builds a reusable renderer. Raises ArgumentError unless mode: is one of
MODES.
98 99 100 101 102 103 |
# File 'lib/maquina_stream/renderer.rb', line 98 def initialize(mode: :streaming, config: MaquinaStream.config) raise ArgumentError, "mode must be one of #{MODES.join(", ")}" unless MODES.include?(mode) @mode = mode @config = config end |
Instance Attribute Details
#config ⇒ Object (readonly)
The Configuration this renderer reads.
72 73 74 |
# File 'lib/maquina_stream/renderer.rb', line 72 def config @config end |
#mode ⇒ Object (readonly)
The mode this renderer was built with, one of MODES.
69 70 71 |
# File 'lib/maquina_stream/renderer.rb', line 69 def mode @mode end |
Class Method Details
.call(markdown, mode: :streaming, config: MaquinaStream.config) ⇒ Object
Renders markdown in one call. The usual entry point.
mode: is :streaming or :static; anything else raises ArgumentError.
config: defaults to the global MaquinaStream.config, and is a keyword
rather than a lookup so the renderer stays callable from a plain Ruby
process with no Rails around it.
80 81 82 |
# File 'lib/maquina_stream/renderer.rb', line 80 def self.call(markdown, mode: :streaming, config: MaquinaStream.config) new(mode: mode, config: config).call(markdown) end |
.prepare(markdown) ⇒ Object
The buffer as commonmarker will see it: repaired, then normalised so a registered block-level tag stands on its own. Document parses this rather than the raw buffer, so its source positions are the ones the rendered document was built from — two parses of two different strings do not line up, and the block ids are derived from the alignment.
Byte-identical to MaquinaRemend.call(markdown) when no tag is
registered.
92 93 94 |
# File 'lib/maquina_stream/renderer.rb', line 92 def self.prepare(markdown) TagBlocks.call(MaquinaRemend.call(markdown)) end |
Instance Method Details
#call(markdown) ⇒ Object
Renders one markdown string to sanitized HTML.
Returns an html_safe String — a plain String when ActiveSupport is not
loaded — and an empty one for nil or whitespace-only input.
109 110 111 112 113 114 115 116 117 118 119 |
# File 'lib/maquina_stream/renderer.rb', line 109 def call(markdown) return safe("") if markdown.nil? || markdown.strip.empty? prepared = self.class.prepare(markdown) parsed = Commonmarker.to_html(prepared, options: COMMONMARKER_OPTIONS, plugins: COMMONMARKER_PLUGINS) fragment = Nokogiri::HTML5.fragment(parsed) PostPass.new(fragment, markdown: prepared, mode: mode, config: config).call safe(Sanitizer.call(fragment.to_html, config: config)) end |