fix overwrite symbols - not sure why it was enabled?
[roojspacker] / roojspacker / DocBuilder.vala
1  
2  
3
4 namespace JSDOC 
5 {
6
7         public class DocBuilder : Object 
8         {
9                 
10  
11                 // extractable via JSON?
12                 public string VERSION = "1.0.0" ;
13                 
14                 private SymbolSet symbolSet;
15                 
16                 public Symbol getSymbol(string name) // wrapper for read only...
17                 {
18                         return this.symbolSet.getSymbol(name);
19                 }
20                 
21                 
22                 
23                 
24                 private Packer packer;
25         
26                 public DocBuilder (Packer p) 
27                 {
28                         
29  
30                         GLib.debug("Roo JsDoc Toolkit started  at %s ",  (new GLib.DateTime.now_local()).format("Y/m/d H:i:s"));
31                         
32                         this.packer = p;
33         
34                     //if (PackerRun.singleton().opt_tmp_dir != null && !FileUtils.test(PackerRun.singleton().opt_tmp_dir, GLib.FileTest.IS_DIR)) {   
35                     //    Posix.mkdir(PackerRun.singleton().opt_tmp_dir, 0700);
36                     //}
37         
38         
39                     this.parseSrcFiles();
40                     
41                     DocParser.validateAugments();                   
42                     DocParser.fillChildClasses();
43                     DocParser.fillTreeChildren();
44                     
45                     
46                     this.symbolSet = DocParser.symbols();
47                     
48                     
49                     var classes =  DocParser.classes();
50                      
51                     
52                     // this currently uses the concept of publish.js...
53                    
54                     if (PackerRun.singleton().opt_doc_dump_tree) {
55                     
56                     
57                         
58                                 
59                          
60                                 //print(JSON.stringify(symbols,null,4));
61                                  
62                         var jsonAll = new Json.Object(); 
63                         var ar = new Json.Array(); 
64                                 for (var i = 0, l = this.symbolSet.values().size; i < l; i++) {
65                                     var symbol = this.symbolSet.values().get(i);    
66                                     //
67                                     ar.add_object_element(  symbol.toJson());
68
69                                 }
70                                 jsonAll.set_array_member("data", ar);
71                                 var generator = new Json.Generator ();
72                             var root = new Json.Node(Json.NodeType.OBJECT);
73                    
74                                 root.init_object(jsonAll);
75                                 generator.set_root (root);
76                                 generator.pretty=  true;
77                                 generator.indent = 2;
78                                  
79                                 size_t l;
80                                 stdout.printf("%s\n",generator.to_data(out l));
81
82                                 return;
83                         }
84                         size_t l;
85                         //GLib.debug("JSON: %s", generator.to_data(out l));
86                     
87                     
88                     
89                     
90                     this.publish();
91         
92         
93                 }
94                 
95          
96                 
97                 /**
98                  * Parse the source files.
99                  * 
100                  */
101  
102                 private void parseSrcFiles() 
103                 {
104                    
105                     
106                     
107                     //var useCache = PackerRun.opt_cache_dir == null ;
108                     //var cacheFile = "";
109                     
110                     for (var i = 0, l = this.packer.files.size; i < l; i++) {
111                         
112                         var srcFile = this.packer.files.get(i);
113                         GLib.debug("Parsing source File: %s", srcFile);
114                      /*   
115                         if (useCache) {
116                         
117                                 cacheFile = PackerRun.opt_cache_dir + srcFile.replace("/", '_') + ".cache";
118                                     
119                                     //print(cacheFile);
120                                     // disabled at present!@!!
121                                     
122                                     if (GLib.FileUtils.test(cacheFile, GLib.FileTest.EXISTS)) {
123                                         // check filetime?
124                                         var cache_mt = File.new_for_path (cacheFile).queryInfo(FileAttribute.TIME_MODIFIED,
125                                                             GLib.FileQueryInfoFlags.NONE, null).
126                                                             get_modification_time();
127                                         var original_mt = File.new_for_path (sourceInfo).queryInfo(FileAttribute.TIME_MODIFIED,
128                                                             GLib.FileQueryInfoFlags.NONE, null).
129                                                             get_modification_time();
130                                         // this check does not appear to work according to the doc's - need to check it out.
131                                        
132                                         if (cache_mt > original_mt) { // cached time  > original time!
133                                             // use the cached mtimes..
134                                             GLib.debug("Read %s" , cacheFile);
135                                                         var parser = new Json.Parser();
136                                             parser.load_from_file(cacheFile);
137                                             var ar = parser.get_root ().get_array();
138
139                                             for(var i = 0;i < ar.get_length();i++) {
140                                                         var o = ar.get_object_element(i);
141                                                         var sym = JSON.gobject_from_data(typeof(Symbol), o) as Symbol;
142                                                         DocParser.symbols.add(sym);
143                                                 }
144                                                 continue;
145                                         }
146                             }
147                         }
148                        */ 
149                         var src = "";
150                         try {
151                             GLib.debug("reading : %s" , srcFile);
152                             GLib.FileUtils.get_contents(srcFile, out src);
153                         }
154                         catch(GLib.FileError e) {
155                             GLib.debug("Can't read source file '%s': %s", srcFile, e.message);
156                             continue;
157                         }
158
159                           
160                         
161                         var tr = new  TokenReader(this.packer);
162                                 tr.keepDocs = true;
163                                 tr.keepWhite = true;
164                                 tr.keepComments = true;
165                                 tr.sepIdents = false;
166                                 tr.collapseWhite = false;
167                                 tr.filename = src;
168                         
169
170                         var toks = tr.tokenize( new TextStream(src) );
171                         if (PackerRun.singleton().opt_dump_tokens) {
172                                         toks.dump();
173                                         return;
174                                         //GLib.Process.exit(0);
175                                 }
176                         
177                         
178                         var ts = new TokenStream(toks.tokens);
179                     
180                     
181                     
182                                  
183                         DocParser.parse(ts, srcFile);
184                        
185                     }
186                     
187                      
188                     
189                     DocParser.finish();
190                     
191                     
192                     // this is probably not the best place for this..
193                    
194                     
195
196                     
197                     
198                     
199                 }
200                 
201                  
202                  
203                  
204         string tempdir;
205         
206                 void publish() 
207                 {
208                     GLib.debug("Publishing");
209                      
210                     // link!!!
211                     this.tempdir = GLib.DirUtils.make_tmp("roopackerXXXXXX");
212                     
213                     GLib.debug("Making directories");
214                     if (!FileUtils.test (PackerRun.singleton().opt_doc_target,FileTest.IS_DIR )) {
215                         Posix.mkdir(PackerRun.singleton().opt_doc_target,0755);
216                     }
217                     if (!FileUtils.test(PackerRun.singleton().opt_doc_target+"/symbols",FileTest.IS_DIR)) {
218                         Posix.mkdir(PackerRun.singleton().opt_doc_target+"/symbols",0755);
219                     }
220                     if (!FileUtils.test(PackerRun.singleton().opt_doc_target+"/src",FileTest.IS_DIR)) {
221                         Posix.mkdir(PackerRun.singleton().opt_doc_target+"/src",0755);
222                     }
223                     if (!FileUtils.test(PackerRun.singleton().opt_doc_target +"/json",FileTest.IS_DIR)) {
224                         Posix.mkdir(PackerRun.singleton().opt_doc_target +"/json",0755);
225                     }
226                     
227                     GLib.debug("Copying files from static: %s " , PackerRun.singleton().opt_doc_template_dir);
228                     // copy everything in 'static' into 
229                     
230                     if (PackerRun.singleton().opt_doc_template_dir  != null) {
231                                 
232                                 var iter = GLib.File.new_for_path(
233                                                 PackerRun.singleton().opt_doc_template_dir + "/static"
234                                         ).enumerate_children (
235                                         "standard::*",
236                                         FileQueryInfoFlags.NOFOLLOW_SYMLINKS, 
237                                         null);
238                                 FileInfo info;
239                                 
240                                 while ( (info = iter.next_file (null)) != null) {
241                                         if (info.get_file_type () == FileType.DIRECTORY) {
242                                                 continue;
243                                         } 
244                                         var src = File.new_for_path(info.get_name());
245                                     GLib.debug("Copy %s to %s/%s" ,
246                                          info.get_name() ,
247                                           PackerRun.singleton().opt_doc_target , src.get_basename());                   
248                                 
249                                         src.copy(
250                                                 GLib.File.new_for_path(
251                                                         PackerRun.singleton().opt_doc_target + "/" + src.get_basename()
252                                                 ),
253                                                 GLib.FileCopyFlags.OVERWRITE
254                                         );
255                                 }
256                 
257                         }                   
258                     GLib.debug("Setting up templates");
259                      
260                     
261                     
262                     var symbols = this.symbolSet.values();
263                     
264                     var files = this.packer.files;
265                     
266                     for (var i = 0, l = files.size; i < l; i++) {
267                         var file = files.get(i);
268                        // var targetDir = PackerRun.singleton().opt_doc_target + "/symbols/src/";
269                         this.makeSrcFile(file);
270                     }
271                     //print(JSON.stringify(symbols,null,4));
272                     var classes = DocParser.classes();
273                      
274                      //GLib.debug("classTemplate Process : all classes");
275                         
276                    // var classesIndex = classesTemplate.process(classes); // kept in memory
277                     
278                     GLib.debug("iterate classes");
279                    
280                     var jsonAll = new Json.Object(); 
281                     
282                     for (var i = 0, l = classes.size; i < l; i++) {
283                         var symbol = classes.get(i);
284                         var output = "";
285                         
286                         GLib.debug("classTemplate Process : %s" , symbol.alias);
287                         
288                         
289                         var   class_gen = new Json.Generator ();
290                             var  class_root = new Json.Node(Json.NodeType.OBJECT);
291                                 class_root.init_object(symbol.toClassDocJSON());
292                                 class_gen.set_root (class_root);
293                                 class_gen.pretty=  true;
294                                 class_gen.indent = 2;
295                                 GLib.debug("writing JSON:  %s", PackerRun.singleton().opt_doc_target+"/symbols/" +symbol.alias+".json");
296                                 this.writeJson(class_gen, PackerRun.singleton().opt_doc_target+"/symbols/" +symbol.alias+".json");
297                         
298                         jsonAll.set_object_member(symbol.alias,  symbol.toClassJSON());
299
300                     }
301                     
302                     // outptu class tree
303                     
304                     var   class_tree_gen = new Json.Generator ();
305             var  class_tree_root = new Json.Node(Json.NodeType.ARRAY);
306                         class_tree_root.init_array(this.class_tree(classes));
307                         class_tree_gen.set_root (class_tree_root);
308                         class_tree_gen.pretty=  true;
309                         class_tree_gen.indent = 2;
310                         GLib.debug("writing JSON:  %s", PackerRun.singleton().opt_doc_target+"/tree.json");
311                         this.writeJson(class_tree_gen,PackerRun.singleton().opt_doc_target+"/tree.json");
312                         size_t class_tree_l;
313                         //GLib.debug("JSON: %s", class_tree_gen.to_data(out class_tree_l));
314                     
315                     
316                     
317                     /*---- this is our 'builder' json file.. -- a full list of objects+functions */
318                     
319                     
320                     var   generator = new Json.Generator ();
321             var  root = new Json.Node(Json.NodeType.OBJECT);
322                         root.init_object(jsonAll);
323                         generator.set_root (root);
324                         generator.pretty=  true;
325                         generator.indent = 2;
326                         GLib.debug("writing Builder JSON:  %s", PackerRun.singleton().opt_doc_target+"/json/roodata.json");
327                         
328                         
329                         this.writeJson(generator,PackerRun.singleton().opt_doc_target+"/json/roodata.json");
330                         size_t l;
331                         //GLib.debug("JSON: %s", generator.to_data(out l));
332                     
333                     
334                      
335                     
336                     GLib.debug("build index");
337                    
338                     
339                     
340                 }
341                 
342  
343                 /**
344                 * needed as Json dumps .xXXX into same directory as it writes...
345                 */
346                 void writeJson(Json.Generator g, string fname)
347                 {
348                                 var tmp = this.tempdir + GLib.Path.get_basename(fname);
349                                 g.to_file(tmp);
350                                 
351                                 if (GLib.FileUtils.test(fname, GLib.FileTest.EXISTS)) {
352                                         string new_data, old_data;
353                                         FileUtils.get_contents(tmp, out new_data);
354                                         FileUtils.get_contents(fname, out old_data);
355                                         if (old_data == new_data) {
356                                                 GLib.File.new_for_path(tmp).delete();
357                                                 return;
358                                         }
359                            }
360                                 
361                         GLib.File.new_for_path(tmp).move( File.new_for_path(fname), GLib.FileCopyFlags.OVERWRITE);
362                       
363                 }
364                  
365                 Gee.HashMap<string,Json.Object> class_tree_map;
366                 Json.Array class_tree_top;
367                 
368                 Json.Object? class_tree_new_obj(string name, bool is_class, out bool is_new) 
369                 {
370                 if (this.class_tree_map.has_key(name)) {
371                         var ret = this.class_tree_map.get(name);
372                         if (!ret.get_boolean_member("is_class") && is_class) {
373                                 ret.set_boolean_member("is_class", is_class);
374                         }
375                         is_new = false;
376                         return ret; // no need to do anything
377                 
378                 }
379                 
380                 GLib.debug("Class Tree: new object %s", name);
381                 var add =  new Json.Object();
382                 add.set_string_member("name", name);
383                 add.set_array_member("cn", new Json.Array());
384                 add.set_boolean_member("is_class", is_class);
385                 
386                 this.class_tree_map.set(name, add);
387                 var bits = name.split(".");
388                 if (bits.length == 1) {
389                         // top level..
390                         this.class_tree_top.add_object_element(add);
391                          
392                 } 
393                 is_new = true;
394                 
395                         return add;
396                 
397                 }
398                 
399                 void class_tree_make_parents(  Json.Object add)
400                 {
401                         var name = add.get_string_member("name");
402                         var bits = name.split(".");
403                 if (bits.length < 2) {
404                         return;
405                 }
406                 // got aaa.bb or aaa.bb.cc
407                 // find the parent..
408                 string[] nn = {};
409                 for(var i=0; i < bits.length-1; i++) {
410                         nn += bits[i];
411                 }
412                 var pname = string.joinv(".", nn);
413                 GLib.debug("Class Tree: adding to parent %s => %s", name, pname); 
414                          
415                         // no parent found.. make one..
416                         bool is_new;
417                         var parent = this.class_tree_new_obj(pname, false, out is_new); 
418                         parent.get_array_member("cn").add_object_element(add);
419                         if (is_new) {
420                                 this.class_tree_make_parents(  parent);
421                         }
422                 
423                 
424                 }
425                 Json.Array class_tree (Gee.ArrayList<Symbol> classes )
426                 {
427                 
428                 
429                     // produce a tree array that can be used to render the navigation.
430                     /*
431                     should produce:
432                     
433                     [
434                         {
435                                 name : Roo,
436                                 desc : ....
437                                 is_class : true,
438                                 cn : [
439                                         {
440                                                 name : 'Roo.util',
441                                                 basename : 'util',
442                                                 is_class : false,
443                                                 cn : [
444                                                         {
445                                                                 ....
446                     
447                     to do this, we will need to create the objects in a hashmap
448                     Roo.util => Json.Object
449                     
450                     */
451                     this.class_tree_top = new Json.Array();
452                     this.class_tree_map = new Gee.HashMap<string,Json.Object>();
453                     foreach (var cls in classes) {
454                         if(cls.alias.length < 1 || cls.alias == "this" || cls.alias == "_global_") {
455                                 GLib.debug("Skip alias|global %s", cls.name);
456                                 continue;
457                         }
458                         bool is_new;
459                         var add =  this.class_tree_new_obj(cls.alias, cls.methods.size > 0 ? true : false,out is_new);
460                                 if (add != null) {
461                                         this.class_tree_make_parents( add);
462                                 }
463                         
464                     }
465                     
466                      return this.class_tree_top;
467                     
468                 }
469                 
470                 
471                 // in Link (js) ???
472                 string srcFileRelName(string sourceFile)
473                 {
474                         var rp = Posix.realpath(sourceFile);
475                         return rp.substring(PackerRun.singleton().opt_real_basedir.length);
476                 }
477                 string srcFileFlatName(string sourceFile)
478                 {
479                     var name = this.srcFileRelName(sourceFile);
480                     name = /\.\.?[\/]/.replace(name, name.length, 0, "");
481                     name = name.replace("/", "_").replace(":", "_") + ".html";
482                     return name;
483                 }
484                 
485                 
486                 void makeSrcFile(string sourceFile) 
487                 {
488                     // this stuff works...
489                     
490                    
491                     
492                         // this check does not appear to work according to the doc's - need to check it out.
493                
494                   
495                     var name = this.srcFileFlatName(sourceFile);
496                     
497                     GLib.debug("Write Source file : %s/src/%s", 
498                 PackerRun.singleton().opt_doc_target, name);
499                 var str = "";
500                 FileUtils.get_contents(sourceFile, out str);
501                     var pretty = PrettyPrint.toPretty(str); 
502                      var fname = PackerRun.singleton().opt_doc_target+"/src/" + name;
503                     
504                     var tmp = this.tempdir + GLib.Path.get_basename(fname);
505                     FileUtils.set_contents(
506                         tmp, 
507                         "<html><head>" +
508                         "<title>" + this.srcFileRelName(sourceFile) + "</title>" +
509                         "<link rel=\"stylesheet\" type=\"text/css\" href=\"../../css/highlight-js.css\"/>" + 
510                         "</head><body class=\"highlightpage\">" +
511                         pretty +
512                         "</body></html>");
513                         
514                     // same content?
515                      if (GLib.FileUtils.test(fname, GLib.FileTest.EXISTS)) {
516                                 string new_data, old_data;
517                                 FileUtils.get_contents(tmp, out new_data);
518                                 FileUtils.get_contents(fname, out old_data);
519                                 if (old_data == new_data) {
520                                         GLib.File.new_for_path(tmp).delete();
521                                         return;
522                                 }
523                      }
524                         
525                 GLib.File.new_for_path(tmp).move( File.new_for_path(fname), GLib.FileCopyFlags.OVERWRITE);
526                       
527                     
528                     
529
530                 }
531         }
532                  
533 }
534   
535
536
537
538
539
540  
541
542
543
544