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,109 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module AsciiDoc
5
+ module Model
6
+ # Section element for organizing document content hierarchically.
7
+ #
8
+ # Sections represent the hierarchical structure of an AsciiDoc document.
9
+ # They can contain nested subsections, paragraphs, and other content.
10
+ #
11
+ # @!attribute [r] id
12
+ # @return [String, nil] Optional identifier for the section
13
+ # @!attribute [r] content
14
+ # @return [String, nil] Optional string content (typically unused, see contents)
15
+ # @!attribute [r] title
16
+ # @return [Title] Section title
17
+ # @!attribute [r] attrs
18
+ # @return [Array<NamedAttribute>] Additional named attributes
19
+ # @!attribute [r] contents
20
+ # @return [Array<Paragraph>] Paragraph content within this section
21
+ # @!attribute [r] sections
22
+ # @return [Array<Section>] Nested subsections
23
+ #
24
+ # @example Create a section
25
+ # section = Coradoc::AsciiDoc::Model::Section.new(
26
+ # title: Coradoc::AsciiDoc::Model::Title.new("Chapter 1"),
27
+ # contents: [Coradoc::AsciiDoc::Model::Paragraph.new("Content here")]
28
+ # )
29
+ #
30
+ # @example Create nested sections
31
+ # parent = Coradoc::AsciiDoc::Model::Section.new(
32
+ # title: Coradoc::AsciiDoc::Model::Title.new("Parent Section")
33
+ # )
34
+ # child = Coradoc::AsciiDoc::Model::Section.new(
35
+ # title: Coradoc::AsciiDoc::Model::Title.new("Child Section")
36
+ # )
37
+ # parent.sections << child
38
+ #
39
+ class Section < Base
40
+ include Coradoc::AsciiDoc::Model::Anchorable
41
+
42
+ def block_level?
43
+ true
44
+ end
45
+
46
+ attribute :id, :string
47
+ attribute :content, :string
48
+ attribute :title, Coradoc::AsciiDoc::Model::Title
49
+ attribute :attrs,
50
+ Coradoc::AsciiDoc::Model::NamedAttribute,
51
+ collection: true,
52
+ initialize_empty: true
53
+ attribute :contents,
54
+ Coradoc::AsciiDoc::Model::Paragraph,
55
+ collection: true,
56
+ initialize_empty: true
57
+ attribute :sections,
58
+ Coradoc::AsciiDoc::Model::Section,
59
+ collection: true,
60
+ initialize_empty: true
61
+ # attribute :anchor, Coradoc::AsciiDoc::Model::Inline::Anchor
62
+
63
+ # Allow setting level directly during initialization
64
+ def initialize(**attributes)
65
+ level_value = attributes.delete(:level)
66
+ super
67
+ if level_value && title
68
+ title.level_int = level_value
69
+ elsif level_value
70
+ self.title = Coradoc::AsciiDoc::Model::Title.new(content: '', level_int: level_value)
71
+ end
72
+ end
73
+
74
+ def validate
75
+ validate_title_type
76
+ super
77
+ end
78
+
79
+ # Get the section level from the title
80
+ # @return [Integer, nil] The section level (0-5 for standard sections)
81
+ def level
82
+ title&.level_int
83
+ end
84
+
85
+ # Set the section level on the title
86
+ # @param value [Integer] The section level
87
+ def level=(value)
88
+ if title
89
+ title.level_int = value
90
+ else
91
+ self.title = Coradoc::AsciiDoc::Model::Title.new(content: '', level_int: value)
92
+ end
93
+ end
94
+
95
+ def safe_to_collapse?
96
+ title.nil? && sections.empty?
97
+ end
98
+
99
+ private
100
+
101
+ def validate_title_type
102
+ return if title.nil? || title.is_a?(Coradoc::AsciiDoc::Model::Title)
103
+
104
+ raise TypeError, "title must be a Coradoc::AsciiDoc::Model::Title, got #{title.class}"
105
+ end
106
+ end
107
+ end
108
+ end
109
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module AsciiDoc
5
+ module Model
6
+ module Serialization
7
+ # Adapter for AsciiDoc serialization in Lutaml::Model format registry.
8
+ #
9
+ # This is a standalone adapter class that delegates to Coradoc's
10
+ # parsing infrastructure. It does NOT inherit from Base to avoid
11
+ # circular dependencies with the format registration system.
12
+ #
13
+ class AsciidocAdapter
14
+ # Delegate to Model::Document for AST creation
15
+ def self.from_ast(elements)
16
+ # Lazy reference to avoid loading Document before format is registered
17
+ Coradoc::AsciiDoc::Model::Document.from_ast(elements)
18
+ end
19
+
20
+ # Delegate to Coradoc.parse for parsing
21
+ def self.parse(string)
22
+ Coradoc.parse(string)
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module AsciiDoc
5
+ module Model
6
+ module Serialization
7
+ # Define the DSL for defining mappings in Asciidoc format
8
+ class AsciidocMapping < Lutaml::Model::Mapping
9
+ attr_reader :mappings
10
+
11
+ def initialize
12
+ super
13
+ @mappings = []
14
+ end
15
+
16
+ def map_model(to:)
17
+ add_mapping('__element', to, field_type: :parsed_element)
18
+ end
19
+
20
+ def map_content(to:)
21
+ add_mapping('__content', to, field_type: :content)
22
+ end
23
+
24
+ def map_attribute(name, to:, render_nil: false)
25
+ add_mapping(
26
+ name,
27
+ to,
28
+ field_type: :attributes,
29
+ render_nil: render_nil
30
+ )
31
+ end
32
+
33
+ private
34
+
35
+ def add_mapping(name, to, **options)
36
+ @mappings << AsciidocMappingRule.new(name, to: to, **options)
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module AsciiDoc
5
+ module Model
6
+ module Serialization
7
+ class AsciidocMappingRule < Lutaml::Model::MappingRule
8
+ # Can be :parsed_element, :content, or :attributes
9
+ attr_reader :field_type
10
+
11
+ def initialize(
12
+ name,
13
+ to:,
14
+ render_nil: false,
15
+ field_type: :attributes
16
+ )
17
+ super(name, to:, render_nil:)
18
+ @field_type = field_type
19
+ end
20
+
21
+ def model_map?
22
+ field_type == :parsed_element
23
+ end
24
+
25
+ def content?
26
+ field_type == :content
27
+ end
28
+
29
+ def deep_dup
30
+ self.class.new(
31
+ name.dup,
32
+ to: to.dup,
33
+ render_nil: render_nil.dup,
34
+ field_type:
35
+ )
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,211 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module AsciiDoc
5
+ module Model
6
+ module Serialization
7
+ # Transform class for converting between Coradoc::Element and Lutaml::Model objects
8
+ #
9
+ # This handles bidirectional transformation for AsciiDoc serialization:
10
+ # - data_to_model: Coradoc::Element -> Lutaml::Model::Serializable
11
+ # - model_to_data: Lutaml::Model::Serializable -> Coradoc::Element
12
+ #
13
+ class AsciidocTransform < Lutaml::Model::Transform
14
+ # Convert Coradoc::Element data to Lutaml::Model instance
15
+ #
16
+ # @param context [Context] The context with attribute and mapping management
17
+ # @param data [Coradoc::Element::Base] The Coradoc element to convert
18
+ # @param format [Symbol] The format type (:asciidoc)
19
+ # @param options [Hash] Additional options
20
+ # @return [Lutaml::Model::Serializable] The model instance
21
+ def self.data_to_model(context, data, _format, options = {})
22
+ new(context).data_to_model(data, options)
23
+ end
24
+
25
+ # Convert Lutaml::Model instance to Coradoc::Element data
26
+ #
27
+ # @param context [Context] The context with attribute and mapping management
28
+ # @param model [Lutaml::Model::Serializable] The model to convert
29
+ # @param format [Symbol] The format type (:asciidoc)
30
+ # @param options [Hash] Additional options
31
+ # @return [Coradoc::Element::Base] The Coradoc element
32
+ def self.model_to_data(context, model, _format, options = {})
33
+ new(context).model_to_data(model, options)
34
+ end
35
+
36
+ # Transform Coradoc::Element to model instance
37
+ def data_to_model(data, options = {})
38
+ return nil if data.nil?
39
+
40
+ # Get mappings for asciidoc format
41
+ mappings = context.mappings_for(:asciidoc)
42
+ return nil unless mappings
43
+
44
+ mapping_rules = mappings.mappings
45
+ return nil unless mapping_rules
46
+
47
+ # Find the parsed_element mapping to get target class
48
+ parsed_element_rule = mapping_rules.find { |m| m.field_type == :parsed_element }
49
+ return nil unless parsed_element_rule
50
+
51
+ target_class = parsed_element_rule.to
52
+ return nil unless target_class
53
+
54
+ # Validate data type if from is specified
55
+ return nil if parsed_element_rule.from && !data.is_a?(parsed_element_rule.from)
56
+
57
+ # Create instance and populate attributes
58
+ instance = target_class.new
59
+ attributes = target_class.attributes
60
+ defaults_used = []
61
+
62
+ mapping_rules.reject(&:model_map?).each do |rule|
63
+ attr = attributes[rule.to]
64
+ next if attr&.derived?
65
+
66
+ # Get value from source data
67
+ source_value = data.public_send(rule.name || rule.to)
68
+
69
+ # Transform the value
70
+ value = transform_value(source_value, attr, options)
71
+
72
+ # Handle defaults
73
+ if value.nil? && (instance.using_default?(rule.to) || rule.render_default)
74
+ defaults_used << rule.to
75
+ value = attr&.default || rule.to_value_for(instance)
76
+ end
77
+
78
+ # Apply value map if present
79
+ value = apply_value_map(value, rule.value_map(:from, options), attr)
80
+
81
+ # Set the value
82
+ instance.public_send(:"#{rule.to}=", value) if value
83
+ end
84
+
85
+ # Mark defaults as used
86
+ defaults_used.each { |attr_name| instance.using_default_for(attr_name) }
87
+
88
+ instance
89
+ end
90
+
91
+ # Transform model instance to Coradoc::Element
92
+ def model_to_data(model, options = {})
93
+ return nil if model.nil?
94
+
95
+ # Get mappings for asciidoc format
96
+ mappings = context.mappings_for(:asciidoc)
97
+ return nil unless mappings
98
+
99
+ mapping_rules = mappings.mappings
100
+ return nil unless mapping_rules
101
+
102
+ # Find the parsed_element mapping to get target class
103
+ parsed_element_rule = mapping_rules.find { |m| m.field_type == :parsed_element }
104
+ return nil unless parsed_element_rule
105
+
106
+ target_class = parsed_element_rule.from
107
+ return nil unless target_class
108
+
109
+ # Create instance and populate attributes
110
+ attributes = model.class.attributes
111
+ instance = target_class.new
112
+
113
+ mapping_rules.reject(&:model_map?).each do |rule|
114
+ attr = attributes[rule.to]
115
+ next if attr&.derived?
116
+
117
+ # Get value from model
118
+ model_value = model.public_send(rule.to)
119
+ next if model_value.nil?
120
+
121
+ # Transform the value back
122
+ value = transform_value_to_data(model_value, attr, options)
123
+
124
+ # Set on target instance
125
+ target_attr = rule.name || rule.to
126
+ instance.public_send(:"#{target_attr}=", value)
127
+ end
128
+
129
+ instance
130
+ end
131
+
132
+ protected
133
+
134
+ # Transform a value from data to model format
135
+ def transform_value(value, attr, options = {})
136
+ return nil if value.nil?
137
+
138
+ case value
139
+ when Array
140
+ value.map { |v| transform_single_value(v, attr, options) }
141
+ else
142
+ transform_single_value(value, attr, options)
143
+ end
144
+ end
145
+
146
+ # Transform a single value
147
+ def transform_single_value(value, attr, options = {})
148
+ case value
149
+ when Lutaml::Model::Type::Value
150
+ value.value
151
+ when Lutaml::Model::Serializable
152
+ # Recursively transform nested models
153
+ self.class.data_to_model(context, value, :asciidoc, options)
154
+ when Coradoc::Element::Base
155
+ # Already a Coradoc element, may need conversion
156
+ if attr&.type&.<(Lutaml::Model::Type::Value)
157
+ value.is_a?(Coradoc::AsciiDoc::Model::Base) && value.class.attributes.key?(:content) ? value.content : value.to_s
158
+ else
159
+ value
160
+ end
161
+ else
162
+ value
163
+ end
164
+ end
165
+
166
+ # Transform a value from model to data format
167
+ def transform_value_to_data(value, attr, options = {})
168
+ case value
169
+ when Array
170
+ value.map { |v| transform_single_value_to_data(v, attr, options) }
171
+ else
172
+ transform_single_value_to_data(value, attr, options)
173
+ end
174
+ end
175
+
176
+ # Transform a single value to data format
177
+ def transform_single_value_to_data(value, _attr, options = {})
178
+ case value
179
+ when Lutaml::Model::Serializable
180
+ # Recursively transform back to Coradoc element
181
+ self.class.model_to_data(context, value, :asciidoc, options)
182
+ when Lutaml::Model::Type::Value
183
+ value.value
184
+ else
185
+ value
186
+ end
187
+ end
188
+
189
+ # Apply value map transformation if present
190
+ def apply_value_map(value, value_map, _attr)
191
+ return value unless value_map
192
+
193
+ case value_map[:type]
194
+ when :symbolize_keys
195
+ value.transform_keys(&:to_sym) if value.is_a?(Hash)
196
+ when :stringify_keys
197
+ value.transform_keys(&:to_s) if value.is_a?(Hash)
198
+ else
199
+ value
200
+ end
201
+ end
202
+
203
+ # Get mappings for asciidoc format
204
+ def mappings
205
+ @mappings ||= context.mappings_for(:asciidoc)&.mappings || []
206
+ end
207
+ end
208
+ end
209
+ end
210
+ end
211
+ end
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module AsciiDoc
5
+ module Model
6
+ module Serialization
7
+ module Errors
8
+ # Base class for all AsciiDoc serialization errors
9
+ # Inherits from Coradoc::Error for consistent error handling
10
+ class AsciidocError < Coradoc::Error; end
11
+
12
+ # Raised when parsing invalid AsciiDoc content
13
+ class ParseError < AsciidocError
14
+ attr_reader :input, :line_number
15
+
16
+ def initialize(message, input: nil, line_number: nil)
17
+ @input = input
18
+ @line_number = line_number
19
+ super(message)
20
+ end
21
+ end
22
+
23
+ # Raised when attribute mapping fails
24
+ class MappingError < AsciidocError
25
+ attr_reader :field_name, :value
26
+
27
+ def initialize(message, field_name: nil, value: nil)
28
+ @field_name = field_name
29
+ @value = value
30
+ super(message)
31
+ end
32
+ end
33
+
34
+ # Raised when required fields are missing
35
+ class ValidationError < AsciidocError
36
+ attr_reader :field_name
37
+
38
+ def initialize(message, field_name: nil)
39
+ @field_name = field_name
40
+ super(message)
41
+ end
42
+ end
43
+
44
+ # Raised when trying to serialize invalid model state
45
+ class SerializationError < AsciidocError
46
+ attr_reader :object
47
+
48
+ def initialize(message, object: nil)
49
+ @object = object
50
+ super(message)
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module AsciiDoc
5
+ module Model
6
+ # Serialization support for AsciiDoc models.
7
+ #
8
+ # This module registers the `asciidoc` format with Lutaml::Model,
9
+ # enabling the `asciidoc do ... end` DSL in model classes.
10
+ #
11
+ # IMPORTANT: This module must be loaded BEFORE any model class
12
+ # that uses the `asciidoc` DSL. It is loaded eagerly by model.rb
13
+ # to ensure the format is registered early.
14
+ #
15
+ module Serialization
16
+ # Load all serialization components eagerly (they're small and interdependent)
17
+ require_relative 'serialization/errors'
18
+ require_relative 'serialization/asciidoc_adapter'
19
+ require_relative 'serialization/asciidoc_mapping_rule'
20
+ require_relative 'serialization/asciidoc_mapping'
21
+ require_relative 'serialization/asciidoc_transform'
22
+
23
+ # Register the asciidoc format with Lutaml::Model
24
+ # This enables the `asciidoc do ... end` DSL in model classes
25
+ def self.register_format!
26
+ Lutaml::Model::FormatRegistry.register(
27
+ :asciidoc,
28
+ mapping_class: AsciidocMapping,
29
+ adapter_class: AsciidocAdapter,
30
+ transformer: AsciidocTransform
31
+ )
32
+ end
33
+
34
+ # Register format when this module is loaded
35
+ register_format!
36
+ end
37
+ end
38
+ end
39
+ end