1 module docs4d; 2 3 import std.stdio; 4 import std.file; 5 import std.path; 6 import mustache; 7 import std.algorithm; 8 import std.array; 9 import std.string; 10 import std.regex; 11 import std.range; 12 import std.conv; 13 import dmarkdown; 14 15 struct Card 16 { 17 string name; 18 string description; 19 string category; 20 Param[] params; 21 Example[] examples; 22 Link[] links; 23 string fileLocation; 24 } 25 26 struct Param 27 { 28 string type; 29 string id; 30 string description; 31 ParamType paramType; 32 } 33 34 struct Example 35 { 36 string code; 37 } 38 39 enum ParamType 40 { 41 INPUT,OUTPUT 42 } 43 44 struct Link 45 { 46 string text; 47 string url; 48 string active = ""; 49 } 50 51 struct Page 52 { 53 string filename; 54 string name; 55 Link[] links; 56 string markdownFile; 57 58 string html(){ 59 auto markdown = readText(markdownFile); 60 return filterMarkdown(markdown); 61 } 62 63 } 64 65 class DocGen 66 { 67 68 string name; 69 string ver; 70 Page[] pages; 71 Card[] cards; 72 Link[] links; 73 alias MustacheEngine!(string) Mustache; 74 Mustache mustache; 75 Mustache.Context context; 76 string githubUrl; 77 string resourcePath; 78 string templatePath; 79 80 this(string name, string ver, string githubUrl = ""){ 81 this.name = name; 82 this.ver = ver; 83 this.githubUrl = githubUrl; 84 this.context = new Mustache.Context; 85 this.resourcePath = absolutePath(__FILE__).replace("source/docs4d.d","resources"); 86 this.templatePath = absolutePath(__FILE__).replace("source/docs4d.d","templates"); 87 mustache.path = templatePath; 88 mustache.level = Mustache.CacheLevel.no; 89 } 90 91 public DocGen withCards(Card[] cards) 92 { 93 this.cards = cards; 94 return this; 95 } 96 97 public DocGen withLinks(Link[] links) 98 { 99 this.links = links; 100 return this; 101 } 102 103 public DocGen withPages(Page[] pages) 104 { 105 this.pages = pages; 106 return this; 107 } 108 109 public void generate(){ 110 this.context["name"] = this.name; 111 this.context["ver"] = this.ver; 112 113 this.links.each!((link){ 114 auto subLinks = context.addSubContext("links"); 115 subLinks["text"] = link.text; 116 subLinks["url"] = link.url; 117 subLinks["active"] = link.active; 118 }); 119 120 foreach (ref card; this.cards.sort!((a,b)=> a.name.toLower() < b.name.toLower())) { 121 auto sub = context.addSubContext("cards"); 122 sub["name"] = card.name; 123 sub["category"] = card.category; 124 sub["description"] = card.description; 125 126 if(card.params.length > 0){ 127 sub["signature"] = card.params.map!(p => p.type).join(" → "); 128 sub.useSection("has_params"); 129 130 foreach(ref param ; card.params){ 131 if(param.paramType == ParamType.INPUT){ 132 auto sub2 = sub.addSubContext("input_params"); 133 sub2["type"] = param.type; 134 sub2["id"] = param.id; 135 sub2["desc"] = param.description; 136 } else { 137 auto sub3 = sub.addSubContext("return_value"); 138 sub.useSection("has_return"); 139 sub3["type"] = param.type; 140 sub3["desc"] = param.description; 141 } 142 } 143 144 } 145 146 if(card.examples.length > 0){ 147 sub.useSection("has_examples"); 148 foreach(ref example ; card.examples){ 149 auto sub4 = sub.addSubContext("examples"); 150 sub4["code"] = example.code; 151 } 152 } 153 154 if(card.links.length > 0){ 155 sub.useSection("has_see_also"); 156 foreach(ref link ; card.links){ 157 auto sub4 = sub.addSubContext("see_also"); 158 sub4["text"] = link.text; 159 sub4["url"] = link.url; 160 } 161 } 162 163 if(!card.fileLocation.empty){ 164 sub.useSection("has_gh"); 165 sub["gh"] = this.githubUrl ~ "/" ~ card.fileLocation; 166 } 167 168 } 169 // make target dir 170 if(exists("Docs")){ 171 rmdirRecurse("docs"); 172 } 173 mkdir("docs"); 174 copy(resourcePath ~ "/main.js","docs/main.js"); 175 copy(resourcePath ~ "/style.css","docs/style.css"); 176 mkdir("docs/fonts"); 177 copy(resourcePath ~ "/fonts/glyphicons-halflings-regular.woff2","docs/fonts/glyphicons-halflings-regular.woff2"); 178 179 std.file.write("docs/documentation.html",mustache.render("documentation", context)); 180 181 foreach(ref page ; pages){ 182 page.links.each!((link){ 183 auto subLinks = context.addSubContext("page_links"); 184 subLinks["text"] = link.text; 185 subLinks["url"] = link.url; 186 subLinks["active"] = link.active; 187 }); 188 context["page_html"] = page.html(); 189 190 std.file.write("docs/" ~ page.filename,mustache.render("page", context)); 191 192 } 193 194 } 195 196 } 197 198