From 21e0dbad25b9abd9ef7d8acf6c650fa632be0136 Mon Sep 17 00:00:00 2001 From: Jeff Williams Date: Wed, 13 Aug 2014 15:32:51 -0700 Subject: [PATCH] allow the Closure version of the `private` tag to specify a type (#730) --- lib/jsdoc/doclet.js | 13 +++++ lib/jsdoc/tag.js | 13 +++++ lib/jsdoc/tag/dictionary/definitions.js | 11 +++- test/fixtures/privatetag2.js | 8 +++ test/specs/tags/privatetag.js | 78 +++++++++++++++++++++++-- 5 files changed, 116 insertions(+), 7 deletions(-) create mode 100644 test/fixtures/privatetag2.js diff --git a/lib/jsdoc/doclet.js b/lib/jsdoc/doclet.js index 6786b156..4ae1d60c 100644 --- a/lib/jsdoc/doclet.js +++ b/lib/jsdoc/doclet.js @@ -136,6 +136,19 @@ function fixDescription(docletSrc) { return docletSrc; } +/** + * Replace the existing tag dictionary with a new tag dictionary. + * + * Used for testing only. + * + * @private + * @param {module:jsdoc/tag/dictionary.Dictionary} dict - The new tag dictionary. + */ +exports._replaceDictionary = function _replaceDictionary(dict) { + jsdoc.tag.dictionary = dict; + require('jsdoc/tag')._replaceDictionary(dict); +}; + /** * @class * @classdesc Represents a single JSDoc comment. diff --git a/lib/jsdoc/tag.js b/lib/jsdoc/tag.js index 1752fc87..abcfece7 100644 --- a/lib/jsdoc/tag.js +++ b/lib/jsdoc/tag.js @@ -102,6 +102,19 @@ function processTagText(tag, tagDef) { } } +/** + * Replace the existing tag dictionary with a new tag dictionary. + * + * Used for testing only. Do not call this method directly. Instead, call + * {@link module:jsdoc/doclet._replaceDictionary}, which also updates this module's tag dictionary. + * + * @private + * @param {module:jsdoc/tag/dictionary.Dictionary} dict - The new tag dictionary. + */ +exports._replaceDictionary = function _replaceDictionary(dict) { + jsdoc.tag.dictionary = dict; +}; + /** Constructs a new tag object. Calls the tag validator. @class diff --git a/lib/jsdoc/tag/dictionary/definitions.js b/lib/jsdoc/tag/dictionary/definitions.js index 387ebe4d..151cb280 100644 --- a/lib/jsdoc/tag/dictionary/definitions.js +++ b/lib/jsdoc/tag/dictionary/definitions.js @@ -773,7 +773,16 @@ var closureTags = exports.closureTags = { lends: cloneTagDef(baseTags.lends), license: cloneTagDef(baseTags.license), param: cloneTagDef(baseTags.param), - private: cloneTagDef(baseTags.private), + private: { + canHaveType: true, + onTagged: function(doclet, tag) { + doclet.access = 'private'; + + if (tag.value && tag.value.type) { + setDocletTypeToValueType(doclet, tag); + } + } + }, protected: cloneTagDef(baseTags.protected), return: cloneTagDef(baseTags.returns), 'this': cloneTagDef(baseTags['this']), diff --git a/test/fixtures/privatetag2.js b/test/fixtures/privatetag2.js new file mode 100644 index 00000000..f41b893a --- /dev/null +++ b/test/fixtures/privatetag2.js @@ -0,0 +1,8 @@ +/** + * @private {Object.} + */ +var connectionPorts = { + 'devServer': 6464, + 'prodServer': 2232, + 'stagingServer': 4997 +}; diff --git a/test/specs/tags/privatetag.js b/test/specs/tags/privatetag.js index a4d5aceb..059f1af3 100644 --- a/test/specs/tags/privatetag.js +++ b/test/specs/tags/privatetag.js @@ -1,9 +1,75 @@ -describe("@private tag", function() { - var docSet = jasmine.getDocSetFromFile('test/fixtures/privatetag.js'), - foo = docSet.getByLongname('Foo')[0], - bar = docSet.getByLongname('Foo#bar')[0]; +/*global afterEach, describe, expect, it, jasmine, spyOn */ +'use strict'; - it('When a symbol has an @private tag, the doclet has an access property that is "private".', function() { +var definitions = require('jsdoc/tag/dictionary/definitions'); +var dictionary = require('jsdoc/tag/dictionary'); +var Dictionary = dictionary.Dictionary; +var doclet = require('jsdoc/doclet'); +var logger = require('jsdoc/util/logger'); + +var originalDictionary = dictionary; + +describe('@private tag', function() { + var docSet = jasmine.getDocSetFromFile('test/fixtures/privatetag.js'); + var foo = docSet.getByLongname('Foo')[0]; + var bar = docSet.getByLongname('Foo#bar')[0]; + + it('When a symbol has a @private tag, the doclet has an `access` property set to `private`.', + function() { expect(foo.access).toBe('private'); }); -}); \ No newline at end of file + + it('When a symbol tagged with @private has members, the members do not inherit the @private ' + + 'tag.', function() { + expect(bar.access).not.toBeDefined(); + }); + + describe('JSDoc tags', function() { + afterEach(function() { + doclet._replaceDictionary(originalDictionary); + }); + + it('When JSDoc tags are enabled, the @private tag does not accept a value.', function() { + var dict = new Dictionary(); + var privateDocs; + + definitions.defineTags(dict, definitions.jsdocTags); + doclet._replaceDictionary(dict); + spyOn(logger, 'warn'); + + privateDocs = jasmine.getDocSetFromFile('test/fixtures/privatetag2.js'); + + expect(logger.warn).toHaveBeenCalled(); + }); + }); + + describe('Closure Compiler tags', function() { + afterEach(function() { + doclet._replaceDictionary(originalDictionary); + }); + + it('When Closure Compiler tags are enabled, the @private tag accepts a type expression.', + function() { + var connectionPorts; + var dict = new Dictionary(); + var privateDocs; + + definitions.defineTags(dict, definitions.closureTags); + doclet._replaceDictionary(dict); + spyOn(logger, 'warn'); + + privateDocs = jasmine.getDocSetFromFile('test/fixtures/privatetag2.js'); + connectionPorts = privateDocs.getByLongname('connectionPorts')[0]; + + expect(logger.warn).not.toHaveBeenCalled(); + + expect(connectionPorts).toBeDefined(); + expect(connectionPorts.access).toBe('private'); + + expect(connectionPorts.type).toBeDefined(); + expect(connectionPorts.type.names).toBeDefined(); + expect(connectionPorts.type.names.length).toBe(1); + expect(connectionPorts.type.names[0]).toBe('Object.'); + }); + }); +});