From 8f547ebc6ab56e5d66c2c1c305165776bc654467 Mon Sep 17 00:00:00 2001 From: Ryuichi Okumura Date: Sat, 16 May 2015 23:25:10 +0900 Subject: [PATCH] Change the linting It just switches from JSHint to ESLint. ESLint has many good linting rules as default, and it makes more consistency code. The summary of changes as follows. * Intended code under `lib/` and `tests/`. * Follow default rules of ESLint as much as possible. * Disable following rules to avoid making large code changes for now. * `camelcase` * `new-cap` * `no-loop-func` * `no-process-exit` * `no-underscore-dangle` * `no-use-before-define` --- .eslintrc | 17 ++ lib/builder.js | 158 +++++++++------- lib/cli.js | 4 +- lib/docparser.js | 187 ++++++++++--------- lib/docview.js | 4 +- lib/files.js | 47 ++--- lib/help.js | 78 ++++---- lib/index.js | 15 +- lib/options.js | 86 ++++----- lib/project.js | 2 + lib/server.js | 408 +++++++++++++++++++++-------------------- lib/utils.js | 31 ++-- lib/yuidoc.js | 32 ++-- package.json | 23 +-- tests/builder.js | 15 +- tests/files.js | 15 +- tests/options.js | 21 ++- tests/parser.js | 35 ++-- tests/parser_coffee.js | 11 +- tests/preprocessor.js | 55 +++--- tests/utils.js | 17 +- 21 files changed, 656 insertions(+), 605 deletions(-) create mode 100644 .eslintrc diff --git a/.eslintrc b/.eslintrc new file mode 100644 index 00000000..b2207e06 --- /dev/null +++ b/.eslintrc @@ -0,0 +1,17 @@ +{ + "env": { + "node": true + }, + "globals": { + "YUI": true + }, + "rules": { + "camelcase": 0, + "new-cap": 0, + "no-loop-func": 0, + "no-process-exit": 0, + "no-underscore-dangle": 0, + "no-use-before-define": 0, + "quotes": [2, "single"] + } +} diff --git a/lib/builder.js b/lib/builder.js index e887c729..eff016a0 100644 --- a/lib/builder.js +++ b/lib/builder.js @@ -3,11 +3,13 @@ * Code licensed under the BSD License: * https://github.com/yui/yuidoc/blob/master/LICENSE */ -var MarkdownIt = require('markdown-it'), - fs = require('graceful-fs'), - noop = function () {}, - path = require('path'), - TEMPLATE; +'use strict'; + +var MarkdownIt = require('markdown-it'); +var fs = require('graceful-fs'); +var noop = function () {}; +var path = require('path'); +var TEMPLATE; /** * Takes the `JSON` data from the `DocParser` class, creates and parses markdown and handlebars @@ -63,7 +65,7 @@ YUI.add('doc-builder', function (Y) { this.files = 0; var self = this; - Y.Handlebars.registerHelper('crossLink', function (item, options) { + Y.Handlebars.registerHelper('crossLink', function (item, helperOptions) { var str = ''; if (!item) { item = ''; @@ -77,16 +79,16 @@ YUI.add('doc-builder', function (Y) { }); str = p.join(' | '); } else { - str = self._parseCrossLink.call(self, item, false, options.fn(this)); + str = self._parseCrossLink.call(self, item, false, helperOptions.fn(this)); } return str; }); - Y.Handlebars.registerHelper('crossLinkModule', function (item, options) { + Y.Handlebars.registerHelper('crossLinkModule', function (item, helperOptions) { var str = item; if (self.data.modules[item]) { - var content = options.fn(this); - if (content === "") { + var content = helperOptions.fn(this); + if (content === '') { content = item; } str = '= 0) { + if (url.indexOf('://') >= 0) { return url; } return path.join(opts.meta.projectRoot, url); @@ -819,8 +821,8 @@ YUI.add('doc-builder', function (Y) { var parts = Y.merge(partials || {}, { layout_content: source }); - Y.each(parts, function (source, name) { - Y.Handlebars.registerPartial(name, source); + Y.each(parts, function (partialsSource, name) { + Y.Handlebars.registerPartial(name, partialsSource); }); if (!TEMPLATE || !this.cacheTemplates) { @@ -856,6 +858,11 @@ YUI.add('doc-builder', function (Y) { var self = this; Y.prepare([DEFAULT_THEME, themeDir], self.getProjectMeta(), function (err, opts) { + if (err) { + Y.log(err, 'error', 'builder'); + cb(err); + return; + } opts.meta.title = self.data.project.name; opts.meta.projectRoot = './'; opts.meta.projectAssets = './assets'; @@ -864,7 +871,12 @@ YUI.add('doc-builder', function (Y) { opts = self.populateModules(opts); var view = new Y.DocView(opts.meta); - self.render('{{>index}}', view, opts.layouts.main, opts.partials, function (err, html) { + self.render('{{>index}}', view, opts.layouts.main, opts.partials, function (renderErr, html) { + if (renderErr) { + Y.log(renderErr, 'error', 'builder'); + cb(renderErr); + return; + } self.files++; cb(html, view); }); @@ -910,6 +922,11 @@ YUI.add('doc-builder', function (Y) { data.displayName = data.name; data.name = self.filterFileName(data.name); Y.prepare([DEFAULT_THEME, themeDir], self.getProjectMeta(), function (err, opts) { + if (err) { + Y.log(err, 'error', 'builder'); + cb(err); + return; + } opts.meta = Y.merge(opts.meta, data); //opts.meta.htmlTitle = v.name + ': ' + self.data.project.name; @@ -969,7 +986,12 @@ YUI.add('doc-builder', function (Y) { var view = new Y.DocView(opts.meta); var mainLayout = opts.layouts[layout]; - self.render('{{>module}}', view, mainLayout, opts.partials, stack.add(function (err, html) { + self.render('{{>module}}', view, mainLayout, opts.partials, stack.add(function (renderErr, html) { + if (renderErr) { + Y.log(renderErr, 'error', 'builder'); + cb(renderErr); + return; + } self.files++; stack.html = html; stack.view = view; @@ -1149,51 +1171,51 @@ YUI.add('doc-builder', function (Y) { } var classItems = []; - self.data.classitems.forEach(function (i) { - if (i.class === data.name) { - classItems.push(i); + self.data.classitems.forEach(function (classItem) { + if (classItem.class === data.name) { + classItems.push(classItem); } }); classItems = self.mergeExtends(data, classItems, true); if (data.is_constructor) { - var i = Y.mix({}, data); - i = self.augmentData(i); - i.paramsList = []; - if (i.params) { - i.params.forEach(function (p) { + var constructor = Y.mix({}, data); + constructor = self.augmentData(constructor); + constructor.paramsList = []; + if (constructor.params) { + constructor.params.forEach(function (p) { var name = p.name; if (p.optional) { name = '[' + name + ((p.optdefault) ? '=' + p.optdefault : '') + ']'; } - i.paramsList.push(name); + constructor.paramsList.push(name); }); } //i.methodDescription = self._parseCode(markdown(i.description)); - i.hasAccessType = i.access; - i.hasParams = i.paramsList.length; - if (i.paramsList.length) { - i.paramsList = i.paramsList.join(', '); + constructor.hasAccessType = constructor.access; + constructor.hasParams = constructor.paramsList.length; + if (constructor.paramsList.length) { + constructor.paramsList = constructor.paramsList.join(', '); } else { - i.paramsList = ' '; + constructor.paramsList = ' '; } - i.returnType = ' '; - if (i["return"]) { - i.hasReturn = true; - i.returnType = i["return"].type; + constructor.returnType = ' '; + if (constructor.return) { + constructor.hasReturn = true; + constructor.returnType = constructor.return.type; } //console.error(i); - opts.meta.is_constructor = [i]; - if (i.example && i.example.length) { - if (i.example.forEach) { - var e = ''; - i.example.forEach(function (v) { - e += self._parseCode(self.markdown(v)); + opts.meta.is_constructor = [constructor]; + if (constructor.example && constructor.example.length) { + if (constructor.example.forEach) { + var example = ''; + constructor.example.forEach(function (v) { + example += self._parseCode(self.markdown(v)); }); - i.example = e; + constructor.example = example; } else { - i.example = self._parseCode(self.markdown(i.example)); + constructor.example = self._parseCode(self.markdown(constructor.example)); } } } @@ -1233,9 +1255,9 @@ YUI.add('doc-builder', function (Y) { i.paramsList = ' '; } i.returnType = ' '; - if (i["return"]) { + if (i.return) { i.hasReturn = true; - i.returnType = i["return"].type; + i.returnType = i.return.type; } // If this item is provided by a module other @@ -1374,7 +1396,12 @@ YUI.add('doc-builder', function (Y) { var view = new Y.DocView(opts.meta); var mainLayout = opts.layouts[layout]; - self.render('{{>classes}}', view, mainLayout, opts.partials, stack.add(function (err, html) { + self.render('{{>classes}}', view, mainLayout, opts.partials, stack.add(function (renderErr, html) { + if (renderErr) { + Y.log(renderErr, 'error', 'builder'); + cb(renderErr); + return; + } self.files++; stack.html = html; stack.view = view; @@ -1533,10 +1560,10 @@ YUI.add('doc-builder', function (Y) { opts = self.populateFiles(opts); opts.meta.fileName = data.name; - fs.readFile(opts.meta.fileName, Y.charset, Y.rbind(function (err, str, opts, data) { - if (err) { - Y.log(err, 'error', 'builder'); - cb(err); + fs.readFile(opts.meta.fileName, Y.charset, Y.rbind(function (readErr, str, readOpts, readData) { + if (readErr) { + Y.log(readErr, 'error', 'builder'); + cb(readErr); return; } @@ -1544,12 +1571,17 @@ YUI.add('doc-builder', function (Y) { str = str.replace(/\t/g, self.options.tabspace); } - opts.meta.fileData = str; - var view = new Y.DocView(opts.meta, 'index'); - var mainLayout = opts.layouts[layout]; - self.render('{{>files}}', view, mainLayout, opts.partials, function (err, html) { + readOpts.meta.fileData = str; + var view = new Y.DocView(readOpts.meta, 'index'); + var mainLayout = readOpts.layouts[layout]; + self.render('{{>files}}', view, mainLayout, readOpts.partials, function (renderErr, html) { + if (renderErr) { + Y.log(renderErr, 'error', 'builder'); + cb(renderErr); + return; + } self.files++; - cb(html, view, data); + cb(html, view, readData); }); }, this, opts, data)); @@ -1629,7 +1661,7 @@ YUI.add('doc-builder', function (Y) { self.makeDirs(function () { Y.log('Copying Assets', 'info', 'builder'); if (!Y.Files.isDirectory(path.join(self.options.outdir, 'assets'))) { - fs.mkdirSync(path.join(self.options.outdir, 'assets'), 0777); + fs.mkdirSync(path.join(self.options.outdir, 'assets'), '0777'); } Y.Files.copyAssets([ path.join(DEFAULT_THEME, 'assets'), diff --git a/lib/cli.js b/lib/cli.js index 05a0e80d..cbacba02 100755 --- a/lib/cli.js +++ b/lib/cli.js @@ -1,4 +1,5 @@ #!/usr/bin/env node +'use strict'; /** * Copyright (c) 2011, Yahoo! Inc. All rights reserved. @@ -12,7 +13,6 @@ * @module yuidoc */ -/*global Y:true */ var Y = require('./index'); var options = Y.Options(Y.Array(process.argv, 2)); @@ -35,7 +35,7 @@ if (options.server) { } else { var json = (new Y.YUIDoc(options)).run(); if (json === null) { - return; + throw new Error('Running YUIDoc returns null.'); } options = Y.Project.mix(json, options); diff --git a/lib/docparser.js b/lib/docparser.js index 266cb191..679dd77c 100644 --- a/lib/docparser.js +++ b/lib/docparser.js @@ -3,6 +3,8 @@ * Code licensed under the BSD License: * https://github.com/yui/yuidoc/blob/master/LICENSE */ +'use strict'; + YUI.add('docparser', function (Y) { var Lang = Y.Lang, @@ -101,74 +103,74 @@ YUI.add('docparser', function (Y) { * @for DocParser */ TAGLIST = [ - "async", // bool, custom events can fire the listeners in a setTimeout - "author", // author best for projects and modules, but can be used anywhere // multi - "attribute", // YUI attributes -- get/set with change notification, etc - "beta", // module maturity identifier - "broadcast", // bool, events - "bubbles", // custom events that bubble - "category", // modules can be in multiple categories - "chainable", // methods that return the host object - "class", // pseudo class - "conditional", // conditional module - "config", // a config param (not an attribute, so no change events) - "const", // not standardized yet, converts to final property - "constructs", // factory methods (not yet used) - "constructor", // this is a constructor - "contributor", // like author - "default", // property/attribute default value - "deprecated", // please specify what to use instead - "description", // can also be free text at the beginning of a comment is - "emitfacade", // bool, YUI custom event can have a dom-like event facade - "event", // YUI custom event - "evil", // uses eval - "extension", // this is an extension for [entity] - "extensionfor", // this is an extension for [entity] - "extension_for",// this is an extension for [entity] - "example", // 0..n code snippets. snippets can also be embedded in the desc - "experimental", // module maturity identifier - "extends", // pseudo inheritance - "file", // file name (used by the parser) - "final", // not meant to be changed - "fireonce", // bool, YUI custom event config allows - "for", // used to change class context - "global", // declare your globals - "icon", // project icon(s) - "in", // indicates module this lives in (obsolete now) - "initonly", // attribute writeonce value - "injects", // injects {HTML|script|CSS} - "knownissue", // 0..n known issues for your consumption - "line", // line number for the comment block (used by the parser) - "method", // a method - "module", // YUI module name - "main", // Description for the module - "namespace", // Y.namespace, used to fully qualify class names - "optional", // For optional attributes - "required", // For required attributes - "param", // member param - "plugin", // this is a plugin for [entityl] - "preventable", // YUI custom events can be preventable ala DOM events - "private", // > access - "project", // project definition, one per source tree allowed - "property", // a regular-ole property - "protected", // > access - "public", // > access - "queuable", // bool, events - "readonly", // YUI attribute config - "requires", // YUI module requirements - "return", // {type} return desc -- returns is converted to this - "see", // 0..n things to look at - "since", // when it was introduced - "static", // static - "submodule", // YUI submodule - "throws", // {execption type} description - "title", // this should be something for the project description - "todo", // 0..n things to revisit eventually (hopefully) - "type", // the var type - "url", // project url(s) - "uses", // 0..n compents mixed (usually, via augment) into the prototype - "value", // the value of a constant - "writeonce" // YUI attribute config + 'async', // bool, custom events can fire the listeners in a setTimeout + 'author', // author best for projects and modules, but can be used anywhere // multi + 'attribute', // YUI attributes -- get/set with change notification, etc + 'beta', // module maturity identifier + 'broadcast', // bool, events + 'bubbles', // custom events that bubble + 'category', // modules can be in multiple categories + 'chainable', // methods that return the host object + 'class', // pseudo class + 'conditional', // conditional module + 'config', // a config param (not an attribute, so no change events) + 'const', // not standardized yet, converts to final property + 'constructs', // factory methods (not yet used) + 'constructor', // this is a constructor + 'contributor', // like author + 'default', // property/attribute default value + 'deprecated', // please specify what to use instead + 'description', // can also be free text at the beginning of a comment is + 'emitfacade', // bool, YUI custom event can have a dom-like event facade + 'event', // YUI custom event + 'evil', // uses eval + 'extension', // this is an extension for [entity] + 'extensionfor', // this is an extension for [entity] + 'extension_for',// this is an extension for [entity] + 'example', // 0..n code snippets. snippets can also be embedded in the desc + 'experimental', // module maturity identifier + 'extends', // pseudo inheritance + 'file', // file name (used by the parser) + 'final', // not meant to be changed + 'fireonce', // bool, YUI custom event config allows + 'for', // used to change class context + 'global', // declare your globals + 'icon', // project icon(s) + 'in', // indicates module this lives in (obsolete now) + 'initonly', // attribute writeonce value + 'injects', // injects {HTML|script|CSS} + 'knownissue', // 0..n known issues for your consumption + 'line', // line number for the comment block (used by the parser) + 'method', // a method + 'module', // YUI module name + 'main', // Description for the module + 'namespace', // Y.namespace, used to fully qualify class names + 'optional', // For optional attributes + 'required', // For required attributes + 'param', // member param + 'plugin', // this is a plugin for [entityl] + 'preventable', // YUI custom events can be preventable ala DOM events + 'private', // > access + 'project', // project definition, one per source tree allowed + 'property', // a regular-ole property + 'protected', // > access + 'public', // > access + 'queuable', // bool, events + 'readonly', // YUI attribute config + 'requires', // YUI module requirements + 'return', // {type} return desc -- returns is converted to this + 'see', // 0..n things to look at + 'since', // when it was introduced + 'static', // static + 'submodule', // YUI submodule + 'throws', // {execption type} description + 'title', // this should be something for the project description + 'todo', // 0..n things to revisit eventually (hopefully) + 'type', // the var type + 'url', // project url(s) + 'uses', // 0..n compents mixed (usually, via augment) into the prototype + 'value', // the value of a constant + 'writeonce' // YUI attribute config ], /** @@ -180,7 +182,7 @@ YUI.add('docparser', function (Y) { * @for DocParser */ IGNORE_TAGLIST = [ - "media" + 'media' ], /** @@ -390,7 +392,7 @@ YUI.add('docparser', function (Y) { // @returns {type} description // methods // @injects {HTML|CSS|script} description // can be used by anthing that has an optional {type} and a description - 'return': function (tagname, value, target, block) { + 'return': function (tagname, value, target) { var desc = implodeString(trim(value)), type, @@ -419,7 +421,7 @@ YUI.add('docparser', function (Y) { 'injects': 'return', // trying to overwrite the constructor value is a bad idea - 'constructor': function (tagname, value, target, block) { + 'constructor': function (tagname, value, target) { target.is_constructor = 1; }, @@ -457,7 +459,7 @@ YUI.add('docparser', function (Y) { }, //Setting the description for the module.. - 'main': function (tagname, value, target, block) { + 'main': function (tagname, value, target) { var o = target; o.mainName = value; o.tag = tagname; @@ -467,13 +469,13 @@ YUI.add('docparser', function (Y) { }, // accepts a single project definition for the source tree - 'project': function (tagname, value, target, block) { + 'project': function () { return this.project; }, // A key bock type for declaring submodules. subsequent class and // member blocks will be assigned to this submodule. - 'submodule': function (tagname, value, target, block) { + 'submodule': function (tagname, value) { //console.log('Setting current submodule: ', value, 'on class'); this.set(CURRENT_SUBMODULE, value); var host = this.modules[value], @@ -537,11 +539,10 @@ YUI.add('docparser', function (Y) { }, // change 'const' to final property - 'const': function (tagname, value, target, block) { + 'const': function (tagname, value, target) { target.itemtype = 'property'; target.name = value; - /*jshint sub:true */ - target['final'] = ''; + target.final = ''; }, // supported classitems @@ -579,7 +580,7 @@ YUI.add('docparser', function (Y) { 'event': 'property', // access fields - 'public': function (tagname, value, target, block) { + 'public': function (tagname, value, target) { target.access = tagname; target.tagname = value; }, @@ -588,7 +589,7 @@ YUI.add('docparser', function (Y) { 'inner': 'public', // tags that can have multiple occurances in a single block - 'todo': function (tagname, value, target, block) { + 'todo': function (tagname, value, target) { if (!Lang.isArray(target[tagname])) { target[tagname] = []; } @@ -605,7 +606,7 @@ YUI.add('docparser', function (Y) { }); }, 'extension_for': 'extensionfor', - 'extensionfor': function (tagname, value, target, block) { + 'extensionfor': function (tagname, value) { if (this.classes[this.get(CURRENT_CLASS)]) { this.classes[this.get(CURRENT_CLASS)].extension_for.push(value); } @@ -635,7 +636,7 @@ YUI.add('docparser', function (Y) { 'category': 'todo', 'unimplemented': 'todo', - genericValueTag: function (tagname, value, target, block) { + genericValueTag: function (tagname, value, target) { target[tagname] = value; }, @@ -643,7 +644,7 @@ YUI.add('docparser', function (Y) { 'contributor': 'genericValueTag', 'since': 'genericValueTag', - 'deprecated': function (tagname, value, target, block) { + 'deprecated': function (tagname, value, target) { target.deprecated = true; if (typeof value === 'string' && value.length) { @@ -652,7 +653,7 @@ YUI.add('docparser', function (Y) { }, // updates the current namespace - 'namespace': function (tagname, value, target, block) { + 'namespace': function (tagname, value) { this.set(CURRENT_NAMESPACE, value); if (value === '') { //Shortcut this if namespace is an empty string. @@ -720,7 +721,7 @@ YUI.add('docparser', function (Y) { // updates the current class only (doesn't create // a new class definition) - 'for': function (tagname, value, target, block) { + 'for': function (tagname, value) { var ns, file, mod; value = this._resolveFor(value); @@ -756,7 +757,7 @@ YUI.add('docparser', function (Y) { * @param {Object} o the config object * @module yuidoc */ - DocParser = function (o) { + DocParser = function () { this.digesters = Y.merge(DocParser.DIGESTERS); this.knowntags = Y.Array.hash(DocParser.TAGLIST); DocParser.superclass.constructor.apply(this, arguments); @@ -915,7 +916,7 @@ YUI.add('docparser', function (Y) { clazz = this.classes[this.get(CURRENT_CLASS)]; if (clazz) { - //Handles case where @module comes after @class in a new directory of files + //Handles case where @module comes after @class in a new directory of files if (clazz.module !== val) { if (this.modules[clazz.module]) { delete this.modules[clazz.module].submodules[clazz.submodule]; @@ -1054,7 +1055,7 @@ YUI.add('docparser', function (Y) { this.warnings = []; var self = this; - self.after('currentfileChange', function (e) { + self.after('currentfileChange', function () { /* * File changed, so we reset class and submodule. * You should use @for if you want to reference another class @@ -1076,16 +1077,12 @@ YUI.add('docparser', function (Y) { self.after('currentsubmoduleChange', function (e) { var mod = e.newVal, - classes = self.classes, - parent; + classes = self.classes; if (mod) { - parent = self.modules[mod].module; Y.each(classes, function (clazz) { if (!(clazz.submodule)) { - //if ((!clazz.module) || clazz.module == parent) { if (!clazz.module) { - //console.log('Adding Submodule: ', mod, ' to', clazz.module, 'with parent', parent); clazz.submodule = mod; } } @@ -1096,8 +1093,8 @@ YUI.add('docparser', function (Y) { self.after('currentclassChange', function (e) { var clazz = e.newVal; Y.each(self.classitems, function (item) { - if (!(item["class"])) { - item["class"] = clazz; + if (!(item.class)) { + item.class = clazz; } }); // Y.log(self.classitems); @@ -1316,7 +1313,7 @@ YUI.add('docparser', function (Y) { Y.mix(host, target); } else { this.classitems.push(target); - target['class'] = this.get(CURRENT_CLASS); + target.class = this.get(CURRENT_CLASS); target.module = this.get(CURRENT_MODULE); host = this.get(CURRENT_SUBMODULE); diff --git a/lib/docview.js b/lib/docview.js index 40341096..298d4536 100644 --- a/lib/docview.js +++ b/lib/docview.js @@ -3,6 +3,8 @@ * Code licensed under the BSD License: * https://github.com/yui/yuidoc/blob/master/LICENSE */ +'use strict'; + YUI.add('docview', function (Y) { /* @@ -12,7 +14,7 @@ YUI.add('docview', function (Y) { */ /** - View class borrowed from [Selleck](https://github.com/rgrove/selleck) + View class borrowed from [Selleck](https://github.com/rgrove/selleck) The view class is a **`handlebars`** template helper. @class DocView @constructor diff --git a/lib/files.js b/lib/files.js index 0db1a8b4..577dbdb0 100644 --- a/lib/files.js +++ b/lib/files.js @@ -3,6 +3,8 @@ * Code licensed under the BSD License: * https://github.com/yui/yuidoc/blob/master/LICENSE */ +'use strict'; + YUI.add('files', function (Y) { /** @@ -19,9 +21,9 @@ YUI.add('files', function (Y) { Licensed under the BSD License. */ - var fs = require('graceful-fs'), - fsPath = require('path'), - useFS = (fs.exists) ? fs : fsPath; + var fs = require('graceful-fs'); + var fsPath = require('path'); + var useFS = (fs.exists) ? fs : fsPath; function exists(file, cb) { @@ -58,7 +60,7 @@ YUI.add('files', function (Y) { } if (!stats.isDirectory()) { - return callback(new Error("Source is not a directory: " + source)); + return callback(new Error('Source is not a directory: ' + source)); } fs.lstat(dest, afterDestStat); @@ -70,20 +72,20 @@ YUI.add('files', function (Y) { } if (stats) { - // If the destination is a file or a link, either delete it or + // If the destination is a file or a link, either delete it or // bubble an error if overwrite isn't true. if (stats.isFile() || stats.isSymbolicLink()) { if (overwrite) { deletePath(dest); // TODO: make this async } else { - callback(new Error("Destination already exists: " + dest)); - return; + callback(new Error('Destination already exists: ' + dest)); + return undefined; } } afterMkDir(); } else { - fs.mkdir(dest, 0755, afterMkDir); + fs.mkdir(dest, '0755', afterMkDir); } } @@ -107,10 +109,9 @@ YUI.add('files', function (Y) { } while ((filename = files.shift())) { - /*jshint loopfunc:true */ - copyPath(fsPath.join(source, filename), fsPath.join(dest, filename), overwrite, function (err) { - if (err) { - return callback(err); + copyPath(fsPath.join(source, filename), fsPath.join(dest, filename), overwrite, function (copyPathErr) { + if (copyPathErr) { + return callback(copyPathErr); } pending -= 1; @@ -147,28 +148,28 @@ YUI.add('files', function (Y) { } if (!sourceStats.isFile()) { - return callback(new Error("Source is not a file: " + source)); + return callback(new Error('Source is not a file: ' + source)); } - fs.lstat(dest, function (err, destStats) { + fs.lstat(dest, function (destStatsErr, destStats) { var rs; - if (err && err.code !== 'ENOENT') { - return callback(err); + if (destStatsErr && destStatsErr.code !== 'ENOENT') { + return callback(destStatsErr); } if (destStats) { if (overwrite) { deletePath(dest); // TODO: make this async } else { - callback(new Error("Destination already exists: " + dest)); - return; + callback(new Error('Destination already exists: ' + dest)); + return undefined; } } rs = fs.createReadStream(source); rs.pipe(fs.createWriteStream(dest, { - mode: 0655 + mode: '0655' })); rs.on('end', callback); }); @@ -207,7 +208,7 @@ YUI.add('files', function (Y) { } if (!sourceStats) { - callback(new Error("Source not found: " + source)); + callback(new Error('Source not found: ' + source)); return; } @@ -216,7 +217,7 @@ YUI.add('files', function (Y) { } else if (sourceStats.isDirectory()) { copyDirectory(source, dest, overwrite, callback); } else { - callback(new Error("Source is neither a file nor a directory: " + source)); + callback(new Error('Source is neither a file nor a directory: ' + source)); } } Y.Files.copyPath = copyPath; @@ -440,9 +441,9 @@ YUI.add('files', function (Y) { var out, args = arguments, flags = { - flags: "w", + flags: 'w', encoding: Y.charset, - mode: 0644 + mode: '0644' }; if (cb) { diff --git a/lib/help.js b/lib/help.js index 453274f7..91d8c113 100644 --- a/lib/help.js +++ b/lib/help.js @@ -3,6 +3,8 @@ * Code licensed under the BSD License: * https://github.com/yui/yuidoc/blob/master/LICENSE */ +'use strict'; + YUI.add('help', function (Y) { /** @@ -18,44 +20,44 @@ YUI.add('help', function (Y) { * @type Array */ var help = [ - "", - "YUI Doc generates API documentation from a modified JavaDoc syntax.", - "", - "Current version ({VERSION})", - "", - "Usage: yuidoc ", - "", - "Common Options:", - " -c, --config, --configfile A JSON config file to provide configuration data.", - " You can also create a yuidoc.json file and place it", - " anywhere under your source tree and YUI Doc will find it", - " and use it.", - " -e, --extension The list of file extensions to parse ", - " for api documentation. (defaults to .js)", - " -x, --exclude Directories to exclude from parsing ", - " (defaults to '.DS_Store,.svn,CVS,.git,build_rollup_tmp,build_tmp')", - " -v, --version Show the current YUIDoc version", - " --project-version Set the doc version for the template", - " -N, --no-color Turn off terminal colors (for automation)", - " -C, --no-code Turn off code generation (don't include source files in output)", - " -n, --norecurse Do not recurse directories (default is to recurse)", - " --no-sort Do not alphabetical sorting of attributes, events, methods, and properties", - " -S, --selleck Look for Selleck component data and attach to API meta data", - " -V, --view Dump the Handlebars.js view data instead of writing template files", - " -p, --parse-only Only parse the API docs and create the JSON data, do not render templates", - " -o, --outdir Path to put the generated files (defaults to ./out)", - " -t, --themedir Path to a custom theme directory containing Handlebars templates", - " -H, --helpers Require these file and add Handlebars helpers. See docs for more information", - " --charset CHARSET Use this as the default charset for all file operations. Defaults to 'utf8'", - " -h, --help Show this help", - " -q, --quiet Supress logging output", - " -T, --theme Choose one of the built in themes (default is default)", - " --syntaxtype Choose comment syntax type (default is js)", - " --server Fire up the YUIDoc server for faster API doc developement. Pass optional port to listen on. (default is 3000)", - " --lint Lint your docs, will print parser warnings and exit code 1 if there are any", - "", - " Supply a list of paths (shell globbing is handy here)", - "", + '', + 'YUI Doc generates API documentation from a modified JavaDoc syntax.', + '', + 'Current version ({VERSION})', + '', + 'Usage: yuidoc ', + '', + 'Common Options:', + ' -c, --config, --configfile A JSON config file to provide configuration data.', + ' You can also create a yuidoc.json file and place it', + ' anywhere under your source tree and YUI Doc will find it', + ' and use it.', + ' -e, --extension The list of file extensions to parse ', + ' for api documentation. (defaults to .js)', + ' -x, --exclude Directories to exclude from parsing ', + ' (defaults to \'.DS_Store,.svn,CVS,.git,build_rollup_tmp,build_tmp\')', + ' -v, --version Show the current YUIDoc version', + ' --project-version Set the doc version for the template', + ' -N, --no-color Turn off terminal colors (for automation)', + ' -C, --no-code Turn off code generation (don\'t include source files in output)', + ' -n, --norecurse Do not recurse directories (default is to recurse)', + ' --no-sort Do not alphabetical sorting of attributes, events, methods, and properties', + ' -S, --selleck Look for Selleck component data and attach to API meta data', + ' -V, --view Dump the Handlebars.js view data instead of writing template files', + ' -p, --parse-only Only parse the API docs and create the JSON data, do not render templates', + ' -o, --outdir Path to put the generated files (defaults to ./out)', + ' -t, --themedir Path to a custom theme directory containing Handlebars templates', + ' -H, --helpers Require these file and add Handlebars helpers. See docs for more information', + ' --charset CHARSET Use this as the default charset for all file operations. Defaults to \'utf8\'', + ' -h, --help Show this help', + ' -q, --quiet Supress logging output', + ' -T, --theme Choose one of the built in themes (default is default)', + ' --syntaxtype Choose comment syntax type (default is js)', + ' --server Fire up the YUIDoc server for faster API doc developement. Pass optional port to listen on. (default is 3000)', + ' --lint Lint your docs, will print parser warnings and exit code 1 if there are any', + '', + ' Supply a list of paths (shell globbing is handy here)', + '' ].join('\n'); /** diff --git a/lib/index.js b/lib/index.js index 9666b96c..6da38ab2 100644 --- a/lib/index.js +++ b/lib/index.js @@ -3,11 +3,12 @@ * Code licensed under the BSD License: * https://github.com/yui/yuidoc/blob/master/LICENSE */ -/*global YUI:true, Y:true */ +'use strict'; + /** Module creates the YUI instance with the required modules, uses them and exports the **Y** to be used -by the _CLI class_ or by extenders: `require('yuidocjs');` -You can use it like this: +by the _CLI class_ or by extenders: `require('yuidocjs');` +You can use it like this: var options = { paths: [ './lib' ], @@ -31,10 +32,10 @@ args.forEach(function (item) { } }); -var YUI = require('yui' + (debug ? '/debug' : '')).YUI, - path = require('path'), - fs = require('graceful-fs'), - metaPath = path.join(__dirname, '../', 'package.json'); +var YUI = require('yui' + (debug ? '/debug' : '')).YUI; +var path = require('path'); +var fs = require('graceful-fs'); +var metaPath = path.join(__dirname, '../', 'package.json'); function log (message, level) { if (!message || !level || typeof console[level] !== 'function') { diff --git a/lib/options.js b/lib/options.js index 72bea37a..6daacc15 100644 --- a/lib/options.js +++ b/lib/options.js @@ -3,6 +3,8 @@ * Code licensed under the BSD License: * https://github.com/yui/yuidoc/blob/master/LICENSE */ +'use strict'; + YUI.add('options', function (Y) { var path = require('path'); @@ -35,75 +37,75 @@ YUI.add('options', function (Y) { options.writeJSON = false; options.quiet = true; break; - case "--debug": + case '--debug': Y.applyConfig({ debug: true, filter: 'debug' }); break; - case "--charset": + case '--charset': Y.charset = args.shift() || 'utf8'; Y.log('Setting default charset to ' + Y.charset, 'yuidoc', 'warn'); break; - case "-c": - case "--config": - case "--configfile": + case '-c': + case '--config': + case '--configfile': options.configfile = args.shift(); break; - case "-e": - case "--extension": + case '-e': + case '--extension': options.extension = args.shift(); break; - case "-x": - case "--exclude": + case '-x': + case '--exclude': options.exclude = args.shift(); break; - case "-v": - case "--version": + case '-v': + case '--version': console.error(Y.packageInfo.version); process.exit(1); break; - case "--project-version": + case '--project-version': options.version = args.shift(); break; - case "-N": - case "--no-color": + case '-N': + case '--no-color': Y.config.useColor = false; options.nocolor = true; break; - case "-D": - case "--no-delete-out": + case '-D': + case '--no-delete-out': options.nodeleteout = true; break; - case "-C": - case "--no-code": + case '-C': + case '--no-code': options.nocode = true; break; - case "-n": - case "--norecurse": + case '-n': + case '--norecurse': options.norecurse = true; break; - case "-S": - case "--selleck": + case '-S': + case '--selleck': options.selleck = true; break; - case "-V": - case "--view": + case '-V': + case '--view': options.dumpview = true; break; - case "-p": - case "--parse-only": + case '-p': + case '--parse-only': options.parseOnly = true; break; - case "-o": - case "--outdir": + case '-o': + case '--outdir': options.outdir = args.shift(); break; - case "-t": - case "--themedir": + case '-t': + case '--themedir': options.themedir = args.shift(); break; - case "--server": + case '--server': options.server = true; var a = args.shift(); var p = parseInt(a, 10); @@ -116,12 +118,12 @@ YUI.add('options', function (Y) { options.port = p; } break; - case "-h": - case "--help": + case '-h': + case '--help': Y.showHelp(); break; - case "-H": - case "--helpers": + case '-H': + case '--helpers': var list = args.shift(); if (list) { options.helpers = list.split(','); @@ -129,19 +131,19 @@ YUI.add('options', function (Y) { throw ('Failed to pass a helper file.'); } break; - case "-T": - case "--theme": + case '-T': + case '--theme': var theme = args.shift(); options.themedir = path.join(__dirname, '../', 'themes', theme); break; - case "-q": - case "--quiet": + case '-q': + case '--quiet': options.quiet = true; break; - case "--syntaxtype": + case '--syntaxtype': options.syntaxtype = args.shift(); break; - case "--tab-to-space": + case '--tab-to-space': options.tabtospace = parseInt(args.shift(), 10); if (typeof options.tabtospace === 'number') { options.tabspace = ''; @@ -150,7 +152,7 @@ YUI.add('options', function (Y) { } } break; - case "--no-sort": + case '--no-sort': options.dontsortfields = true; break; default: diff --git a/lib/project.js b/lib/project.js index 89ed07f2..31d66922 100644 --- a/lib/project.js +++ b/lib/project.js @@ -3,6 +3,8 @@ * Code licensed under the BSD License: * https://github.com/yui/yuidoc/blob/master/LICENSE */ +'use strict'; + YUI.add('project', function (Y) { Y.Project = { diff --git a/lib/server.js b/lib/server.js index e9595b49..c8025aaf 100644 --- a/lib/server.js +++ b/lib/server.js @@ -3,233 +3,235 @@ * Code licensed under the BSD License: * https://github.com/yui/yuidoc/blob/master/LICENSE */ +'use strict'; + +var path = require('path'); +var express = require('express'); + YUI.add('server', function (Y) { - var path = require('path'), + /** + * Provides the `--server` server option for YUIDoc + * @class Server + * @module yuidoc + */ + var Server = { /** - * Provides the `--server` server option for YUIDoc - * @class Server - * @module yuidoc + * Cache for external mixed in data. + * @property _externalData + * @private + * @type Object */ - Server = { - /** - * Cache for external mixed in data. - * @property _externalData - * @private - * @type Object - */ - _externalData: null, - /** - * Middleware to parse the API docs per request - * @method parse - * @param {Request} req Express request object - * @param {Response} res Express response object - * @param {Function} next Express next callback - */ - parse: function (req, res, next) { - var json = (new Y.YUIDoc(Server.options)).run(); - Server.options = Y.Project.mix(json, Server.options); - Server.builder = new Y.DocBuilder(Server.options, json); - if (Server._externalData) { - Server.options.externalData = Server._externalData; - Server.builder._mixExternal(); - } + _externalData: null, + /** + * Middleware to parse the API docs per request + * @method parse + * @param {Request} req Express request object + * @param {Response} res Express response object + * @param {Function} next Express next callback + */ + parse: function (req, res, next) { + var json = (new Y.YUIDoc(Server.options)).run(); + Server.options = Y.Project.mix(json, Server.options); + Server.builder = new Y.DocBuilder(Server.options, json); + if (Server._externalData) { + Server.options.externalData = Server._externalData; + Server.builder._mixExternal(); + } - next(); - }, - /** - * Create the routes used to serve YUIDoc files dynamically - * @method routes - */ - routes: function () { - var app = Server.app; - - app.get('/', Server.parse, function (req, res) { - Server.home(req, res); - }); - app.get('/api.js', function (req, res) { - Server.builder.renderAPIMeta(function (js) { - res.contentType('.js'); - res.send(js); - }); + next(); + }, + /** + * Create the routes used to serve YUIDoc files dynamically + * @method routes + */ + routes: function () { + var app = Server.app; + + app.get('/', Server.parse, function (req, res) { + Server.home(req, res); + }); + app.get('/api.js', function (req, res) { + Server.builder.renderAPIMeta(function (js) { + res.contentType('.js'); + res.send(js); }); + }); - app.get('/classes/:class.html', Server.parse, function (req, res, next) { - Server.clazz(req, res, next); - }); + app.get('/classes/:class.html', Server.parse, function (req, res, next) { + Server.clazz(req, res, next); + }); - app.get('/modules/:module.html', Server.parse, function (req, res, next) { - Server.module(req, res, next); - }); + app.get('/modules/:module.html', Server.parse, function (req, res, next) { + Server.module(req, res, next); + }); - app.get('/files/:file.html', Server.parse, function (req, res, next) { - Server.files(req, res, next); - }); + app.get('/files/:file.html', Server.parse, function (req, res, next) { + Server.files(req, res, next); + }); - //These routes are special catch routes.. + //These routes are special catch routes.. - app.get('//api.js', function (req, res) { - res.redirect('/api.js'); - }); - app.get('//classes/:class.html', Server.parse, function (req, res, next) { - Server.clazz(req, res, next); - }); + app.get('//api.js', function (req, res) { + res.redirect('/api.js'); + }); + app.get('//classes/:class.html', Server.parse, function (req, res, next) { + Server.clazz(req, res, next); + }); - app.get('//modules/:module.html', Server.parse, function (req, res, next) { - Server.module(req, res, next); - }); + app.get('//modules/:module.html', Server.parse, function (req, res, next) { + Server.module(req, res, next); + }); - app.get('//files/:file.html', Server.parse, function (req, res, next) { - Server.files(req, res, next); - }); + app.get('//files/:file.html', Server.parse, function (req, res, next) { + Server.files(req, res, next); + }); - app.get('*', function (req, res) { - var type = req.url.split('/')[1], - html = ['

Item Not Found in internal meta-data

']; + app.get('*', function (req, res) { + var type = req.url.split('/')[1], + html = ['

Item Not Found in internal meta-data

']; - if (type === 'class') { - type = 'classes'; - } - if (Server.builder && Server.builder.data && Server.builder.data[type]) { - if (Object.keys(Server.builder.data[type]).length) { - html.push('

But I know about these? Misname your module?

'); - html.push('
'); - } + if (type === 'class') { + type = 'classes'; + } + if (Server.builder && Server.builder.data && Server.builder.data[type]) { + if (Object.keys(Server.builder.data[type]).length) { + html.push('

But I know about these? Misname your module?

'); + html.push(''); } + } - res.status(404).send(html.join('\n')); - }); + res.status(404).send(html.join('\n')); + }); - }, - /** - * `/files` endpoint - * @method files - * @param {Request} req Express request object - * @param {Response} res Express response object - */ - files: function (req, res, next) { - var fileName = req.params.file, - data; - Object.keys(Server.builder.data.files).forEach(function (file) { - if (fileName === Server.builder.filterFileName(file)) { - data = Server.builder.data.files[file]; - } - }); - - if (!data) { - return next(); + }, + /** + * `/files` endpoint + * @method files + * @param {Request} req Express request object + * @param {Response} res Express response object + */ + files: function (req, res, next) { + var fileName = req.params.file, + data; + Object.keys(Server.builder.data.files).forEach(function (file) { + if (fileName === Server.builder.filterFileName(file)) { + data = Server.builder.data.files[file]; } + }); - Y.log('Serving /files/' + data.name, 'info', 'server'); - - - Server.builder.renderFile(function (html) { - res.send(html); - }, data, (req.xhr ? 'xhr' : 'main')); - }, - /** - * `/classes` endpoint - * @method clazz - * @param {Request} req Express request object - * @param {Response} res Express response object - */ - clazz: function (req, res, next) { - var className = req.params['class']; - Y.log('Serving /classes/' + className + '.html', 'info', 'server'); - if (!Server.builder.data.classes[className]) { - return next(); - } - Server.builder.renderClass(function (html) { - res.send(html); - }, Server.builder.data.classes[className], (req.xhr ? 'xhr' : 'main')); - }, - /** - * `/modules` endpoint - * @method modules - * @param {Request} req Express request object - * @param {Response} res Express response object - */ - module: function (req, res, next) { - var modName = req.params.module; - Y.log('Serving /modules/' + modName + '.html', 'info', 'server'); - if (!Server.builder.data.modules[modName]) { - return next(); - } - Server.builder.renderModule(function (html) { - res.send(html); - }, Server.builder.data.modules[modName], (req.xhr ? 'xhr' : 'main')); - }, - /** - * `/` endpoint - * @method home - * @param {Request} req Express request object - * @param {Response} res Express response object - */ - home: function (req, res, next) { - Y.log('Serving index.html', 'info', 'server'); - Server.builder.renderIndex(function (html) { - res.send(html); - }); - }, - /** - * Creates the Express server and prep's YUI for serving - * @method init - */ - init: function () { - var express = require('express'), - path = require('path'), - stat; - - Server.app = express(); - //console.log(Server.options); - stat = Server.options.themedir || path.join(__dirname, '../', 'themes', 'default'); - Server.app.use(express.static(stat)); - Server.routes(); - Server.app.listen(Server.options.port); - - Y.log('Starting server: http:/' + '/127.0.0.1:' + Server.options.port, 'info', 'server'); - }, - /** - * Start the server with the supplied options. - * @method start - * @param {Object} options Server options - */ - start: function (options) { - options = Y.Project.init(options); - Server.options = options; - - Server.options.cacheTemplates = false; //Don't cache the Handlebars templates - Server.options.writeJSON = false; //Don't write the JSON file out - - Y.config.logExclude.yuidoc = true; - Y.config.logExclude.docparser = true; - Y.config.logExclude.builder = true; - - if (Server.options.external) { - Y.log('Fetching external data, this may take a minute', 'warn', 'server'); - var json, builder; - - json = (new Y.YUIDoc(Server.options)).run(); - Server.options = Y.Project.mix(json, Server.options); - - builder = new Y.DocBuilder(Server.options, json); - builder.mixExternal(function () { - Y.log('External data fetched, launching server..', 'info', 'server'); - Server._externalData = builder.options.externalData; - Server.init(); - }); - - } else { + if (!data) { + return next(); + } + + Y.log('Serving /files/' + data.name, 'info', 'server'); + + + Server.builder.renderFile(function (html) { + res.send(html); + }, data, (req.xhr ? 'xhr' : 'main')); + }, + /** + * `/classes` endpoint + * @method clazz + * @param {Request} req Express request object + * @param {Response} res Express response object + */ + clazz: function (req, res, next) { + var className = req.params.class; + Y.log('Serving /classes/' + className + '.html', 'info', 'server'); + if (!Server.builder.data.classes[className]) { + return next(); + } + Server.builder.renderClass(function (html) { + res.send(html); + }, Server.builder.data.classes[className], (req.xhr ? 'xhr' : 'main')); + }, + /** + * `/modules` endpoint + * @method modules + * @param {Request} req Express request object + * @param {Response} res Express response object + */ + module: function (req, res, next) { + var modName = req.params.module; + Y.log('Serving /modules/' + modName + '.html', 'info', 'server'); + if (!Server.builder.data.modules[modName]) { + return next(); + } + Server.builder.renderModule(function (html) { + res.send(html); + }, Server.builder.data.modules[modName], (req.xhr ? 'xhr' : 'main')); + }, + /** + * `/` endpoint + * @method home + * @param {Request} req Express request object + * @param {Response} res Express response object + */ + home: function (req, res) { + Y.log('Serving index.html', 'info', 'server'); + Server.builder.renderIndex(function (html) { + res.send(html); + }); + }, + /** + * Creates the Express server and prep's YUI for serving + * @method init + */ + init: function () { + var stat; + + Server.app = express(); + //console.log(Server.options); + stat = Server.options.themedir || path.join(__dirname, '../', 'themes', 'default'); + Server.app.use(express.static(stat)); + Server.routes(); + Server.app.listen(Server.options.port); + + Y.log('Starting server: http:/' + '/127.0.0.1:' + Server.options.port, 'info', 'server'); + }, + /** + * Start the server with the supplied options. + * @method start + * @param {Object} options Server options + */ + start: function (options) { + options = Y.Project.init(options); + Server.options = options; + + Server.options.cacheTemplates = false; //Don't cache the Handlebars templates + Server.options.writeJSON = false; //Don't write the JSON file out + + Y.config.logExclude.yuidoc = true; + Y.config.logExclude.docparser = true; + Y.config.logExclude.builder = true; + + if (Server.options.external) { + Y.log('Fetching external data, this may take a minute', 'warn', 'server'); + var json, builder; + + json = (new Y.YUIDoc(Server.options)).run(); + Server.options = Y.Project.mix(json, Server.options); + + builder = new Y.DocBuilder(Server.options, json); + builder.mixExternal(function () { + Y.log('External data fetched, launching server..', 'info', 'server'); + Server._externalData = builder.options.externalData; Server.init(); - } + }); + + } else { + Server.init(); } - }; + } + }; Y.Server = Server; }); diff --git a/lib/utils.js b/lib/utils.js index 12e7eb99..328a409e 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -3,6 +3,8 @@ * Code licensed under the BSD License: * https://github.com/yui/yuidoc/blob/master/LICENSE */ +'use strict'; + var path = require('path'), minimatch = require('minimatch'), fs = require('graceful-fs'); @@ -22,7 +24,7 @@ YUI.add('utils', function (Y) { '<': '<', '>': '>', '"': '"', - "'": ''', + '\'': ''', '/': '/', '`': '`' }; @@ -225,18 +227,17 @@ YUI.add('utils', function (Y) { /** * Walk the directory tree to locate the yuidoc.json file. * @method getProjectData - * @param {Path} [dir=process.cwd()] The directory to start from + * @param {Path} [directory=process.cwd()] The directory to start from */ - var getProjectData = function (dir) { - var dirs = [dir || process.cwd()]; + var getProjectData = function (directory) { + var dirs = [directory || process.cwd()]; var projectData, packageData; var dirCount = 0; - // keep looping until + // keep looping until // * data is found // * there are no more dirs to process // * we abort due to failsafe while (dirs.length && !projectData) { - /*jshint loopfunc:true */ if (dirCount++ > 5000) { Y.log('Scanned ' + dirCount + ' directories looking for a yuidoc.json file, something is probably wrong here..', 'error', 'yuidoc'); process.exit(1); @@ -380,11 +381,11 @@ YUI.add('utils', function (Y) { if (!Y.Lang.isArray(paths)) { paths = [paths]; } - paths.forEach(function (path) { - var glob = path || ''; + paths.forEach(function (validatePath) { + var glob = validatePath || ''; if (process.platform === 'win32') { - glob = path.replace(/\//g, '\\\\'); + glob = validatePath.replace(/\//g, '\\\\'); } var glob_paths = getDirs('.'), @@ -411,12 +412,14 @@ YUI.add('utils', function (Y) { }); paths = newpaths; - paths.forEach(function (p) { + paths.forEach(function (newPath) { try { - if (!Y.Files.isDirectory(p)) { - throw ('Path not a directory: ' + p); + if (!Y.Files.isDirectory(newPath)) { + throw ('Path not a directory: ' + newPath); } - } catch (e) {} + } catch (e) { + throw new Error(e.message); + } }); if (!paths || !paths.forEach) { @@ -482,7 +485,7 @@ YUI.add('utils', function (Y) { * @param {Array|String*} url the list of parts to be joined and normalized * @return {String} The joined and normalized url **/ - function webpath(url) { + function webpath() { var args = [].concat.apply([], arguments), parts = path.join.apply(path, args).split(/[\\\/]/); return parts.join('/'); diff --git a/lib/yuidoc.js b/lib/yuidoc.js index a6c9f7c6..3c6cc91a 100755 --- a/lib/yuidoc.js +++ b/lib/yuidoc.js @@ -3,9 +3,11 @@ * 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'); +'use strict'; + +var fs = require('graceful-fs'); +var rimraf = require('rimraf'); +var path = require('path'); /** This is the __module__ description for the `YUIDoc` module. @@ -56,7 +58,7 @@ YUI.add('yuidoc', function (Y) { var Y = require('yuidoc'); var json = (new Y.YUIDoc(options)).run(); - + * @class YUIDoc * @module yuidoc * @constructor @@ -246,8 +248,8 @@ YUI.add('yuidoc', function (Y) { }, /** - * Applies preprocessors to the data tree. - * This function first clones the data and operates on the clone. + * 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 @@ -257,14 +259,14 @@ YUI.add('yuidoc', function (Y) { preprocessors, preprocessorsRelativeTo; - // We will try to load the preprocessors as npm modules, but we will also + // 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, + // 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)); + data = JSON.parse(JSON.stringify(data)); preprocessors = [].concat(self.options.preprocessor); @@ -305,9 +307,9 @@ YUI.add('yuidoc', function (Y) { data = this.runPreprocessors(data); if (self.selleck && self.options.selleck && data.files && data.modules) { - Object.keys(self.selleck).forEach(function (file) { + Object.keys(self.selleck).forEach(function (selleckFile) { Object.keys(data.files).forEach(function (f) { - if (file === f) { + if (selleckFile === f) { var mods = data.files[f].modules; if (mods) { Object.keys(mods).forEach(function (mod) { @@ -315,7 +317,7 @@ YUI.add('yuidoc', function (Y) { if (!data.modules[mod].extra) { data.modules[mod].extra = {}; } - data.modules[mod].extra.selleck = self.selleck[file]; + data.modules[mod].extra.selleck = self.selleck[selleckFile]; } }); } @@ -340,16 +342,16 @@ YUI.add('yuidoc', function (Y) { if (!Y.Files.exists(self.options.outdir)) { Y.log('Making out dir: ' + self.options.outdir, 'info', 'yuidoc'); try { - fs.mkdirSync(self.options.outdir, 0777); + fs.mkdirSync(self.options.outdir, '0777'); } catch (e) { Y.log('Outdir creation failed', 'warn', 'yuidoc'); } } out = fs.createWriteStream(file, { - flags: "w", + flags: 'w', encoding: Y.charset, - mode: 0644 + mode: '0644' }); out.write(JSON.stringify(data, null, 4)); out.end(); diff --git a/package.json b/package.json index 5adfd567..116adff2 100644 --- a/package.json +++ b/package.json @@ -78,14 +78,14 @@ "yui": "^3.18.1" }, "devDependencies": { + "eslint": "^0.21.0", "istanbul": "^0.3.5", - "jshint": "^2.6.0", "selleck": "^0.1.18", "ytestrunner": "^0.3.3", "yuitest": "^0.7.9" }, "scripts": { - "pretest": "jshint ./lib/*.js ./tests/*.js", + "pretest": "eslint lib/*.js tests/*.js", "test": "istanbul cover --print=both --yui ytestrunner -- --include ./tests/options.js --include ./tests/builder.js --include ./tests/parser.js --include ./tests/parser_coffee.js --include ./tests/files.js --include ./tests/utils.js --include ./tests/preprocessor.js" }, "preferGlobal": "true", @@ -99,25 +99,6 @@ "type": "git", "url": "http://github.com/yui/yuidoc.git" }, - "jshintConfig": { - "bitwise": true, - "browser": true, - "curly": true, - "eqeqeq": true, - "forin": true, - "immed": true, - "latedef": "nofunc", - "laxbreak": true, - "maxerr": 500, - "maxlen": 150, - "newcap": true, - "noarg": true, - "node": true, - "noempty": true, - "undef": true, - "unused": "vars", - "yui": true - }, "yuidoc": { "name": "YUIDoc", "options": { diff --git a/tests/builder.js b/tests/builder.js index 1de640e3..2ff28f71 100644 --- a/tests/builder.js +++ b/tests/builder.js @@ -1,9 +1,10 @@ -/*global Y:true */ -var YUITest = require('yuitest'), - Assert = YUITest.Assert, - path = require('path'), - fs = require('fs'), - Y = require(path.join(__dirname, '../', 'lib', 'index')); +'use strict'; + +var YUITest = require('yuitest'); +var Assert = YUITest.Assert; +var path = require('path'); +var fs = require('fs'); +var Y = require(path.join(__dirname, '../', 'lib', 'index')); //Move to the test dir before running the tests. process.chdir(__dirname); @@ -33,7 +34,7 @@ var suite = new YUITest.TestSuite({ path.join(__dirname, 'lib/davglass.js') ], markdown: { - langPrefix: "language-" + langPrefix: 'language-' } }; json = (new Y.YUIDoc(options)).run(); diff --git a/tests/files.js b/tests/files.js index df132eae..583d4f62 100644 --- a/tests/files.js +++ b/tests/files.js @@ -1,9 +1,10 @@ -/*global Y:true */ -var YUITest = require('yuitest'), - Assert = YUITest.Assert, - path = require('path'), - fs = require('fs'), - Y = require(path.join(__dirname, '../', 'lib', 'index')); +'use strict'; + +var YUITest = require('yuitest'); +var Assert = YUITest.Assert; +var path = require('path'); +var fs = require('fs'); +var Y = require(path.join(__dirname, '../', 'lib', 'index')); //Move to the test dir before running the tests. process.chdir(__dirname); @@ -168,7 +169,7 @@ suite.add(new YUITest.TestCase({ }, 'test: readFile': function () { var test = this; - Y.Files.readFile('input/test/test.js', 'utf8', function (err, data) { + Y.Files.readFile('input/test/test.js', 'utf8', function (err) { test.resume(function () { Assert.isNull(err); }); diff --git a/tests/options.js b/tests/options.js index 489b1a56..99ee1306 100644 --- a/tests/options.js +++ b/tests/options.js @@ -1,8 +1,9 @@ -/*global Y:true */ -var YUITest = require('yuitest'), - Assert = YUITest.Assert, - path = require('path'), - Y = require(path.join(__dirname, '../', 'lib', 'index')); +'use strict'; + +var YUITest = require('yuitest'); +var Assert = YUITest.Assert; +var path = require('path'); +var Y = require(path.join(__dirname, '../', 'lib', 'index')); //Move to the test dir before running the tests. process.chdir(__dirname); @@ -10,7 +11,7 @@ process.chdir(__dirname); var suite = new YUITest.TestSuite('Options Test Suite'); suite.add(new YUITest.TestCase({ - name: "Server Options", + name: 'Server Options', 'test: server': function () { var options = Y.Options([ '--server' @@ -93,20 +94,20 @@ suite.add(new YUITest.TestCase({ })); suite.add(new YUITest.TestCase({ - name: "Various Options", - "test: long quiet option": function () { + name: 'Various Options', + 'test: long quiet option': function () { var options = Y.Options([ '--quiet' ]); Assert.isTrue(options.quiet, 'Failed to set long quiet'); }, - "test: short quiet option": function () { + 'test: short quiet option': function () { var options = Y.Options([ '-q' ]); Assert.isTrue(options.quiet, 'Failed to set short quiet'); }, - "test: short config": function () { + 'test: short config': function () { var options = Y.Options([ '-c', './foo.json' diff --git a/tests/parser.js b/tests/parser.js index d18e7b5b..df46e7ad 100644 --- a/tests/parser.js +++ b/tests/parser.js @@ -1,10 +1,11 @@ -/*global Y:true */ -var YUITest = require('yuitest'), - Assert = YUITest.Assert, - ArrayAssert = YUITest.ArrayAssert, - path = require('path'), - fs = require('fs'), - Y = require(path.join(__dirname, '../', 'lib', 'index')); +'use strict'; + +var YUITest = require('yuitest'); +var Assert = YUITest.Assert; +var ArrayAssert = YUITest.ArrayAssert; +var path = require('path'); +var fs = require('fs'); +var Y = require(path.join(__dirname, '../', 'lib', 'index')); //Move to the test dir before running the tests. process.chdir(__dirname); @@ -26,7 +27,7 @@ var suite = new YUITest.TestSuite({ }); suite.add(new YUITest.TestCase({ - name: "Project Data", + name: 'Project Data', setUp: function () { this.project = suite.project; this.data = suite.data; @@ -254,12 +255,12 @@ suite.add(new YUITest.TestCase({ Assert.areSame('', item.evil, 'Single tag not found'); Assert.areSame('HTML', item.injects.type, 'Injection type not found'); - Assert.isUndefined(item["return"].type, 'Type should be missing'); + Assert.isUndefined(item.return.type, 'Type should be missing'); Assert.isUndefined(item.throws.type, 'Type should be missing'); Assert.areSame(2, item.example.length, 'Should have 2 example snippets'); item2 = this.findByName('testobjectparam', 'myclass'); - Assert.areSame('String', item2["return"].type, 'Type should not be missing'); + Assert.areSame('String', item2.return.type, 'Type should not be missing'); Assert.areSame('Error', item2.throws.type, 'Type should not be missing'); }, 'test: parameter parsing': function () { @@ -291,7 +292,7 @@ suite.add(new YUITest.TestCase({ Assert.areSame(1, item2.params.length, 'Failed to parse all 5 parameters'); Assert.isTrue(item2.params[0].optional, 'Optional not set'); Assert.isTrue(item2.params[0].multiple, 'Multiple not set'); - Assert.isUndefined(item2["return"].type, 'Type should be missing'); + Assert.isUndefined(item2.return.type, 'Type should be missing'); Assert.isUndefined(item2.throws.type, 'Type should be missing'); item2 = this.findByName('test1ton', 'myclass'); @@ -299,7 +300,7 @@ suite.add(new YUITest.TestCase({ Assert.areSame(1, item2.params.length, 'Failed to parse all 5 parameters'); Assert.isUndefined(item2.params[0].optional, 'Optional should not be set'); Assert.isTrue(item2.params[0].multiple, 'Multiple not set'); - Assert.isUndefined(item2["return"].type, 'Type should be missing'); + Assert.isUndefined(item2.return.type, 'Type should be missing'); Assert.isUndefined(item2.throws.type, 'Type should be missing'); item3 = this.findByName('testrestparam0n', 'myclass'); @@ -307,7 +308,7 @@ suite.add(new YUITest.TestCase({ Assert.areSame(1, item3.params.length, 'Failed to parse all 5 parameters'); Assert.isTrue(item3.params[0].optional, 'Optional not set'); Assert.isTrue(item3.params[0].multiple, 'Multiple not set'); - Assert.isUndefined(item3['return'].type, 'Type should be missing'); + Assert.isUndefined(item3.return.type, 'Type should be missing'); Assert.isUndefined(item3.throws.type, 'Type should be missing'); item4 = this.findByName('testrestparam1n', 'myclass'); @@ -315,7 +316,7 @@ suite.add(new YUITest.TestCase({ Assert.areSame(1, item4.params.length, 'Failed to parse all 5 parameters'); Assert.isUndefined(item4.params[0].optional, 'Optional should not be set'); Assert.isTrue(item4.params[0].multiple, 'Multiple not set'); - Assert.isUndefined(item4['return'].type, 'Type should be missing'); + Assert.isUndefined(item4.return.type, 'Type should be missing'); Assert.isUndefined(item4.throws.type, 'Type should be missing'); item = this.findByName('testNewlineBeforeDescription', 'myclass'); @@ -339,10 +340,10 @@ suite.add(new YUITest.TestCase({ 'test: indented description': function () { var item = this.findByName('testNewlineBeforeDescription', 'myclass'); - Assert.areSame('Boolean', item['return'].type, 'Type should be correct.'); + Assert.areSame('Boolean', item.return.type, 'Type should be correct.'); Assert.areSame( 'Sometimes true, sometimes false.\nNobody knows!', - item['return'].description, + item.return.description, 'Description indentation should be normalized to the first line.' ); Assert.areSame('Error', item.throws.type, 'Type should be correct.'); @@ -377,7 +378,7 @@ suite.add(new YUITest.TestCase({ var item = this.findByName('testoptional', 'myclass'); Assert.isObject(item, 'failed to find item'); - Assert.isNotUndefined(item["return"], 'Failed to replace returns with return'); + Assert.isNotUndefined(item.return, 'Failed to replace returns with return'); item = this.findByName('_positionChangeHandler', 'Axis'); Assert.isObject(item, 'failed to find item'); diff --git a/tests/parser_coffee.js b/tests/parser_coffee.js index b1d137aa..d95f2011 100644 --- a/tests/parser_coffee.js +++ b/tests/parser_coffee.js @@ -1,8 +1,9 @@ -/*global Y:true */ -var YUITest = require('yuitest'), - Assert = YUITest.Assert, - path = require('path'), - Y = require(path.join(__dirname, '../', 'lib', 'index')); +'use strict'; + +var YUITest = require('yuitest'); +var Assert = YUITest.Assert; +var path = require('path'); +var Y = require(path.join(__dirname, '../', 'lib', 'index')); //Move to the test dir before running the tests. process.chdir(__dirname); diff --git a/tests/preprocessor.js b/tests/preprocessor.js index ab78ea68..d6fd3ca8 100644 --- a/tests/preprocessor.js +++ b/tests/preprocessor.js @@ -1,9 +1,10 @@ -/*global Y:true */ -var YUITest = require('yuitest'), - Assert = YUITest.Assert, - path = require('path'), - fs = require('fs'), - Y = require(path.join(__dirname, '../', 'lib', 'index')); +'use strict'; + +var YUITest = require('yuitest'); +var Assert = YUITest.Assert; +var path = require('path'); +var fs = require('fs'); +var Y = require(path.join(__dirname, '../', 'lib', 'index')); //Move to the test dir before running the tests. process.chdir(__dirname); @@ -16,9 +17,9 @@ var suite = new YUITest.TestSuite({ }); suite.add(new YUITest.TestCase({ - name: "Preprocessor", + name: 'Preprocessor', 'test: single preprocessor': function () { - global.testPreprocessorCallCount=0; + global.testPreprocessorCallCount = 0; var json = (new Y.YUIDoc({ quiet: true, @@ -28,33 +29,33 @@ suite.add(new YUITest.TestCase({ })).run(); Assert.isObject(json); - Assert.areSame(global.testPreprocessorCallCount,1,"the preprocessor was not called"); + Assert.areSame(global.testPreprocessorCallCount, 1, 'the preprocessor was not called'); }, 'test: single preprocessor with absolute path': function () { - global.testPreprocessorCallCount=0; + global.testPreprocessorCallCount = 0; var json = (new Y.YUIDoc({ quiet: true, paths: ['input/preprocessor'], outdir: './out', - preprocessor: path.join(process.cwd(),'/lib/testpreprocessor.js') + preprocessor: path.join(process.cwd(), '/lib/testpreprocessor.js') })).run(); Assert.isObject(json); - Assert.areSame(global.testPreprocessorCallCount,1,"the preprocessor was not called when an absolute path was used"); + Assert.areSame(global.testPreprocessorCallCount, 1, 'the preprocessor was not called when an absolute path was used'); }, 'test: several preprocessors': function () { - global.testPreprocessorCallCount=0; + global.testPreprocessorCallCount = 0; var json = (new Y.YUIDoc({ quiet: true, paths: ['input/preprocessor'], outdir: './out', - preprocessor: ['lib/testpreprocessor.js','./lib/testpreprocessor'] + preprocessor: ['lib/testpreprocessor.js', './lib/testpreprocessor'] })).run(); Assert.isObject(json); - Assert.areSame(global.testPreprocessorCallCount,2,"the preprocessor was not called twice"); + Assert.areSame(global.testPreprocessorCallCount, 2, 'the preprocessor was not called twice'); }, 'test: the test preprocessor does its job': function () { var json = (new Y.YUIDoc({ @@ -62,24 +63,24 @@ suite.add(new YUITest.TestCase({ paths: ['input/preprocessor'], outdir: './out', preprocessor: 'lib/testpreprocessor.js', - star: "#" + star: '#' })).run(); Assert.isObject(json); - Assert.areSame(json.classes.TestPreprocessor.customtagPlusStar,"hello#","the preprocessor did not modify the data"); + Assert.areSame(json.classes.TestPreprocessor.customtagPlusStar, 'hello#', 'the preprocessor did not modify the data'); }, 'test: load preprocessor as a npm module': function () { // We are testing if it works to load the preprocessor from node_modules, // so first we need to copy it in place. - if (!fs.existsSync("../node_modules/testpreprocessormodule")) { - fs.mkdirSync("../node_modules/testpreprocessormodule"); + if (!fs.existsSync('../node_modules/testpreprocessormodule')) { + fs.mkdirSync('../node_modules/testpreprocessormodule'); } - fs.writeFileSync("../node_modules/testpreprocessormodule/package.json", - fs.readFileSync("lib/testpreprocessormodule/package.json")); + fs.writeFileSync('../node_modules/testpreprocessormodule/package.json', + fs.readFileSync('lib/testpreprocessormodule/package.json')); - fs.writeFileSync("../node_modules/testpreprocessormodule/testpreprocessormodule.js", - fs.readFileSync("lib/testpreprocessormodule/testpreprocessormodule.js")); + fs.writeFileSync('../node_modules/testpreprocessormodule/testpreprocessormodule.js', + fs.readFileSync('lib/testpreprocessormodule/testpreprocessormodule.js')); var json = (new Y.YUIDoc({ quiet: true, @@ -89,12 +90,12 @@ suite.add(new YUITest.TestCase({ })).run(); Assert.isObject(json); - Assert.isTrue(json.testModuleWasHere,"the preprocesor module was not run"); + Assert.isTrue(json.testModuleWasHere, 'the preprocesor module was not run'); // Clean up things when we are done. - fs.unlinkSync("../node_modules/testpreprocessormodule/package.json"); - fs.unlinkSync("../node_modules/testpreprocessormodule/testpreprocessormodule.js"); - fs.rmdirSync("../node_modules/testpreprocessormodule"); + fs.unlinkSync('../node_modules/testpreprocessormodule/package.json'); + fs.unlinkSync('../node_modules/testpreprocessormodule/testpreprocessormodule.js'); + fs.rmdirSync('../node_modules/testpreprocessormodule'); } })); diff --git a/tests/utils.js b/tests/utils.js index 6e1c5a5f..2b915a57 100644 --- a/tests/utils.js +++ b/tests/utils.js @@ -1,8 +1,9 @@ -/*global Y:true */ -var YUITest = require('yuitest'), - Assert = YUITest.Assert, - path = require('path'), - Y = require(path.join(__dirname, '../', 'lib', 'index')); +'use strict'; + +var YUITest = require('yuitest'); +var Assert = YUITest.Assert; +var path = require('path'); +var Y = require(path.join(__dirname, '../', 'lib', 'index')); var suite = new YUITest.TestSuite({ name: 'Utils Test Suite' @@ -78,15 +79,15 @@ suite.add(new YUITest.TestCase({ suite.add(new YUITest.TestCase({ name: 'produce valid web urls', - 'test: Adds paths onto end in sequence' : function() { + 'test: Adds paths onto end in sequence': function() { var url = Y.webpath('foo', 'bar', 'baz'); Assert.areEqual('foo/bar/baz', url, 'parts should be added in sequence'); }, - 'test: normalises windows paths into web happy urls' : function() { + 'test: normalises windows paths into web happy urls': function() { var url = Y.webpath('foo\\bar', 'baz'); Assert.areEqual('foo/bar/baz', url, '\\ should be normalised to /'); }, - 'test: joins relative paths' : function() { + 'test: joins relative paths': function() { var url = Y.webpath('./foo/bar', './baz/'); Assert.areEqual('foo/bar/baz/', url, 'should join relative paths'); }