Skip to content

Commit

Permalink
implement a temporary Markdown-To-BBCode converter
Browse files Browse the repository at this point in the history
  • Loading branch information
HSGamer committed Nov 27, 2024
1 parent 4cdfeff commit 1b518dc
Show file tree
Hide file tree
Showing 5 changed files with 307 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import me.hsgamer.mcreleaser.core.platform.Platform;
import me.hsgamer.mcreleaser.core.property.CommonPropertyKey;
import me.hsgamer.mcreleaser.core.util.PropertyKeyUtil;
import me.hsgamer.mcreleaser.renderer.text.MarkdownToTextConverter;
import me.hsgamer.mcreleaser.renderer.bbcode.MarkdownToBBCodeConverter;
import org.apache.hc.client5.http.classic.HttpClient;
import org.apache.hc.client5.http.classic.methods.HttpPost;
import org.apache.hc.client5.http.entity.mime.MultipartEntityBuilder;
Expand Down Expand Up @@ -48,7 +48,7 @@ public Optional<BatchRunnable> createUploadRunnable(FileBundle fileBundle) {

try {
String description = CommonPropertyKey.DESCRIPTION.getValue();
String textDescription = MarkdownToTextConverter.convert(description); // TODO: Convert to BBCode or ask Polymart to support Markdown or HTML
String textDescription = MarkdownToBBCodeConverter.convert(description);
builder.addTextBody("message", textDescription);
} catch (Exception e) {
logger.error("Failed to convert description", e);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package me.hsgamer.mcreleaser.renderer.bbcode;

import me.hsgamer.mcreleaser.renderer.bbcode.internal.BBCodeNodeRendererContext;
import me.hsgamer.mcreleaser.renderer.bbcode.internal.BBCodeWriter;
import me.hsgamer.mcreleaser.renderer.bbcode.internal.CodeBBCodeNodeRenderer;
import org.commonmark.internal.util.Escaping;
import org.commonmark.node.Node;
import org.commonmark.parser.Parser;

public class MarkdownToBBCodeConverter {
private static final Parser parser = Parser.builder().build();

// TODO: Implement a dedicated library for BBCode rendering
public static String convert(String markdown) {
Node document = parser.parse(markdown);
StringBuilder builder = new StringBuilder();
BBCodeNodeRendererContext context = new BBCodeNodeRendererContext() {
@Override
public String escapeUrl(String url) {
return Escaping.escapeHtml(url);
}

@Override
public BBCodeWriter getWriter() {
return new BBCodeWriter(builder);
}

@Override
public String getSoftBreak() {
return "\n";
}
};
document.accept(new CodeBBCodeNodeRenderer(context));
return builder.toString();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package me.hsgamer.mcreleaser.renderer.bbcode.internal;

public interface BBCodeNodeRendererContext {
String escapeUrl(String url);

BBCodeWriter getWriter();

String getSoftBreak();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package me.hsgamer.mcreleaser.renderer.bbcode.internal;

import org.commonmark.internal.util.Escaping;

import java.io.IOException;
import java.util.Map;

public class BBCodeWriter {
private static final Map<String, String> NO_ATTRIBUTES = Map.of();

private final Appendable appendable;
private char lastChar = 0;

public BBCodeWriter(Appendable appendable) {
this.appendable = appendable;
}

public void raw(String s) {
append(s);
}

public void text(String text) {
append(Escaping.escapeHtml(text));
}

public void tag(String name) {
tag(name, null, NO_ATTRIBUTES, false);
}

public void tag(String name, String value) {
tag(name, value, NO_ATTRIBUTES, false);
}

public void tag(String name, Map<String, String> attrs) {
tag(name, null, attrs, false);
}

public void tag(String name, String value, Map<String, String> attrs, boolean voidElement) {
append("[");
append(name);
if (value != null) {
append("=");
append(value);
}
if (attrs != null && !attrs.isEmpty()) {
for (Map.Entry<String, String> entry : attrs.entrySet()) {
append(" ");
append(entry.getKey());
append("=");
append(entry.getValue());
}
}
if (voidElement) {
append("/");
}
append("]");
}

public void line() {
if (lastChar != 0 && lastChar != '\n') {
append("\n");
}
}

protected void append(String s) {
try {
appendable.append(s);
} catch (IOException e) {
throw new RuntimeException(e);
}
int length = s.length();
if (length != 0) {
lastChar = s.charAt(length - 1);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
package me.hsgamer.mcreleaser.renderer.bbcode.internal;

import org.commonmark.node.*;
import org.commonmark.renderer.NodeRenderer;

import java.util.Set;

public class CodeBBCodeNodeRenderer extends AbstractVisitor implements NodeRenderer {
private final BBCodeNodeRendererContext context;
private final BBCodeWriter writer;

public CodeBBCodeNodeRenderer(BBCodeNodeRendererContext context) {
this.context = context;
this.writer = context.getWriter();
}

@Override
public Set<Class<? extends Node>> getNodeTypes() {
return Set.of(
Document.class,
Heading.class,
Paragraph.class,
BlockQuote.class,
BulletList.class,
FencedCodeBlock.class,
HtmlBlock.class,
ThematicBreak.class,
IndentedCodeBlock.class,
Link.class,
ListItem.class,
OrderedList.class,
Image.class,
Emphasis.class,
StrongEmphasis.class,
Text.class,
Code.class,
HtmlInline.class,
SoftLineBreak.class,
HardLineBreak.class
);
}

@Override
public void render(Node node) {
node.accept(this);
}

@Override
public void visit(Document document) {
visitChildren(document);
}

@Override
public void visit(Heading heading) {
int size = Math.max(1, 8 - heading.getLevel());
writer.tag("b");
writer.tag("size", String.valueOf(size));
visitChildren(heading);
writer.tag("/size");
writer.tag("/b");
writer.line();
}

@Override
public void visit(Paragraph paragraph) {
visitChildren(paragraph);
writer.line();
}

@Override
public void visit(BlockQuote blockQuote) {
writer.tag("quote");
visitChildren(blockQuote);
writer.tag("/quote");
writer.line();
}

@Override
public void visit(BulletList bulletList) {
writer.tag("list");
visitChildren(bulletList);
writer.tag("/list");
writer.line();
}

@Override
public void visit(FencedCodeBlock fencedCodeBlock) {
writer.tag("code");
writer.text(fencedCodeBlock.getLiteral());
writer.tag("/code");
writer.line();
}

@Override
public void visit(HtmlBlock htmlBlock) {
writer.text(htmlBlock.getLiteral());
writer.line();
}

@Override
public void visit(ThematicBreak thematicBreak) {
writer.tag("hr");
writer.line();
}

@Override
public void visit(IndentedCodeBlock indentedCodeBlock) {
writer.tag("code");
writer.text(indentedCodeBlock.getLiteral());
writer.tag("/code");
writer.line();
}

@Override
public void visit(Link link) {
writer.tag("url", context.escapeUrl(link.getDestination()));
visitChildren(link);
writer.tag("/url");
}

@Override
public void visit(ListItem listItem) {
writer.tag("*");
visitChildren(listItem);
writer.line();
}

@Override
public void visit(OrderedList orderedList) {
writer.tag("list", orderedList.getMarkerStartNumber() + "");
visitChildren(orderedList);
writer.tag("/list");
writer.line();
}

@Override
public void visit(Image image) {
writer.tag("img", context.escapeUrl(image.getDestination()));
writer.tag("/img");
}

@Override
public void visit(Emphasis emphasis) {
writer.tag("i");
visitChildren(emphasis);
writer.tag("/i");
}

@Override
public void visit(StrongEmphasis strongEmphasis) {
writer.tag("b");
writer.tag("i");
visitChildren(strongEmphasis);
writer.tag("/i");
writer.tag("/b");
}

@Override
public void visit(Text text) {
writer.text(text.getLiteral());
}

@Override
public void visit(Code code) {
writer.tag("code");
writer.text(code.getLiteral());
writer.tag("/code");
}

@Override
public void visit(HtmlInline htmlInline) {
writer.text(htmlInline.getLiteral());
}

@Override
public void visit(SoftLineBreak softLineBreak) {
writer.raw(context.getSoftBreak());
}

@Override
public void visit(HardLineBreak hardLineBreak) {
writer.line();
}
}

0 comments on commit 1b518dc

Please sign in to comment.