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(makeSortby("alias"));
346             
347         }
348         var props = []; 
349         //println(cfgProperties.toSource());
350         var p ='';
351         for(var i =0; i < cfgProperties.length;i++) {
352             p = cfgProperties[i];
353             var add = {
354                 name : p.name,
355                 type : p.type,
356                 desc : p.desc,
357                 
358                 memberOf : p.memberOf == data.alias ? '' : p.memberOf
359             }
360             if (p.optvalues) {
361                 add.optvals = p.optvalues;
362             }
363             props.push(add );
364         }
365         
366          
367         var ownEvents = data.methods.filter( function(e){
368                 return e.isEvent && !e.comment.getTag('hide').length;
369             }).sort(makeSortby("name"));
370              
371         
372         var events = [];
373         var m;
374         for(var i =0; i < ownEvents.length;i++) {
375             m = ownEvents[i];
376             events.push( {
377                 name : m.name.substring(1),
378                 sig : this.makeFuncSkel(m.params),
379                 type : 'function',
380                 desc : m.desc
381             });
382         }
383         
384         var ownMethods = data.methods.filter( function(e){
385                 return !e.isEvent && !e.comment.getTag('hide').length;
386             }).sort(makeSortby("name"));
387              
388         
389         var methods = [];
390         
391         for(var i =0; i < ownMethods.length;i++) {
392             m = ownMethods[i];
393             methods.push( {
394                 name : m.name,
395                 sig : this.makeMethodSkel(m.params),
396                 type : 'function',
397                 desc : m.desc
398             });
399         }
400         
401         //println(props.toSource());
402         // we need to output:
403         //classname => {
404         //    propname => 
405         //        type=>
406         //        desc=>
407         //    }
408
409         var ret = {
410             props : props,
411             events: events,
412             methods : methods,
413         };
414         return ret;
415         
416         
417         
418         // b) methods
419         // c) events
420         
421         
422     },
423     srcFileRelName : function(sourceFile)
424     {
425       return sourceFile.substring(PackerRun.opt_real_basedir.length+1);
426     },
427     srcFileFlatName: function(sourceFile)
428     {
429         var name = this.srcFileRelName(sourceFile);
430         name = name.replace(/\.\.?[\\\/]/g, "").replace(/[\\\/]/g, "_");
431         return name.replace(/\:/g, "_") + '.html'; //??;
432         
433     },
434     
435     makeSrcFile: function(sourceFile) 
436     {
437         // this stuff works...
438      
439         
440         var name = this.srcFileFlatName(sourceFile);
441         
442         GLib.debug("Write Source file : " + PackerRun.opt_doc_target+"/symbols/src/" + name);
443         var pretty = imports.PrettyPrint.toPretty(File.read(  sourceFile));
444         File.write(PackerRun.opt_doc_target+"/symbols/src/" + name, 
445             '<html><head>' +
446             '<title>' + sourceFile + '</title>' +
447             '<link rel="stylesheet" type="text/css" href="../../../css/highlight-js.css"/>' + 
448             '</head><body class="highlightpage">' +
449             pretty +
450             '</body></html>');
451     },
452     /**
453      * used by JSON output to generate a function skeleton
454      */
455     makeFuncSkel :function(params) {
456         if (!params) return "function ()\n{\n\n}";
457         return "function ("     +
458             params.filter(
459                 function($) {
460                     return $.name.indexOf(".") == -1; // don't show config params in signature
461                 }
462             ).map( function($) { return $.name == 'this' ? '_self' : $.name; } ).join(", ") +
463         ")\n{\n\n}";
464     },
465         makeMethodSkel :function(params) {
466         if (!params) return "()";
467         return "("      +
468             params.filter(
469                 function($) {
470                     return $.name.indexOf(".") == -1; // don't show config params in signature
471                 }
472             ).map( function($) { return  $.type + " "  +(  $.name == 'this' ? '_self' : $.name ); } ).join(", ") +
473         ")";
474     }
475  
476     
477 };
478   
479
480
481
482
483
484  
485
486
487
488