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(" &#8594; ");
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