179 lines · cpp
1///===----------------------------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8///9/// \file10/// This file contains the implementation of the MustacheHTMLGenerator class,11/// which is Clang-Doc generator for HTML using Mustache templates.12///13//===----------------------------------------------------------------------===//14 15#include "Generators.h"16#include "Representation.h"17#include "support/File.h"18#include "llvm/Support/Error.h"19#include "llvm/Support/Path.h"20 21using namespace llvm;22using namespace llvm::json;23using namespace llvm::mustache;24 25namespace clang {26namespace doc {27 28static std::unique_ptr<MustacheTemplateFile> NamespaceTemplate = nullptr;29 30static std::unique_ptr<MustacheTemplateFile> RecordTemplate = nullptr;31 32class MustacheHTMLGenerator : public MustacheGenerator {33public:34 static const char *Format;35 Error createResources(ClangDocContext &CDCtx) override;36 Error generateDocForInfo(Info *I, raw_ostream &OS,37 const ClangDocContext &CDCtx) override;38 Error setupTemplateFiles(const ClangDocContext &CDCtx) override;39 Error generateDocForJSON(json::Value &JSON, raw_fd_ostream &OS,40 const ClangDocContext &CDCtx, StringRef ObjTypeStr,41 StringRef RelativeRootPath) override;42 // Populates templates with CSS stylesheets, JS scripts paths.43 Error setupTemplateResources(const ClangDocContext &CDCtx, json::Value &V,44 SmallString<128> RelativeRootPath);45 llvm::Error generateDocumentation(46 StringRef RootDir, llvm::StringMap<std::unique_ptr<doc::Info>> Infos,47 const ClangDocContext &CDCtx, std::string DirName) override;48};49 50Error MustacheHTMLGenerator::setupTemplateFiles(const ClangDocContext &CDCtx) {51 // Template files need to use the native path when they're opened,52 // but have to be used in POSIX style when used in HTML.53 auto ConvertToNative = [](std::string &&Path) -> std::string {54 SmallString<128> PathBuf(Path);55 llvm::sys::path::native(PathBuf);56 return PathBuf.str().str();57 };58 59 std::string NamespaceFilePath =60 ConvertToNative(CDCtx.MustacheTemplates.lookup("namespace-template"));61 std::string ClassFilePath =62 ConvertToNative(CDCtx.MustacheTemplates.lookup("class-template"));63 std::string CommentFilePath =64 ConvertToNative(CDCtx.MustacheTemplates.lookup("comment-template"));65 std::string FunctionFilePath =66 ConvertToNative(CDCtx.MustacheTemplates.lookup("function-template"));67 std::string EnumFilePath =68 ConvertToNative(CDCtx.MustacheTemplates.lookup("enum-template"));69 std::vector<std::pair<StringRef, StringRef>> Partials = {70 {"Comments", CommentFilePath},71 {"FunctionPartial", FunctionFilePath},72 {"EnumPartial", EnumFilePath}};73 74 if (Error Err = setupTemplate(NamespaceTemplate, NamespaceFilePath, Partials))75 return Err;76 77 if (Error Err = setupTemplate(RecordTemplate, ClassFilePath, Partials))78 return Err;79 80 return Error::success();81}82 83Error MustacheHTMLGenerator::setupTemplateResources(84 const ClangDocContext &CDCtx, json::Value &V,85 SmallString<128> RelativeRootPath) {86 V.getAsObject()->insert({"ProjectName", CDCtx.ProjectName});87 json::Value StylesheetArr = Array();88 sys::path::native(RelativeRootPath, sys::path::Style::posix);89 90 auto *SSA = StylesheetArr.getAsArray();91 SSA->reserve(CDCtx.UserStylesheets.size());92 for (const auto &FilePath : CDCtx.UserStylesheets) {93 SmallString<128> StylesheetPath = RelativeRootPath;94 sys::path::append(StylesheetPath, sys::path::Style::posix,95 sys::path::filename(FilePath));96 SSA->emplace_back(StylesheetPath);97 }98 V.getAsObject()->insert({"Stylesheets", StylesheetArr});99 100 json::Value ScriptArr = Array();101 auto *SCA = ScriptArr.getAsArray();102 SCA->reserve(CDCtx.JsScripts.size());103 for (auto Script : CDCtx.JsScripts) {104 SmallString<128> JsPath = RelativeRootPath;105 sys::path::append(JsPath, sys::path::Style::posix,106 sys::path::filename(Script));107 SCA->emplace_back(JsPath);108 }109 V.getAsObject()->insert({"Scripts", ScriptArr});110 return Error::success();111}112 113Error MustacheHTMLGenerator::generateDocForJSON(json::Value &JSON,114 raw_fd_ostream &OS,115 const ClangDocContext &CDCtx,116 StringRef ObjTypeStr,117 StringRef RelativeRootPath) {118 if (ObjTypeStr == "namespace") {119 if (auto Err = setupTemplateResources(CDCtx, JSON, RelativeRootPath))120 return Err;121 assert(NamespaceTemplate && "NamespaceTemplate is nullptr.");122 NamespaceTemplate->render(JSON, OS);123 } else if (ObjTypeStr == "record") {124 if (auto Err = setupTemplateResources(CDCtx, JSON, RelativeRootPath))125 return Err;126 assert(RecordTemplate && "RecordTemplate is nullptr.");127 RecordTemplate->render(JSON, OS);128 }129 return Error::success();130}131 132Error MustacheHTMLGenerator::generateDocForInfo(Info *I, raw_ostream &OS,133 const ClangDocContext &CDCtx) {134 switch (I->IT) {135 case InfoType::IT_enum:136 case InfoType::IT_function:137 case InfoType::IT_typedef:138 case InfoType::IT_namespace:139 case InfoType::IT_record:140 case InfoType::IT_concept:141 case InfoType::IT_variable:142 case InfoType::IT_friend:143 break;144 case InfoType::IT_default:145 return createStringError(inconvertibleErrorCode(), "unexpected InfoType");146 }147 return Error::success();148}149 150Error MustacheHTMLGenerator::createResources(ClangDocContext &CDCtx) {151 std::string ResourcePath(CDCtx.OutDirectory + "/html");152 for (const auto &FilePath : CDCtx.UserStylesheets)153 if (Error Err = copyFile(FilePath, ResourcePath))154 return Err;155 for (const auto &FilePath : CDCtx.JsScripts)156 if (Error Err = copyFile(FilePath, ResourcePath))157 return Err;158 return Error::success();159}160 161Error MustacheHTMLGenerator::generateDocumentation(162 StringRef RootDir, llvm::StringMap<std::unique_ptr<doc::Info>> Infos,163 const ClangDocContext &CDCtx, std::string DirName) {164 return MustacheGenerator::generateDocumentation(RootDir, std::move(Infos),165 CDCtx, "html");166}167 168const char *MustacheHTMLGenerator::Format = "mustache";169 170static GeneratorRegistry::Add<MustacheHTMLGenerator>171 MHTML(MustacheHTMLGenerator::Format, "Generator for mustache HTML output.");172 173// This anchor is used to force the linker to link in the generated object174// file and thus register the generator.175volatile int MHTMLGeneratorAnchorSource = 0;176 177} // namespace doc178} // namespace clang179