From 3d1c36a325fe37ec120c98775f45e91c77980d09 Mon Sep 17 00:00:00 2001 From: Jeff Williams Date: Tue, 15 Apr 2014 09:26:19 -0700 Subject: [PATCH] keep all type info for `return` and `type` tags (#618) For consistency with method parameters, this change extends our unfortunate practice of adding type properties to the parent of the `type` object, rather than the object itself. --- lib/jsdoc/schema.js | 27 +++++++++++++++++++++- lib/jsdoc/tag/dictionary/definitions.js | 5 ++++- test/fixtures/returnstag.js | 6 +++++ test/fixtures/typetag.js | 7 +++++- test/specs/tags/returnstag.js | 30 +++++++++++++++++-------- test/specs/tags/typetag.js | 23 +++++++++++++------ 6 files changed, 79 insertions(+), 19 deletions(-) diff --git a/lib/jsdoc/schema.js b/lib/jsdoc/schema.js index a13b5ca8..9f96ba83 100644 --- a/lib/jsdoc/schema.js +++ b/lib/jsdoc/schema.js @@ -146,12 +146,25 @@ var ENUM_PROPERTY_SCHEMA = exports.ENUM_PROPERTY_SCHEMA = { name: { type: STRING }, + // is this member nullable? (derived from the type expression) + nullable: { + type: BOOLEAN_OPTIONAL + }, + // is this member optional? (derived from the type expression) + optional: { + type: BOOLEAN_OPTIONAL + }, scope: { type: STRING, // TODO: get this from a real enum somewhere enum: ['static'] }, - type: TYPE_PROPERTY_SCHEMA + type: TYPE_PROPERTY_SCHEMA, + // can this member be provided more than once? (derived from the type expression) + variable: { + type: BOOLEAN_OPTIONAL + }, + } }; @@ -395,6 +408,14 @@ var DOCLET_SCHEMA = exports.DOCLET_SCHEMA = { name: { type: STRING }, + // is this member nullable? (derived from the type expression) + nullable: { + type: BOOLEAN_OPTIONAL + }, + // is this member optional? (derived from the type expression) + optional: { + type: BOOLEAN_OPTIONAL + }, // are there function parameters associated with this doc? params: { type: ARRAY, @@ -518,6 +539,10 @@ var DOCLET_SCHEMA = exports.DOCLET_SCHEMA = { type: BOOLEAN, optional: true }, + // can this member be provided more than once? (derived from the type expression) + variable: { + type: BOOLEAN_OPTIONAL + }, variation: { type: STRING, optional: true diff --git a/lib/jsdoc/tag/dictionary/definitions.js b/lib/jsdoc/tag/dictionary/definitions.js index 47052d07..848893ef 100644 --- a/lib/jsdoc/tag/dictionary/definitions.js +++ b/lib/jsdoc/tag/dictionary/definitions.js @@ -82,7 +82,10 @@ function setDocletDescriptionToValue(doclet, tag) { function setDocletTypeToValueType(doclet, tag) { if (tag.value && tag.value.type) { - doclet.type = tag.value.type; + // add the type names and other type properties (such as `optional`) + Object.keys(tag.value).forEach(function(prop) { + doclet[prop] = tag.value[prop]; + }); } } diff --git a/test/fixtures/returnstag.js b/test/fixtures/returnstag.js index 52b0a271..7c6d4535 100644 --- a/test/fixtures/returnstag.js +++ b/test/fixtures/returnstag.js @@ -4,6 +4,12 @@ function find(targetName) { } +/** + * @returns {!string} The name, if defined. + */ +function getName() { +} + /** * @return The binding id. */ diff --git a/test/fixtures/typetag.js b/test/fixtures/typetag.js index 5ece569a..12300eed 100644 --- a/test/fixtures/typetag.js +++ b/test/fixtures/typetag.js @@ -6,4 +6,9 @@ var foo; /** * @type integer */ -var bar = +(new Date()).getTime(); \ No newline at end of file +var bar = +(new Date()).getTime(); + +/** + * @type {!Array.} + */ +var baz = [1, 2, 3]; diff --git a/test/specs/tags/returnstag.js b/test/specs/tags/returnstag.js index 6b23fd5b..fdf61321 100644 --- a/test/specs/tags/returnstag.js +++ b/test/specs/tags/returnstag.js @@ -1,23 +1,35 @@ -describe("@returns tag", function() { - var docSet = jasmine.getDocSetFromFile('test/fixtures/returnstag.js'), - find = docSet.getByLongname('find')[0], - bind = docSet.getByLongname('bind')[0], - convert = docSet.getByLongname('convert')[0]; +/*global describe, expect, it, jasmine */ +describe('@returns tag', function() { + var docSet = jasmine.getDocSetFromFile('test/fixtures/returnstag.js'); + + it('When a symbol has a @returns tag with a type and description, the doclet has a "returns" property that includes that info.', function() { + var find = docSet.getByLongname('find')[0]; - it('When a symbol has an @returns tag with a type and description, the doclet has a returns array that includes that return.', function() { expect(typeof find.returns).toBe('object'); expect(find.returns.length).toBe(1); - expect(find.returns[0].type.names.join(', ')).toBe('String, Array.'); + expect(find.returns[0].type.names.join(', ')).toBe('string, Array.'); expect(find.returns[0].description).toBe('The names of the found item(s).'); }); - it('When a symbol has an @returns tag with only a description, the doclet has a returns array property that includes that return.', function() { + it('When a symbol has a @returns tag with a non-nullable type, the doclet indicates that the type is non-nullable', function() { + var getName = docSet.getByLongname('getName')[0]; + + expect(typeof getName.returns).toBe('object'); + expect(getName.returns.length).toBe(1); + expect(getName.returns[0].nullable).toBe(false); + }); + + it('When a symbol has a @returns tag with only a description, the doclet has a "returns" property that includes the description.', function() { + var bind = docSet.getByLongname('bind')[0]; + expect(typeof bind.returns).toBe('object'); expect(bind.returns.length).toBe(1); expect(bind.returns[0].description).toBe('The binding id.'); }); - it('When a symbol has an @returns tag without a type but with an inline tag, the doclet does not confuse the inline tag for a type.', function() { + it('When a symbol has a @returns tag without a type but with an inline tag, the inline tag is not mistaken for a type.', function() { + var convert = docSet.getByLongname('convert')[0]; + expect(typeof convert.returns).toBe('object'); expect(convert.returns.length).toBe(1); expect(convert.returns[0].description).toBe('An object to be passed to {@link find}.'); diff --git a/test/specs/tags/typetag.js b/test/specs/tags/typetag.js index 055fa81d..0c4246eb 100644 --- a/test/specs/tags/typetag.js +++ b/test/specs/tags/typetag.js @@ -1,15 +1,24 @@ -describe("@type tag", function() { - var docSet = jasmine.getDocSetFromFile('test/fixtures/typetag.js'), - foo = docSet.getByLongname('foo')[0], - bar = docSet.getByLongname('bar')[0]; +/*global describe, expect, it, jasmine */ +describe('@type tag', function() { + var docSet = jasmine.getDocSetFromFile('test/fixtures/typetag.js'); + + it('When a symbol has a @type tag, the doclet has a type property set to that value\'s type.', function() { + var foo = docSet.getByLongname('foo')[0]; - it('When a symbol has an @type tag, the doclet has a type property set to that value\'s type.', function() { expect(typeof foo.type).toBe('object'); expect(typeof foo.type.names).toBe('object'); expect(foo.type.names.join(', ')).toBe('string, Array.'); }); - it('When a symbol has an @type tag set to a plain string, the doclet has a type property set to that string as if it were a type.', function() { + it('When a symbol has a @type tag set to a plain string, the doclet has a type property set to that value\'s type.', function() { + var bar = docSet.getByLongname('bar')[0]; + expect(bar.type.names.join(', ')).toBe('integer'); }); -}); \ No newline at end of file + + it('When a symbol has a @type tag for a non-nullable type, the doclet indicates that the type is non-nullable', function() { + var baz = docSet.getByLongname('baz')[0]; + + expect(baz.nullable).toBe(false); + }); +});