From 683e11593e282a11484ba502bcf0b0c220b3fa66 Mon Sep 17 00:00:00 2001 From: Michael Mathews Date: Tue, 18 Jan 2011 20:05:57 +0000 Subject: [PATCH] Added better support for documenting module members via @exports and @requires. --- modules/jsdoc/src/parser.js | 6 +++-- modules/jsdoc/tag/dictionary/definitions.js | 22 ++++++++++++++++- test/cases/exportstag.js | 20 +++++++++++++++ test/cases/exportstag2.js | 18 ++++++++++++++ test/runner.js | 3 +++ test/t/cases/exportstag.js | 27 +++++++++++++++++++++ test/t/cases/exportstag2.js | 22 +++++++++++++++++ test/t/cases/requirestag.js | 6 ++--- 8 files changed, 118 insertions(+), 6 deletions(-) create mode 100644 test/cases/exportstag.js create mode 100644 test/cases/exportstag2.js create mode 100644 test/t/cases/exportstag.js create mode 100644 test/t/cases/exportstag2.js diff --git a/modules/jsdoc/src/parser.js b/modules/jsdoc/src/parser.js index a1b4e1aa..72f432ac 100644 --- a/modules/jsdoc/src/parser.js +++ b/modules/jsdoc/src/parser.js @@ -146,10 +146,12 @@ memberof.id = 'astnode'+astnode.enclosingFunction.hashCode(); memberof.doclet = this.refs[memberof.id]; - if (!memberof.doclet) return '[[anonymous]]'; // TODO handle global this? + if (!memberof.doclet) { + return '[[anonymous]]'; // TODO handle global this? + } // walk up to the closest @constructor we can find - if (memberof.doclet.kind === 'constructor') { + if (memberof.doclet.kind === 'constructor' || memberof.doclet.kind === 'module') { return memberof.doclet.longname||memberof.doclet.name; } else { diff --git a/modules/jsdoc/tag/dictionary/definitions.js b/modules/jsdoc/tag/dictionary/definitions.js index a1d7e7bd..bcf9a467 100644 --- a/modules/jsdoc/tag/dictionary/definitions.js +++ b/modules/jsdoc/tag/dictionary/definitions.js @@ -93,6 +93,22 @@ } }); + dictionary.defineTag('exports', { + mustHaveValue: true, + onTagged: function(doclet, tag) { + var modName = firstWordOf(tag.value); + + if ( modName.indexOf('module:') !== 0) { + modName = 'module:'+modName; + } + + doclet.addTag('alias', modName); + doclet.addTag('kind', 'module'); + + return false; + } + }); + dictionary.defineTag('deprecated', { // value is optional onTagged: function(doclet, tag) { @@ -333,8 +349,12 @@ dictionary.defineTag('requires', { mustHaveValue: true, onTagged: function(doclet, tag) { + var modName = firstWordOf(tag.value); + if (modName.indexOf('module:') !== 0) { + modName = 'module:'+modName; + } if (!doclet.requires) { doclet.requires = []; } - doclet.requires.push( firstWordOf(tag.value) ); + doclet.requires.push(modName); return true; } diff --git a/test/cases/exportstag.js b/test/cases/exportstag.js new file mode 100644 index 00000000..26f787ea --- /dev/null +++ b/test/cases/exportstag.js @@ -0,0 +1,20 @@ +define(function () { + /** + A module representing a shirt. + @exports my/shirt + @version 1.0 + */ + var shirt = { + + /** A property of the module. */ + color: "black", + + /** @constructor */ + Turtleneck: function(size) { + /** A property of the class. */ + this.size = size; + } + }; + + return shirt; +}); \ No newline at end of file diff --git a/test/cases/exportstag2.js b/test/cases/exportstag2.js new file mode 100644 index 00000000..5e00268a --- /dev/null +++ b/test/cases/exportstag2.js @@ -0,0 +1,18 @@ +define( + ["my/buttons"], + function () { + /** + A module representing a coat. + @exports my/coat + @requires my/buttons + @version 1.0 + */ + var myModule = function(wool) { + /** document me */ + this.wool = wool; + } + + return myModule; + + } +); \ No newline at end of file diff --git a/test/runner.js b/test/runner.js index f970f6b5..74089d5c 100644 --- a/test/runner.js +++ b/test/runner.js @@ -95,6 +95,8 @@ testFile('test/t/cases/authortag.js'); testFile('test/t/cases/classtag.js'); testFile('test/t/cases/copyrighttag.js'); testFile('test/t/cases/deprecatedtag.js'); +testFile('test/t/cases/exportstag.js'); +testFile('test/t/cases/exportstag2.js'); testFile('test/t/cases/exceptiontag.js'); testFile('test/t/cases/globaltag.js'); testFile('test/t/cases/ignoretag.js'); @@ -109,5 +111,6 @@ testFile('test/t/cases/sincetag.js'); testFile('test/t/cases/typetag.js'); testFile('test/t/cases/versiontag.js'); + report(); diff --git a/test/t/cases/exportstag.js b/test/t/cases/exportstag.js new file mode 100644 index 00000000..9114a39b --- /dev/null +++ b/test/t/cases/exportstag.js @@ -0,0 +1,27 @@ +(function() { + var docSet = testhelpers.getDocSetFromFile('test/cases/exportstag.js'), + shirt = docSet.getByLongname('module:my/shirt')[0], + color = docSet.getByLongname('module:my/shirt.color')[0], + tneck = docSet.getByLongname('module:my/shirt.Turtleneck')[0], + size = docSet.getByLongname('module:my/shirt.Turtleneck#size')[0]; + + //dump(docSet.doclets); exit(0); + + test('When an objlit symbol has an @exports tag, the doclet is aliased to "module:" + the tag value.', function() { + assert.equal(typeof shirt, 'object'); + assert.equal(shirt.alias, 'module:my/shirt'); + }); + + test('When an objlit symbol has an @exports tag, the doclet kind is set to module.', function() { + assert.equal(shirt.kind, 'module'); + }); + + test('When an objlit symbol has an @exports tag, the objlit members are documented as members of the module.', function() { + assert.equal(typeof color, 'object'); + assert.equal(color.memberof, 'module:my/shirt'); + + assert.equal(typeof tneck, 'object'); + assert.equal(typeof size, 'object'); + }); + +})(); \ No newline at end of file diff --git a/test/t/cases/exportstag2.js b/test/t/cases/exportstag2.js new file mode 100644 index 00000000..62472aef --- /dev/null +++ b/test/t/cases/exportstag2.js @@ -0,0 +1,22 @@ +(function() { + var docSet = testhelpers.getDocSetFromFile('test/cases/exportstag2.js'), + coat = docSet.getByLongname('module:my/coat')[0], + wool = docSet.getByLongname('module:my/coat#wool')[0]; + + //dump(docSet.doclets); exit(0); + + test('When a function symbol has an @exports tag, the doclet is aliased to "module:" + the tag value.', function() { + assert.equal(typeof coat, 'object'); + assert.equal(coat.alias, 'module:my/coat'); + }); + + test('When a function symbol has an @exports tag, the doclet kind is set to module.', function() { + assert.equal(coat.kind, 'module'); + }); + + test('When a function symbol has an @exports tag, the this members are documented as instance members of the module.', function() { + assert.equal(typeof wool, 'object'); + assert.equal(wool.memberof, 'module:my/coat'); + }); + +})(); \ No newline at end of file diff --git a/test/t/cases/requirestag.js b/test/t/cases/requirestag.js index 86efe4ca..de4537d5 100644 --- a/test/t/cases/requirestag.js +++ b/test/t/cases/requirestag.js @@ -5,13 +5,13 @@ //dump(docSet.doclets); exit(0); - test('When a symbol has an @requires tag, the doclet has a requires property that includes that value.', function() { + test('When a symbol has an @requires tag, the doclet has a requires property that includes that value, with the "module:" namespace added.', function() { assert.equal(typeof foo.requires, 'object'); assert.equal(foo.requires[0], 'module:foo/helper'); assert.equal(typeof bar.requires, 'object'); - assert.equal(bar.requires[0], 'foo'); - assert.equal(bar.requires[1], 'Pez#blat'); + assert.equal(bar.requires[0], 'module:foo'); + assert.equal(bar.requires[1], 'module:Pez#blat'); }); })(); \ No newline at end of file