| // 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 static java.nio.charset.StandardCharsets.UTF_8; | 
 |  | 
 | import com.google.devtools.build.skydoc.rendering.proto.StardocOutputProtos.AspectInfo; | 
 | import com.google.devtools.build.skydoc.rendering.proto.StardocOutputProtos.ModuleInfo; | 
 | import com.google.devtools.build.skydoc.rendering.proto.StardocOutputProtos.ProviderInfo; | 
 | import com.google.devtools.build.skydoc.rendering.proto.StardocOutputProtos.RuleInfo; | 
 | import com.google.devtools.build.skydoc.rendering.proto.StardocOutputProtos.StarlarkFunctionInfo; | 
 | import java.io.FileNotFoundException; | 
 | import java.io.IOException; | 
 | import java.io.InputStream; | 
 | import java.io.InputStreamReader; | 
 | import java.io.Reader; | 
 | import java.io.StringWriter; | 
 | import java.nio.file.Files; | 
 | import java.nio.file.Path; | 
 | import java.nio.file.Paths; | 
 | 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 { | 
 |   // TODO(kendalllane): Refactor MarkdownRenderer to take in something other than filepaths. | 
 |   private final String headerTemplateFilename; | 
 |   private final String ruleTemplateFilename; | 
 |   private final String providerTemplateFilename; | 
 |   private final String functionTemplateFilename; | 
 |   private final String aspectTemplateFilename; | 
 |  | 
 |   private final VelocityEngine velocityEngine; | 
 |  | 
 |   public MarkdownRenderer( | 
 |       String headerTemplate, | 
 |       String ruleTemplate, | 
 |       String providerTemplate, | 
 |       String functionTemplate, | 
 |       String aspectTemplate) { | 
 |     this.headerTemplateFilename = headerTemplate; | 
 |     this.ruleTemplateFilename = ruleTemplate; | 
 |     this.providerTemplateFilename = providerTemplate; | 
 |     this.functionTemplateFilename = functionTemplate; | 
 |     this.aspectTemplateFilename = aspectTemplate; | 
 |  | 
 |     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 header string that should appear at the top of Stardoc's output, providing a | 
 |    * summary for the input Starlark module. | 
 |    */ | 
 |   public String renderMarkdownHeader(ModuleInfo moduleInfo) throws IOException { | 
 |     VelocityContext context = new VelocityContext(); | 
 |     context.put("util", new MarkdownUtil()); | 
 |     context.put("moduleDocstring", moduleInfo.getModuleDocstring()); | 
 |  | 
 |     StringWriter stringWriter = new StringWriter(); | 
 |     Reader reader = readerFromPath(headerTemplateFilename); | 
 |     try { | 
 |       velocityEngine.evaluate(context, stringWriter, headerTemplateFilename, reader); | 
 |     } catch (ResourceNotFoundException | ParseErrorException | MethodInvocationException e) { | 
 |       throw new IOException(e); | 
 |     } | 
 |     return stringWriter.toString(); | 
 |   } | 
 |  | 
 |   /** | 
 |    * 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(); | 
 |     context.put("util", new MarkdownUtil()); | 
 |     context.put("ruleName", ruleName); | 
 |     context.put("ruleInfo", ruleInfo); | 
 |  | 
 |     StringWriter stringWriter = new StringWriter(); | 
 |     Reader reader = readerFromPath(ruleTemplateFilename); | 
 |     try { | 
 |       velocityEngine.evaluate(context, stringWriter, ruleTemplateFilename, reader); | 
 |     } catch (ResourceNotFoundException | ParseErrorException | MethodInvocationException e) { | 
 |       throw new IOException(e); | 
 |     } | 
 |     return stringWriter.toString(); | 
 |   } | 
 |  | 
 |   /** | 
 |    * Returns a markdown rendering of provider documentation for the given provider information | 
 |    * object with the given name. | 
 |    */ | 
 |   public String render(String providerName, ProviderInfo providerInfo) throws IOException { | 
 |     VelocityContext context = new VelocityContext(); | 
 |     context.put("util", new MarkdownUtil()); | 
 |     context.put("providerName", providerName); | 
 |     context.put("providerInfo", providerInfo); | 
 |  | 
 |     StringWriter stringWriter = new StringWriter(); | 
 |     Reader reader = readerFromPath(providerTemplateFilename); | 
 |     try { | 
 |       velocityEngine.evaluate(context, stringWriter, providerTemplateFilename, reader); | 
 |     } catch (ResourceNotFoundException | ParseErrorException | MethodInvocationException e) { | 
 |       throw new IOException(e); | 
 |     } | 
 |     return stringWriter.toString(); | 
 |   } | 
 |  | 
 |   /** | 
 |    * Returns a markdown rendering of a user-defined function's documentation for the function info | 
 |    * object. | 
 |    */ | 
 |   public String render(StarlarkFunctionInfo functionInfo) throws IOException { | 
 |     VelocityContext context = new VelocityContext(); | 
 |     context.put("util", new MarkdownUtil()); | 
 |     context.put("funcInfo", functionInfo); | 
 |  | 
 |     StringWriter stringWriter = new StringWriter(); | 
 |     Reader reader = readerFromPath(functionTemplateFilename); | 
 |     try { | 
 |       velocityEngine.evaluate(context, stringWriter, functionTemplateFilename, reader); | 
 |     } catch (ResourceNotFoundException | ParseErrorException | MethodInvocationException e) { | 
 |       throw new IOException(e); | 
 |     } | 
 |     return stringWriter.toString(); | 
 |   } | 
 |  | 
 |   /** | 
 |    * Returns a markdown rendering of aspect documentation for the given aspect information object | 
 |    * with the given aspect name. | 
 |    */ | 
 |   public String render(String aspectName, AspectInfo aspectInfo) throws IOException { | 
 |     VelocityContext context = new VelocityContext(); | 
 |     context.put("util", new MarkdownUtil()); | 
 |     context.put("aspectName", aspectName); | 
 |     context.put("aspectInfo", aspectInfo); | 
 |  | 
 |     StringWriter stringWriter = new StringWriter(); | 
 |     Reader reader = readerFromPath(aspectTemplateFilename); | 
 |     try { | 
 |       velocityEngine.evaluate(context, stringWriter, aspectTemplateFilename, reader); | 
 |     } catch (ResourceNotFoundException | ParseErrorException | MethodInvocationException e) { | 
 |       throw new IOException(e); | 
 |     } | 
 |     return stringWriter.toString(); | 
 |   } | 
 |   /** | 
 |    * Returns a reader from the given path. | 
 |    * | 
 |    * @param filePath The given path, either a filesystem path or a java Resource | 
 |    */ | 
 |   private static Reader readerFromPath(String filePath) throws IOException { | 
 |     if (Files.exists(Paths.get(filePath))) { | 
 |       Path path = Paths.get(filePath); | 
 |       return Files.newBufferedReader(path); | 
 |     } | 
 |  | 
 |     InputStream inputStream = MarkdownRenderer.class.getClassLoader().getResourceAsStream(filePath); | 
 |     if (inputStream == null) { | 
 |       throw new FileNotFoundException(filePath + " was not found as a resource."); | 
 |     } | 
 |     return new InputStreamReader(inputStream, UTF_8); | 
 |   } | 
 | } |