diff --git a/lib/jsdoc/src/astnode.js b/lib/jsdoc/src/astnode.js index d9e6980d..626796e8 100644 --- a/lib/jsdoc/src/astnode.js +++ b/lib/jsdoc/src/astnode.js @@ -206,6 +206,16 @@ var nodeToValue = exports.nodeToValue = function(node) { parent.parent.type === Syntax.ExportDefaultDeclaration) { str = 'module.exports'; } + // for the constructor of a module's named export, use the name of the export + // declaration + else if (node.kind === 'constructor' && parent.parent && + parent.parent.type === Syntax.ExportNamedDeclaration) { + str = nodeToValue(parent.parent); + } + // for other constructors, use the name of the parent class + else if (node.kind === 'constructor') { + str = nodeToValue(parent); + } // if the method is a member of a module's default export, ignore the name, because it's // irrelevant else if (parent.parent && parent.parent.type === Syntax.ExportDefaultDeclaration) { diff --git a/lib/jsdoc/src/visitor.js b/lib/jsdoc/src/visitor.js index fa6a4d38..c1bef156 100644 --- a/lib/jsdoc/src/visitor.js +++ b/lib/jsdoc/src/visitor.js @@ -296,7 +296,18 @@ function makeDefaultParamFinisher(parser) { function makeConstructorFinisher(parser) { return function(e) { var doclet = e.doclet; - var parentDoclet = parser._getDocletById(e.code.node.parent.parent.nodeId); + var parentDoclet; + + // for class declarations that are named module exports, the node that's documented is the + // ExportNamedDeclaration, not the ClassDeclaration + if (e.code.node.parent.parent.parent && + e.code.node.parent.parent.parent.type === Syntax.ExportNamedDeclaration) { + parentDoclet = parser._getDocletById(e.code.node.parent.parent.parent.nodeId); + } + // otherwise, we want the ClassDeclaration + else { + parentDoclet = parser._getDocletById(e.code.node.parent.parent.nodeId); + } if (!doclet || !parentDoclet || parentDoclet.undocumented) { return; diff --git a/test/fixtures/moduletag11.js b/test/fixtures/moduletag11.js index 464e6a88..65a97aab 100644 --- a/test/fixtures/moduletag11.js +++ b/test/fixtures/moduletag11.js @@ -5,6 +5,8 @@ /** Test class. */ export class Foo { + /** Test class constructor. */ + constructor() {} /** Test method. */ testMethod() {} diff --git a/test/specs/tags/classtag.js b/test/specs/tags/classtag.js index 0dbad196..f7dda38d 100644 --- a/test/specs/tags/classtag.js +++ b/test/specs/tags/classtag.js @@ -14,63 +14,61 @@ describe('@class tag', function() { expect(news.longname).toBe('NewsSource'); }); - if (jasmine.jsParser !== 'rhino') { - describe('ES 2015 classes', function() { - var docSet2 = jasmine.getDocSetFromFile('test/fixtures/classtag2.js'); - var subscription = docSet2.getByLongname('Subscription')[0]; - var expire = docSet2.getByLongname('Subscription#expire')[0]; - var subscriber = docSet2.getByLongname('Subscriber')[0]; - var hasCallback = docSet2.getByLongname('Subscriber#hasCallback')[0]; - var expiringSubscription = docSet2.getByLongname('subclasses.ExpiringSubscription')[0]; - var invalidSubscriptionFoo = docSet2.getByLongname('subclasses.InvalidSubscription#foo')[0]; + describe('ES 2015 classes', function() { + var docSet2 = jasmine.getDocSetFromFile('test/fixtures/classtag2.js'); + var subscription = docSet2.getByLongname('Subscription')[0]; + var expire = docSet2.getByLongname('Subscription#expire')[0]; + var subscriber = docSet2.getByLongname('Subscriber')[0]; + var hasCallback = docSet2.getByLongname('Subscriber#hasCallback')[0]; + var expiringSubscription = docSet2.getByLongname('subclasses.ExpiringSubscription')[0]; + var invalidSubscriptionFoo = docSet2.getByLongname('subclasses.InvalidSubscription#foo')[0]; - it('When a symbol is a class declaration, the doclet does not require the @class tag', function() { - expect(subscription.kind).toBe('class'); - expect(subscription.name).toBe('Subscription'); - expect(subscription.classdesc).toBe('Describe the Subscription class here.'); - }); - - it('When a symbol is a class declaration, the constructor info is merged into the doclet for the symbol', function() { - expect(subscription.description).toBe('Describe the constructor here.'); - expect(subscription.params.length).toBe(1); - expect(subscription.params[0].name).toBe('name'); - }); - - it('When a symbol is a class declaration, its members get the correct longname and memberof', function() { - expect(expire.kind).toBe('function'); - expect(expire.name).toBe('expire'); - expect(expire.memberof).toBe('Subscription'); - }); - - it('When a symbol is a class expression, the doclet does not require the @class tag', function() { - expect(subscriber.kind).toBe('class'); - expect(subscriber.name).toBe('Subscriber'); - expect(subscriber.classdesc).toBe('Describe the Subscriber class here.'); - }); - - it('When a symbol is a class expression, the constructor info is merged into the doclet for the symbol', function() { - expect(subscriber.description).toBe('Describe the constructor here.'); - expect(subscriber.params.length).toBe(1); - expect(subscriber.params[0].name).toBe('name'); - }); - - it('When a symbol is a class expression, its members get the correct longname and memberof', function() { - expect(hasCallback.kind).toBe('function'); - expect(hasCallback.name).toBe('hasCallback'); - expect(hasCallback.memberof).toBe('Subscriber'); - }); - - it('When a class expression is assigned to an object property, it is parsed correctly', function() { - expect(expiringSubscription.kind).toBe('class'); - expect(expiringSubscription.name).toBe('ExpiringSubscription'); - expect(expiringSubscription.params[0].name).toBe('name'); - }); - - it('When a class is a static memberof something else, the class\' instance methods have the correct scope', function() { - expect(invalidSubscriptionFoo.kind).toBe('function'); - expect(invalidSubscriptionFoo.name).toBe('foo'); - expect(invalidSubscriptionFoo.scope).toBe('instance'); - }); + it('When a symbol is a class declaration, the doclet does not require the @class tag', function() { + expect(subscription.kind).toBe('class'); + expect(subscription.name).toBe('Subscription'); + expect(subscription.classdesc).toBe('Describe the Subscription class here.'); }); - } + + it('When a symbol is a class declaration, the constructor info is merged into the doclet for the symbol', function() { + expect(subscription.description).toBe('Describe the constructor here.'); + expect(subscription.params.length).toBe(1); + expect(subscription.params[0].name).toBe('name'); + }); + + it('When a symbol is a class declaration, its members get the correct longname and memberof', function() { + expect(expire.kind).toBe('function'); + expect(expire.name).toBe('expire'); + expect(expire.memberof).toBe('Subscription'); + }); + + it('When a symbol is a class expression, the doclet does not require the @class tag', function() { + expect(subscriber.kind).toBe('class'); + expect(subscriber.name).toBe('Subscriber'); + expect(subscriber.classdesc).toBe('Describe the Subscriber class here.'); + }); + + it('When a symbol is a class expression, the constructor info is merged into the doclet for the symbol', function() { + expect(subscriber.description).toBe('Describe the constructor here.'); + expect(subscriber.params.length).toBe(1); + expect(subscriber.params[0].name).toBe('name'); + }); + + it('When a symbol is a class expression, its members get the correct longname and memberof', function() { + expect(hasCallback.kind).toBe('function'); + expect(hasCallback.name).toBe('hasCallback'); + expect(hasCallback.memberof).toBe('Subscriber'); + }); + + it('When a class expression is assigned to an object property, it is parsed correctly', function() { + expect(expiringSubscription.kind).toBe('class'); + expect(expiringSubscription.name).toBe('ExpiringSubscription'); + expect(expiringSubscription.params[0].name).toBe('name'); + }); + + it('When a class is a static memberof something else, the class\' instance methods have the correct scope', function() { + expect(invalidSubscriptionFoo.kind).toBe('function'); + expect(invalidSubscriptionFoo.name).toBe('foo'); + expect(invalidSubscriptionFoo.scope).toBe('instance'); + }); + }); }); diff --git a/test/specs/tags/moduletag.js b/test/specs/tags/moduletag.js index 89189ac0..1a84138f 100644 --- a/test/specs/tags/moduletag.js +++ b/test/specs/tags/moduletag.js @@ -173,6 +173,11 @@ describe('@module tag', function() { expect(foo).toBeDefined(); }); + it('should merge the doclet for the constructor with the doclet for the ' + + 'class', function() { + expect(foo.description).toBe('Test class constructor.'); + }); + it('should identify the correct scope for the exported class\'s methods', function() { expect(testMethod).toBeDefined(); });