coradoc-markdown 1.0.11 → 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: 860562e968c6a646a564edac417a882d9d477ef09c7bb84c477a6ab13fcd6fd0
4
- data.tar.gz: de5901c3b2e6eb123a718a14466d6bf688358e350ad95564abfcc17ebd62c660
3
+ metadata.gz: 232eab66f6d33edae8a3cca57f5ebd16cca11ed96c4dd9a51611b9669410595b
4
+ data.tar.gz: 1b0f0051729a0e226826c66d49bed0c4227732491b0bbf6148f42df524b1e95f
5
5
  SHA512:
6
- metadata.gz: 313e3f097c07329bfacd65ce3283c33087136a9e3d8f5259298c40781b76d10495b98dd89c3c3977b27e40d667d0a056ef9c012dc89165bcecc47293333e3442
7
- data.tar.gz: 5125a17bab25bde3da034de5b898fd28214f9e18857a9ca471e03795683fd2a9f85d3d7c3bd2925d0abf1f4b36acf6e37c71ef6f4ce2aa7389a65c7e562f8bf3
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
@@ -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)
@@ -32,7 +31,7 @@ module Coradoc
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
@@ -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? }
@@ -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
@@ -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.11'
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'
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.11
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
@@ -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