Make all Markdown extensions configurable Allow site admins to selectively enable or disable Markdown extensions. This can help a site avoid creating documentation that isn't compatible with other CommonMark parsers. Change-Id: I0466b03ef213a398d79f943af2ddf95a7e0853e7
diff --git a/gitiles-servlet/src/main/java/com/google/gitiles/ReadmeHelper.java b/gitiles-servlet/src/main/java/com/google/gitiles/ReadmeHelper.java index 468b26e..911c4ef 100644 --- a/gitiles-servlet/src/main/java/com/google/gitiles/ReadmeHelper.java +++ b/gitiles-servlet/src/main/java/com/google/gitiles/ReadmeHelper.java
@@ -98,7 +98,7 @@ .setReader(reader) .setRootTree(rootTree) .build() - .toSoyHtml(GitilesMarkdown.parse(raw)); + .toSoyHtml(GitilesMarkdown.parse(config, raw)); } catch (RuntimeException | IOException err) { log.error( String.format(
diff --git a/gitiles-servlet/src/main/java/com/google/gitiles/doc/DocServlet.java b/gitiles-servlet/src/main/java/com/google/gitiles/doc/DocServlet.java index bd5c481..78d1cf8 100644 --- a/gitiles-servlet/src/main/java/com/google/gitiles/doc/DocServlet.java +++ b/gitiles-servlet/src/main/java/com/google/gitiles/doc/DocServlet.java
@@ -167,9 +167,9 @@ MarkdownFile srcFile) throws IOException { Map<String, Object> data = new HashMap<>(); - data.putAll(buildNavbar(fmt, navFile)); + data.putAll(buildNavbar(cfg, fmt, navFile)); - Node doc = GitilesMarkdown.parse(srcFile.consumeContent()); + Node doc = GitilesMarkdown.parse(cfg, srcFile.consumeContent()); data.put("pageTitle", pageTitle(doc, srcFile)); if (view.getType() != GitilesView.Type.ROOTED_DOC) { data.put("sourceUrl", GitilesView.show().copyFrom(view).toUrl()); @@ -190,11 +190,12 @@ } } - private Map<String, Object> buildNavbar(MarkdownToHtml.Builder fmt, MarkdownFile navFile) { + private Map<String, Object> buildNavbar( + MarkdownConfig cfg, MarkdownToHtml.Builder fmt, MarkdownFile navFile) { Navbar navbar = new Navbar(); if (navFile != null) { navbar.setFormatter(fmt.setFilePath(navFile.path).build()); - navbar.setMarkdown(navFile.consumeContent()); + navbar.setMarkdown(cfg, navFile.consumeContent()); } return navbar.toSoyData(); }
diff --git a/gitiles-servlet/src/main/java/com/google/gitiles/doc/GitilesMarkdown.java b/gitiles-servlet/src/main/java/com/google/gitiles/doc/GitilesMarkdown.java index cc50048..e094931 100644 --- a/gitiles-servlet/src/main/java/com/google/gitiles/doc/GitilesMarkdown.java +++ b/gitiles-servlet/src/main/java/com/google/gitiles/doc/GitilesMarkdown.java
@@ -14,7 +14,9 @@ package com.google.gitiles.doc; -import com.google.common.collect.ImmutableList; +import java.util.ArrayList; +import java.util.List; +import org.commonmark.Extension; import org.commonmark.ext.autolink.AutolinkExtension; import org.commonmark.ext.gfm.strikethrough.StrikethroughExtension; import org.commonmark.ext.gfm.tables.TablesExtension; @@ -24,28 +26,43 @@ /** Parses Gitiles style CommonMark Markdown. */ public class GitilesMarkdown { - private static final Parser PARSER = - Parser.builder() - .extensions( - ImmutableList.of( - AutolinkExtension.create(), - BlockNoteExtension.create(), - GitilesHtmlExtension.create(), - GitHubThematicBreakExtension.create(), - MultiColumnExtension.create(), - NamedAnchorExtension.create(), - SmartQuotedExtension.create(), - StrikethroughExtension.create(), - TablesExtension.create(), - TocExtension.create())) - .build(); - - public static Node parse(byte[] md) { - return parse(RawParseUtils.decode(md)); + public static Node parse(MarkdownConfig cfg, byte[] md) { + return parse(cfg, RawParseUtils.decode(md)); } - public static Node parse(String md) { - return PARSER.parse(md); + public static Node parse(MarkdownConfig cfg, String md) { + List<Extension> ext = new ArrayList<>(); + if (cfg.autoLink) { + ext.add(AutolinkExtension.create()); + } + if (cfg.blockNote) { + ext.add(BlockNoteExtension.create()); + } + if (cfg.safeHtml) { + ext.add(GitilesHtmlExtension.create()); + } + if (cfg.ghThematicBreak) { + ext.add(GitHubThematicBreakExtension.create()); + } + if (cfg.multiColumn) { + ext.add(MultiColumnExtension.create()); + } + if (cfg.namedAnchor) { + ext.add(NamedAnchorExtension.create()); + } + if (cfg.smartQuote) { + ext.add(SmartQuotedExtension.create()); + } + if (cfg.strikethrough) { + ext.add(StrikethroughExtension.create()); + } + if (cfg.tables) { + ext.add(TablesExtension.create()); + } + if (cfg.toc) { + ext.add(TocExtension.create()); + } + return Parser.builder().extensions(ext).build().parse(md); } private GitilesMarkdown() {}
diff --git a/gitiles-servlet/src/main/java/com/google/gitiles/doc/MarkdownConfig.java b/gitiles-servlet/src/main/java/com/google/gitiles/doc/MarkdownConfig.java index 5737d85..79ddbb6 100644 --- a/gitiles-servlet/src/main/java/com/google/gitiles/doc/MarkdownConfig.java +++ b/gitiles-servlet/src/main/java/com/google/gitiles/doc/MarkdownConfig.java
@@ -41,6 +41,17 @@ final int imageLimit; final String analyticsId; + final boolean autoLink; + final boolean blockNote; + final boolean ghThematicBreak; + final boolean multiColumn; + final boolean namedAnchor; + final boolean safeHtml; + final boolean smartQuote; + final boolean strikethrough; + final boolean tables; + final boolean toc; + private final boolean allowAnyIFrame; private final ImmutableList<String> allowIFrame; @@ -50,7 +61,22 @@ imageLimit = cfg.getInt("markdown", "imageLimit", IMAGE_LIMIT); analyticsId = Strings.emptyToNull(cfg.getString("google", null, "analyticsId")); - String[] f = cfg.getStringList("markdown", null, "allowiframe"); + boolean githubFlavor = cfg.getBoolean("markdown", "githubFlavor", true); + autoLink = cfg.getBoolean("markdown", "autolink", githubFlavor); + blockNote = cfg.getBoolean("markdown", "blocknote", false); + ghThematicBreak = cfg.getBoolean("markdown", "ghthematicbreak", githubFlavor); + multiColumn = cfg.getBoolean("markdown", "multicolumn", false); + namedAnchor = cfg.getBoolean("markdown", "namedanchor", false); + safeHtml = cfg.getBoolean("markdown", "safehtml", githubFlavor); + smartQuote = cfg.getBoolean("markdown", "smartquote", false); + strikethrough = cfg.getBoolean("markdown", "strikethrough", githubFlavor); + tables = cfg.getBoolean("markdown", "tables", githubFlavor); + toc = cfg.getBoolean("markdown", "toc", true); + + String[] f = {}; + if (safeHtml) { + f = cfg.getStringList("markdown", null, "allowiframe"); + } allowAnyIFrame = f.length == 1 && StringUtils.toBooleanOrNull(f[0]) == Boolean.TRUE; if (allowAnyIFrame) { allowIFrame = ImmutableList.of();
diff --git a/gitiles-servlet/src/main/java/com/google/gitiles/doc/Navbar.java b/gitiles-servlet/src/main/java/com/google/gitiles/doc/Navbar.java index 50e0b61..a4581f1 100644 --- a/gitiles-servlet/src/main/java/com/google/gitiles/doc/Navbar.java +++ b/gitiles-servlet/src/main/java/com/google/gitiles/doc/Navbar.java
@@ -42,9 +42,9 @@ return this; } - Navbar setMarkdown(byte[] md) { + Navbar setMarkdown(MarkdownConfig cfg, byte[] md) { if (md != null && md.length > 0) { - parse(RawParseUtils.decode(md)); + parse(cfg, RawParseUtils.decode(md)); } return this; } @@ -73,8 +73,8 @@ } } - private void parse(String markdown) { - node = GitilesMarkdown.parse(markdown); + private void parse(MarkdownConfig cfg, String markdown) { + node = GitilesMarkdown.parse(cfg, markdown); extractSiteTitle(); extractRefLinks(markdown);