src/jsdoc/DocBuilder.vala
[roojspacker] / src / jsdoc / DocBuilder.vala
1  
2  
3
4 namespace JSDOC 
5 {
6
7         class DocBuilder : Object 
8         {
9                 
10
11                 public string VERSION = "1.0.0";
12                 
13                 
14                 private Packer packer;
15         
16                 public DocBuilder (Packer p) 
17                 {
18                         
19                         DocBuilder.init();
20                         GLib.debug("Roo JsDoc Toolkit started  at %s ",  (new GLib.DateTime()).format("Y/m/d H:i:s"));
21                         
22                         this.packer = p;
23         
24                     if (PackerRun.opt_tmp_dir != null && !FileUtils.test(PackerRun.opt_tmp_dir, GLib.FileTest.IS_DIR)) {   
25                         Posix.mkdir(PackerRun.opt_tmp_dir, 0700);
26                     }
27         
28         
29                     this.parseSrcFiles();
30                     
31                     this.symbolSet = DocParser.symbols;
32                     
33                     // this currently uses the concept of publish.js...
34                     
35                     this.publish();
36         
37         
38                 }
39                 
40                 static bool done_init = false;
41                 
42                 static GLib.Regex regex_dotdot;
43                 
44                 static void init()
45                 {
46                         if (done_init) {
47                                 return;
48                         }
49                         // ./ or ../
50                         DocBuilder.regex_dotdot = new Regex("\\\\.\\\\.?[/]");
51
52
53                 }
54                 
55                 
56                 /**
57                  * Parse the source files.
58                  * 
59                  */
60
61                 private void parseSrcFiles() 
62                 {
63                     DocParser.init();
64                     
65                     
66                     var useCache = PackerRun.opt_cache_dir == null ;
67                     var cacheFile = "";
68                     
69                     for (var i = 0, l = this.packer.files.size; i < l; i++) {
70                         
71                         var srcFile = this.packer.files.get(i);
72                         
73                         if (useCache) {
74                         
75                                 cacheFile = PackerRun.opt_cache_dir + srcFile.replace("/", '_') + ".cache";
76                                     
77                                     //print(cacheFile);
78                                     // disabled at present!@!!
79                                     
80                                     if (GLib.FileUtils.test(cacheFile, GLib.FileTest.EXISTS)) {
81                                         // check filetime?
82                                         var cache_mt = File.new_for_path (cacheFile).queryInfo(FileAttribute.TIME_MODIFIED,
83                                                             GLib.FileQueryInfoFlags.NONE, null).
84                                                             get_modification_time();
85                                         var original_mt = File.new_for_path (sourceInfo).queryInfo(FileAttribute.TIME_MODIFIED,
86                                                             GLib.FileQueryInfoFlags.NONE, null).
87                                                             get_modification_time();
88                                         // this check does not appear to work according to the doc's - need to check it out.
89                                        
90                                         if (cache_mt > original_mt) { // cached time  > original time!
91                                             // use the cached mtimes..
92                                             GLib.debug("Read %s" , cacheFile);
93                                                         var parser = new Json.Parser();
94                                             parser.load_from_file(cacheFile);
95                                             var ar = parser.get_root ().get_array();
96
97                                             for(var i = 0;i < ar.get_length();i++) {
98                                                         var o = ar.get_object_element(i);
99                                                         var sym = Json.gobject_from_data(typeof(Symbol), o) as Symbol;
100                                                         DocParser.symbols.add(sym);
101                                                 }
102                                                 continue;
103                                         }
104                             }
105                         }
106                         
107                         var src = "";
108                         try {
109                             GLib.debug("reading : %s" , srcFile);
110                             src = GLib.FileUtils.get_contents(srcFile);
111                         }
112                         catch(GLib.FileError e) {
113                             GLib.debug("Can't read source file '%s': %s", srcFile, e.to_string());
114                             continue;
115                         }
116
117                           
118                         
119                         var tr = new  TokenReader(this.packer);
120                                 tr.keepDocs = true;
121                                 tr.keepWhite = true;
122                                 tr.keepComments = true;
123                                 tr.sepIdents = false;
124                                 tr.collapseWhite = false;
125                                 tr.filename = src;
126                         
127
128                         var toks = tr.tokenize( new TextStream(src) );
129                         if (PackerRun.opt_dump_tokens) {
130                                         toks.dump();
131                                         return "";
132                                         //GLib.Process.exit(0);
133                                 }
134                         
135                         
136                         var ts = new TokenStream(toks);
137                     
138                     
139                     
140                                  
141                         DocParser.parse(ts, srcFile);
142                         
143                         if (useCache) {
144                                 
145                                 var ar = DocParser.symbolsToObject(srcFile);
146                                 
147                                 var builder = new Json.Builder ();
148                                 builder.begin_array ();
149                                 for (var i=0;i<ar.size;i++) {
150                                 
151                                                 builder.add_object_value (ar.get(i));
152                                         }
153                                         builder.end_array ();
154                                         Json.Generator generator = new Json.Generator ();
155                                         Json.Node root = builder.get_root ();
156                                         generator.set_root (root);
157                                         generator.pretty=  true;
158                                         generator.ident = 2;
159                                         generator.to_file(cacheFile);
160                         
161                          
162                             
163                                  }
164                     }
165                     
166                     
167                     
168                     Parser.finish();
169                 }
170                 
171      
172         
173                 void publish() 
174                 {
175                     GLib.debug("Publishing");
176                      
177                     // link!!!
178                     
179                     
180                     GLib.debug("Making directories");
181                     if (!File.isDirectory(PackerRun.opt_doc_target)) {
182                         Posix.mkdir(PackerRun.opt_doc_target,0755);
183                     }
184                     if (!File.isDirectory(PackerRun.opt_doc_target+"/symbols")) {
185                         Posix.mkdir(PackerRun.opt_doc_target+"/symbols",0755);
186                     }
187                     if (!File.isDirectory(PackerRun.opt_doc_target+"/symbols/src")) {
188                         Posix.mkdir(PackerRun.opt_doc_target+"/symbols/src",075);
189                     }
190                     if (!File.isDirectory(PackerRun.opt_doc_target +"/json")) {
191                         File.mkdir(PackerRun.opt_doc_target +"/json",0755);
192                     }
193                     
194                     GLib.debug("Copying files from static: %s " , PackerRun.opt_doc_template_dir);
195                     // copy everything in 'static' into 
196                     
197                     var iter = GLib.File.new_from_path(PackerRun.opt_doc_template_dir + "/static").enumerate_children (
198                                 "standard::*",
199                                 FileQueryInfoFlags.NOFOLLOW_SYMLINKS, 
200                                 null);
201                     
202                     
203                     while ( (info = enumerator.next_file (null)) != null) {
204                                 if (info.get_file_type () == FileType.DIRECTORY) {
205                                         continue;
206                                 } 
207                                 var src = File.new_from_path(info.get_name());
208                         GLib.debug("Copy %s to %s/%s" , info.get_name() , f,  PackerRun.opt_doc_target , src.get_basename());                   
209                         
210                                 src.copy(
211                                         GLib.File.new_from_path(PackerRun.opt_doc_target + '/' + src.get_basename()),
212                                         GLib.FileCopyFlags.OVERWRITE
213                                 );
214                         }
215         
216                     
217                     GLib.debug("Setting up templates");
218                     // used to check the details of things being linked to
219                     Link.symbolSet = this.symbolSet;// need to work out where 'symbolset will be stored/set!
220                     Link.base = "../";
221                     
222                     Link.srcFileFlatName = this.srcFileFlatName; // where set?
223                     Link.srcFileRelName = this.srcFileRelName; // where set?
224                     
225                     var classTemplate = new Template( PackerRun.opt_doc_template_dir  + "/class." + PackerRun.opt_doc_ext );
226                     var classesTemplate = new Template( PackerRun.opt_doc_template_dir+"/allclasses." + PackerRun.opt_doc_ext  );
227                     var classesindexTemplate = new Template( PackerRun.opt_doc_template_dir +"/index."  + PackerRun.opt_doc_ext );
228                     var fileindexTemplate = new Template( PackerRun.opt_doc_template_dir +"/allfiles."+ PackerRun.opt_doc_ext );
229
230                     
231                     classTemplate.symbolSet = this.symbolSet; // where?
232                     
233                     /*
234                     function hasNoParent($) {
235                         return ($.memberOf == "")
236                     }
237                     function isaFile($) {
238                         return ($.is("FILE"))
239                     }
240                     function isaClass($) {
241                         return ($.is("CONSTRUCTOR") || $.isNamespace || $.isClass); 
242                     }
243                     */
244                     
245                     
246                     
247                     
248                     
249                     
250                     
251                     
252                     
253                     var symbols = this.symbolSet.toArray();
254                     
255                     var files = this.packer.files;
256                     
257                     for (var i = 0, l = files.size; i < l; i++) {
258                         var file = files.get(i);
259                         var targetDir = PackerRun.opt_doc_target + "/symbols/src/";
260                         this.makeSrcFile(file, targetDir);
261                     }
262                     //print(JSON.stringify(symbols,null,4));
263                     var classes = new Gee.ArrayList<Symbol>();
264                     
265                     foreach(var symbol in symbols) {
266                                 if (symbol.isaClass()) { 
267                                         classes.add(symbol);
268                                 }
269                     }   
270                     classes.sort( (a,b) => {
271                                 return a.alias.collate(b.alias); 
272                         });
273                      
274                      //GLib.debug("classTemplate Process : all classes");
275                         
276                    // var classesIndex = classesTemplate.process(classes); // kept in memory
277                     
278                     GLib.debug("iterate classes");
279                     
280                     var jsonAll = new JSON.Object(); 
281                     
282                     for (var i = 0, l = classes.size; i < l; i++) {
283                         var symbol = classes.get(i);
284                         var output = "";
285                         
286                         GLib.debug("classTemplate Process : %s" , symbol.alias);
287                         
288                         
289                         
290                         
291                         FileUtils.set_contents(
292                                                 PackerRun.opt_doc_target+"/symbols/" +symbol.alias+'.' + PackerRun.opt_doc_ext ,
293                                 classTemplate.process(symbol)
294                         );
295                         
296                         jsonAll.set_object_member(symbol.alias,  this.publishJSON(symbol));
297
298                     }
299                     Json.Generator generator = new Json.Generator ();
300                         generator.set_root (jsonAll.get_node());
301                         generator.pretty=  true;
302                         generator.ident = 2;
303                         generator.to_file(PackerRun.opt_doc_target+"/json/roodata.json");
304
305                     
306                     
307                     // regenrate the index with different relative links
308                     Link.base = "";
309                     //var classesIndex = classesTemplate.process(classes);
310                     
311                     GLib.debug("build index");
312                     
313                     FileUtils.set_contents(
314                                 PackerRun.opt_doc_target +  "/index." + PackerRun.opt_doc_ext , 
315                         classesindexTemplate.process(classes)
316                     );
317                     
318                     // blank everything???? classesindexTemplate = classesIndex = classes = null;
319                     
320          
321                     /*
322                     var documentedFiles = symbols.filter(function ($) {
323                         return ($.is("FILE"))
324                     });
325                     
326                     var allFiles = [];
327                     
328                     for (var i = 0; i < files.length; i++) {
329                         allFiles.push(new  Symbol(files[i], [], "FILE", new DocComment("/** *" + "/")));
330                     }
331                     
332                     for (var i = 0; i < documentedFiles.length; i++) {
333                         var offset = files.indexOf(documentedFiles[i].alias);
334                         allFiles[offset] = documentedFiles[i];
335                     }
336                         
337                     allFiles = allFiles.sort(makeSortby("name"));
338                     GLib.debug("write files index");
339                     
340                     FileUtils.set_contents(
341                                 PackerRun.opt_doc_target + "/files." + PackerRun.opt_doc_ext , 
342                         fileindexTemplate.process(allFiles)
343                     );
344                     */
345                     
346                     
347                     
348                 }
349     /**
350      * JSON files are lookup files for the documentation
351      * - can be used by IDE's or AJAX based doc tools
352      * 
353      * 
354      */
355     JSON.Object publishJSON (Symbol data)
356     {
357         // what we need to output to be usefull...
358         // a) props..
359         var cfgProperties = new GLib.ArrayList<Symbol>();
360         if (!data.comment.getTag(DocTagTitle.SINGLETON).length) {
361             cfgProperties = data.configToArray();
362             cfgProperties = cfgProperties.sort((a,b) =>{
363                         return a.alias.collate(b.alias);
364             });
365             
366         }
367         
368         var props = new JSON.Array();; 
369         //println(cfgProperties.toSource());
370         
371         for(var i =0; i < cfgProperties.size;i++) {
372             var p = cfgPropertiesget.get(i);
373             var add = new JSON.Object();
374             add.set_string_member("name",p.name);
375             add.set_string_member("type",p.type);
376             add.set_string_member("desc",p.desc);
377             add.set_string_member("memberOf", p.memberOf == data.alias ? '' : p.memberOf);
378                 
379             if (p.optvalues.size) {
380                         add.set_array_member("desc",p.optvalues_as_json_array());
381             }
382             props.add_object(add );
383         }
384         
385         ///// --- events
386         var ownEvents = new Gee.ArrayList<Symbol>();
387         for(var i =0; i < data.methods.size;i++) {
388                 var e = data.methods.get(i);
389                 if (e.isEvent && e.comment.getTag(DocTagTitle.HIDE) == "") {
390                         ownEvents.add(e);
391                         }
392                 };
393                 ownEvents.sort((a,b) => {
394                         return a.name.collate(b.name);
395                 });
396         
397         var events = new JSON.Array();
398          
399         for(var i =0; i < ownEvents.size;i++) {
400             var m = ownEvents.get(i);
401             var add = new JSON.Object();
402             add.set_string_member("name",m.name.substring(1,m.name.length-1));
403             add.set_string_member("type","function");
404             add.set_string_member("desc",m.desc);
405             add.set_string_member("sig", this.makeFuncSkel(m.params));
406             events.add(add);
407         }
408         
409         // methods
410         var ownMethods = new Gee.ArrayList<Symbol>();
411         for(var i =0; i < data.methods.size;i++) {
412                 var e = data.methods.get(i);
413                 if (!e.isEvent && e.comment.getTag(DocTagTitle.HIDE) == "") {
414                         ownMethods.add(e);
415                         }
416                 };
417                 ownMethods.sort((a,b) => {
418                         return a.name.collate(b.name);
419                 });
420         
421                 var methods = new JSON.Array();
422          
423         for(var i =0; i < ownMethods.size;i++) {
424             var m = ownMethods.get(i);
425             var add = new JSON.Object();
426             add.set_string_member("name",m.name.substring(1,m.name.length-1);
427             add.set_string_member("type","function");
428             add.set_string_member("desc",m.desc);
429             add.set_string_member("sig", this.makeMethodSkel(m.params));
430             events.add(add);
431         }
432          
433         //println(props.toSource());
434         // we need to output:
435         //classname => {
436         //    propname => 
437         //        type=>
438         //        desc=>
439         //    }
440                 var ret =  new JSON.Object();
441                 ret.set_object_member("props", props);
442                 ret.set_object_member("events", events);
443                 ret.set_object_member("methods", methods);
444                 
445        return ret;
446         
447         
448         // b) methods
449         // c) events
450         
451         
452     },
453      
454     // in Link (js) ???
455     string srcFileRelName(string sourceFile)
456     {
457                 return sourceFile.substring(PackerRun.opt_real_basedir.length+1);
458     }
459     string srcFileFlatName(string sourceFile)
460     {
461         var name = this.srcFileRelName(sourceFile);
462         name = DocBuilder.regex_dotdot.replace(name, name.length, 0, "");
463         name = name.replace("/", "_").replace(":", "_") + .".html";
464         
465     }
466     
467     
468     void makeSrcFile(string sourceFile) 
469     {
470         // this stuff works...
471      
472         
473         var name = this.srcFileFlatName(sourceFile);
474         
475         GLib.debug("Write Source file : %s/symbols/src/%s", opt_doc_target, name);
476         var pretty = PrettyPrint.toPretty(FileUtils.get_contenst(sourceFile));
477         File.write(PackerRun.opt_doc_target+"/symbols/src/" + name, 
478             "<html><head>" +
479             "<title>" + sourceFile + "</title>" +
480             "<link rel=\"stylesheet\" type=\"text/css\" href=\"../../../css/highlight-js.css\"/>" + 
481             "</head><body class=\"highlightpage\">" +
482             pretty +
483             "</body></html>");
484     },
485     /**
486      * used by JSON output to generate a function skeleton
487      */
488      /*
489     string makeFuncSkel(Gee.ArrayList<Symbol> params) {
490         if (params.length < 0) {
491                  return "function ()\n{\n\n}";
492                 }
493                 
494         return "function ("     +
495             params.filter(
496                 function($) {
497                     return $.name.indexOf(".") == -1; // don't show config params in signature
498                 }
499             ).map( function($) { return $.name == 'this' ? '_self' : $.name; } ).join(", ") +
500         ")\n{\n\n}";
501     },
502         makeMethodSkel :function(params) {
503         if (!params) return "()";
504         return "("      +
505             params.filter(
506                 function($) {
507                     return $.name.indexOf(".") == -1; // don't show config params in signature
508                 }
509             ).map( function($) { return  $.type + " "  +(  $.name == 'this' ? '_self' : $.name ); } ).join(", ") +
510         ")";
511     }
512  
513     */
514 };
515   
516
517
518
519
520
521  
522
523
524
525