1 //<script type="text/javascript">
4 * This is the main container for the JSDOC application.
8 BuildDocs = imports.JSDOC.BuildDocs.BuildDocs
16 new ArgsParser(argv, imports.BuildDocs.BuildDocs )
24 XObject = imports.XObject.XObject;
25 File = imports.File.File;
29 Template = imports.JsTemplate.Template.Template;
30 Link = imports.JsTemplate.Link.Link; // ?? fixme!??
39 * Main class used to build documentation
41 BuildDocs = XObject.define(
43 XObject.extend(this, opts); // overlay cfg..
46 this.LOG = imports.JSDOC.Log.Log;
49 imports.SymbolSet.SymbolSet.LOG = this.LOG
50 /*this.parser = new imports.JSDOC.Parser.Parser({
52 docPrivate : this.docPrivate
66 * @cfg {Object} LOG an implementation of the log interface..
71 * @cfg {String} baseDir root directory (for relative publishing?)
77 * @cfg {String} cacheDirectory where to store the cached parse.
79 cacheDirectory: false,
82 * @cfg {String} ext comma-delimited list of extensions to handle..
87 * @cfg {String} lang Language to parse (eg. js / php ...)
92 * @cfg {Array} src base source files/directories.
97 * @cfg {Array} excludeSrc base source files/directories.
101 * @cfg {String} target where to write the output to.
109 * @cfg {String} templateDir where get the templates from.
113 * @cfg {String} publishExt output extenstion.
120 * @cfg {Boolean} docPrivate document private variables.
126 * @cfg {String} roojs Path to roojs installation.
128 roojs : 'http://roojs.com/roojs1/',
132 * @cfg {Boolean} ignoreNamespace should the memberOf be stripped for seed classes
134 ignoreNamespace : false,
141 * Full list of source files.
163 * start the build process
169 this.LOG.inform("JsDoc Toolkit main() running at "+new Date()+".");
172 if (this.cacheDirectory.length && !File.isDirectory(this.cacheDirectory)) {
173 File.mkdir(this.cacheDirectory)
176 this.srcFiles = this._getSrcFiles();
177 this._parseSrcFiles();
178 this.symbolSet = imports.ScopeNamer.ScopeNamer.symbols;
179 //this.symbolSet = this.parser.symbols;
181 // this currently uses the concept of publish.js...
189 * create a list of files in this.srcFiles using list of directories / files in Options.src
193 _getSrcFiles : function()
198 var ext = this.ext.split(",").map(function($) {return $.toLowerCase()});
200 this.src.forEach(function(src_in) {
201 // add to sourcefiles..
202 var src = File.join(_this.baseDir , src_in);
205 if (!File.isDirectory(src)) {
210 File.list(src ).forEach(function($) {
211 if (_this.excludeSrc.indexOf($) > -1) {
214 var thisExt = $.split(".").pop().toLowerCase();
215 if (ext.indexOf(thisExt) < 0) {
218 ret.push( File.join(src, $));
222 //Seed.print(JSON.stringify(this.srcFiles, null,4));Seed.quit();
226 * Parse the source files.
230 _parseSrcFiles : function()
234 this.srcFiles.forEach(function(srcFile) {
237 var cacheFile = !_this.cacheDirectory.length ? false :
238 _this.cacheDirectory + srcFile.replace(/\//g, '_') + ".cache";
241 // disabled at present!@!!
243 if (cacheFile && File.exists(cacheFile)) {
246 var c_mt = File.mtime(cacheFile);
247 var o_mt = File.mtime(srcFile);
248 //println(c_mt.toSource());
249 // println(o_mt.toSource());
251 // this check does not appear to work according to the doc's - need to check it out.
253 if (c_mt > o_mt) { // cached time > original time!
254 // use the cached mtimes..
255 print("Read " + cacheFile);
257 var syms = JSON.parse(File.read(cacheFile), function(k, v) {
259 if (typeof(v) != 'object') {
262 if (typeof(v['*object']) == 'undefined') {
266 var cls = imports[v['*object']][v['*object']];
267 //print(v['*object']);
270 XObject.extend(ret, v);
274 //print("Add sybmols " + cacheFile);
275 for (var sy in syms._index) {
276 // print("ADD:" + sy );
277 imports.ScopeNamer.ScopeNamer.symbols.addSymbol(syms._index[sy]);
285 _this.LOG.inform("reading : " + srcFile);
286 src = File.read(srcFile);
289 _this.LOG.warn("Can't read source file '"+srcFile+"': "+e.message);
293 var txs = new imports.TextStream.TextStream(src);
295 var tr = new imports.TokenReader.TokenReader({
300 filename : _this.srcFileRelName(srcFile)
302 print(JSON.stringify(tr, null, 4));
305 var col = new imports.Collapse.Collapse(tr.tokenize(txs),
306 _this.srcFileRelName(srcFile));
307 // print(JSON.stringify(col, null,4));
308 imports.Symbol.Symbol.namespace = '';
309 new imports.ScopeNamer.ScopeNamer(col.tokens,
310 _this.srcFileRelName(srcFile));
319 File.write(cacheFile,
321 _this.parser.symbolsToObject(srcFile),
330 print(JSON.stringify(
331 XObject.keys(imports.ScopeNamer.ScopeNamer.symbols._index),
334 imports.ScopeNamer.ScopeNamer.symbols.relate();
336 //print(JSON.stringify(
337 // XObject.keys(imports.ScopeNamer.ScopeNamer.symbols._index),
341 //print(JSON.stringify(imports.ScopeNamer.ScopeNamer.symbols._index, null,4));
342 //this.parser.finish();
346 * publish the parsed data into html, js etc.
349 publish : function() {
350 this.LOG.inform("Publishing");
355 this.LOG.inform("Making directories:" + this.target);
356 if (!File.isDirectory(this.target))
357 File.mkdir(this.target);
359 if (!File.isDirectory(this.target+"/symbols"))
360 File.mkdir(this.target+"/symbols");
361 if (!File.isDirectory(this.target+"/symbols/src"))
362 File.mkdir(this.target+"/symbols/src");
364 if (!File.isDirectory(this.target +"/json")) {
365 File.mkdir(this.target +"/json");
368 this.LOG.inform("Copying files from static: " +this.templateDir);
369 // copy everything in 'static' into
370 File.list(this.templateDir + '/static').forEach(function (f) {
371 _this.LOG.inform("Copy " + _this.templateDir + '/static/' + f + ' to ' + _this.target + '/' + f);
372 File.copyFile(_this.templateDir + '/static/' + f, _this.target + '/' + f, Gio.FileCopyFlags.OVERWRITE);
376 this.LOG.inform("Setting up templates");
379 // used to check the details of things being linked to
380 Link.symbolSet = this.symbolSet;
383 Link.srcFileFlatName = XObject.createDelegate(this.srcFileFlatName, this);
384 Link.srcFileRelName = XObject.createDelegate(this.srcFileRelName, this);
386 var classTemplate = new Template({
387 templateFile : this.templateDir + "/class.html",
390 var classesTemplate = new Template({
391 templateFile : this.templateDir +"/allclasses.html",
394 var classesindexTemplate = new Template({
395 templateFile : this.templateDir +"/index.html",
398 var fileindexTemplate = new Template({
399 templateFile : this.templateDir +"/allfiles.html",
404 classTemplate.symbolSet = this.symbolSet;
407 function hasNoParent($) {
408 return ($.memberOf == "")
410 function isaFile($) {
411 return ($.is("FILE"))
413 function isaClass($) {
414 //return ($.is("CONSTRUCTOR") || $.isNamespace);
415 return ($.is("CONSTRUCTOR") || $.is("OBJECT"));
427 var symbols = this.symbolSet.toArray();
429 var files = this.srcFiles;
431 for (var i = 0, l = files.length; i < l; i++) {
433 var targetDir = _this.target + "/symbols/src/";
434 this.makeSrcFile(file, targetDir);
436 var makeSortby = imports.JsTemplate.Template.Template.prototype.makeSortby;
437 //print(JSON.stringify(symbols,null, 4));
438 var classes = symbols.filter(isaClass).sort(makeSortby("alias"));
441 this.LOG.inform("iterate classes");
445 for (var i = 0, l = classes.length; i < l; i++) {
446 var symbol = classes[i];
451 symbol.ignoreNamespace = this.ignoreNamespace;
453 var ns = File.dirname(symbol.srcFile).replace(/\//g,'.');
454 if (symbol.alias.substring(0, ns.length) == ns) {
457 ns += ns.length ? '.' : '';
460 this.LOG.inform("classTemplate Process : " +
461 this.target+"/symbols/" + ns + symbol.alias+'.' + this.publishExt);
463 File.write(this.target+"/symbols/" + ns + symbol.alias+'.' + this.publishExt ,
464 classTemplate.process(symbol));
466 jsonAll[symbol.alias] = this.publishJSON(symbol);
472 File.write(this.target+"/json/roodata.json",
480 // regenrate the index with different relative links
483 this.LOG.inform("build index");
485 File.write(this.target + "/index."+ this.publishExt,
486 classesindexTemplate.process(classes)
489 // blank everything???? classesindexTemplate = classesIndex = classes = null;
493 var documentedFiles = symbols.filter(function ($) {
494 return ($.is("FILE"))
499 for (var i = 0; i < files.length; i++) {
500 allFiles.push(new imports.Symbol.Symbol(files[i], [], "FILE", new imports.DocComment.DocComment("/** */")));
503 for (var i = 0; i < documentedFiles.length; i++) {
504 var offset = files.indexOf(documentedFiles[i].alias);
505 allFiles[offset] = documentedFiles[i];
508 allFiles = allFiles.sort(makeSortby("name"));
509 this.LOG.inform("write files index");
511 File.write(this.target + "/files."+this.publishExt,
512 fileindexTemplate.process(allFiles)
520 * JSON files are lookup files for the documentation
521 * - can be used by IDE's or AJAX based doc tools
522 * @param {Symbol} data The symbol to publish
525 publishJSON : function(data)
527 // what we need to output to be usefull...
529 var makeSortby = imports.JsTemplate.Template.Template.prototype.makeSortby;
531 var cfgProperties = [];
532 if (!data.comment.getTag('singleton').length) {
533 cfgProperties = data.configToArray();
534 cfgProperties = cfgProperties.sort(makeSortby("alias"));
538 //println(cfgProperties.toSource());
540 for(var i =0; i < cfgProperties.length;i++) {
541 p = cfgProperties[i];
546 memberOf : p.memberOf == data.alias ? '' : p.memberOf
551 var ownEvents = data.methods.filter( function(e){
552 return e.isEvent && !e.comment.getTag('hide').length;
553 }).sort(makeSortby("name"));
558 for(var i =0; i < ownEvents.length;i++) {
561 name : m.name.substring(1),
562 sig : this.makeFuncSkel(m.params),
567 //println(props.toSource());
568 // we need to output:
588 srcFileRelName : function(sourceFile)
590 // print(JSON.stringify([ sourceFile, this.baseDir ] ));
591 return sourceFile.substring(this.baseDir.length+1);
593 srcFileFlatName: function(sourceFile)
595 var name = sourceFile; //this.srcFileRelName(sourceFile);
596 // print("NAME: " + name);
597 name = name.replace(/\.\.?[\\\/]/g, "").replace(/[\\\/]/g, "_");
598 return name.replace(/\:/g, "_") + '.html'; //??;
602 makeSrcFile: function(sourceFile)
604 // this stuff works...
607 var name = this.srcFileFlatName(sourceFile);
609 this.LOG.inform("Write Source file : " + this.target+"/symbols/src/" + name + " FROM: " + sourceFile);
611 var pretty = imports.PrettyPrint.toPretty(File.read( sourceFile));
613 File.write(this.target+"/symbols/src/" + name,
615 '<title>' + sourceFile + '</title>' +
616 '<link rel="stylesheet" type="text/css" href="' + this.roojs + '/css/highlight-js.css"/>' +
617 '</head><body class="highlightpage">' +
622 * used by JSON output to generate a function skeleton
624 makeFuncSkel :function(params) {
625 if (!params) return "function ()\n{\n\n}";
626 return "function (" +
629 return $.name.indexOf(".") == -1; // don't show config params in signature
631 ).map( function($) { return $.name == 'this' ? '_self' : $.name; } ).join(", ") +