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
526