coradoc-adoc 2.0.0

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 (217) hide show
  1. checksums.yaml +7 -0
  2. data/.rspec +3 -0
  3. data/lib/coradoc/asciidoc/model/admonition.rb +37 -0
  4. data/lib/coradoc/asciidoc/model/anchorable.rb +64 -0
  5. data/lib/coradoc/asciidoc/model/attached.rb +26 -0
  6. data/lib/coradoc/asciidoc/model/attribute.rb +22 -0
  7. data/lib/coradoc/asciidoc/model/attribute_list/matchers.rb +45 -0
  8. data/lib/coradoc/asciidoc/model/attribute_list.rb +230 -0
  9. data/lib/coradoc/asciidoc/model/attribute_list_attribute.rb +11 -0
  10. data/lib/coradoc/asciidoc/model/audio.rb +44 -0
  11. data/lib/coradoc/asciidoc/model/author.rb +36 -0
  12. data/lib/coradoc/asciidoc/model/base.rb +141 -0
  13. data/lib/coradoc/asciidoc/model/bibliography.rb +37 -0
  14. data/lib/coradoc/asciidoc/model/bibliography_entry.rb +38 -0
  15. data/lib/coradoc/asciidoc/model/block/core.rb +139 -0
  16. data/lib/coradoc/asciidoc/model/block/example.rb +14 -0
  17. data/lib/coradoc/asciidoc/model/block/listing.rb +14 -0
  18. data/lib/coradoc/asciidoc/model/block/literal.rb +14 -0
  19. data/lib/coradoc/asciidoc/model/block/open.rb +14 -0
  20. data/lib/coradoc/asciidoc/model/block/pass.rb +14 -0
  21. data/lib/coradoc/asciidoc/model/block/quote.rb +14 -0
  22. data/lib/coradoc/asciidoc/model/block/reviewer_comment.rb +14 -0
  23. data/lib/coradoc/asciidoc/model/block/side.rb +14 -0
  24. data/lib/coradoc/asciidoc/model/block/source_code.rb +14 -0
  25. data/lib/coradoc/asciidoc/model/block.rb +21 -0
  26. data/lib/coradoc/asciidoc/model/break.rb +33 -0
  27. data/lib/coradoc/asciidoc/model/comment_block.rb +33 -0
  28. data/lib/coradoc/asciidoc/model/comment_line.rb +30 -0
  29. data/lib/coradoc/asciidoc/model/content_list.rb +334 -0
  30. data/lib/coradoc/asciidoc/model/document.rb +197 -0
  31. data/lib/coradoc/asciidoc/model/document_attributes.rb +43 -0
  32. data/lib/coradoc/asciidoc/model/glossaries.rb +11 -0
  33. data/lib/coradoc/asciidoc/model/header.rb +57 -0
  34. data/lib/coradoc/asciidoc/model/highlight.rb +11 -0
  35. data/lib/coradoc/asciidoc/model/image/block_image/attribute_list.rb +23 -0
  36. data/lib/coradoc/asciidoc/model/image/block_image.rb +25 -0
  37. data/lib/coradoc/asciidoc/model/image/core/attribute_list.rb +43 -0
  38. data/lib/coradoc/asciidoc/model/image/core.rb +72 -0
  39. data/lib/coradoc/asciidoc/model/image/inline_image.rb +17 -0
  40. data/lib/coradoc/asciidoc/model/image.rb +14 -0
  41. data/lib/coradoc/asciidoc/model/include.rb +66 -0
  42. data/lib/coradoc/asciidoc/model/inline/anchor.rb +41 -0
  43. data/lib/coradoc/asciidoc/model/inline/attribute_reference.rb +25 -0
  44. data/lib/coradoc/asciidoc/model/inline/base.rb +15 -0
  45. data/lib/coradoc/asciidoc/model/inline/bold.rb +38 -0
  46. data/lib/coradoc/asciidoc/model/inline/cross_reference.rb +29 -0
  47. data/lib/coradoc/asciidoc/model/inline/cross_reference_arg.rb +15 -0
  48. data/lib/coradoc/asciidoc/model/inline/footnote.rb +34 -0
  49. data/lib/coradoc/asciidoc/model/inline/hard_line_break.rb +24 -0
  50. data/lib/coradoc/asciidoc/model/inline/highlight.rb +36 -0
  51. data/lib/coradoc/asciidoc/model/inline/italic.rb +38 -0
  52. data/lib/coradoc/asciidoc/model/inline/link.rb +46 -0
  53. data/lib/coradoc/asciidoc/model/inline/monospace.rb +39 -0
  54. data/lib/coradoc/asciidoc/model/inline/quotation.rb +25 -0
  55. data/lib/coradoc/asciidoc/model/inline/small.rb +25 -0
  56. data/lib/coradoc/asciidoc/model/inline/span.rb +38 -0
  57. data/lib/coradoc/asciidoc/model/inline/stem.rb +24 -0
  58. data/lib/coradoc/asciidoc/model/inline/strikethrough.rb +39 -0
  59. data/lib/coradoc/asciidoc/model/inline/subscript.rb +33 -0
  60. data/lib/coradoc/asciidoc/model/inline/superscript.rb +33 -0
  61. data/lib/coradoc/asciidoc/model/inline/underline.rb +25 -0
  62. data/lib/coradoc/asciidoc/model/inline.rb +31 -0
  63. data/lib/coradoc/asciidoc/model/line_break.rb +11 -0
  64. data/lib/coradoc/asciidoc/model/list/core.rb +61 -0
  65. data/lib/coradoc/asciidoc/model/list/definition.rb +27 -0
  66. data/lib/coradoc/asciidoc/model/list/definition_item.rb +43 -0
  67. data/lib/coradoc/asciidoc/model/list/item.rb +72 -0
  68. data/lib/coradoc/asciidoc/model/list/nestable.rb +14 -0
  69. data/lib/coradoc/asciidoc/model/list/ordered.rb +34 -0
  70. data/lib/coradoc/asciidoc/model/list/unordered.rb +34 -0
  71. data/lib/coradoc/asciidoc/model/list.rb +29 -0
  72. data/lib/coradoc/asciidoc/model/named_attribute.rb +12 -0
  73. data/lib/coradoc/asciidoc/model/paragraph.rb +59 -0
  74. data/lib/coradoc/asciidoc/model/rejected_positional_attribute.rb +12 -0
  75. data/lib/coradoc/asciidoc/model/resolvable.rb +71 -0
  76. data/lib/coradoc/asciidoc/model/resolver.rb +430 -0
  77. data/lib/coradoc/asciidoc/model/reviewer_note.rb +54 -0
  78. data/lib/coradoc/asciidoc/model/revision.rb +47 -0
  79. data/lib/coradoc/asciidoc/model/section.rb +109 -0
  80. data/lib/coradoc/asciidoc/model/serialization/asciidoc_adapter.rb +28 -0
  81. data/lib/coradoc/asciidoc/model/serialization/asciidoc_mapping.rb +42 -0
  82. data/lib/coradoc/asciidoc/model/serialization/asciidoc_mapping_rule.rb +41 -0
  83. data/lib/coradoc/asciidoc/model/serialization/asciidoc_transform.rb +211 -0
  84. data/lib/coradoc/asciidoc/model/serialization/errors.rb +57 -0
  85. data/lib/coradoc/asciidoc/model/serialization.rb +39 -0
  86. data/lib/coradoc/asciidoc/model/spacing.rb +282 -0
  87. data/lib/coradoc/asciidoc/model/table.rb +44 -0
  88. data/lib/coradoc/asciidoc/model/table_cell.rb +122 -0
  89. data/lib/coradoc/asciidoc/model/table_row.rb +26 -0
  90. data/lib/coradoc/asciidoc/model/tag.rb +36 -0
  91. data/lib/coradoc/asciidoc/model/term.rb +48 -0
  92. data/lib/coradoc/asciidoc/model/text_element.rb +66 -0
  93. data/lib/coradoc/asciidoc/model/title.rb +85 -0
  94. data/lib/coradoc/asciidoc/model/video/attribute_list.rb +43 -0
  95. data/lib/coradoc/asciidoc/model/video.rb +49 -0
  96. data/lib/coradoc/asciidoc/model.rb +75 -0
  97. data/lib/coradoc/asciidoc/parse_error.rb +161 -0
  98. data/lib/coradoc/asciidoc/parser/admonition.rb +26 -0
  99. data/lib/coradoc/asciidoc/parser/attribute_list.rb +110 -0
  100. data/lib/coradoc/asciidoc/parser/base.rb +159 -0
  101. data/lib/coradoc/asciidoc/parser/bibliography.rb +31 -0
  102. data/lib/coradoc/asciidoc/parser/block.rb +186 -0
  103. data/lib/coradoc/asciidoc/parser/block_assembler.rb +183 -0
  104. data/lib/coradoc/asciidoc/parser/cache.rb +155 -0
  105. data/lib/coradoc/asciidoc/parser/citation.rb +32 -0
  106. data/lib/coradoc/asciidoc/parser/content.rb +76 -0
  107. data/lib/coradoc/asciidoc/parser/document_attributes.rb +27 -0
  108. data/lib/coradoc/asciidoc/parser/fix_files.rb +76 -0
  109. data/lib/coradoc/asciidoc/parser/header.rb +31 -0
  110. data/lib/coradoc/asciidoc/parser/inline.rb +199 -0
  111. data/lib/coradoc/asciidoc/parser/list.rb +130 -0
  112. data/lib/coradoc/asciidoc/parser/metadata_detector.rb +164 -0
  113. data/lib/coradoc/asciidoc/parser/paragraph.rb +64 -0
  114. data/lib/coradoc/asciidoc/parser/section.rb +62 -0
  115. data/lib/coradoc/asciidoc/parser/stem.rb +19 -0
  116. data/lib/coradoc/asciidoc/parser/table.rb +166 -0
  117. data/lib/coradoc/asciidoc/parser/term.rb +70 -0
  118. data/lib/coradoc/asciidoc/parser/text.rb +156 -0
  119. data/lib/coradoc/asciidoc/parser.rb +10 -0
  120. data/lib/coradoc/asciidoc/serializer/adoc_serializer.rb +86 -0
  121. data/lib/coradoc/asciidoc/serializer/element_registry.rb +95 -0
  122. data/lib/coradoc/asciidoc/serializer/fallback_serializer.rb +21 -0
  123. data/lib/coradoc/asciidoc/serializer/formatter.rb +144 -0
  124. data/lib/coradoc/asciidoc/serializer/registrations.rb +108 -0
  125. data/lib/coradoc/asciidoc/serializer/serialization_context.rb +238 -0
  126. data/lib/coradoc/asciidoc/serializer/serializers/admonition.rb +19 -0
  127. data/lib/coradoc/asciidoc/serializer/serializers/attribute.rb +23 -0
  128. data/lib/coradoc/asciidoc/serializer/serializers/attribute_list.rb +40 -0
  129. data/lib/coradoc/asciidoc/serializer/serializers/attribute_list_attribute.rb +18 -0
  130. data/lib/coradoc/asciidoc/serializer/serializers/audio.rb +33 -0
  131. data/lib/coradoc/asciidoc/serializer/serializers/author.rb +20 -0
  132. data/lib/coradoc/asciidoc/serializer/serializers/base.rb +152 -0
  133. data/lib/coradoc/asciidoc/serializer/serializers/bibliography.rb +35 -0
  134. data/lib/coradoc/asciidoc/serializer/serializers/bibliography_entry.rb +24 -0
  135. data/lib/coradoc/asciidoc/serializer/serializers/block/core.rb +70 -0
  136. data/lib/coradoc/asciidoc/serializer/serializers/block/example.rb +17 -0
  137. data/lib/coradoc/asciidoc/serializer/serializers/block/listing.rb +22 -0
  138. data/lib/coradoc/asciidoc/serializer/serializers/block/literal.rb +17 -0
  139. data/lib/coradoc/asciidoc/serializer/serializers/block/open.rb +22 -0
  140. data/lib/coradoc/asciidoc/serializer/serializers/block/pass.rb +17 -0
  141. data/lib/coradoc/asciidoc/serializer/serializers/block/quote.rb +17 -0
  142. data/lib/coradoc/asciidoc/serializer/serializers/block/reviewer_comment.rb +17 -0
  143. data/lib/coradoc/asciidoc/serializer/serializers/block/side.rb +22 -0
  144. data/lib/coradoc/asciidoc/serializer/serializers/block/source_code.rb +22 -0
  145. data/lib/coradoc/asciidoc/serializer/serializers/block.rb +23 -0
  146. data/lib/coradoc/asciidoc/serializer/serializers/break.rb +18 -0
  147. data/lib/coradoc/asciidoc/serializer/serializers/comment_block.rb +22 -0
  148. data/lib/coradoc/asciidoc/serializer/serializers/comment_line.rb +22 -0
  149. data/lib/coradoc/asciidoc/serializer/serializers/document.rb +65 -0
  150. data/lib/coradoc/asciidoc/serializer/serializers/document_attributes.rb +21 -0
  151. data/lib/coradoc/asciidoc/serializer/serializers/header.rb +24 -0
  152. data/lib/coradoc/asciidoc/serializer/serializers/highlight.rb +23 -0
  153. data/lib/coradoc/asciidoc/serializer/serializers/image/core.rb +30 -0
  154. data/lib/coradoc/asciidoc/serializer/serializers/image.rb +14 -0
  155. data/lib/coradoc/asciidoc/serializer/serializers/include.rb +19 -0
  156. data/lib/coradoc/asciidoc/serializer/serializers/inline/anchor.rb +20 -0
  157. data/lib/coradoc/asciidoc/serializer/serializers/inline/attribute_reference.rb +20 -0
  158. data/lib/coradoc/asciidoc/serializer/serializers/inline/bold.rb +26 -0
  159. data/lib/coradoc/asciidoc/serializer/serializers/inline/cross_reference.rb +30 -0
  160. data/lib/coradoc/asciidoc/serializer/serializers/inline/cross_reference_arg.rb +20 -0
  161. data/lib/coradoc/asciidoc/serializer/serializers/inline/footnote.rb +24 -0
  162. data/lib/coradoc/asciidoc/serializer/serializers/inline/hard_line_break.rb +20 -0
  163. data/lib/coradoc/asciidoc/serializer/serializers/inline/highlight.rb +26 -0
  164. data/lib/coradoc/asciidoc/serializer/serializers/inline/italic.rb +26 -0
  165. data/lib/coradoc/asciidoc/serializer/serializers/inline/link.rb +38 -0
  166. data/lib/coradoc/asciidoc/serializer/serializers/inline/monospace.rb +26 -0
  167. data/lib/coradoc/asciidoc/serializer/serializers/inline/quotation.rb +21 -0
  168. data/lib/coradoc/asciidoc/serializer/serializers/inline/small.rb +20 -0
  169. data/lib/coradoc/asciidoc/serializer/serializers/inline/span.rb +35 -0
  170. data/lib/coradoc/asciidoc/serializer/serializers/inline/stem.rb +23 -0
  171. data/lib/coradoc/asciidoc/serializer/serializers/inline/strikethrough.rb +29 -0
  172. data/lib/coradoc/asciidoc/serializer/serializers/inline/subscript.rb +29 -0
  173. data/lib/coradoc/asciidoc/serializer/serializers/inline/superscript.rb +26 -0
  174. data/lib/coradoc/asciidoc/serializer/serializers/inline/underline.rb +20 -0
  175. data/lib/coradoc/asciidoc/serializer/serializers/inline.rb +32 -0
  176. data/lib/coradoc/asciidoc/serializer/serializers/line_break.rb +18 -0
  177. data/lib/coradoc/asciidoc/serializer/serializers/list/core.rb +47 -0
  178. data/lib/coradoc/asciidoc/serializer/serializers/list/definition.rb +35 -0
  179. data/lib/coradoc/asciidoc/serializer/serializers/list/definition_item.rb +38 -0
  180. data/lib/coradoc/asciidoc/serializer/serializers/list/item.rb +120 -0
  181. data/lib/coradoc/asciidoc/serializer/serializers/list/ordered.rb +24 -0
  182. data/lib/coradoc/asciidoc/serializer/serializers/list/unordered.rb +29 -0
  183. data/lib/coradoc/asciidoc/serializer/serializers/list.rb +19 -0
  184. data/lib/coradoc/asciidoc/serializer/serializers/named_attribute.rb +22 -0
  185. data/lib/coradoc/asciidoc/serializer/serializers/paragraph.rb +65 -0
  186. data/lib/coradoc/asciidoc/serializer/serializers/reviewer_note.rb +28 -0
  187. data/lib/coradoc/asciidoc/serializer/serializers/revision.rb +26 -0
  188. data/lib/coradoc/asciidoc/serializer/serializers/section.rb +37 -0
  189. data/lib/coradoc/asciidoc/serializer/serializers/table.rb +24 -0
  190. data/lib/coradoc/asciidoc/serializer/serializers/table_cell.rb +75 -0
  191. data/lib/coradoc/asciidoc/serializer/serializers/table_row.rb +24 -0
  192. data/lib/coradoc/asciidoc/serializer/serializers/tag.rb +19 -0
  193. data/lib/coradoc/asciidoc/serializer/serializers/term.rb +20 -0
  194. data/lib/coradoc/asciidoc/serializer/serializers/text_element.rb +23 -0
  195. data/lib/coradoc/asciidoc/serializer/serializers/title.rb +55 -0
  196. data/lib/coradoc/asciidoc/serializer/serializers/video.rb +33 -0
  197. data/lib/coradoc/asciidoc/serializer/spacing_strategy.rb +70 -0
  198. data/lib/coradoc/asciidoc/serializer.rb +75 -0
  199. data/lib/coradoc/asciidoc/transform/from_core_model.rb +502 -0
  200. data/lib/coradoc/asciidoc/transform/from_core_model_registrations.rb +126 -0
  201. data/lib/coradoc/asciidoc/transform/registry.rb +146 -0
  202. data/lib/coradoc/asciidoc/transform/to_core_model.rb +564 -0
  203. data/lib/coradoc/asciidoc/transform/to_core_model_registrations.rb +257 -0
  204. data/lib/coradoc/asciidoc/transform.rb +13 -0
  205. data/lib/coradoc/asciidoc/transformer/block_rules.rb +101 -0
  206. data/lib/coradoc/asciidoc/transformer/header_rules.rb +91 -0
  207. data/lib/coradoc/asciidoc/transformer/inline_rules.rb +179 -0
  208. data/lib/coradoc/asciidoc/transformer/list_rules.rb +131 -0
  209. data/lib/coradoc/asciidoc/transformer/misc_rules.rb +196 -0
  210. data/lib/coradoc/asciidoc/transformer/structural_rules.rb +216 -0
  211. data/lib/coradoc/asciidoc/transformer/text_rules.rb +107 -0
  212. data/lib/coradoc/asciidoc/transformer.rb +406 -0
  213. data/lib/coradoc/asciidoc/version.rb +7 -0
  214. data/lib/coradoc/asciidoc.rb +148 -0
  215. data/lib/coradoc/util/asciidoc.rb +71 -0
  216. data/lib/coradoc/util.rb +8 -0
  217. metadata +343 -0
@@ -0,0 +1,85 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module AsciiDoc
5
+ module Model
6
+ # Title element for sections and document headers.
7
+ #
8
+ # Represents a title with optional level information. Titles are used by
9
+ # sections to define their heading level and text content.
10
+ #
11
+ # @!attribute [r] id
12
+ # @return [String, nil] Optional identifier for the title
13
+ # @!attribute [r] content
14
+ # @return [Array<TextElement>] Title text content (can include inline formatting)
15
+ # @!attribute [r] level_int
16
+ # @return [Integer, nil] Heading level (0-5 for standard, 6+ uses style attribute)
17
+ # @!attribute [r] line_break
18
+ # @return [String] Line break character after title (default: newline)
19
+ # @!attribute [r] style
20
+ # @return [String, nil] Optional style attribute for title formatting
21
+ #
22
+ # @example Create a level 1 title
23
+ # title = Coradoc::AsciiDoc::Model::Title.new(
24
+ # content: [Coradoc::AsciiDoc::Model::TextElement.new("Chapter 1")],
25
+ # level_int: 0
26
+ # )
27
+ # title.to_adoc # => "= Chapter 1\n"
28
+ #
29
+ # @example Create a level 2 title
30
+ # title = Coradoc::AsciiDoc::Model::Title.new(
31
+ # content: [Coradoc::AsciiDoc::Model::TextElement.new("Section 1.1")],
32
+ # level_int: 1
33
+ # )
34
+ # title.to_adoc # => "== Section 1.1\n"
35
+ #
36
+ class Title < Base
37
+ include Coradoc::AsciiDoc::Model::Anchorable
38
+
39
+ attribute :id, :string
40
+ attribute :content, Coradoc::AsciiDoc::Model::TextElement, collection: true
41
+ # attribute :level, :string
42
+ attribute :level_int, :integer
43
+ attribute :line_break, :string, default: -> { "\n" }
44
+ attribute :style, :string
45
+
46
+ alias text content
47
+
48
+ # Convert title content to string
49
+ # @return [String] The title text
50
+ def to_s
51
+ case content
52
+ when String
53
+ content
54
+ when Array
55
+ content.map do |item|
56
+ item.is_a?(Coradoc::AsciiDoc::Model::TextElement) ? item.content.to_s : item.to_s
57
+ end.join
58
+ else
59
+ content.to_s
60
+ end
61
+ end
62
+
63
+ def level_str
64
+ return '' if level_int.nil?
65
+
66
+ if level_int <= 5
67
+ '=' * (level_int + 1)
68
+ else
69
+ '======'
70
+ end
71
+ end
72
+
73
+ def style_str
74
+ return '' if level_int.nil?
75
+
76
+ _style = [style]
77
+ _style << "level=#{level_int}" if level_int > 5
78
+ _style = _style.compact.join(',')
79
+
80
+ _style.empty? ? '' : "[#{_style}]\n"
81
+ end
82
+ end
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module AsciiDoc
5
+ module Model
6
+ class Video < Base
7
+ class AttributeList < Coradoc::AsciiDoc::Model::AttributeList
8
+ extend AttributeList::Matchers
9
+ def positional_validators
10
+ [
11
+ [:alt, String],
12
+ [:width, Integer],
13
+ [:height, Integer]
14
+ ]
15
+ end
16
+
17
+ def named_validators
18
+ {
19
+ title: String,
20
+ poster: String,
21
+ width: Integer,
22
+ height: Integer,
23
+ start: Integer,
24
+ end: Integer,
25
+ theme: one('dark', 'light'),
26
+ lang: /[a-z]{2,3}(?:-[A-Z]{2})?/,
27
+ list: String,
28
+ playlist: String,
29
+ options: many(
30
+ 'autoplay',
31
+ 'loop',
32
+ 'modest',
33
+ 'nocontrols',
34
+ 'nofullscreen',
35
+ 'muted'
36
+ )
37
+ }
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module AsciiDoc
5
+ module Model
6
+ # Video block element for AsciiDoc documents.
7
+ #
8
+ # Videos are embedded multimedia content with support for various
9
+ # video platforms and custom attributes.
10
+ #
11
+ # @!attribute [r] id
12
+ # @return [String, nil] Optional identifier for the video
13
+ #
14
+ # @!attribute [r] title
15
+ # @return [String, nil] Optional video title
16
+ #
17
+ # @!attribute [r] src
18
+ # @return [String] The video source URL or path
19
+ #
20
+ # @!attribute [r] attributes
21
+ # @return [Coradoc::AsciiDoc::Model::Video::AttributeList] Video-specific attributes
22
+ #
23
+ # @!attribute [r] line_break
24
+ # @return [String] Line break character (default: "\n")
25
+ #
26
+ # @example Create a video block
27
+ # video = Coradoc::AsciiDoc::Model::Video.new
28
+ # video.src = "https://example.com/video.mp4"
29
+ # video.title = "Demo Video"
30
+ #
31
+ class Video < Base
32
+ # Autoload nested AttributeList class
33
+ autoload :AttributeList, 'coradoc/asciidoc/model/video/attribute_list'
34
+
35
+ include Coradoc::AsciiDoc::Model::Anchorable
36
+
37
+ attribute :id, :string
38
+ attribute :title, :string
39
+ attribute :src, :string, default: -> { '' }
40
+ attribute :attributes,
41
+ Video::AttributeList,
42
+ default: lambda {
43
+ Coradoc::AsciiDoc::Model::AttributeList.new
44
+ }
45
+ attribute :line_break, :string, default: -> { "\n" }
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,75 @@
1
+ # frozen_string_literal: true
2
+
3
+ # IMPORTANT: Load Serialization module eagerly — it registers the asciidoc
4
+ # format with Lutaml::Model, which is needed before any model class can
5
+ # use the asciidoc DSL.
6
+ require_relative 'model/serialization'
7
+
8
+ module Coradoc
9
+ module AsciiDoc
10
+ module Model
11
+ # Base class for all AsciiDoc model classes (no side effects)
12
+ autoload :Base, "#{__dir__}/model/base"
13
+
14
+ # Layer 0: Mixins (no dependencies)
15
+ autoload :Anchorable, "#{__dir__}/model/anchorable"
16
+ autoload :Attached, "#{__dir__}/model/attached"
17
+ autoload :Spacing, "#{__dir__}/model/spacing"
18
+
19
+ # Layer 1: Simple types (only depend on Layer 0)
20
+ autoload :Attribute, "#{__dir__}/model/attribute"
21
+ autoload :AttributeListAttribute, "#{__dir__}/model/attribute_list_attribute"
22
+ autoload :NamedAttribute, "#{__dir__}/model/named_attribute"
23
+ autoload :RejectedPositionalAttribute, "#{__dir__}/model/rejected_positional_attribute"
24
+ autoload :AttributeList, "#{__dir__}/model/attribute_list"
25
+ autoload :Author, "#{__dir__}/model/author"
26
+ autoload :Revision, "#{__dir__}/model/revision"
27
+ autoload :Break, "#{__dir__}/model/break"
28
+ autoload :CommentBlock, "#{__dir__}/model/comment_block"
29
+ autoload :CommentLine, "#{__dir__}/model/comment_line"
30
+ autoload :Glossaries, "#{__dir__}/model/glossaries"
31
+ autoload :Include, "#{__dir__}/model/include"
32
+ autoload :Tag, "#{__dir__}/model/tag"
33
+
34
+ # Layer 2-3: Text types
35
+ autoload :TextElement, "#{__dir__}/model/text_element"
36
+ autoload :Admonition, "#{__dir__}/model/admonition"
37
+ autoload :Highlight, "#{__dir__}/model/highlight"
38
+ autoload :LineBreak, "#{__dir__}/model/line_break"
39
+ autoload :Title, "#{__dir__}/model/title"
40
+ autoload :Paragraph, "#{__dir__}/model/paragraph"
41
+
42
+ # Layer 4-5: Block and List types
43
+ autoload :Block, "#{__dir__}/model/block"
44
+ autoload :ContentList, "#{__dir__}/model/content_list"
45
+ autoload :Term, "#{__dir__}/model/term"
46
+ autoload :List, "#{__dir__}/model/list"
47
+
48
+ # Layer 6: Structural types
49
+ autoload :DocumentAttributes, "#{__dir__}/model/document_attributes"
50
+ autoload :Header, "#{__dir__}/model/header"
51
+ autoload :Section, "#{__dir__}/model/section"
52
+
53
+ # Layer 7-8: Content types
54
+ autoload :Audio, "#{__dir__}/model/audio"
55
+ autoload :BibliographyEntry, "#{__dir__}/model/bibliography_entry"
56
+ autoload :Bibliography, "#{__dir__}/model/bibliography"
57
+ autoload :Video, "#{__dir__}/model/video"
58
+ autoload :Image, "#{__dir__}/model/image"
59
+
60
+ # Layer 9: Table types
61
+ autoload :TableCell, "#{__dir__}/model/table_cell"
62
+ autoload :TableRow, "#{__dir__}/model/table_row"
63
+ autoload :Table, "#{__dir__}/model/table"
64
+
65
+ # Layer 10: Inline types
66
+ autoload :Inline, "#{__dir__}/model/inline"
67
+
68
+ # Layer 11: Complex types
69
+ autoload :ReviewerNote, "#{__dir__}/model/reviewer_note"
70
+
71
+ # Layer 12: Document
72
+ autoload :Document, "#{__dir__}/model/document"
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,161 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module AsciiDoc
5
+ # Custom error class for parsing failures
6
+ #
7
+ # Provides detailed context about where parsing failed, including
8
+ # line number, column position, and source snippet.
9
+ #
10
+ # @example Raising a parse error
11
+ # raise Coradoc::AsciiDoc::ParseError.new(
12
+ # "Unexpected token",
13
+ # line: 42,
14
+ # column: 10,
15
+ # source: "line with error",
16
+ # suggestion: "Did you mean X?"
17
+ # )
18
+ #
19
+ class ParseError < Error
20
+ # @return [Integer, nil] Line number where error occurred
21
+ attr_reader :line
22
+
23
+ # @return [Integer, nil] Column position where error occurred
24
+ attr_reader :column
25
+
26
+ # @return [String, nil] Source line containing the error
27
+ attr_reader :source_line
28
+
29
+ # @return [String, nil] Helpful suggestion for fixing the error
30
+ attr_reader :suggestion
31
+
32
+ # @return [String, nil] Full source content (for multi-line context)
33
+ attr_reader :source
34
+
35
+ # @return [Exception, nil] Original exception that caused this error
36
+ attr_reader :cause
37
+
38
+ # Create a new ParseError
39
+ #
40
+ # @param message [String] Error description
41
+ # @param line [Integer, nil] Line number (1-indexed)
42
+ # @param column [Integer, nil] Column position (1-indexed)
43
+ # @param source_line [String, nil] The source line containing the error
44
+ # @param source [String, nil] Full source content
45
+ # @param suggestion [String, nil] Suggestion for fixing the error
46
+ # @param cause [Exception, nil] Original exception that caused this error
47
+ def initialize(message, line: nil, column: nil, source_line: nil, source: nil, suggestion: nil, cause: nil)
48
+ @line = line
49
+ @column = column
50
+ @source_line = source_line
51
+ @source = source
52
+ @suggestion = suggestion
53
+ @cause = cause
54
+
55
+ full_message = build_full_message(message)
56
+ super(full_message)
57
+
58
+ set_backtrace(cause.backtrace) if cause&.backtrace
59
+ end
60
+
61
+ # Build a formatted error message with context
62
+ #
63
+ # @param base_message [String] The base error message
64
+ # @return [String] Formatted error message with location context
65
+ def build_full_message(base_message)
66
+ parts = [base_message]
67
+
68
+ if line && column
69
+ parts << "at line #{line}, column #{column}"
70
+ elsif line
71
+ parts << "at line #{line}"
72
+ end
73
+
74
+ if source_line
75
+ parts << "\n > #{source_line}"
76
+ parts << " > #{' ' * (column - 1)}^" if column&.positive?
77
+ end
78
+
79
+ parts << "\n Suggestion: #{suggestion}" if suggestion
80
+
81
+ parts.join("\n")
82
+ end
83
+
84
+ # Create a ParseError from a Parslet exception
85
+ #
86
+ # @param exception [Parslet::ParseFailed] The Parslet exception
87
+ # @param source [String] The original source text
88
+ # @return [ParseError] A new ParseError with extracted context
89
+ def self.from_parslet(exception, source = nil)
90
+ return exception if exception.is_a?(ParseError)
91
+
92
+ line, column = extract_location(exception)
93
+ source_line = extract_source_line(source, line)
94
+ suggestion = generate_suggestion(exception)
95
+
96
+ new(
97
+ exception.message,
98
+ line: line,
99
+ column: column,
100
+ source_line: source_line,
101
+ source: source,
102
+ suggestion: suggestion,
103
+ cause: exception
104
+ )
105
+ rescue StandardError
106
+ # If we can't extract details, wrap the original exception
107
+ new(exception.message, cause: exception)
108
+ end
109
+
110
+ # Extract line and column from Parslet error
111
+ #
112
+ # @param exception [Parslet::ParseFailed] The Parslet exception
113
+ # @return [Array<Integer, Integer>] Line and column numbers
114
+ def self.extract_location(exception)
115
+ return [nil, nil] unless exception.is_a?(Parslet::ParseFailed)
116
+
117
+ cause = exception.cause
118
+ return [nil, nil] unless cause
119
+
120
+ [cause.source_line, cause.source_column]
121
+ rescue NoMethodError
122
+ [nil, nil]
123
+ end
124
+
125
+ # Extract the relevant source line
126
+ #
127
+ # @param source [String, nil] Full source text
128
+ # @param line [Integer, nil] Line number
129
+ # @return [String, nil] The source line
130
+ def self.extract_source_line(source, line)
131
+ return nil if source.nil? || line.nil?
132
+
133
+ lines = source.split("\n")
134
+ lines[line - 1] if line.positive? && line <= lines.length
135
+ end
136
+
137
+ # Generate a helpful suggestion based on the error
138
+ #
139
+ # @param exception [Exception] The parsing exception
140
+ # @return [String, nil] A suggestion string
141
+ def self.generate_suggestion(exception)
142
+ message = exception.message.to_s.downcase
143
+
144
+ case message
145
+ when /expected.*heading/
146
+ "Make sure headings start with '=' followed by a space"
147
+ when /expected.*list/
148
+ "List items should start with '*', '.', or a term followed by '::'"
149
+ when /expected.*table/
150
+ "Tables require '|===' delimiters and '|' for cell separators"
151
+ when /expected.*block/
152
+ 'Block delimiters should be 4 identical characters (----, ====, etc.)'
153
+ when /expected.*attribute/
154
+ "Attributes should be in the format ':name: value'"
155
+ when /unexpected.*end/
156
+ 'Check for missing closing delimiters or incomplete syntax'
157
+ end
158
+ end
159
+ end
160
+ end
161
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module AsciiDoc
5
+ module Parser
6
+ module Admonition
7
+ def admonition_type
8
+ str('NOTE') | str('TIP') | str('EDITOR') |
9
+ str('IMPORTANT') | str('WARNING') | str('CAUTION') |
10
+ str('TODO')
11
+ # requires atypical syntax for access?
12
+ # | str('DANGER')
13
+ # | str('SAFETY PRECAUTION')
14
+ end
15
+
16
+ def admonition_line
17
+ admonition_type.as(:admonition_type) >> str(': ') >>
18
+ (text.as(:text) >>
19
+ line_ending.as(:line_break)
20
+ ).repeat(1)
21
+ .as(:content)
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,110 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module AsciiDoc
5
+ module Parser
6
+ module AttributeList
7
+ def named_attribute_name
8
+ attribute_name
9
+ end
10
+
11
+ def named_value_noquote
12
+ match('[^\],]').repeat(1)
13
+ end
14
+
15
+ def named_value_single_quote
16
+ str("'") >>
17
+ match("[^']").repeat(1) >>
18
+ str("'")
19
+ end
20
+
21
+ def named_value_double_quote
22
+ str('"') >>
23
+ match('[^"]').repeat(1) >>
24
+ str('"')
25
+ end
26
+
27
+ def named_value
28
+ (named_value_single_quote |
29
+ named_value_double_quote |
30
+ named_value_noquote
31
+ ).as(:named_value)
32
+ end
33
+
34
+ def named_key
35
+ match('[a-zA-Z0-9_-]').repeat(1).as(:named_key)
36
+ end
37
+
38
+ def named_attribute
39
+ (named_key >>
40
+ str(' ').maybe >> str('=') >> str(' ').maybe >>
41
+ named_value >>
42
+ str(' ').maybe
43
+ ).as(:named)
44
+ end
45
+
46
+ def positional_value_unquoted
47
+ match['a-zA-Z0-9_\-%.'].repeat(1)
48
+ end
49
+
50
+ def positional_value_single_quote
51
+ str("'") >>
52
+ match("[^']").repeat(1) >>
53
+ str("'")
54
+ end
55
+
56
+ def positional_value_double_quote
57
+ str('"') >>
58
+ match('[^"]').repeat(1) >>
59
+ str('"')
60
+ end
61
+
62
+ def positional_attribute
63
+ ((positional_value_single_quote |
64
+ positional_value_double_quote |
65
+ positional_value_unquoted
66
+ ) >>
67
+ str('=').absent?
68
+ ).as(:positional)
69
+ end
70
+
71
+ def named_many
72
+ (named_attribute.repeat(1, 1) >>
73
+ (str(',') >> space.maybe >> named_attribute).repeat(0))
74
+ end
75
+
76
+ def positional_one_named_many
77
+ (positional_attribute.repeat(1, 1) >>
78
+ (str(',') >> space.maybe >> named_attribute).repeat(1))
79
+ end
80
+
81
+ def positional_many_named_many
82
+ (positional_attribute.repeat(1, 1) >>
83
+ (str(',') >> space.maybe >> positional_attribute).repeat(1) >>
84
+ (str(',') >> space.maybe >> named_attribute).repeat(1))
85
+ end
86
+
87
+ def positional_many
88
+ (positional_attribute.repeat(1, 1) >>
89
+ (str(',') >> space.maybe >> positional_attribute).repeat(0))
90
+ end
91
+
92
+ def positional_zero_or_one
93
+ positional_attribute.repeat(0, 1)
94
+ end
95
+
96
+ def attribute_list(name = :attribute_list)
97
+ str('[').present? >>
98
+ str('[') >> str('[').absent? >>
99
+ (named_many |
100
+ positional_one_named_many |
101
+ positional_many_named_many |
102
+ positional_many |
103
+ positional_zero_or_one
104
+ ).as(:attribute_array).as(name) >>
105
+ str(']')
106
+ end
107
+ end
108
+ end
109
+ end
110
+ end