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.
- checksums.yaml +4 -4
- data/.rspec +1 -1
- data/Rakefile +3 -12
- data/exe/coradoc +21 -2
- data/lib/coradoc/cli.rb +185 -91
- data/lib/coradoc/configurable.rb +527 -0
- data/lib/coradoc/coradoc.rb +463 -0
- data/lib/coradoc/core_model/annotation_block.rb +57 -0
- data/lib/coradoc/core_model/base.rb +172 -0
- data/lib/coradoc/core_model/bibliography.rb +41 -0
- data/lib/coradoc/core_model/bibliography_entry.rb +48 -0
- data/lib/coradoc/core_model/block.rb +63 -0
- data/lib/coradoc/core_model/children_content.rb +53 -0
- data/lib/coradoc/core_model/comment_block.rb +10 -0
- data/lib/coradoc/core_model/definition_item.rb +46 -0
- data/lib/coradoc/core_model/definition_list.rb +28 -0
- data/lib/coradoc/core_model/element_attribute.rb +26 -0
- data/lib/coradoc/core_model/example_block.rb +10 -0
- data/lib/coradoc/core_model/footnote.rb +92 -0
- data/lib/coradoc/core_model/horizontal_rule_block.rb +10 -0
- data/lib/coradoc/core_model/id_generator.rb +16 -0
- data/lib/coradoc/core_model/image.rb +66 -0
- data/lib/coradoc/core_model/inline_element.rb +140 -0
- data/lib/coradoc/core_model/list_block.rb +135 -0
- data/lib/coradoc/core_model/list_item.rb +142 -0
- data/lib/coradoc/core_model/listing_block.rb +13 -0
- data/lib/coradoc/core_model/literal_block.rb +10 -0
- data/lib/coradoc/core_model/metadata.rb +79 -0
- data/lib/coradoc/core_model/open_block.rb +10 -0
- data/lib/coradoc/core_model/paragraph_block.rb +10 -0
- data/lib/coradoc/core_model/pass_block.rb +10 -0
- data/lib/coradoc/core_model/quote_block.rb +12 -0
- data/lib/coradoc/core_model/reviewer_block.rb +10 -0
- data/lib/coradoc/core_model/sidebar_block.rb +10 -0
- data/lib/coradoc/core_model/source_block.rb +10 -0
- data/lib/coradoc/core_model/structural_element.rb +94 -0
- data/lib/coradoc/core_model/table.rb +148 -0
- data/lib/coradoc/core_model/term.rb +53 -0
- data/lib/coradoc/core_model/text_content.rb +22 -0
- data/lib/coradoc/core_model/toc.rb +105 -0
- data/lib/coradoc/core_model/toc_generator.rb +151 -0
- data/lib/coradoc/core_model/verse_block.rb +12 -0
- data/lib/coradoc/core_model.rb +77 -0
- data/lib/coradoc/document_builder.rb +184 -0
- data/lib/coradoc/document_manipulator.rb +203 -0
- data/lib/coradoc/errors.rb +312 -0
- data/lib/coradoc/format_module.rb +49 -0
- data/lib/coradoc/hooks.rb +176 -0
- data/lib/coradoc/input.rb +17 -7
- data/lib/coradoc/logger.rb +54 -0
- data/lib/coradoc/output.rb +17 -6
- data/lib/coradoc/performance_regression.rb +109 -0
- data/lib/coradoc/processor_registry.rb +50 -0
- data/lib/coradoc/query.rb +455 -0
- data/lib/coradoc/registry.rb +156 -0
- data/lib/coradoc/serializer/registry.rb +150 -0
- data/lib/coradoc/transform.rb +11 -0
- data/lib/coradoc/validation.rb +646 -0
- data/lib/coradoc/version.rb +1 -1
- data/lib/coradoc/visitor.rb +283 -0
- data/lib/coradoc.rb +40 -19
- metadata +67 -277
- data/.editorconfig +0 -15
- data/.envrc +0 -1
- data/.irbrc +0 -1
- data/.pryrc.sample +0 -1
- data/.rubocop.yml +0 -14
- data/.rubocop_todo.yml +0 -179
- data/CHANGELOG.md +0 -9
- data/CODE_OF_CONDUCT.md +0 -84
- data/Dockerfile +0 -19
- data/Gemfile +0 -16
- data/LICENSE.txt +0 -21
- data/Makefile +0 -35
- data/README.Docker.adoc +0 -57
- data/README.adoc +0 -119
- data/coradoc.gemspec +0 -40
- data/docker-compose.yml +0 -14
- data/exe/reverse_adoc +0 -81
- data/exe/w2a +0 -60
- data/flake.lock +0 -114
- data/flake.nix +0 -135
- data/lib/coradoc/converter.rb +0 -144
- data/lib/coradoc/document.rb +0 -77
- data/lib/coradoc/element/admonition.rb +0 -18
- data/lib/coradoc/element/attribute.rb +0 -36
- data/lib/coradoc/element/attribute_list.rb +0 -138
- data/lib/coradoc/element/audio.rb +0 -33
- data/lib/coradoc/element/author.rb +0 -24
- data/lib/coradoc/element/base.rb +0 -92
- data/lib/coradoc/element/bibliography.rb +0 -24
- data/lib/coradoc/element/bibliography_entry.rb +0 -24
- data/lib/coradoc/element/block/core.rb +0 -76
- data/lib/coradoc/element/block/example.rb +0 -23
- data/lib/coradoc/element/block/listing.rb +0 -21
- data/lib/coradoc/element/block/literal.rb +0 -21
- data/lib/coradoc/element/block/open.rb +0 -22
- data/lib/coradoc/element/block/pass.rb +0 -21
- data/lib/coradoc/element/block/quote.rb +0 -19
- data/lib/coradoc/element/block/reviewer_comment.rb +0 -19
- data/lib/coradoc/element/block/side.rb +0 -19
- data/lib/coradoc/element/block/sourcecode.rb +0 -21
- data/lib/coradoc/element/block.rb +0 -17
- data/lib/coradoc/element/break.rb +0 -11
- data/lib/coradoc/element/comment_block.rb +0 -22
- data/lib/coradoc/element/comment_line.rb +0 -18
- data/lib/coradoc/element/document_attributes.rb +0 -33
- data/lib/coradoc/element/header.rb +0 -22
- data/lib/coradoc/element/image/block_image.rb +0 -32
- data/lib/coradoc/element/image/core.rb +0 -58
- data/lib/coradoc/element/image/inline_image.rb +0 -12
- data/lib/coradoc/element/image.rb +0 -10
- data/lib/coradoc/element/include.rb +0 -18
- data/lib/coradoc/element/inline/anchor.rb +0 -19
- data/lib/coradoc/element/inline/attribute_reference.rb +0 -19
- data/lib/coradoc/element/inline/bold.rb +0 -25
- data/lib/coradoc/element/inline/cross_reference.rb +0 -46
- data/lib/coradoc/element/inline/footnote.rb +0 -24
- data/lib/coradoc/element/inline/hard_line_break.rb +0 -11
- data/lib/coradoc/element/inline/highlight.rb +0 -25
- data/lib/coradoc/element/inline/italic.rb +0 -25
- data/lib/coradoc/element/inline/link.rb +0 -42
- data/lib/coradoc/element/inline/monospace.rb +0 -25
- data/lib/coradoc/element/inline/quotation.rb +0 -20
- data/lib/coradoc/element/inline/small.rb +0 -19
- data/lib/coradoc/element/inline/span.rb +0 -37
- data/lib/coradoc/element/inline/subscript.rb +0 -20
- data/lib/coradoc/element/inline/superscript.rb +0 -20
- data/lib/coradoc/element/inline/underline.rb +0 -19
- data/lib/coradoc/element/inline.rb +0 -23
- data/lib/coradoc/element/list/core.rb +0 -51
- data/lib/coradoc/element/list/definition.rb +0 -29
- data/lib/coradoc/element/list/ordered.rb +0 -17
- data/lib/coradoc/element/list/unordered.rb +0 -17
- data/lib/coradoc/element/list.rb +0 -13
- data/lib/coradoc/element/list_item.rb +0 -98
- data/lib/coradoc/element/list_item_definition.rb +0 -32
- data/lib/coradoc/element/paragraph.rb +0 -37
- data/lib/coradoc/element/revision.rb +0 -27
- data/lib/coradoc/element/section.rb +0 -62
- data/lib/coradoc/element/table.rb +0 -91
- data/lib/coradoc/element/tag.rb +0 -19
- data/lib/coradoc/element/term.rb +0 -22
- data/lib/coradoc/element/text_element.rb +0 -92
- data/lib/coradoc/element/title.rb +0 -62
- data/lib/coradoc/element/video.rb +0 -50
- data/lib/coradoc/generator.rb +0 -19
- data/lib/coradoc/input/adoc.rb +0 -30
- data/lib/coradoc/input/docx.rb +0 -64
- data/lib/coradoc/input/html/LICENSE.txt +0 -25
- data/lib/coradoc/input/html/README.adoc +0 -308
- data/lib/coradoc/input/html/cleaner.rb +0 -142
- data/lib/coradoc/input/html/config.rb +0 -77
- data/lib/coradoc/input/html/converters/a.rb +0 -52
- data/lib/coradoc/input/html/converters/aside.rb +0 -16
- data/lib/coradoc/input/html/converters/audio.rb +0 -29
- data/lib/coradoc/input/html/converters/base.rb +0 -108
- data/lib/coradoc/input/html/converters/blockquote.rb +0 -22
- data/lib/coradoc/input/html/converters/br.rb +0 -15
- data/lib/coradoc/input/html/converters/bypass.rb +0 -81
- data/lib/coradoc/input/html/converters/code.rb +0 -23
- data/lib/coradoc/input/html/converters/div.rb +0 -19
- data/lib/coradoc/input/html/converters/dl.rb +0 -62
- data/lib/coradoc/input/html/converters/drop.rb +0 -26
- data/lib/coradoc/input/html/converters/em.rb +0 -21
- data/lib/coradoc/input/html/converters/figure.rb +0 -25
- data/lib/coradoc/input/html/converters/h.rb +0 -42
- data/lib/coradoc/input/html/converters/head.rb +0 -23
- data/lib/coradoc/input/html/converters/hr.rb +0 -15
- data/lib/coradoc/input/html/converters/ignore.rb +0 -20
- data/lib/coradoc/input/html/converters/img.rb +0 -110
- data/lib/coradoc/input/html/converters/li.rb +0 -17
- data/lib/coradoc/input/html/converters/mark.rb +0 -19
- data/lib/coradoc/input/html/converters/markup.rb +0 -31
- data/lib/coradoc/input/html/converters/math.rb +0 -38
- data/lib/coradoc/input/html/converters/ol.rb +0 -65
- data/lib/coradoc/input/html/converters/p.rb +0 -23
- data/lib/coradoc/input/html/converters/pass_through.rb +0 -17
- data/lib/coradoc/input/html/converters/pre.rb +0 -55
- data/lib/coradoc/input/html/converters/q.rb +0 -16
- data/lib/coradoc/input/html/converters/strong.rb +0 -20
- data/lib/coradoc/input/html/converters/sub.rb +0 -22
- data/lib/coradoc/input/html/converters/sup.rb +0 -22
- data/lib/coradoc/input/html/converters/table.rb +0 -319
- data/lib/coradoc/input/html/converters/td.rb +0 -81
- data/lib/coradoc/input/html/converters/text.rb +0 -32
- data/lib/coradoc/input/html/converters/th.rb +0 -18
- data/lib/coradoc/input/html/converters/tr.rb +0 -22
- data/lib/coradoc/input/html/converters/video.rb +0 -29
- data/lib/coradoc/input/html/converters.rb +0 -59
- data/lib/coradoc/input/html/errors.rb +0 -14
- data/lib/coradoc/input/html/html_converter.rb +0 -168
- data/lib/coradoc/input/html/plugin.rb +0 -131
- data/lib/coradoc/input/html/plugins/plateau.rb +0 -213
- data/lib/coradoc/input/html/postprocessor.rb +0 -220
- data/lib/coradoc/input/html.rb +0 -61
- data/lib/coradoc/legacy_parser.rb +0 -200
- data/lib/coradoc/oscal.rb +0 -99
- data/lib/coradoc/output/adoc.rb +0 -19
- data/lib/coradoc/output/coradoc_tree_debug.rb +0 -21
- data/lib/coradoc/parser/asciidoc/admonition.rb +0 -24
- data/lib/coradoc/parser/asciidoc/attribute_list.rb +0 -89
- data/lib/coradoc/parser/asciidoc/base.rb +0 -87
- data/lib/coradoc/parser/asciidoc/bibliography.rb +0 -29
- data/lib/coradoc/parser/asciidoc/block.rb +0 -94
- data/lib/coradoc/parser/asciidoc/citation.rb +0 -30
- data/lib/coradoc/parser/asciidoc/content.rb +0 -64
- data/lib/coradoc/parser/asciidoc/document_attributes.rb +0 -25
- data/lib/coradoc/parser/asciidoc/header.rb +0 -29
- data/lib/coradoc/parser/asciidoc/inline.rb +0 -195
- data/lib/coradoc/parser/asciidoc/list.rb +0 -115
- data/lib/coradoc/parser/asciidoc/paragraph.rb +0 -54
- data/lib/coradoc/parser/asciidoc/section.rb +0 -61
- data/lib/coradoc/parser/asciidoc/table.rb +0 -32
- data/lib/coradoc/parser/asciidoc/term.rb +0 -41
- data/lib/coradoc/parser/asciidoc/text.rb +0 -158
- data/lib/coradoc/parser/base.rb +0 -40
- data/lib/coradoc/parser.rb +0 -11
- data/lib/coradoc/reverse_adoc.rb +0 -18
- data/lib/coradoc/transformer.rb +0 -476
- data/lib/coradoc/util.rb +0 -12
- data/lib/reverse_adoc.rb +0 -20
- data/utils/inspect_asciidoc.rb +0 -29
- data/utils/parser_analyzer.rb +0 -66
- 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,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
|