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