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.isa != "CONSTRUCTOR");
379 ret.set_boolean_member("isBuiltin", cls.isBuiltin());
381 // needded so that the class can fake a ctor..
382 ret.set_string_member("memberOf", cls.name);
383 ret.set_string_member("example", cls.comment.getTagAsString(DocTagTitle.EXAMPLE));
384 ret.set_string_member("deprecated", // as depricated is used as a flag...
385 cls.comment.getTag(DocTagTitle.DEPRECATED).size > 0 ?
386 "This has been deprecated: "+ cls.comment.getTagAsString(DocTagTitle.DEPRECATED) :
388 ret.set_string_member("since", cls.comment.getTagAsString(DocTagTitle.SINCE));
389 ret.set_string_member("see", cls.comment.getTagAsString(DocTagTitle.SINCE));
390 // not supported or used yet?
391 //add.set_string_member("exceptions", m.comment.getTagAsString(DocTagTitle.EXCEPTIONS));
392 //add.set_string_member("requires", m.comment.getTagAsString(DocTagTitle.REQUIRES));
393 ret.set_array_member("params", cls.paramsToJson());
394 ret.set_array_member("returns", new Json.Array());
396 //ret.set_string_member("desc", cls.comment.getTagAsString(DocTagTitle.DESC));
397 /// fixme - @see ... any others..
399 var props = new Json.Array();
400 ret.set_array_member("config", props);
401 var cfgProperties = cls.configToArray();
402 for(var i =0; i < cfgProperties.size;i++) {
403 var p = cfgProperties.get(i);
404 var add = new Json.Object();
405 add.set_string_member("name",p.name);
406 add.set_string_member("type",p.type);
407 add.set_string_member("desc",p.desc);
408 add.set_string_member("memberOf", p.memberOf);
409 add.set_array_member("values",p.optvalues.size > 0 ? p.optvalue_as_json_array() : new Json.Array());
410 props.add_object_element(add );
416 var methods = new Json.Array();
417 ret.set_array_member("methods", methods);
418 foreach(var m in cls.methods) {
419 if (m.isEvent || m.isIgnored) {
423 var add = new Json.Object();
424 add.set_string_member("name",m.name);
425 //add.set_string_member("type","function");
426 add.set_string_member("desc",m.desc);
427 //add.set_string_member("sig", m.makeMethodSkel());
428 add.set_boolean_member("isStatic", m.isStatic);
429 add.set_boolean_member("isConstructor", m.isa == "CONSTRUCTOR");
430 add.set_boolean_member("isPrivate", m.isPrivate);
431 //add.set_string_member("instanceOf", m.comment.getTagAsString(DocTagTitle.INSTANCEOF));
432 add.set_string_member("memberOf", m.memberOf);
433 add.set_string_member("example", m.comment.getTagAsString(DocTagTitle.EXAMPLE));
434 add.set_string_member("deprecated", // as depricated is used as a flag...
435 m.comment.getTag(DocTagTitle.DEPRECATED).size > 0 ?
436 "This has been deprecated: "+ m.comment.getTagAsString(DocTagTitle.DEPRECATED) :
438 add.set_string_member("since", m.comment.getTagAsString(DocTagTitle.SINCE));
439 add.set_string_member("see", m.comment.getTagAsString(DocTagTitle.SINCE));
440 // not supported or used yet?
441 //add.set_string_member("exceptions", m.comment.getTagAsString(DocTagTitle.EXCEPTIONS));
442 //add.set_string_member("requires", m.comment.getTagAsString(DocTagTitle.REQUIRES));
443 add.set_array_member("params", m.paramsToJson());
444 add.set_array_member("returns", m.returnsToJson());
446 /// fixme - @see ... any others..
449 methods.add_object_element(add);
453 var events = new Json.Array();
454 ret.set_array_member("events", events);
455 foreach(var m in cls.methods) {
456 if (!m.isEvent || m.isIgnored) {
460 var add = new Json.Object();
461 add.set_string_member("name",m.name.substring(1)); // all prefixed with '*'...
462 //add.set_string_member("type","function");
463 add.set_string_member("desc",m.desc);
464 //add.set_string_member("sig", m.makeMethodSkel());
466 add.set_string_member("memberOf", m.memberOf == cls.alias ? "" : m.memberOf);
467 add.set_string_member("example", m.comment.getTagAsString(DocTagTitle.EXAMPLE));
468 add.set_string_member("deprecated", // as depricated is used as a flag...
469 m.comment.getTag(DocTagTitle.DEPRECATED).size > 0 ?
470 "This has been deprecated: "+ m.comment.getTagAsString(DocTagTitle.DEPRECATED) :
472 add.set_string_member("since", m.comment.getTagAsString(DocTagTitle.SINCE));
473 add.set_string_member("see", m.comment.getTagAsString(DocTagTitle.SINCE));
474 // not supported or used yet?
475 //add.set_string_member("exceptions", m.comment.getTagAsString(DocTagTitle.EXCEPTIONS));
476 //add.set_string_member("requires", m.comment.getTagAsString(DocTagTitle.REQUIRES));
478 add.set_array_member("params", m.paramsToJson());
479 add.set_array_member("returns", m.returnsToJson());
481 /// fixme - @see ... any others..
484 events.add_object_element(add);
493 * JSON files are lookup files for the documentation
494 * - can be used by IDE's or AJAX based doc tools
498 Json.Object publishJSON (Symbol data)
500 // what we need to output to be usefull...
502 var cfgProperties = new Gee.ArrayList<DocTag>();
503 if (data.comment.getTag(DocTagTitle.SINGLETON).size < 1) {
504 cfgProperties = data.configToArray();
505 cfgProperties.sort((a,b) =>{
506 return a.name.collate(b.name);
511 var props = new Json.Array();
512 //println(cfgProperties.toSource());
514 for(var i =0; i < cfgProperties.size;i++) {
515 var p = cfgProperties.get(i);
516 var add = new Json.Object();
517 add.set_string_member("name",p.name);
518 add.set_string_member("type",p.type);
519 add.set_string_member("desc",p.desc);
520 add.set_string_member("memberOf", p.memberOf == data.alias ? "" : p.memberOf);
522 if (p.optvalues.size > 0) {
523 add.set_array_member("desc",p.optvalue_as_json_array());
526 props.add_object_element(add );
530 var ownEvents = new Gee.ArrayList<Symbol>();
531 for(var i =0; i < data.methods.size;i++) {
532 var e = data.methods.get(i);
533 if (e.isEvent && !e.isIgnored) {
537 ownEvents.sort((a,b) => {
538 return a.name.collate(b.name);
541 var events = new Json.Array();
543 for(var i =0; i < ownEvents.size;i++) {
544 var m = ownEvents.get(i);
545 var add = new Json.Object();
546 add.set_string_member("name",m.name.substring(1,-1)); // remove'*' on events..
547 add.set_string_member("type","function");
548 add.set_string_member("desc",m.desc);
549 add.set_string_member("sig", m.makeFuncSkel());
550 add.set_string_member("memberOf", m.memberOf == data.alias ? "" : m.memberOf);
551 events.add_object_element(add);
555 var ownMethods = new Gee.ArrayList<Symbol>();
556 for(var i =0; i < data.methods.size;i++) {
557 var e = data.methods.get(i);
558 if (!e.isEvent && !e.isIgnored) {
562 ownMethods.sort((a,b) => {
563 return a.name.collate(b.name);
566 var methods = new Json.Array();
568 for(var i =0; i < ownMethods.size;i++) {
569 var m = ownMethods.get(i);
570 var add = new Json.Object();
571 add.set_string_member("name",m.name);
572 add.set_string_member("type","function");
573 add.set_string_member("desc",m.desc);
574 add.set_string_member("sig", m.makeMethodSkel());
575 add.set_boolean_member("static", m.isStatic);
576 add.set_string_member("memberOf", m.memberOf == data.alias ? "" : m.memberOf);
577 methods.add_object_element(add);
580 //println(props.toSource());
581 // we need to output:
587 var ret = new Json.Object();
588 ret.set_array_member("props", props);
589 ret.set_array_member("events", events);
590 ret.set_array_member("methods", methods);
600 Gee.HashMap<string,Json.Object> class_tree_map;
601 Json.Array class_tree_top;
603 Json.Object? class_tree_new_obj(string name, bool is_class, out bool is_new)
605 if (this.class_tree_map.has_key(name)) {
606 var ret = this.class_tree_map.get(name);
607 if (!ret.get_boolean_member("is_class") && is_class) {
608 ret.set_boolean_member("is_class", is_class);
611 return ret; // no need to do anything
615 GLib.debug("Class Tree: new object %s", name);
616 var add = new Json.Object();
617 add.set_string_member("name", name);
618 add.set_array_member("cn", new Json.Array());
619 add.set_boolean_member("is_class", is_class);
620 this.class_tree_map.set(name, add);
621 var bits = name.split(".");
622 if (bits.length == 1) {
624 this.class_tree_top.add_object_element(add);
633 void class_tree_make_parents( Json.Object add)
635 var name = add.get_string_member("name");
636 var bits = name.split(".");
637 if (bits.length < 2) {
640 // got aaa.bb or aaa.bb.cc
643 for(var i=0; i < bits.length-1; i++) {
646 var pname = string.joinv(".", nn);
647 GLib.debug("Class Tree: adding to parent %s => %s", name, pname);
649 // no parent found.. make one..
651 var parent = this.class_tree_new_obj(pname, false, out is_new);
652 parent.get_array_member("cn").add_object_element(add);
654 this.class_tree_make_parents( parent);
659 Json.Array class_tree (Gee.ArrayList<Symbol> classes )
663 // produce a tree array that can be used to render the navigation.
681 to do this, we will need to create the objects in a hashmap
682 Roo.util => Json.Object
685 this.class_tree_top = new Json.Array();
686 this.class_tree_map = new Gee.HashMap<string,Json.Object>();
687 foreach (var cls in classes) {
688 if(cls.alias.length < 1 || cls.alias == "this" || cls.alias == "_global_") {
692 var add = this.class_tree_new_obj(cls.alias, cls.methods.size > 0 ? true : false,out is_new);
694 this.class_tree_make_parents( add);
699 return this.class_tree_top;
705 string srcFileRelName(string sourceFile)
707 var rp = Posix.realpath(sourceFile);
708 return rp.substring(PackerRun.singleton().opt_real_basedir.length);
710 string srcFileFlatName(string sourceFile)
712 var name = this.srcFileRelName(sourceFile);
713 name = /\.\.?[\/]/.replace(name, name.length, 0, "");
714 name = name.replace("/", "_").replace(":", "_") + ".html";
719 void makeSrcFile(string sourceFile)
721 // this stuff works...
723 var name = this.srcFileFlatName(sourceFile);
725 GLib.debug("Write Source file : %s/src/%s",
726 PackerRun.singleton().opt_doc_target, name);
728 FileUtils.get_contents(sourceFile, out str);
729 var pretty = PrettyPrint.toPretty(str);
730 FileUtils.set_contents(
731 PackerRun.singleton().opt_doc_target+"/src/" + name,
733 "<title>" + sourceFile + "</title>" +
734 "<link rel=\"stylesheet\" type=\"text/css\" href=\"../../css/highlight-js.css\"/>" +
735 "</head><body class=\"highlightpage\">" +