coradoc-adoc 2.0.30 → 2.0.32

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 79a252c883acda46234ba968656577308075f2c1694ee2cdff96aa78006d3fe4
4
- data.tar.gz: 20186d4848bfe7a63a16a11a43ce3b6ae861bb1bf60be7a71af4d96e7e31ea2b
3
+ metadata.gz: 451e2ccdd5dbbd4771079ee9bdc1041c3ee0d3ff74847237d7f3d4aea5064031
4
+ data.tar.gz: 9f161020aca1c07565f9f20c510114b562925cbfb55d4666db14f1d61a68ed81
5
5
  SHA512:
6
- metadata.gz: dbb9841fe7829f87693c9d31bea1303d2f00c1762810e0f948112e01a6958210700bf90e5df15b3685fb49868dba22cf77f169e8842e420c15fa43e1160ec266
7
- data.tar.gz: eb765458ac486a19fca72b69fcb15dea61eb09bb4c0f7ab1bc48793997653ae64dc24dbcd070fa526f3f9b8f467a6a7e157e353719a08d6ed2f795e5e2a1de7d
6
+ metadata.gz: 20150d6a118ae76db46737ca68c47b87a1195cd716ee88700de2afdb06094dd3edee9c66a5b224702e20c6333d28c4082d9840e24b590210154abe46643aad7a
7
+ data.tar.gz: a881fc61dd3bce4e276f3db93fd250d3cf0cd0ab18a2e93a296887a416070b43b0da61972818e79ff0d7c00bd9f4af6320bb8cae8976402fff8519943ce05299
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module AsciiDoc
5
+ module ReferenceMaterializers
6
+ # Render a navigation edge as a first-class CrossReferenceElement
7
+ # — the model-driven xref node the AsciiDoc serializer already
8
+ # knows how to emit (never a raw macro string). Materializing for
9
+ # AsciiDoc fills in the visible text from the authored label or
10
+ # the resolved target's title.
11
+ class Navigation < Coradoc::Reference::Materializer::Base
12
+ class << self
13
+ def kind
14
+ :navigation
15
+ end
16
+
17
+ def presentation
18
+ :any
19
+ end
20
+
21
+ def format
22
+ :asciidoc
23
+ end
24
+ end
25
+
26
+ def materialize(edge:, result:, **)
27
+ text = display_text(edge, result)
28
+ Coradoc::CoreModel::CrossReferenceElement.new(
29
+ target: xref_target(edge.address),
30
+ content: text,
31
+ children: [
32
+ Coradoc::CoreModel::TextElement.new(content: text)
33
+ ]
34
+ )
35
+ end
36
+
37
+ private
38
+
39
+ def xref_target(address)
40
+ [address.target, address.fragment].compact.join('#')
41
+ end
42
+
43
+ def display_text(edge, result)
44
+ return edge.label if edge.label && !edge.label.empty?
45
+ return result.target.title if result.is_a?(Coradoc::Reference::Result::Resolved) && result.target&.title
46
+
47
+ edge.address.to_s
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module AsciiDoc
5
+ # Materializers rendering resolved reference Edges into
6
+ # AsciiDoc-shaped CoreModel nodes. They live in the format gem
7
+ # (not coradoc core) so format knowledge stays at the spoke of the
8
+ # hub-and-spoke architecture; registration is a load-time side
9
+ # effect via the Materializer registry's global extension point.
10
+ module ReferenceMaterializers
11
+ autoload :Navigation, "#{__dir__}/reference_materializers/navigation"
12
+ end
13
+ end
14
+ end
15
+
16
+ Coradoc::Reference::Materializer::Registry.register_global(
17
+ Coradoc::AsciiDoc::ReferenceMaterializers::Navigation
18
+ )
@@ -169,19 +169,22 @@ module Coradoc
169
169
 
170
170
  # Single admonition dispatch used by every block-form path
171
171
  # (example / sidebar / quote / pass / open). Builds an
172
- # AnnotationBlock with annotation_type set from the style and
173
- # the block's body lines joined into a single content string.
174
- # Type is canonicalised via AdmonitionStyles so every code path
175
- # (line admonition, block admonition, attribute-cast admonition)
176
- # produces the same uppercase key.
172
+ # AnnotationBlock by delegating to +transform_typed_block+
173
+ # with +annotation_type+ injected via +extra_attrs+. This
174
+ # preserves inline formatting (links, monospace, bold), list
175
+ # structure, and paragraph breaks — the typed-block pipeline
176
+ # already groups lines into ParagraphBlock children and
177
+ # dispatches block-level lines (lists, tables) through
178
+ # ToCoreModel.transform. Type is canonicalised via
179
+ # AdmonitionStyles so every code path (line admonition, block
180
+ # admonition, attribute-cast admonition) produces the same
181
+ # uppercase key.
177
182
  def transform_admonition_block(block, type)
178
183
  canonical = AdmonitionStyles.canonicalize(type) || type.to_s
179
- content_lines = Array(block.lines).map { |line| ToCoreModel.extract_text_content(line) }.join("\n")
180
- Coradoc::CoreModel::AnnotationBlock.new(
181
- annotation_type: canonical,
182
- content: content_lines,
183
- title: ToCoreModel.extract_title_text(block.title),
184
- source_line: block.source_line
184
+ transform_typed_block(
185
+ block,
186
+ Coradoc::CoreModel::AnnotationBlock,
187
+ annotation_type: canonical
185
188
  )
186
189
  end
187
190
 
@@ -214,76 +217,85 @@ module Coradoc
214
217
  end
215
218
 
216
219
  def transform_typed_block(block, klass, extra_attrs = {})
217
- raw_lines = Array(block.lines)
218
- has_nested_blocks = raw_lines.any? { |line| block_level_child?(line) }
219
-
220
- if has_nested_blocks
221
- children = raw_lines.reject do |line|
222
- line.is_a?(Coradoc::AsciiDoc::Model::LineBreak) ||
223
- line.is_a?(Coradoc::AsciiDoc::Model::Break::PageBreak)
224
- end.filter_map do |line|
225
- result = ToCoreModel.transform(line)
226
- next nil if result.nil?
227
- next result if result.is_a?(Coradoc::CoreModel::Base)
228
-
229
- text = ToCoreModel.extract_text_content(result)
230
- next nil if text.nil? || text.strip.empty?
231
-
232
- Coradoc::CoreModel::TextContent.new(text: text)
233
- end
234
- klass.new(
235
- id: block.id,
236
- title: ToCoreModel.extract_title_text(block.title),
237
- children: children,
238
- language: ToCoreModel.extract_block_language(block),
239
- source_line: block.source_line,
240
- **extra_attrs
241
- )
242
- else
243
- paragraph_groups = group_block_lines_into_paragraphs(raw_lines)
244
-
245
- content_lines = paragraph_groups.map do |group|
246
- ToCoreModel.extract_text_content(group)
247
- end.join("\n\n")
248
-
249
- children = paragraph_groups.map do |group|
250
- inline = ToCoreModel.transform_inline_content(group)
251
- inline = [Coradoc::CoreModel::TextContent.new(text: '')] if inline.empty?
252
- Coradoc::CoreModel::ParagraphBlock.new(
253
- content: ToCoreModel.extract_text_content(group),
254
- children: Array(inline),
255
- source_line: ToCoreModel.extract_source_line(group)
256
- )
257
- end
220
+ children, content = build_typed_block_children(block.lines)
258
221
 
259
- klass.new(
260
- id: block.id,
261
- title: ToCoreModel.extract_title_text(block.title),
262
- content: content_lines,
263
- children: children,
264
- language: ToCoreModel.extract_block_language(block),
265
- source_line: block.source_line,
266
- **extra_attrs
267
- )
268
- end
222
+ klass.new(
223
+ id: block.id,
224
+ title: ToCoreModel.extract_title_text(block.title),
225
+ content: content,
226
+ children: children,
227
+ language: ToCoreModel.extract_block_language(block),
228
+ source_line: block.source_line,
229
+ **extra_attrs
230
+ )
269
231
  end
270
232
 
271
- # AsciiDoc joins consecutive non-blank lines into one paragraph;
272
- # blank lines (parsed as Model::LineBreak) separate paragraphs.
273
- def group_block_lines_into_paragraphs(lines)
274
- groups = []
275
- current = []
276
- lines.each do |line|
233
+ # Walks block.lines in document order and emits the typed
234
+ # block's children alongside the prose-string view of its
235
+ # paragraphs.
236
+ #
237
+ # Consecutive inline lines coalesce into one ParagraphBlock
238
+ # (preserving AsciiDoc paragraph semantics: soft-wrapped
239
+ # source lines are one paragraph, blank lines split them).
240
+ # Block-level lines (lists, tables, nested blocks — anything
241
+ # whose AsciiDoc model returns true from +block_level?+)
242
+ # dispatch through +ToCoreModel.transform+ and slot in at
243
+ # their original document-order position. LineBreak /
244
+ # PageBreak lines flush the pending inline paragraph.
245
+ #
246
+ # Returns [+children+, +content+] where +content+ is the
247
+ # paragraph text joined with blank-line separators (nil when
248
+ # the block has no paragraphs, e.g. contains only nested
249
+ # blocks).
250
+ #
251
+ # Single source of truth for typed-block body construction.
252
+ # Used by every typed-block transformer (example, sidebar,
253
+ # quote, open, typed-cast, admonition) so they all preserve
254
+ # inline formatting, list structure, and paragraph breaks
255
+ # identically.
256
+ def build_typed_block_children(lines)
257
+ children = []
258
+ paragraph_texts = []
259
+ pending_inline = []
260
+
261
+ Array(lines).each do |line|
277
262
  if line.is_a?(Coradoc::AsciiDoc::Model::LineBreak) ||
278
263
  line.is_a?(Coradoc::AsciiDoc::Model::Break::PageBreak)
279
- groups << current if current.any?
280
- current = []
264
+ flush_inline_paragraph(pending_inline, children, paragraph_texts)
265
+ pending_inline.clear
266
+ elsif block_level_child?(line)
267
+ flush_inline_paragraph(pending_inline, children, paragraph_texts)
268
+ pending_inline.clear
269
+ dispatched = ToCoreModel.transform(line)
270
+ children << dispatched if dispatched
281
271
  else
282
- current << line
272
+ pending_inline << line
283
273
  end
284
274
  end
285
- groups << current if current.any?
286
- groups
275
+ flush_inline_paragraph(pending_inline, children, paragraph_texts)
276
+
277
+ content = paragraph_texts.any? ? paragraph_texts.join("\n\n") : nil
278
+ [children, content]
279
+ end
280
+
281
+ # Materialises +pending_inline+ into a ParagraphBlock and
282
+ # appends it to +children+, recording its flat text in
283
+ # +paragraph_texts+ for later content-string joining. No-op
284
+ # when +pending_inline+ is empty so callers can flush
285
+ # unconditionally at every boundary (blank line, block-level
286
+ # child, end-of-input) without producing empty paragraphs.
287
+ def flush_inline_paragraph(pending_inline, children, paragraph_texts)
288
+ return if pending_inline.empty?
289
+
290
+ inline = ToCoreModel.transform_inline_content(pending_inline)
291
+ inline = [Coradoc::CoreModel::TextContent.new(text: '')] if inline.empty?
292
+ text = ToCoreModel.extract_text_content(pending_inline)
293
+ paragraph_texts << text
294
+ children << Coradoc::CoreModel::ParagraphBlock.new(
295
+ content: text,
296
+ children: Array(inline),
297
+ source_line: ToCoreModel.extract_source_line(pending_inline)
298
+ )
287
299
  end
288
300
 
289
301
  # A line that should be emitted as a direct child of the
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Coradoc
4
4
  module AsciiDoc
5
- VERSION = '2.0.30'
5
+ VERSION = '2.0.32'
6
6
  end
7
7
  end
@@ -94,6 +94,12 @@ module Coradoc
94
94
  document.to_adoc
95
95
  end
96
96
  end
97
+
98
+ # AsciiDoc round-trips include:: directives natively — graph-mode
99
+ # documents serialize losslessly, no hydration required.
100
+ def preserves_unresolved_includes?
101
+ true
102
+ end
97
103
  end
98
104
 
99
105
  # Backward-compatible aliases for model classes
@@ -152,3 +158,7 @@ Coradoc.register_format(:asciidoc, Coradoc::AsciiDoc,
152
158
  # Backward-compatibility: Coradoc::Model is now Coradoc::AsciiDoc::Model
153
159
  # This alias is provided for legacy code that hasn't been updated
154
160
  Coradoc::Model = Coradoc::AsciiDoc::Model unless defined?(Coradoc::Model)
161
+
162
+ # Reference materializers for format: :asciidoc. Required (not autoloaded)
163
+ # because registration is a load-time side effect, like register_format.
164
+ require 'coradoc/asciidoc/reference_materializers'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: coradoc-adoc
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.30
4
+ version: 2.0.32
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.
@@ -235,6 +235,8 @@ files:
235
235
  - lib/coradoc/asciidoc/parser/table.rb
236
236
  - lib/coradoc/asciidoc/parser/term.rb
237
237
  - lib/coradoc/asciidoc/parser/text.rb
238
+ - lib/coradoc/asciidoc/reference_materializers.rb
239
+ - lib/coradoc/asciidoc/reference_materializers/navigation.rb
238
240
  - lib/coradoc/asciidoc/serializer.rb
239
241
  - lib/coradoc/asciidoc/serializer/adoc_serializer.rb
240
242
  - lib/coradoc/asciidoc/serializer/element_registry.rb