support the this tag correctly for Closure Compiler (#605)

This commit is contained in:
Jeff Williams 2017-07-21 14:04:53 -07:00
parent 2164532d30
commit e33f48c471
3 changed files with 89 additions and 12 deletions

View File

@ -204,6 +204,21 @@ function firstWordOf(string) {
}
}
function combineTypes(tag) {
var combined;
if (tag.value && tag.value.type) {
if (tag.value.type.names.length === 1) {
combined = tag.value.type.names[0];
}
else {
combined = '(' + tag.value.type.names.join('|') + ')';
}
}
return combined;
}
// Tags that JSDoc uses internally, and that must always be defined.
var internalTags = {
// Special separator tag indicating that multiple doclets should be generated for the same
@ -978,7 +993,12 @@ exports.closureTags = {
template: {
onTagged: ignore
},
'this': cloneTagDef(baseTags.this),
'this': {
canHaveType: true,
onTagged: function(doclet, tag) {
doclet.this = combineTypes(tag);
}
},
throws: cloneTagDef(baseTags.throws),
type: cloneTagDef(baseTags.type, {
mustNotHaveDescription: false

15
test/fixtures/thistag2.js vendored Normal file
View File

@ -0,0 +1,15 @@
/** @constructor */
function Foo(name) {
setName.apply(this, name);
}
/** @this {Foo} */
function setName(name) {
/** document me */
this.name = name;
}
/** @this {(Foo|Bar)} */
function getName(name) {
return this.name;
}

View File

@ -1,18 +1,60 @@
'use strict';
describe('@this tag', function() {
afterEach(function() {
jasmine.restoreTagDictionary();
});
describe('JSDoc tags', function() {
beforeEach(function() {
jasmine.replaceTagDictionary('jsdoc');
});
it('should add a `this` property set to the @this tag\'s value', function() {
var docSet = jasmine.getDocSetFromFile('test/fixtures/thistag.js');
var setName = docSet.getByLongname('setName')[0];
var fooName = docSet.getByLongname('Foo#name')[0];
it('When a symbol has a @this tag, the doclet has a this property that is set to that value.', function() {
expect(setName.this).toBe('Foo');
});
it('When a this symbol is documented inside a function with a @this tag, the symbol is documented as a member of that tags value.', function() {
it('should change the memberof for symbols like `this.foo`', function() {
var docSet = jasmine.getDocSetFromFile('test/fixtures/thistag.js');
var fooName = docSet.getByLongname('Foo#name')[0];
expect(typeof fooName).toBe('object');
expect(fooName.name).toBe('name');
expect(fooName.memberof).toBe('Foo');
expect(fooName.scope).toBe('instance');
});
});
describe('Closure Compiler tags', function() {
beforeEach(function() {
jasmine.replaceTagDictionary('closure');
});
it('should add a `this` property set to the @this tag\'s type expression', function() {
var docSet = jasmine.getDocSetFromFile('test/fixtures/thistag2.js');
var setName = docSet.getByLongname('setName')[0];
expect(setName.this).toBe('Foo');
});
it('should change the memberof for symbols like `this.foo`', function() {
var docSet = jasmine.getDocSetFromFile('test/fixtures/thistag2.js');
var fooName = docSet.getByLongname('Foo#name')[0];
expect(typeof fooName).toBe('object');
expect(fooName.name).toBe('name');
expect(fooName.memberof).toBe('Foo');
expect(fooName.scope).toBe('instance');
});
it('should work with type unions', function() {
var docSet = jasmine.getDocSetFromFile('test/fixtures/thistag2.js');
var getName = docSet.getByLongname('getName')[0];
expect(getName.this).toBe('(Foo|Bar)');
});
});
});