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,156 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module AsciiDoc
5
+ module Parser
6
+ module Text
7
+ def space?
8
+ space.maybe
9
+ end
10
+
11
+ def space
12
+ str(' ').repeat(1)
13
+ end
14
+
15
+ def text
16
+ match("[^\n]").repeat(1)
17
+ end
18
+
19
+ def line_start?
20
+ match('^[^\n]').present?
21
+ end
22
+
23
+ def line_ending
24
+ str("\n") # | match('[\z]')# | match('$')
25
+ end
26
+
27
+ def eof?
28
+ any.absent?
29
+ end
30
+
31
+ def line_end
32
+ str("\n") | str("\r\n") | eof?
33
+ end
34
+
35
+ def endline
36
+ newline | any.absent?
37
+ end
38
+
39
+ # def endline_single
40
+ # newline_single | any.absent?
41
+ # end
42
+
43
+ def newline
44
+ (str("\n") | str("\r\n")).repeat(1)
45
+ end
46
+
47
+ def newline_single
48
+ (str("\n") | str("\r\n"))
49
+ end
50
+
51
+ def keyword
52
+ (match('[a-zA-Z0-9_\-.,]') | str('.')).repeat(1)
53
+ end
54
+
55
+ def empty_line
56
+ str("\n")
57
+ end
58
+
59
+ def digit
60
+ match('[0-9]')
61
+ end
62
+
63
+ def digits
64
+ match('[0-9]').repeat(1)
65
+ end
66
+
67
+ def word
68
+ match('[a-zA-Z0-9_-]').repeat(1)
69
+ end
70
+
71
+ def words
72
+ word >> (space? >> word).repeat
73
+ end
74
+
75
+ def rich_texts
76
+ rich_text >> (space? >> rich_text).repeat
77
+ end
78
+
79
+ def rich_text
80
+ (match('[a-zA-Z0-9_-]') | str('.') | str('*') | match('@')).repeat(1)
81
+ end
82
+
83
+ def email
84
+ word >> str('@') >> word >> str('.') >> word
85
+ end
86
+
87
+ def special_character
88
+ match('^[*:=-]') | str('[#') | str('[[')
89
+ end
90
+
91
+ def date
92
+ digit.repeat(2, 4) >> str('-') >>
93
+ digit.repeat(1, 2) >> str('-') >> digit.repeat(1, 2)
94
+ end
95
+
96
+ def attr_name
97
+ match("[^\t\s]").repeat(1)
98
+ end
99
+
100
+ def file_path
101
+ match('[^\[]').repeat(1)
102
+ end
103
+
104
+ def include_directive
105
+ (str('include::') >>
106
+ file_path.as(:path) >>
107
+ attribute_list >>
108
+ (newline | str('')).as(:line_break)
109
+ ).as(:include)
110
+ end
111
+
112
+ # block_image is defined in inline.rb with full syntax
113
+ # inline_image is defined in inline.rb for inline images (image:)
114
+
115
+ def block_image
116
+ (element_id.maybe >>
117
+ block_title.maybe >>
118
+ (attribute_list >> newline).maybe >>
119
+ match('^i') >> str('mage::') >>
120
+ file_path.as(:path) >>
121
+ attribute_list(:attribute_list_macro) >>
122
+ newline.as(:line_break)
123
+ ).as(:block_image)
124
+ end
125
+
126
+ def comment_line
127
+ tag.absent? >>
128
+ (str('//') >> str('/').absent? >>
129
+ space? >>
130
+ text.maybe.as(:comment_text) >>
131
+ line_ending.as(:line_break)
132
+ ).as(:comment_line)
133
+ end
134
+
135
+ def tag
136
+ (str('//') >> str('/').absent? >>
137
+ space? >>
138
+ (str('tag') | str('end')).as(:prefix) >>
139
+ str('::') >> str(':').absent? >>
140
+ match('[^\[]').repeat(1).as(:name) >>
141
+ attribute_list >>
142
+ line_ending.maybe.as(:line_break)
143
+ ).as(:tag)
144
+ end
145
+
146
+ def comment_block
147
+ (str('////') >> line_ending >>
148
+ ((line_ending >> str('////')).absent? >> any
149
+ ).repeat.as(:comment_text) >>
150
+ line_ending >> str('////')
151
+ ).as(:comment_block)
152
+ end
153
+ end
154
+ end
155
+ end
156
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module AsciiDoc
5
+ module Parser
6
+ autoload :Base, "#{__dir__}/parser/base"
7
+ autoload :Cache, "#{__dir__}/parser/cache"
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,86 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Autoload FallbackSerializer - only needed when no registered serializer is found
4
+ autoload :FallbackSerializer, 'coradoc/asciidoc/serializer/fallback_serializer'
5
+
6
+ module Coradoc
7
+ module AsciiDoc
8
+ module Serializer
9
+ # Main orchestrator for serializing Coradoc models to AsciiDoc format.
10
+ # Dispatches to appropriate serializer via ElementRegistry.
11
+ #
12
+ # This class is ONLY responsible for orchestration and dispatch.
13
+ # Element registration is handled by ElementRegistry.
14
+ class AdocSerializer
15
+ class << self
16
+ # Serialize a Coradoc model to AsciiDoc string
17
+ # @param model [Coradoc::AsciiDoc::Model::Base, Array, String] Model to serialize
18
+ # @param options [Hash] Serialization options
19
+ # @return [String] AsciiDoc representation
20
+ def serialize(model, options = {})
21
+ case model
22
+ when nil
23
+ ''
24
+ when String
25
+ model
26
+ when Array
27
+ serialize_array(model, options)
28
+ when Coradoc::AsciiDoc::Model::Base
29
+ serialize_model(model, options)
30
+ when Lutaml::Model::Serializable
31
+ raise ArgumentError,
32
+ "Cannot serialize #{model.class.name} to AsciiDoc. " \
33
+ 'Expected a Coradoc::AsciiDoc::Model::Base with a registered serializer.'
34
+ else
35
+ raise ArgumentError,
36
+ "Unknown element type for AsciiDoc serialization: #{model.class}. " \
37
+ 'Expected String, Array, or Coradoc::AsciiDoc::Model::Base.'
38
+ end
39
+ end
40
+
41
+ # Get appropriate serializer instance for a model
42
+ # @param model [Coradoc::AsciiDoc::Model::Base] Model to serialize
43
+ # @return [Serializers::Base] Serializer instance
44
+ def serializer_for(model)
45
+ # Try to find registered serializer
46
+ if ElementRegistry.registered?(model.class)
47
+ serializer_class = ElementRegistry.lookup(model.class)
48
+ return serializer_class.new
49
+ end
50
+
51
+ # Fallback: use FallbackSerializer which raises a clear error
52
+ return FallbackSerializer.new
53
+
54
+ raise ArgumentError, "No serializer registered for #{model.class.name} and model doesn't respond to to_adoc"
55
+ end
56
+
57
+ private
58
+
59
+ # Serialize an array of models
60
+ # @param models [Array] Array of models
61
+ # @param options [Hash] Serialization options
62
+ # @return [String] Serialized array
63
+ def serialize_array(models, options = {})
64
+ results = models.map { |model| serialize(model, options) }
65
+
66
+ # Apply spacing if needed
67
+ if options[:apply_spacing]
68
+ SpacingStrategy.apply(models.zip(results).map(&:first), options)
69
+ else
70
+ results.join
71
+ end
72
+ end
73
+
74
+ # Serialize a single model
75
+ # @param model [Coradoc::AsciiDoc::Model::Base] Model to serialize
76
+ # @param options [Hash] Serialization options
77
+ # @return [String] Serialized model
78
+ def serialize_model(model, options = {})
79
+ serializer = serializer_for(model)
80
+ serializer.serialize(model, options)
81
+ end
82
+ end
83
+ end
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,95 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module AsciiDoc
5
+ module Serializer
6
+ # Registry for mapping Coradoc model classes to their AsciiDoc serializers.
7
+ # This is the authoritative source for model→serializer mappings.
8
+ #
9
+ # Pattern mirrors Input::Html::Converters registry for symmetry.
10
+ #
11
+ # @example Registering a custom serializer
12
+ # ElementRegistry.override(Model::Paragraph, CustomParagraphSerializer)
13
+ #
14
+ # @example Wrapping an existing serializer
15
+ # original = ElementRegistry.get(Model::Paragraph)
16
+ # ElementRegistry.override(Model::Paragraph, WrapperSerializer.new(original))
17
+ class ElementRegistry
18
+ class << self
19
+ # Register a serializer for a model class
20
+ # @param model_class [Class] The Coradoc model class
21
+ # @param serializer_class [Class] The serializer class
22
+ def register(model_class, serializer_class)
23
+ registry[model_class] = serializer_class
24
+ end
25
+
26
+ # Override a serializer for a model class
27
+ # This is an alias for register that makes the intent explicit
28
+ # @param model_class [Class] The Coradoc model class
29
+ # @param serializer_class [Class] The new serializer class
30
+ # @return [Class, nil] The previous serializer class, or nil if none
31
+ def override(model_class, serializer_class)
32
+ previous = registry[model_class]
33
+ registry[model_class] = serializer_class
34
+ previous
35
+ end
36
+
37
+ # Unregister a serializer for a model class
38
+ # @param model_class [Class] The model class to unregister
39
+ # @return [Class, nil] The removed serializer class, or nil if none
40
+ def unregister(model_class)
41
+ registry.delete(model_class)
42
+ end
43
+
44
+ # Get the serializer for a model class without raising
45
+ # @param model_class [Class] The model class
46
+ # @return [Class, nil] The serializer class, or nil if not registered
47
+ def get(model_class)
48
+ registry[model_class]
49
+ end
50
+
51
+ # Lookup serializer for a model class
52
+ # @param model_class [Class] The model class
53
+ # @return [Class] The serializer class
54
+ # @raise [ArgumentError] If no serializer is registered
55
+ def lookup(model_class)
56
+ serializer_class = registry[model_class]
57
+
58
+ unless serializer_class
59
+ raise ArgumentError,
60
+ "No serializer registered for #{model_class.name}. " \
61
+ 'Please register a serializer in ElementRegistry, or the serializer ' \
62
+ 'may not have been loaded yet (check Registrations.load_all!)'
63
+ end
64
+
65
+ serializer_class
66
+ end
67
+
68
+ # Get all registered model classes
69
+ # @return [Array<Class>] Array of registered model classes
70
+ def registered_models
71
+ registry.keys
72
+ end
73
+
74
+ # Check if a model class has a registered serializer
75
+ # @param model_class [Class] The model class
76
+ # @return [Boolean] True if registered
77
+ def registered?(model_class)
78
+ registry.key?(model_class)
79
+ end
80
+
81
+ # Clear all registrations (mainly for testing)
82
+ def clear!
83
+ registry.clear
84
+ end
85
+
86
+ # Get the registry hash
87
+ # @return [Hash] Model class => Serializer class mapping
88
+ def registry
89
+ @@registry ||= {}
90
+ end
91
+ end
92
+ end
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module AsciiDoc
5
+ module Serializer
6
+ # Fallback serializer for models that don't have explicit serializers.
7
+ #
8
+ # NOTE: This serializer does NOT call to_adoc on the model to avoid
9
+ # infinite recursion (model.to_adoc → Serializer.serialize → FallbackSerializer → model.to_adoc).
10
+ # Instead, it raises a clear error indicating the serializer is missing.
11
+ class FallbackSerializer
12
+ def serialize(model, _options = {})
13
+ raise ArgumentError,
14
+ "No serializer registered for #{model.class.name}. " \
15
+ 'Please register a serializer in ElementRegistry, or the serializer ' \
16
+ 'may not have been loaded yet (check Registrations.load_all!)'
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,144 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module AsciiDoc
5
+ module Serializer
6
+ # Handles AsciiDoc-specific formatting for attributes and special structures
7
+ class Formatter
8
+ class << self
9
+ # Format an attribute list for AsciiDoc output
10
+ # @param attrs [Coradoc::AsciiDoc::Model::AttributeList] Attribute list
11
+ # @return [String] Formatted attribute list
12
+ def attribute_list(attrs)
13
+ return '' if attrs.nil?
14
+
15
+ attrs.to_s
16
+ end
17
+
18
+ # Format block attributes (anchor, role, options, etc.)
19
+ # @param attrs [Hash, Coradoc::AsciiDoc::Model::AttributeList] Block attributes
20
+ # @return [String] Formatted block attributes
21
+ def block_attributes(attrs)
22
+ return '' if attrs.nil?
23
+ return '' if attrs.is_a?(String) && attrs.empty?
24
+ return '' if attrs.is_a?(Hash) && attrs.empty?
25
+
26
+ # If it's an AttributeList model, use its serialization
27
+ return attribute_list(attrs) if attrs.is_a?(Coradoc::AsciiDoc::Model::AttributeList)
28
+
29
+ # Otherwise format as hash
30
+ lines = []
31
+
32
+ # Handle anchor if present
33
+ if attrs[:id] || attrs['id']
34
+ id = attrs[:id] || attrs['id']
35
+ lines << "[[#{id}]]"
36
+ end
37
+
38
+ # Handle other attributes
39
+ attr_parts = []
40
+ attrs.each do |key, value|
41
+ next if [:id, 'id'].include?(key)
42
+
43
+ attr_parts << case key
44
+ when :role, 'role'
45
+ ".#{value}"
46
+ when :options, 'options'
47
+ "[#{value}]"
48
+ else
49
+ "#{key}=#{value}"
50
+ end
51
+ end
52
+
53
+ lines << "[#{attr_parts.join(',')}]" unless attr_parts.empty?
54
+ lines.join("\n")
55
+ end
56
+
57
+ # Format a section heading
58
+ # @param level [Integer] Section level (1-6)
59
+ # @param title [String] Section title
60
+ # @param id [String, nil] Optional section ID
61
+ # @return [String] Formatted section heading
62
+ def section_heading(level, title, id = nil)
63
+ prefix = '=' * level
64
+ anchor = id ? "[[#{id}]]\n" : ''
65
+ "#{anchor}#{prefix} #{title}"
66
+ end
67
+
68
+ # Format a block delimiter
69
+ # @param type [Symbol] Block type (:example, :sidebar, :quote, etc.)
70
+ # @return [String] Block delimiter
71
+ def block_delimiter(type)
72
+ case type
73
+ when :example
74
+ '===='
75
+ when :sidebar
76
+ '****'
77
+ when :quote
78
+ '____'
79
+ when :listing, :literal
80
+ '----'
81
+ when :passthrough
82
+ '++++'
83
+ else
84
+ '----'
85
+ end
86
+ end
87
+
88
+ # Format an admonition
89
+ # @param type [String] Admonition type (NOTE, TIP, etc.)
90
+ # @param content [String] Admonition content
91
+ # @return [String] Formatted admonition
92
+ def admonition(type, content)
93
+ "#{type.upcase}: #{content}"
94
+ end
95
+
96
+ # Format a list marker
97
+ # @param type [Symbol] List type (:ordered, :unordered, :definition)
98
+ # @param level [Integer] Nesting level
99
+ # @param index [Integer, nil] Item index for ordered lists
100
+ # @return [String] List marker
101
+ def list_marker(type, level = 1, _index = nil)
102
+ case type
103
+ when :ordered
104
+ "#{'.' * level} "
105
+ when :unordered
106
+ "#{'*' * level} "
107
+ when :definition
108
+ ''
109
+ else
110
+ '* '
111
+ end
112
+ end
113
+
114
+ # Escape special AsciiDoc characters in text
115
+ # Works by prepending a backslash to all delimiter characters
116
+ # in the string that are adjacent to a whitespace.
117
+ # @param text [String] Text to escape
118
+ # @param escape_chars [Array<String>] Characters to escape by prepending backslash
119
+ # @param pass_through [Array<String>] Characters to pass through using pass:[] macro
120
+ # @return [String] Escaped text
121
+ def escape_text(text, escape_chars: [], pass_through: [])
122
+ return '' if text.nil?
123
+
124
+ result = text.to_s.dup
125
+
126
+ regex_chars = Regexp.escape(escape_chars.join)
127
+ unless regex_chars.empty?
128
+ result.gsub!(
129
+ /((?<=\s)[#{regex_chars}]+)|([#{regex_chars}]+(?=\s))/
130
+ ) do |match|
131
+ match.chars.map { |c| "\\#{c}" }.join
132
+ end
133
+ end
134
+
135
+ regex_pass = Regexp.escape(pass_through.join)
136
+ result.gsub!(/([#{regex_pass}]+)/, '{pass:[\\1]}') unless regex_pass.empty?
137
+
138
+ result
139
+ end
140
+ end
141
+ end
142
+ end
143
+ end
144
+ end
@@ -0,0 +1,108 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module AsciiDoc
5
+ module Serializer
6
+ # Trigger loading of all serializer registrations
7
+ #
8
+ # Each serializer file self-registers when loaded via autoload.
9
+ # This module triggers the autoload of all serializers by accessing
10
+ # their constants, which causes the registration code in each file to execute.
11
+ module Registrations
12
+ class << self
13
+ # Load all serializers to trigger their registration
14
+ # rubocop:disable Lint/Void - Constants are referenced to trigger autoload
15
+ def load_all!
16
+ # Top-level serializers
17
+ Serializers::Base
18
+ Serializers::Admonition
19
+ Serializers::Attribute
20
+ Serializers::AttributeList
21
+ Serializers::AttributeListAttribute
22
+ Serializers::Audio
23
+ Serializers::Author
24
+ Serializers::Bibliography
25
+ Serializers::BibliographyEntry
26
+ Serializers::Break
27
+ Serializers::CommentBlock
28
+ Serializers::CommentLine
29
+ Serializers::Document
30
+ Serializers::DocumentAttributes
31
+ Serializers::Header
32
+ Serializers::Highlight
33
+ Serializers::Include
34
+ Serializers::LineBreak
35
+ Serializers::List
36
+ Serializers::NamedAttribute
37
+ Serializers::Paragraph
38
+ Serializers::ReviewerNote
39
+ Serializers::Revision
40
+ Serializers::Section
41
+ Serializers::Tag
42
+ Serializers::TableCell
43
+ Serializers::TableRow
44
+ Serializers::Table
45
+ Serializers::Term
46
+ Serializers::TextElement
47
+ Serializers::Title
48
+ Serializers::Video
49
+
50
+ # Block serializers
51
+ Serializers::Block
52
+ Serializers::Block::Core
53
+ Serializers::Block::Example
54
+ Serializers::Block::Listing
55
+ Serializers::Block::Literal
56
+ Serializers::Block::Open
57
+ Serializers::Block::Pass
58
+ Serializers::Block::Quote
59
+ Serializers::Block::ReviewerComment
60
+ Serializers::Block::Side
61
+ Serializers::Block::SourceCode
62
+
63
+ # Image serializers
64
+ Serializers::Image
65
+ Serializers::Image::Core
66
+
67
+ # Inline serializers
68
+ Serializers::Inline
69
+ Serializers::Inline::Anchor
70
+ Serializers::Inline::AttributeReference
71
+ Serializers::Inline::Bold
72
+ Serializers::Inline::CrossReference
73
+ Serializers::Inline::CrossReferenceArg
74
+ Serializers::Inline::Footnote
75
+ Serializers::Inline::HardLineBreak
76
+ Serializers::Inline::Highlight
77
+ Serializers::Inline::Italic
78
+ Serializers::Inline::Link
79
+ Serializers::Inline::Monospace
80
+ Serializers::Inline::Quotation
81
+ Serializers::Inline::Small
82
+ Serializers::Inline::Span
83
+ Serializers::Inline::Stem
84
+ Serializers::Inline::Strikethrough
85
+ Serializers::Inline::Subscript
86
+ Serializers::Inline::Superscript
87
+ Serializers::Inline::Underline
88
+
89
+ # List serializers
90
+ Serializers::List
91
+ Serializers::List::Core
92
+ Serializers::List::Definition
93
+ Serializers::List::DefinitionItem
94
+ Serializers::List::Item
95
+ Serializers::List::Ordered
96
+ Serializers::List::Unordered
97
+
98
+ true
99
+ end
100
+ # rubocop:enable Lint/Void
101
+ end
102
+
103
+ # Auto-load all on module inclusion
104
+ load_all!
105
+ end
106
+ end
107
+ end
108
+ end