Fix #6894 - debugging generator
[roojspacker] / roojspacker / DocBuilder.vala
1  
2  
3
4 namespace JSDOC 
5 {
6
7         class DocBuilder : Object 
8         {
9                 
10  
11                 // extractable via JSON?
12                 public string VERSION = "1.0.0" ;
13                 
14                 private SymbolSet symbolSet;
15                 
16                 private Packer packer;
17         
18                 public DocBuilder (Packer p) 
19                 {
20                         
21  
22                         GLib.debug("Roo JsDoc Toolkit started  at %s ",  (new GLib.DateTime.now_local()).format("Y/m/d H:i:s"));
23                         
24                         this.packer = p;
25         
26                     //if (PackerRun.singleton().opt_tmp_dir != null && !FileUtils.test(PackerRun.singleton().opt_tmp_dir, GLib.FileTest.IS_DIR)) {   
27                     //    Posix.mkdir(PackerRun.singleton().opt_tmp_dir, 0700);
28                     //}
29         
30         
31                     this.parseSrcFiles();
32                     
33                     this.symbolSet = DocParser.symbols();
34                      
35                     // this currently uses the concept of publish.js...
36                     
37                     if (PackerRun.singleton().opt_doc_dump_tree) {
38                     
39                     
40                         var symbols = this.symbolSet.values();
41                     
42                                  
43                                 
44                          
45                                 //print(JSON.stringify(symbols,null,4));
46                                 var classes = new Gee.ArrayList<Symbol>();
47                                 
48                                 foreach(var symbol in symbols) {
49                                         if (symbol.isaClass()) { 
50                                                 classes.add(symbol);
51                                         }
52                                 }    
53                                 classes.sort( (a,b) => {
54                                         return a.alias.collate(b.alias); 
55                                 });
56                     
57                         var jsonAll = new Json.Object(); 
58                                 for (var i = 0, l = classes.size; i < l; i++) {
59                                     var symbol = classes.get(i);
60                                          
61                                     jsonAll.set_object_member(symbol.alias,  this.publishJSON(symbol));
62
63                                 }
64                                 
65                                 var generator = new Json.Generator ();
66                             var root = new Json.Node(Json.NodeType.OBJECT);
67                    
68                                 root.init_object(jsonAll);
69                                 generator.set_root (root);
70                                 generator.pretty=  true;
71                                 generator.indent = 2;
72                                  
73                                 size_t l;
74                                 stdout.printf("%s\n",generator.to_data(out l));
75
76                                 return;
77                         }
78                         size_t l;
79                         //GLib.debug("JSON: %s", generator.to_data(out l));
80                     
81                     
82                     
83                     
84                     this.publish();
85         
86         
87                 }
88                 
89          
90                 
91                 /**
92                  * Parse the source files.
93                  * 
94                  */
95  
96                 private void parseSrcFiles() 
97                 {
98                    
99                     
100                     
101                     //var useCache = PackerRun.opt_cache_dir == null ;
102                     //var cacheFile = "";
103                     
104                     for (var i = 0, l = this.packer.files.size; i < l; i++) {
105                         
106                         var srcFile = this.packer.files.get(i);
107                         GLib.debug("Parsing source File: %s", srcFile);
108                      /*   
109                         if (useCache) {
110                         
111                                 cacheFile = PackerRun.opt_cache_dir + srcFile.replace("/", '_') + ".cache";
112                                     
113                                     //print(cacheFile);
114                                     // disabled at present!@!!
115                                     
116                                     if (GLib.FileUtils.test(cacheFile, GLib.FileTest.EXISTS)) {
117                                         // check filetime?
118                                         var cache_mt = File.new_for_path (cacheFile).queryInfo(FileAttribute.TIME_MODIFIED,
119                                                             GLib.FileQueryInfoFlags.NONE, null).
120                                                             get_modification_time();
121                                         var original_mt = File.new_for_path (sourceInfo).queryInfo(FileAttribute.TIME_MODIFIED,
122                                                             GLib.FileQueryInfoFlags.NONE, null).
123                                                             get_modification_time();
124                                         // this check does not appear to work according to the doc's - need to check it out.
125                                        
126                                         if (cache_mt > original_mt) { // cached time  > original time!
127                                             // use the cached mtimes..
128                                             GLib.debug("Read %s" , cacheFile);
129                                                         var parser = new Json.Parser();
130                                             parser.load_from_file(cacheFile);
131                                             var ar = parser.get_root ().get_array();
132
133                                             for(var i = 0;i < ar.get_length();i++) {
134                                                         var o = ar.get_object_element(i);
135                                                         var sym = JSON.gobject_from_data(typeof(Symbol), o) as Symbol;
136                                                         DocParser.symbols.add(sym);
137                                                 }
138                                                 continue;
139                                         }
140                             }
141                         }
142                        */ 
143                         var src = "";
144                         try {
145                             GLib.debug("reading : %s" , srcFile);
146                             GLib.FileUtils.get_contents(srcFile, out src);
147                         }
148                         catch(GLib.FileError e) {
149                             GLib.debug("Can't read source file '%s': %s", srcFile, e.message);
150                             continue;
151                         }
152
153                           
154                         
155                         var tr = new  TokenReader(this.packer);
156                                 tr.keepDocs = true;
157                                 tr.keepWhite = true;
158                                 tr.keepComments = true;
159                                 tr.sepIdents = false;
160                                 tr.collapseWhite = false;
161                                 tr.filename = src;
162                         
163
164                         var toks = tr.tokenize( new TextStream(src) );
165                         if (PackerRun.singleton().opt_dump_tokens) {
166                                         toks.dump();
167                                         return;
168                                         //GLib.Process.exit(0);
169                                 }
170                         
171                         
172                         var ts = new TokenStream(toks.tokens);
173                     
174                     
175                     
176                                  
177                         DocParser.parse(ts, srcFile);
178                         /*
179                         if (useCache) {
180                                 
181                                 var ar = DocParser.symbolsToObject(srcFile);
182                                 
183                                 var builder = new Json.Builder ();
184                                 builder.begin_array ();
185                                 for (var i=0;i<ar.size;i++) {
186                                 
187                                                 builder.add_object_value (ar.get(i));
188                                         }
189                                         builder.end_array ();
190                                         Json.Generator generator = new Json.Generator ();
191                                         Json.Node root = builder.get_root ();
192                                         generator.set_root (root);
193                                         generator.pretty=  true;
194                                         generator.ident = 2;
195                                         generator.to_file(cacheFile);
196                         
197                          
198                             
199                                  }
200                                  */
201                     }
202                     
203                      
204                     
205                     DocParser.finish();
206                 }
207                 /*
208
209             //var txs =
210             
211             var tr = new  TokenReader(this.packer);
212                         tr.keepDocs = true;
213                         tr.keepWhite = true;
214                         tr.keepComments = true;
215                         tr.sepIdents = false;
216                         tr.collapseWhite = false;
217                         tr.filename = src;
218             
219
220             var toks = tr.tokenize( new TextStream(src));
221             if (PackerRun.opt_dump_tokens) {
222                                 toks.dump();
223                                 return "";
224                                 //GLib.Process.exit(0);
225                         }
226             
227             
228             var ts = new TokenStream(toks);
229         
230         
231         
232                      
233             DocParser.parse(ts, srcFile);
234             
235             if (useCache) {
236                         
237                         var ar = DocParser.symbolsToObject(srcFile);
238                         
239                         var builder = new Json.Builder ();
240                 builder.begin_array ();
241                 for (var i=0;i<ar.size;i++) {
242                 
243                                         builder.add_object_value (ar.get(i));
244                                 }
245                                 builder.end_array ();
246                                 Json.Generator generator = new Json.Generator ();
247                                 Json.Node root = builder.get_root ();
248                                 generator.set_root (root);
249                                 generator.pretty=  true;
250                                 generator.ident = 2;
251                                 generator.to_file(cacheFile);
252             
253              
254                 
255     //          }
256         }
257         
258         
259         
260         Parser.finish();
261     }
262     
263      */
264         string tempdir;
265         
266                 void publish() 
267                 {
268                     GLib.debug("Publishing");
269                      
270                     // link!!!
271                     this.tempdir = GLib.DirUtils.make_tmp("roopackerXXXXXX");
272                     
273                     GLib.debug("Making directories");
274                     if (!FileUtils.test (PackerRun.singleton().opt_doc_target,FileTest.IS_DIR )) {
275                         Posix.mkdir(PackerRun.singleton().opt_doc_target,0755);
276                     }
277                     if (!FileUtils.test(PackerRun.singleton().opt_doc_target+"/symbols",FileTest.IS_DIR)) {
278                         Posix.mkdir(PackerRun.singleton().opt_doc_target+"/symbols",0755);
279                     }
280                     if (!FileUtils.test(PackerRun.singleton().opt_doc_target+"/src",FileTest.IS_DIR)) {
281                         Posix.mkdir(PackerRun.singleton().opt_doc_target+"/src",0755);
282                     }
283                     if (!FileUtils.test(PackerRun.singleton().opt_doc_target +"/json",FileTest.IS_DIR)) {
284                         Posix.mkdir(PackerRun.singleton().opt_doc_target +"/json",0755);
285                     }
286                     
287                     GLib.debug("Copying files from static: %s " , PackerRun.singleton().opt_doc_template_dir);
288                     // copy everything in 'static' into 
289                     
290                     if (PackerRun.singleton().opt_doc_template_dir  != null) {
291                                 
292                                 var iter = GLib.File.new_for_path(
293                                                 PackerRun.singleton().opt_doc_template_dir + "/static"
294                                         ).enumerate_children (
295                                         "standard::*",
296                                         FileQueryInfoFlags.NOFOLLOW_SYMLINKS, 
297                                         null);
298                                 FileInfo info;
299                                 
300                                 while ( (info = iter.next_file (null)) != null) {
301                                         if (info.get_file_type () == FileType.DIRECTORY) {
302                                                 continue;
303                                         } 
304                                         var src = File.new_for_path(info.get_name());
305                                     GLib.debug("Copy %s to %s/%s" ,
306                                          info.get_name() ,
307                                           PackerRun.singleton().opt_doc_target , src.get_basename());                   
308                                 
309                                         src.copy(
310                                                 GLib.File.new_for_path(
311                                                         PackerRun.singleton().opt_doc_target + "/" + src.get_basename()
312                                                 ),
313                                                 GLib.FileCopyFlags.OVERWRITE
314                                         );
315                                 }
316                 
317                         }                   
318                     GLib.debug("Setting up templates");
319                      
320                     
321                     
322                     var symbols = this.symbolSet.values();
323                     
324                     var files = this.packer.files;
325                     
326                     for (var i = 0, l = files.size; i < l; i++) {
327                         var file = files.get(i);
328                        // var targetDir = PackerRun.singleton().opt_doc_target + "/symbols/src/";
329                         this.makeSrcFile(file);
330                     }
331                     //print(JSON.stringify(symbols,null,4));
332                     var classes = new Gee.ArrayList<Symbol>();
333                     
334                     foreach(var symbol in symbols) {
335                                 if (symbol.isaClass()) { 
336                                         classes.add(symbol);
337                                 }
338                     }    
339                     classes.sort( (a,b) => {
340                                 return a.alias.collate(b.alias); 
341                         });
342                      
343                      //GLib.debug("classTemplate Process : all classes");
344                         
345                    // var classesIndex = classesTemplate.process(classes); // kept in memory
346                     
347                     GLib.debug("iterate classes");
348                    
349                     var jsonAll = new Json.Object(); 
350                     
351                     for (var i = 0, l = classes.size; i < l; i++) {
352                         var symbol = classes.get(i);
353                         var output = "";
354                         
355                         GLib.debug("classTemplate Process : %s" , symbol.alias);
356                         
357                         
358                         var   class_gen = new Json.Generator ();
359                             var  class_root = new Json.Node(Json.NodeType.OBJECT);
360                                 class_root.init_object(this.class_to_json(symbol));
361                                 class_gen.set_root (class_root);
362                                 class_gen.pretty=  true;
363                                 class_gen.indent = 2;
364                                 GLib.warning("writing JSON:  %s", PackerRun.singleton().opt_doc_target+"/symbols/" +symbol.alias+".json");
365                                 this.writeJson(class_gen, PackerRun.singleton().opt_doc_target+"/symbols/" +symbol.alias+".json");
366                         
367                         jsonAll.set_object_member(symbol.alias,  this.publishJSON(symbol));
368
369                     }
370                     
371                     // outptu class truee
372                     
373                     var   class_tree_gen = new Json.Generator ();
374             var  class_tree_root = new Json.Node(Json.NodeType.ARRAY);
375                         class_tree_root.init_array(this.class_tree(classes));
376                         class_tree_gen.set_root (class_tree_root);
377                         class_tree_gen.pretty=  true;
378                         class_tree_gen.indent = 2;
379                         GLib.warning("writing JSON:  %s", PackerRun.singleton().opt_doc_target+"/tree.json");
380                         this.writeJson(class_tree_gen,PackerRun.singleton().opt_doc_target+"/tree.json");
381                         size_t class_tree_l;
382                         //GLib.debug("JSON: %s", class_tree_gen.to_data(out class_tree_l));
383                     
384                     
385                     
386                     /*---- this is our 'builder' json file.. -- a full list of objects+functions */
387                     
388                     
389                     var   generator = new Json.Generator ();
390             var  root = new Json.Node(Json.NodeType.OBJECT);
391                         root.init_object(jsonAll);
392                         generator.set_root (root);
393                         generator.pretty=  true;
394                         generator.indent = 2;
395                         GLib.warning("writing JSON:  %s", PackerRun.singleton().opt_doc_target+"/json/roodata.json");
396                         
397                         
398                         this.writeJson(generator,PackerRun.singleton().opt_doc_target+"/json/roodata.json");
399                         size_t l;
400                         //GLib.debug("JSON: %s", generator.to_data(out l));
401                     
402                     
403                      
404                     
405                     GLib.debug("build index");
406                    
407                     
408                     
409                 }
410                 
411                 Json.Object class_to_json (Symbol cls)
412                 {
413                         var ret = new Json.Object();
414                         ret.set_string_member("name", cls.alias);
415                         var ag = new Json.Array();
416                         ret.set_array_member("augments", ag);                   
417                         for(var ii = 0, il = cls.augments.size; ii < il; ii++) {
418                   var contributer = this.symbolSet.getSymbol(cls.augments[ii]);
419                   if (contributer == null) {
420                         continue;
421                         }
422                   ag.add_string_element(contributer.alias);
423             }
424             ret.set_string_member("name", cls.alias);  
425             ret.set_string_member("desc", cls.desc);
426                 ret.set_boolean_member("isSingleton", cls.comment.getTag(DocTagTitle.SINGLETON).size > 0);
427                 ret.set_boolean_member("isStatic", cls.isa != "CONSTRUCTOR");
428                 ret.set_boolean_member("isBuiltin", cls.isBuiltin());
429                 
430                 // needded so that the class can fake a ctor..
431             ret.set_string_member("memberOf", cls.name);
432                         ret.set_string_member("example", cls.comment.getTagAsString(DocTagTitle.EXAMPLE));
433                     ret.set_string_member("deprecated", // as depricated is used as a flag...
434                                         cls.comment.getTag(DocTagTitle.DEPRECATED).size > 0 ? 
435                                         "This has been deprecated: "+  cls.comment.getTagAsString(DocTagTitle.DEPRECATED) : 
436                                 "");
437                 ret.set_string_member("since", cls.comment.getTagAsString(DocTagTitle.SINCE));
438                 ret.set_string_member("see", cls.comment.getTagAsString(DocTagTitle.SINCE));
439                         // not supported or used yet?
440                         //add.set_string_member("exceptions", m.comment.getTagAsString(DocTagTitle.EXCEPTIONS));
441                         //add.set_string_member("requires", m.comment.getTagAsString(DocTagTitle.REQUIRES));
442                 ret.set_array_member("params", cls.paramsToJson());
443                 ret.set_array_member("returns", new Json.Array()); 
444                                 
445                         //ret.set_string_member("desc", cls.comment.getTagAsString(DocTagTitle.DESC));
446                 /// fixme - @see ... any others..
447                         
448                         var props = new Json.Array(); 
449                         ret.set_array_member("config", props);
450                         var cfgProperties = cls.configToArray();
451                         for(var i =0; i < cfgProperties.size;i++) {
452                         var p = cfgProperties.get(i);
453                         var add = new Json.Object();
454                         add.set_string_member("name",p.name);
455                         add.set_string_member("type",p.type);
456                         add.set_string_member("desc",p.desc);
457                         add.set_string_member("memberOf",  p.memberOf);
458                         add.set_array_member("optvals",p.optvalues.size > 0 ? p.optvalue_as_json_array() : new Json.Array());
459                         props.add_object_element(add );
460                     }
461                      
462                     // methods
463
464                          
465                         var methods = new Json.Array();
466                         ret.set_array_member("methods", methods);                    
467                     foreach(var m in cls.methods) {
468                         if (m.isEvent || m.isIgnored) {
469                                 continue;
470                         }
471                         
472                         var add = new Json.Object();
473                         add.set_string_member("name",m.name);
474                         //add.set_string_member("type","function");
475                         add.set_string_member("desc",m.desc);
476                         //add.set_string_member("sig", m.makeMethodSkel());
477                         add.set_boolean_member("isStatic", m.isStatic);
478                         add.set_boolean_member("isConstructor", m.isa == "CONSTRUCTOR");
479                         add.set_boolean_member("isPrivate", m.isPrivate);
480                         //add.set_string_member("instanceOf", m.comment.getTagAsString(DocTagTitle.INSTANCEOF));
481                         add.set_string_member("memberOf", m.memberOf);
482                         add.set_string_member("example", m.comment.getTagAsString(DocTagTitle.EXAMPLE));
483                         add.set_string_member("deprecated", // as depricated is used as a flag...
484                                         m.comment.getTag(DocTagTitle.DEPRECATED).size > 0 ? 
485                                         "This has been deprecated: "+  m.comment.getTagAsString(DocTagTitle.DEPRECATED) : 
486                                         "");
487                         add.set_string_member("since", m.comment.getTagAsString(DocTagTitle.SINCE));
488                         add.set_string_member("see", m.comment.getTagAsString(DocTagTitle.SINCE));
489                         // not supported or used yet?
490                         //add.set_string_member("exceptions", m.comment.getTagAsString(DocTagTitle.EXCEPTIONS));
491                         //add.set_string_member("requires", m.comment.getTagAsString(DocTagTitle.REQUIRES));
492                         add.set_array_member("params", m.paramsToJson());
493                         add.set_array_member("returns", m.returnsToJson());
494                         
495                         /// fixme - @see ... any others..
496                           
497                         
498                         methods.add_object_element(add);
499                     }
500                     
501                     
502                         var events = new Json.Array();
503                         ret.set_array_member("events", events);              
504                     foreach(var m in cls.methods) {
505                         if (!m.isEvent || m.isIgnored) {
506                                 continue;
507                         }
508                         
509                         var add = new Json.Object();
510                         add.set_string_member("name",m.name.substring(1)); // all prefixed with '*'...
511                         //add.set_string_member("type","function");
512                         add.set_string_member("desc",m.desc);
513                         //add.set_string_member("sig", m.makeMethodSkel());
514
515                         add.set_string_member("memberOf", m.memberOf);
516                         add.set_string_member("example", m.comment.getTagAsString(DocTagTitle.EXAMPLE));
517                         add.set_string_member("deprecated", // as depricated is used as a flag...
518                                         m.comment.getTag(DocTagTitle.DEPRECATED).size > 0 ? 
519                                         "This has been deprecated: "+  m.comment.getTagAsString(DocTagTitle.DEPRECATED) : 
520                                         "");
521                         add.set_string_member("since", m.comment.getTagAsString(DocTagTitle.SINCE));
522                         add.set_string_member("see", m.comment.getTagAsString(DocTagTitle.SINCE));
523                         // not supported or used yet?
524                         //add.set_string_member("exceptions", m.comment.getTagAsString(DocTagTitle.EXCEPTIONS));
525                         //add.set_string_member("requires", m.comment.getTagAsString(DocTagTitle.REQUIRES));
526                         
527                         add.set_array_member("params", m.paramsToJson());
528                         add.set_array_member("returns", m.returnsToJson());
529                         
530                         /// fixme - @see ... any others..
531                           
532                         
533                         events.add_object_element(add);
534                     }
535                     
536                         
537                         
538                 
539                         return ret;
540                 }
541                 /**
542                 * needed as Json dumps .xXXX into same directory as it writes...
543                 */
544                 void writeJson(Json.Generator g, string fname)
545                 {
546                                 var tmp = this.tempdir + GLib.Path.get_basename(fname);
547                                 g.to_file(tmp);
548                                 
549                                 if (GLib.FileUtils.test(fname, GLib.FileTest.EXISTS)) {
550                                         string new_data, old_data;
551                                         FileUtils.get_contents(tmp, out new_data);
552                                         FileUtils.get_contents(fname, out old_data);
553                                         if (old_data == new_data) {
554                                                 GLib.File.new_for_path(tmp).delete();
555                                                 return;
556                                         }
557                            }
558                                 
559                         GLib.File.new_for_path(tmp).move( File.new_for_path(fname), GLib.FileCopyFlags.OVERWRITE);
560                       
561                 }
562                 
563                 /**
564                  * JSON files are lookup files for the documentation
565                  * - can be used by IDE's or AJAX based doc tools
566                  * 
567                  * 
568                  */
569                 Json.Object publishJSON (Symbol data)
570                 {
571                     // what we need to output to be usefull...
572                     // a) props..
573                     var cfgProperties = new Gee.ArrayList<DocTag>();
574                     if (data.comment.getTag(DocTagTitle.SINGLETON).size < 1) {
575                          cfgProperties = data.configToArray();
576                          cfgProperties.sort((a,b) =>{
577                                 return a.name.collate(b.name);
578                         }); 
579                         
580                     } 
581                     
582                     var props = new Json.Array(); 
583                     //println(cfgProperties.toSource());
584                     
585                     for(var i =0; i < cfgProperties.size;i++) {
586                         var p = cfgProperties.get(i);
587                         var add = new Json.Object();
588                         add.set_string_member("name",p.name);
589                         add.set_string_member("type",p.type);
590                         add.set_string_member("desc",p.desc);
591                         add.set_string_member("memberOf", p.memberOf == data.alias ? "" : p.memberOf);
592                             
593                         if (p.optvalues.size > 0) {
594                              add.set_array_member("optvals",p.optvalue_as_json_array());
595                         }
596                         
597                         props.add_object_element(add );
598                     }
599                     
600                     ///// --- events
601                     var ownEvents = new Gee.ArrayList<Symbol>();
602                     for(var i =0; i < data.methods.size;i++) {
603                                 var e = data.methods.get(i);
604                                 if (e.isEvent && !e.isIgnored) {
605                                         ownEvents.add(e);
606                                 }
607                         }; 
608                         ownEvents.sort((a,b) => {
609                                 return a.name.collate(b.name);
610                         });
611                     
612                     var events = new Json.Array();
613                      
614                     for(var i =0; i < ownEvents.size;i++) {
615                         var m = ownEvents.get(i);
616                         var add = new Json.Object();
617                         add.set_string_member("name",m.name.substring(1,-1)); // remove'*' on events..
618                         add.set_string_member("type","function");
619                         add.set_string_member("desc",m.desc);
620                         add.set_string_member("sig", m.makeFuncSkel());
621                         add.set_string_member("memberOf", m.memberOf == data.alias ? "" : m.memberOf);                  
622                         events.add_object_element(add);
623                     } 
624                      
625                     // methods
626                     var ownMethods = new Gee.ArrayList<Symbol>();
627                     for(var i =0; i < data.methods.size;i++) {
628                                 var e = data.methods.get(i);
629                                 if (!e.isEvent && !e.isIgnored) {
630                                         ownMethods.add(e);
631                                 }
632                         };
633                         ownMethods.sort((a,b) => {
634                                 return a.name.collate(b.name);
635                         });
636                     
637                         var methods = new Json.Array();
638                      
639                     for(var i =0; i < ownMethods.size;i++) {
640                         var m = ownMethods.get(i);
641                         var add = new Json.Object();
642                         add.set_string_member("name",m.name);
643                         add.set_string_member("type","function");
644                         add.set_string_member("desc",m.desc);
645                         add.set_string_member("sig", m.makeMethodSkel());
646                         add.set_boolean_member("static", m.isStatic);
647                         add.set_string_member("memberOf", m.memberOf == data.alias ? "" : m.memberOf);  
648                         methods.add_object_element(add);
649                     }
650                      
651                     //println(props.toSource());
652                     // we need to output:
653                     //classname => {
654                     //    propname => 
655                     //        type=>
656                     //        desc=>
657                     //    }
658                         var ret =  new Json.Object();
659                         ret.set_array_member("props", props);
660                         ret.set_array_member("events", events);
661                         ret.set_array_member("methods", methods);
662                 
663                     return ret;
664                     
665                     
666                     // b) methods
667                     // c) events
668                     
669                     
670                 }
671                 Gee.HashMap<string,Json.Object> class_tree_map;
672                 Json.Array class_tree_top;
673                 
674                 Json.Object? class_tree_new_obj(string name, bool is_class, out bool is_new) 
675                 {
676                 if (this.class_tree_map.has_key(name)) {
677                         var ret = this.class_tree_map.get(name);
678                         if (!ret.get_boolean_member("is_class") && is_class) {
679                                 ret.set_boolean_member("is_class", is_class);
680                         }
681                         is_new = false;
682                         return ret; // no need to do anything
683                 
684                 }
685                 
686                 GLib.debug("Class Tree: new object %s", name);
687                 var add =  new Json.Object();
688                 add.set_string_member("name", name);
689                 add.set_array_member("cn", new Json.Array());
690                 add.set_boolean_member("is_class", is_class);
691                 this.class_tree_map.set(name, add);
692                 var bits = name.split(".");
693                 if (bits.length == 1) {
694                         // top level..
695                         this.class_tree_top.add_object_element(add);
696                          
697                 } 
698                 is_new = true;
699                 
700                         return add;
701                 
702                 }
703                 
704                 void class_tree_make_parents(  Json.Object add)
705                 {
706                         var name = add.get_string_member("name");
707                         var bits = name.split(".");
708                 if (bits.length < 2) {
709                         return;
710                 }
711                 // got aaa.bb or aaa.bb.cc
712                 // find the parent..
713                 string[] nn = {};
714                 for(var i=0; i < bits.length-1; i++) {
715                         nn += bits[i];
716                 }
717                 var pname = string.joinv(".", nn);
718                 GLib.debug("Class Tree: adding to parent %s => %s", name, pname); 
719                          
720                         // no parent found.. make one..
721                         bool is_new;
722                         var parent = this.class_tree_new_obj(pname, false, out is_new); 
723                         parent.get_array_member("cn").add_object_element(add);
724                         if (is_new) {
725                                 this.class_tree_make_parents(  parent);
726                         }
727                 
728                 
729                 }
730                 Json.Array class_tree (Gee.ArrayList<Symbol> classes )
731                 {
732                 
733                 
734                     // produce a tree array that can be used to render the navigation.
735                     /*
736                     should produce:
737                     
738                     [
739                         {
740                                 name : Roo,
741                                 desc : ....
742                                 is_class : true,
743                                 cn : [
744                                         {
745                                                 name : 'Roo.util',
746                                                 basename : 'util',
747                                                 is_class : false,
748                                                 cn : [
749                                                         {
750                                                                 ....
751                     
752                     to do this, we will need to create the objects in a hashmap
753                     Roo.util => Json.Object
754                     
755                     */
756                     this.class_tree_top = new Json.Array();
757                     this.class_tree_map = new Gee.HashMap<string,Json.Object>();
758                     foreach (var cls in classes) {
759                         if(cls.alias.length < 1 || cls.alias == "this" || cls.alias == "_global_") {
760                                 continue;
761                         }
762                         bool is_new;
763                         var add =  this.class_tree_new_obj(cls.alias, cls.methods.size > 0 ? true : false,out is_new);
764                                 if (add != null) {
765                                         this.class_tree_make_parents( add);
766                                 }
767                         
768                     }
769                     
770                      return this.class_tree_top;
771                     
772                 }
773                 
774                 
775                 // in Link (js) ???
776                 string srcFileRelName(string sourceFile)
777                 {
778                         var rp = Posix.realpath(sourceFile);
779                         return rp.substring(PackerRun.singleton().opt_real_basedir.length);
780                 }
781                 string srcFileFlatName(string sourceFile)
782                 {
783                     var name = this.srcFileRelName(sourceFile);
784                     name = /\.\.?[\/]/.replace(name, name.length, 0, "");
785                     name = name.replace("/", "_").replace(":", "_") + ".html";
786                     return name;
787                 }
788                 
789                 
790                 void makeSrcFile(string sourceFile) 
791                 {
792                     // this stuff works...
793                     
794                    
795                     
796                         // this check does not appear to work according to the doc's - need to check it out.
797                
798                   
799                     var name = this.srcFileFlatName(sourceFile);
800                     
801                     GLib.debug("Write Source file : %s/src/%s", 
802                 PackerRun.singleton().opt_doc_target, name);
803                 var str = "";
804                 FileUtils.get_contents(sourceFile, out str);
805                     var pretty = PrettyPrint.toPretty(str); 
806                      var fname = PackerRun.singleton().opt_doc_target+"/src/" + name;
807                     
808                     var tmp = this.tempdir + GLib.Path.get_basename(fname);
809                     FileUtils.set_contents(
810                         tmp, 
811                         "<html><head>" +
812                         "<title>" + this.srcFileRelName(sourceFile) + "</title>" +
813                         "<link rel=\"stylesheet\" type=\"text/css\" href=\"../../css/highlight-js.css\"/>" + 
814                         "</head><body class=\"highlightpage\">" +
815                         pretty +
816                         "</body></html>");
817                         
818                     // same content?
819                      if (GLib.FileUtils.test(fname, GLib.FileTest.EXISTS)) {
820                                 string new_data, old_data;
821                                 FileUtils.get_contents(tmp, out new_data);
822                                 FileUtils.get_contents(fname, out old_data);
823                                 if (old_data == new_data) {
824                                         GLib.File.new_for_path(tmp).delete();
825                                         return;
826                                 }
827                      }
828                         
829                 GLib.File.new_for_path(tmp).move( File.new_for_path(fname), GLib.FileCopyFlags.OVERWRITE);
830                       
831                     
832                     
833
834                 }
835         }
836                  
837 }
838   
839
840
841
842
843
844  
845
846
847
848