Simple Markdown rendering for skydoc

This uses apache velocity engine templates to create markdown-HTML. There are other alternatives, but there is already precedent for depending on this library from docgen.

RELNOTES: None.
PiperOrigin-RevId: 203795431
diff --git a/src/main/java/com/google/devtools/build/skydoc/rendering/AttributeInfo.java b/src/main/java/com/google/devtools/build/skydoc/rendering/AttributeInfo.java
new file mode 100644
index 0000000..8051057
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/skydoc/rendering/AttributeInfo.java
@@ -0,0 +1,37 @@
+// Copyright 2018 The Bazel Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.devtools.build.skydoc.rendering;
+
+/**
+ * Stores information about a skylark attribute definition.
+ */
+public class AttributeInfo {
+
+  private final String name;
+  private final String docString;
+
+  public AttributeInfo(String name, String docString) {
+    this.name = name;
+    this.docString = docString;
+  }
+
+  public String getName() {
+    return name;
+  }
+
+  public String getDocString() {
+    return docString;
+  }
+}
diff --git a/src/main/java/com/google/devtools/build/skydoc/rendering/BUILD b/src/main/java/com/google/devtools/build/skydoc/rendering/BUILD
index 0dc5f08..6a2633b 100644
--- a/src/main/java/com/google/devtools/build/skydoc/rendering/BUILD
+++ b/src/main/java/com/google/devtools/build/skydoc/rendering/BUILD
@@ -12,11 +12,20 @@
 java_library(
     name = "rendering",
     srcs = glob(["*.java"]),
+    resources = [":template_files"],
     deps = [
         "//src/main/java/com/google/devtools/build/lib:events",
         "//src/main/java/com/google/devtools/build/lib:skylarkinterface",
         "//src/main/java/com/google/devtools/build/lib:syntax",
+        "//third_party:apache_velocity",
         "//third_party:guava",
         "//third_party:jsr305",
     ],
 )
+
+filegroup(
+    name = "template_files",
+    srcs = glob([
+        "templates/*.vm",
+    ]),
+)
diff --git a/src/main/java/com/google/devtools/build/skydoc/rendering/MarkdownRenderer.java b/src/main/java/com/google/devtools/build/skydoc/rendering/MarkdownRenderer.java
new file mode 100644
index 0000000..f9f5495
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/skydoc/rendering/MarkdownRenderer.java
@@ -0,0 +1,77 @@
+// Copyright 2018 The Bazel Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.devtools.build.skydoc.rendering;
+
+import com.google.common.base.Joiner;
+import java.io.IOException;
+import java.io.StringWriter;
+import java.util.List;
+import java.util.stream.Collectors;
+import org.apache.velocity.VelocityContext;
+import org.apache.velocity.app.VelocityEngine;
+import org.apache.velocity.exception.MethodInvocationException;
+import org.apache.velocity.exception.ParseErrorException;
+import org.apache.velocity.exception.ResourceNotFoundException;
+import org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader;
+import org.apache.velocity.runtime.resource.loader.JarResourceLoader;
+
+/**
+ * Produces skydoc output in markdown form.
+ */
+public class MarkdownRenderer {
+
+  private static final String TEMPLATE_FILENAME =
+      "com/google/devtools/build/skydoc/rendering/templates/test.vm";
+
+  private final VelocityEngine velocityEngine;
+
+  public MarkdownRenderer() {
+    this.velocityEngine = new VelocityEngine();
+    velocityEngine.setProperty("resource.loader", "classpath, jar");
+    velocityEngine.setProperty("classpath.resource.loader.class",
+        ClasspathResourceLoader.class.getName());
+    velocityEngine.setProperty("jar.resource.loader.class", JarResourceLoader.class.getName());
+    velocityEngine.setProperty("input.encoding", "UTF-8");
+    velocityEngine.setProperty("output.encoding", "UTF-8");
+    velocityEngine.setProperty("runtime.references.strict", true);
+  }
+
+  /**
+   * Returns a markdown rendering of rule documentation for the given rule information object with
+   * the given rule name.
+   */
+  public String render(String ruleName, RuleInfo ruleInfo) throws IOException {
+    VelocityContext context = new VelocityContext();
+    // TODO(cparsons): Attributes in summary form should have links.
+    context.put("summaryform", getSummaryForm(ruleName, ruleInfo));
+    context.put("ruleName", ruleName);
+    context.put("ruleInfo", ruleInfo);
+
+    StringWriter stringWriter = new StringWriter();
+    try {
+      velocityEngine.mergeTemplate(TEMPLATE_FILENAME, "UTF-8", context, stringWriter);
+    } catch (ResourceNotFoundException | ParseErrorException | MethodInvocationException e) {
+      throw new IOException(e);
+    }
+    return stringWriter.toString();
+  }
+
+  private static String getSummaryForm(String ruleName, RuleInfo ruleInfo) {
+    List<String> attributeNames = ruleInfo.getAttributes().stream()
+        .map(attr -> attr.getName())
+        .collect(Collectors.toList());
+    return String.format("%s(%s)", ruleName, Joiner.on(", ").join(attributeNames));
+  }
+}
diff --git a/src/main/java/com/google/devtools/build/skydoc/rendering/RuleInfo.java b/src/main/java/com/google/devtools/build/skydoc/rendering/RuleInfo.java
index dee5e0f..6f231cf 100644
--- a/src/main/java/com/google/devtools/build/skydoc/rendering/RuleInfo.java
+++ b/src/main/java/com/google/devtools/build/skydoc/rendering/RuleInfo.java
@@ -14,8 +14,6 @@
 
 package com.google.devtools.build.skydoc.rendering;
 
-import com.google.common.base.Joiner;
-import com.google.common.base.Strings;
 import com.google.devtools.build.lib.events.Location;
 import com.google.devtools.build.lib.syntax.BaseFunction;
 import java.util.Collection;
@@ -28,16 +26,16 @@
   private final BaseFunction identifierFunction;
   private final Location location;
   private final String docString;
-  private final Collection<String> attrNames;
+  private final Collection<AttributeInfo> attrInfos;
 
   public RuleInfo(BaseFunction identifierFunction,
       Location location,
       String docString,
-      Collection<String> attrNames) {
+      Collection<AttributeInfo> attrInfos) {
     this.identifierFunction = identifierFunction;
     this.location = location;
     this.docString = docString;
-    this.attrNames = attrNames;
+    this.attrInfos = attrInfos;
   }
 
   public BaseFunction getIdentifierFunction() {
@@ -52,17 +50,7 @@
     return docString;
   }
 
-  public Collection<String> getAttrNames() {
-    return attrNames;
-  }
-
-  public String getDescription() {
-    StringBuilder stringBuilder = new StringBuilder();
-    if (!Strings.isNullOrEmpty(docString)) {
-      stringBuilder.append(docString);
-      stringBuilder.append("\n");
-    }
-    Joiner.on(",").appendTo(stringBuilder, attrNames);
-    return stringBuilder.toString();
+  public Collection<AttributeInfo> getAttributes() {
+    return attrInfos;
   }
 }
diff --git a/src/main/java/com/google/devtools/build/skydoc/rendering/templates/test.vm b/src/main/java/com/google/devtools/build/skydoc/rendering/templates/test.vm
new file mode 100644
index 0000000..b1600e9
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/skydoc/rendering/templates/test.vm
@@ -0,0 +1,27 @@
+<a name="#${ruleName}"></a>
+#[[##]]# ${ruleName}
+
+<pre>
+${summaryform}
+</pre>
+
+${ruleInfo.docString}
+
+#[[###]]# Attributes
+
+#if (!$ruleInfo.attributes.isEmpty())
+<table class="params-table">
+  <colgroup>
+    <col class="col-param" />
+    <col class="col-description" />
+  </colgroup>
+  <tbody>
+#foreach ($attribute in $ruleInfo.attributes)
+    <tr id="#${ruleName}_${attribute.name}">
+      <td><code>${attribute.name}</code></td>
+      <td>${attribute.docString}</td>
+    </tr>
+#end
+  </tbody>
+</table>
+#end