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,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module CoreModel
5
+ # Bibliography section in a document.
6
+ #
7
+ # Bibliography sections contain lists of references cited in the document.
8
+ #
9
+ # @!attribute [r] id
10
+ # @return [String, nil] Optional identifier for the bibliography
11
+ #
12
+ # @!attribute [r] title
13
+ # @return [String, nil] Bibliography section title
14
+ #
15
+ # @!attribute [r] level
16
+ # @return [Integer, nil] Section level
17
+ #
18
+ # @!attribute [r] entries
19
+ # @return [Array<Coradoc::CoreModel::BibliographyEntry>] Bibliography entries
20
+ #
21
+ # @example Create a bibliography section
22
+ # bib = Coradoc::CoreModel::Bibliography.new(
23
+ # id: "norm-refs",
24
+ # title: "Normative references",
25
+ # entries: [
26
+ # Coradoc::CoreModel::BibliographyEntry.new(
27
+ # anchor_name: "ISO712",
28
+ # document_id: "ISO 712",
29
+ # ref_text: "Cereals and cereal products..."
30
+ # )
31
+ # ]
32
+ # )
33
+ #
34
+ class Bibliography < Base
35
+ attribute :id, :string
36
+ attribute :title, :string
37
+ attribute :level, :integer
38
+ attribute :entries, Coradoc::CoreModel::BibliographyEntry, collection: true
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module CoreModel
5
+ # Individual bibliography entry (reference).
6
+ #
7
+ # Bibliography entries represent single references within a bibliography,
8
+ # with anchor names for citation linking.
9
+ #
10
+ # @!attribute [r] anchor_name
11
+ # @return [String, nil] The anchor name for citing this entry (e.g., "ISO712")
12
+ #
13
+ # @!attribute [r] document_id
14
+ # @return [String, nil] The document identifier (e.g., "ISO 712")
15
+ #
16
+ # @!attribute [r] ref_text
17
+ # @return [String, nil] The reference text/citation description
18
+ #
19
+ # @!attribute [r] url
20
+ # @return [String, nil] Optional URL for the reference
21
+ #
22
+ # @example Create a bibliography entry
23
+ # entry = Coradoc::CoreModel::BibliographyEntry.new(
24
+ # anchor_name: "ISO712",
25
+ # document_id: "ISO 712",
26
+ # ref_text: "Cereals and cereal products. Determination of moisture content."
27
+ # )
28
+ #
29
+ class BibliographyEntry < Base
30
+ attribute :anchor_name, :string
31
+ attribute :document_id, :string
32
+ attribute :ref_text, :string
33
+ attribute :url, :string
34
+
35
+ # Returns a formatted display string combining label and reference text.
36
+ #
37
+ # Uses document_id or anchor_name as the label, falling back to ref_text
38
+ # alone when no label is available.
39
+ #
40
+ # @return [String] formatted citation text
41
+ def display_text
42
+ label = document_id || anchor_name || ''
43
+ ref = ref_text || ''
44
+ label.empty? ? ref : "#{label}: #{ref}"
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module CoreModel
5
+ # Generic block model
6
+ #
7
+ # Represents all block-level elements in a format-neutral way.
8
+ # Typed subclasses (SourceBlock, QuoteBlock, etc.) express their
9
+ # semantic identity via the class hierarchy — the class IS the type.
10
+ # Generic Block instances use block_semantic_type for typing.
11
+ class Block < Base
12
+ attribute :children, Base, collection: true
13
+
14
+ include ChildrenContent
15
+
16
+ class << self
17
+ def semantic_type
18
+ nil
19
+ end
20
+ end
21
+
22
+ def resolve_semantic_type
23
+ self.class.semantic_type || block_semantic_type&.to_sym
24
+ end
25
+
26
+ # Derived element_type string for backward compatibility.
27
+ # Returns the semantic type as a string, derived from the class
28
+ # or block_semantic_type.
29
+ def element_type
30
+ resolve_semantic_type&.to_s
31
+ end
32
+
33
+ # @!attribute block_semantic_type
34
+ # @return [String, nil] semantic type for generic Block instances.
35
+ # Typed subclasses should not override this — use the class instead.
36
+ attribute :block_semantic_type, :string
37
+
38
+ # @!attribute delimiter_type
39
+ # @return [String, nil] raw delimiter for round-trip fidelity.
40
+ # Format-specific; CoreModel does NOT derive semantics from this.
41
+ attribute :delimiter_type, :string
42
+
43
+ # @!attribute content
44
+ # @return [String, nil] the block's text content (simple string)
45
+ # For mixed content with inline elements, use children instead.
46
+ attribute :content, :string
47
+
48
+ # @!attribute lines
49
+ # @return [Array<String>, nil] individual lines of content
50
+ attribute :lines, :string, collection: true
51
+
52
+ # @!attribute language
53
+ # @return [String, nil] language identifier for source code blocks
54
+ attribute :language, :string
55
+
56
+ private
57
+
58
+ def comparable_attributes
59
+ super + %i[block_semantic_type content]
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module CoreModel
5
+ # Shared helpers for models that carry mixed-content children
6
+ # (TextContent + InlineElement + Block instances) alongside a string
7
+ # content attribute.
8
+ #
9
+ # Included by Block, ListItem, TableCell, and InlineElement.
10
+ # The children attribute is declared as
11
+ # attribute :children, Base, collection: true
12
+ # on each including class. This module overrides the setter to
13
+ # auto-wrap raw strings as TextContent, keeping all callers simple.
14
+ module ChildrenContent
15
+ # Override the children= setter to auto-wrap strings as TextContent.
16
+ # This is defined via define_method so it always overrides the
17
+ # lutaml-generated setter, regardless of include order.
18
+ def self.included(base)
19
+ super
20
+
21
+ base.define_method(:children=) do |value|
22
+ wrapped = Array(value).map do |item|
23
+ next nil if item.nil?
24
+ next item if item.is_a?(CoreModel::Base)
25
+
26
+ CoreModel::TextContent.new(text: item.to_s)
27
+ end.compact
28
+ instance_variable_set(:@children, wrapped)
29
+ end
30
+ end
31
+
32
+ # Get content for rendering, preferring children over content.
33
+ # When children are all TextContent (plain text), use the content
34
+ # attribute instead since it already has proper spacing between lines.
35
+ def renderable_content
36
+ return content if children.nil? || children.none?
37
+ return content if content && children.all?(TextContent)
38
+
39
+ children
40
+ end
41
+
42
+ # Flatten renderable_content to a single plain-text string.
43
+ def flat_text
44
+ rc = renderable_content
45
+ case rc
46
+ when String then rc
47
+ when Array then rc.map { |c| c.is_a?(TextContent) ? c.text : c.content.to_s }.join
48
+ else rc.to_s
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module CoreModel
5
+ # Comment block — editorial or hidden comments
6
+ class CommentBlock < Block
7
+ def self.semantic_type = :comment
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module CoreModel
5
+ class DefinitionItem < Base
6
+ attribute :term, :string
7
+ attribute :definitions, :string, collection: true
8
+
9
+ def initialize(args = {})
10
+ @term_children = args.delete(:term_children) || []
11
+ @definition_children = args.delete(:definition_children) || []
12
+ super(args)
13
+ end
14
+
15
+ attr_reader :term_children, :definition_children
16
+
17
+ def term_children=(value)
18
+ @term_children = value || []
19
+ end
20
+
21
+ def definition_children=(value)
22
+ @definition_children = value || []
23
+ end
24
+
25
+ def term_renderable
26
+ return term if term_children.nil? || term_children.none?
27
+ return term if term && term_children.all?(String)
28
+
29
+ term_children
30
+ end
31
+
32
+ def definition_renderable
33
+ return definitions if definition_children.nil? || definition_children.none?
34
+ return definitions if definition_children.all?(String)
35
+
36
+ definition_children
37
+ end
38
+
39
+ private
40
+
41
+ def comparable_attributes
42
+ super + %i[term definitions term_children definition_children]
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module CoreModel
5
+ # Represents a definition list
6
+ #
7
+ # DefinitionList contains terms and their definitions.
8
+ #
9
+ # @example Creating a definition list
10
+ # list = CoreModel::DefinitionList.new(
11
+ # items: [
12
+ # DefinitionItem.new(term: "API", definitions: ["Application Programming Interface"]),
13
+ # DefinitionItem.new(term: "REST", definitions: ["Representational State Transfer"])
14
+ # ]
15
+ # )
16
+ class DefinitionList < Base
17
+ # @!attribute items
18
+ # @return [Array<DefinitionItem>] the definition items
19
+ attribute :items, DefinitionItem, collection: true
20
+
21
+ private
22
+
23
+ def comparable_attributes
24
+ super + %i[items]
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module CoreModel
5
+ # Represents a single attribute (key-value pair) on an element
6
+ #
7
+ # @example
8
+ # attr = ElementAttribute.new(name: "role", value: "note")
9
+ class ElementAttribute < Base
10
+ attribute :name, :string
11
+ attribute :value, :string
12
+
13
+ # Convert to hash representation
14
+ # @return [Hash] Single key-value pair
15
+ def to_h
16
+ { name => value }
17
+ end
18
+
19
+ # Convert to string representation (e.g., for serialization)
20
+ # @return [String] Attribute in name="value" format
21
+ def to_s
22
+ %("#{name}="#{value}"")
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module CoreModel
5
+ # Example block — a delimited block for examples
6
+ class ExampleBlock < Block
7
+ def self.semantic_type = :example
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,92 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module CoreModel
5
+ # Represents a footnote definition in a document
6
+ #
7
+ # Footnotes are used for auxiliary information, citations, or
8
+ # explanatory notes that appear at the bottom of a page or
9
+ # end of a document.
10
+ #
11
+ # @example Creating a simple footnote
12
+ # footnote = CoreModel::Footnote.new(
13
+ # id: "fn1",
14
+ # content: "This is a footnote explanation."
15
+ # )
16
+ #
17
+ # @example Creating a footnote with backlink
18
+ # footnote = CoreModel::Footnote.new(
19
+ # id: "cite1",
20
+ # content: "Smith, J. (2024). The Reference.",
21
+ # backlink: true
22
+ # )
23
+ class Footnote < Base
24
+ # @!attribute id
25
+ # @return [String, nil] the footnote identifier (e.g., "1", "fn1")
26
+ attribute :id, :string
27
+
28
+ # @!attribute content
29
+ # @return [String, nil] the footnote content
30
+ attribute :content, :string
31
+
32
+ # @!attribute inline_content
33
+ # @return [Array<String>, nil] inline content elements
34
+ attribute :inline_content, :string, collection: true
35
+
36
+ # @!attribute backlink
37
+ # @return [Boolean] whether to include backlink to reference
38
+ attribute :backlink, :boolean, default: -> { true }
39
+
40
+ private
41
+
42
+ def comparable_attributes
43
+ super + %i[id content backlink]
44
+ end
45
+ end
46
+
47
+ # Represents an inline footnote reference
48
+ #
49
+ # FootnoteReference links to a Footnote definition within document text.
50
+ #
51
+ # @example Creating a footnote reference
52
+ # ref = CoreModel::FootnoteReference.new(id: "fn1")
53
+ # # Renders as: [^fn1] in Markdown, <sup>1</sup> in HTML
54
+ class FootnoteReference < Base
55
+ # @!attribute id
56
+ # @return [String, nil] the footnote identifier being referenced
57
+ attribute :id, :string
58
+
59
+ private
60
+
61
+ def comparable_attributes
62
+ super + %i[id]
63
+ end
64
+ end
65
+
66
+ # Represents an abbreviation definition in a document
67
+ #
68
+ # Abbreviations define the expansion of shortened terms.
69
+ # They are typically rendered with the full definition on first use.
70
+ #
71
+ # @example Creating an abbreviation
72
+ # abbr = CoreModel::Abbreviation.new(
73
+ # term: "API",
74
+ # definition: "Application Programming Interface"
75
+ # )
76
+ class Abbreviation < Base
77
+ # @!attribute term
78
+ # @return [String, nil] the abbreviated term
79
+ attribute :term, :string
80
+
81
+ # @!attribute definition
82
+ # @return [String, nil] the full definition/expansion
83
+ attribute :definition, :string
84
+
85
+ private
86
+
87
+ def comparable_attributes
88
+ super + %i[term definition]
89
+ end
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module CoreModel
5
+ # Horizontal rule — a thematic break between sections
6
+ class HorizontalRuleBlock < Block
7
+ def self.semantic_type = :horizontal_rule
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module CoreModel
5
+ module IdGenerator
6
+ def self.generate_from_title(title)
7
+ return nil if title.nil? || title.to_s.strip.empty?
8
+
9
+ '_' + title.to_s.downcase
10
+ .gsub(/[^a-z0-9\s]/, '')
11
+ .gsub(/\s+/, '_')
12
+ .gsub(/^_+|_+$/, '')
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module CoreModel
5
+ # Represents an image in a document
6
+ #
7
+ # Images can be block-level (standalone) or inline. They support
8
+ # various attributes like alt text, dimensions, and linking.
9
+ #
10
+ # @example Creating a block image
11
+ # image = CoreModel::Image.new(
12
+ # src: "images/diagram.png",
13
+ # alt: "System Architecture",
14
+ # caption: "Figure 1: System Overview",
15
+ # width: "800px"
16
+ # )
17
+ #
18
+ # @example Creating an inline image
19
+ # icon = CoreModel::Image.new(
20
+ # src: "icons/warning.png",
21
+ # alt: "Warning",
22
+ # inline: true
23
+ # )
24
+ class Image < Base
25
+ # @!attribute src
26
+ # @return [String, nil] source URL or path to the image
27
+ attribute :src, :string
28
+
29
+ # @!attribute alt
30
+ # @return [String, nil] alternative text for accessibility
31
+ attribute :alt, :string
32
+
33
+ # @!attribute caption
34
+ # @return [String, nil] caption text for the image
35
+ attribute :caption, :string
36
+
37
+ # @!attribute width
38
+ # @return [String, nil] image width (e.g., '100%', '500px')
39
+ attribute :width, :string
40
+
41
+ # @!attribute height
42
+ # @return [String, nil] image height (e.g., '300px', 'auto')
43
+ attribute :height, :string
44
+
45
+ # @!attribute link
46
+ # @return [String, nil] URL to link to when image is clicked
47
+ # @note Not yet wired by any transformer; reserved for future use
48
+ attribute :link, :string
49
+
50
+ # @!attribute inline
51
+ # @return [Boolean] whether this is an inline image
52
+ attribute :inline, :boolean, default: -> { false }
53
+
54
+ # @!attribute float
55
+ # @return [String, nil] float position ('left', 'right')
56
+ # @note Not yet wired by any transformer; reserved for future use
57
+ attribute :float, :string
58
+
59
+ private
60
+
61
+ def comparable_attributes
62
+ super + %i[src alt caption width height link inline]
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,140 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module CoreModel
5
+ # Generic inline formatting element
6
+ #
7
+ # Typed subclasses (BoldElement, ItalicElement, etc.) express their
8
+ # format identity via the class hierarchy — the class IS the format type.
9
+ # Generic InlineElement instances use the format_type attribute for typing.
10
+ class InlineElement < Base
11
+ attribute :children, Base, collection: true
12
+
13
+ include ChildrenContent
14
+
15
+ class << self
16
+ def format_type
17
+ nil
18
+ end
19
+
20
+ def format_type_class(type)
21
+ FORMAT_TYPE_CLASS_MAP[type] || InlineElement
22
+ end
23
+ end
24
+
25
+ def resolve_format_type
26
+ self.class.format_type || format_type
27
+ end
28
+
29
+ FORMAT_TYPES = %w[
30
+ bold italic monospace underline strikethrough
31
+ subscript superscript highlight
32
+ link xref stem footnote
33
+ hard_line_break text span term
34
+ line_break quotation
35
+ ].freeze
36
+
37
+ attribute :format_type, :string
38
+ attribute :content, :string
39
+ attribute :nested_elements, InlineElement, collection: true
40
+ attribute :target, :string
41
+ attribute :stem_type, :string
42
+
43
+ private
44
+
45
+ def comparable_attributes
46
+ %i[format_type content nested_elements stem_type]
47
+ end
48
+ end
49
+
50
+ # Typed InlineElement subclasses
51
+
52
+ class BoldElement < InlineElement
53
+ def self.format_type = 'bold'
54
+ end
55
+
56
+ class ItalicElement < InlineElement
57
+ def self.format_type = 'italic'
58
+ end
59
+
60
+ class MonospaceElement < InlineElement
61
+ def self.format_type = 'monospace'
62
+ end
63
+
64
+ class UnderlineElement < InlineElement
65
+ def self.format_type = 'underline'
66
+ end
67
+
68
+ class StrikethroughElement < InlineElement
69
+ def self.format_type = 'strikethrough'
70
+ end
71
+
72
+ class SubscriptElement < InlineElement
73
+ def self.format_type = 'subscript'
74
+ end
75
+
76
+ class SuperscriptElement < InlineElement
77
+ def self.format_type = 'superscript'
78
+ end
79
+
80
+ class HighlightElement < InlineElement
81
+ def self.format_type = 'highlight'
82
+ end
83
+
84
+ class LinkElement < InlineElement
85
+ def self.format_type = 'link'
86
+ end
87
+
88
+ class CrossReferenceElement < InlineElement
89
+ def self.format_type = 'xref'
90
+ end
91
+
92
+ class StemElement < InlineElement
93
+ def self.format_type = 'stem'
94
+ end
95
+
96
+ class FootnoteElement < InlineElement
97
+ def self.format_type = 'footnote'
98
+ end
99
+
100
+ class HardLineBreakElement < InlineElement
101
+ def self.format_type = 'hard_line_break'
102
+ end
103
+
104
+ class TextElement < InlineElement
105
+ def self.format_type = 'text'
106
+ end
107
+
108
+ class SpanElement < InlineElement
109
+ def self.format_type = 'span'
110
+ end
111
+
112
+ class TermElement < InlineElement
113
+ def self.format_type = 'term'
114
+ end
115
+
116
+ class LineBreakElement < InlineElement
117
+ def self.format_type = 'line_break'
118
+ end
119
+
120
+ FORMAT_TYPE_CLASS_MAP = {
121
+ 'bold' => BoldElement,
122
+ 'italic' => ItalicElement,
123
+ 'monospace' => MonospaceElement,
124
+ 'underline' => UnderlineElement,
125
+ 'strikethrough' => StrikethroughElement,
126
+ 'subscript' => SubscriptElement,
127
+ 'superscript' => SuperscriptElement,
128
+ 'highlight' => HighlightElement,
129
+ 'link' => LinkElement,
130
+ 'xref' => CrossReferenceElement,
131
+ 'stem' => StemElement,
132
+ 'footnote' => FootnoteElement,
133
+ 'hard_line_break' => HardLineBreakElement,
134
+ 'text' => TextElement,
135
+ 'span' => SpanElement,
136
+ 'term' => TermElement,
137
+ 'line_break' => LineBreakElement
138
+ }.freeze
139
+ end
140
+ end