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. // Tags that JSDoc uses internally, and that must always be defined.
var internalTags = { var internalTags = {
// Special separator tag indicating that multiple doclets should be generated for the same // Special separator tag indicating that multiple doclets should be generated for the same
@ -978,7 +993,12 @@ exports.closureTags = {
template: { template: {
onTagged: ignore onTagged: ignore
}, },
'this': cloneTagDef(baseTags.this), 'this': {
canHaveType: true,
onTagged: function(doclet, tag) {
doclet.this = combineTypes(tag);
}
},
throws: cloneTagDef(baseTags.throws), throws: cloneTagDef(baseTags.throws),
type: cloneTagDef(baseTags.type, { type: cloneTagDef(baseTags.type, {
mustNotHaveDescription: false 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'; 'use strict';
describe('@this tag', function() { 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 docSet = jasmine.getDocSetFromFile('test/fixtures/thistag.js');
var setName = docSet.getByLongname('setName')[0]; 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'); 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(typeof fooName).toBe('object');
expect(fooName.name).toBe('name'); expect(fooName.name).toBe('name');
expect(fooName.memberof).toBe('Foo'); expect(fooName.memberof).toBe('Foo');
expect(fooName.scope).toBe('instance'); 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)');
});
});
}); });