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         for(var symbol in symbol) {
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