coradoc 1.1.8 → 2.0.12

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 (225) hide show
  1. checksums.yaml +4 -4
  2. data/.rspec +1 -1
  3. data/Rakefile +3 -12
  4. data/exe/coradoc +21 -2
  5. data/lib/coradoc/cli.rb +185 -91
  6. data/lib/coradoc/configurable.rb +527 -0
  7. data/lib/coradoc/coradoc.rb +463 -0
  8. data/lib/coradoc/core_model/annotation_block.rb +57 -0
  9. data/lib/coradoc/core_model/base.rb +172 -0
  10. data/lib/coradoc/core_model/bibliography.rb +41 -0
  11. data/lib/coradoc/core_model/bibliography_entry.rb +48 -0
  12. data/lib/coradoc/core_model/block.rb +63 -0
  13. data/lib/coradoc/core_model/children_content.rb +53 -0
  14. data/lib/coradoc/core_model/comment_block.rb +10 -0
  15. data/lib/coradoc/core_model/definition_item.rb +46 -0
  16. data/lib/coradoc/core_model/definition_list.rb +28 -0
  17. data/lib/coradoc/core_model/element_attribute.rb +26 -0
  18. data/lib/coradoc/core_model/example_block.rb +10 -0
  19. data/lib/coradoc/core_model/footnote.rb +92 -0
  20. data/lib/coradoc/core_model/horizontal_rule_block.rb +10 -0
  21. data/lib/coradoc/core_model/id_generator.rb +16 -0
  22. data/lib/coradoc/core_model/image.rb +66 -0
  23. data/lib/coradoc/core_model/inline_element.rb +140 -0
  24. data/lib/coradoc/core_model/list_block.rb +135 -0
  25. data/lib/coradoc/core_model/list_item.rb +142 -0
  26. data/lib/coradoc/core_model/listing_block.rb +13 -0
  27. data/lib/coradoc/core_model/literal_block.rb +10 -0
  28. data/lib/coradoc/core_model/metadata.rb +79 -0
  29. data/lib/coradoc/core_model/open_block.rb +10 -0
  30. data/lib/coradoc/core_model/paragraph_block.rb +10 -0
  31. data/lib/coradoc/core_model/pass_block.rb +10 -0
  32. data/lib/coradoc/core_model/quote_block.rb +12 -0
  33. data/lib/coradoc/core_model/reviewer_block.rb +10 -0
  34. data/lib/coradoc/core_model/sidebar_block.rb +10 -0
  35. data/lib/coradoc/core_model/source_block.rb +10 -0
  36. data/lib/coradoc/core_model/structural_element.rb +94 -0
  37. data/lib/coradoc/core_model/table.rb +148 -0
  38. data/lib/coradoc/core_model/term.rb +53 -0
  39. data/lib/coradoc/core_model/text_content.rb +22 -0
  40. data/lib/coradoc/core_model/toc.rb +105 -0
  41. data/lib/coradoc/core_model/toc_generator.rb +151 -0
  42. data/lib/coradoc/core_model/verse_block.rb +12 -0
  43. data/lib/coradoc/core_model.rb +77 -0
  44. data/lib/coradoc/document_builder.rb +184 -0
  45. data/lib/coradoc/document_manipulator.rb +203 -0
  46. data/lib/coradoc/errors.rb +312 -0
  47. data/lib/coradoc/format_module.rb +49 -0
  48. data/lib/coradoc/hooks.rb +176 -0
  49. data/lib/coradoc/input.rb +17 -7
  50. data/lib/coradoc/logger.rb +54 -0
  51. data/lib/coradoc/output.rb +17 -6
  52. data/lib/coradoc/performance_regression.rb +109 -0
  53. data/lib/coradoc/processor_registry.rb +50 -0
  54. data/lib/coradoc/query.rb +455 -0
  55. data/lib/coradoc/registry.rb +156 -0
  56. data/lib/coradoc/serializer/registry.rb +150 -0
  57. data/lib/coradoc/transform.rb +11 -0
  58. data/lib/coradoc/validation.rb +646 -0
  59. data/lib/coradoc/version.rb +1 -1
  60. data/lib/coradoc/visitor.rb +283 -0
  61. data/lib/coradoc.rb +40 -19
  62. metadata +67 -277
  63. data/.editorconfig +0 -15
  64. data/.envrc +0 -1
  65. data/.irbrc +0 -1
  66. data/.pryrc.sample +0 -1
  67. data/.rubocop.yml +0 -14
  68. data/.rubocop_todo.yml +0 -179
  69. data/CHANGELOG.md +0 -9
  70. data/CODE_OF_CONDUCT.md +0 -84
  71. data/Dockerfile +0 -19
  72. data/Gemfile +0 -16
  73. data/LICENSE.txt +0 -21
  74. data/Makefile +0 -35
  75. data/README.Docker.adoc +0 -57
  76. data/README.adoc +0 -119
  77. data/coradoc.gemspec +0 -40
  78. data/docker-compose.yml +0 -14
  79. data/exe/reverse_adoc +0 -81
  80. data/exe/w2a +0 -60
  81. data/flake.lock +0 -114
  82. data/flake.nix +0 -135
  83. data/lib/coradoc/converter.rb +0 -144
  84. data/lib/coradoc/document.rb +0 -77
  85. data/lib/coradoc/element/admonition.rb +0 -18
  86. data/lib/coradoc/element/attribute.rb +0 -36
  87. data/lib/coradoc/element/attribute_list.rb +0 -138
  88. data/lib/coradoc/element/audio.rb +0 -33
  89. data/lib/coradoc/element/author.rb +0 -24
  90. data/lib/coradoc/element/base.rb +0 -92
  91. data/lib/coradoc/element/bibliography.rb +0 -24
  92. data/lib/coradoc/element/bibliography_entry.rb +0 -24
  93. data/lib/coradoc/element/block/core.rb +0 -76
  94. data/lib/coradoc/element/block/example.rb +0 -23
  95. data/lib/coradoc/element/block/listing.rb +0 -21
  96. data/lib/coradoc/element/block/literal.rb +0 -21
  97. data/lib/coradoc/element/block/open.rb +0 -22
  98. data/lib/coradoc/element/block/pass.rb +0 -21
  99. data/lib/coradoc/element/block/quote.rb +0 -19
  100. data/lib/coradoc/element/block/reviewer_comment.rb +0 -19
  101. data/lib/coradoc/element/block/side.rb +0 -19
  102. data/lib/coradoc/element/block/sourcecode.rb +0 -21
  103. data/lib/coradoc/element/block.rb +0 -17
  104. data/lib/coradoc/element/break.rb +0 -11
  105. data/lib/coradoc/element/comment_block.rb +0 -22
  106. data/lib/coradoc/element/comment_line.rb +0 -18
  107. data/lib/coradoc/element/document_attributes.rb +0 -33
  108. data/lib/coradoc/element/header.rb +0 -22
  109. data/lib/coradoc/element/image/block_image.rb +0 -32
  110. data/lib/coradoc/element/image/core.rb +0 -58
  111. data/lib/coradoc/element/image/inline_image.rb +0 -12
  112. data/lib/coradoc/element/image.rb +0 -10
  113. data/lib/coradoc/element/include.rb +0 -18
  114. data/lib/coradoc/element/inline/anchor.rb +0 -19
  115. data/lib/coradoc/element/inline/attribute_reference.rb +0 -19
  116. data/lib/coradoc/element/inline/bold.rb +0 -25
  117. data/lib/coradoc/element/inline/cross_reference.rb +0 -46
  118. data/lib/coradoc/element/inline/footnote.rb +0 -24
  119. data/lib/coradoc/element/inline/hard_line_break.rb +0 -11
  120. data/lib/coradoc/element/inline/highlight.rb +0 -25
  121. data/lib/coradoc/element/inline/italic.rb +0 -25
  122. data/lib/coradoc/element/inline/link.rb +0 -42
  123. data/lib/coradoc/element/inline/monospace.rb +0 -25
  124. data/lib/coradoc/element/inline/quotation.rb +0 -20
  125. data/lib/coradoc/element/inline/small.rb +0 -19
  126. data/lib/coradoc/element/inline/span.rb +0 -37
  127. data/lib/coradoc/element/inline/subscript.rb +0 -20
  128. data/lib/coradoc/element/inline/superscript.rb +0 -20
  129. data/lib/coradoc/element/inline/underline.rb +0 -19
  130. data/lib/coradoc/element/inline.rb +0 -23
  131. data/lib/coradoc/element/list/core.rb +0 -51
  132. data/lib/coradoc/element/list/definition.rb +0 -29
  133. data/lib/coradoc/element/list/ordered.rb +0 -17
  134. data/lib/coradoc/element/list/unordered.rb +0 -17
  135. data/lib/coradoc/element/list.rb +0 -13
  136. data/lib/coradoc/element/list_item.rb +0 -98
  137. data/lib/coradoc/element/list_item_definition.rb +0 -32
  138. data/lib/coradoc/element/paragraph.rb +0 -37
  139. data/lib/coradoc/element/revision.rb +0 -27
  140. data/lib/coradoc/element/section.rb +0 -62
  141. data/lib/coradoc/element/table.rb +0 -91
  142. data/lib/coradoc/element/tag.rb +0 -19
  143. data/lib/coradoc/element/term.rb +0 -22
  144. data/lib/coradoc/element/text_element.rb +0 -92
  145. data/lib/coradoc/element/title.rb +0 -62
  146. data/lib/coradoc/element/video.rb +0 -50
  147. data/lib/coradoc/generator.rb +0 -19
  148. data/lib/coradoc/input/adoc.rb +0 -30
  149. data/lib/coradoc/input/docx.rb +0 -64
  150. data/lib/coradoc/input/html/LICENSE.txt +0 -25
  151. data/lib/coradoc/input/html/README.adoc +0 -308
  152. data/lib/coradoc/input/html/cleaner.rb +0 -142
  153. data/lib/coradoc/input/html/config.rb +0 -77
  154. data/lib/coradoc/input/html/converters/a.rb +0 -52
  155. data/lib/coradoc/input/html/converters/aside.rb +0 -16
  156. data/lib/coradoc/input/html/converters/audio.rb +0 -29
  157. data/lib/coradoc/input/html/converters/base.rb +0 -108
  158. data/lib/coradoc/input/html/converters/blockquote.rb +0 -22
  159. data/lib/coradoc/input/html/converters/br.rb +0 -15
  160. data/lib/coradoc/input/html/converters/bypass.rb +0 -81
  161. data/lib/coradoc/input/html/converters/code.rb +0 -23
  162. data/lib/coradoc/input/html/converters/div.rb +0 -19
  163. data/lib/coradoc/input/html/converters/dl.rb +0 -62
  164. data/lib/coradoc/input/html/converters/drop.rb +0 -26
  165. data/lib/coradoc/input/html/converters/em.rb +0 -21
  166. data/lib/coradoc/input/html/converters/figure.rb +0 -25
  167. data/lib/coradoc/input/html/converters/h.rb +0 -42
  168. data/lib/coradoc/input/html/converters/head.rb +0 -23
  169. data/lib/coradoc/input/html/converters/hr.rb +0 -15
  170. data/lib/coradoc/input/html/converters/ignore.rb +0 -20
  171. data/lib/coradoc/input/html/converters/img.rb +0 -110
  172. data/lib/coradoc/input/html/converters/li.rb +0 -17
  173. data/lib/coradoc/input/html/converters/mark.rb +0 -19
  174. data/lib/coradoc/input/html/converters/markup.rb +0 -31
  175. data/lib/coradoc/input/html/converters/math.rb +0 -38
  176. data/lib/coradoc/input/html/converters/ol.rb +0 -65
  177. data/lib/coradoc/input/html/converters/p.rb +0 -23
  178. data/lib/coradoc/input/html/converters/pass_through.rb +0 -17
  179. data/lib/coradoc/input/html/converters/pre.rb +0 -55
  180. data/lib/coradoc/input/html/converters/q.rb +0 -16
  181. data/lib/coradoc/input/html/converters/strong.rb +0 -20
  182. data/lib/coradoc/input/html/converters/sub.rb +0 -22
  183. data/lib/coradoc/input/html/converters/sup.rb +0 -22
  184. data/lib/coradoc/input/html/converters/table.rb +0 -319
  185. data/lib/coradoc/input/html/converters/td.rb +0 -81
  186. data/lib/coradoc/input/html/converters/text.rb +0 -32
  187. data/lib/coradoc/input/html/converters/th.rb +0 -18
  188. data/lib/coradoc/input/html/converters/tr.rb +0 -22
  189. data/lib/coradoc/input/html/converters/video.rb +0 -29
  190. data/lib/coradoc/input/html/converters.rb +0 -59
  191. data/lib/coradoc/input/html/errors.rb +0 -14
  192. data/lib/coradoc/input/html/html_converter.rb +0 -168
  193. data/lib/coradoc/input/html/plugin.rb +0 -131
  194. data/lib/coradoc/input/html/plugins/plateau.rb +0 -213
  195. data/lib/coradoc/input/html/postprocessor.rb +0 -220
  196. data/lib/coradoc/input/html.rb +0 -61
  197. data/lib/coradoc/legacy_parser.rb +0 -200
  198. data/lib/coradoc/oscal.rb +0 -99
  199. data/lib/coradoc/output/adoc.rb +0 -19
  200. data/lib/coradoc/output/coradoc_tree_debug.rb +0 -21
  201. data/lib/coradoc/parser/asciidoc/admonition.rb +0 -24
  202. data/lib/coradoc/parser/asciidoc/attribute_list.rb +0 -89
  203. data/lib/coradoc/parser/asciidoc/base.rb +0 -87
  204. data/lib/coradoc/parser/asciidoc/bibliography.rb +0 -29
  205. data/lib/coradoc/parser/asciidoc/block.rb +0 -94
  206. data/lib/coradoc/parser/asciidoc/citation.rb +0 -30
  207. data/lib/coradoc/parser/asciidoc/content.rb +0 -64
  208. data/lib/coradoc/parser/asciidoc/document_attributes.rb +0 -25
  209. data/lib/coradoc/parser/asciidoc/header.rb +0 -29
  210. data/lib/coradoc/parser/asciidoc/inline.rb +0 -195
  211. data/lib/coradoc/parser/asciidoc/list.rb +0 -115
  212. data/lib/coradoc/parser/asciidoc/paragraph.rb +0 -54
  213. data/lib/coradoc/parser/asciidoc/section.rb +0 -61
  214. data/lib/coradoc/parser/asciidoc/table.rb +0 -32
  215. data/lib/coradoc/parser/asciidoc/term.rb +0 -41
  216. data/lib/coradoc/parser/asciidoc/text.rb +0 -158
  217. data/lib/coradoc/parser/base.rb +0 -40
  218. data/lib/coradoc/parser.rb +0 -11
  219. data/lib/coradoc/reverse_adoc.rb +0 -18
  220. data/lib/coradoc/transformer.rb +0 -476
  221. data/lib/coradoc/util.rb +0 -12
  222. data/lib/reverse_adoc.rb +0 -20
  223. data/utils/inspect_asciidoc.rb +0 -29
  224. data/utils/parser_analyzer.rb +0 -66
  225. data/utils/round_trip.rb +0 -53
@@ -0,0 +1,135 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module CoreModel
5
+ # Represents a single item within a list
6
+ #
7
+ # A list item can contain:
8
+ # - Simple text content
9
+ # - A nested list
10
+ # - Child elements (paragraphs, blocks, etc.)
11
+ #
12
+ # Note: The nested_list attribute type is set after ListBlock is defined
13
+ # to avoid circular dependency issues.
14
+ #
15
+ # @example Simple list item
16
+ # item = ListItem.new(
17
+ # marker: "*",
18
+ # content: "Item text"
19
+ # )
20
+ #
21
+ # @example List item with nested list
22
+ # item = ListItem.new(
23
+ # marker: "*",
24
+ # content: "Parent item",
25
+ # nested_list: nested_list_block
26
+ # )
27
+ class ListItem < Base
28
+ # @!attribute marker
29
+ # @return [String, nil] the marker character(s) for this item
30
+ # (e.g., '*', '**', '.', '..', '-')
31
+ attribute :marker, :string
32
+
33
+ # @!attribute content
34
+ # @return [String, nil] text content of the list item
35
+ attribute :content, :string
36
+
37
+ # @!attribute nested_list
38
+ # @return [ListBlock, nil] nested list within this item
39
+ # Note: Typed as string initially, retyped after ListBlock defined
40
+ attribute :nested_list, :string
41
+
42
+ private
43
+
44
+ # Attributes to compare for semantic equivalence
45
+ #
46
+ # List items are semantically equivalent if they have the same
47
+ # content, nested list, and children, regardless of the specific
48
+ # marker used.
49
+ #
50
+ # @return [Array<Symbol>] list of comparable attributes
51
+ def comparable_attributes
52
+ %i[content nested_list children]
53
+ end
54
+ end
55
+
56
+ # Represents a list block with proper nesting support
57
+ #
58
+ # Handles all list types:
59
+ # - Unordered lists
60
+ # - Ordered lists
61
+ # - Description lists
62
+ #
63
+ # Lists can contain nested lists at multiple levels, with each level
64
+ # tracked through marker_level.
65
+ #
66
+ # @example Creating an unordered list
67
+ # list = CoreModel::ListBlock.new(
68
+ # marker_type: "unordered",
69
+ # marker_level: 1,
70
+ # items: [
71
+ # ListItem.new(marker: "*", content: "First item"),
72
+ # ListItem.new(marker: "*", content: "Second item")
73
+ # ]
74
+ # )
75
+ #
76
+ # @example Creating a nested list
77
+ # nested = CoreModel::ListBlock.new(
78
+ # marker_type: "unordered",
79
+ # marker_level: 2,
80
+ # items: [ListItem.new(marker: "**", content: "Nested item")]
81
+ # )
82
+ # list = CoreModel::ListBlock.new(
83
+ # marker_type: "unordered",
84
+ # marker_level: 1,
85
+ # items: [
86
+ # ListItem.new(
87
+ # marker: "*",
88
+ # content: "Parent item",
89
+ # nested_list: nested
90
+ # )
91
+ # ]
92
+ # )
93
+ class ListBlock < Base
94
+ # @!attribute marker_type
95
+ # @return [String, nil] type of list marker
96
+ # (e.g., 'unordered', 'ordered', 'definition')
97
+ attribute :marker_type, :string
98
+
99
+ # @!attribute marker_level
100
+ # @return [Integer] nesting level of the list (default: 1)
101
+ attribute :marker_level, :integer, default: -> { 1 }
102
+
103
+ # @!attribute start
104
+ # @return [Integer, nil] starting number for ordered lists
105
+ attribute :start, :integer
106
+
107
+ # @!attribute items
108
+ # @return [Array<ListItem>] collection of list items
109
+ attribute :items, ListItem, collection: true
110
+
111
+ private
112
+
113
+ # Attributes to compare for semantic equivalence
114
+ #
115
+ # Lists are semantically equivalent if they have the same marker
116
+ # type and items, regardless of marker level (which is structural).
117
+ #
118
+ # @return [Array<Symbol>] list of comparable attributes
119
+ def comparable_attributes
120
+ super + %i[marker_type items]
121
+ end
122
+ end
123
+
124
+ # Re-open ListItem to properly type nested_list now that ListBlock
125
+ # is defined
126
+ class ListItem
127
+ # Remove the temporary string-typed attribute
128
+ remove_method :nested_list if method_defined?(:nested_list)
129
+ remove_method :nested_list= if method_defined?(:nested_list=)
130
+
131
+ # Re-define with proper ListBlock type
132
+ attribute :nested_list, ListBlock
133
+ end
134
+ end
135
+ end
@@ -0,0 +1,142 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module CoreModel
5
+ # Represents a list item
6
+ #
7
+ # List items can contain text content, nested lists, and attached blocks.
8
+ # They support various marker types and can have different nesting levels.
9
+ #
10
+ # @example Creating a simple list item
11
+ # item = ListItem.new(
12
+ # marker: "*",
13
+ # content: "First item"
14
+ # )
15
+ #
16
+ # @example Creating a list item with nested content
17
+ # item = ListItem.new(
18
+ # marker: "*",
19
+ # content: "Item with nested list",
20
+ # nested_list: nested_list_block,
21
+ # children: [attached_block]
22
+ # )
23
+ class ListItem < Base
24
+ attribute :children, Base, collection: true
25
+
26
+ include ChildrenContent
27
+
28
+ # @!attribute marker
29
+ # @return [String] the list marker (*, -, 1., etc.)
30
+ attribute :marker, :string
31
+
32
+ # @!attribute content
33
+ # @return [String] the text content of the list item
34
+ attribute :content, :string
35
+
36
+ # @!attribute children
37
+ # @return [Array] array of attached blocks/elements (mixed content, via ChildrenContent)
38
+
39
+ # Initialize with optional nested structure support
40
+ # @param args [Hash] initialization arguments
41
+ def initialize(args = {})
42
+ # Support :nested as alias for :nested_list
43
+ args[:nested_list] = args.delete(:nested) if args.key?(:nested)
44
+ super
45
+ end
46
+
47
+ # Delegate nested to nested_list (lutaml attribute added by list_block.rb)
48
+ def nested
49
+ nested_list
50
+ end
51
+
52
+ # Set nested list
53
+ # @param value [ListBlock, nil] nested list block
54
+ def nested=(value)
55
+ self.nested_list = value
56
+ end
57
+
58
+ # Convert to hash representation
59
+ #
60
+ # @return [Hash] hash representation of the list item
61
+ def to_h
62
+ {
63
+ marker: marker,
64
+ content: content,
65
+ nested_list: nested&.to_h,
66
+ children: children&.map { |child| child.is_a?(CoreModel::TextContent) ? { text: child.text } : child.to_h }
67
+ }.compact
68
+ end
69
+
70
+ # Create from hash
71
+ #
72
+ # @param hash [Hash] hash representation
73
+ # @return [ListItem] new list item instance
74
+ def self.from_h(hash)
75
+ raw_children = hash[:children] || []
76
+ children = raw_children.map do |child|
77
+ if child.is_a?(Hash) && child.key?(:text)
78
+ CoreModel::TextContent.new(text: child[:text])
79
+ elsif child.is_a?(CoreModel::Base)
80
+ child
81
+ end
82
+ end.compact
83
+
84
+ new(
85
+ marker: hash[:marker],
86
+ content: hash[:content],
87
+ nested: hash[:nested_list],
88
+ children: children
89
+ )
90
+ end
91
+
92
+ # Override semantic equivalence to handle nested structures properly
93
+ def semantically_equivalent?(other)
94
+ return false unless other.is_a?(self.class)
95
+ return false unless content == other.content
96
+
97
+ # Compare nested lists if present
98
+ if nested || other.nested
99
+ return false if nested.nil? != other.nested.nil?
100
+ return false if nested && !lists_equivalent?(nested, other.nested)
101
+ end
102
+
103
+ # Compare children if present
104
+ if children || other.children
105
+ return false if children.nil? != other.children.nil?
106
+ return false if children && !arrays_equivalent?(children, other.children)
107
+ end
108
+
109
+ true
110
+ end
111
+
112
+ private
113
+
114
+ # Compare two list blocks for equivalence
115
+ def lists_equivalent?(list1, list2)
116
+ # Both should be ListBlock objects or compatible
117
+ return true if list1 == list2
118
+ return false if list1.nil? || list2.nil?
119
+
120
+ # Check if both are ListBlock instances
121
+ if list1.is_a?(Coradoc::CoreModel::ListBlock) &&
122
+ list2.is_a?(Coradoc::CoreModel::ListBlock)
123
+ list1.semantically_equivalent?(list2)
124
+ elsif list1.instance_of?(::Coradoc::CoreModel::ListBlock) &&
125
+ list2.instance_of?(::Coradoc::CoreModel::ListBlock)
126
+ # Serialized by Lutaml - compare as objects
127
+ list1.marker_type == list2.marker_type &&
128
+ list1.items.to_a == list2.items.to_a
129
+ else
130
+ list1 == list2
131
+ end
132
+ end
133
+
134
+ # Compare two arrays for equivalence
135
+ def arrays_equivalent?(arr1, arr2)
136
+ return false unless arr1.size == arr2.size
137
+
138
+ arr1.zip(arr2).all? { |a, b| a == b }
139
+ end
140
+ end
141
+ end
142
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module CoreModel
5
+ # Listing block — a delimited block for listing/content without source language
6
+ #
7
+ # Distinct from SourceBlock: a listing has no language annotation.
8
+ # When a language is present, SourceBlock should be used instead.
9
+ class ListingBlock < Block
10
+ def self.semantic_type = :listing
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module CoreModel
5
+ # Literal block — a delimited block for preformatted literal text
6
+ class LiteralBlock < Block
7
+ def self.semantic_type = :literal
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,79 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module CoreModel
5
+ # A single metadata entry (key-value pair)
6
+ class MetadataEntry < Base
7
+ attribute :key, :string
8
+ attribute :value, :string
9
+ end
10
+
11
+ # Represents metadata associated with a document element
12
+ #
13
+ # Stores arbitrary key-value pairs for tracking source location,
14
+ # processing information, and other contextual data.
15
+ #
16
+ # @example
17
+ # meta = Metadata.new
18
+ # meta["source_line"] = 42
19
+ # meta["parser_version"] = "1.0.0"
20
+ class Metadata < Base
21
+ attribute :entries, MetadataEntry, collection: true
22
+
23
+ # Get a metadata value by key
24
+ # @param key [String] The metadata key
25
+ # @return [String, nil] The value or nil if not found
26
+ def [](key)
27
+ return nil if entries.nil?
28
+
29
+ find_entry(key)&.value
30
+ end
31
+
32
+ # Set a metadata value
33
+ # @param key [String] The metadata key
34
+ # @param value [String] The value to set
35
+ def []=(key, value)
36
+ self.entries ||= []
37
+ existing = find_entry(key)
38
+ if existing
39
+ existing.value = value
40
+ else
41
+ entries << MetadataEntry.new(key: key, value: value)
42
+ end
43
+ end
44
+
45
+ # Check if a key exists
46
+ # @param key [String] The key to check
47
+ # @return [Boolean] True if key exists
48
+ def key?(key)
49
+ return false if entries.nil?
50
+
51
+ !find_entry(key).nil?
52
+ end
53
+
54
+ # Get all keys
55
+ # @return [Array<String>] List of keys
56
+ def keys
57
+ return [] if entries.nil?
58
+
59
+ entries.map(&:key)
60
+ end
61
+
62
+ # Convert to hash representation
63
+ # @return [Hash] Hash of all metadata entries
64
+ def to_h
65
+ return {} if entries.nil?
66
+
67
+ entries.each_with_object({}) { |entry, hash| hash[entry.key] = entry.value }
68
+ end
69
+
70
+ private
71
+
72
+ def find_entry(key)
73
+ return nil if entries.nil?
74
+
75
+ entries.find { |e| e.key == key }
76
+ end
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module CoreModel
5
+ # Open block — a generic container block with no special rendering
6
+ class OpenBlock < Block
7
+ def self.semantic_type = :open
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module CoreModel
5
+ # Paragraph block — a block of prose text
6
+ class ParagraphBlock < Block
7
+ def self.semantic_type = :paragraph
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module CoreModel
5
+ # Pass-through block — raw content passed through without processing
6
+ class PassBlock < Block
7
+ def self.semantic_type = :pass
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module CoreModel
5
+ # Quote block — a delimited block for quotations
6
+ class QuoteBlock < Block
7
+ def self.semantic_type = :quote
8
+
9
+ attribute :attribution, :string
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module CoreModel
5
+ # Reviewer comment block — a block for reviewer annotations
6
+ class ReviewerBlock < AnnotationBlock
7
+ def self.semantic_type = :reviewer
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module CoreModel
5
+ # Sidebar block — a delimited block for sidebars
6
+ class SidebarBlock < Block
7
+ def self.semantic_type = :sidebar
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module CoreModel
5
+ # Specialized block for source code listings
6
+ class SourceBlock < Block
7
+ def self.semantic_type = :source_code
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,94 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module CoreModel
5
+ # Base class for structural elements
6
+ #
7
+ # Represents document structure elements that organize content.
8
+ # Typed subclasses (SectionElement, DocumentElement, etc.) express
9
+ # their role via the class hierarchy — the class IS the type.
10
+ #
11
+ # Structural elements can contain other elements (blocks, lists, etc.)
12
+ # and can be nested hierarchically to represent document structure.
13
+ class StructuralElement < Base
14
+ # @!attribute level
15
+ # @return [Integer, nil] hierarchical level (1-6 for sections)
16
+ attribute :level, :integer
17
+
18
+ # @!attribute content
19
+ # @return [String, nil] text content of the element
20
+ attribute :content, :string
21
+
22
+ # @!attribute children
23
+ # @return [Array<Base>, nil] child elements (sections, blocks, etc.)
24
+ attribute :children, Base, collection: true
25
+
26
+ # @!attribute attributes
27
+ # @return [Metadata, nil] document-level attributes (typed key-value pairs)
28
+ attribute :attributes, Metadata
29
+
30
+ def heading_level
31
+ level || 1
32
+ end
33
+
34
+ def section? = false
35
+ def document? = false
36
+ def preamble? = false
37
+ def header? = false
38
+
39
+ # Derived element_type string for backward compatibility with
40
+ # templates and legacy consumers. Subclasses override this.
41
+ def element_type
42
+ self.class.element_type_name
43
+ end
44
+
45
+ class << self
46
+ def element_type_name
47
+ nil
48
+ end
49
+ end
50
+
51
+ private
52
+
53
+ def comparable_attributes
54
+ [:title] + %i[level children]
55
+ end
56
+ end
57
+
58
+ # Root document element
59
+ class DocumentElement < StructuralElement
60
+ def document? = true
61
+
62
+ class << self
63
+ def element_type_name = 'document'
64
+ end
65
+ end
66
+
67
+ # Section with a heading at a specific level
68
+ class SectionElement < StructuralElement
69
+ def section? = true
70
+
71
+ class << self
72
+ def element_type_name = 'section'
73
+ end
74
+ end
75
+
76
+ # Preamble content before the first section heading
77
+ class PreambleElement < StructuralElement
78
+ def preamble? = true
79
+
80
+ class << self
81
+ def element_type_name = 'preamble'
82
+ end
83
+ end
84
+
85
+ # Header / title block of a document
86
+ class HeaderElement < StructuralElement
87
+ def header? = true
88
+
89
+ class << self
90
+ def element_type_name = 'header'
91
+ end
92
+ end
93
+ end
94
+ end