coradoc-adoc 2.0.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.
Files changed (217) hide show
  1. checksums.yaml +7 -0
  2. data/.rspec +3 -0
  3. data/lib/coradoc/asciidoc/model/admonition.rb +37 -0
  4. data/lib/coradoc/asciidoc/model/anchorable.rb +64 -0
  5. data/lib/coradoc/asciidoc/model/attached.rb +26 -0
  6. data/lib/coradoc/asciidoc/model/attribute.rb +22 -0
  7. data/lib/coradoc/asciidoc/model/attribute_list/matchers.rb +45 -0
  8. data/lib/coradoc/asciidoc/model/attribute_list.rb +230 -0
  9. data/lib/coradoc/asciidoc/model/attribute_list_attribute.rb +11 -0
  10. data/lib/coradoc/asciidoc/model/audio.rb +44 -0
  11. data/lib/coradoc/asciidoc/model/author.rb +36 -0
  12. data/lib/coradoc/asciidoc/model/base.rb +141 -0
  13. data/lib/coradoc/asciidoc/model/bibliography.rb +37 -0
  14. data/lib/coradoc/asciidoc/model/bibliography_entry.rb +38 -0
  15. data/lib/coradoc/asciidoc/model/block/core.rb +139 -0
  16. data/lib/coradoc/asciidoc/model/block/example.rb +14 -0
  17. data/lib/coradoc/asciidoc/model/block/listing.rb +14 -0
  18. data/lib/coradoc/asciidoc/model/block/literal.rb +14 -0
  19. data/lib/coradoc/asciidoc/model/block/open.rb +14 -0
  20. data/lib/coradoc/asciidoc/model/block/pass.rb +14 -0
  21. data/lib/coradoc/asciidoc/model/block/quote.rb +14 -0
  22. data/lib/coradoc/asciidoc/model/block/reviewer_comment.rb +14 -0
  23. data/lib/coradoc/asciidoc/model/block/side.rb +14 -0
  24. data/lib/coradoc/asciidoc/model/block/source_code.rb +14 -0
  25. data/lib/coradoc/asciidoc/model/block.rb +21 -0
  26. data/lib/coradoc/asciidoc/model/break.rb +33 -0
  27. data/lib/coradoc/asciidoc/model/comment_block.rb +33 -0
  28. data/lib/coradoc/asciidoc/model/comment_line.rb +30 -0
  29. data/lib/coradoc/asciidoc/model/content_list.rb +334 -0
  30. data/lib/coradoc/asciidoc/model/document.rb +197 -0
  31. data/lib/coradoc/asciidoc/model/document_attributes.rb +43 -0
  32. data/lib/coradoc/asciidoc/model/glossaries.rb +11 -0
  33. data/lib/coradoc/asciidoc/model/header.rb +57 -0
  34. data/lib/coradoc/asciidoc/model/highlight.rb +11 -0
  35. data/lib/coradoc/asciidoc/model/image/block_image/attribute_list.rb +23 -0
  36. data/lib/coradoc/asciidoc/model/image/block_image.rb +25 -0
  37. data/lib/coradoc/asciidoc/model/image/core/attribute_list.rb +43 -0
  38. data/lib/coradoc/asciidoc/model/image/core.rb +72 -0
  39. data/lib/coradoc/asciidoc/model/image/inline_image.rb +17 -0
  40. data/lib/coradoc/asciidoc/model/image.rb +14 -0
  41. data/lib/coradoc/asciidoc/model/include.rb +66 -0
  42. data/lib/coradoc/asciidoc/model/inline/anchor.rb +41 -0
  43. data/lib/coradoc/asciidoc/model/inline/attribute_reference.rb +25 -0
  44. data/lib/coradoc/asciidoc/model/inline/base.rb +15 -0
  45. data/lib/coradoc/asciidoc/model/inline/bold.rb +38 -0
  46. data/lib/coradoc/asciidoc/model/inline/cross_reference.rb +29 -0
  47. data/lib/coradoc/asciidoc/model/inline/cross_reference_arg.rb +15 -0
  48. data/lib/coradoc/asciidoc/model/inline/footnote.rb +34 -0
  49. data/lib/coradoc/asciidoc/model/inline/hard_line_break.rb +24 -0
  50. data/lib/coradoc/asciidoc/model/inline/highlight.rb +36 -0
  51. data/lib/coradoc/asciidoc/model/inline/italic.rb +38 -0
  52. data/lib/coradoc/asciidoc/model/inline/link.rb +46 -0
  53. data/lib/coradoc/asciidoc/model/inline/monospace.rb +39 -0
  54. data/lib/coradoc/asciidoc/model/inline/quotation.rb +25 -0
  55. data/lib/coradoc/asciidoc/model/inline/small.rb +25 -0
  56. data/lib/coradoc/asciidoc/model/inline/span.rb +38 -0
  57. data/lib/coradoc/asciidoc/model/inline/stem.rb +24 -0
  58. data/lib/coradoc/asciidoc/model/inline/strikethrough.rb +39 -0
  59. data/lib/coradoc/asciidoc/model/inline/subscript.rb +33 -0
  60. data/lib/coradoc/asciidoc/model/inline/superscript.rb +33 -0
  61. data/lib/coradoc/asciidoc/model/inline/underline.rb +25 -0
  62. data/lib/coradoc/asciidoc/model/inline.rb +31 -0
  63. data/lib/coradoc/asciidoc/model/line_break.rb +11 -0
  64. data/lib/coradoc/asciidoc/model/list/core.rb +61 -0
  65. data/lib/coradoc/asciidoc/model/list/definition.rb +27 -0
  66. data/lib/coradoc/asciidoc/model/list/definition_item.rb +43 -0
  67. data/lib/coradoc/asciidoc/model/list/item.rb +72 -0
  68. data/lib/coradoc/asciidoc/model/list/nestable.rb +14 -0
  69. data/lib/coradoc/asciidoc/model/list/ordered.rb +34 -0
  70. data/lib/coradoc/asciidoc/model/list/unordered.rb +34 -0
  71. data/lib/coradoc/asciidoc/model/list.rb +29 -0
  72. data/lib/coradoc/asciidoc/model/named_attribute.rb +12 -0
  73. data/lib/coradoc/asciidoc/model/paragraph.rb +59 -0
  74. data/lib/coradoc/asciidoc/model/rejected_positional_attribute.rb +12 -0
  75. data/lib/coradoc/asciidoc/model/resolvable.rb +71 -0
  76. data/lib/coradoc/asciidoc/model/resolver.rb +430 -0
  77. data/lib/coradoc/asciidoc/model/reviewer_note.rb +54 -0
  78. data/lib/coradoc/asciidoc/model/revision.rb +47 -0
  79. data/lib/coradoc/asciidoc/model/section.rb +109 -0
  80. data/lib/coradoc/asciidoc/model/serialization/asciidoc_adapter.rb +28 -0
  81. data/lib/coradoc/asciidoc/model/serialization/asciidoc_mapping.rb +42 -0
  82. data/lib/coradoc/asciidoc/model/serialization/asciidoc_mapping_rule.rb +41 -0
  83. data/lib/coradoc/asciidoc/model/serialization/asciidoc_transform.rb +211 -0
  84. data/lib/coradoc/asciidoc/model/serialization/errors.rb +57 -0
  85. data/lib/coradoc/asciidoc/model/serialization.rb +39 -0
  86. data/lib/coradoc/asciidoc/model/spacing.rb +282 -0
  87. data/lib/coradoc/asciidoc/model/table.rb +44 -0
  88. data/lib/coradoc/asciidoc/model/table_cell.rb +122 -0
  89. data/lib/coradoc/asciidoc/model/table_row.rb +26 -0
  90. data/lib/coradoc/asciidoc/model/tag.rb +36 -0
  91. data/lib/coradoc/asciidoc/model/term.rb +48 -0
  92. data/lib/coradoc/asciidoc/model/text_element.rb +66 -0
  93. data/lib/coradoc/asciidoc/model/title.rb +85 -0
  94. data/lib/coradoc/asciidoc/model/video/attribute_list.rb +43 -0
  95. data/lib/coradoc/asciidoc/model/video.rb +49 -0
  96. data/lib/coradoc/asciidoc/model.rb +75 -0
  97. data/lib/coradoc/asciidoc/parse_error.rb +161 -0
  98. data/lib/coradoc/asciidoc/parser/admonition.rb +26 -0
  99. data/lib/coradoc/asciidoc/parser/attribute_list.rb +110 -0
  100. data/lib/coradoc/asciidoc/parser/base.rb +159 -0
  101. data/lib/coradoc/asciidoc/parser/bibliography.rb +31 -0
  102. data/lib/coradoc/asciidoc/parser/block.rb +186 -0
  103. data/lib/coradoc/asciidoc/parser/block_assembler.rb +183 -0
  104. data/lib/coradoc/asciidoc/parser/cache.rb +155 -0
  105. data/lib/coradoc/asciidoc/parser/citation.rb +32 -0
  106. data/lib/coradoc/asciidoc/parser/content.rb +76 -0
  107. data/lib/coradoc/asciidoc/parser/document_attributes.rb +27 -0
  108. data/lib/coradoc/asciidoc/parser/fix_files.rb +76 -0
  109. data/lib/coradoc/asciidoc/parser/header.rb +31 -0
  110. data/lib/coradoc/asciidoc/parser/inline.rb +199 -0
  111. data/lib/coradoc/asciidoc/parser/list.rb +130 -0
  112. data/lib/coradoc/asciidoc/parser/metadata_detector.rb +164 -0
  113. data/lib/coradoc/asciidoc/parser/paragraph.rb +64 -0
  114. data/lib/coradoc/asciidoc/parser/section.rb +62 -0
  115. data/lib/coradoc/asciidoc/parser/stem.rb +19 -0
  116. data/lib/coradoc/asciidoc/parser/table.rb +166 -0
  117. data/lib/coradoc/asciidoc/parser/term.rb +70 -0
  118. data/lib/coradoc/asciidoc/parser/text.rb +156 -0
  119. data/lib/coradoc/asciidoc/parser.rb +10 -0
  120. data/lib/coradoc/asciidoc/serializer/adoc_serializer.rb +86 -0
  121. data/lib/coradoc/asciidoc/serializer/element_registry.rb +95 -0
  122. data/lib/coradoc/asciidoc/serializer/fallback_serializer.rb +21 -0
  123. data/lib/coradoc/asciidoc/serializer/formatter.rb +144 -0
  124. data/lib/coradoc/asciidoc/serializer/registrations.rb +108 -0
  125. data/lib/coradoc/asciidoc/serializer/serialization_context.rb +238 -0
  126. data/lib/coradoc/asciidoc/serializer/serializers/admonition.rb +19 -0
  127. data/lib/coradoc/asciidoc/serializer/serializers/attribute.rb +23 -0
  128. data/lib/coradoc/asciidoc/serializer/serializers/attribute_list.rb +40 -0
  129. data/lib/coradoc/asciidoc/serializer/serializers/attribute_list_attribute.rb +18 -0
  130. data/lib/coradoc/asciidoc/serializer/serializers/audio.rb +33 -0
  131. data/lib/coradoc/asciidoc/serializer/serializers/author.rb +20 -0
  132. data/lib/coradoc/asciidoc/serializer/serializers/base.rb +152 -0
  133. data/lib/coradoc/asciidoc/serializer/serializers/bibliography.rb +35 -0
  134. data/lib/coradoc/asciidoc/serializer/serializers/bibliography_entry.rb +24 -0
  135. data/lib/coradoc/asciidoc/serializer/serializers/block/core.rb +70 -0
  136. data/lib/coradoc/asciidoc/serializer/serializers/block/example.rb +17 -0
  137. data/lib/coradoc/asciidoc/serializer/serializers/block/listing.rb +22 -0
  138. data/lib/coradoc/asciidoc/serializer/serializers/block/literal.rb +17 -0
  139. data/lib/coradoc/asciidoc/serializer/serializers/block/open.rb +22 -0
  140. data/lib/coradoc/asciidoc/serializer/serializers/block/pass.rb +17 -0
  141. data/lib/coradoc/asciidoc/serializer/serializers/block/quote.rb +17 -0
  142. data/lib/coradoc/asciidoc/serializer/serializers/block/reviewer_comment.rb +17 -0
  143. data/lib/coradoc/asciidoc/serializer/serializers/block/side.rb +22 -0
  144. data/lib/coradoc/asciidoc/serializer/serializers/block/source_code.rb +22 -0
  145. data/lib/coradoc/asciidoc/serializer/serializers/block.rb +23 -0
  146. data/lib/coradoc/asciidoc/serializer/serializers/break.rb +18 -0
  147. data/lib/coradoc/asciidoc/serializer/serializers/comment_block.rb +22 -0
  148. data/lib/coradoc/asciidoc/serializer/serializers/comment_line.rb +22 -0
  149. data/lib/coradoc/asciidoc/serializer/serializers/document.rb +65 -0
  150. data/lib/coradoc/asciidoc/serializer/serializers/document_attributes.rb +21 -0
  151. data/lib/coradoc/asciidoc/serializer/serializers/header.rb +24 -0
  152. data/lib/coradoc/asciidoc/serializer/serializers/highlight.rb +23 -0
  153. data/lib/coradoc/asciidoc/serializer/serializers/image/core.rb +30 -0
  154. data/lib/coradoc/asciidoc/serializer/serializers/image.rb +14 -0
  155. data/lib/coradoc/asciidoc/serializer/serializers/include.rb +19 -0
  156. data/lib/coradoc/asciidoc/serializer/serializers/inline/anchor.rb +20 -0
  157. data/lib/coradoc/asciidoc/serializer/serializers/inline/attribute_reference.rb +20 -0
  158. data/lib/coradoc/asciidoc/serializer/serializers/inline/bold.rb +26 -0
  159. data/lib/coradoc/asciidoc/serializer/serializers/inline/cross_reference.rb +30 -0
  160. data/lib/coradoc/asciidoc/serializer/serializers/inline/cross_reference_arg.rb +20 -0
  161. data/lib/coradoc/asciidoc/serializer/serializers/inline/footnote.rb +24 -0
  162. data/lib/coradoc/asciidoc/serializer/serializers/inline/hard_line_break.rb +20 -0
  163. data/lib/coradoc/asciidoc/serializer/serializers/inline/highlight.rb +26 -0
  164. data/lib/coradoc/asciidoc/serializer/serializers/inline/italic.rb +26 -0
  165. data/lib/coradoc/asciidoc/serializer/serializers/inline/link.rb +38 -0
  166. data/lib/coradoc/asciidoc/serializer/serializers/inline/monospace.rb +26 -0
  167. data/lib/coradoc/asciidoc/serializer/serializers/inline/quotation.rb +21 -0
  168. data/lib/coradoc/asciidoc/serializer/serializers/inline/small.rb +20 -0
  169. data/lib/coradoc/asciidoc/serializer/serializers/inline/span.rb +35 -0
  170. data/lib/coradoc/asciidoc/serializer/serializers/inline/stem.rb +23 -0
  171. data/lib/coradoc/asciidoc/serializer/serializers/inline/strikethrough.rb +29 -0
  172. data/lib/coradoc/asciidoc/serializer/serializers/inline/subscript.rb +29 -0
  173. data/lib/coradoc/asciidoc/serializer/serializers/inline/superscript.rb +26 -0
  174. data/lib/coradoc/asciidoc/serializer/serializers/inline/underline.rb +20 -0
  175. data/lib/coradoc/asciidoc/serializer/serializers/inline.rb +32 -0
  176. data/lib/coradoc/asciidoc/serializer/serializers/line_break.rb +18 -0
  177. data/lib/coradoc/asciidoc/serializer/serializers/list/core.rb +47 -0
  178. data/lib/coradoc/asciidoc/serializer/serializers/list/definition.rb +35 -0
  179. data/lib/coradoc/asciidoc/serializer/serializers/list/definition_item.rb +38 -0
  180. data/lib/coradoc/asciidoc/serializer/serializers/list/item.rb +120 -0
  181. data/lib/coradoc/asciidoc/serializer/serializers/list/ordered.rb +24 -0
  182. data/lib/coradoc/asciidoc/serializer/serializers/list/unordered.rb +29 -0
  183. data/lib/coradoc/asciidoc/serializer/serializers/list.rb +19 -0
  184. data/lib/coradoc/asciidoc/serializer/serializers/named_attribute.rb +22 -0
  185. data/lib/coradoc/asciidoc/serializer/serializers/paragraph.rb +65 -0
  186. data/lib/coradoc/asciidoc/serializer/serializers/reviewer_note.rb +28 -0
  187. data/lib/coradoc/asciidoc/serializer/serializers/revision.rb +26 -0
  188. data/lib/coradoc/asciidoc/serializer/serializers/section.rb +37 -0
  189. data/lib/coradoc/asciidoc/serializer/serializers/table.rb +24 -0
  190. data/lib/coradoc/asciidoc/serializer/serializers/table_cell.rb +75 -0
  191. data/lib/coradoc/asciidoc/serializer/serializers/table_row.rb +24 -0
  192. data/lib/coradoc/asciidoc/serializer/serializers/tag.rb +19 -0
  193. data/lib/coradoc/asciidoc/serializer/serializers/term.rb +20 -0
  194. data/lib/coradoc/asciidoc/serializer/serializers/text_element.rb +23 -0
  195. data/lib/coradoc/asciidoc/serializer/serializers/title.rb +55 -0
  196. data/lib/coradoc/asciidoc/serializer/serializers/video.rb +33 -0
  197. data/lib/coradoc/asciidoc/serializer/spacing_strategy.rb +70 -0
  198. data/lib/coradoc/asciidoc/serializer.rb +75 -0
  199. data/lib/coradoc/asciidoc/transform/from_core_model.rb +502 -0
  200. data/lib/coradoc/asciidoc/transform/from_core_model_registrations.rb +126 -0
  201. data/lib/coradoc/asciidoc/transform/registry.rb +146 -0
  202. data/lib/coradoc/asciidoc/transform/to_core_model.rb +564 -0
  203. data/lib/coradoc/asciidoc/transform/to_core_model_registrations.rb +257 -0
  204. data/lib/coradoc/asciidoc/transform.rb +13 -0
  205. data/lib/coradoc/asciidoc/transformer/block_rules.rb +101 -0
  206. data/lib/coradoc/asciidoc/transformer/header_rules.rb +91 -0
  207. data/lib/coradoc/asciidoc/transformer/inline_rules.rb +179 -0
  208. data/lib/coradoc/asciidoc/transformer/list_rules.rb +131 -0
  209. data/lib/coradoc/asciidoc/transformer/misc_rules.rb +196 -0
  210. data/lib/coradoc/asciidoc/transformer/structural_rules.rb +216 -0
  211. data/lib/coradoc/asciidoc/transformer/text_rules.rb +107 -0
  212. data/lib/coradoc/asciidoc/transformer.rb +406 -0
  213. data/lib/coradoc/asciidoc/version.rb +7 -0
  214. data/lib/coradoc/asciidoc.rb +148 -0
  215. data/lib/coradoc/util/asciidoc.rb +71 -0
  216. data/lib/coradoc/util.rb +8 -0
  217. metadata +343 -0
@@ -0,0 +1,146 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module AsciiDoc
5
+ module Transform
6
+ # Registry for model transformers
7
+ #
8
+ # Provides a flexible, extensible way to register and lookup transformers
9
+ # that convert between different model types. This replaces case statements
10
+ # with a registry pattern, following the Open/Closed Principle.
11
+ #
12
+ # @example Register a transformer
13
+ # Coradoc::AsciiDoc::Transform::Registry.register(
14
+ # Coradoc::AsciiDoc::Model::Document,
15
+ # ->(model) { transform_document(model) }
16
+ # )
17
+ #
18
+ # @example Lookup and apply a transformer
19
+ # transformer = Coradoc::AsciiDoc::Transform::Registry.lookup(model.class)
20
+ # result = transformer.call(model) if transformer
21
+ #
22
+ class Registry
23
+ class << self
24
+ # Get the global registry instance
25
+ #
26
+ # @return [Hash] the registry hash
27
+ def registry
28
+ @registry ||= {}
29
+ end
30
+
31
+ # Register a transformer for a source class
32
+ #
33
+ # @param source_class [Class] the source model class
34
+ # @param transformer [#call] a callable that transforms the model
35
+ # @param target_class [Class, nil] optional target class for bidirectional lookup
36
+ # @return [void]
37
+ def register(source_class, transformer, target_class: nil)
38
+ registry[source_class] = transformer
39
+
40
+ # Store reverse mapping if target class specified
41
+ return unless target_class
42
+
43
+ reverse_registry[target_class] = transformer
44
+ end
45
+
46
+ # Register a transformer with a priority
47
+ #
48
+ # Higher priority transformers are checked first.
49
+ # This is useful for handling subclasses before parent classes.
50
+ #
51
+ # @param source_class [Class] the source model class
52
+ # @param transformer [#call] a callable that transforms the model
53
+ # @param priority [Integer] priority level (higher = checked first)
54
+ # @return [void]
55
+ def register_with_priority(source_class, transformer, priority: 0)
56
+ @prioritized_registry ||= []
57
+ @prioritized_registry << {
58
+ class: source_class,
59
+ transformer: transformer,
60
+ priority: priority
61
+ }
62
+ # Sort by priority descending
63
+ @prioritized_registry.sort_by! { |e| -e[:priority] }
64
+ end
65
+
66
+ # Lookup a transformer for a model
67
+ #
68
+ # First checks exact class match, then checks prioritized registry,
69
+ # then walks up the inheritance chain.
70
+ #
71
+ # @param model_class [Class] the model class to find a transformer for
72
+ # @return [#call, nil] the transformer or nil if not found
73
+ def lookup(model_class)
74
+ # 1. Check exact match in main registry
75
+ return registry[model_class] if registry.key?(model_class)
76
+
77
+ # 2. Check prioritized registry
78
+ if @prioritized_registry
79
+ entry = @prioritized_registry.find { |e| model_class <= e[:class] }
80
+ return entry[:transformer] if entry
81
+ end
82
+
83
+ # 3. Walk up inheritance chain
84
+ model_class.ancestors.each do |ancestor|
85
+ next if ancestor == model_class
86
+ next if [Object, BasicObject].include?(ancestor)
87
+
88
+ return registry[ancestor] if registry.key?(ancestor)
89
+ end
90
+
91
+ nil
92
+ end
93
+
94
+ # Transform a model using the registered transformer
95
+ #
96
+ # @param model [Object] the model to transform
97
+ # @return [Object] the transformed model
98
+ # @raise [ArgumentError] if no transformer is registered
99
+ def transform(model)
100
+ return model if model.nil?
101
+
102
+ # Handle arrays specially
103
+ return model.map { |item| transform(item) } if model.is_a?(Array)
104
+
105
+ transformer = lookup(model.class)
106
+ if transformer
107
+ transformer.call(model)
108
+ else
109
+ # Return unchanged if no transformer found
110
+ model
111
+ end
112
+ end
113
+
114
+ # Check if a transformer is registered for a class
115
+ #
116
+ # @param model_class [Class] the class to check
117
+ # @return [Boolean]
118
+ def registered?(model_class)
119
+ !lookup(model_class).nil?
120
+ end
121
+
122
+ # Clear all registrations (useful for testing)
123
+ #
124
+ # @return [void]
125
+ def clear
126
+ registry.clear
127
+ @prioritized_registry = nil
128
+ end
129
+
130
+ # Get all registered source classes
131
+ #
132
+ # @return [Array<Class>]
133
+ def registered_classes
134
+ registry.keys
135
+ end
136
+
137
+ private
138
+
139
+ def reverse_registry
140
+ @reverse_registry ||= {}
141
+ end
142
+ end
143
+ end
144
+ end
145
+ end
146
+ end
@@ -0,0 +1,564 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'to_core_model_registrations'
4
+
5
+ module Coradoc
6
+ module AsciiDoc
7
+ module Transform
8
+ # Transforms AsciiDoc models to CoreModel equivalents
9
+ class ToCoreModel
10
+ def transform(model)
11
+ self.class.transform(model)
12
+ end
13
+
14
+ class << self
15
+ def transform(model)
16
+ return model.map { |item| transform(item) }.compact if model.is_a?(Array)
17
+ return model unless model.is_a?(Coradoc::AsciiDoc::Model::Base)
18
+
19
+ transformer = Registry.lookup(model.class)
20
+ return transformer.call(model) if transformer
21
+
22
+ transform_with_case(model)
23
+ end
24
+
25
+ def transform_with_case(model)
26
+ case model
27
+ when Coradoc::AsciiDoc::Model::Document
28
+ transform_document(model)
29
+ when Coradoc::AsciiDoc::Model::Section
30
+ transform_section(model)
31
+ when Coradoc::AsciiDoc::Model::Paragraph
32
+ transform_paragraph(model)
33
+ when Coradoc::AsciiDoc::Model::Block::SourceCode
34
+ transform_source_block(model)
35
+ when Coradoc::AsciiDoc::Model::Block::Quote
36
+ transform_typed_block(model, Coradoc::CoreModel::QuoteBlock)
37
+ when Coradoc::AsciiDoc::Model::Block::Example
38
+ transform_typed_block(model, Coradoc::CoreModel::ExampleBlock)
39
+ when Coradoc::AsciiDoc::Model::Block::Side
40
+ transform_typed_block(model, Coradoc::CoreModel::SidebarBlock)
41
+ when Coradoc::AsciiDoc::Model::Block::Literal
42
+ transform_typed_block(model, Coradoc::CoreModel::LiteralBlock)
43
+ when Coradoc::AsciiDoc::Model::Block::Open
44
+ transform_typed_block(model, Coradoc::CoreModel::OpenBlock)
45
+ when Coradoc::AsciiDoc::Model::Block::Pass
46
+ transform_typed_block(model, Coradoc::CoreModel::PassBlock)
47
+ when Coradoc::AsciiDoc::Model::Block::Listing
48
+ transform_typed_block(model, Coradoc::CoreModel::ListingBlock)
49
+ when Coradoc::AsciiDoc::Model::Block::Core
50
+ transform_block(model, model.delimiter.to_s)
51
+ when Coradoc::AsciiDoc::Model::Table
52
+ transform_table(model)
53
+ when Coradoc::AsciiDoc::Model::TableRow
54
+ transform_table_row(model)
55
+ when Coradoc::AsciiDoc::Model::TableCell
56
+ transform_table_cell(model)
57
+ when Coradoc::AsciiDoc::Model::List::Unordered
58
+ transform_list(model, 'unordered')
59
+ when Coradoc::AsciiDoc::Model::List::Ordered
60
+ transform_list(model, 'ordered')
61
+ when Coradoc::AsciiDoc::Model::List::Definition
62
+ transform_list(model, 'definition')
63
+ when Coradoc::AsciiDoc::Model::Term
64
+ transform_term(model)
65
+ when Coradoc::AsciiDoc::Model::Admonition
66
+ transform_admonition(model)
67
+ when Coradoc::AsciiDoc::Model::Inline::Bold
68
+ transform_inline(model, 'bold')
69
+ when Coradoc::AsciiDoc::Model::Inline::Italic
70
+ transform_inline(model, 'italic')
71
+ when Coradoc::AsciiDoc::Model::Inline::Monospace
72
+ transform_inline(model, 'monospace')
73
+ when Coradoc::AsciiDoc::Model::Inline::Highlight
74
+ transform_inline(model, 'highlight')
75
+ when Coradoc::AsciiDoc::Model::Inline::Link
76
+ transform_link(model)
77
+ when Coradoc::AsciiDoc::Model::Inline::CrossReference
78
+ transform_cross_reference(model)
79
+ when Coradoc::AsciiDoc::Model::Inline::Stem
80
+ transform_stem(model)
81
+ when Coradoc::AsciiDoc::Model::CommentBlock
82
+ Coradoc::CoreModel::Block.new(
83
+ element_type: 'comment',
84
+ content: model.text.to_s
85
+ )
86
+ when Coradoc::AsciiDoc::Model::Bibliography
87
+ transform_bibliography(model)
88
+ when Coradoc::AsciiDoc::Model::BibliographyEntry
89
+ transform_bibliography_entry(model)
90
+ when Coradoc::AsciiDoc::Model::Image::BlockImage
91
+ transform_image(model)
92
+ when Coradoc::AsciiDoc::Model::TextElement
93
+ extract_text_content(model)
94
+ else
95
+ model
96
+ end
97
+ end
98
+
99
+ def transform_document(doc)
100
+ title_text = extract_title_text(doc.header&.title)
101
+ attributes = extract_document_attributes(doc)
102
+ Coradoc::CoreModel::StructuralElement.new(
103
+ element_type: 'document',
104
+ id: doc.id,
105
+ title: title_text,
106
+ attributes: attributes,
107
+ children: transform(doc.sections || doc.contents || [])
108
+ )
109
+ end
110
+
111
+ def transform_section(section)
112
+ title_text = extract_title_text(section.title)
113
+ content_children = transform(section.contents || [])
114
+ nested_sections = transform(section.sections || [])
115
+
116
+ Coradoc::CoreModel::StructuralElement.new(
117
+ element_type: 'section',
118
+ id: section.id,
119
+ level: section.level,
120
+ title: title_text,
121
+ children: content_children + nested_sections
122
+ )
123
+ end
124
+
125
+ def transform_paragraph(para)
126
+ children = transform_inline_content(para.content)
127
+
128
+ Coradoc::CoreModel::Block.new(
129
+ element_type: 'paragraph',
130
+ block_semantic_type: :paragraph,
131
+ id: para.id,
132
+ content: extract_text_content(para.content),
133
+ children: children
134
+ )
135
+ end
136
+
137
+ def transform_source_block(block)
138
+ content_lines = Array(block.lines).reject do |line|
139
+ line.is_a?(Coradoc::AsciiDoc::Model::LineBreak) ||
140
+ line.is_a?(Coradoc::AsciiDoc::Model::Break::PageBreak)
141
+ end.map do |line|
142
+ extract_text_content(line)
143
+ end.join("\n")
144
+
145
+ language = extract_block_language(block)
146
+
147
+ Coradoc::CoreModel::SourceBlock.new(
148
+ element_type: 'block',
149
+ id: block.id,
150
+ title: extract_title_text(block.title),
151
+ content: content_lines,
152
+ language: language
153
+ )
154
+ end
155
+
156
+ def transform_block(block, semantic_type_or_delimiter)
157
+ content_lines = extract_block_lines(block)
158
+ semantic_type = if semantic_type_or_delimiter.is_a?(Symbol)
159
+ semantic_type_or_delimiter
160
+ else
161
+ asciidoc_delimiter_to_semantic(semantic_type_or_delimiter)
162
+ end
163
+
164
+ Coradoc::CoreModel::Block.new(
165
+ element_type: 'block',
166
+ block_semantic_type: semantic_type,
167
+ delimiter_type: semantic_type_or_delimiter.is_a?(String) ? semantic_type_or_delimiter : nil,
168
+ id: block.id,
169
+ title: extract_title_text(block.title),
170
+ content: content_lines,
171
+ language: extract_block_language(block)
172
+ )
173
+ end
174
+
175
+ def transform_typed_block(block, klass, extra_attrs = {})
176
+ content_lines = extract_block_lines(block)
177
+
178
+ klass.new(
179
+ element_type: 'block',
180
+ id: block.id,
181
+ title: extract_title_text(block.title),
182
+ content: content_lines,
183
+ language: extract_block_language(block),
184
+ **extra_attrs
185
+ )
186
+ end
187
+
188
+ def extract_block_lines(block)
189
+ Array(block.lines).reject do |line|
190
+ line.is_a?(Coradoc::AsciiDoc::Model::LineBreak) ||
191
+ line.is_a?(Coradoc::AsciiDoc::Model::Break::PageBreak)
192
+ end.map do |line|
193
+ extract_text_content(line)
194
+ end.join("\n")
195
+ end
196
+
197
+ def transform_table(table)
198
+ rows = Array(table.rows).map do |row|
199
+ transform_table_row(row)
200
+ end
201
+
202
+ Coradoc::CoreModel::Table.new(
203
+ id: table.id,
204
+ title: table.title&.to_s,
205
+ rows: rows
206
+ )
207
+ end
208
+
209
+ def transform_table_row(row)
210
+ cells = Array(row.columns).map do |cell|
211
+ transform_table_cell(cell)
212
+ end
213
+ Coradoc::CoreModel::TableRow.new(
214
+ cells: cells,
215
+ header: row.header
216
+ )
217
+ end
218
+
219
+ def transform_table_cell(cell)
220
+ children = transform_inline_content(cell.content)
221
+
222
+ Coradoc::CoreModel::TableCell.new(
223
+ content: extract_text_content(cell.content),
224
+ alignment: cell.horizontal_alignment,
225
+ vertical_alignment: cell.vertical_alignment,
226
+ colspan: cell.colspan,
227
+ rowspan: cell.rowspan,
228
+ style: cell.style_name,
229
+ children: children
230
+ )
231
+ end
232
+
233
+ def transform_list(list, marker_type)
234
+ items = Array(list.items).map do |item|
235
+ if item.is_a?(Coradoc::AsciiDoc::Model::List::DefinitionItem)
236
+ term_content = item.terms
237
+ def_content = item.contents
238
+
239
+ Coradoc::CoreModel::DefinitionItem.new(
240
+ term: extract_text_content(term_content),
241
+ definitions: [extract_text_content(def_content)]
242
+ )
243
+ else
244
+ content_val = item.content
245
+ children = transform_inline_content(content_val)
246
+
247
+ li = Coradoc::CoreModel::ListItem.new(
248
+ content: extract_text_content(content_val),
249
+ marker: item.marker
250
+ )
251
+ li.children = children
252
+ li
253
+ end
254
+ end
255
+
256
+ if marker_type == 'definition'
257
+ Coradoc::CoreModel::DefinitionList.new(items: items)
258
+ else
259
+ Coradoc::CoreModel::ListBlock.new(
260
+ marker_type: marker_type,
261
+ items: items
262
+ )
263
+ end
264
+ end
265
+
266
+ def transform_term(term)
267
+ Coradoc::CoreModel::Term.new(
268
+ text: term.term.to_s,
269
+ type: term.type&.to_s || 'preferred',
270
+ lang: term.lang&.to_s || 'en'
271
+ )
272
+ end
273
+
274
+ def transform_admonition(admonition)
275
+ Coradoc::CoreModel::AnnotationBlock.new(
276
+ annotation_type: admonition.type,
277
+ content: extract_text_content(admonition.content)
278
+ )
279
+ end
280
+
281
+ def transform_inline(inline, format_type)
282
+ Coradoc::CoreModel::InlineElement.new(
283
+ format_type: format_type,
284
+ content: extract_text_content(inline.content)
285
+ )
286
+ end
287
+
288
+ def transform_inline_text(inline, format_type)
289
+ Coradoc::CoreModel::InlineElement.new(
290
+ format_type: format_type,
291
+ content: inline.text.to_s
292
+ )
293
+ end
294
+
295
+ def transform_inline_footnote(footnote)
296
+ parsed_content = parse_and_transform_inline(footnote.text.to_s)
297
+ Coradoc::CoreModel::InlineElement.new(
298
+ format_type: 'footnote',
299
+ target: footnote.id,
300
+ content: parsed_content
301
+ )
302
+ end
303
+
304
+ def transform_link(link)
305
+ Coradoc::CoreModel::InlineElement.new(
306
+ format_type: 'link',
307
+ target: link.path,
308
+ content: link.name || link.path
309
+ )
310
+ end
311
+
312
+ def transform_cross_reference(xref)
313
+ Coradoc::CoreModel::InlineElement.new(
314
+ format_type: 'xref',
315
+ target: xref.href,
316
+ content: xref.args&.first || xref.href
317
+ )
318
+ end
319
+
320
+ def transform_stem(stem)
321
+ Coradoc::CoreModel::InlineElement.new(
322
+ format_type: 'stem',
323
+ content: stem.content,
324
+ stem_type: stem.type || 'stem'
325
+ )
326
+ end
327
+
328
+ def transform_image(image)
329
+ Coradoc::CoreModel::Image.new(
330
+ src: image.src,
331
+ alt: image.title&.to_s,
332
+ width: image.attributes&.[]('width'),
333
+ height: image.attributes&.[]('height')
334
+ )
335
+ end
336
+
337
+ def transform_bibliography(bib)
338
+ entries = Array(bib.entries).map do |entry|
339
+ transform_bibliography_entry(entry)
340
+ end
341
+
342
+ Coradoc::CoreModel::Bibliography.new(
343
+ id: bib.id,
344
+ title: bib.title.to_s,
345
+ level: nil,
346
+ entries: entries
347
+ )
348
+ end
349
+
350
+ def transform_bibliography_entry(entry)
351
+ Coradoc::CoreModel::BibliographyEntry.new(
352
+ anchor_name: entry.anchor_name,
353
+ document_id: entry.document_id,
354
+ ref_text: entry.ref_text.to_s
355
+ )
356
+ end
357
+
358
+ private
359
+
360
+ # AsciiDoc delimiters are any length of the same character (4+ for most, 2+ for open).
361
+ # We map by the first character to handle all lengths correctly.
362
+ ADOC_DELIMITER_CHAR_TO_SEMANTIC = {
363
+ '-' => :source_code,
364
+ '=' => :example,
365
+ '_' => :quote,
366
+ '*' => :sidebar,
367
+ '.' => :literal,
368
+ '+' => :pass
369
+ }.freeze
370
+
371
+ def asciidoc_delimiter_to_semantic(delimiter)
372
+ return :open if delimiter && delimiter.length < 4
373
+
374
+ char = delimiter&.[](0)
375
+ ADOC_DELIMITER_CHAR_TO_SEMANTIC[char] || :open
376
+ end
377
+
378
+ def extract_document_attributes(doc)
379
+ return {} unless doc.document_attributes
380
+
381
+ doc.document_attributes.to_hash
382
+ end
383
+
384
+ def extract_block_language(block)
385
+ lang = block.lang
386
+ return lang if lang.is_a?(String) && !lang.empty?
387
+
388
+ attrs = block.attributes
389
+ return nil unless attrs.is_a?(Coradoc::AsciiDoc::Model::AttributeList)
390
+
391
+ named_lang = attrs['language']
392
+ return named_lang.to_s if named_lang
393
+
394
+ # For [source,yaml], the language is the second positional attribute
395
+ positional = attrs.positional
396
+ positional[1]&.value&.to_s if positional.length > 1
397
+ end
398
+
399
+ def transform_inline_content(content)
400
+ return [] if content.nil?
401
+
402
+ case content
403
+ when Array
404
+ content.flat_map { |item| transform_inline_content(item) }
405
+ when Coradoc::AsciiDoc::Model::TextElement
406
+ transform_inline_content(content.content)
407
+ when Coradoc::AsciiDoc::Model::Term
408
+ [Coradoc::CoreModel::InlineElement.new(
409
+ format_type: 'term',
410
+ content: content.term.to_s
411
+ )]
412
+ when String
413
+ content.empty? ? [] : [content]
414
+ when Coradoc::AsciiDoc::Model::Base
415
+ [transform(content)]
416
+ else
417
+ text = extract_text_content(content)
418
+ text.empty? ? [] : [text]
419
+ end
420
+ end
421
+
422
+ def extract_core_model_text(model)
423
+ case model
424
+ when Coradoc::CoreModel::ListBlock
425
+ model.items.map do |item|
426
+ item.is_a?(Coradoc::CoreModel::ListItem) ? "* #{item.flat_text}" : item.to_s
427
+ end.join("\n")
428
+ when Coradoc::CoreModel::AnnotationBlock
429
+ "#{model.annotation_type}: #{model.flat_text}"
430
+ when Coradoc::CoreModel::Block
431
+ model.flat_text
432
+ when Coradoc::CoreModel::Image
433
+ model.alt || ''
434
+ when Coradoc::CoreModel::InlineElement
435
+ model.content.to_s
436
+ else
437
+ ''
438
+ end
439
+ end
440
+
441
+ def extract_title_text(title)
442
+ return nil if title.nil?
443
+ return title.to_s unless title.is_a?(Coradoc::AsciiDoc::Model::Title)
444
+
445
+ content = title.content
446
+ return '' if content.nil?
447
+
448
+ if content.is_a?(String)
449
+ content
450
+ elsif content.is_a?(Array)
451
+ content.map { |c| extract_text_content(c) }.join
452
+ else
453
+ extract_text_content(content)
454
+ end
455
+ end
456
+
457
+ def extract_text_content(content)
458
+ case content
459
+ when nil
460
+ ''
461
+ when String
462
+ content
463
+ when Array
464
+ result = []
465
+ content.each_with_index do |item, idx|
466
+ text = extract_text_content(item)
467
+ result << text if text && !text.empty?
468
+
469
+ next unless idx < content.length - 1 && text && !text.empty?
470
+
471
+ result << ' ' if item.is_a?(Coradoc::AsciiDoc::Model::TextElement) && item.line_break != '+'
472
+ end
473
+ result.join
474
+ when Coradoc::AsciiDoc::Model::TextElement
475
+ if content.content.is_a?(Array)
476
+ extract_text_content(content.content)
477
+ else
478
+ content.content.to_s
479
+ end
480
+ when Coradoc::AsciiDoc::Model::Inline::Bold,
481
+ Coradoc::AsciiDoc::Model::Inline::Italic,
482
+ Coradoc::AsciiDoc::Model::Inline::Monospace,
483
+ Coradoc::AsciiDoc::Model::Inline::Highlight,
484
+ Coradoc::AsciiDoc::Model::Inline::Strikethrough,
485
+ Coradoc::AsciiDoc::Model::Inline::Subscript,
486
+ Coradoc::AsciiDoc::Model::Inline::Superscript,
487
+ Coradoc::AsciiDoc::Model::Inline::Underline
488
+ extract_text_content(content.content)
489
+ when Coradoc::AsciiDoc::Model::Inline::Link
490
+ content.name || content.path || ''
491
+ when Coradoc::AsciiDoc::Model::Inline::CrossReference
492
+ content.href || ''
493
+ when Coradoc::AsciiDoc::Model::Inline::Stem
494
+ content.content.to_s
495
+ when Coradoc::AsciiDoc::Model::Inline::Footnote
496
+ if content.content
497
+ extract_text_content(content.content)
498
+ else
499
+ ''
500
+ end
501
+ when Coradoc::AsciiDoc::Model::Inline::AttributeReference
502
+ "{#{content.name}}"
503
+ when Coradoc::AsciiDoc::Model::Term
504
+ content.term.to_s
505
+ when Coradoc::CoreModel::Image
506
+ content.alt || content.src || ''
507
+ when Coradoc::AsciiDoc::Model::Base
508
+ if content.content
509
+ extract_text_content(content.content)
510
+ else
511
+ ''
512
+ end
513
+ else
514
+ if content.is_a?(String)
515
+ content
516
+ elsif content.class.name.start_with?('Parslet::')
517
+ content.to_s
518
+ else
519
+ ''
520
+ end
521
+ end
522
+ end
523
+
524
+ def parse_and_transform_inline(text)
525
+ return text if text.nil? || text.to_s.strip.empty?
526
+
527
+ inline_patterns = [
528
+ /stem:\[/,
529
+ /term:\[/,
530
+ /footnote:\[/,
531
+ /\{[a-zA-Z_]+\}/,
532
+ %r{https?://},
533
+ /<[^>]+>/
534
+ ]
535
+
536
+ has_inline_markup = inline_patterns.any? { |pattern| text =~ pattern }
537
+ return text unless has_inline_markup
538
+
539
+ begin
540
+ parsed_elements = Coradoc::AsciiDoc::Transformer.parse_inline_content(text)
541
+ content_array = parsed_elements.flat_map do |element|
542
+ if element.is_a?(Coradoc::AsciiDoc::Model::TextElement)
543
+ element.content
544
+ else
545
+ element
546
+ end
547
+ end
548
+
549
+ transformed = transform_inline_content(content_array)
550
+
551
+ if transformed.all? { |item| item.is_a?(String) }
552
+ transformed.join
553
+ else
554
+ transformed
555
+ end
556
+ rescue StandardError
557
+ text
558
+ end
559
+ end
560
+ end
561
+ end
562
+ end
563
+ end
564
+ end