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