7 class DocBuilder : Object
11 // extractable via JSON?
12 public string VERSION = "1.0.0" ;
14 private SymbolSet symbolSet;
16 private Packer packer;
18 public DocBuilder (Packer p)
22 GLib.debug("Roo JsDoc Toolkit started at %s ", (new GLib.DateTime.now_local()).format("Y/m/d H:i:s"));
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);
33 this.symbolSet = DocParser.symbols();
35 // this currently uses the concept of publish.js...
45 * Parse the source files.
49 private void parseSrcFiles()
54 //var useCache = PackerRun.opt_cache_dir == null ;
57 for (var i = 0, l = this.packer.files.size; i < l; i++) {
59 var srcFile = this.packer.files.get(i);
60 GLib.debug("Parsing source File: %s", srcFile);
64 cacheFile = PackerRun.opt_cache_dir + srcFile.replace("/", '_') + ".cache";
67 // disabled at present!@!!
69 if (GLib.FileUtils.test(cacheFile, GLib.FileTest.EXISTS)) {
71 var cache_mt = File.new_for_path (cacheFile).queryInfo(FileAttribute.TIME_MODIFIED,
72 GLib.FileQueryInfoFlags.NONE, null).
73 get_modification_time();
74 var original_mt = File.new_for_path (sourceInfo).queryInfo(FileAttribute.TIME_MODIFIED,
75 GLib.FileQueryInfoFlags.NONE, null).
76 get_modification_time();
77 // this check does not appear to work according to the doc's - need to check it out.
79 if (cache_mt > original_mt) { // cached time > original time!
80 // use the cached mtimes..
81 GLib.debug("Read %s" , cacheFile);
82 var parser = new Json.Parser();
83 parser.load_from_file(cacheFile);
84 var ar = parser.get_root ().get_array();
86 for(var i = 0;i < ar.get_length();i++) {
87 var o = ar.get_object_element(i);
88 var sym = JSON.gobject_from_data(typeof(Symbol), o) as Symbol;
89 DocParser.symbols.add(sym);
98 GLib.debug("reading : %s" , srcFile);
99 GLib.FileUtils.get_contents(srcFile, out src);
101 catch(GLib.FileError e) {
102 GLib.debug("Can't read source file '%s': %s", srcFile, e.message);
108 var tr = new TokenReader(this.packer);
111 tr.keepComments = true;
112 tr.sepIdents = false;
113 tr.collapseWhite = false;
117 var toks = tr.tokenize( new TextStream(src) );
118 if (PackerRun.singleton().opt_dump_tokens) {
121 //GLib.Process.exit(0);
125 var ts = new TokenStream(toks.tokens);
130 DocParser.parse(ts, srcFile);
134 var ar = DocParser.symbolsToObject(srcFile);
136 var builder = new Json.Builder ();
137 builder.begin_array ();
138 for (var i=0;i<ar.size;i++) {
140 builder.add_object_value (ar.get(i));
142 builder.end_array ();
143 Json.Generator generator = new Json.Generator ();
144 Json.Node root = builder.get_root ();
145 generator.set_root (root);
146 generator.pretty= true;
148 generator.to_file(cacheFile);
164 var tr = new TokenReader(this.packer);
167 tr.keepComments = true;
168 tr.sepIdents = false;
169 tr.collapseWhite = false;
173 var toks = tr.tokenize( new TextStream(src));
174 if (PackerRun.opt_dump_tokens) {
177 //GLib.Process.exit(0);
181 var ts = new TokenStream(toks);
186 DocParser.parse(ts, srcFile);
190 var ar = DocParser.symbolsToObject(srcFile);
192 var builder = new Json.Builder ();
193 builder.begin_array ();
194 for (var i=0;i<ar.size;i++) {
196 builder.add_object_value (ar.get(i));
198 builder.end_array ();
199 Json.Generator generator = new Json.Generator ();
200 Json.Node root = builder.get_root ();
201 generator.set_root (root);
202 generator.pretty= true;
204 generator.to_file(cacheFile);
220 GLib.debug("Publishing");
225 GLib.debug("Making directories");
226 if (!FileUtils.test (PackerRun.singleton().opt_doc_target,FileTest.IS_DIR )) {
227 Posix.mkdir(PackerRun.singleton().opt_doc_target,0755);
229 if (!FileUtils.test(PackerRun.singleton().opt_doc_target+"/symbols",FileTest.IS_DIR)) {
230 Posix.mkdir(PackerRun.singleton().opt_doc_target+"/symbols",0755);
232 if (!FileUtils.test(PackerRun.singleton().opt_doc_target+"/src",FileTest.IS_DIR)) {
233 Posix.mkdir(PackerRun.singleton().opt_doc_target+"/src",0755);
235 if (!FileUtils.test(PackerRun.singleton().opt_doc_target +"/json",FileTest.IS_DIR)) {
236 Posix.mkdir(PackerRun.singleton().opt_doc_target +"/json",0755);
239 GLib.debug("Copying files from static: %s " , PackerRun.singleton().opt_doc_template_dir);
240 // copy everything in 'static' into
242 if (PackerRun.singleton().opt_doc_template_dir != null) {
244 var iter = GLib.File.new_for_path(
245 PackerRun.singleton().opt_doc_template_dir + "/static"
246 ).enumerate_children (
248 FileQueryInfoFlags.NOFOLLOW_SYMLINKS,
252 while ( (info = iter.next_file (null)) != null) {
253 if (info.get_file_type () == FileType.DIRECTORY) {
256 var src = File.new_for_path(info.get_name());
257 GLib.debug("Copy %s to %s/%s" ,
259 PackerRun.singleton().opt_doc_target , src.get_basename());
262 GLib.File.new_for_path(
263 PackerRun.singleton().opt_doc_target + "/" + src.get_basename()
265 GLib.FileCopyFlags.OVERWRITE
270 GLib.debug("Setting up templates");
274 var symbols = this.symbolSet.values();
276 var files = this.packer.files;
278 for (var i = 0, l = files.size; i < l; i++) {
279 var file = files.get(i);
280 // var targetDir = PackerRun.singleton().opt_doc_target + "/symbols/src/";
281 this.makeSrcFile(file);
283 //print(JSON.stringify(symbols,null,4));
284 var classes = new Gee.ArrayList<Symbol>();
286 foreach(var symbol in symbols) {
287 if (symbol.isaClass()) {
291 classes.sort( (a,b) => {
292 return a.alias.collate(b.alias);
295 //GLib.debug("classTemplate Process : all classes");
297 // var classesIndex = classesTemplate.process(classes); // kept in memory
299 GLib.debug("iterate classes");
301 var jsonAll = new Json.Object();
303 for (var i = 0, l = classes.size; i < l; i++) {
304 var symbol = classes.get(i);
307 GLib.debug("classTemplate Process : %s" , symbol.alias);
310 var class_gen = new Json.Generator ();
311 var class_root = new Json.Node(Json.NodeType.OBJECT);
312 class_root.init_object(this.class_to_json(symbol));
313 class_gen.set_root (class_root);
314 class_gen.pretty= true;
315 class_gen.indent = 2;
316 GLib.warning("writing JSON: %s", PackerRun.singleton().opt_doc_target+"/symbols/" +symbol.alias+".json");
317 class_gen.to_file(PackerRun.singleton().opt_doc_target+"/symbols/" +symbol.alias+".json");
320 jsonAll.set_object_member(symbol.alias, this.publishJSON(symbol));
324 // outptu class truee
326 var class_tree_gen = new Json.Generator ();
327 var class_tree_root = new Json.Node(Json.NodeType.ARRAY);
328 class_tree_root.init_array(this.class_tree(classes));
329 class_tree_gen.set_root (class_tree_root);
330 class_tree_gen.pretty= true;
331 class_tree_gen.indent = 2;
332 GLib.warning("writing JSON: %s", PackerRun.singleton().opt_doc_target+"/tree.json");
333 class_tree_gen.to_file(PackerRun.singleton().opt_doc_target+"/tree.json");
335 //GLib.debug("JSON: %s", class_tree_gen.to_data(out class_tree_l));
339 /*---- this is our 'builder' json file.. -- a full list of objects+functions */
342 var generator = new Json.Generator ();
343 var root = new Json.Node(Json.NodeType.OBJECT);
344 root.init_object(jsonAll);
345 generator.set_root (root);
346 generator.pretty= true;
347 generator.indent = 2;
348 GLib.warning("writing JSON: %s", PackerRun.singleton().opt_doc_target+"/json/roodata.json");
349 generator.to_file(PackerRun.singleton().opt_doc_target+"/json/roodata.json");
351 //GLib.debug("JSON: %s", generator.to_data(out l));
356 GLib.debug("build index");
362 Json.Object class_to_json (Symbol cls)
364 var ret = new Json.Object();
365 ret.set_string_member("name", cls.alias);
366 var ag = new Json.Array();
367 ret.set_array_member("augments", ag);
368 for(var ii = 0, il = cls.augments.size; ii < il; ii++) {
369 var contributer = this.symbolSet.getSymbol(cls.augments[ii]);
370 if (contributer == null) {
373 ag.add_string_element(contributer.alias);
375 ret.set_string_member("name", cls.alias);
376 ret.set_string_member("desc", cls.desc);
377 ret.set_boolean_member("isSingleton", cls.comment.getTag(DocTagTitle.SINGLETON).size > 0);
378 ret.set_boolean_member("isStatic", cls.isStatic);
379 ret.set_boolean_member("isBuiltin", cls.isBuiltin());
380 //ret.set_string_member("desc", cls.comment.getTagAsString(DocTagTitle.DESC));
381 /// fixme - @see ... any others..
383 var props = new Json.Array();
384 ret.set_array_member("config", props);
385 var cfgProperties = cls.configToArray();
386 for(var i =0; i < cfgProperties.size;i++) {
387 var p = cfgProperties.get(i);
388 var add = new Json.Object();
389 add.set_string_member("name",p.name);
390 add.set_string_member("type",p.type);
391 add.set_string_member("desc",p.desc);
392 add.set_string_member("memberOf", p.memberOf);
393 add.set_array_member("values",p.optvalues.size > 0 ? p.optvalue_as_json_array() : new Json.Array());
394 props.add_object_element(add );
400 var methods = new Json.Array();
401 ret.set_array_member("methods", methods);
402 foreach(var m in cls.methods) {
403 if (m.isEvent || m.isIgnored) {
407 var add = new Json.Object();
408 add.set_string_member("name",m.name);
409 //add.set_string_member("type","function");
410 add.set_string_member("desc",m.desc);
411 //add.set_string_member("sig", m.makeMethodSkel());
412 add.set_boolean_member("isStatic", m.isStatic);
413 add.set_boolean_member("isConstructor", m.isa == "CONSTRUCTOR");
414 add.set_boolean_member("isPrivate", m.isPrivate);
415 //add.set_string_member("instanceOf", m.comment.getTagAsString(DocTagTitle.INSTANCEOF));
416 add.set_string_member("memberOf", m.memberOf);
417 add.set_string_member("example", m.comment.getTagAsString(DocTagTitle.EXAMPLE));
418 add.set_string_member("deprecated", // as depricated is used as a flag...
419 m.comment.getTag(DocTagTitle.DEPRECATED).size > 0 ?
420 "This has been deprecated: "+ m.comment.getTagAsString(DocTagTitle.DEPRECATED) :
422 add.set_string_member("since", m.comment.getTagAsString(DocTagTitle.SINCE));
423 add.set_string_member("see", m.comment.getTagAsString(DocTagTitle.SINCE));
424 // not supported or used yet?
425 //add.set_string_member("exceptions", m.comment.getTagAsString(DocTagTitle.EXCEPTIONS));
426 //add.set_string_member("requires", m.comment.getTagAsString(DocTagTitle.REQUIRES));
427 add.set_array_member("params", m.paramsToJson());
428 add.set_array_member("returns", m.returnsToJson());
430 /// fixme - @see ... any others..
433 methods.add_object_element(add);
437 var events = new Json.Array();
438 ret.set_array_member("events", events);
439 foreach(var m in cls.methods) {
440 if (!m.isEvent || m.isIgnored) {
444 var add = new Json.Object();
445 add.set_string_member("name",m.name.substring(1)); // all prefixed with '*'...
446 //add.set_string_member("type","function");
447 add.set_string_member("desc",m.desc);
448 //add.set_string_member("sig", m.makeMethodSkel());
450 add.set_string_member("memberOf", m.memberOf == cls.alias ? "" : m.memberOf);
451 add.set_string_member("example", m.comment.getTagAsString(DocTagTitle.EXAMPLE));
452 add.set_string_member("deprecated", // as depricated is used as a flag...
453 m.comment.getTag(DocTagTitle.DEPRECATED).size > 0 ?
454 "This has been deprecated: "+ m.comment.getTagAsString(DocTagTitle.DEPRECATED) :
456 add.set_string_member("since", m.comment.getTagAsString(DocTagTitle.SINCE));
457 add.set_string_member("see", m.comment.getTagAsString(DocTagTitle.SINCE));
458 // not supported or used yet?
459 //add.set_string_member("exceptions", m.comment.getTagAsString(DocTagTitle.EXCEPTIONS));
460 //add.set_string_member("requires", m.comment.getTagAsString(DocTagTitle.REQUIRES));
462 add.set_array_member("params", m.paramsToJson());
463 add.set_array_member("returns", m.returnsToJson());
465 /// fixme - @see ... any others..
468 events.add_object_element(add);
477 * JSON files are lookup files for the documentation
478 * - can be used by IDE's or AJAX based doc tools
482 Json.Object publishJSON (Symbol data)
484 // what we need to output to be usefull...
486 var cfgProperties = new Gee.ArrayList<DocTag>();
487 if (data.comment.getTag(DocTagTitle.SINGLETON).size < 1) {
488 cfgProperties = data.configToArray();
489 cfgProperties.sort((a,b) =>{
490 return a.name.collate(b.name);
495 var props = new Json.Array();
496 //println(cfgProperties.toSource());
498 for(var i =0; i < cfgProperties.size;i++) {
499 var p = cfgProperties.get(i);
500 var add = new Json.Object();
501 add.set_string_member("name",p.name);
502 add.set_string_member("type",p.type);
503 add.set_string_member("desc",p.desc);
504 add.set_string_member("memberOf", p.memberOf == data.alias ? "" : p.memberOf);
506 if (p.optvalues.size > 0) {
507 add.set_array_member("desc",p.optvalue_as_json_array());
510 props.add_object_element(add );
514 var ownEvents = new Gee.ArrayList<Symbol>();
515 for(var i =0; i < data.methods.size;i++) {
516 var e = data.methods.get(i);
517 if (e.isEvent && !e.isIgnored) {
521 ownEvents.sort((a,b) => {
522 return a.name.collate(b.name);
525 var events = new Json.Array();
527 for(var i =0; i < ownEvents.size;i++) {
528 var m = ownEvents.get(i);
529 var add = new Json.Object();
530 add.set_string_member("name",m.name.substring(1,-1)); // remove'*' on events..
531 add.set_string_member("type","function");
532 add.set_string_member("desc",m.desc);
533 add.set_string_member("sig", m.makeFuncSkel());
534 add.set_string_member("memberOf", m.memberOf == data.alias ? "" : m.memberOf);
535 events.add_object_element(add);
539 var ownMethods = new Gee.ArrayList<Symbol>();
540 for(var i =0; i < data.methods.size;i++) {
541 var e = data.methods.get(i);
542 if (!e.isEvent && !e.isIgnored) {
546 ownMethods.sort((a,b) => {
547 return a.name.collate(b.name);
550 var methods = new Json.Array();
552 for(var i =0; i < ownMethods.size;i++) {
553 var m = ownMethods.get(i);
554 var add = new Json.Object();
555 add.set_string_member("name",m.name);
556 add.set_string_member("type","function");
557 add.set_string_member("desc",m.desc);
558 add.set_string_member("sig", m.makeMethodSkel());
559 add.set_boolean_member("static", m.isStatic);
560 add.set_string_member("memberOf", m.memberOf == data.alias ? "" : m.memberOf);
561 methods.add_object_element(add);
564 //println(props.toSource());
565 // we need to output:
571 var ret = new Json.Object();
572 ret.set_array_member("props", props);
573 ret.set_array_member("events", events);
574 ret.set_array_member("methods", methods);
584 Gee.HashMap<string,Json.Object> class_tree_map;
585 Json.Array class_tree_top;
587 Json.Object? class_tree_new_obj(string name, bool is_class, out bool is_new)
589 if (this.class_tree_map.has_key(name)) {
590 var ret = this.class_tree_map.get(name);
591 if (!ret.get_boolean_member("is_class") && is_class) {
592 ret.set_boolean_member("is_class", is_class);
595 return ret; // no need to do anything
599 GLib.debug("Class Tree: new object %s", name);
600 var add = new Json.Object();
601 add.set_string_member("name", name);
602 add.set_array_member("cn", new Json.Array());
603 add.set_boolean_member("is_class", is_class);
604 this.class_tree_map.set(name, add);
605 var bits = name.split(".");
606 if (bits.length == 1) {
608 this.class_tree_top.add_object_element(add);
617 void class_tree_make_parents( Json.Object add)
619 var name = add.get_string_member("name");
620 var bits = name.split(".");
621 if (bits.length < 2) {
624 // got aaa.bb or aaa.bb.cc
627 for(var i=0; i < bits.length-1; i++) {
630 var pname = string.joinv(".", nn);
631 GLib.debug("Class Tree: adding to parent %s => %s", name, pname);
633 // no parent found.. make one..
635 var parent = this.class_tree_new_obj(pname, false, out is_new);
636 parent.get_array_member("cn").add_object_element(add);
638 this.class_tree_make_parents( parent);
643 Json.Array class_tree (Gee.ArrayList<Symbol> classes )
647 // produce a tree array that can be used to render the navigation.
665 to do this, we will need to create the objects in a hashmap
666 Roo.util => Json.Object
669 this.class_tree_top = new Json.Array();
670 this.class_tree_map = new Gee.HashMap<string,Json.Object>();
671 foreach (var cls in classes) {
672 if(cls.alias.length < 1 || cls.alias == "this" || cls.alias == "_global_") {
676 var add = this.class_tree_new_obj(cls.alias, cls.methods.size > 0 ? true : false,out is_new);
678 this.class_tree_make_parents( add);
683 return this.class_tree_top;
689 string srcFileRelName(string sourceFile)
691 var rp = Posix.realpath(sourceFile);
692 return rp.substring(PackerRun.singleton().opt_real_basedir.length);
694 string srcFileFlatName(string sourceFile)
696 var name = this.srcFileRelName(sourceFile);
697 name = /\.\.?[\/]/.replace(name, name.length, 0, "");
698 name = name.replace("/", "_").replace(":", "_") + ".html";
703 void makeSrcFile(string sourceFile)
705 // this stuff works...
707 var name = this.srcFileFlatName(sourceFile);
709 GLib.debug("Write Source file : %s/src/%s",
710 PackerRun.singleton().opt_doc_target, name);
712 FileUtils.get_contents(sourceFile, out str);
713 var pretty = PrettyPrint.toPretty(str);
714 FileUtils.set_contents(
715 PackerRun.singleton().opt_doc_target+"/src/" + name,
717 "<title>" + sourceFile + "</title>" +
718 "<link rel=\"stylesheet\" type=\"text/css\" href=\"../../css/highlight-js.css\"/>" +
719 "</head><body class=\"highlightpage\">" +