git » sdk » commit ad1e806

Paras for unstyled

author Stephen Paul Weber
2026-05-03 03:07:52 UTC
committer Stephen Paul Weber
2026-05-03 03:07:52 UTC
parent b93c05534c0b5c37df5daa4340f19fd126e1fc01

Paras for unstyled

borogove/ChatMessage.hx +5 -1
borogove/Html.hx +1 -1
borogove/XEP0393.hx +5 -2
test/TestChatMessage.hx +20 -1

diff --git a/borogove/ChatMessage.hx b/borogove/ChatMessage.hx
index 3433c2a..c84681a 100644
--- a/borogove/ChatMessage.hx
+++ b/borogove/ChatMessage.hx
@@ -395,7 +395,11 @@ class ChatMessage {
 			if (payloads.find((p) -> p.attr.get("xmlns") == "urn:xmpp:styling:0" && p.name == "unstyled") == null) {
 				return XEP0393.parse(body).map(s -> Element(s));
 			} else {
-				return body.split("\n").map(line -> Element(new Stanza("div").text(line)));
+				return body.split("\n\n").map(para -> {
+					final lines = para.split("\n").flatMap(line -> [CData(new TextNode(line)), Element(new Stanza("br"))]);
+					lines.pop();
+					return Element(new Stanza("p").addChildNodes(lines));
+				});
 			}
 		}
 	}
diff --git a/borogove/Html.hx b/borogove/Html.hx
index 70ce706..3ef6d0e 100644
--- a/borogove/Html.hx
+++ b/borogove/Html.hx
@@ -250,7 +250,7 @@ class Html {
 		// Could use reduce, but we already have XEP0393.render around
 		final body = new Stanza("body");
 		body.addChildNodes(xml);
-		return ~/\n$/.replace(XEP0393.render(body), "");
+		return ~/\n(\n)?$/.replace(XEP0393.render(body), "");
 	}
 
 	#if js
diff --git a/borogove/XEP0393.hx b/borogove/XEP0393.hx
index 0ba958f..61ec127 100644
--- a/borogove/XEP0393.hx
+++ b/borogove/XEP0393.hx
@@ -113,13 +113,17 @@ class XEP0393 {
 			endsWithNewline = true;
 		}
 
+		if (xhtml.name == "p") {
+			s.add("\n");
+		}
+
 		if (xhtml.name == "pre") {
 			s.add("```\n");
 			endsWithNewline = true;
 		}
 
 		if (xhtml.name == "blockquote") {
-			return ~/^/gm.replace(s.toString(), "> ");
+			return ~/^/gm.replace(s.toString(), "> ") + "\n";
 		}
 
 		return s.toString();
@@ -261,7 +265,6 @@ class XEP0393 {
 		return { block: new Stanza("blockquote").addChildren(parse(lines.join(""))), rest: styled.substr(end) };
 	}
 
-
 	public static function parsePreformatted(styled: UnicodeString) {
 		final lines = [];
 		var line = "";
diff --git a/test/TestChatMessage.hx b/test/TestChatMessage.hx
index 620235a..cbb922a 100644
--- a/test/TestChatMessage.hx
+++ b/test/TestChatMessage.hx
@@ -9,6 +9,25 @@ import borogove.Message;
 @:access(borogove)
 class TestChatMessage extends utest.Test {
 	public function testUnstyledBody() {
+		final stanza = new Stanza("message");
+		stanza.attr.set("id", "test-id-1");
+		stanza.attr.set("from", "alice@example.com");
+		stanza.attr.set("to", "bob@example.com");
+		stanza.attr.set("type", "chat");
+		stanza.addChild(new Stanza("body").text("line 1\n\n*line 2*"));
+		stanza.addChild(new Stanza("unstyled", {xmlns: "urn:xmpp:styling:0"}));
+
+		final msg = Message.fromStanza(stanza, JID.parse("bob@example.com"));
+		switch (msg.parsed) {
+			case ChatMessageStanza(m):
+				Assert.equals("<p>line 1</p><p>*line 2*</p>", m.body().toString());
+				Assert.equals("line 1\n\n*line 2*", m.body().toPlainText());
+			default:
+				Assert.fail("Expected ChatMessageStanza");
+		}
+	}
+
+	public function testUnstyledBodyLineBreak() {
 		final stanza = new Stanza("message");
 		stanza.attr.set("id", "test-id-1");
 		stanza.attr.set("from", "alice@example.com");
@@ -20,7 +39,7 @@ class TestChatMessage extends utest.Test {
 		final msg = Message.fromStanza(stanza, JID.parse("bob@example.com"));
 		switch (msg.parsed) {
 			case ChatMessageStanza(m):
-				Assert.equals("<div>line 1</div><div>*line 2*</div>", m.body().toString());
+				Assert.equals("<p>line 1<br />*line 2*</p>", m.body().toString());
 				Assert.equals("line 1\n*line 2*", m.body().toPlainText());
 			default:
 				Assert.fail("Expected ChatMessageStanza");