UNPKG

yuidoc-asp

Version:

YUIDoc, YUI's JavaScript Documentation engine tweaked to work with VB/VBScript comments.

417 lines (353 loc) 13.6 kB
/** * Copyright (c) 2011, Yahoo! Inc. All rights reserved. * Code licensed under the BSD License: * https://github.com/yui/yuidoc/blob/master/LICENSE */ var fs = require('graceful-fs'), rimraf = require('rimraf'), path = require('path'); /** This is the __module__ description for the `YUIDoc` module. var options = { paths: [ './lib' ], outdir: './out' }; var Y = require('yuidocjs'); var json = (new Y.YUIDoc(options)).run(); @class YUIDoc @main yuidoc */ YUI.add('yuidoc', function (Y) { /** * The default list of configuration options * @property OPTIONS * @type Object * @final * @for YUIDoc */ var OPTIONS = { quiet: false, writeJSON: true, outdir: path.join(process.cwd(), 'out'), extension: '.js', exclude: '.DS_Store,.svn,CVS,.git,build_rollup_tmp,build_tmp,node_modules', norecurse: false, version: '0.1.0', paths: [], themedir: path.join(__dirname, 'themes', 'default'), syntaxtype: 'js' }; /** * YUIDoc main class var options = { paths: [ './lib' ], outdir: './out' }; var Y = require('yuidoc'); var json = (new Y.YUIDoc(options)).run(); * @class YUIDoc * @module yuidoc * @constructor * @param config The config object */ Y.YUIDoc = function (config) { /** * Holds the number of files that we are processing. * @property filecount * @type Boolean * @private */ this.filecount = 0; /** * Hash map of dirnames to selleck config options. * @property selleck * @type Object * @private */ this.selleck = {}; /** * Holder for the list of files we are processing. * @property filemap * @type Object * @private */ this.filemap = {}; /** * Holder for the list of directories we are processing. * @property dirmap * @type Object * @private */ this.dirmap = {}; /** * Internal holder for configuration options. * @property options * @type Object * @private */ this.options = Y.merge(OPTIONS, config); if (this.options.quiet) { Y.applyConfig({ debug: false }); } }; Y.YUIDoc.prototype = { /** * Always exclude these directories * @method _setDefaultExcludes * @private */ _setDefaultExcludes: function () { //These should always be excluded var excludes = '.DS_Store,.svn,CVS,.git,build_rollup_tmp,build_tmp,node_modules'.split(','), self = this; excludes.forEach(function (item) { self.options.excludes[item] = true; }); }, /** * Does post process on self.options. * @method _processConfig * @private */ _processConfig: function () { this.options.extensions = Y.Array.hash(this.options.extension.split(',')); this.options.excludes = Y.Array.hash(this.options.exclude.split(',')); this._setDefaultExcludes(); }, /** * Walks the paths and parses the directory contents * @method walk * @private */ walk: function () { Y.each(this.options.paths, function (dir) { this.parsedir(dir); }, this); }, /** * Walks the passed directory and grabs all the files recursively. * @method parsedir * @param {String} dir The directory to parse the contents of. * @private */ parsedir: function (dir) { if (!Y.Files.isDirectory(dir)) { throw ('Can not find directory: ' + dir); } var allfiles = fs.readdirSync(dir), stats, files = [], fullpath, self = this; if (dir in self.options.excludes) { return; } allfiles = allfiles.sort(); Y.each(allfiles, function (filename) { if (!(filename in self.options.excludes)) { fullpath = path.join(dir, filename); stats = fs.statSync(fullpath); if (stats.isDirectory() && !self.options.norecurse) { self.parsedir(fullpath); } else { files.push(filename); } } }); if (!(dir in self.options.excludes)) { this.parsefiles(dir, files); } }, /** * Gathers all the file data and populates the filemap and dirmap hashes. * @method parsefiles * @param {String} dir The directory to start from. * @param {Array} files List of files to parse. * @private */ parsefiles: function (dir, files) { var self = this; files = files.sort(); Y.each(files, function (filename) { var ext = path.extname(filename), text, fullpath; if (ext) { if (ext in self.options.extensions) { fullpath = path.join(dir, filename); if (Y.Files.exists(fullpath)) { self.filecount++; text = fs.readFileSync(fullpath, Y.charset); self.filemap[fullpath] = text.replace(/\r?\n|\r/g, '\n'); self.dirmap[fullpath] = dir; self.getSelleck(fullpath); } else { Y.log('File skipped: ' + fullpath, 'warn', 'yuidoc'); } } } }); }, getSelleck: function (fullpath) { var self = this, base, comp, json; if (self.options.selleck) { base = path.dirname(fullpath); comp = path.join(base, '../', 'docs', 'component.json'); //Y.log('Checking for Selleck data: ' + comp, 'info', 'yuidoc'); if (Y.Files.exists(comp)) { try { json = JSON.parse(fs.readFileSync(comp, 'utf8')); delete json.examples; //Remove the selleck example data, we only want the comp info self.selleck[fullpath] = json; } catch (e) { Y.log('JSON parse failed on Selleck component.json file: ' + comp, 'error', 'yuidoc'); } } } }, /** * Applies preprocessors to the data tree. * This function first clones the data and operates on the clone. * @method runPreprocessors * @private * @return {Object} The mutated data */ runPreprocessors: function (data) { var self = this, preprocessors, preprocessorsRelativeTo; // We will try to load the preprocessors as npm modules, but we will also // search for them relative to the process working directory. // The latter is consistent with how other paths are treated by yuidoc, // such as the config options 'paths' and 'outdir'. preprocessorsRelativeTo = process.cwd(); if (self.options.preprocessor) { data=JSON.parse(JSON.stringify(data)); preprocessors = [].concat(self.options.preprocessor); preprocessors.forEach(function (preprocessor) { var preprocessorModule; try { preprocessorModule = require(preprocessor); } catch (e) { preprocessorModule = require(path.resolve(preprocessorsRelativeTo, preprocessor)); } preprocessorModule(data, self.options); }); } return data; }, /** * Writes the parser JSON data to disk. * Applies preprocessors, if any. * @method writeJSON * @param {Object} parser The DocParser instance to use * @private * @return {Object} The JSON data returned from the DocParser */ writeJSON: function (parser) { var self = this, data, file, out; data = parser.data; data.warnings = parser.warnings; data = this.runPreprocessors(data); if (self.selleck && self.options.selleck && data.files && data.modules) { Object.keys(self.selleck).forEach(function (file) { Object.keys(data.files).forEach(function (f) { if (file === f) { var mods = data.files[f].modules; if (mods) { Object.keys(mods).forEach(function (mod) { if (data.modules[mod]) { if (!data.modules[mod].extra) { data.modules[mod].extra = {}; } data.modules[mod].extra.selleck = self.selleck[file]; } }); } } }); }); } if (self.options.project) { data.project = self.options.project; } if (self.options.writeJSON) { // Y.log(Y.JSON.stringify(parser.data, null, 4)); file = path.join(self.options.outdir, 'data.json'); if (Y.Files.exists(self.options.outdir) && !self.options.nodeleteout) { Y.log('Found out dir, deleting: ' + self.options.outdir, 'warn', 'yuidoc'); rimraf.sync(self.options.outdir); } if (!Y.Files.exists(self.options.outdir)) { Y.log('Making out dir: ' + self.options.outdir, 'info', 'yuidoc'); try { fs.mkdirSync(self.options.outdir, 0777); } catch (e) { Y.log('Outdir creation failed', 'warn', 'yuidoc'); } } out = fs.createWriteStream(file, { flags: "w", encoding: Y.charset, mode: 0644 }); out.write(JSON.stringify(data, null, 4)); out.end(); } return data; }, lint: function (warnings) { var code = 0, count = 0; if (warnings && warnings.length) { code = 1; console.log('YUIDoc found', warnings.length, 'lint errors in your docs'); warnings.forEach(function (item) { count++; console.log('#' + count, item.message, item.line + '\n'); }); process.exit(code); } }, /** * Process the config, walk the file tree and write out the JSON data. * @method run * @return {Object} The JSON data returned from the DocParser */ run: function () { /** * Timestamp holder so we know when YUIDoc started the parse process. * @property starttime * @type Timestamp */ Y.log('YUIDoc Starting from: ' + this.options.paths.join(','), 'info', 'yuidoc'); this.starttime = new Date().getTime(); this._processConfig(); this.walk(); var json = this.writeJSON(new Y.DocParser({ syntaxtype: this.options.syntaxtype, filemap: this.filemap, dirmap: this.dirmap }).parse()); if (this.options.lint) { this.lint(json.warnings); return null; } /** * Timestamp holder so we know when YUIDoc has finished the parse process. * @property endtime * @type Timestamp */ this.endtime = new Date().getTime(); Y.log('Parsed ' + this.filecount + ' files in ' + ((this.endtime - this.starttime) / 1000) + ' seconds', 'info', 'yuidoc'); return json; } }; });