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