markbridge 0.1.1 → 0.1.2
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/lib/markbridge/all.rb +4 -7
- data/lib/markbridge/ast/document.rb +1 -1
- data/lib/markbridge/ast/element.rb +2 -2
- data/lib/markbridge/ast/list.rb +2 -2
- data/lib/markbridge/ast/table.rb +6 -12
- data/lib/markbridge/ast/text.rb +5 -1
- data/lib/markbridge/bbcode.rb +4 -0
- data/lib/markbridge/gem_loader.rb +2 -3
- data/lib/markbridge/html.rb +4 -0
- data/lib/markbridge/mediawiki.rb +4 -0
- data/lib/markbridge/parsers/bbcode/closing_strategies/base.rb +0 -10
- data/lib/markbridge/parsers/bbcode/closing_strategies/reordering.rb +17 -4
- data/lib/markbridge/parsers/bbcode/closing_strategies/tag_reconciler.rb +64 -44
- data/lib/markbridge/parsers/bbcode/handler_registry.rb +21 -11
- data/lib/markbridge/parsers/bbcode/handlers/attachment_handler.rb +17 -12
- data/lib/markbridge/parsers/bbcode/handlers/base_handler.rb +0 -10
- data/lib/markbridge/parsers/bbcode/handlers/code_handler.rb +6 -10
- data/lib/markbridge/parsers/bbcode/handlers/image_handler.rb +9 -17
- data/lib/markbridge/parsers/bbcode/handlers/list_handler.rb +1 -5
- data/lib/markbridge/parsers/bbcode/handlers/list_item_handler.rb +1 -2
- data/lib/markbridge/parsers/bbcode/handlers/quote_handler.rb +6 -18
- data/lib/markbridge/parsers/bbcode/handlers/raw_handler.rb +2 -6
- data/lib/markbridge/parsers/bbcode/handlers/self_closing_handler.rb +4 -4
- data/lib/markbridge/parsers/bbcode/handlers/table_cell_handler.rb +1 -1
- data/lib/markbridge/parsers/bbcode/handlers/table_handler.rb +2 -2
- data/lib/markbridge/parsers/bbcode/handlers/table_row_handler.rb +3 -3
- data/lib/markbridge/parsers/bbcode/parser.rb +5 -8
- data/lib/markbridge/parsers/bbcode/parser_state.rb +12 -18
- data/lib/markbridge/parsers/bbcode/peekable_enumerator.rb +9 -59
- data/lib/markbridge/parsers/bbcode/raw_content_collector.rb +2 -2
- data/lib/markbridge/parsers/bbcode/scanner.rb +49 -63
- data/lib/markbridge/parsers/bbcode/tokens/tag_end_token.rb +1 -5
- data/lib/markbridge/parsers/bbcode/tokens/tag_start_token.rb +1 -6
- data/lib/markbridge/parsers/bbcode/tokens/text_token.rb +1 -7
- data/lib/markbridge/parsers/bbcode/tokens/token.rb +1 -1
- data/lib/markbridge/parsers/bbcode.rb +1 -0
- data/lib/markbridge/parsers/html/handler_registry.rb +32 -49
- data/lib/markbridge/parsers/html/handlers/base_handler.rb +0 -2
- data/lib/markbridge/parsers/html/handlers/image_handler.rb +1 -4
- data/lib/markbridge/parsers/html/parser.rb +3 -13
- data/lib/markbridge/parsers/media_wiki/inline_parser.rb +56 -67
- data/lib/markbridge/parsers/media_wiki/inline_tag_registry.rb +103 -0
- data/lib/markbridge/parsers/media_wiki/parser.rb +51 -76
- data/lib/markbridge/parsers/media_wiki.rb +1 -0
- data/lib/markbridge/parsers/text_formatter/handler_registry.rb +5 -37
- data/lib/markbridge/parsers/text_formatter/parser.rb +3 -8
- data/lib/markbridge/processors/discourse_markdown/code_block_tracker.rb +24 -17
- data/lib/markbridge/processors/discourse_markdown/detectors/base.rb +9 -15
- data/lib/markbridge/processors/discourse_markdown/detectors/event.rb +11 -10
- data/lib/markbridge/processors/discourse_markdown/detectors/poll.rb +11 -39
- data/lib/markbridge/processors/discourse_markdown/detectors/upload.rb +38 -63
- data/lib/markbridge/processors/discourse_markdown/scanner.rb +25 -33
- data/lib/markbridge/renderers/discourse/builders/list_item_builder.rb +6 -6
- data/lib/markbridge/renderers/discourse/html_escaper.rb +20 -0
- data/lib/markbridge/renderers/discourse/markdown_escaper.rb +49 -49
- data/lib/markbridge/renderers/discourse/render_context.rb +23 -11
- data/lib/markbridge/renderers/discourse/renderer.rb +54 -12
- data/lib/markbridge/renderers/discourse/rendering_interface.rb +12 -4
- data/lib/markbridge/renderers/discourse/tag.rb +14 -1
- data/lib/markbridge/renderers/discourse/tag_library.rb +30 -25
- data/lib/markbridge/renderers/discourse/tags/align_tag.rb +15 -7
- data/lib/markbridge/renderers/discourse/tags/bold_tag.rb +2 -0
- data/lib/markbridge/renderers/discourse/tags/code_tag.rb +14 -9
- data/lib/markbridge/renderers/discourse/tags/email_tag.rb +5 -3
- data/lib/markbridge/renderers/discourse/tags/event_tag.rb +3 -1
- data/lib/markbridge/renderers/discourse/tags/heading_tag.rb +6 -2
- data/lib/markbridge/renderers/discourse/tags/horizontal_rule_tag.rb +2 -2
- data/lib/markbridge/renderers/discourse/tags/image_tag.rb +13 -2
- data/lib/markbridge/renderers/discourse/tags/italic_tag.rb +2 -0
- data/lib/markbridge/renderers/discourse/tags/line_break_tag.rb +2 -2
- data/lib/markbridge/renderers/discourse/tags/list_item_tag.rb +24 -47
- data/lib/markbridge/renderers/discourse/tags/list_tag.rb +10 -15
- data/lib/markbridge/renderers/discourse/tags/mention_tag.rb +5 -1
- data/lib/markbridge/renderers/discourse/tags/paragraph_tag.rb +10 -0
- data/lib/markbridge/renderers/discourse/tags/poll_tag.rb +9 -2
- data/lib/markbridge/renderers/discourse/tags/quote_tag.rb +2 -0
- data/lib/markbridge/renderers/discourse/tags/spoiler_tag.rb +9 -0
- data/lib/markbridge/renderers/discourse/tags/strikethrough_tag.rb +2 -0
- data/lib/markbridge/renderers/discourse/tags/table_tag.rb +12 -8
- data/lib/markbridge/renderers/discourse/tags/underline_tag.rb +10 -3
- data/lib/markbridge/renderers/discourse/tags/upload_tag.rb +29 -2
- data/lib/markbridge/renderers/discourse/tags/url_tag.rb +5 -3
- data/lib/markbridge/renderers/discourse.rb +1 -0
- data/lib/markbridge/textformatter.rb +4 -0
- data/lib/markbridge/version.rb +1 -1
- data/lib/markbridge.rb +8 -8
- metadata +8 -2
|
@@ -15,7 +15,10 @@ module Markbridge
|
|
|
15
15
|
if markdown_compatible?(rows_data, interface)
|
|
16
16
|
render_markdown(rows_data)
|
|
17
17
|
else
|
|
18
|
-
|
|
18
|
+
# Re-render cells in html_mode so inline Markdown like **bold** becomes
|
|
19
|
+
# <strong>bold</strong>; CommonMark would not parse Markdown inside an HTML block.
|
|
20
|
+
html_rows = extract_rows(element, interface, child_context.with_html_mode(true))
|
|
21
|
+
render_html(html_rows)
|
|
19
22
|
end
|
|
20
23
|
end
|
|
21
24
|
|
|
@@ -25,13 +28,15 @@ module Markbridge
|
|
|
25
28
|
# @return [Array<Hash>] array of {cells: [{content:, header:}], ...}
|
|
26
29
|
def extract_rows(element, interface, child_context)
|
|
27
30
|
element.children.filter_map do |child|
|
|
28
|
-
next unless child.
|
|
31
|
+
next unless child.instance_of?(AST::TableRow)
|
|
29
32
|
|
|
30
33
|
cells =
|
|
31
34
|
child.children.filter_map do |cell|
|
|
32
|
-
next unless cell.
|
|
35
|
+
next unless cell.instance_of?(AST::TableCell)
|
|
33
36
|
|
|
34
|
-
|
|
37
|
+
# Push the cell itself into the parent chain so descendants
|
|
38
|
+
# can detect they're inside a cell via has_parent?.
|
|
39
|
+
cell_context = child_context.with_parent(cell)
|
|
35
40
|
content = interface.render_children(cell, context: cell_context).strip
|
|
36
41
|
{ content:, header: cell.header? }
|
|
37
42
|
end
|
|
@@ -42,7 +47,6 @@ module Markbridge
|
|
|
42
47
|
|
|
43
48
|
# Check if the table can be rendered as Markdown
|
|
44
49
|
def markdown_compatible?(rows_data, interface)
|
|
45
|
-
return false if rows_data.empty?
|
|
46
50
|
return false if interface.has_parent?(AST::Table)
|
|
47
51
|
|
|
48
52
|
cell_count = rows_data.first[:cells].length
|
|
@@ -90,7 +94,7 @@ module Markbridge
|
|
|
90
94
|
|
|
91
95
|
unless header_rows.empty?
|
|
92
96
|
lines << "<thead>"
|
|
93
|
-
header_rows.each { |row| lines << html_row(row
|
|
97
|
+
header_rows.each { |row| lines << html_row(row) }
|
|
94
98
|
lines << "</thead>"
|
|
95
99
|
end
|
|
96
100
|
|
|
@@ -108,10 +112,10 @@ module Markbridge
|
|
|
108
112
|
end
|
|
109
113
|
|
|
110
114
|
# Render a single HTML table row
|
|
111
|
-
def html_row(row
|
|
115
|
+
def html_row(row)
|
|
112
116
|
cells_html =
|
|
113
117
|
row[:cells].map do |cell|
|
|
114
|
-
tag =
|
|
118
|
+
tag = cell[:header] ? "th" : "td"
|
|
115
119
|
"<#{tag}>#{cell[:content]}</#{tag}>"
|
|
116
120
|
end
|
|
117
121
|
|
|
@@ -4,13 +4,20 @@ module Markbridge
|
|
|
4
4
|
module Renderers
|
|
5
5
|
module Discourse
|
|
6
6
|
module Tags
|
|
7
|
-
#
|
|
7
|
+
# Discourse's HTML sanitizer strips raw `<u>`, but `[u]…[/u]` is
|
|
8
|
+
# cooked by the BBCode plugin into `<span class="bbcode-u">`. The
|
|
9
|
+
# BBCode plugin runs on Markdown source, not on raw HTML inside an
|
|
10
|
+
# HTML block, so in html_mode we emit the cooked form directly.
|
|
8
11
|
class UnderlineTag < Tag
|
|
9
12
|
def render(element, interface)
|
|
10
13
|
child_context = interface.with_parent(element)
|
|
11
14
|
content = interface.render_children(element, context: child_context)
|
|
12
|
-
|
|
13
|
-
|
|
15
|
+
|
|
16
|
+
if interface.html_mode?
|
|
17
|
+
%(<span class="bbcode-u">#{content}</span>)
|
|
18
|
+
else
|
|
19
|
+
"[u]#{content}[/u]"
|
|
20
|
+
end
|
|
14
21
|
end
|
|
15
22
|
end
|
|
16
23
|
end
|
|
@@ -29,7 +29,9 @@ module Markbridge
|
|
|
29
29
|
# end
|
|
30
30
|
# end
|
|
31
31
|
class UploadTag < Tag
|
|
32
|
-
def render(element,
|
|
32
|
+
def render(element, interface)
|
|
33
|
+
return build_upload_html(element) if interface.html_mode?
|
|
34
|
+
|
|
33
35
|
# Return raw Markdown if available, otherwise reconstruct
|
|
34
36
|
return element.raw if element.raw
|
|
35
37
|
|
|
@@ -56,7 +58,7 @@ module Markbridge
|
|
|
56
58
|
def build_attachment_markdown(element)
|
|
57
59
|
filename = element.filename || "attachment"
|
|
58
60
|
url = build_upload_url(element)
|
|
59
|
-
size_part =
|
|
61
|
+
size_part = " (#{element.size})" if element.size
|
|
60
62
|
|
|
61
63
|
"[#{filename}|attachment](#{url})#{size_part}"
|
|
62
64
|
end
|
|
@@ -73,6 +75,31 @@ module Markbridge
|
|
|
73
75
|
filename = element.filename || element.sha1
|
|
74
76
|
"upload://#{filename}"
|
|
75
77
|
end
|
|
78
|
+
|
|
79
|
+
# html_mode reconstructs from the AST fields rather than reusing
|
|
80
|
+
# element.raw — raw is Markdown, which CommonMark passes through
|
|
81
|
+
# unchanged inside an HTML block (so the user would see the
|
|
82
|
+
# literal "" string instead of an image).
|
|
83
|
+
def build_upload_html(element)
|
|
84
|
+
if element.type == :image
|
|
85
|
+
build_image_html(element)
|
|
86
|
+
else
|
|
87
|
+
build_attachment_html(element)
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def build_image_html(element)
|
|
92
|
+
src = HtmlEscaper.escape(build_upload_url(element))
|
|
93
|
+
alt = HtmlEscaper.escape(element.alt)
|
|
94
|
+
%(<img src="#{src}" alt="#{alt}">)
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def build_attachment_html(element)
|
|
98
|
+
href = HtmlEscaper.escape(build_upload_url(element))
|
|
99
|
+
filename = HtmlEscaper.escape(element.filename || "attachment")
|
|
100
|
+
size_part = " (#{HtmlEscaper.escape(element.size)})" if element.size
|
|
101
|
+
%(<a href="#{href}">#{filename}</a>#{size_part})
|
|
102
|
+
end
|
|
76
103
|
end
|
|
77
104
|
end
|
|
78
105
|
end
|
|
@@ -11,10 +11,12 @@ module Markbridge
|
|
|
11
11
|
text = interface.render_children(element, context: child_context)
|
|
12
12
|
href = element.href
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
return text unless href&.match?(/\A(?:https?|ftps?|mailto):/i)
|
|
15
|
+
|
|
16
|
+
if interface.html_mode?
|
|
17
|
+
%(<a href="#{HtmlEscaper.escape(href)}">#{text}</a>)
|
|
16
18
|
else
|
|
17
|
-
text
|
|
19
|
+
"[#{text}](#{href})"
|
|
18
20
|
end
|
|
19
21
|
end
|
|
20
22
|
end
|
|
@@ -5,6 +5,7 @@ require_relative "discourse/tag_library"
|
|
|
5
5
|
require_relative "discourse/render_context"
|
|
6
6
|
require_relative "discourse/rendering_interface"
|
|
7
7
|
require_relative "discourse/markdown_escaper"
|
|
8
|
+
require_relative "discourse/html_escaper"
|
|
8
9
|
|
|
9
10
|
# Builders
|
|
10
11
|
require_relative "discourse/builders/list_item_builder"
|
data/lib/markbridge/version.rb
CHANGED
data/lib/markbridge.rb
CHANGED
|
@@ -5,8 +5,6 @@ require_relative "markbridge/configuration"
|
|
|
5
5
|
|
|
6
6
|
require_relative "markbridge/ast"
|
|
7
7
|
require_relative "markbridge/renderers/discourse"
|
|
8
|
-
require_relative "markbridge/parsers/media_wiki"
|
|
9
|
-
require_relative "markbridge/parsers/text_formatter"
|
|
10
8
|
require_relative "markbridge/processors"
|
|
11
9
|
|
|
12
10
|
module Markbridge
|
|
@@ -70,21 +68,23 @@ module Markbridge
|
|
|
70
68
|
|
|
71
69
|
# Parse MediaWiki wikitext to AST
|
|
72
70
|
# @param input [String] MediaWiki source
|
|
71
|
+
# @param inline_tag_registry [Parsers::MediaWiki::InlineTagRegistry, nil] custom registry
|
|
73
72
|
# @return [AST::Document]
|
|
74
|
-
def parse_mediawiki(input)
|
|
73
|
+
def parse_mediawiki(input, inline_tag_registry: nil)
|
|
75
74
|
raise ArgumentError, "input cannot be nil" if input.nil?
|
|
76
75
|
|
|
77
76
|
input = input.to_s
|
|
78
|
-
parser = Parsers::MediaWiki::Parser.new
|
|
77
|
+
parser = Parsers::MediaWiki::Parser.new(inline_tag_registry:)
|
|
79
78
|
parser.parse(input)
|
|
80
79
|
end
|
|
81
80
|
|
|
82
81
|
# Convert MediaWiki wikitext to Discourse Markdown
|
|
83
82
|
# @param input [String] MediaWiki source
|
|
83
|
+
# @param inline_tag_registry [Parsers::MediaWiki::InlineTagRegistry, nil] custom registry
|
|
84
84
|
# @param tag_library [TagLibrary, nil] custom tag library or use default
|
|
85
85
|
# @return [String] Markdown output
|
|
86
|
-
def mediawiki_to_markdown(input, tag_library: nil)
|
|
87
|
-
ast = parse_mediawiki(input)
|
|
86
|
+
def mediawiki_to_markdown(input, inline_tag_registry: nil, tag_library: nil)
|
|
87
|
+
ast = parse_mediawiki(input, inline_tag_registry:)
|
|
88
88
|
render_to_markdown(ast, tag_library:)
|
|
89
89
|
end
|
|
90
90
|
|
|
@@ -142,7 +142,7 @@ module Markbridge
|
|
|
142
142
|
parser.parse(input.to_s)
|
|
143
143
|
end
|
|
144
144
|
|
|
145
|
-
def render_to_markdown(ast, tag_library:
|
|
145
|
+
def render_to_markdown(ast, tag_library:)
|
|
146
146
|
tag_library ||= default_tag_library
|
|
147
147
|
renderer = build_renderer(tag_library:)
|
|
148
148
|
cleanup_markdown(renderer.render(ast))
|
|
@@ -159,7 +159,7 @@ module Markbridge
|
|
|
159
159
|
def cleanup_markdown(text)
|
|
160
160
|
text
|
|
161
161
|
.gsub(/\n{3,}/, "\n\n") # Max 2 consecutive newlines
|
|
162
|
-
.gsub(/^[ \t]
|
|
162
|
+
.gsub(/^[ \t]+$/, "") # Remove whitespace-only lines
|
|
163
163
|
.strip # Trim leading/trailing whitespace
|
|
164
164
|
end
|
|
165
165
|
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.1.
|
|
4
|
+
version: 0.1.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Discourse Team
|
|
@@ -52,8 +52,11 @@ files:
|
|
|
52
52
|
- lib/markbridge/ast/underline.rb
|
|
53
53
|
- lib/markbridge/ast/upload.rb
|
|
54
54
|
- lib/markbridge/ast/url.rb
|
|
55
|
+
- lib/markbridge/bbcode.rb
|
|
55
56
|
- lib/markbridge/configuration.rb
|
|
56
57
|
- lib/markbridge/gem_loader.rb
|
|
58
|
+
- lib/markbridge/html.rb
|
|
59
|
+
- lib/markbridge/mediawiki.rb
|
|
57
60
|
- lib/markbridge/parsers/bbcode.rb
|
|
58
61
|
- lib/markbridge/parsers/bbcode/closing_strategies/base.rb
|
|
59
62
|
- lib/markbridge/parsers/bbcode/closing_strategies/reordering.rb
|
|
@@ -107,6 +110,7 @@ files:
|
|
|
107
110
|
- lib/markbridge/parsers/html/parser.rb
|
|
108
111
|
- lib/markbridge/parsers/media_wiki.rb
|
|
109
112
|
- lib/markbridge/parsers/media_wiki/inline_parser.rb
|
|
113
|
+
- lib/markbridge/parsers/media_wiki/inline_tag_registry.rb
|
|
110
114
|
- lib/markbridge/parsers/media_wiki/parser.rb
|
|
111
115
|
- lib/markbridge/parsers/text_formatter.rb
|
|
112
116
|
- lib/markbridge/parsers/text_formatter/handler_registry.rb
|
|
@@ -133,6 +137,7 @@ files:
|
|
|
133
137
|
- lib/markbridge/processors/discourse_markdown/scanner.rb
|
|
134
138
|
- lib/markbridge/renderers/discourse.rb
|
|
135
139
|
- lib/markbridge/renderers/discourse/builders/list_item_builder.rb
|
|
140
|
+
- lib/markbridge/renderers/discourse/html_escaper.rb
|
|
136
141
|
- lib/markbridge/renderers/discourse/markdown_escaper.rb
|
|
137
142
|
- lib/markbridge/renderers/discourse/render_context.rb
|
|
138
143
|
- lib/markbridge/renderers/discourse/renderer.rb
|
|
@@ -168,6 +173,7 @@ files:
|
|
|
168
173
|
- lib/markbridge/renderers/discourse/tags/underline_tag.rb
|
|
169
174
|
- lib/markbridge/renderers/discourse/tags/upload_tag.rb
|
|
170
175
|
- lib/markbridge/renderers/discourse/tags/url_tag.rb
|
|
176
|
+
- lib/markbridge/textformatter.rb
|
|
171
177
|
- lib/markbridge/version.rb
|
|
172
178
|
homepage: https://github.com/discourse/markbridge
|
|
173
179
|
licenses:
|
|
@@ -183,7 +189,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
183
189
|
requirements:
|
|
184
190
|
- - ">="
|
|
185
191
|
- !ruby/object:Gem::Version
|
|
186
|
-
version: 3.
|
|
192
|
+
version: 3.3.0
|
|
187
193
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
188
194
|
requirements:
|
|
189
195
|
- - ">="
|