coradoc-adoc 2.0.32 → 2.0.34

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 (34) hide show
  1. checksums.yaml +4 -4
  2. data/lib/coradoc/asciidoc/model/admonition.rb +0 -1
  3. data/lib/coradoc/asciidoc/model/attribute.rb +1 -1
  4. data/lib/coradoc/asciidoc/model/base.rb +1 -1
  5. data/lib/coradoc/asciidoc/model/bibliography_entry.rb +1 -1
  6. data/lib/coradoc/asciidoc/model/reviewer_note.rb +0 -2
  7. data/lib/coradoc/asciidoc/model/title.rb +1 -1
  8. data/lib/coradoc/asciidoc/parse_error.rb +6 -6
  9. data/lib/coradoc/asciidoc/parser/base.rb +18 -5
  10. data/lib/coradoc/asciidoc/parser/block.rb +1 -1
  11. data/lib/coradoc/asciidoc/parser/block_header.rb +8 -8
  12. data/lib/coradoc/asciidoc/parser/list.rb +48 -18
  13. data/lib/coradoc/asciidoc/parser/rule_dispatcher.rb +7 -7
  14. data/lib/coradoc/asciidoc/parser/text.rb +20 -0
  15. data/lib/coradoc/asciidoc/transform/element_transformers/list_transformer.rb +5 -2
  16. data/lib/coradoc/asciidoc/transform/text_extract_visitor.rb +3 -3
  17. data/lib/coradoc/asciidoc/transform/to_core_model.rb +2 -2
  18. data/lib/coradoc/asciidoc/transformer/attribute_list_normalizer.rb +2 -2
  19. data/lib/coradoc/asciidoc/transformer/block_rules.rb +3 -2
  20. data/lib/coradoc/asciidoc/transformer/block_type_classifier.rb +1 -1
  21. data/lib/coradoc/asciidoc/transformer/header_rules.rb +1 -1
  22. data/lib/coradoc/asciidoc/transformer/inline_rules.rb +1 -1
  23. data/lib/coradoc/asciidoc/transformer/list_rules.rb +3 -3
  24. data/lib/coradoc/asciidoc/transformer/misc_rules.rb +2 -2
  25. data/lib/coradoc/asciidoc/transformer/source_line_extractor.rb +7 -7
  26. data/lib/coradoc/asciidoc/transformer/structural_rules.rb +1 -1
  27. data/lib/coradoc/asciidoc/transformer/table_cell_builder.rb +6 -6
  28. data/lib/coradoc/asciidoc/transformer/table_layout.rb +1 -1
  29. data/lib/coradoc/asciidoc/transformer/text_rules.rb +1 -1
  30. data/lib/coradoc/asciidoc/transformer.rb +9 -8
  31. data/lib/coradoc/asciidoc/typographic_quotes.rb +2 -2
  32. data/lib/coradoc/asciidoc/version.rb +1 -1
  33. data/lib/coradoc/asciidoc.rb +1 -1
  34. metadata +2 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 451e2ccdd5dbbd4771079ee9bdc1041c3ee0d3ff74847237d7f3d4aea5064031
4
- data.tar.gz: 9f161020aca1c07565f9f20c510114b562925cbfb55d4666db14f1d61a68ed81
3
+ metadata.gz: bc2b5c2f53fa18844c9b33a2083b07e6f4a4fab8eac18ca2e3f0cc6211f5f4c7
4
+ data.tar.gz: 8b0d84abd2eef737e536e63811279e2520134d9f23860667dfcd2167855521f9
5
5
  SHA512:
6
- metadata.gz: 20150d6a118ae76db46737ca68c47b87a1195cd716ee88700de2afdb06094dd3edee9c66a5b224702e20c6333d28c4082d9840e24b590210154abe46643aad7a
7
- data.tar.gz: a881fc61dd3bce4e276f3db93fd250d3cf0cd0ab18a2e93a296887a416070b43b0da61972818e79ff0d7c00bd9f4af6320bb8cae8976402fff8519943ce05299
6
+ metadata.gz: 5e016f7d12d34b9dc307583120f436f4ab6742fbfec161cbb9b006a72efc373a2413fcc12010b2f395cbacb2586bf9096528a0c0a028cf934a5b4a543aa7ad6f
7
+ data.tar.gz: ca1cf91e5acca757738b3f39907376777f870b0e4a203fc746b96653b3dec58ab87d7ea2bbb5f7a8a266ed19c7010e6d5e98d8e9fd4623f68802bd34d0993bf3
@@ -30,7 +30,6 @@ module Coradoc
30
30
  class Admonition < Attached
31
31
  attribute :content,
32
32
  Lutaml::Model::Serializable,
33
- collection: true,
34
33
  polymorphic: [
35
34
  Lutaml::Model::Type::String,
36
35
  Coradoc::AsciiDoc::Model::TextElement
@@ -5,7 +5,7 @@ module Coradoc
5
5
  module Model
6
6
  class Attribute < Base
7
7
  attribute :key, :string
8
- attribute :value, :string, collection: true
8
+ attribute :value, :string
9
9
  attribute :line_break, :string, default: -> { "\n" }
10
10
 
11
11
  private
@@ -36,7 +36,7 @@ module Coradoc
36
36
  attribute :id, :string
37
37
 
38
38
  # 1-indexed source line where this element begins, when known.
39
- # Populated by the Parslet transformer from the matched Slice's
39
+ # Populated by the Parsanol transformer from the matched Slice's
40
40
  # line_and_column. nil for programmatically constructed models.
41
41
  # Single source of truth for source-position propagation through
42
42
  # AsciiDoc::Model → CoreModel (Issue 1, STATUS-2026-06-28).
@@ -35,7 +35,7 @@ module Coradoc
35
35
 
36
36
  # Coerce a raw parser AST value into the canonical ref_text string.
37
37
  # Accepts the shapes produced by Parser::Bibliography for `:ref_text`:
38
- # nil, Parslet::Slice, plain String, single Model::Base, or an Array
38
+ # nil, Parsanol::Slice, plain String, single Model::Base, or an Array
39
39
  # of any of these. Model objects (TextElement, Inline::Italic, etc.)
40
40
  # are flattened via TextExtractVisitor so their text content is
41
41
  # preserved instead of leaking `#<Class:0x...>` inspect strings.
@@ -39,8 +39,6 @@ module Coradoc
39
39
  # Content can be any AsciiDoc elements (paragraphs, lists, etc.)
40
40
  attribute :content,
41
41
  Coradoc::AsciiDoc::Model::Base,
42
- collection: true,
43
- initialize_empty: true,
44
42
  polymorphic: [
45
43
  Coradoc::AsciiDoc::Model::TextElement,
46
44
  Coradoc::AsciiDoc::Model::Paragraph,
@@ -37,7 +37,7 @@ module Coradoc
37
37
  include Coradoc::AsciiDoc::Model::Anchorable
38
38
 
39
39
  attribute :id, :string
40
- attribute :content, Coradoc::AsciiDoc::Model::TextElement, collection: true
40
+ attribute :content, Coradoc::AsciiDoc::Model::TextElement
41
41
  # attribute :level, :string
42
42
  attribute :level_int, :integer
43
43
  attribute :line_break, :string, default: -> { "\n" }
@@ -81,12 +81,12 @@ module Coradoc
81
81
  parts.join("\n")
82
82
  end
83
83
 
84
- # Create a ParseError from a Parslet exception
84
+ # Create a ParseError from a Parsanol exception
85
85
  #
86
- # @param exception [Parslet::ParseFailed] The Parslet exception
86
+ # @param exception [Parsanol::ParseFailed] The Parsanol exception
87
87
  # @param source [String] The original source text
88
88
  # @return [ParseError] A new ParseError with extracted context
89
- def self.from_parslet(exception, source = nil)
89
+ def self.from_parse_failure(exception, source = nil)
90
90
  return exception if exception.is_a?(ParseError)
91
91
 
92
92
  line, column = extract_location(exception)
@@ -107,12 +107,12 @@ module Coradoc
107
107
  new(exception.message, cause: exception)
108
108
  end
109
109
 
110
- # Extract line and column from Parslet error
110
+ # Extract line and column from Parsanol error
111
111
  #
112
- # @param exception [Parslet::ParseFailed] The Parslet exception
112
+ # @param exception [Parsanol::ParseFailed] The Parsanol exception
113
113
  # @return [Array<Integer, Integer>] Line and column numbers
114
114
  def self.extract_location(exception)
115
- return [nil, nil] unless exception.is_a?(Parslet::ParseFailed)
115
+ return [nil, nil] unless exception.is_a?(Parsanol::ParseFailed)
116
116
 
117
117
  cause = exception.cause
118
118
  return [nil, nil] unless cause
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'parslet'
4
- require 'parslet/convenience'
3
+ require 'parsanol'
4
+ require 'parsanol/convenience'
5
5
 
6
6
  module Coradoc
7
7
  module AsciiDoc
@@ -26,7 +26,7 @@ module Coradoc
26
26
  autoload :Text, 'coradoc/asciidoc/parser/text'
27
27
  autoload :Stem, 'coradoc/asciidoc/parser/stem'
28
28
 
29
- class Base < Parslet::Parser
29
+ class Base < Parsanol::Parser
30
30
  include Admonition
31
31
  include AttributeList
32
32
  include Bibliography
@@ -81,10 +81,23 @@ module Coradoc
81
81
  # @return [Hash] The parsed AST object
82
82
  def self.parse(string)
83
83
  new.parse(string)
84
- rescue Parslet::ParseFailed => e
84
+ rescue Parsanol::ParseFailed => e
85
85
  warn e.parse_failure_cause.ascii_tree
86
86
  end
87
87
 
88
+ # The Ruby engine is the required surface for this grammar.
89
+ # parsanol 1.3.44 fixes capture WRITES across the bridge
90
+ # (parsanol-ruby#80 — verified with a continuation-style repro),
91
+ # but the native tree still diverges from the Ruby-engine tree
92
+ # on attribute-list constructs: 69 suite failures natively from
93
+ # transform rules receiving raw Hashes where models are
94
+ # expected (e.g. Image::AttributeExtractor.promote_positional).
95
+ # Drop the override when native/Ruby tree parity holds for this
96
+ # grammar.
97
+ def parse(string, **options)
98
+ super(string, **options, mode: options.fetch(:mode, :ruby))
99
+ end
100
+
88
101
  def rule_dispatch(rule_name, *, **)
89
102
  RuleDispatcher.dispatch(self, rule_name, *, **)
90
103
  end
@@ -98,7 +111,7 @@ module Coradoc
98
111
  end
99
112
  end
100
113
 
101
- # Wrap every parser rule for Parslet memoization. Must run after all
114
+ # Wrap every parser rule for Parsanol memoization. Must run after all
102
115
  # parser modules are included in Base so that instance_method(rule_name)
103
116
  # finds the methods defined by every module.
104
117
  RuleDispatcher.apply(Base)
@@ -193,7 +193,7 @@ module Coradoc
193
193
  str(c.captures[capture_key].to_s.strip)
194
194
  end
195
195
 
196
- # Closure so the call bypasses Parslet's method_missing inside the
196
+ # Closure so the call bypasses Parsanol's method_missing inside the
197
197
  # dynamic block. capture() stashes the parsed AST (a nested Hash for
198
198
  # a `[source,ruby]` header). Inspect the structure directly so we
199
199
  # don't depend on Ruby's Hash#to_s format (it changed in 3.4).
@@ -18,17 +18,17 @@ module Coradoc
18
18
  # titles. The section's heading IS its title. Mixing the two shapes
19
19
  # into one rule caused `section_block` to admit `.Foo` lines that
20
20
  # collided with `section_title`'s `:title` capture, triggering
21
- # Parslet's "Duplicate subtrees while merging result … (keys:
21
+ # Parsanol's "Duplicate subtrees while merging result … (keys:
22
22
  # [:title])" warning and silently dropping the block title.
23
23
  #
24
24
  # Before this module existed, every block-like rule inlined its own
25
25
  # header rule with subtly different slot orderings — and several
26
- # captured the same Parslet key more than once in a single sequence,
27
- # which triggered Parslet's "Duplicate subtrees" warning and silently
26
+ # captured the same Parsanol key more than once in a single sequence,
27
+ # which triggered Parsanol's "Duplicate subtrees" warning and silently
28
28
  # discarded one of the captured values.
29
29
  #
30
30
  # `attribute_blocks` accepts one or more consecutive `[...]` attribute
31
- # lists, captured as a Parslet sequence under the :attribute_list key.
31
+ # lists, captured as a Parsanol sequence under the :attribute_list key.
32
32
  # Real-world AsciiDoc often stacks attribute lists before a block:
33
33
  #
34
34
  # [role=quote]
@@ -46,7 +46,7 @@ module Coradoc
46
46
  # an optional `.Title` line before its body. Single canonical
47
47
  # order; each of title, id, and attribute_blocks is optional and
48
48
  # matched at most once.
49
- # @return [Parslet::Atoms::Base]
49
+ # @return [Parsanol::Atoms::Base]
50
50
  def block_header
51
51
  block_title.maybe >>
52
52
  element_id.maybe >>
@@ -57,18 +57,18 @@ module Coradoc
57
57
  # sections — the section heading itself is the title. Sections
58
58
  # still accept the same element_id and attribute_blocks slots
59
59
  # that blocks do (`[[anchor]]`, `[appendix]`, `[role=x]`, etc.).
60
- # @return [Parslet::Atoms::Base]
60
+ # @return [Parsanol::Atoms::Base]
61
61
  def section_header
62
62
  element_id.maybe >>
63
63
  attribute_blocks.maybe
64
64
  end
65
65
 
66
66
  # One or more consecutive attribute_list + newline sequences, captured
67
- # as a Parslet sequence under :attribute_list. When multiple `[...]`
67
+ # as a Parsanol sequence under :attribute_list. When multiple `[...]`
68
68
  # blocks precede a delimiter, all of them reach the transformer; when
69
69
  # only one appears, the sequence has a single element and the existing
70
70
  # transformer rule handles it the same way as before.
71
- # @return [Parslet::Atoms::Base]
71
+ # @return [Parsanol::Atoms::Base]
72
72
  def attribute_blocks
73
73
  (attribute_list >> newline).repeat(1).as(:attribute_list)
74
74
  end
@@ -17,21 +17,56 @@ module Coradoc
17
17
  line_start? >> str("+\n")
18
18
  end
19
19
 
20
+ # Single source of truth for "what can appear between consecutive
21
+ # list items without ending the list". Asciidoctor treats blank
22
+ # lines and `//` comment lines as non-terminating inside every
23
+ # list type. Comments are consumed without capture — they are
24
+ # structurally invisible inside a list (no CommentLine node is
25
+ # emitted). Tag directives (`// tag::`) keep their separate
26
+ # handling via `comment_line_content`'s `tag.absent?` guard.
27
+ def list_item_separator
28
+ (comment_line_content | empty_line).repeat(0)
29
+ end
30
+
31
+ # Single source of truth for "what block can attach to a list
32
+ # item via a `+` continuation marker". The `+` line is consumed
33
+ # by {#list_item_attached}; this rule expresses only the block
34
+ # that follows. Definition lists are intentionally excluded —
35
+ # `+` before a continuing dlist run is handled inside
36
+ # `dlist_item` as a continuation marker so the run nests by
37
+ # delimiter depth (see there).
38
+ def list_attached_block
39
+ admonition_line | unordered_list(1) | ordered_list(1) | paragraph | block
40
+ end
41
+
42
+ # Shared `+`-continuation attachment for every list item type
43
+ # (ulist, olist, dlist). A `+` line directly followed by an
44
+ # attached block becomes a child of the current item. The
45
+ # `list_continuation.present?` lookahead prevents greedy
46
+ # over-match when the `+` actually belongs to surrounding
47
+ # context.
48
+ def list_item_attached
49
+ (list_continuation.present? >>
50
+ list_continuation >>
51
+ list_attached_block
52
+ ).repeat(0).as(:attached)
53
+ end
54
+
20
55
  def ordered_list(nesting_level = 1)
21
56
  attrs = (attribute_list >> newline).maybe
22
57
  r = olist_item(nesting_level)
23
- attrs >> (empty_line.repeat(0) >> r).repeat(1).as(:ordered)
58
+ attrs >> (list_item_separator >> r).repeat(1).as(:ordered)
24
59
  end
25
60
 
26
61
  def unordered_list(nesting_level = 1)
27
62
  attrs = (attribute_list >> newline).maybe
28
63
  r = ulist_item(nesting_level)
29
- attrs >> (empty_line.repeat(0) >> r).repeat(1).as(:unordered)
64
+ attrs >> (list_item_separator >> r).repeat(1).as(:unordered)
30
65
  end
31
66
 
32
67
  def definition_list(_delimiter = nil)
33
68
  (attribute_list >> newline).maybe >>
34
- dlist_item.repeat(1).as(:definition_list) >>
69
+ (list_item_separator >> dlist_item).repeat(1).as(:definition_list) >>
35
70
  dlist_item.absent?
36
71
  end
37
72
 
@@ -56,11 +91,7 @@ module Coradoc
56
91
  (list_body_text_line >>
57
92
  list_item_continuation_lines).as(:lines)
58
93
 
59
- att = (list_continuation.present? >>
60
- list_continuation >>
61
- (admonition_line | paragraph | block)
62
- ).repeat(0).as(:attached)
63
- item >>= att.maybe
94
+ item >>= list_item_attached.maybe
64
95
 
65
96
  if nesting_level <= 4
66
97
  item >>= (list_marker(nesting_level + 1).present? >>
@@ -108,11 +139,7 @@ module Coradoc
108
139
  (list_body_text_line >>
109
140
  list_item_continuation_lines).as(:lines)
110
141
 
111
- att = (list_continuation.present? >>
112
- list_continuation >>
113
- (admonition_line | paragraph | block)
114
- ).repeat(0).as(:attached)
115
- item >>= att.maybe
142
+ item >>= list_item_attached.maybe
116
143
 
117
144
  if nesting_level <= 4
118
145
  item >>= (list_marker(nesting_level + 1).present? >>
@@ -273,11 +300,14 @@ module Coradoc
273
300
 
274
301
  item = multi_line | inline
275
302
 
276
- attached = (list_continuation.present? >>
277
- list_continuation >>
278
- (admonition_line | paragraph | block)
279
- ).repeat(0).as(:attached)
280
- item >>= attached.maybe
303
+ item >>= list_item_attached.maybe
304
+
305
+ # A `+` line directly before a continuing dlist run is a
306
+ # list-continuation marker (asciidoctor semantics): consume it
307
+ # so the following items stay in the current list and nest by
308
+ # delimiter depth. Without this, the `+` dangles and the run
309
+ # splits off as a detached sibling list.
310
+ item >>= (list_continuation >> dlist_item.present?).repeat(0)
281
311
 
282
312
  item.as(:definition_list_item)
283
313
  end
@@ -3,12 +3,12 @@
3
3
  module Coradoc
4
4
  module AsciiDoc
5
5
  module Parser
6
- # Wraps every parser rule for Parslet memoization.
6
+ # Wraps every parser rule for Parsanol memoization.
7
7
  #
8
8
  # Parameterized rules (e.g., `block_style(n_deep, delimiter, repeater)`)
9
- # cannot be memoized by Parslet directly because their result depends
9
+ # cannot be memoized by Parsanol directly because their result depends
10
10
  # on the args. This module aliases each rule to a per-args dispatch
11
- # rule so Parslet sees a memoizable, parameterless rule for every
11
+ # rule so Parsanol sees a memoizable, parameterless rule for every
12
12
  # (rule_name, args) combination. Parameterless rules get a single
13
13
  # memoized alias.
14
14
  #
@@ -141,11 +141,11 @@ module Coradoc
141
141
  :"#{alias_name}_#{key}"
142
142
  end
143
143
 
144
- # Build a Parslet memoizable rule that closes over the captured
145
- # args and forwards to the original aliased rule. Using Parslet's
144
+ # Build a Parsanol memoizable rule that closes over the captured
145
+ # args and forwards to the original aliased rule. Using Parsanol's
146
146
  # class-level `rule()` (not define_method on singleton_class) is
147
- # essential — Parslet's memoization, `as()`, and tree building
148
- # depend on the rule going through the standard Parslet machinery.
147
+ # essential — Parsanol's memoization, `as()`, and tree building
148
+ # depend on the rule going through the standard Parsanol machinery.
149
149
  def build_dispatch_rule(parser_class, original_alias, rule_name, args, kwargs)
150
150
  parser_class.class_eval do
151
151
  rule(rule_name) do
@@ -121,6 +121,26 @@ module Coradoc
121
121
  ).as(:block_image)
122
122
  end
123
123
 
124
+ # Non-capturing form of {#comment_line}. Same shape (a `//`
125
+ # comment line, excluding tag directives like `// tag::`), but
126
+ # consumes without producing an AST node.
127
+ #
128
+ # Used by list rules to absorb inter-item comments so the list
129
+ # continues across them — asciidoctor treats `//` comments inside
130
+ # any list as structurally invisible. Uses raw character matchers
131
+ # instead of `text` so no inner captures leak into the consuming
132
+ # rule's AST.
133
+ #
134
+ # Single source of truth for the comment-line shape: any future
135
+ # adjustment to the `//`-line grammar happens here and both the
136
+ # capturing and non-capturing forms stay in sync.
137
+ def comment_line_content
138
+ tag.absent? >>
139
+ str('//') >> str('/').absent? >>
140
+ space? >>
141
+ match('[^\n]').repeat(0) >> line_ending
142
+ end
143
+
124
144
  def comment_line
125
145
  tag.absent? >>
126
146
  (str('//') >> str('/').absent? >>
@@ -114,14 +114,17 @@ module Coradoc
114
114
 
115
115
  def transform_list_item(item)
116
116
  content_val = item.content
117
- children = ToCoreModel.transform_inline_content(content_val)
117
+ inline_children = ToCoreModel.transform_inline_content(content_val)
118
+ attached_children = Array(item.attached).filter_map do |block|
119
+ ToCoreModel.transform(block)
120
+ end
118
121
 
119
122
  li = Coradoc::CoreModel::ListItem.new(
120
123
  content: ToCoreModel.extract_text_content(content_val),
121
124
  marker: item.marker,
122
125
  source_line: item.source_line
123
126
  )
124
- li.children = children
127
+ li.children = inline_children + attached_children
125
128
 
126
129
  nested_lists = extract_nested_lists(item)
127
130
  li.nested_list = nested_lists.first if nested_lists.size == 1
@@ -23,7 +23,7 @@ module Coradoc
23
23
  model
24
24
  end
25
25
 
26
- def visit_parslet_slice(model)
26
+ def visit_parsanol_slice(model)
27
27
  model.to_s
28
28
  end
29
29
 
@@ -127,7 +127,7 @@ module Coradoc
127
127
  case model
128
128
  when nil then visit_nil(model)
129
129
  when String then visit_string(model)
130
- when Parslet::Slice then visit_parslet_slice(model)
130
+ when Parsanol::Slice then visit_parsanol_slice(model)
131
131
  when CoreModel::TextContent then visit_core_model_text_content(model)
132
132
  when CoreModel::Image then visit_core_model_image(model)
133
133
  when CoreModel::InlineElement then visit_core_model_inline(model)
@@ -149,7 +149,7 @@ module Coradoc
149
149
  when Model::LineBreak, Model::CommentLine, Model::CommentBlock then ''
150
150
  when Model::Base then visit_base_model(model)
151
151
  else
152
- model.class.name.start_with?('Parslet::') ? model.to_s : ''
152
+ model.class.name.start_with?('Parsanol::') ? model.to_s : ''
153
153
  end
154
154
  end
155
155
  end
@@ -128,7 +128,7 @@ module Coradoc
128
128
  else
129
129
  [text]
130
130
  end
131
- rescue Parslet::ParseFailed
131
+ rescue Parsanol::ParseFailed
132
132
  [text]
133
133
  end
134
134
 
@@ -151,7 +151,7 @@ module Coradoc
151
151
  else
152
152
  transformed
153
153
  end
154
- rescue Parslet::ParseFailed
154
+ rescue Parsanol::ParseFailed
155
155
  text
156
156
  end
157
157
  end
@@ -2,12 +2,12 @@
2
2
 
3
3
  module Coradoc
4
4
  module AsciiDoc
5
- class Transformer < Parslet::Transform
5
+ class Transformer < Parsanol::Transform
6
6
  # Pure-function module for normalizing raw parser `:attribute_list`
7
7
  # values into a single canonical Model::AttributeList.
8
8
  #
9
9
  # The parser's `block_header` rule captures every consecutive `[...]`
10
- # block before a structural element as a Parslet sequence under
10
+ # block before a structural element as a Parsanol sequence under
11
11
  # `:attribute_list`. Real-world AsciiDoc often stacks multiple lists
12
12
  # before a single delimiter:
13
13
  #
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Coradoc
4
4
  module AsciiDoc
5
- class Transformer < Parslet::Transform
5
+ class Transformer < Parsanol::Transform
6
6
  # Module containing block element transformation rules
7
7
  module BlockRules
8
8
  def self.apply(transformer_class)
@@ -48,8 +48,9 @@ module Coradoc
48
48
  content: sequence(:content)
49
49
  ) do
50
50
  canonical = Coradoc::AsciiDoc::Transform::ElementTransformers::AdmonitionStyles.canonicalize(admonition_type.to_s)
51
+ content_value = content.is_a?(Array) && content.length == 1 ? content.first : content
51
52
  Model::Admonition.new(
52
- content: content,
53
+ content: content_value,
53
54
  type: canonical
54
55
  )
55
56
  end
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Coradoc
4
4
  module AsciiDoc
5
- class Transformer < Parslet::Transform
5
+ class Transformer < Parsanol::Transform
6
6
  # Single source of truth for "which delimiter maps to which block model".
7
7
  #
8
8
  # The block rule in BlockRules delegates here to convert a parser
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Coradoc
4
4
  module AsciiDoc
5
- class Transformer < Parslet::Transform
5
+ class Transformer < Parsanol::Transform
6
6
  # Module containing header transformation rules
7
7
  module HeaderRules
8
8
  def self.apply(transformer_class)
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Coradoc
4
4
  module AsciiDoc
5
- class Transformer < Parslet::Transform
5
+ class Transformer < Parsanol::Transform
6
6
  # Module containing inline element transformation rules
7
7
  module InlineRules
8
8
  # Inline formatting variants that share the same rule shape:
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Coradoc
4
4
  module AsciiDoc
5
- class Transformer < Parslet::Transform
5
+ class Transformer < Parsanol::Transform
6
6
  # Module containing list transformation rules
7
7
  module ListRules
8
8
  class << self
@@ -199,10 +199,10 @@ module Coradoc
199
199
  case term_data
200
200
  when Hash
201
201
  text = term_data[:text]
202
- text = text.to_s if text.is_a?(Parslet::Slice) || text.is_a?(String)
202
+ text = text.to_s if text.is_a?(Parsanol::Slice) || text.is_a?(String)
203
203
  text = text.content.to_s if text.is_a?(Model::TextElement)
204
204
  id = term_data[:id]
205
- id = id.to_s if id.is_a?(Parslet::Slice)
205
+ id = id.to_s if id.is_a?(Parsanol::Slice)
206
206
  { text: text.to_s, id: id, delimiter: delim.to_s }
207
207
  when Model::TextElement
208
208
  { text: term_data.content.to_s, id: term_data.id, delimiter: delim.to_s }
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Coradoc
4
4
  module AsciiDoc
5
- class Transformer < Parslet::Transform
5
+ class Transformer < Parsanol::Transform
6
6
  # Module containing miscellaneous transformation rules
7
7
  module MiscRules
8
8
  def self.apply(transformer_class)
@@ -62,7 +62,7 @@ module Coradoc
62
62
 
63
63
  attributes.each do |a|
64
64
  case a
65
- when Parslet::Slice
65
+ when Parsanol::Slice
66
66
  attr_list.add_positional(a.to_s)
67
67
  when String
68
68
  attr_list.add_positional(a)
@@ -1,15 +1,15 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'parslet'
3
+ require 'parsanol'
4
4
 
5
5
  module Coradoc
6
6
  module AsciiDoc
7
- class Transformer < Parslet::Transform
8
- # Walks a Parslet AST subtree (Hash/Array/Slice/String/Model) and
9
- # returns the 1-indexed source line of the first +Parslet::Slice+
7
+ class Transformer < Parsanol::Transform
8
+ # Walks a Parsanol AST subtree (Hash/Array/Slice/String/Model) and
9
+ # returns the 1-indexed source line of the first +Parsanol::Slice+
10
10
  # or Model::Base#source_line it finds.
11
11
  #
12
- # Parslet preserves byte offsets on every matched slice
12
+ # Parsanol preserves byte offsets on every matched slice
13
13
  # (+slice.line_and_column+ returns +[line, column]+); the
14
14
  # transformer receives these slices in the AST but most rules
15
15
  # discard the position when building Model objects. This helper
@@ -18,7 +18,7 @@ module Coradoc
18
18
  # parser.
19
19
  #
20
20
  # Handles two distinct shapes:
21
- # * Pre-transform AST (Hash/Array of Parslet::Slice) — used by
21
+ # * Pre-transform AST (Hash/Array of Parsanol::Slice) — used by
22
22
  # rules that bind raw slices via +simple(:x)+.
23
23
  # * Post-transform Model tree (Model::Base instances whose
24
24
  # +source_line+ was populated by an earlier rule) — used by
@@ -33,7 +33,7 @@ module Coradoc
33
33
 
34
34
  def extract(node)
35
35
  case node
36
- when Parslet::Slice then line_of(node)
36
+ when Parsanol::Slice then line_of(node)
37
37
  when Coradoc::AsciiDoc::Model::Base then node.source_line
38
38
  when Hash then extract_from_hash(node)
39
39
  when Array then extract_from_array(node)
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Coradoc
4
4
  module AsciiDoc
5
- class Transformer < Parslet::Transform
5
+ class Transformer < Parsanol::Transform
6
6
  # Module containing table and structural element transformation rules
7
7
  module StructuralRules
8
8
  def self.apply(transformer_class)
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Coradoc
4
4
  module AsciiDoc
5
- class Transformer < Parslet::Transform
5
+ class Transformer < Parsanol::Transform
6
6
  # Pure functions for parsing the cell-format prefix (`2+^.^a`) and
7
7
  # building a Model::TableCell from raw parser values.
8
8
  #
@@ -27,7 +27,7 @@ module Coradoc
27
27
  end
28
28
 
29
29
  # Coerce the parser-supplied cell content into a plain String.
30
- # The cell parser emits `text:` as either a single Parslet::Slice
30
+ # The cell parser emits `text:` as either a single Parsanol::Slice
31
31
  # or an Array of slices (from `.repeat(0)`). An empty Array must
32
32
  # map to "" — Ruby's `[].to_s` returns "[]", which previously
33
33
  # leaked into TableCell content as a phantom "[]" cell.
@@ -70,7 +70,7 @@ module Coradoc
70
70
  transformed = Transformer.new.apply(ast)
71
71
  content_array = transformed.is_a?(Array) ? transformed : [transformed]
72
72
  [Model::TextElement.new(content: content_array)]
73
- rescue Parslet::ParseFailed
73
+ rescue Parsanol::ParseFailed
74
74
  [Model::TextElement.new(content: text.to_s)]
75
75
  end
76
76
  end
@@ -100,13 +100,13 @@ module Coradoc
100
100
  before_transformed = Transformer.new.apply(before_ast)
101
101
  before_array = before_transformed.is_a?(Array) ? before_transformed : [before_transformed]
102
102
  before_elements = [Model::TextElement.new(content: before_array)]
103
- rescue Parslet::ParseFailed
103
+ rescue Parsanol::ParseFailed
104
104
  before_elements = [Model::TextElement.new(content: before_list)]
105
105
  end
106
106
  end
107
107
 
108
108
  return before_elements + [transformed]
109
- rescue Parslet::ParseFailed
109
+ rescue Parsanol::ParseFailed
110
110
  # fall through to inline parsing
111
111
  end
112
112
  end
@@ -117,7 +117,7 @@ module Coradoc
117
117
  transformed = Transformer.new.apply(ast)
118
118
  content_array = transformed.is_a?(Array) ? transformed : [transformed]
119
119
  [Model::TextElement.new(content: content_array)]
120
- rescue Parslet::ParseFailed
120
+ rescue Parsanol::ParseFailed
121
121
  [Model::TextElement.new(content: text_str)]
122
122
  end
123
123
  end
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Coradoc
4
4
  module AsciiDoc
5
- class Transformer < Parslet::Transform
5
+ class Transformer < Parsanol::Transform
6
6
  # Pure functions for table row/column layout.
7
7
  #
8
8
  # Extracted from the Transformer god class so that:
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Coradoc
4
4
  module AsciiDoc
5
- class Transformer < Parslet::Transform
5
+ class Transformer < Parsanol::Transform
6
6
  # Module containing text and paragraph transformation rules
7
7
  module TextRules
8
8
  def self.apply(transformer_class)
@@ -1,10 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'parslet'
3
+ require 'parsanol'
4
4
 
5
5
  module Coradoc
6
6
  module AsciiDoc
7
- # Parslet::Transform subclass that converts AST to AsciiDoc model objects.
7
+ # Parsanol::Transform subclass that converts AST to AsciiDoc model objects.
8
8
  #
9
9
  # This transformer uses a modular rule system where each group of rules
10
10
  # is defined in a separate file for maintainability.
@@ -18,7 +18,7 @@ module Coradoc
18
18
  # - StructuralRules: Sections, tables, documents
19
19
  # - MiscRules: Comments, attributes, media elements
20
20
  #
21
- class Transformer < Parslet::Transform
21
+ class Transformer < Parsanol::Transform
22
22
  # Autoload rule modules at the class level.
23
23
  # Each rule file reopens this class and defines a module inside it.
24
24
  # The file path matches the expected constant path.
@@ -128,7 +128,7 @@ module Coradoc
128
128
  # Used by the paragraph and reviewer_note rules to share the same
129
129
  # line-shape handling (DRY).
130
130
  def self.lines_to_text_elements(lines)
131
- # Parslet may deliver `lines` as a single Hash (one line captured)
131
+ # Parsanol may deliver `lines` as a single Hash (one line captured)
132
132
  # or an Array of Hashes (multiple lines). `Array(hash)` converts
133
133
  # to nested pairs, which we don't want — normalize explicitly.
134
134
  normalized = case lines
@@ -218,11 +218,12 @@ module Coradoc
218
218
  new.apply(syntax_tree)
219
219
  end
220
220
 
221
- # Single deepening seam for source_line propagation. Parslet's
221
+ # Single deepening seam for source_line propagation. Parsanol's
222
222
  # transform pipeline funnels every rule block through
223
- # +call_on_match(bindings, block)+; overriding it lets us post-
224
- # process the block's result and inject +source_line+ from the
225
- # matched bindings, so individual rules no longer need to call
223
+ # +call_on_match(bindings, block)+ (restored as the stable seam in
224
+ # parsanol 1.3.39, GH-74). Overriding it lets us post-process the
225
+ # block's result and inject +source_line+ from the matched
226
+ # bindings, so individual rules no longer need to call
226
227
  # SourceLineExtractor.extract themselves (DRY — was 47 call
227
228
  # sites across 7 rule files).
228
229
  #
@@ -22,12 +22,12 @@ module Coradoc
22
22
  "`'" => '’' # U+2019 right single
23
23
  }.freeze
24
24
 
25
- # All four 2-char patterns, suitable for building a Parslet alternation.
25
+ # All four 2-char patterns, suitable for building a Parsanol alternation.
26
26
  # @return [Array<String>]
27
27
  PATTERNS = PATTERN_TO_CHAR.keys.freeze
28
28
 
29
29
  # Look up the Unicode char for a matched pattern.
30
- # @param pattern [String, Parslet::Slice] the matched 2-char pattern
30
+ # @param pattern [String, Parsanol::Slice] the matched 2-char pattern
31
31
  # @return [String] the Unicode curly quote char
32
32
  def self.char_for(pattern)
33
33
  PATTERN_TO_CHAR.fetch(pattern.to_s, pattern.to_s)
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Coradoc
4
4
  module AsciiDoc
5
- VERSION = '2.0.32'
5
+ VERSION = '2.0.34'
6
6
  end
7
7
  end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'parslet'
3
+ require 'parsanol'
4
4
  require 'lutaml/model'
5
5
  require 'coradoc'
6
6
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: coradoc-adoc
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.32
4
+ version: 2.0.34
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.
@@ -38,7 +38,7 @@ dependencies:
38
38
  - !ruby/object:Gem::Version
39
39
  version: 0.8.0
40
40
  - !ruby/object:Gem::Dependency
41
- name: parslet
41
+ name: parsanol
42
42
  requirement: !ruby/object:Gem::Requirement
43
43
  requirements:
44
44
  - - ">="