Skip to content

Commit 2c32c30

Browse files
committed
FEATURE: Expose the bare-link judgment as AST::Url#bare?
Review feedback: consumers that intercept Url nodes need the same bare-or-not decision the renderer makes (a deferred-link handler must record nil text for a bare URL, or the importer rebuilds [url](url) and re-breaks oneboxing). Keeping it private in UrlTag would force a second copy that can drift. Url#bare? judges the AST: no children, or a single Text child equal to the href. UrlTag delegates to it and keeps one render-time extra — a label that renders to nothing (e.g. an empty formatting child) also falls back to the bare href, since [](url) shows nothing.
1 parent e8f3b8a commit 2c32c30

4 files changed

Lines changed: 63 additions & 13 deletions

File tree

lib/markbridge/ast/url.rb

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,21 @@ def initialize(href: nil)
2222
super()
2323
@href = href
2424
end
25+
26+
# Whether this link is "bare" — it has no link text of its own:
27+
# either no children, or a single Text child whose content is
28+
# exactly the href (how parsers model a URL that stands for
29+
# itself). Consumers that record or rewrite links need this
30+
# judgment too (a bare URL must stay bare to keep autolinking
31+
# and oneboxing working), so it lives on the node rather than
32+
# in the renderer.
33+
#
34+
# @return [Boolean]
35+
def bare?
36+
return true if children.empty?
37+
38+
children.size == 1 && children.first.instance_of?(Text) && children.first.text == href
39+
end
2540
end
2641
end
2742
end

lib/markbridge/renderers/discourse/tags/url_tag.rb

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,10 @@ def render(element, interface)
2828

2929
if interface.html_mode?
3030
%(<a href="#{HtmlEscaper.escape(href)}">#{text}</a>)
31-
elsif bare?(element, text)
31+
elsif element.bare? || text.empty?
32+
# Url#bare? judges the AST (so label escaping can't confuse
33+
# it); the rendered-text check additionally catches labels
34+
# that render to nothing (e.g. an empty formatting child).
3235
href
3336
else
3437
"[#{text}](#{markdown_destination(href)})"
@@ -50,18 +53,6 @@ def linkable?(href)
5053

5154
!href.match?(SCHEME_LIKE)
5255
end
53-
54-
# Bare when there is no link text, or when the only child is a
55-
# Text node whose content is exactly the href (compared on the
56-
# AST, not on the rendered text, so Markdown escaping in the
57-
# label cannot break the detection).
58-
def bare?(element, rendered_text)
59-
return true if rendered_text.empty?
60-
61-
children = element.children
62-
children.size == 1 && children.first.instance_of?(AST::Text) &&
63-
children.first.text == element.href
64-
end
6556
end
6657
end
6758
end

spec/unit/markbridge/ast/url_spec.rb

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,4 +33,39 @@
3333

3434
expect(element.children).to eq([text])
3535
end
36+
37+
describe "#bare?" do
38+
it "is bare with no children" do
39+
expect(described_class.new(href: "https://example.com").bare?).to be true
40+
end
41+
42+
it "is bare when the only child is a Text equal to the href" do
43+
element = described_class.new(href: "https://example.com")
44+
element << Markbridge::AST::Text.new("https://example.com")
45+
46+
expect(element.bare?).to be true
47+
end
48+
49+
it "is not bare when the text differs from the href" do
50+
element = described_class.new(href: "https://example.com")
51+
element << Markbridge::AST::Text.new("click here")
52+
53+
expect(element.bare?).to be false
54+
end
55+
56+
it "is not bare when more children follow the href-equal text" do
57+
element = described_class.new(href: "https://example.com")
58+
element << Markbridge::AST::Text.new("https://example.com")
59+
element << Markbridge::AST::Bold.new
60+
61+
expect(element.bare?).to be false
62+
end
63+
64+
it "is not bare when the only child is a non-Text node" do
65+
element = described_class.new(href: "https://example.com")
66+
element << Markbridge::AST::Bold.new
67+
68+
expect(element.bare?).to be false
69+
end
70+
end
3671
end

spec/unit/markbridge/renderers/discourse/tags/url_tag_spec.rb

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,15 @@
163163
expect(tag.render(element, interface)).to eq("https://example.com")
164164
end
165165

166+
it "renders the plain href when the label renders to nothing" do
167+
# Not bare on the AST (a non-Text child exists), but the child
168+
# produces no output — `[](url)` would show nothing.
169+
element = Markbridge::AST::Url.new(href: "https://example.com")
170+
element << Markbridge::AST::Bold.new
171+
172+
expect(tag.render(element, interface)).to eq("https://example.com")
173+
end
174+
166175
it "detects bareness on the AST, unaffected by Markdown escaping of the label" do
167176
# The rendered label would be "https://example.com/a\_b" — comparing
168177
# rendered text against the href would miss this bare URL.

0 commit comments

Comments
 (0)