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