* Resolve what "this" refers to relative to a node. * @param {node} node - The "this" node * @returns {string} The longname of the enclosing node.
(node)
| 497 | * @returns {string} The longname of the enclosing node. |
| 498 | */ |
| 499 | resolveThis(node) { |
| 500 | let doclet; |
| 501 | let parentClass; |
| 502 | let result; |
| 503 | |
| 504 | // Properties are handled below. |
| 505 | if (node.type !== Syntax.Property && node.enclosingScope) { |
| 506 | // For ES2015 constructor functions, we use the class declaration to resolve `this`. |
| 507 | if (node.parent && node.parent.type === Syntax.MethodDefinition && |
| 508 | node.parent.kind === 'constructor') { |
| 509 | doclet = this._getDocletById(node.parent.parent.parent.nodeId); |
| 510 | } |
| 511 | // Otherwise, if there's an enclosing scope, we use the enclosing scope to resolve `this`. |
| 512 | else { |
| 513 | doclet = this._getDocletById(node.enclosingScope.nodeId); |
| 514 | } |
| 515 | |
| 516 | if (!doclet) { |
| 517 | result = jsdoc.name.LONGNAMES.ANONYMOUS; // TODO handle global this? |
| 518 | } |
| 519 | else if (doclet.this) { |
| 520 | result = doclet.this; |
| 521 | } |
| 522 | else if (doclet.kind === 'function' && doclet.memberof) { |
| 523 | parentClass = this._getParentClass(node); |
| 524 | |
| 525 | // like: function Foo() { this.bar = function(n) { /** blah */ this.name = n; }; |
| 526 | // or: Foo.prototype.bar = function(n) { /** blah */ this.name = n; }; |
| 527 | // or: var Foo = exports.Foo = function(n) { /** blah */ this.name = n; }; |
| 528 | // or: Foo.constructor = function(n) { /** blah */ this.name = n; } |
| 529 | if ( parentClass || /\.constructor$/.test(doclet.longname) ) { |
| 530 | result = doclet.memberof; |
| 531 | } |
| 532 | // like: function notAClass(n) { /** global this */ this.name = n; } |
| 533 | else { |
| 534 | result = doclet.longname; |
| 535 | } |
| 536 | } |
| 537 | // like: var foo = function(n) { /** blah */ this.bar = n; } |
| 538 | else if ( doclet.kind === 'member' && jsdoc.src.astnode.isAssignment(node) ) { |
| 539 | result = doclet.longname; |
| 540 | } |
| 541 | // walk up to the closest class we can find |
| 542 | else if (doclet.kind === 'class' || doclet.kind === 'interface' || doclet.kind === 'module') { |
| 543 | result = doclet.longname; |
| 544 | } |
| 545 | else if (node.enclosingScope) { |
| 546 | result = this.resolveThis(node.enclosingScope); |
| 547 | } |
| 548 | } |
| 549 | // For object properties, we use the node's parent (the object) instead. |
| 550 | else { |
| 551 | doclet = this._getDocletById(node.parent.nodeId); |
| 552 | |
| 553 | if (!doclet) { |
| 554 | // The object wasn't documented, so we don't know what name to use. |
| 555 | result = ''; |
| 556 | } |
no test coverage detected