From f16fa3beb75499b7266946fe3d1ef212ec34f83d Mon Sep 17 00:00:00 2001 From: Jeff Williams Date: Fri, 15 Feb 2013 21:17:40 -0800 Subject: [PATCH 1/5] use a 'range' property in parser events rather than 'linelength' and 'absposition' (#346) --- lib/jsdoc/src/parser.js | 37 ++++++++++++++++++------------------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/lib/jsdoc/src/parser.js b/lib/jsdoc/src/parser.js index 9e205655..f08821fd 100644 --- a/lib/jsdoc/src/parser.js +++ b/lib/jsdoc/src/parser.js @@ -300,6 +300,20 @@ function getBasename(name) { return name; } +/** @private + * @memberof module:src/parser.Parser + * @param {object} node + * @return {Array.} Start and end lines. + */ +function getRange(node) { + var range = []; + + range[0] = parseInt(String(node.getAbsolutePosition()), 10); + range[1] = range[0] + parseInt(String(node.getLength()), 10); + + return range; +} + /** @private * @memberof module:src/parser.Parser */ @@ -312,17 +326,7 @@ exports.Parser.prototype._makeEvent = function(node, extras) { id: extras.id || 'astnode' + node.hashCode(), comment: extras.comment || String(node.getJsDoc() || '@undocumented'), lineno: extras.lineno || node.left.getLineno(), - range: (function() { - var range = []; - if (extras.range) { - range = extras.range; - } - else { - range[0] = parseInt(String(node.getAbsolutePosition()), 10); - range[1] = range[0] + parseInt(String(node.getLength()), 10); - } - return range; - })(), + range: extras.range || getRange(node), filename: extras.filename || this._currentSourceName, astnode: extras.astnode || node, code: extras.code || aboutNode(node), @@ -388,8 +392,7 @@ exports.Parser.prototype._visitNode = function(node) { comment: commentSrc, lineno: comment.getLineno(), filename: this._currentSourceName, - linelength: comment.getLength(), - absposition: comment.getAbsolutePosition() + range: getRange(comment) }; this.emit('jsdocCommentFound', e, this); @@ -432,9 +435,7 @@ exports.Parser.prototype._visitNode = function(node) { } extras = { - lineno: node.getLineno(), - linelength: node.getLength(), - absposition: node.getAbsolutePosition() + lineno: node.getLineno() }; e = this._makeEvent(node, extras); @@ -442,9 +443,7 @@ exports.Parser.prototype._visitNode = function(node) { } else if (node.type == Token.FUNCTION || node.type == tkn.NAMEDFUNCTIONSTATEMENT) { extras = { - lineno: node.getLineno(), - linelength: node.getLength(), - absposition: node.getAbsolutePosition() + lineno: node.getLineno() }; e = this._makeEvent(node, extras); From e553dad941ec2a6c9986546d9098f10f35799880 Mon Sep 17 00:00:00 2001 From: Jeff Williams Date: Fri, 15 Feb 2013 21:32:57 -0800 Subject: [PATCH 2/5] add `@emits` as a synonym for `@fires` (#324) --- lib/jsdoc/tag/dictionary/definitions.js | 3 ++- test/fixtures/eventfirestag.js | 12 +++++++++++ test/specs/tags/eventfirestag.js | 27 ++++++++++++++++--------- 3 files changed, 31 insertions(+), 11 deletions(-) diff --git a/lib/jsdoc/tag/dictionary/definitions.js b/lib/jsdoc/tag/dictionary/definitions.js index db3ca55f..59a66113 100644 --- a/lib/jsdoc/tag/dictionary/definitions.js +++ b/lib/jsdoc/tag/dictionary/definitions.js @@ -349,7 +349,8 @@ exports.defineTags = function(dictionary) { applyNamespace('event', tag); doclet.fires.push(tag.value); } - }); + }) + .synonym('emits'); dictionary.defineTag('function', { onTagged: function(doclet, tag) { diff --git a/test/fixtures/eventfirestag.js b/test/fixtures/eventfirestag.js index 4fe3e746..331eaf8c 100644 --- a/test/fixtures/eventfirestag.js +++ b/test/fixtures/eventfirestag.js @@ -16,3 +16,15 @@ Hurl.prototype.snowball = function () { */ this.emit('snowball', {}); }; + +/** + * Throw a football match. + * + * @emits Hurl#footballMatch + */ +Hurl.prototype.footballMatch = function () { + /** + * @event Hurl#footballMatch + */ + this.emit('footballMatch', {}); +}; diff --git a/test/specs/tags/eventfirestag.js b/test/specs/tags/eventfirestag.js index 13b37402..55d86f4a 100644 --- a/test/specs/tags/eventfirestag.js +++ b/test/specs/tags/eventfirestag.js @@ -1,23 +1,30 @@ -describe("@event and @fires tags", function() { +/*global describe: true, expect: true, it: true, jasmine: true */ +describe('@event and @fires/@emits tags', function() { var docSet = jasmine.getDocSetFromFile('test/fixtures/eventfirestag.js'), snowballMethod = docSet.getByLongname('Hurl#snowball')[0], - snowballEvent = docSet.getByLongname('Hurl#event:snowball')[0]; + snowballEvent = docSet.getByLongname('Hurl#event:snowball')[0], + footballMatchMethod = docSet.getByLongname('Hurl#footballMatch')[0]; // @event tag it('When a symbol has an @event tag, the doclet is of kind "event".', function() { - expect(snowballEvent.kind).toEqual('event'); + expect(snowballEvent.kind).toBe('event'); }); - // @fires tag + // @fires/@emits tag it('When a symbol has a @fires tag, the doclet has an array named "fires".', function() { - expect(typeof snowballMethod.fires).toEqual('object'); + expect(typeof snowballMethod.fires).toBe('object'); }); - it('When a symbol has a fires array, the members have the event namespace.', function() { - expect(snowballMethod.fires[0]).toEqual('Hurl#event:snowball'); + it('When a symbol has an @emits tag, the doclet has an array named "fires".', function() { + expect(typeof footballMatchMethod.fires).toBe('object'); }); - it('When a symbol has a fires array with a name that already has an event: namespace, it doesn\'t have a secong namespace applied.', function() { - expect(snowballMethod.fires[1]).toEqual('Hurl#event:brick'); + it('When a symbol has a "fires" array, the members have the "event:" namespace.', function() { + expect(snowballMethod.fires[0]).toBe('Hurl#event:snowball'); }); -}); \ No newline at end of file + + it('When a symbol has a "fires" array with a name that already has an "event:" namespace, ' + + 'it does not have a second namespace applied.', function() { + expect(snowballMethod.fires[1]).toBe('Hurl#event:brick'); + }); +}); From ef9660119f88695455ed302a333f928e47d39fda Mon Sep 17 00:00:00 2001 From: Gergely Aradszki Date: Sun, 17 Feb 2013 14:54:09 +0100 Subject: [PATCH 3/5] Merge source includes with command line arguments *before* checking for README.md and package.json. Allows to set these in configs source.includes. --- jsdoc.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/jsdoc.js b/jsdoc.js index 553297e1..480b3f88 100644 --- a/jsdoc.js +++ b/jsdoc.js @@ -179,6 +179,10 @@ function main() { if (env.conf.plugins) { plugins.installPlugins(env.conf.plugins, app.jsdoc.parser); } + + if (env.conf.source && env.conf.source.include) { + env.opts._ = (env.opts._ || []).concat(env.conf.source.include); + } // any source file named package.json or README.md is treated special for (i = 0, l = env.opts._.length; i < l; i++ ) { @@ -193,10 +197,6 @@ function main() { } } - if (env.conf.source && env.conf.source.include) { - env.opts._ = (env.opts._ || []).concat(env.conf.source.include); - } - if (env.conf.source && env.opts._.length > 0) { // are there any files to scan and parse? filter = new Filter(env.conf.source); From 9d13a1e6bbf8d583d60ce41fa3a8e7e8658e93ec Mon Sep 17 00:00:00 2001 From: Jeff Williams Date: Mon, 18 Feb 2013 21:30:17 -0800 Subject: [PATCH 4/5] allow JSDoc to run from a path containing one or more spaces (#347) --- lib/jsdoc/util/vm.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/jsdoc/util/vm.js b/lib/jsdoc/util/vm.js index 61279b14..eb7048b1 100644 --- a/lib/jsdoc/util/vm.js +++ b/lib/jsdoc/util/vm.js @@ -58,7 +58,7 @@ var vm = exports.vm = (function() { * @return {object} An object containing VM-specific functions for the requested module. */ exports.getModule = function(modulePath) { - modulePath = [__dirname, vm, modulePath].join('/'); + modulePath = [__dirname, vm, modulePath].join('/').replace(/ /g, '%20'); if (os.platform() === 'win32') { modulePath = pathToUri(modulePath); } From dfe917a35a78e3e7cebdca8e6cae3ae5b59a7c61 Mon Sep 17 00:00:00 2001 From: Jeff Williams Date: Tue, 19 Feb 2013 07:02:08 -0800 Subject: [PATCH 5/5] generate human-readable filenames (#339) --- lib/jsdoc/util/templateHelper.js | 25 +++++++++++++++---------- test/specs/jsdoc/util/templateHelper.js | 10 ++++++---- 2 files changed, 21 insertions(+), 14 deletions(-) diff --git a/lib/jsdoc/util/templateHelper.js b/lib/jsdoc/util/templateHelper.js index 94867bc4..ef036c1a 100644 --- a/lib/jsdoc/util/templateHelper.js +++ b/lib/jsdoc/util/templateHelper.js @@ -3,7 +3,6 @@ * @module jsdoc/util/templateHelper */ -var crypto = require('crypto'); var dictionary = require('jsdoc/tag/dictionary'); var util = require('util'); @@ -14,7 +13,6 @@ var files = {}; // each container gets its own html file var containers = ['class', 'module', 'external', 'namespace', 'mixin']; -/** @external {jsdoc.tutorial.Tutorial} */ var tutorials; /** Sets tutorials map. @@ -68,18 +66,25 @@ var nsprefix = /^(event|module|external):/; * @return {string} The filename to use for the string. */ var getUniqueFilename = exports.getUniqueFilename = function(str) { - var result; - // allow for namespace prefix - var basename = str.replace(nsprefix, '$1-'); + var basename = str.replace(nsprefix, '$1-') + // and use - instead of ~ to denote 'inner' + .replace(/~/g, '-'); - if ( /[^$a-z0-9._\-]/i.test(basename) ) { - result = crypto.createHash('sha1').update(str).digest('hex').substr(0, 10); - } else { - result = makeFilenameUnique(basename, str); + // if the basename includes characters that we can't use in a filepath, remove everything up to + // and including the last bad character + var regexp = /[^$a-z0-9._\-](?=[$a-z0-9._\-]*$)/i; + var result = regexp.exec(basename); + if (result && result.index) { + basename = basename.substr(result.index + 1); } - return result + exports.fileExtension; + // make sure we don't create hidden files on POSIX systems + basename = basename.replace(/^\./, ''); + // and in case we've now stripped the entire basename (uncommon, but possible): + basename = basename.length ? basename : '_'; + + return makeFilenameUnique(basename, str) + exports.fileExtension; }; // two-way lookup diff --git a/test/specs/jsdoc/util/templateHelper.js b/test/specs/jsdoc/util/templateHelper.js index 41ee1c15..54bd9a55 100644 --- a/test/specs/jsdoc/util/templateHelper.js +++ b/test/specs/jsdoc/util/templateHelper.js @@ -140,14 +140,16 @@ describe("jsdoc/util/templateHelper", function() { // disabled because Jasmine appears to execute this code twice, which causes getUniqueFilename // to return an unexpected variation on the name the second time xdescribe("getUniqueFilename", function() { + // TODO: needs more tests for unusual values and things that get special treatment (such as + // inner members) it('should convert a simple string into the string plus the default extension', function() { var filename = helper.getUniqueFilename('BackusNaur'); expect(filename).toEqual('BackusNaur.html'); }); - it('should convert a string with slashes into an alphanumeric hash plus the default extension', function() { + it('should convert a string with slashes into the text following the last slash plus the default extension', function() { var filename = helper.getUniqueFilename('tick/tock'); - expect(filename).toMatch(/^[A-Za-z0-9]+\.html$/); + expect(filename).toMatch(/^tock\.html$/); }); it('should not return the same filename twice', function() { @@ -743,7 +745,7 @@ describe("jsdoc/util/templateHelper", function() { expect(newUrl).toEqual(nestedNamespaceUrl); }); - it('should create a url for a name with invalid characters using a digest.', function() { + it('should create a url for a name with invalid characters.', function() { var mockDoclet = { kind: 'function', longname: 'ns1."!"."*foo"', @@ -752,7 +754,7 @@ describe("jsdoc/util/templateHelper", function() { }, url = helper.createLink(mockDoclet); - expect(url).toEqual('be9d9563a3.html#"*foo"'); + expect(url).toEqual('_.html#"*foo"'); }); }); });