diff --git a/lib/jsdoc/tag/dictionary/definitions.js b/lib/jsdoc/tag/dictionary/definitions.js index d7f77293..6ff62de6 100644 --- a/lib/jsdoc/tag/dictionary/definitions.js +++ b/lib/jsdoc/tag/dictionary/definitions.js @@ -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 diff --git a/test/fixtures/thistag2.js b/test/fixtures/thistag2.js new file mode 100644 index 00000000..8e138105 --- /dev/null +++ b/test/fixtures/thistag2.js @@ -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; +} diff --git a/test/specs/tags/thistag.js b/test/specs/tags/thistag.js index 520e3fe0..a7ee6fa7 100644 --- a/test/specs/tags/thistag.js +++ b/test/specs/tags/thistag.js @@ -1,18 +1,60 @@ 'use strict'; describe('@this tag', 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'); + afterEach(function() { + jasmine.restoreTagDictionary(); }); - 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() { - expect(typeof fooName).toBe('object'); - expect(fooName.name).toBe('name'); - expect(fooName.memberof).toBe('Foo'); - expect(fooName.scope).toBe('instance'); + 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]; + + expect(setName.this).toBe('Foo'); + }); + + 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)'); + }); }); });