mirror of
https://github.com/jsdoc/jsdoc.git
synced 2025-12-08 19:46:11 +00:00
resolve this correctly in chained class declarations within modules (#894)
This commit is contained in:
parent
fe04fa18f9
commit
65f307322a
@ -359,6 +359,24 @@ Parser.prototype.astnodeToMemberof = function(node) {
|
|||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the doclet for the lowest-level class, if any, that is in the scope chain for a given node.
|
||||||
|
*
|
||||||
|
* @param {Object} node - The node whose scope chain will be searched.
|
||||||
|
* @return {module:jsdoc/doclet.Doclet?} The doclet for the lowest-level class in the node's scope
|
||||||
|
* chain.
|
||||||
|
*/
|
||||||
|
Parser.prototype._getParentClass = function(node) {
|
||||||
|
var doclet;
|
||||||
|
|
||||||
|
do {
|
||||||
|
doclet = this._getDoclet(node.enclosingScope.nodeId);
|
||||||
|
node = node.enclosingScope;
|
||||||
|
} while (node && node.enclosingScope && doclet && doclet.kind !== 'class');
|
||||||
|
|
||||||
|
return (doclet.kind === 'class' ? doclet : null);
|
||||||
|
};
|
||||||
|
|
||||||
// TODO: docs
|
// TODO: docs
|
||||||
/**
|
/**
|
||||||
* Resolve what "this" refers to relative to a node.
|
* Resolve what "this" refers to relative to a node.
|
||||||
@ -367,6 +385,7 @@ Parser.prototype.astnodeToMemberof = function(node) {
|
|||||||
*/
|
*/
|
||||||
Parser.prototype.resolveThis = function(node) {
|
Parser.prototype.resolveThis = function(node) {
|
||||||
var doclet;
|
var doclet;
|
||||||
|
var parentClass;
|
||||||
var result;
|
var result;
|
||||||
|
|
||||||
// In general, if there's an enclosing scope, we use the enclosing scope to resolve `this`.
|
// In general, if there's an enclosing scope, we use the enclosing scope to resolve `this`.
|
||||||
@ -380,10 +399,20 @@ Parser.prototype.resolveThis = function(node) {
|
|||||||
else if (doclet.this) {
|
else if (doclet.this) {
|
||||||
result = doclet.this;
|
result = doclet.this;
|
||||||
}
|
}
|
||||||
// like: Foo.constructor = function(n) { /** blah */ this.name = n; }
|
|
||||||
else if (doclet.kind === 'function' && doclet.memberof) {
|
else if (doclet.kind === 'function' && doclet.memberof) {
|
||||||
|
parentClass = this._getParentClass(node);
|
||||||
|
|
||||||
|
// like: function Foo() { this.bar = function(n) { /** blah */ this.name = n; };
|
||||||
|
// or: var Foo = exports.Foo = function(n) { /** blah */ this.name = n; };
|
||||||
|
// or: Foo.constructor = function(n) { /** blah */ this.name = n; }
|
||||||
|
if ( parentClass || /\.constructor$/.test(doclet.longname) ) {
|
||||||
result = doclet.memberof;
|
result = doclet.memberof;
|
||||||
}
|
}
|
||||||
|
// like: function notAClass(n) { /** global this */ this.name = n; }
|
||||||
|
else {
|
||||||
|
result = doclet.longname;
|
||||||
|
}
|
||||||
|
}
|
||||||
// like: var foo = function(n) { /** blah */ this.bar = n; }
|
// like: var foo = function(n) { /** blah */ this.bar = n; }
|
||||||
else if ( doclet.kind === 'member' && jsdoc.src.astnode.isAssignment(node) ) {
|
else if ( doclet.kind === 'member' && jsdoc.src.astnode.isAssignment(node) ) {
|
||||||
result = doclet.longname;
|
result = doclet.longname;
|
||||||
|
|||||||
9
test/fixtures/this4.js
vendored
Normal file
9
test/fixtures/this4.js
vendored
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
/** @class */
|
||||||
|
function Template() {}
|
||||||
|
|
||||||
|
Template.constructor = function() {
|
||||||
|
/** Render content. */
|
||||||
|
this.render = function(data) {};
|
||||||
|
};
|
||||||
12
test/fixtures/this5.js
vendored
Normal file
12
test/fixtures/this5.js
vendored
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
/** @module template */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @class
|
||||||
|
* @alias module:template.Template
|
||||||
|
*/
|
||||||
|
var Template = exports.Template = function() {
|
||||||
|
/** View file. */
|
||||||
|
this.view = null;
|
||||||
|
};
|
||||||
@ -81,6 +81,40 @@ describe('this', function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('When "this" is assigned inside an explicit definition of the class constructor', function() {
|
||||||
|
var docSet = jasmine.getDocSetFromFile('test/fixtures/this4.js');
|
||||||
|
var found = docSet.getByLongname('Template#render');
|
||||||
|
|
||||||
|
it('should have a longname like Constructor#member', function() {
|
||||||
|
expect(found.length).toBe(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have the correct name', function() {
|
||||||
|
expect(found[0].name).toBe('render');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have the correct memberof', function() {
|
||||||
|
expect(found[0].memberof).toBe('Template');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('When "this" is assigned in a chained declaration in a module', function() {
|
||||||
|
var docSet = jasmine.getDocSetFromFile('test/fixtures/this5.js');
|
||||||
|
var found = docSet.getByLongname('module:template.Template#view');
|
||||||
|
|
||||||
|
it('should have a longname like Constructor#member', function() {
|
||||||
|
expect(found.length).toBe(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have the correct name', function() {
|
||||||
|
expect(found[0].name).toBe('view');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have the correct memberof', function() {
|
||||||
|
expect(found[0].memberof).toBe('module:template.Template');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('When a member is nested inside an objectlit "this" property inside a constructor', function() {
|
describe('When a member is nested inside an objectlit "this" property inside a constructor', function() {
|
||||||
var docSet = jasmine.getDocSetFromFile('test/fixtures/this-and-objectlit.js');
|
var docSet = jasmine.getDocSetFromFile('test/fixtures/this-and-objectlit.js');
|
||||||
var found = docSet.getByLongname('Page#parts.body.heading');
|
var found = docSet.getByLongname('Page#parts.body.heading');
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user