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.

Potentially problematic release.


This version of coradoc might be problematic. Click here for more details.

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,148 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module CoreModel
5
+ # Represents a table cell in a document
6
+ #
7
+ # Table cells can contain text content and have various formatting
8
+ # attributes like alignment, colspan, rowspan, and styling.
9
+ #
10
+ # Cell format specification: [colspan][.rowspan][halign][valign][style][*]
11
+ #
12
+ # @example Creating a table cell with full formatting
13
+ # cell = CoreModel::TableCell.new(
14
+ # content: "Cell content",
15
+ # alignment: "center",
16
+ # colspan: 2,
17
+ # rowspan: 3,
18
+ # style: "emphasis",
19
+ # bgcolor: "#ffff00"
20
+ # )
21
+ class TableCell < Base
22
+ attribute :children, Base, collection: true
23
+
24
+ include ChildrenContent
25
+
26
+ # @!attribute content
27
+ # @return [String, nil] text content of the cell
28
+ attribute :content, :string
29
+
30
+ # @!attribute alignment
31
+ # @return [String, nil] horizontal text alignment ('left', 'center', 'right')
32
+ attribute :alignment, :string
33
+
34
+ # @!attribute vertical_alignment
35
+ # @return [String, nil] vertical alignment ('top', 'middle', 'bottom')
36
+ attribute :vertical_alignment, :string
37
+
38
+ # @!attribute colspan
39
+ # @return [Integer, nil] number of columns to span
40
+ attribute :colspan, :integer
41
+
42
+ # @!attribute rowspan
43
+ # @return [Integer, nil] number of rows to span
44
+ attribute :rowspan, :integer
45
+
46
+ # @!attribute header
47
+ # @return [Boolean] whether this is a header cell
48
+ attribute :header, :boolean, default: -> { false }
49
+
50
+ # @!attribute style
51
+ # @return [String, nil] cell style ('default', 'strong', 'emphasis', 'monospace',
52
+ # 'asciidoc', 'literal', 'verse')
53
+ attribute :style, :string
54
+
55
+ private
56
+
57
+ def comparable_attributes
58
+ %i[content alignment vertical_alignment colspan rowspan header style]
59
+ end
60
+ end
61
+
62
+ # Represents a row in a table
63
+ #
64
+ # A table row contains multiple cells and can be a header row
65
+ # or a data row.
66
+ #
67
+ # @example Creating a table row
68
+ # row = CoreModel::TableRow.new(
69
+ # cells: [
70
+ # CoreModel::TableCell.new(content: "Name"),
71
+ # CoreModel::TableCell.new(content: "Value")
72
+ # ],
73
+ # header: true
74
+ # )
75
+ class TableRow < Base
76
+ # @!attribute cells
77
+ # @return [Array<TableCell>] collection of cells in the row
78
+ attribute :cells, TableCell, collection: true
79
+
80
+ # @!attribute header
81
+ # @return [Boolean] whether this is a header row
82
+ attribute :header, :boolean, default: -> { false }
83
+
84
+ private
85
+
86
+ def comparable_attributes
87
+ %i[cells header]
88
+ end
89
+ end
90
+
91
+ # Represents a table in a document
92
+ #
93
+ # Tables contain rows of cells and support various formatting options
94
+ # like frame, grid, column widths, and styling.
95
+ #
96
+ # @example Creating a simple table
97
+ # table = CoreModel::Table.new(
98
+ # title: "Data Table",
99
+ # rows: [
100
+ # CoreModel::TableRow.new(
101
+ # cells: [
102
+ # CoreModel::TableCell.new(content: "Header 1", header: true),
103
+ # CoreModel::TableCell.new(content: "Header 2", header: true)
104
+ # ],
105
+ # header: true
106
+ # ),
107
+ # CoreModel::TableRow.new(
108
+ # cells: [
109
+ # CoreModel::TableCell.new(content: "Cell 1"),
110
+ # CoreModel::TableCell.new(content: "Cell 2")
111
+ # ]
112
+ # )
113
+ # ]
114
+ # )
115
+ #
116
+ # @example Creating a table with column specifications
117
+ # table = CoreModel::Table.new(
118
+ # cols: ["1", "2", "3"], # relative widths
119
+ # col_alignments: ["left", "center", "right"],
120
+ # col_styles: [nil, "emphasis", "monospace"],
121
+ # rows: [...]
122
+ # )
123
+ class Table < Base
124
+ # @!attribute rows
125
+ # @return [Array<TableRow>] collection of table rows
126
+ attribute :rows, TableRow, collection: true
127
+
128
+ # @!attribute grid
129
+ # @return [String, nil] table grid style ('all', 'cols', 'rows', 'none')
130
+ # @note Not yet wired by any transformer; reserved for future use
131
+ attribute :grid, :string
132
+
133
+ # @!attribute width
134
+ # @return [String, nil] table width (e.g., '100%', '500px')
135
+ attribute :width, :string
136
+
137
+ # @!attribute cols
138
+ # @return [Array<String>, nil] column width specifications (e.g., ["1", "2", "3"])
139
+ attribute :cols, :string, collection: true
140
+
141
+ private
142
+
143
+ def comparable_attributes
144
+ super + %i[rows grid width cols]
145
+ end
146
+ end
147
+ end
148
+ end
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module CoreModel
5
+ # Represents a definition term in a document
6
+ #
7
+ # Terms are used in definition lists, glossaries, and terminology
8
+ # sections. They can have various types (acronym, symbol, preferred, etc.)
9
+ # and support multi-language content.
10
+ #
11
+ # @example Creating a simple term
12
+ # term = CoreModel::Term.new(
13
+ # text: "API",
14
+ # type: "acronym",
15
+ # definition: "Application Programming Interface"
16
+ # )
17
+ #
18
+ # @example Creating a multi-language term
19
+ # term = CoreModel::Term.new(
20
+ # text: "computer",
21
+ # type: "preferred",
22
+ # lang: "en",
23
+ # definition: "An electronic device for processing data"
24
+ # )
25
+ class Term < Base
26
+ # @!attribute text
27
+ # @return [String, nil] the term text
28
+ attribute :text, :string
29
+
30
+ # @!attribute type
31
+ # @return [String, nil] term type ('acronym', 'symbol', 'preferred', 'admitted', 'deprecated')
32
+ attribute :type, :string
33
+
34
+ # @!attribute lang
35
+ # @return [String] language code (default: 'en')
36
+ attribute :lang, :string, default: -> { 'en' }
37
+
38
+ # @!attribute definition
39
+ # @return [String, nil] definition of the term
40
+ attribute :definition, :string
41
+
42
+ # @!attribute source
43
+ # @return [String, nil] source reference for the term
44
+ attribute :source, :string
45
+
46
+ private
47
+
48
+ def comparable_attributes
49
+ super + %i[text type lang definition]
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module CoreModel
5
+ # Wrapper for plain-text strings in mixed-content children arrays.
6
+ #
7
+ # Enables every child in a children collection to be a typed Base
8
+ # instance, so that children can be declared as
9
+ # attribute :children, Base, collection: true
10
+ # matching StructuralElement's proven pattern.
11
+ #
12
+ # @example
13
+ # TextContent.new(text: "Hello, world")
14
+ class TextContent < Base
15
+ attribute :text, :string
16
+
17
+ def to_s
18
+ text.to_s
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,105 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module CoreModel
5
+ # Represents a Table of Contents in a document
6
+ #
7
+ # TOC provides hierarchical navigation structure for documents.
8
+ # It can be auto-generated from document sections or manually defined.
9
+ #
10
+ # @example Creating a TOC from sections
11
+ # toc = CoreModel::Toc.new(
12
+ # entries: [
13
+ # CoreModel::TocEntry.new(
14
+ # id: 'section-1',
15
+ # title: 'Section 1',
16
+ # level: 1,
17
+ # children: [
18
+ # CoreModel::TocEntry.new(id: 'subsection', title: 'Subsection', level: 2)
19
+ # ]
20
+ # )
21
+ # ]
22
+ # )
23
+ #
24
+ # @example Creating a TOC with configuration
25
+ # toc = CoreModel::Toc.new(
26
+ # entries: entries,
27
+ # min_level: 1,
28
+ # max_level: 3,
29
+ # numbered: true
30
+ # )
31
+ class Toc < Base
32
+ # @!attribute entries
33
+ # @return [Array<TocEntry>] the TOC entries
34
+ attribute :entries, :string, collection: true
35
+
36
+ # @!attribute min_level
37
+ # @return [Integer] minimum heading level to include (default: 1)
38
+ attribute :min_level, :integer, default: -> { 1 }
39
+
40
+ # @!attribute max_level
41
+ # @return [Integer] maximum heading level to include (default: 6)
42
+ attribute :max_level, :integer, default: -> { 6 }
43
+
44
+ # @!attribute numbered
45
+ # @return [Boolean] whether to include section numbers
46
+ attribute :numbered, :boolean, default: -> { false }
47
+
48
+ # @!attribute styled
49
+ # @return [Boolean] whether to include styling
50
+ attribute :styled, :boolean, default: -> { false }
51
+
52
+ private
53
+
54
+ def comparable_attributes
55
+ super + %i[entries min_level max_level numbered styled]
56
+ end
57
+ end
58
+
59
+ # Represents a single entry in a Table of Contents
60
+ #
61
+ # Each entry represents a heading/section and can contain
62
+ # nested child entries.
63
+ class TocEntry < Base
64
+ # @!attribute id
65
+ # @return [String, nil] the anchor ID for linking
66
+ attribute :id, :string
67
+
68
+ # @!attribute title
69
+ # @return [String, nil] the heading text
70
+ attribute :title, :string
71
+
72
+ # @!attribute level
73
+ # @return [Integer] the heading level (1-6)
74
+ attribute :level, :integer, default: -> { 1 }
75
+
76
+ # @!attribute number
77
+ # @return [String, nil] the section number (e.g., "1.2.3")
78
+ attribute :number, :string
79
+
80
+ # @!attribute children
81
+ # @return [Array<TocEntry>] nested child entries
82
+ attribute :children, :string, collection: true
83
+
84
+ private
85
+
86
+ def comparable_attributes
87
+ super + %i[id title level number children]
88
+ end
89
+ end
90
+
91
+ # Re-open Toc to properly type entries now that TocEntry is defined
92
+ class Toc
93
+ remove_method :entries if method_defined?(:entries)
94
+ remove_method :entries= if method_defined?(:entries=)
95
+ attribute :entries, TocEntry, collection: true
96
+ end
97
+
98
+ # Re-open TocEntry to properly type children now that TocEntry is defined
99
+ class TocEntry
100
+ remove_method :children if method_defined?(:children)
101
+ remove_method :children= if method_defined?(:children=)
102
+ attribute :children, TocEntry, collection: true
103
+ end
104
+ end
105
+ end
@@ -0,0 +1,151 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module CoreModel
5
+ # Table of Contents Generator for CoreModel documents
6
+ #
7
+ # Generates a Toc model from CoreModel::StructuralElement documents.
8
+ # Supports configurable level ranges and section numbering.
9
+ #
10
+ # @example Basic usage
11
+ # doc = Coradoc::CoreModel::StructuralElement.new(
12
+ # element_type: 'document',
13
+ # children: [section1, section2]
14
+ # )
15
+ # toc = CoreModel::TocGenerator.generate(doc)
16
+ #
17
+ # @example With options
18
+ # toc = CoreModel::TocGenerator.generate(doc,
19
+ # min_level: 2,
20
+ # max_level: 4,
21
+ # numbered: true
22
+ # )
23
+ #
24
+ class TocGenerator
25
+ # Default options for TOC generation
26
+ DEFAULT_OPTIONS = {
27
+ min_level: 1,
28
+ max_level: 6,
29
+ numbered: false,
30
+ styled: false
31
+ }.freeze
32
+
33
+ class << self
34
+ # Generate a Toc from a CoreModel document
35
+ #
36
+ # @param document [CoreModel::StructuralElement] The document to process
37
+ # @param options [Hash] Generation options
38
+ # @option options [Integer] :min_level (1) Minimum heading level
39
+ # @option options [Integer] :max_level (6) Maximum heading level
40
+ # @option options [Boolean] :numbered (false) Add section numbers
41
+ # @option options [Boolean] :styled (false) Add styling
42
+ # @return [CoreModel::Toc, nil] The generated TOC or nil if no sections
43
+ def generate(document, options = {})
44
+ opts = DEFAULT_OPTIONS.merge(options)
45
+ entries = extract_toc_entries(document, opts)
46
+
47
+ return nil if entries.empty?
48
+
49
+ CoreModel::Toc.new(
50
+ entries: entries,
51
+ min_level: opts[:min_level],
52
+ max_level: opts[:max_level],
53
+ numbered: opts[:numbered],
54
+ styled: opts[:styled]
55
+ )
56
+ end
57
+
58
+ private
59
+
60
+ # Extract TOC entries from a document
61
+ def extract_toc_entries(document, options)
62
+ sections = find_sections(document, options[:min_level], options[:max_level])
63
+ return [] if sections.empty?
64
+
65
+ # Track section numbers
66
+ counters = {}
67
+
68
+ build_entries(sections, options, counters)
69
+ end
70
+
71
+ # Find all sections in the document within level range
72
+ def find_sections(element, min_level, max_level)
73
+ sections = []
74
+ return sections unless element.is_a?(CoreModel::StructuralElement)
75
+
76
+ Array(element.children).each do |child|
77
+ next unless child.is_a?(CoreModel::StructuralElement)
78
+
79
+ if child.section?
80
+ level = child.heading_level
81
+ sections << { element: child, level: level } if level >= min_level && level <= max_level
82
+
83
+ # Also search nested sections
84
+ else
85
+ # Search children for sections
86
+ end
87
+ sections.concat(find_sections(child, min_level, max_level))
88
+ end
89
+
90
+ sections
91
+ end
92
+
93
+ # Build hierarchical TOC entries from flat section list
94
+ def build_entries(sections, options, counters)
95
+ return [] if sections.empty?
96
+
97
+ entries = []
98
+ options[:min_level]
99
+
100
+ # Stack for tracking parent entries at each level
101
+ stack = { options[:min_level] - 1 => nil }
102
+
103
+ sections.each do |section_info|
104
+ element = section_info[:element]
105
+ level = section_info[:level]
106
+
107
+ # Update counters
108
+ counters[level] ||= 0
109
+ counters[level] += 1
110
+ # Reset deeper level counters
111
+ (level + 1..6).each { |l| counters[l] = 0 }
112
+
113
+ # Generate number if needed
114
+ number = (generate_number(counters, options[:min_level], level) if options[:numbered])
115
+
116
+ entry = CoreModel::TocEntry.new(
117
+ id: element.id,
118
+ title: element.title,
119
+ level: level,
120
+ number: number,
121
+ children: []
122
+ )
123
+
124
+ # Find parent at previous level
125
+ parent_level = level - 1
126
+ parent_level -= 1 while parent_level >= options[:min_level] - 1 && !stack.key?(parent_level)
127
+
128
+ if stack[parent_level]
129
+ stack[parent_level].children << entry
130
+ else
131
+ entries << entry
132
+ end
133
+
134
+ # Add to stack for potential children
135
+ stack[level] = entry
136
+ end
137
+
138
+ entries
139
+ end
140
+
141
+ def generate_number(counters, min_level, current_level)
142
+ parts = []
143
+ (min_level..current_level).each do |l|
144
+ parts << counters[l] if counters[l]&.positive?
145
+ end
146
+ parts.join('.')
147
+ end
148
+ end
149
+ end
150
+ end
151
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module CoreModel
5
+ # Verse block — a block for verse/poetry with optional attribution
6
+ class VerseBlock < Block
7
+ def self.semantic_type = :verse
8
+
9
+ attribute :attribution, :string
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,77 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ # CoreModel namespace for format-agnostic document models
5
+ #
6
+ # CoreModel provides the canonical document representation used as the hub
7
+ # in the hub-and-spoke architecture. Format-specific builders live in their
8
+ # respective format gems (e.g., Coradoc::AsciiDoc::Builder).
9
+ #
10
+ # @see CoreModel::Base for base functionality
11
+ module CoreModel
12
+ # Autoload submodules lazily using relative paths
13
+ autoload :Base, "#{__dir__}/core_model/base"
14
+ autoload :ChildrenContent, "#{__dir__}/core_model/children_content"
15
+ autoload :Block, "#{__dir__}/core_model/block"
16
+ autoload :AnnotationBlock, "#{__dir__}/core_model/annotation_block"
17
+ autoload :ListBlock, "#{__dir__}/core_model/list_block"
18
+ autoload :ListItem, "#{__dir__}/core_model/list_item"
19
+ autoload :InlineElement, "#{__dir__}/core_model/inline_element"
20
+ autoload :BoldElement, "#{__dir__}/core_model/inline_element"
21
+ autoload :ItalicElement, "#{__dir__}/core_model/inline_element"
22
+ autoload :MonospaceElement, "#{__dir__}/core_model/inline_element"
23
+ autoload :UnderlineElement, "#{__dir__}/core_model/inline_element"
24
+ autoload :StrikethroughElement, "#{__dir__}/core_model/inline_element"
25
+ autoload :SubscriptElement, "#{__dir__}/core_model/inline_element"
26
+ autoload :SuperscriptElement, "#{__dir__}/core_model/inline_element"
27
+ autoload :HighlightElement, "#{__dir__}/core_model/inline_element"
28
+ autoload :LinkElement, "#{__dir__}/core_model/inline_element"
29
+ autoload :CrossReferenceElement, "#{__dir__}/core_model/inline_element"
30
+ autoload :StemElement, "#{__dir__}/core_model/inline_element"
31
+ autoload :FootnoteElement, "#{__dir__}/core_model/inline_element"
32
+ autoload :HardLineBreakElement, "#{__dir__}/core_model/inline_element"
33
+ autoload :TextElement, "#{__dir__}/core_model/inline_element"
34
+ autoload :SpanElement, "#{__dir__}/core_model/inline_element"
35
+ autoload :TermElement, "#{__dir__}/core_model/inline_element"
36
+ autoload :LineBreakElement, "#{__dir__}/core_model/inline_element"
37
+ autoload :StructuralElement, "#{__dir__}/core_model/structural_element"
38
+ autoload :DocumentElement, "#{__dir__}/core_model/structural_element"
39
+ autoload :SectionElement, "#{__dir__}/core_model/structural_element"
40
+ autoload :PreambleElement, "#{__dir__}/core_model/structural_element"
41
+ autoload :HeaderElement, "#{__dir__}/core_model/structural_element"
42
+
43
+ autoload :Table, "#{__dir__}/core_model/table"
44
+ autoload :TableCell, "#{__dir__}/core_model/table"
45
+ autoload :TableRow, "#{__dir__}/core_model/table"
46
+ autoload :TextContent, "#{__dir__}/core_model/text_content"
47
+ autoload :Image, "#{__dir__}/core_model/image"
48
+ autoload :Term, "#{__dir__}/core_model/term"
49
+ autoload :ElementAttribute, "#{__dir__}/core_model/element_attribute"
50
+ autoload :Metadata, "#{__dir__}/core_model/metadata"
51
+ autoload :MetadataEntry, "#{__dir__}/core_model/metadata"
52
+ autoload :Footnote, "#{__dir__}/core_model/footnote"
53
+ autoload :FootnoteReference, "#{__dir__}/core_model/footnote"
54
+ autoload :Abbreviation, "#{__dir__}/core_model/footnote"
55
+ autoload :DefinitionItem, "#{__dir__}/core_model/definition_item"
56
+ autoload :DefinitionList, "#{__dir__}/core_model/definition_list"
57
+ autoload :Toc, "#{__dir__}/core_model/toc"
58
+ autoload :TocEntry, "#{__dir__}/core_model/toc"
59
+ autoload :TocGenerator, "#{__dir__}/core_model/toc_generator"
60
+ autoload :Bibliography, "#{__dir__}/core_model/bibliography"
61
+ autoload :BibliographyEntry, "#{__dir__}/core_model/bibliography_entry"
62
+ autoload :SourceBlock, "#{__dir__}/core_model/source_block"
63
+ autoload :ExampleBlock, "#{__dir__}/core_model/example_block"
64
+ autoload :QuoteBlock, "#{__dir__}/core_model/quote_block"
65
+ autoload :SidebarBlock, "#{__dir__}/core_model/sidebar_block"
66
+ autoload :LiteralBlock, "#{__dir__}/core_model/literal_block"
67
+ autoload :PassBlock, "#{__dir__}/core_model/pass_block"
68
+ autoload :ListingBlock, "#{__dir__}/core_model/listing_block"
69
+ autoload :OpenBlock, "#{__dir__}/core_model/open_block"
70
+ autoload :VerseBlock, "#{__dir__}/core_model/verse_block"
71
+ autoload :ReviewerBlock, "#{__dir__}/core_model/reviewer_block"
72
+ autoload :ParagraphBlock, "#{__dir__}/core_model/paragraph_block"
73
+ autoload :CommentBlock, "#{__dir__}/core_model/comment_block"
74
+ autoload :HorizontalRuleBlock, "#{__dir__}/core_model/horizontal_rule_block"
75
+ autoload :IdGenerator, "#{__dir__}/core_model/id_generator"
76
+ end
77
+ end