coradoc 1.1.7 → 2.0.15

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 +205 -91
  6. data/lib/coradoc/configurable.rb +527 -0
  7. data/lib/coradoc/coradoc.rb +467 -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 +12 -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 +12 -0
  19. data/lib/coradoc/core_model/footnote.rb +92 -0
  20. data/lib/coradoc/core_model/horizontal_rule_block.rb +12 -0
  21. data/lib/coradoc/core_model/id_generator.rb +20 -0
  22. data/lib/coradoc/core_model/image.rb +66 -0
  23. data/lib/coradoc/core_model/inline_element.rb +172 -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 +15 -0
  27. data/lib/coradoc/core_model/literal_block.rb +12 -0
  28. data/lib/coradoc/core_model/metadata.rb +79 -0
  29. data/lib/coradoc/core_model/open_block.rb +12 -0
  30. data/lib/coradoc/core_model/paragraph_block.rb +12 -0
  31. data/lib/coradoc/core_model/pass_block.rb +12 -0
  32. data/lib/coradoc/core_model/quote_block.rb +14 -0
  33. data/lib/coradoc/core_model/reviewer_block.rb +12 -0
  34. data/lib/coradoc/core_model/sidebar_block.rb +12 -0
  35. data/lib/coradoc/core_model/source_block.rb +12 -0
  36. data/lib/coradoc/core_model/structural_element.rb +111 -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 +14 -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 +60 -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 +69 -282
  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 -37
  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,12 @@
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
8
+ :comment
9
+ end
10
+ end
11
+ end
12
+ 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,12 @@
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
8
+ :example
9
+ end
10
+ end
11
+ end
12
+ 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,12 @@
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
8
+ :horizontal_rule
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module CoreModel
5
+ module IdGenerator
6
+ def self.generate_from_title(title, parent_id: nil)
7
+ return nil if title.nil? || title.to_s.strip.empty?
8
+
9
+ suffix = title.to_s.downcase
10
+ .gsub(/[^a-z0-9\s]/, '')
11
+ .gsub(/\s+/, '_')
12
+ .gsub(/^_+|_+$/, '')
13
+
14
+ return "_#{suffix}" if parent_id.nil? || parent_id.to_s.strip.empty?
15
+
16
+ "#{parent_id}_#{suffix}"
17
+ end
18
+ end
19
+ end
20
+ 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,172 @@
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
+ def self.format_type
16
+ nil
17
+ end
18
+
19
+ def self.format_type_class(type)
20
+ FORMAT_TYPE_CLASS_MAP[type] || InlineElement
21
+ end
22
+
23
+ def resolve_format_type
24
+ self.class.format_type || format_type
25
+ end
26
+
27
+ FORMAT_TYPES = %w[
28
+ bold italic monospace underline strikethrough
29
+ subscript superscript highlight
30
+ link xref stem footnote
31
+ hard_line_break text span term
32
+ line_break quotation
33
+ ].freeze
34
+
35
+ attribute :format_type, :string
36
+ attribute :content, :string
37
+ attribute :nested_elements, InlineElement, collection: true
38
+ attribute :target, :string
39
+ attribute :stem_type, :string
40
+
41
+ private
42
+
43
+ def comparable_attributes
44
+ %i[format_type content nested_elements stem_type]
45
+ end
46
+ end
47
+
48
+ # Typed InlineElement subclasses
49
+
50
+ class BoldElement < InlineElement
51
+ def self.format_type
52
+ 'bold'
53
+ end
54
+ end
55
+
56
+ class ItalicElement < InlineElement
57
+ def self.format_type
58
+ 'italic'
59
+ end
60
+ end
61
+
62
+ class MonospaceElement < InlineElement
63
+ def self.format_type
64
+ 'monospace'
65
+ end
66
+ end
67
+
68
+ class UnderlineElement < InlineElement
69
+ def self.format_type
70
+ 'underline'
71
+ end
72
+ end
73
+
74
+ class StrikethroughElement < InlineElement
75
+ def self.format_type
76
+ 'strikethrough'
77
+ end
78
+ end
79
+
80
+ class SubscriptElement < InlineElement
81
+ def self.format_type
82
+ 'subscript'
83
+ end
84
+ end
85
+
86
+ class SuperscriptElement < InlineElement
87
+ def self.format_type
88
+ 'superscript'
89
+ end
90
+ end
91
+
92
+ class HighlightElement < InlineElement
93
+ def self.format_type
94
+ 'highlight'
95
+ end
96
+ end
97
+
98
+ class LinkElement < InlineElement
99
+ def self.format_type
100
+ 'link'
101
+ end
102
+ end
103
+
104
+ class CrossReferenceElement < InlineElement
105
+ def self.format_type
106
+ 'xref'
107
+ end
108
+ end
109
+
110
+ class StemElement < InlineElement
111
+ def self.format_type
112
+ 'stem'
113
+ end
114
+ end
115
+
116
+ class FootnoteElement < InlineElement
117
+ def self.format_type
118
+ 'footnote'
119
+ end
120
+ end
121
+
122
+ class HardLineBreakElement < InlineElement
123
+ def self.format_type
124
+ 'hard_line_break'
125
+ end
126
+ end
127
+
128
+ class TextElement < InlineElement
129
+ def self.format_type
130
+ 'text'
131
+ end
132
+ end
133
+
134
+ class SpanElement < InlineElement
135
+ def self.format_type
136
+ 'span'
137
+ end
138
+ end
139
+
140
+ class TermElement < InlineElement
141
+ def self.format_type
142
+ 'term'
143
+ end
144
+ end
145
+
146
+ class LineBreakElement < InlineElement
147
+ def self.format_type
148
+ 'line_break'
149
+ end
150
+ end
151
+
152
+ FORMAT_TYPE_CLASS_MAP = {
153
+ 'bold' => BoldElement,
154
+ 'italic' => ItalicElement,
155
+ 'monospace' => MonospaceElement,
156
+ 'underline' => UnderlineElement,
157
+ 'strikethrough' => StrikethroughElement,
158
+ 'subscript' => SubscriptElement,
159
+ 'superscript' => SuperscriptElement,
160
+ 'highlight' => HighlightElement,
161
+ 'link' => LinkElement,
162
+ 'xref' => CrossReferenceElement,
163
+ 'stem' => StemElement,
164
+ 'footnote' => FootnoteElement,
165
+ 'hard_line_break' => HardLineBreakElement,
166
+ 'text' => TextElement,
167
+ 'span' => SpanElement,
168
+ 'term' => TermElement,
169
+ 'line_break' => LineBreakElement
170
+ }.freeze
171
+ end
172
+ end