markbridge 0.1.2 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/LICENSE.txt +1 -1
- data/lib/markbridge/ast/details.rb +24 -0
- data/lib/markbridge/ast/element.rb +63 -0
- data/lib/markbridge/ast.rb +1 -0
- data/lib/markbridge/conversion.rb +40 -0
- data/lib/markbridge/parse.rb +20 -0
- data/lib/markbridge/parsers/bbcode/handler_registry.rb +25 -2
- data/lib/markbridge/parsers/bbcode/handlers/raw_handler.rb +13 -2
- data/lib/markbridge/parsers/html/handler_registry.rb +97 -17
- data/lib/markbridge/parsers/html/handlers/self_closing_handler.rb +26 -0
- data/lib/markbridge/parsers/html/handlers/span_handler.rb +74 -0
- data/lib/markbridge/parsers/html/parser.rb +88 -18
- data/lib/markbridge/parsers/html.rb +2 -0
- data/lib/markbridge/parsers/media_wiki/inline_parser.rb +21 -8
- data/lib/markbridge/parsers/media_wiki/parser.rb +13 -5
- data/lib/markbridge/parsers/text_formatter/handler_registry.rb +27 -4
- data/lib/markbridge/parsers/text_formatter/handlers/attachment_handler.rb +1 -1
- data/lib/markbridge/parsers/text_formatter/handlers/attribute_handler.rb +1 -1
- data/lib/markbridge/parsers/text_formatter/handlers/base_handler.rb +1 -1
- data/lib/markbridge/parsers/text_formatter/handlers/code_handler.rb +1 -1
- data/lib/markbridge/parsers/text_formatter/handlers/email_handler.rb +1 -1
- data/lib/markbridge/parsers/text_formatter/handlers/image_handler.rb +1 -1
- data/lib/markbridge/parsers/text_formatter/handlers/list_handler.rb +1 -1
- data/lib/markbridge/parsers/text_formatter/handlers/quote_handler.rb +1 -1
- data/lib/markbridge/parsers/text_formatter/handlers/simple_handler.rb +1 -1
- data/lib/markbridge/parsers/text_formatter/handlers/table_cell_handler.rb +1 -1
- data/lib/markbridge/parsers/text_formatter/handlers/url_handler.rb +1 -1
- data/lib/markbridge/parsers/text_formatter/parser.rb +17 -3
- data/lib/markbridge/renderers/discourse/identity_escaper.rb +37 -0
- data/lib/markbridge/renderers/discourse/markdown_escaper.rb +91 -9
- data/lib/markbridge/renderers/discourse/postprocessor.rb +53 -0
- data/lib/markbridge/renderers/discourse/render_context.rb +14 -40
- data/lib/markbridge/renderers/discourse/renderer.rb +15 -5
- data/lib/markbridge/renderers/discourse/rendering_interface.rb +4 -3
- data/lib/markbridge/renderers/discourse/tag_library.rb +42 -2
- data/lib/markbridge/renderers/discourse/tags/align_tag.rb +2 -2
- data/lib/markbridge/renderers/discourse/tags/code_tag.rb +5 -3
- data/lib/markbridge/renderers/discourse/tags/details_tag.rb +46 -0
- data/lib/markbridge/renderers/discourse/tags/heading_tag.rb +1 -1
- data/lib/markbridge/renderers/discourse/tags/paragraph_tag.rb +5 -2
- data/lib/markbridge/renderers/discourse/tags/quote_tag.rb +4 -3
- data/lib/markbridge/renderers/discourse/tags/underline_tag.rb +13 -0
- data/lib/markbridge/renderers/discourse.rb +3 -0
- data/lib/markbridge/version.rb +1 -1
- data/lib/markbridge.rb +274 -110
- metadata +9 -2
- data/lib/markbridge/configuration.rb +0 -11
data/lib/markbridge.rb
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require_relative "markbridge/version"
|
|
4
|
-
require_relative "markbridge/
|
|
4
|
+
require_relative "markbridge/parse"
|
|
5
|
+
require_relative "markbridge/conversion"
|
|
5
6
|
|
|
6
7
|
require_relative "markbridge/ast"
|
|
7
8
|
require_relative "markbridge/renderers/discourse"
|
|
@@ -9,158 +10,321 @@ require_relative "markbridge/processors"
|
|
|
9
10
|
|
|
10
11
|
module Markbridge
|
|
11
12
|
class << self
|
|
12
|
-
# Parse BBCode to AST
|
|
13
|
+
# Parse BBCode to AST.
|
|
14
|
+
#
|
|
13
15
|
# @param input [String] BBCode source
|
|
14
|
-
# @param handlers [HandlerRegistry, nil] custom
|
|
15
|
-
# @return [
|
|
16
|
+
# @param handlers [Parsers::BBCode::HandlerRegistry, nil] custom handlers (defaults to .default)
|
|
17
|
+
# @return [Parse]
|
|
16
18
|
def parse_bbcode(input, handlers: nil)
|
|
17
|
-
|
|
18
|
-
|
|
19
|
+
raise ArgumentError, "input cannot be nil" if input.nil?
|
|
20
|
+
|
|
21
|
+
parser = Parsers::BBCode::Parser.new(handlers:)
|
|
22
|
+
ast = parser.parse(input.to_s)
|
|
23
|
+
|
|
24
|
+
Parse.new(
|
|
25
|
+
ast:,
|
|
26
|
+
format: :bbcode,
|
|
27
|
+
unknown_tags: parser.unknown_tags,
|
|
28
|
+
diagnostics: bbcode_diagnostics(parser),
|
|
29
|
+
)
|
|
19
30
|
end
|
|
20
31
|
|
|
21
|
-
# Convert BBCode to Discourse Markdown
|
|
32
|
+
# Convert BBCode to Discourse Markdown.
|
|
33
|
+
#
|
|
34
|
+
# If a block is given, it is called with the parsed AST between
|
|
35
|
+
# parse and render — the caller can append/remove/replace nodes
|
|
36
|
+
# before rendering. Mutations to the yielded AST persist in
|
|
37
|
+
# {Conversion#ast}.
|
|
38
|
+
#
|
|
22
39
|
# @param input [String] BBCode source
|
|
23
|
-
# @param handlers [HandlerRegistry, nil] custom
|
|
24
|
-
# @param
|
|
25
|
-
#
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
40
|
+
# @param handlers [Parsers::BBCode::HandlerRegistry, nil] custom handlers
|
|
41
|
+
# @param renderer [Renderers::Discourse::Renderer, nil] custom renderer
|
|
42
|
+
# (build with {.discourse_renderer}); defaults to a fresh default Renderer
|
|
43
|
+
# @param raise_on_error [Boolean] when true (default), let render-time
|
|
44
|
+
# exceptions propagate; when false, swallow them, return a
|
|
45
|
+
# {Conversion} with an empty +markdown+ string, and surface the
|
|
46
|
+
# exceptions via {Conversion#errors}.
|
|
47
|
+
# @yieldparam ast [AST::Document] mutate before rendering (optional)
|
|
48
|
+
# @return [Conversion]
|
|
49
|
+
def bbcode_to_markdown(input, handlers: nil, renderer: nil, raise_on_error: true)
|
|
50
|
+
parse = parse_bbcode(input, handlers:)
|
|
51
|
+
yield(parse.ast) if block_given?
|
|
52
|
+
build_conversion(parse, renderer:, raise_on_error:)
|
|
29
53
|
end
|
|
30
54
|
|
|
31
|
-
# Parse HTML to AST
|
|
32
|
-
#
|
|
33
|
-
# @param
|
|
34
|
-
#
|
|
55
|
+
# Parse HTML to AST.
|
|
56
|
+
#
|
|
57
|
+
# @param input [String, Nokogiri::XML::Node] HTML source or
|
|
58
|
+
# pre-parsed Nokogiri tree (e.g. the +DocumentFragment+ returned
|
|
59
|
+
# by +Nokogiri::HTML.fragment+). Passing a pre-parsed tree lets
|
|
60
|
+
# callers run their own Nokogiri-driven pre-processing without
|
|
61
|
+
# forcing Markbridge to re-parse the same bytes.
|
|
62
|
+
# @param handlers [Parsers::HTML::HandlerRegistry, nil] custom handlers
|
|
63
|
+
# @return [Parse]
|
|
35
64
|
def parse_html(input, handlers: nil)
|
|
36
|
-
|
|
37
|
-
|
|
65
|
+
raise ArgumentError, "input cannot be nil" if input.nil?
|
|
66
|
+
|
|
67
|
+
parser = Parsers::HTML::Parser.new(handlers:)
|
|
68
|
+
ast = parser.parse(input)
|
|
69
|
+
|
|
70
|
+
Parse.new(ast:, format: :html, unknown_tags: parser.unknown_tags, diagnostics: {})
|
|
38
71
|
end
|
|
39
72
|
|
|
40
|
-
# Convert HTML to Discourse Markdown
|
|
41
|
-
#
|
|
42
|
-
#
|
|
43
|
-
#
|
|
44
|
-
#
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
73
|
+
# Convert HTML to Discourse Markdown.
|
|
74
|
+
#
|
|
75
|
+
# If a block is given, it is called with the parsed AST between
|
|
76
|
+
# parse and render — the caller can append/remove/replace nodes
|
|
77
|
+
# before rendering. Mutations to the yielded AST persist in
|
|
78
|
+
# {Conversion#ast}.
|
|
79
|
+
#
|
|
80
|
+
# @param input [String, Nokogiri::XML::Node] HTML source or
|
|
81
|
+
# pre-parsed Nokogiri tree (see {.parse_html})
|
|
82
|
+
# @param handlers [Parsers::HTML::HandlerRegistry, nil] custom handlers
|
|
83
|
+
# @param renderer [Renderers::Discourse::Renderer, nil] custom renderer
|
|
84
|
+
# @param raise_on_error [Boolean] when true (default), let render-time
|
|
85
|
+
# exceptions propagate; when false, swallow them, return a
|
|
86
|
+
# {Conversion} with an empty +markdown+ string, and surface the
|
|
87
|
+
# exceptions via {Conversion#errors}.
|
|
88
|
+
# @yieldparam ast [AST::Document] mutate before rendering (optional)
|
|
89
|
+
# @return [Conversion]
|
|
90
|
+
def html_to_markdown(input, handlers: nil, renderer: nil, raise_on_error: true)
|
|
91
|
+
parse = parse_html(input, handlers:)
|
|
92
|
+
yield(parse.ast) if block_given?
|
|
93
|
+
build_conversion(parse, renderer:, raise_on_error:)
|
|
48
94
|
end
|
|
49
95
|
|
|
50
|
-
# Parse s9e/TextFormatter XML to AST
|
|
51
|
-
#
|
|
52
|
-
# @param
|
|
53
|
-
#
|
|
96
|
+
# Parse s9e/TextFormatter XML to AST.
|
|
97
|
+
#
|
|
98
|
+
# @param input [String, Nokogiri::XML::Node] XML source or
|
|
99
|
+
# pre-parsed Nokogiri tree. A +Nokogiri::XML::Document+ is
|
|
100
|
+
# unwrapped via +#root+; any other node is treated as the root.
|
|
101
|
+
# @param handlers [Parsers::TextFormatter::HandlerRegistry, nil] custom handlers
|
|
102
|
+
# @return [Parse]
|
|
54
103
|
def parse_text_formatter_xml(input, handlers: nil)
|
|
55
|
-
|
|
56
|
-
|
|
104
|
+
raise ArgumentError, "input cannot be nil" if input.nil?
|
|
105
|
+
|
|
106
|
+
parser = Parsers::TextFormatter::Parser.new(handlers:)
|
|
107
|
+
ast = parser.parse(input)
|
|
108
|
+
unknown_tags = parser.unknown_tags
|
|
109
|
+
|
|
110
|
+
Parse.new(ast:, format: :text_formatter_xml, unknown_tags:, diagnostics: {})
|
|
57
111
|
end
|
|
58
112
|
|
|
59
|
-
# Convert s9e/TextFormatter XML to Discourse Markdown
|
|
60
|
-
#
|
|
61
|
-
#
|
|
62
|
-
#
|
|
63
|
-
#
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
113
|
+
# Convert s9e/TextFormatter XML to Discourse Markdown.
|
|
114
|
+
#
|
|
115
|
+
# If a block is given, it is called with the parsed AST between
|
|
116
|
+
# parse and render — the caller can append/remove/replace nodes
|
|
117
|
+
# before rendering. Mutations to the yielded AST persist in
|
|
118
|
+
# {Conversion#ast}.
|
|
119
|
+
#
|
|
120
|
+
# @param input [String, Nokogiri::XML::Node] XML source or
|
|
121
|
+
# pre-parsed Nokogiri tree (see {.parse_text_formatter_xml})
|
|
122
|
+
# @param handlers [Parsers::TextFormatter::HandlerRegistry, nil] custom handlers
|
|
123
|
+
# @param renderer [Renderers::Discourse::Renderer, nil] custom renderer
|
|
124
|
+
# @param raise_on_error [Boolean] see {.bbcode_to_markdown}
|
|
125
|
+
# @yieldparam ast [AST::Document] mutate before rendering (optional)
|
|
126
|
+
# @return [Conversion]
|
|
127
|
+
def text_formatter_xml_to_markdown(input, handlers: nil, renderer: nil, raise_on_error: true)
|
|
128
|
+
parse = parse_text_formatter_xml(input, handlers:)
|
|
129
|
+
yield(parse.ast) if block_given?
|
|
130
|
+
build_conversion(parse, renderer:, raise_on_error:)
|
|
67
131
|
end
|
|
68
132
|
|
|
69
|
-
# Parse MediaWiki wikitext to AST
|
|
133
|
+
# Parse MediaWiki wikitext to AST.
|
|
134
|
+
#
|
|
70
135
|
# @param input [String] MediaWiki source
|
|
71
|
-
# @param
|
|
72
|
-
# @return [
|
|
73
|
-
def parse_mediawiki(input,
|
|
136
|
+
# @param handlers [Parsers::MediaWiki::InlineTagRegistry, nil] custom inline-tag registry
|
|
137
|
+
# @return [Parse]
|
|
138
|
+
def parse_mediawiki(input, handlers: nil)
|
|
74
139
|
raise ArgumentError, "input cannot be nil" if input.nil?
|
|
75
140
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
141
|
+
parser = Parsers::MediaWiki::Parser.new(handlers:)
|
|
142
|
+
ast = parser.parse(input.to_s)
|
|
143
|
+
|
|
144
|
+
Parse.new(ast:, format: :mediawiki, unknown_tags: parser.unknown_tags, diagnostics: {})
|
|
79
145
|
end
|
|
80
146
|
|
|
81
|
-
# Convert MediaWiki wikitext to Discourse Markdown
|
|
147
|
+
# Convert MediaWiki wikitext to Discourse Markdown.
|
|
148
|
+
#
|
|
149
|
+
# If a block is given, it is called with the parsed AST between
|
|
150
|
+
# parse and render — the caller can append/remove/replace nodes
|
|
151
|
+
# before rendering. Mutations to the yielded AST persist in
|
|
152
|
+
# {Conversion#ast}.
|
|
153
|
+
#
|
|
82
154
|
# @param input [String] MediaWiki source
|
|
83
|
-
# @param
|
|
84
|
-
# @param
|
|
85
|
-
# @
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
155
|
+
# @param handlers [Parsers::MediaWiki::InlineTagRegistry, nil]
|
|
156
|
+
# @param renderer [Renderers::Discourse::Renderer, nil] custom renderer
|
|
157
|
+
# @param raise_on_error [Boolean] see {.bbcode_to_markdown}
|
|
158
|
+
# @yieldparam ast [AST::Document] mutate before rendering (optional)
|
|
159
|
+
# @return [Conversion]
|
|
160
|
+
def mediawiki_to_markdown(input, handlers: nil, renderer: nil, raise_on_error: true)
|
|
161
|
+
parse = parse_mediawiki(input, handlers:)
|
|
162
|
+
yield(parse.ast) if block_given?
|
|
163
|
+
build_conversion(parse, renderer:, raise_on_error:)
|
|
89
164
|
end
|
|
90
165
|
|
|
91
|
-
#
|
|
92
|
-
#
|
|
93
|
-
|
|
94
|
-
|
|
166
|
+
# Convert input in the given format. Thin dispatcher over the
|
|
167
|
+
# four +*_to_markdown+ methods; useful when the format is data-
|
|
168
|
+
# driven (e.g. iterating posts whose +:format+ column varies).
|
|
169
|
+
# An optional block is forwarded to the dispatched method.
|
|
170
|
+
#
|
|
171
|
+
# @param input [String, Nokogiri::XML::Node] source content; the
|
|
172
|
+
# HTML and TextFormatter dispatch targets also accept pre-parsed
|
|
173
|
+
# Nokogiri trees.
|
|
174
|
+
# @param format [Symbol] one of +:bbcode+, +:html+,
|
|
175
|
+
# +:text_formatter_xml+, +:mediawiki+
|
|
176
|
+
# @param kwargs [Hash] forwarded to the underlying convenience method
|
|
177
|
+
# (e.g. +handlers:+, +renderer:+, +raise_on_error:+).
|
|
178
|
+
# @yieldparam ast [AST::Document] mutate before rendering (optional)
|
|
179
|
+
# @return [Conversion]
|
|
180
|
+
def convert(input, format:, **kwargs, &block)
|
|
181
|
+
case format
|
|
182
|
+
when :bbcode
|
|
183
|
+
bbcode_to_markdown(input, **kwargs, &block)
|
|
184
|
+
when :html
|
|
185
|
+
html_to_markdown(input, **kwargs, &block)
|
|
186
|
+
when :text_formatter_xml
|
|
187
|
+
text_formatter_xml_to_markdown(input, **kwargs, &block)
|
|
188
|
+
when :mediawiki
|
|
189
|
+
mediawiki_to_markdown(input, **kwargs, &block)
|
|
190
|
+
else
|
|
191
|
+
raise ArgumentError,
|
|
192
|
+
"unknown format #{format.inspect} " \
|
|
193
|
+
"(expected :bbcode, :html, :text_formatter_xml, or :mediawiki)"
|
|
194
|
+
end
|
|
95
195
|
end
|
|
96
196
|
|
|
97
|
-
#
|
|
98
|
-
#
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
197
|
+
# Render a {Parse} or a bare AST node to Discourse Markdown.
|
|
198
|
+
# Useful when the caller has mutated the AST between parse and
|
|
199
|
+
# render (e.g. appending attachments not present in the source),
|
|
200
|
+
# or built an AST programmatically.
|
|
201
|
+
#
|
|
202
|
+
# When given a {Parse}, the returned {Conversion} carries the
|
|
203
|
+
# parser's +unknown_tags+, +diagnostics+, and source +format+
|
|
204
|
+
# forward. When given an AST node, those fields default to empty
|
|
205
|
+
# and +format+ is +nil+ — there was no source document, so there
|
|
206
|
+
# is no source format to report. A bare node that isn't already a
|
|
207
|
+
# {AST::Document} is wrapped in one, so {Conversion#ast} is always
|
|
208
|
+
# a Document (and tree helpers like +each_descendant+ are always
|
|
209
|
+
# available on it).
|
|
210
|
+
#
|
|
211
|
+
# @param parse_or_ast [Parse, AST::Node]
|
|
212
|
+
# @param format [Symbol] :discourse (only renderer currently shipped)
|
|
213
|
+
# @param renderer [Renderers::Discourse::Renderer, nil]
|
|
214
|
+
# @param raise_on_error [Boolean]
|
|
215
|
+
# @return [Conversion]
|
|
216
|
+
def render(parse_or_ast, format: :discourse, renderer: nil, raise_on_error: true)
|
|
217
|
+
raise ArgumentError, "unknown render format #{format.inspect}" unless format == :discourse
|
|
102
218
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
219
|
+
parse =
|
|
220
|
+
case parse_or_ast
|
|
221
|
+
when Parse
|
|
222
|
+
parse_or_ast
|
|
223
|
+
when AST::Document
|
|
224
|
+
Parse.new(ast: parse_or_ast, format: nil, unknown_tags: {}, diagnostics: {})
|
|
225
|
+
when AST::Node
|
|
226
|
+
document = AST::Document.new([parse_or_ast])
|
|
227
|
+
Parse.new(ast: document, format: nil, unknown_tags: {}, diagnostics: {})
|
|
228
|
+
else
|
|
229
|
+
raise ArgumentError, "expected Parse or AST::Node, got #{parse_or_ast.class}"
|
|
230
|
+
end
|
|
108
231
|
|
|
109
|
-
|
|
110
|
-
# @return [Parsers::TextFormatter::HandlerRegistry]
|
|
111
|
-
def default_text_formatter_handlers
|
|
112
|
-
@default_text_formatter_handlers ||= Parsers::TextFormatter::HandlerRegistry.default
|
|
232
|
+
build_conversion(parse, renderer:, raise_on_error:)
|
|
113
233
|
end
|
|
114
234
|
|
|
115
|
-
#
|
|
116
|
-
#
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
235
|
+
# Build a configured Discourse {Renderers::Discourse::Renderer}
|
|
236
|
+
# for use with the +renderer:+ kwarg on the +*_to_markdown+
|
|
237
|
+
# convenience methods.
|
|
238
|
+
#
|
|
239
|
+
# @param tags [Hash{Class => Tag, nil}, nil] mappings to merge on
|
|
240
|
+
# top of the default library; +nil+ values unregister the class.
|
|
241
|
+
# @param tag_library [Renderers::Discourse::TagLibrary, nil] base
|
|
242
|
+
# library to start from. Defaults to a fresh {TagLibrary.default}.
|
|
243
|
+
# When supplied, it is +dup+'d before any +tags:+ / +unregister:+
|
|
244
|
+
# mutation, so the caller's library is left untouched.
|
|
245
|
+
# @param unregister [Array<Class>, nil] AST classes to drop from
|
|
246
|
+
# the library so they fall through to +render_children+.
|
|
247
|
+
# @param escaper [#escape, nil] when given, used as-is; +escape:+,
|
|
248
|
+
# +escape_hard_line_breaks:+, and +allow:+ are then ignored.
|
|
249
|
+
# @param escape [Boolean] when +false+, the renderer is built with
|
|
250
|
+
# {Renderers::Discourse::IdentityEscaper} (no Markdown escaping).
|
|
251
|
+
# Mutually exclusive with +escape_hard_line_breaks:+ / +allow:+.
|
|
252
|
+
# @param escape_hard_line_breaks [Boolean] forwarded to a fresh
|
|
253
|
+
# {MarkdownEscaper} when no explicit +escaper:+ is given.
|
|
254
|
+
# @param allow [Symbol, Array<Symbol>, nil] block-level constructs to
|
|
255
|
+
# pass through unescaped (e.g. +:lists+, +:bullet_list+,
|
|
256
|
+
# +:ordered_list+, +:atx_heading+, +:block_quote+); forwarded to a
|
|
257
|
+
# fresh {MarkdownEscaper}.
|
|
258
|
+
# @param postprocessor [Renderers::Discourse::Postprocessor, nil] when given,
|
|
259
|
+
# used as-is; +strip_trailing_invisibles:+ is then ignored.
|
|
260
|
+
# @param strip_trailing_invisibles [Boolean] forwarded to a fresh
|
|
261
|
+
# {Renderers::Discourse::Postprocessor} when no explicit
|
|
262
|
+
# +postprocessor:+ is given. Strips NBSP and zero-width format
|
|
263
|
+
# characters from the end of each line.
|
|
264
|
+
# @return [Renderers::Discourse::Renderer]
|
|
265
|
+
def discourse_renderer(
|
|
266
|
+
tags: nil,
|
|
267
|
+
tag_library: nil,
|
|
268
|
+
unregister: nil,
|
|
269
|
+
escaper: nil,
|
|
270
|
+
escape: true,
|
|
271
|
+
escape_hard_line_breaks: false,
|
|
272
|
+
allow: nil,
|
|
273
|
+
postprocessor: nil,
|
|
274
|
+
strip_trailing_invisibles: false
|
|
275
|
+
)
|
|
276
|
+
# Dup the caller's library before mutating so successive
|
|
277
|
+
# +discourse_renderer+ calls against the same +tag_library:+ don't
|
|
278
|
+
# see each other's overrides. +TagLibrary.default+ already returns
|
|
279
|
+
# a fresh instance, so the dup is only needed in the explicit
|
|
280
|
+
# +tag_library:+ branch.
|
|
281
|
+
library = tag_library ? tag_library.dup : Renderers::Discourse::TagLibrary.default
|
|
282
|
+
library.merge!(tags) if tags
|
|
283
|
+
Array(unregister).each { |klass| library.unregister(klass) }
|
|
120
284
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
def configure
|
|
124
|
-
yield configuration
|
|
125
|
-
end
|
|
285
|
+
escaper ||= build_escaper(escape:, escape_hard_line_breaks:, allow:)
|
|
286
|
+
postprocessor ||= Renderers::Discourse::Postprocessor.new(strip_trailing_invisibles:)
|
|
126
287
|
|
|
127
|
-
|
|
128
|
-
def reset_defaults!
|
|
129
|
-
@default_handlers = nil
|
|
130
|
-
@default_html_handlers = nil
|
|
131
|
-
@default_tag_library = nil
|
|
132
|
-
@default_text_formatter_handlers = nil
|
|
133
|
-
@configuration = nil
|
|
288
|
+
Renderers::Discourse::Renderer.new(tag_library: library, escaper:, postprocessor:)
|
|
134
289
|
end
|
|
135
290
|
|
|
136
291
|
private
|
|
137
292
|
|
|
138
|
-
def
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
293
|
+
def bbcode_diagnostics(parser)
|
|
294
|
+
{
|
|
295
|
+
auto_closed_tags_count: parser.auto_closed_tags_count,
|
|
296
|
+
depth_exceeded_count: parser.depth_exceeded_count,
|
|
297
|
+
unclosed_raw_tags: parser.unclosed_raw_tags,
|
|
298
|
+
}
|
|
143
299
|
end
|
|
144
300
|
|
|
145
|
-
def
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
301
|
+
def build_conversion(parse, renderer:, raise_on_error:)
|
|
302
|
+
renderer ||= Renderers::Discourse::Renderer.new
|
|
303
|
+
markdown, errors = render_through(renderer, parse.ast, raise_on_error:)
|
|
304
|
+
|
|
305
|
+
Conversion.new(parsed: parse, markdown:, errors:)
|
|
149
306
|
end
|
|
150
307
|
|
|
151
|
-
def
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
308
|
+
def build_escaper(escape:, escape_hard_line_breaks:, allow:)
|
|
309
|
+
if escape == false
|
|
310
|
+
if escape_hard_line_breaks || allow
|
|
311
|
+
raise ArgumentError,
|
|
312
|
+
"escape: false is mutually exclusive with " \
|
|
313
|
+
"escape_hard_line_breaks: / allow: (those configure " \
|
|
314
|
+
"MarkdownEscaper, which escape: false replaces wholesale)"
|
|
315
|
+
end
|
|
316
|
+
Renderers::Discourse::IdentityEscaper.new
|
|
317
|
+
else
|
|
318
|
+
Renderers::Discourse::MarkdownEscaper.new(escape_hard_line_breaks:, allow:)
|
|
319
|
+
end
|
|
157
320
|
end
|
|
158
321
|
|
|
159
|
-
def
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
322
|
+
def render_through(renderer, ast, raise_on_error:)
|
|
323
|
+
raw = renderer.render(ast)
|
|
324
|
+
[renderer.postprocessor.call(raw), []]
|
|
325
|
+
rescue StandardError => e
|
|
326
|
+
raise if raise_on_error
|
|
327
|
+
["", [e]]
|
|
164
328
|
end
|
|
165
329
|
end
|
|
166
330
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: markbridge
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Discourse Team
|
|
@@ -25,6 +25,7 @@ files:
|
|
|
25
25
|
- lib/markbridge/ast/bold.rb
|
|
26
26
|
- lib/markbridge/ast/code.rb
|
|
27
27
|
- lib/markbridge/ast/color.rb
|
|
28
|
+
- lib/markbridge/ast/details.rb
|
|
28
29
|
- lib/markbridge/ast/document.rb
|
|
29
30
|
- lib/markbridge/ast/element.rb
|
|
30
31
|
- lib/markbridge/ast/email.rb
|
|
@@ -53,10 +54,11 @@ files:
|
|
|
53
54
|
- lib/markbridge/ast/upload.rb
|
|
54
55
|
- lib/markbridge/ast/url.rb
|
|
55
56
|
- lib/markbridge/bbcode.rb
|
|
56
|
-
- lib/markbridge/
|
|
57
|
+
- lib/markbridge/conversion.rb
|
|
57
58
|
- lib/markbridge/gem_loader.rb
|
|
58
59
|
- lib/markbridge/html.rb
|
|
59
60
|
- lib/markbridge/mediawiki.rb
|
|
61
|
+
- lib/markbridge/parse.rb
|
|
60
62
|
- lib/markbridge/parsers/bbcode.rb
|
|
61
63
|
- lib/markbridge/parsers/bbcode/closing_strategies/base.rb
|
|
62
64
|
- lib/markbridge/parsers/bbcode/closing_strategies/reordering.rb
|
|
@@ -102,7 +104,9 @@ files:
|
|
|
102
104
|
- lib/markbridge/parsers/html/handlers/paragraph_handler.rb
|
|
103
105
|
- lib/markbridge/parsers/html/handlers/quote_handler.rb
|
|
104
106
|
- lib/markbridge/parsers/html/handlers/raw_handler.rb
|
|
107
|
+
- lib/markbridge/parsers/html/handlers/self_closing_handler.rb
|
|
105
108
|
- lib/markbridge/parsers/html/handlers/simple_handler.rb
|
|
109
|
+
- lib/markbridge/parsers/html/handlers/span_handler.rb
|
|
106
110
|
- lib/markbridge/parsers/html/handlers/table_cell_handler.rb
|
|
107
111
|
- lib/markbridge/parsers/html/handlers/table_handler.rb
|
|
108
112
|
- lib/markbridge/parsers/html/handlers/table_row_handler.rb
|
|
@@ -138,7 +142,9 @@ files:
|
|
|
138
142
|
- lib/markbridge/renderers/discourse.rb
|
|
139
143
|
- lib/markbridge/renderers/discourse/builders/list_item_builder.rb
|
|
140
144
|
- lib/markbridge/renderers/discourse/html_escaper.rb
|
|
145
|
+
- lib/markbridge/renderers/discourse/identity_escaper.rb
|
|
141
146
|
- lib/markbridge/renderers/discourse/markdown_escaper.rb
|
|
147
|
+
- lib/markbridge/renderers/discourse/postprocessor.rb
|
|
142
148
|
- lib/markbridge/renderers/discourse/render_context.rb
|
|
143
149
|
- lib/markbridge/renderers/discourse/renderer.rb
|
|
144
150
|
- lib/markbridge/renderers/discourse/rendering_interface.rb
|
|
@@ -149,6 +155,7 @@ files:
|
|
|
149
155
|
- lib/markbridge/renderers/discourse/tags/bold_tag.rb
|
|
150
156
|
- lib/markbridge/renderers/discourse/tags/code_tag.rb
|
|
151
157
|
- lib/markbridge/renderers/discourse/tags/color_tag.rb
|
|
158
|
+
- lib/markbridge/renderers/discourse/tags/details_tag.rb
|
|
152
159
|
- lib/markbridge/renderers/discourse/tags/email_tag.rb
|
|
153
160
|
- lib/markbridge/renderers/discourse/tags/event_tag.rb
|
|
154
161
|
- lib/markbridge/renderers/discourse/tags/heading_tag.rb
|