coradoc-markdown 1.0.10 → 1.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 45a195eaddedba173983f2ba2ab08ce81044fe089124b8287b4a643262dbc6f8
4
- data.tar.gz: b163677948cdc8459692c411c2840f2bfa0cfe401e47453d61e88d156bbfc910
3
+ metadata.gz: 232eab66f6d33edae8a3cca57f5ebd16cca11ed96c4dd9a51611b9669410595b
4
+ data.tar.gz: 1b0f0051729a0e226826c66d49bed0c4227732491b0bbf6148f42df524b1e95f
5
5
  SHA512:
6
- metadata.gz: 3b6c63bf4e97c80a63c4f6289576f80577434d6aa8176aafd3067c026abbad4c9ab72fbe509e936933f60ef6cf02c7e3b6087efab353f541618ffe75d6c93ad1
7
- data.tar.gz: 0a7a78dc0d92fd3c03344df7a6063429b443dcacfc760686a7d3080b6df7daff9b873251a1576d73307bbacfa8e642e08e02561625f6cfcd2d493f524843dd4b
6
+ metadata.gz: d20d1132ed4f527557207c11736d3ad10289fecf47a480341ed3b768bee9b2e812195fcf77d377a374b9c82804044c8c2aa701688c7e08706070ef62f957545c
7
+ data.tar.gz: 24547cfb89cbe67a61f0bb63cee59495d2520d61df54ed03141963f5245e2cd5b1c537b80b2903a55b9cfa36d51639fc85f170a963686a6b71faff2a95845b11
@@ -84,8 +84,8 @@ module Coradoc
84
84
  node.map { |child| process_node(child) }
85
85
  when Hash
86
86
  process_hash(node)
87
- when Parslet::Slice
88
- # Process escape sequences in Parslet::Slice values
87
+ when Parsanol::Slice
88
+ # Process escape sequences in Parsanol::Slice values
89
89
  process_escapes(node.to_s)
90
90
  else
91
91
  node
@@ -161,7 +161,7 @@ module Coradoc
161
161
  return value if value.nil?
162
162
 
163
163
  case value
164
- when Parslet::Slice
164
+ when Parsanol::Slice
165
165
  end
166
166
  text = value.to_s
167
167
 
@@ -229,13 +229,13 @@ module Coradoc
229
229
  result
230
230
  end
231
231
 
232
- # Process a text value (Parslet::Slice or String)
232
+ # Process a text value (Parsanol::Slice or String)
233
233
  # Only processes escape sequences without changing structure
234
234
  def process_text_value(value)
235
235
  return value if value.nil?
236
236
 
237
237
  case value
238
- when Parslet::Slice
238
+ when Parsanol::Slice
239
239
  end
240
240
  process_escapes(value.to_s)
241
241
  end
@@ -374,7 +374,7 @@ module Coradoc
374
374
  joined = extract_text_content(result)
375
375
  { ln: joined }
376
376
  end
377
- rescue Parslet::ParseFailed
377
+ rescue Parsanol::ParseFailed
378
378
  # If parsing fails, return original text in ln structure
379
379
  { ln: text }
380
380
  end
@@ -390,7 +390,7 @@ module Coradoc
390
390
 
391
391
  # Pattern to match HTML tags with markdown attribute
392
392
  # Captures: tag name, markdown value, content, closing tag
393
- pattern = %r{<(#{HTML_TAG_PATTERN})\s+([^>]*?)markdown\s*=\s*["']([^"']+)["']([^>]*)>(.*?)</\1>}im
393
+ pattern = %r{<(#{HTML_TAG_PATTERN})\s+([^>]*?)markdown\s*=\s*["']([^"']+)["']([^>]*)>(.*?)</\1>}imo
394
394
 
395
395
  text.gsub(pattern) do |_match|
396
396
  tag_name = ::Regexp.last_match(1)
@@ -441,7 +441,7 @@ module Coradoc
441
441
 
442
442
  # Convert result back to string representation
443
443
  inline_result_to_string(result)
444
- rescue Parslet::ParseFailed
444
+ rescue Parsanol::ParseFailed
445
445
  content
446
446
  end
447
447
  end
@@ -3,11 +3,10 @@
3
3
  module Coradoc
4
4
  module Markdown
5
5
  module Parser
6
- autoload :ParsletExtras, "#{__dir__}/parslet_extras"
7
-
8
- class BlockParser < Parslet::Parser
9
- using ParsletExtras
6
+ # Load-time DSL side effect (sanctioned require_relative exception)
7
+ require_relative 'parsanol_atoms'
10
8
 
9
+ class BlockParser < Parsanol::Parser
11
10
  # NOTE: Debug method for parser development. Outputs current parse position
12
11
  # and capture context. Only called during parser debugging sessions.
13
12
  def debug(msg)
@@ -23,16 +22,16 @@ module Coradoc
23
22
 
24
23
  rule(:whitespace) { match[" \t"] }
25
24
  # NOTE: repeat(1) before EOF (any.absent?) because infinite loop otherwise
26
- rule(:blank_line) { (whitespace.repeat(1) >> any.absent? | whitespace.repeat >> line_ending).ignore }
25
+ rule(:blank_line) { ((whitespace.repeat(1) >> any.absent?) | (whitespace.repeat >> line_ending)).ignore }
27
26
  rule(:blank_line_verbatim) do
28
- whitespace.repeat(1).as(:ln) >> any.absent? | whitespace.repeat.as(:ln) >> line_ending
27
+ (whitespace.repeat(1).as(:ln) >> any.absent?) | (whitespace.repeat.as(:ln) >> line_ending)
29
28
  end
30
29
  rule(:line_char) { match["^\r\n"] }
31
30
  rule(:line_verbatim) { line_char.repeat(1).as(:ln) >> line_ending_or_eof }
32
31
 
33
32
  rule(:non_indent_space) { str(' ').repeat(0, 3) }
34
33
 
35
- # Block nesting is the tricky part, but Parslet's `dynamic` and `scope`
34
+ # Block nesting is the tricky part, but Parsanol's `dynamic` and `scope`
36
35
  # make it possible to be aware of what blocks we're already in, and implement
37
36
  # a check for whether we're still inside of those blocks on the beginning of
38
37
  # every line. The rules that match the line run inside of the innermost
@@ -53,11 +52,17 @@ module Coradoc
53
52
 
54
53
  def open_block(kind, cont_rule)
55
54
  dynamic do |_src, ctx|
56
- parent_scope = ctx.captures.current.parent
57
- ctx.captures[:cont] = cont_rule
58
- ctx.captures[:cont] = parent_scope[:cont] >> cont_rule if parent_scope.key?(:cont)
59
- ctx.captures[:block] = kind
60
- # puts "starting block #{kind} at #{src.line_and_column} (#{src.bytepos}): #{ctx.captures[:cont]}"
55
+ caps = ctx.captures
56
+ # Chain-read before the write: picks up the enclosing
57
+ # block's continuation rule when one is in scope (Parsanol's
58
+ # Scope#[] searches parent frames; #key? is chain-aware).
59
+ caps[:cont] =
60
+ if caps.key?(:cont)
61
+ caps[:cont] >> cont_rule
62
+ else
63
+ cont_rule
64
+ end
65
+ caps[:block] = kind
61
66
  any.present? | any.absent?
62
67
  end
63
68
  end
@@ -222,7 +227,7 @@ module Coradoc
222
227
  end
223
228
 
224
229
  rule(:paragraph_line) do
225
- line_char.repeat(1).as(:ln) >> any.absent? | line_char.repeat.as(:ln) >> line_ending
230
+ (line_char.repeat(1).as(:ln) >> any.absent?) | (line_char.repeat.as(:ln) >> line_ending)
226
231
  end
227
232
 
228
233
  rule(:paragraph_continued_line) do
@@ -286,8 +291,8 @@ module Coradoc
286
291
  rule(:ial_key_value) do
287
292
  match['\\w\\-'].repeat(1) >> str('=') >>
288
293
  (
289
- str('"') >> match['^"'].repeat(0) >> str('"') |
290
- str("'") >> match["^'"].repeat(0) >> str("'") |
294
+ (str('"') >> match['^"'].repeat(0) >> str('"')) |
295
+ (str("'") >> match["^'"].repeat(0) >> str("'")) |
291
296
  match['^\\s\\}'].repeat(1)
292
297
  )
293
298
  end
@@ -322,8 +327,8 @@ module Coradoc
322
327
  rule(:extension_option) do
323
328
  match['\\w\\-'].repeat(1) >> str('=') >>
324
329
  (
325
- str('"') >> match['^"'].repeat(0) >> str('"') |
326
- str("'") >> match["^'"].repeat(0) >> str("'") |
330
+ (str('"') >> match['^"'].repeat(0) >> str('"')) |
331
+ (str("'") >> match["^'"].repeat(0) >> str("'")) |
327
332
  match['^\\s/\\}'].repeat(1)
328
333
  )
329
334
  end
@@ -466,11 +471,11 @@ module Coradoc
466
471
  # List item continuation line (indented content that's not a block)
467
472
  # Excludes lines that look like nested list markers
468
473
  rule(:list_continuation_line) do
469
- (str(' ') | str("\t")) >>
474
+ ((str(' ') | str("\t")) >>
470
475
  nested_list_marker.absent? >>
471
- line_verbatim |
472
- nested_list_marker.absent? >>
473
- line_verbatim
476
+ line_verbatim) |
477
+ (nested_list_marker.absent? >>
478
+ line_verbatim)
474
479
  end
475
480
 
476
481
  # Nested list marker detection (for 4-space indented lists)
@@ -513,8 +518,8 @@ module Coradoc
513
518
 
514
519
  # Nested block (indented list, etc.)
515
520
  rule(:nested_block) do
516
- (str(' ') | str("\t")) >> nested_unordered_list |
517
- (str(' ') | str("\t")) >> nested_ordered_list
521
+ ((str(' ') | str("\t")) >> nested_unordered_list) |
522
+ ((str(' ') | str("\t")) >> nested_ordered_list)
518
523
  end
519
524
 
520
525
  # Nested unordered list (4-space indented)
@@ -727,7 +732,7 @@ module Coradoc
727
732
  def self.parse(filename)
728
733
  content = File.read(filename)
729
734
  new.parse(content)
730
- rescue Parslet::ParseFailed => e
735
+ rescue Parsanol::ParseFailed => e
731
736
  puts e.parse_failure_cause.ascii_tree
732
737
  end
733
738
 
@@ -735,7 +740,7 @@ module Coradoc
735
740
  def self.parse_with_processing(content)
736
741
  ast = new.parse(content)
737
742
  AstProcessor.process(ast)
738
- rescue Parslet::ParseFailed => e
743
+ rescue Parsanol::ParseFailed => e
739
744
  puts e.parse_failure_cause.ascii_tree
740
745
  nil
741
746
  end
@@ -3,11 +3,12 @@
3
3
  module Coradoc
4
4
  module Markdown
5
5
  module Parser
6
- autoload :ParsletExtras, "#{__dir__}/parslet_extras"
6
+ # Load-time DSL side effect (sanctioned require_relative exception)
7
+ require_relative 'parsanol_atoms'
8
+
7
9
  autoload :HtmlEntities, "#{__dir__}/html_entities"
8
10
 
9
- class InlineParser < Parslet::Parser
10
- using ParsletExtras
11
+ class InlineParser < Parsanol::Parser
11
12
 
12
13
  rule(:line_ending) { (str("\n") | str("\r\n") | str("\r")).ignore }
13
14
  rule(:line_ending_or_eof) { line_ending | any.absent? }
@@ -266,7 +267,7 @@ module Coradoc
266
267
  end
267
268
 
268
269
  def parse(io, options = {})
269
- process_emphasis(super(io, options))
270
+ process_emphasis(super)
270
271
  end
271
272
  end
272
273
  end
@@ -0,0 +1,135 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'parsanol'
4
+
5
+ module Coradoc
6
+ module Markdown
7
+ module Parser
8
+ # Custom grammar atoms and DSL surface for the Markdown parser,
9
+ # built on Parsanol::Atoms::Custom — the sanctioned extension
10
+ # point. Replaces the former parslet_extras module, which
11
+ # reached into Parslet internals via refinements.
12
+ module ParsanolAtoms
13
+ # Matches +parslet+ but yields a fixed +value+.
14
+ class Output < Parsanol::Atoms::Custom
15
+ attr_reader :parslet, :value
16
+
17
+ def initialize(parslet, value)
18
+ @parslet = parslet
19
+ @value = value
20
+ super()
21
+ end
22
+
23
+ def try_match(source, context, consume_all)
24
+ success, = parslet.apply(source, context, consume_all)
25
+ [success, success ? value : nil]
26
+ end
27
+ end
28
+
29
+ # Matches +parslet+ and yields the callable applied to the
30
+ # flattened match value.
31
+ class DynamicOutput < Parsanol::Atoms::Custom
32
+ include Parsanol::Atoms::CanFlatten
33
+
34
+ attr_reader :parslet, :callable
35
+
36
+ def initialize(parslet, callable)
37
+ @parslet = parslet
38
+ @callable = callable
39
+ super()
40
+ end
41
+
42
+ def try_match(source, context, consume_all)
43
+ success, value = parslet.apply(source, context, consume_all)
44
+ return [false, nil] unless success
45
+
46
+ [true, callable.call(flatten(value))]
47
+ end
48
+ end
49
+
50
+ # Positive/negative lookbehind: succeeds (zero-width) when the
51
+ # preceding +number+ characters are/are not matched by
52
+ # +bound_parslet+. Character-accurate for multibyte input —
53
+ # rewinds over UTF-8 continuation bytes.
54
+ class Lookbehind < Parsanol::Atoms::Custom
55
+ attr_reader :positive, :number, :bound_parslet
56
+
57
+ def initialize(bound_parslet, number, positive: true)
58
+ @positive = positive
59
+ @number = number
60
+ @bound_parslet = bound_parslet
61
+ super()
62
+ end
63
+
64
+ def error_msgs
65
+ @error_msgs ||= {
66
+ positive: ['Input should be preceded by ', bound_parslet],
67
+ negative: ['Input should not be preceded by ', bound_parslet]
68
+ }
69
+ end
70
+
71
+ def try_match(source, context, _consume_all)
72
+ rewind_pos = source.bytepos
73
+ if rewind_pos.zero?
74
+ return [true, nil] unless positive
75
+
76
+ return context.err_at(self, source, error_msgs[:positive], source.pos)
77
+ end
78
+
79
+ source.bytepos = rewind_chars(source, number)
80
+ error_pos = source.pos
81
+ success, = bound_parslet.apply(source, context, false)
82
+
83
+ if positive
84
+ return [true, nil] if success
85
+
86
+ context.err_at(self, source, error_msgs[:positive], error_pos)
87
+ elsif success
88
+ context.err_at(self, source, error_msgs[:negative], error_pos)
89
+ else
90
+ [true, nil]
91
+ end
92
+ ensure
93
+ source.bytepos = rewind_pos
94
+ end
95
+
96
+ private
97
+
98
+ def rewind_chars(source, nchars)
99
+ input = source.input
100
+ pos = source.bytepos
101
+ nchars.times do
102
+ pos -= 1
103
+ pos -= 1 while pos.positive? && (input.getbyte(pos) & 0xC0) == 0x80
104
+ end
105
+ [pos, 0].max
106
+ end
107
+ end
108
+ end
109
+ end
110
+ end
111
+ end
112
+
113
+ # Additive DSL surface (no overrides): exposes the custom atoms on
114
+ # every atom the way the former parslet_extras refinements did.
115
+ module Parsanol
116
+ module Atoms
117
+ module DSL
118
+ def output(value)
119
+ Coradoc::Markdown::Parser::ParsanolAtoms::Output.new(self, value)
120
+ end
121
+
122
+ def dynamic_output(callable)
123
+ Coradoc::Markdown::Parser::ParsanolAtoms::DynamicOutput.new(self, callable)
124
+ end
125
+
126
+ def precedes?(num = 1)
127
+ Coradoc::Markdown::Parser::ParsanolAtoms::Lookbehind.new(self, num, positive: true)
128
+ end
129
+
130
+ def does_not_precede?(num = 1)
131
+ Coradoc::Markdown::Parser::ParsanolAtoms::Lookbehind.new(self, num, positive: false)
132
+ end
133
+ end
134
+ end
135
+ end
@@ -71,11 +71,11 @@ module Coradoc
71
71
  def self.extract_quoted_value(scanner, handle_escapes: false)
72
72
  if scanner.scan(/"([^"\\]*(?:\\.[^"\\]*)*)"/)
73
73
  value = scanner[1]
74
- value = value.gsub(/\\"/, '"') if handle_escapes
74
+ value = value.gsub('\"', '"') if handle_escapes
75
75
  value
76
76
  elsif scanner.scan(/'([^'\\]*(?:\\.[^'\\]*)*)'/)
77
77
  value = scanner[1]
78
- value = value.gsub(/\\'/, "'") if handle_escapes
78
+ value = value.gsub('\\\'', "'") if handle_escapes
79
79
  value
80
80
  elsif scanner.scan(/(\S+)/)
81
81
  scanner[1]
@@ -48,7 +48,7 @@ module Coradoc
48
48
  end
49
49
 
50
50
  def with(overrides)
51
- self.class.new(**to_h.merge(symbolize(overrides)))
51
+ self.class.new(**to_h, **symbolize(overrides))
52
52
  end
53
53
 
54
54
  private
@@ -58,15 +58,9 @@ module Coradoc
58
58
  end
59
59
 
60
60
  def validate_options!(resolved)
61
- unless %i[github container html gfm_alert].include?(resolved.fetch(:admonition_style))
62
- raise ArgumentError, "Unknown admonition_style: #{resolved[:admonition_style].inspect}"
63
- end
64
- unless %i[html flatten].include?(resolved.fetch(:definition_list_nested))
65
- raise ArgumentError, "Unknown definition_list_nested: #{resolved[:definition_list_nested].inspect}"
66
- end
67
- unless [true, false].include?(resolved.fetch(:suppress_comments))
68
- raise ArgumentError, 'suppress_comments must be boolean'
69
- end
61
+ raise ArgumentError, "Unknown admonition_style: #{resolved[:admonition_style].inspect}" unless %i[github container html gfm_alert].include?(resolved.fetch(:admonition_style))
62
+ raise ArgumentError, "Unknown definition_list_nested: #{resolved[:definition_list_nested].inspect}" unless %i[html flatten].include?(resolved.fetch(:definition_list_nested))
63
+ raise ArgumentError, 'suppress_comments must be boolean' unless [true, false].include?(resolved.fetch(:suppress_comments))
70
64
  return if [true, false].include?(resolved.fetch(:autolinks))
71
65
 
72
66
  raise ArgumentError, 'autolinks must be boolean'
@@ -39,7 +39,7 @@ module Coradoc
39
39
  def lookup!(element)
40
40
  lookup(element) || raise(ArgumentError,
41
41
  "Unknown element type for serialization: #{element.class}. " \
42
- 'Expected a known Markdown model type.')
42
+ 'Expected a known Markdown model type.')
43
43
  end
44
44
 
45
45
  private
@@ -40,7 +40,7 @@ module Coradoc
40
40
  else
41
41
  raise ArgumentError,
42
42
  "Unknown element type for serialization: #{element.class}. " \
43
- 'Expected a known Markdown model type.'
43
+ 'Expected a known Markdown model type.'
44
44
  end
45
45
  end
46
46
  end
@@ -55,6 +55,8 @@ module Coradoc
55
55
  Coradoc::Markdown::Text.new(content: model.title.to_s)
56
56
  when Coradoc::CoreModel::CommentLine
57
57
  Coradoc::Markdown::Comment.new(text: model.text.to_s)
58
+ when Coradoc::CoreModel::Include
59
+ transform_include(model)
58
60
  when Coradoc::CoreModel::TextContent
59
61
  model.text.to_s
60
62
  when Array
@@ -66,6 +68,17 @@ module Coradoc
66
68
 
67
69
  private
68
70
 
71
+ # Markdown has no transclusion — an unresolved include edge is
72
+ # preserved as an HTML comment so no information is lost and
73
+ # serialization never crashes on graph-mode documents.
74
+ def transform_include(element)
75
+ Coradoc::Markdown::Comment.new(text: include_directive_text(element))
76
+ end
77
+
78
+ def include_directive_text(element)
79
+ "include::#{element.target}[#{element.raw_options}]"
80
+ end
81
+
69
82
  def transform_structural_element(element)
70
83
  case element
71
84
  when CoreModel::DocumentElement
@@ -1,17 +1,17 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'parslet'
3
+ require 'parsanol'
4
4
 
5
5
  module Coradoc
6
6
  module Markdown
7
7
  autoload :ParserUtil, "#{__dir__}/parser_util"
8
8
 
9
- # Transformer converts Parslet AST into Markdown Document Model objects.
9
+ # Transformer converts Parsanol AST into Markdown Document Model objects.
10
10
  #
11
11
  # This transformer takes the raw output from the BlockParser/InlineParser
12
12
  # and converts it into semantic model objects (Heading, Paragraph, etc.)
13
13
  #
14
- class Transformer < Parslet::Transform
14
+ class Transformer < Parsanol::Transform
15
15
  # ATX Heading: # Heading
16
16
  rule(heading: simple(:heading), text: simple(:text)) do
17
17
  Heading.new(level: heading.to_s.length, text: text.to_s.strip)
@@ -198,7 +198,7 @@ module Coradoc
198
198
  when Array
199
199
  # Transform each item
200
200
  element.map { |e| transform_element(e) }.compact
201
- when Parslet::Slice
201
+ when Parsanol::Slice
202
202
  Text.new(content: element.to_s)
203
203
  else
204
204
  Text.new(content: element.to_s)
@@ -536,7 +536,7 @@ module Coradoc
536
536
  else
537
537
  content.values.map { |v| extract_text(v) }.join
538
538
  end
539
- when Parslet::Slice
539
+ when Parsanol::Slice
540
540
  content.to_s
541
541
  else
542
542
  content.to_s
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Coradoc
4
4
  module Markdown
5
- VERSION = '1.0.10'
5
+ VERSION = '1.0.12'
6
6
  end
7
7
  end
@@ -5,7 +5,7 @@
5
5
  # This gem provides Markdown support for the Coradoc document processing library.
6
6
  # It includes:
7
7
  # - Markdown Document Model (Coradoc::Markdown::*)
8
- # - Markdown Parser (CommonMark-compliant, Parslet-based)
8
+ # - Markdown Parser (CommonMark-compliant, Parsanol-based)
9
9
  # - Markdown Serializer (round-trip capable)
10
10
  # - Kramdown extensions support (IAL, ALD, math, TOC)
11
11
  #
@@ -18,7 +18,8 @@
18
18
  # # Serialize back to Markdown
19
19
  # output = Coradoc::Markdown.serialize(document)
20
20
 
21
- require 'parslet'
21
+ require 'parsanol'
22
+ require 'parsanol/convenience'
22
23
  require 'lutaml/model'
23
24
 
24
25
  # Coradoc document transformation library.
@@ -91,7 +92,7 @@ module Coradoc
91
92
  module Parser
92
93
  autoload :BlockParser, 'coradoc/markdown/parser/block_parser'
93
94
  autoload :InlineParser, 'coradoc/markdown/parser/inline_parser'
94
- autoload :ParsletExtras, 'coradoc/markdown/parser/parslet_extras'
95
+ autoload :ParsanolAtoms, 'coradoc/markdown/parser/parsanol_atoms'
95
96
  autoload :HTML_ENTITIES, 'coradoc/markdown/parser/html_entities'
96
97
  autoload :AstProcessor, 'coradoc/markdown/parser/ast_processor'
97
98
  autoload :FrontmatterParser, 'coradoc/markdown/parser/frontmatter_parser'
@@ -127,9 +128,9 @@ module Coradoc
127
128
  # @param filename [String] Path to the Markdown file
128
129
  # @param options [Hash] Parsing options (see #parse)
129
130
  # @return [Array] The parsed AST
130
- def from_file(filename, **options)
131
+ def from_file(filename, **)
131
132
  content = File.read(filename)
132
- parse(content, **options)
133
+ parse(content, **)
133
134
  end
134
135
 
135
136
  # Parse inline Markdown content
@@ -150,6 +151,13 @@ module Coradoc
150
151
  Serializer.serialize(document, options)
151
152
  end
152
153
 
154
+ # Markdown preserves unresolved include edges as HTML comments
155
+ # (Transform::FromCoreModel#transform_include) — lossy formatting,
156
+ # but never silent content loss.
157
+ def preserves_unresolved_includes?
158
+ true
159
+ end
160
+
153
161
  # Check if this format can transform the given model to CoreModel
154
162
  #
155
163
  # @param model [Object] The model to check
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: coradoc-markdown
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.10
4
+ version: 1.0.12
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
  - - ">="
@@ -94,7 +94,7 @@ dependencies:
94
94
  - !ruby/object:Gem::Version
95
95
  version: '0'
96
96
  description: Provides Markdown parsing and serialization capabilities for Coradoc.
97
- Includes the Markdown Document Model, a CommonMark-compliant Parslet-based parser,
97
+ Includes the Markdown Document Model, a CommonMark-compliant Parsanol-based parser,
98
98
  and round-trip capable serializer.
99
99
  email:
100
100
  - open.source@ribose.com
@@ -152,7 +152,7 @@ files:
152
152
  - lib/coradoc/markdown/parser/frontmatter_parser.rb
153
153
  - lib/coradoc/markdown/parser/html_entities.rb
154
154
  - lib/coradoc/markdown/parser/inline_parser.rb
155
- - lib/coradoc/markdown/parser/parslet_extras.rb
155
+ - lib/coradoc/markdown/parser/parsanol_atoms.rb
156
156
  - lib/coradoc/markdown/parser_util.rb
157
157
  - lib/coradoc/markdown/serializer.rb
158
158
  - lib/coradoc/markdown/serializer/builder.rb
@@ -232,6 +232,7 @@ metadata:
232
232
  homepage_uri: https://github.com/metanorma/coradoc
233
233
  source_code_uri: https://github.com/metanorma/coradoc
234
234
  changelog_uri: https://github.com/metanorma/coradoc/releases
235
+ rubygems_mfa_required: 'true'
235
236
  rdoc_options: []
236
237
  require_paths:
237
238
  - lib
@@ -1,215 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'parslet'
4
- require 'parslet/convenience'
5
-
6
- module Coradoc
7
- module Markdown
8
- module Parser
9
- module ParsletExtras
10
- refine Parslet::Source do
11
- def rewind(nchars)
12
- # https://github.com/ruby/strscan/issues/122
13
- self.charpos = @str.charpos - nchars
14
- end
15
-
16
- def charpos=(pos)
17
- @str.reset
18
- @str.getch while @str.charpos < pos
19
- end
20
-
21
- def charpos
22
- @str.charpos
23
- end
24
-
25
- def peek_byte
26
- @str.peek(1)
27
- end
28
- end
29
-
30
- refine Parslet::Scope do
31
- attr_reader :current
32
-
33
- def key?(...)
34
- @current.key?(...)
35
- end
36
-
37
- def has_key?(...)
38
- @current.key?(...)
39
- end
40
-
41
- def root
42
- scope = current
43
- scope = scope.parent while scope.parent
44
- scope
45
- end
46
- end
47
-
48
- refine Parslet::Scope::Binding do
49
- def key?(...)
50
- @hash.key?(...)
51
- end
52
-
53
- def has_key?(...)
54
- @hash.key?(...)
55
- end
56
-
57
- def initialize_copy(original)
58
- super
59
- @hash = @hash.clone
60
- end
61
- end
62
-
63
- # like Named but returning other things
64
- class Output < Parslet::Atoms::Base
65
- attr_reader :parslet, :value
66
-
67
- def initialize(parslet, value)
68
- super()
69
-
70
- @parslet = parslet
71
- @value = value
72
- end
73
-
74
- def apply(source, context, consume_all)
75
- success, = result = parslet.apply(source, context, consume_all)
76
-
77
- return result unless success
78
-
79
- succ(@value)
80
- end
81
-
82
- def to_s_inner(prec)
83
- "#{value}:#{parslet.to_s(prec)}"
84
- end
85
- end
86
-
87
- class DynamicOutput < Parslet::Atoms::Base
88
- attr_reader :parslet, :callable
89
-
90
- def initialize(parslet, callable)
91
- super()
92
-
93
- @parslet = parslet
94
- @callable = callable
95
- end
96
-
97
- def apply(source, context, consume_all)
98
- success, value = result = parslet.apply(source, context, consume_all)
99
-
100
- return result unless success
101
-
102
- succ(@callable.call(flatten(value)))
103
- end
104
-
105
- def to_s_inner(prec)
106
- "#{callable}:#{parslet.to_s(prec)}"
107
- end
108
- end
109
-
110
- class Lookbehind < Parslet::Atoms::Base
111
- using ParsletExtras
112
- attr_reader :positive
113
- attr_reader :number, :bound_parslet
114
-
115
- def initialize(bound_parslet, number, positive: true)
116
- super()
117
-
118
- # Model positive and negative lookbehind by testing this flag.
119
- @positive = positive
120
- @number = number
121
- @bound_parslet = bound_parslet
122
- end
123
-
124
- def error_msgs
125
- @error_msgs ||= {
126
- positive: ['Input should be preceded by ', bound_parslet],
127
- negative: ['Input should not be preceded by ', bound_parslet]
128
- }
129
- end
130
-
131
- def try(source, context, consume_all)
132
- rewind_pos = source.bytepos
133
- if source.bytepos.zero?
134
- return succ(nil) unless positive
135
-
136
- return context.err_at(self, source, error_msgs[:positive], source.pos)
137
- end
138
- source.rewind(number)
139
- error_pos = source.pos
140
-
141
- success, = bound_parslet.apply(source, context, consume_all)
142
-
143
- if positive
144
- return succ(nil) if success
145
-
146
- context.err_at(self, source, error_msgs[:positive], error_pos)
147
- else
148
- return succ(nil) unless success
149
-
150
- context.err_at(self, source, error_msgs[:negative], error_pos)
151
- end
152
- ensure
153
- source.bytepos = rewind_pos
154
- end
155
-
156
- def to_s_inner(prec)
157
- @char = positive ? '&' : '!'
158
- "<#{@char}<#{number}<#{bound_parslet.to_s(prec)}"
159
- end
160
- end
161
-
162
- # Like Dynamic but does not return a further parslet, just a reject/accept boolean
163
- module ::Parslet
164
- module Atoms
165
- class Check < ::Parslet::Atoms::Base
166
- attr_reader :block
167
-
168
- def initialize(block)
169
- super()
170
- @block = block
171
- end
172
-
173
- def cached?
174
- false
175
- end
176
-
177
- def try(source, context, _consume_all)
178
- [block.call(source, context), nil]
179
- end
180
-
181
- def to_s_inner(_prec)
182
- 'check { ... }'
183
- end
184
- end
185
- end
186
- end
187
-
188
- refine ::Parslet do
189
- def check(&block)
190
- ::Parslet::Atoms::Check.new(block)
191
- end
192
- module_function :check
193
- end
194
-
195
- refine ::Parslet::Atoms::DSL do
196
- def output(value)
197
- Output.new(self, value)
198
- end
199
-
200
- def dynamic_output(value)
201
- DynamicOutput.new(self, value)
202
- end
203
-
204
- def precedes?(num = 1)
205
- Lookbehind.new(self, num, positive: true)
206
- end
207
-
208
- def does_not_precede?(num = 1)
209
- Lookbehind.new(self, num, positive: false)
210
- end
211
- end
212
- end
213
- end
214
- end
215
- end