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