coradoc-markdown 1.0.0 → 1.0.3

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 (102) hide show
  1. checksums.yaml +4 -4
  2. data/lib/coradoc/markdown/model/admonition.rb +35 -0
  3. data/lib/coradoc/markdown/model/attribute_list.rb +5 -16
  4. data/lib/coradoc/markdown/model/base.rb +2 -34
  5. data/lib/coradoc/markdown/model/comment.rb +14 -0
  6. data/lib/coradoc/markdown/model/cross_reference.rb +10 -0
  7. data/lib/coradoc/markdown/model/definition_list.rb +0 -12
  8. data/lib/coradoc/markdown/model/definition_term.rb +16 -6
  9. data/lib/coradoc/markdown/model/document.rb +9 -0
  10. data/lib/coradoc/markdown/model/example_block.rb +26 -0
  11. data/lib/coradoc/markdown/model/extension.rb +9 -18
  12. data/lib/coradoc/markdown/model/footnote_reference.rb +0 -5
  13. data/lib/coradoc/markdown/model/hard_line_break.rb +21 -0
  14. data/lib/coradoc/markdown/model/highlight.rb +0 -5
  15. data/lib/coradoc/markdown/model/horizontal_rule.rb +1 -6
  16. data/lib/coradoc/markdown/model/list_item.rb +1 -1
  17. data/lib/coradoc/markdown/model/literal.rb +21 -0
  18. data/lib/coradoc/markdown/model/math.rb +0 -14
  19. data/lib/coradoc/markdown/model/named_value.rb +18 -0
  20. data/lib/coradoc/markdown/model/open_block.rb +22 -0
  21. data/lib/coradoc/markdown/model/paragraph.rb +2 -2
  22. data/lib/coradoc/markdown/model/pass.rb +21 -0
  23. data/lib/coradoc/markdown/model/sidebar.rb +22 -0
  24. data/lib/coradoc/markdown/model/strikethrough.rb +0 -5
  25. data/lib/coradoc/markdown/model/subscript.rb +9 -0
  26. data/lib/coradoc/markdown/model/superscript.rb +9 -0
  27. data/lib/coradoc/markdown/model/underline.rb +9 -0
  28. data/lib/coradoc/markdown/model/verse.rb +27 -0
  29. data/lib/coradoc/markdown/parser/block_parser.rb +1 -1
  30. data/lib/coradoc/markdown/parser/frontmatter_parser.rb +23 -0
  31. data/lib/coradoc/markdown/serializer/builder.rb +57 -0
  32. data/lib/coradoc/markdown/serializer/config.rb +77 -0
  33. data/lib/coradoc/markdown/serializer/context.rb +66 -0
  34. data/lib/coradoc/markdown/serializer/element_serializer.rb +46 -0
  35. data/lib/coradoc/markdown/serializer/flavor.rb +82 -0
  36. data/lib/coradoc/markdown/serializer/registrations.rb +111 -0
  37. data/lib/coradoc/markdown/serializer/registry.rb +62 -0
  38. data/lib/coradoc/markdown/serializer/runner.rb +84 -0
  39. data/lib/coradoc/markdown/serializer/serializers/abbreviation.rb +19 -0
  40. data/lib/coradoc/markdown/serializer/serializers/admonition.rb +20 -0
  41. data/lib/coradoc/markdown/serializer/serializers/attribute_list.rb +25 -0
  42. data/lib/coradoc/markdown/serializer/serializers/blockquote.rb +19 -0
  43. data/lib/coradoc/markdown/serializer/serializers/code.rb +19 -0
  44. data/lib/coradoc/markdown/serializer/serializers/code_block.rb +19 -0
  45. data/lib/coradoc/markdown/serializer/serializers/comment.rb +31 -0
  46. data/lib/coradoc/markdown/serializer/serializers/cross_reference.rb +19 -0
  47. data/lib/coradoc/markdown/serializer/serializers/definition_list.rb +20 -0
  48. data/lib/coradoc/markdown/serializer/serializers/document.rb +22 -0
  49. data/lib/coradoc/markdown/serializer/serializers/emphasis.rb +19 -0
  50. data/lib/coradoc/markdown/serializer/serializers/example_block.rb +40 -0
  51. data/lib/coradoc/markdown/serializer/serializers/extension.rb +30 -0
  52. data/lib/coradoc/markdown/serializer/serializers/footnote.rb +20 -0
  53. data/lib/coradoc/markdown/serializer/serializers/footnote_reference.rb +19 -0
  54. data/lib/coradoc/markdown/serializer/serializers/hard_line_break.rb +22 -0
  55. data/lib/coradoc/markdown/serializer/serializers/heading.rb +19 -0
  56. data/lib/coradoc/markdown/serializer/serializers/highlight.rb +19 -0
  57. data/lib/coradoc/markdown/serializer/serializers/horizontal_rule.rb +19 -0
  58. data/lib/coradoc/markdown/serializer/serializers/image.rb +19 -0
  59. data/lib/coradoc/markdown/serializer/serializers/link.rb +29 -0
  60. data/lib/coradoc/markdown/serializer/serializers/list.rb +45 -0
  61. data/lib/coradoc/markdown/serializer/serializers/literal.rb +21 -0
  62. data/lib/coradoc/markdown/serializer/serializers/math.rb +23 -0
  63. data/lib/coradoc/markdown/serializer/serializers/open_block.rb +38 -0
  64. data/lib/coradoc/markdown/serializer/serializers/paragraph.rb +23 -0
  65. data/lib/coradoc/markdown/serializer/serializers/pass.rb +21 -0
  66. data/lib/coradoc/markdown/serializer/serializers/sidebar.rb +20 -0
  67. data/lib/coradoc/markdown/serializer/serializers/strikethrough.rb +19 -0
  68. data/lib/coradoc/markdown/serializer/serializers/strong.rb +19 -0
  69. data/lib/coradoc/markdown/serializer/serializers/subscript.rb +19 -0
  70. data/lib/coradoc/markdown/serializer/serializers/superscript.rb +19 -0
  71. data/lib/coradoc/markdown/serializer/serializers/table.rb +37 -0
  72. data/lib/coradoc/markdown/serializer/serializers/underline.rb +19 -0
  73. data/lib/coradoc/markdown/serializer/serializers/verse.rb +31 -0
  74. data/lib/coradoc/markdown/serializer/strategies/admonition/base.rb +30 -0
  75. data/lib/coradoc/markdown/serializer/strategies/admonition/container.rb +34 -0
  76. data/lib/coradoc/markdown/serializer/strategies/admonition/gfm_alert.rb +28 -0
  77. data/lib/coradoc/markdown/serializer/strategies/admonition/github.rb +29 -0
  78. data/lib/coradoc/markdown/serializer/strategies/admonition/html.rb +25 -0
  79. data/lib/coradoc/markdown/serializer/strategies/admonition/registry.rb +50 -0
  80. data/lib/coradoc/markdown/serializer/strategies/autolink/angle.rb +35 -0
  81. data/lib/coradoc/markdown/serializer/strategies/autolink/bare.rb +23 -0
  82. data/lib/coradoc/markdown/serializer/strategies/autolink/base.rb +33 -0
  83. data/lib/coradoc/markdown/serializer/strategies/autolink/none.rb +27 -0
  84. data/lib/coradoc/markdown/serializer/strategies/autolink/registry.rb +58 -0
  85. data/lib/coradoc/markdown/serializer/strategies/definition_list/base.rb +37 -0
  86. data/lib/coradoc/markdown/serializer/strategies/definition_list/flat.rb +48 -0
  87. data/lib/coradoc/markdown/serializer/strategies/definition_list/nested_html.rb +54 -0
  88. data/lib/coradoc/markdown/serializer/strategies/definition_list/registry.rb +37 -0
  89. data/lib/coradoc/markdown/serializer.rb +30 -181
  90. data/lib/coradoc/markdown/toc_generator.rb +2 -8
  91. data/lib/coradoc/markdown/transform/block_transformer.rb +163 -0
  92. data/lib/coradoc/markdown/transform/from_core_model.rb +205 -40
  93. data/lib/coradoc/markdown/transform/image_transformer.rb +20 -0
  94. data/lib/coradoc/markdown/transform/inline_transformer.rb +74 -0
  95. data/lib/coradoc/markdown/transform/list_transformer.rb +52 -0
  96. data/lib/coradoc/markdown/transform/structural_transformer.rb +94 -0
  97. data/lib/coradoc/markdown/transform/table_transformer.rb +40 -0
  98. data/lib/coradoc/markdown/transform/to_core_model.rb +36 -30
  99. data/lib/coradoc/markdown/transformer.rb +87 -2
  100. data/lib/coradoc/markdown/version.rb +1 -1
  101. data/lib/coradoc/markdown.rb +23 -20
  102. metadata +89 -10
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e985a5efd633ee5e945c01d6f9465316f36ed682e8a65fa1c6c33304f8af453c
4
- data.tar.gz: ece9f3be5276f6ef0c1c325fa59a3f43452472b8aa5e2350ad690381b5b7a173
3
+ metadata.gz: e84594b2f47a9d07086b781a843c5b1f7b2ddb34303bbe32114ea1c9e7ac1aec
4
+ data.tar.gz: 7fd311efb6eef499247c37bacb8357d3b6349eabc1347c6a875d21c6b315fa18
5
5
  SHA512:
6
- metadata.gz: 531bc6952f8a55ccbd3b86190ced905b60242bebe6dd65873fee5cc0715fcdaa802147473fb897fb818bdec611937e48eb3b995db4844cd4c7c08a4f575bdbf7
7
- data.tar.gz: 022055b32982e6a661bcbcca4e6044e8ccb4f36d265d7f4bbe1575c07e9a424acb711d8dc532a8ba49bc4afd2d56423f0c9be127bb9a996d1cdd5c9e1e738d26
6
+ metadata.gz: ee32797ed75c3659d6e21fd9041d4f9a193497c50417f1f2ca986bd23459bf83b5a3cab47540f417d34014d806b1f20671e132ca4b0c0195b7b23870cb4aff37
7
+ data.tar.gz: 2cfc83d2fa5c1e732283d6efa0d37f05b5f9ea4c8970217f64cbb6771084c4aa2f6fa0aaaba4049aceb9ed9fb611d6395d210a5c8ce8c199a3bbf1768e4d4665
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'base'
4
+
5
+ module Coradoc
6
+ module Markdown
7
+ # Admonition block — a callout like NOTE, WARNING, TIP, etc.
8
+ #
9
+ # Markdown has no native admonition syntax (GFM Alerts since Dec 2023
10
+ # notwithstanding — see admonition/gfm_alert strategy). The
11
+ # `admonition_style` config option selects the output form:
12
+ #
13
+ # :github → > **NOTE:** text (broad compat)
14
+ # :gfm_alert → > [!NOTE]\n> text (GFM native since 2024)
15
+ # :container → :::note\n... \n::: (VitePress / markdown-it)
16
+ # :html → <div class="note">...</div>
17
+ #
18
+ # Type is stored lowercase. Content is raw Markdown text (already
19
+ # serialized). Title is optional.
20
+ class Admonition < Base
21
+ ALLOWED_TYPES = %w[note tip warning important caution].freeze
22
+
23
+ attribute :admonition_type, :string
24
+ attribute :content, :string
25
+ attribute :title, :string
26
+
27
+ def initialize(admonition_type:, content:, title: nil, **rest)
28
+ super
29
+ @admonition_type = admonition_type.to_s.downcase
30
+ @content = content
31
+ @title = title
32
+ end
33
+ end
34
+ end
35
+ end
@@ -16,7 +16,7 @@ module Coradoc
16
16
  class AttributeList < Base
17
17
  attribute :id, :string
18
18
  attribute :classes, :string, collection: true, default: []
19
- attribute :attributes, :hash, default: {}
19
+ attribute :attributes, NamedValue, collection: true, default: []
20
20
  attribute :name, :string # For ALD - the reference name
21
21
 
22
22
  # Parse an IAL string into an AttributeList
@@ -50,7 +50,9 @@ module Coradoc
50
50
 
51
51
  self.id = other.id if other.id
52
52
  self.classes = (classes + other.classes).uniq
53
- self.attributes = attributes.merge(other.attributes)
53
+ merged = {}
54
+ (attributes + other.attributes).each { |nv| merged[nv.name] = nv }
55
+ self.attributes = merged.values
54
56
  self
55
57
  end
56
58
 
@@ -67,19 +69,6 @@ module Coradoc
67
69
  id.nil? && classes.empty? && attributes.empty?
68
70
  end
69
71
 
70
- # Convert to Markdown IAL syntax
71
- # @return [String]
72
- def to_md
73
- return '' if empty?
74
-
75
- parts = []
76
- parts << "##{id}" if id
77
- parts += classes.map { |c| ".#{c}" }
78
- parts += attributes.map { |k, v| %(#{k}="#{v}") }
79
-
80
- "{:#{parts.join(' ')}}"
81
- end
82
-
83
72
  def self.parse_attributes(content, attr_list)
84
73
  # Use shared IalParser for consistent parsing
85
74
  ParserUtil::IalParser.tokenize(content).each do |token|
@@ -89,7 +78,7 @@ module Coradoc
89
78
  when :id
90
79
  attr_list.id = token[:value]
91
80
  when :attribute
92
- attr_list.attributes[token[:key]] = token[:value]
81
+ attr_list.attributes << NamedValue.new(name: token[:key], value: token[:value])
93
82
  end
94
83
  end
95
84
  end
@@ -18,8 +18,8 @@ module Coradoc
18
18
  # Classes from IAL (for convenience)
19
19
  attribute :classes, :string, collection: true
20
20
 
21
- # Additional attributes from IAL
22
- attribute :attributes, :hash, default: {}
21
+ # Additional attributes from IAL (typed key-value pairs)
22
+ attribute :attributes, NamedValue, collection: true, default: []
23
23
 
24
24
  # Visit pattern for traversing the document tree
25
25
  def self.visit(element, &block)
@@ -49,38 +49,6 @@ module Coradoc
49
49
  end
50
50
  self
51
51
  end
52
-
53
- # Serialize polymorphic content to Markdown string
54
- def serialize_content(content)
55
- case content
56
- when Array
57
- content.map { |elem| serialize_content(elem) }.join
58
- when String
59
- content
60
- when nil
61
- ''
62
- else
63
- if content.is_a?(Base)
64
- content.to_md
65
- else
66
- raise ArgumentError,
67
- "Cannot serialize #{content.class.name} to Markdown. " \
68
- 'Expected String or Base subclass.'
69
- end
70
- end
71
- end
72
-
73
- # Does a shallow attribute dump of the object
74
- def to_h
75
- self.class.attributes.keys.each_with_object({}) do |attribute, acc|
76
- acc[attribute] = public_send(attribute)
77
- end
78
- end
79
-
80
- # Serialize this model element to Markdown
81
- def to_md
82
- Coradoc::Markdown::Serializer.serialize(self)
83
- end
84
52
  end
85
53
  end
86
54
  end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module Markdown
5
+ # HTML comment in Markdown source (`<!-- text -->`).
6
+ #
7
+ # Markdown has no native comment syntax; HTML comments are the conventional
8
+ # mechanism for non-rendered authoring notes. Both AsciiDoc single-line
9
+ # (`//`) and block (`//// ... ////`) comments collapse to this type.
10
+ class Comment < Base
11
+ attribute :text, :string
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module Markdown
5
+ class CrossReference < Base
6
+ attribute :text, :string
7
+ attribute :target, :string
8
+ end
9
+ end
10
+ end
@@ -30,18 +30,6 @@ module Coradoc
30
30
  class DefinitionList < Base
31
31
  # Terms with their definitions
32
32
  attribute :items, Coradoc::Markdown::DefinitionTerm, collection: true
33
-
34
- # Serialize to Markdown
35
- def to_md
36
- items.map do |term|
37
- term_text = term.text.to_s
38
- defs = term.definitions.map do |defn|
39
- content = defn.content.to_s
40
- ": #{content}"
41
- end.join("\n")
42
- "#{term_text}\n#{defs}"
43
- end.join("\n\n")
44
- end
45
33
  end
46
34
  end
47
35
  end
@@ -7,15 +7,25 @@ module Coradoc
7
7
  # A term can have multiple definitions and can span multiple lines.
8
8
  # Terms can also have IAL attributes attached.
9
9
  #
10
- # @example Simple term
11
- # term = Coradoc::Markdown::DefinitionTerm.new(text: "kramdown")
12
- #
10
+ # A term can carry a nested DefinitionList when the original document
11
+ # had structured sub-entries (e.g. glossary sub-terms). When `nested`
12
+ # is present, the serializer's nested_html strategy kicks in to emit
13
+ # HTML `<dl>` structure that Markdown syntax cannot express.
13
14
  class DefinitionTerm < Base
14
- # The term text content
15
15
  attribute :text, :string
16
-
17
- # Definitions for this term
18
16
  attribute :definitions, Coradoc::Markdown::DefinitionItem, collection: true, default: []
17
+
18
+ # Optional nested definition list under this term.
19
+ # When present, the flat-PHP-Markdown-Extra syntax is no longer
20
+ # sufficient and the serializer falls back to HTML <dl>/<dt>/<dd>.
21
+ attribute :nested, Coradoc::Markdown::DefinitionList
22
+
23
+ def initialize(text: '', definitions: [], nested: nil, **rest)
24
+ super
25
+ @text = text
26
+ @definitions = definitions
27
+ @nested = nested
28
+ end
19
29
  end
20
30
  end
21
31
  end
@@ -18,6 +18,15 @@ module Coradoc
18
18
  class Document < Base
19
19
  attribute :blocks, Coradoc::Markdown::Base, collection: true
20
20
 
21
+ # Raw YAML frontmatter text, or nil if absent.
22
+ #
23
+ # Markdown treats frontmatter as opaque text — the YAML is only
24
+ # parsed/emitted at the CoreModel boundary by
25
+ # CoreModel::FrontmatterBlock::Codec (single source of truth).
26
+ # Storing raw text keeps Markdown's parser/serializer symmetric
27
+ # without dragging YAML semantics into the Markdown model (MECE).
28
+ attribute :frontmatter, :string
29
+
21
30
  # @param [Integer] index The index of the block to retrieve
22
31
  # @return [Coradoc::Markdown::Base] The block at the specified index
23
32
  def [](index)
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'base'
4
+
5
+ module Coradoc
6
+ module Markdown
7
+ # Example block — an illustrative container, optionally with a caption.
8
+ #
9
+ # Markdown has no native example syntax. Default rendering is an
10
+ # HTML fallback that preserves the caption as an `<h4>` heading
11
+ # inside a `<div class="example">` wrapper.
12
+ #
13
+ # When `admonition_style == :container` (VitePress), the serializer
14
+ # emits `:::details Caption\n...\n:::`.
15
+ class ExampleBlock < Base
16
+ attribute :content, :string
17
+ attribute :caption, :string
18
+
19
+ def initialize(content:, caption: nil, **rest)
20
+ super
21
+ @content = content
22
+ @caption = caption
23
+ end
24
+ end
25
+ end
26
+ end
@@ -13,7 +13,7 @@ module Coradoc
13
13
  #
14
14
  class Extension < Base
15
15
  attribute :name, :string
16
- attribute :options, :hash, default: {}
16
+ attribute :options, NamedValue, collection: true, default: []
17
17
  attribute :content, :string # For block extensions with content
18
18
  attribute :body, :string # Alias for content
19
19
 
@@ -32,14 +32,14 @@ module Coradoc
32
32
  # @param options [Hash] TOC options (levels, etc.)
33
33
  # @return [Extension]
34
34
  def self.toc(options = {})
35
- new(name: :toc, options: options)
35
+ new(name: :toc, options: hash_to_named(options))
36
36
  end
37
37
 
38
38
  # Create an options extension
39
39
  # @param options [Hash] Parser options
40
40
  # @return [Extension]
41
41
  def self.options(options = {})
42
- new(name: :options, options: options)
42
+ new(name: :options, options: hash_to_named(options))
43
43
  end
44
44
 
45
45
  # Create a comment extension
@@ -69,23 +69,14 @@ module Coradoc
69
69
  content.nil? || content.empty?
70
70
  end
71
71
 
72
- # Convert to Markdown
73
- # @return [String]
74
- def to_md
75
- opts = options.empty? ? '' : " #{options_to_s}"
76
- if self_closing?
77
- "{::#{name}#{opts} /}"
78
- else
79
- "{::#{name}#{opts}}#{content}{:/}"
80
- end
81
- end
72
+ class << self
73
+ private
82
74
 
83
- private
75
+ def hash_to_named(hash)
76
+ return [] if hash.nil? || hash.empty?
84
77
 
85
- def options_to_s
86
- options.map do |k, v|
87
- %(#{k}="#{v}")
88
- end.join(' ')
78
+ hash.map { |k, v| NamedValue.new(name: k.to_s, value: v.to_s) }
79
+ end
89
80
  end
90
81
  end
91
82
  end
@@ -12,11 +12,6 @@ module Coradoc
12
12
  class FootnoteReference < Base
13
13
  # The footnote identifier
14
14
  attribute :id, :string
15
-
16
- # Serialize to Markdown
17
- def to_md
18
- "[^#{id}]"
19
- end
20
15
  end
21
16
  end
22
17
  end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'base'
4
+
5
+ module Coradoc
6
+ module Markdown
7
+ # Hard line break — forces a line break within a paragraph, distinct
8
+ # from a new paragraph.
9
+ #
10
+ # Two strategy modes (configurable via the serializer config):
11
+ # - `:trailing_space` (CommonMark default): two trailing spaces
12
+ # - `:backslash` (GFM alternative): backslash before newline
13
+ #
14
+ # AsciiDoc `+` line-continuation maps to this element.
15
+ class HardLineBreak < Base
16
+ def initialize(**_rest)
17
+ super
18
+ end
19
+ end
20
+ end
21
+ end
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
-
4
3
  module Coradoc
5
4
  module Markdown
6
5
  # Represents highlighted text using == syntax (extended Markdown).
@@ -9,10 +8,6 @@ module Coradoc
9
8
  #
10
9
  class Highlight < Base
11
10
  attribute :text, :string
12
-
13
- def to_md
14
- "==#{text}=="
15
- end
16
11
  end
17
12
  end
18
13
  end
@@ -5,12 +5,7 @@ module Coradoc
5
5
  # HorizontalRule model representing a Markdown horizontal rule (---, ***, ___).
6
6
  #
7
7
  class HorizontalRule < Base
8
- attribute :style, :string, default: '---' # ---, ***, or ___
9
-
10
- def initialize(style: '---')
11
- super()
12
- @style = style
13
- end
8
+ attribute :style, :string, default: '---'
14
9
  end
15
10
  end
16
11
  end
@@ -18,7 +18,7 @@ module Coradoc
18
18
  @text = args[:text] || ''
19
19
  @checked = args[:checked]
20
20
  @sublist = args[:sublist]
21
- @children = args[:children] || []
21
+ @children = args.fetch(:children, [])
22
22
  end
23
23
 
24
24
  def children=(value)
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'base'
4
+
5
+ module Coradoc
6
+ module Markdown
7
+ # Literal block — preformatted text with no syntax highlighting and
8
+ # no inline formatting. Distinct from a code block (which carries a
9
+ # language for highlighting).
10
+ #
11
+ # Markdown: indented code block (4 leading spaces per line).
12
+ class Literal < Base
13
+ attribute :content, :string
14
+
15
+ def initialize(content:, **rest)
16
+ super
17
+ @content = content
18
+ end
19
+ end
20
+ end
21
+ end
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
-
4
3
  module Coradoc
5
4
  module Markdown
6
5
  # Represents a math block (block or inline)
@@ -29,22 +28,9 @@ module Coradoc
29
28
  new(content: content, inline: true)
30
29
  end
31
30
 
32
- # Create a block math element
33
- # @param content [String] The math content
34
- # @return [Math]
35
31
  def self.block(content)
36
32
  new(content: content, inline: false)
37
33
  end
38
-
39
- # Convert to Markdown
40
- # @return [String]
41
- def to_md
42
- if inline?
43
- "$$#{content}$$"
44
- else
45
- "$$\n#{content}\n$$"
46
- end
47
- end
48
34
  end
49
35
  end
50
36
  end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module Markdown
5
+ # A typed key-value pair used wherever Markdown models need arbitrary
6
+ # attributes (IAL key="value" pairs, extension options, etc.).
7
+ #
8
+ # Replaces raw Hash attributes so that every attribute on a model is
9
+ # a typed lutaml-model declaration.
10
+ #
11
+ # @example
12
+ # NamedValue.new(name: "data-role", value: "main")
13
+ class NamedValue < Base
14
+ attribute :name, :string
15
+ attribute :value, :string
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'base'
4
+
5
+ module Coradoc
6
+ module Markdown
7
+ # Open block — generic container that groups content without semantic
8
+ # formatting. Used in AsciiDoc to apply IDs/attributes to a group.
9
+ #
10
+ # Markdown has no native container. The serializer's OpenBlock strategy:
11
+ # - Without id/classes → emit children as siblings (no wrapper)
12
+ # - With id/classes → emit `<div id="...">...</div>` wrapper
13
+ class OpenBlock < Base
14
+ attribute :children, Coradoc::Markdown::Base, collection: true, default: []
15
+
16
+ def initialize(children: [], **rest)
17
+ super
18
+ @children = Array(children)
19
+ end
20
+ end
21
+ end
22
+ end
@@ -14,10 +14,10 @@ module Coradoc
14
14
  # @return [Array] mixed content array
15
15
  attr_reader :children
16
16
 
17
- def initialize(text: '', children: nil)
17
+ def initialize(text: '', children: [])
18
18
  super()
19
19
  @text = text
20
- @children = children || []
20
+ @children = children
21
21
  end
22
22
 
23
23
  def children=(value)
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'base'
4
+
5
+ module Coradoc
6
+ module Markdown
7
+ # Pass block — raw content passed through verbatim, never rendered as
8
+ # Markdown. Used for embedding HTML or other markup directly.
9
+ #
10
+ # Markdown has no native pass concept; the content is emitted as-is
11
+ # inside a `nomarkdown` kramdown extension or raw HTML passthrough.
12
+ class Pass < Base
13
+ attribute :content, :string
14
+
15
+ def initialize(content:, **rest)
16
+ super
17
+ @content = content
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'base'
4
+
5
+ module Coradoc
6
+ module Markdown
7
+ # Sidebar block — a tangential aside, visually distinct from main flow.
8
+ #
9
+ # Markdown has no native sidebar. Serialized as an HTML fallback:
10
+ # <div class="sidebar">...</div>
11
+ class Sidebar < Base
12
+ attribute :content, :string
13
+ attribute :title, :string
14
+
15
+ def initialize(content:, title: nil, **rest)
16
+ super
17
+ @content = content
18
+ @title = title
19
+ end
20
+ end
21
+ end
22
+ end
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
-
4
3
  module Coradoc
5
4
  module Markdown
6
5
  # Represents strikethrough text using GFM ~~ syntax.
@@ -9,10 +8,6 @@ module Coradoc
9
8
  #
10
9
  class Strikethrough < Base
11
10
  attribute :text, :string
12
-
13
- def to_md
14
- "~~#{text}~~"
15
- end
16
11
  end
17
12
  end
18
13
  end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module Markdown
5
+ class Subscript < Base
6
+ attribute :text, :string
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module Markdown
5
+ class Superscript < Base
6
+ attribute :text, :string
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module Markdown
5
+ class Underline < Base
6
+ attribute :text, :string
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'base'
4
+
5
+ module Coradoc
6
+ module Markdown
7
+ # Verse block — preformatted text preserving line breaks but allowing
8
+ # inline formatting. Distinct from a literal block (no formatting)
9
+ # or a code block (no formatting + language hint).
10
+ #
11
+ # Markdown has no native verse. Serialized as a blockquote with the
12
+ # understanding that verse semantics are lost but line breaks are
13
+ # preserved via hard line breaks.
14
+ class Verse < Base
15
+ attribute :content, :string
16
+ attribute :attribution, :string
17
+ attribute :citetitle, :string
18
+
19
+ def initialize(content:, attribution: nil, citetitle: nil, **rest)
20
+ super
21
+ @content = content
22
+ @attribution = attribution
23
+ @citetitle = citetitle
24
+ end
25
+ end
26
+ end
27
+ end
@@ -424,7 +424,7 @@ module Coradoc
424
424
  table_separator_row.as(:table_separator) >>
425
425
  line_ending >>
426
426
  (
427
- table_row.as(:table_body_row) >> line_ending
427
+ table_row.as(:table_body_row) >> (line_ending | any.absent?)
428
428
  ).repeat(1).as(:table_body)
429
429
  end
430
430
 
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module Markdown
5
+ module Parser
6
+ # Markdown frontmatter extractor.
7
+ #
8
+ # Delegates to the shared +Coradoc::CoreModel::FrontmatterBlock::TextSplitter+
9
+ # — the single source of truth for the `---\n...\n---\n` convention
10
+ # (DRY). Format gems retain a local parser module for discoverability
11
+ # and as the seam for any format-specific extensions should they arise.
12
+ module FrontmatterParser
13
+ class << self
14
+ def call(text)
15
+ Coradoc::CoreModel::FrontmatterBlock::TextSplitter.call(text)
16
+ end
17
+ end
18
+
19
+ Result = Coradoc::CoreModel::FrontmatterBlock::TextSplitter::Result
20
+ end
21
+ end
22
+ end
23
+ end