Added tests for @name and @example. Added fix for preserving whitespace in examples.

This commit is contained in:
Michael Mathews 2010-07-05 21:13:15 +01:00
parent 93a3c0dd81
commit df444b4524
9 changed files with 279 additions and 37 deletions

View File

@ -114,6 +114,22 @@
this.tags[this.tags.length] = parse_tag.fromText(tagName + ' ' + tagValue);
}
/**
Return the first tag with the given name.
@method Doclet#getTag
@param {String} tagName
@returns {Tag} The irst found tag with that name.
*/
Doclet.prototype.getTag = function(tagName) {
for (var i = 0, leni = this.tags.length; i < leni; i++) {
if (this.tags[i].name === tagName) {
return this.tags[i];
}
}
return null;
}
/**
Does a tag with the given name exist in this doclet?
@method Doclet#hasTag
@ -249,7 +265,8 @@
if (tagAbout.setsDocletAccess) {
tags[tags.length] = parse_tag.fromText('access '+tags[i].name);
}
else if (tags[i].name === 'const') {
if (tags[i].name === 'const') {
tags[tags.length] = parse_tag.fromText('attribute constant');
}
else if (tags[i].name === 'readonly') {
@ -319,7 +336,11 @@
tags[tags.length] = parse_tag.fromText('memberof ' + memberof);
}
}
// TODO should iterate over the tags here rather than letting doclet decide
// which ones to pick and choose from. the tag dictionary should tell us what to do
// now that we have a doclet object we can do some final adjustments
function postprocess(doclet) {
if ( doclet.hasTag('class') && !doclet.hasTag('constructor') ) {
doclet.tags[doclet.tags.length] = parse_tag.fromText('isa constructor');
@ -344,6 +365,21 @@
doclet.tags[doclet.tags.length] = parse_tag.fromText('attribute constant');
}
}
if ( doclet.hasTag('property') ) {
if ( !doclet.hasTag('type') ) {
var propertyTag = doclet.getTag('property'),
types = [];
if (propertyTag.type) {
if (typeof propertyTag.type === 'string') types = [propertyTag.type];
else types = propertyTag.type;
for (var i = 0, leni = types.length; i < leni; i++) {
doclet.tags[doclet.tags.length] = parse_tag.fromText('type '+types[i]);
}
}
}
}
}
function DocTagConflictError(message) {

View File

@ -59,7 +59,7 @@
// if name doesn't already have a docspace and needs one
// the namespace should appear in the path but not the name
if (tagDictionary.lookUp(isa).isDocspace) {
if (tagDictionary.lookUp(isa).setsDocletDocspace) {
if ( /^[a-z_$-]+:(\S+)/i.test(name) ) {
name = RegExp.$1;
}
@ -86,6 +86,8 @@
var atoms = [],
cursor = 0;
path = path.replace(/(".+?")/g, function($) {
$ = $.slice(1, -1);
var token = '@' + atoms.length + '@';
atoms.push($);
return token;
@ -102,6 +104,10 @@
for (var i = 0, leni = atoms.length; i < leni; i++) {
prefix = prefix.replace('@'+i+'@', atoms[i]);
shortname = shortname.replace('@'+i+'@', atoms[i]);
// remove quotes from shortnames
///^"(.+)"$/.test(shortname);
//if (RegExp.$1) { shortname = RegExp.$1; }
}
return [prefix, shortname];

View File

@ -42,7 +42,7 @@
this.pdesc = '';
// raw is like: "tagname andsometagtext"
var parts = this.raw.match(/^\s*(\S+)(?:\s+([\s\S]*))?$/);
var parts = this.raw.match(/^\s*(\S+)(?:\s([\s\S]*))?$/);
if (parts) {
this.name = (parts[1] || '').toLowerCase(); // like @name
@ -54,11 +54,9 @@
var tagAbout = tagDictionary.lookUp(this.name);
if (!tagAbout.keepsWhitespace) {
this.value = trim(tagText);
}
else {
this.value = tagText;
tagText = trim(tagText);
}
this.value = tagText;
if (tagAbout.canHaveType) {
var [

View File

@ -48,8 +48,9 @@
isExported : false, // this tag should appear as a top level property in the doclet?
setsDocletIsa : false, // the name of this tag is used to define the doclet's isa property
setsDocletName : false, // this tag can be used to name the doclet
setsDocletAccess: false,
isDocspace : false, // the name of this tag becomes the docspace for the doclet name, like "event:"
setsDocletAccess: false, // the name of this tag becomes the access of the doclet
setsDocletType : false, // the type of this tag becomes th type of the doclet
setsDocletDocspace : false, // the name of this tag becomes the docspace for the doclet name, like "event:"
canHaveType : false, // this tag can have a {type}
canHavePname : false, // this tag can have a parameter-type name
canHavePdesc : false, // this tag can have a parameter-type desc
@ -74,7 +75,7 @@
// }
// @desc <text>
new TagDefinition('desc', {
new TagDefinition('desc', { // t
isExported: true
});
@ -94,18 +95,18 @@
});
// @memberof <text>
new TagDefinition('memberof', {
new TagDefinition('memberof', { //t
isExported: true
});
// @namespace <docletName>
new TagDefinition('namespace', {
new TagDefinition('namespace', { //t
setsDocletIsa: true,
setsDocletName: true
});
// @constructor <docletName>
new TagDefinition('constructor', {
new TagDefinition('constructor', { //t
setsDocletIsa: true,
setsDocletName: true
});
@ -123,14 +124,14 @@
});
// @file|overview|fileoverview <docletName>
new TagDefinition('file', {
new TagDefinition('file', { //t
setsDocletIsa: true,
setsDocletName: true,
isDocspace: true
setsDocletDocspace: true
});
// @method <docletType> <docletName> <docletDesc>
new TagDefinition('method', {
new TagDefinition('method', { //t
canHaveType: true,
canHavePname: true,
canHavePdesc: true,
@ -138,25 +139,26 @@
});
// @property <docletType> <docletName> <docletDesc>
new TagDefinition('property', {
new TagDefinition('property', { //t
canHaveType: true,
canHavePname: true,
canHavePdesc: true,
setsDocletName: true
setsDocletName: true,
setsDocletType: true
});
// @event <docletName>
new TagDefinition('event', {
setsDocletIsa: true,
setsDocletName: true,
isDocspace: true
setsDocletDocspace: true
});
// @module <docletName>
new TagDefinition('module', {
setsDocletIsa: true,
setsDocletName: true,
isDocspace: true
setsDocletDocspace: true
});
// @example <text>

View File

@ -5,6 +5,7 @@ load(BASEDIR + '/test/tests/04_jsdoc_docset.js');
load(BASEDIR + '/test/tests/05_jsdoc_doclet.js');
load(BASEDIR + '/test/tests/06_jsdoc_tag.js');
load(BASEDIR + '/test/tests/08_tag_name.js');
load(BASEDIR + '/test/tests/09_tag_desc.js');
load(BASEDIR + '/test/tests/10_tag_constructor.js');
load(BASEDIR + '/test/tests/11_tag_namespace.js');
@ -13,6 +14,7 @@ load(BASEDIR + '/test/tests/13_tag_method.js');
load(BASEDIR + '/test/tests/14_tag_member.js');
load(BASEDIR + '/test/tests/15_tag_type.js');
load(BASEDIR + '/test/tests/16_tag_return.js');
load(BASEDIR + '/test/tests/17_tag_example.js');
load(BASEDIR + '/test/tests/20_tag_file.js');

73
test/tests/08_tag_name.js Normal file
View File

@ -0,0 +1,73 @@
(function() {
var jsdoc,
doclets;
JSpec.describe('@name', function() {
before(function() {
// docsets can only be created by parsers
jsdoc = {
tag: require('jsdoc/tag'),
parser: require('jsdoc/parser')
};
jsdoc.parser.parseFiles(BASEDIR + 'test/tests/08_tag_name.js');
doclets = jsdoc.parser.result;
});
describe('A doclet that has a @name tag followed by a simple string', function() {
it('should have an `name` property set to that string', function() {
var doclet = doclets[0].toObject();
expect(doclet).to(have_property, 'name');
expect(doclet.name).to(eql, 'Tipsy');
});
});
describe('A doclet that has a @name tag followed by a dotted string', function() {
it('should have an `name` property set to the last segment of that string', function() {
var doclet = doclets[1].toObject();
expect(doclet).to(have_property, 'name');
expect(doclet.name).to(eql, 'LaLa');
});
});
describe('A doclet that has a @name tag followed by a dotted string with quotes', function() {
it('should have an `name` property set to the last entire quoted segment of that string', function() {
var doclet = doclets[2].toObject();
expect(doclet).to(have_property, 'name');
expect(doclet.name).to(eql, 'and.don\'t.forget#Po!');
});
});
describe('A doclet that has a @name tag followed by a number', function() {
it('should have an `name` property set to the number', function() {
var doclet = doclets[3].toObject();
expect(doclet).to(have_property, 'name');
expect(doclet.name).to(eql, '0');
});
});
});
})();
(function testarea() {
/**
@name Tipsy
@isa property
*/
/**
@name Tubbie.LaLa
@isa property
*/
/**
@name Tubbie."and.don't.forget#Po!"
@isa property
*/
/**
@name Custards.0
@isa property
*/
})();

View File

@ -14,7 +14,7 @@
doclets = jsdoc.parser.result;
});
describe('A doclet with a named property tag attached to a namespace', function() {
describe('A doclet with a named @property attached to a namespace', function() {
it('should have an `isa` property set to "property"', function() {
var doclet = doclets[2].toObject();
expect(doclet).to(have_property, 'isa');
@ -34,7 +34,7 @@
});
});
describe('A doclet with a named property tag attached to a constructor', function() {
describe('A doclet with a named @property and a type and a description', function() {
it('should have an `isa` property set to "property"', function() {
var doclet = doclets[3].toObject();
expect(doclet).to(have_property, 'isa');
@ -47,36 +47,89 @@
expect(doclet.name).to(eql, 'bah');
});
it('should have a `memberof` property set to the parent object name', function() {
it('should have a `type` property set to the parent given type', function() {
var doclet = doclets[3].toObject();
expect(doclet).to(have_property, 'memberof');
expect(doclet.memberof).to(eql, 'bar');
expect(doclet).to(have_property, 'type');
expect(doclet.type).to(eql, ['string', 'number']);
});
it('should have a `desc` property set to the given description', function() {
var doclet = doclets[3].toObject();
expect(doclet).to(have_property, 'desc');
expect(doclet.desc).to(eql, 'Here is a description.');
});
});
describe('A doclet with a named property tag after to a constructor tag', function() {
describe('A doclet with a named @property after to a constructor tag', function() {
it('should be a constructor', function() {
var doclet = doclets[4].toObject();
expect(doclet).to(have_property, 'isa');
expect(doclet.isa).to(eql, 'constructor');
});
});
describe('A doclet with a named @variable tag and a description', function() {
it('should have an `isa` property set to "property"', function() {
var doclet = doclets[5].toObject();
expect(doclet).to(have_property, 'isa');
expect(doclet.isa).to(eql, 'property');
});
it('should have a `name` property set to the given name', function() {
var doclet = doclets[5].toObject();
expect(doclet).to(have_property, 'name');
expect(doclet.name).to(eql, 'zub');
});
it('should have a `desc` property set to the given description', function() {
var doclet = doclets[5].toObject();
expect(doclet).to(have_property, 'desc');
expect(doclet.desc).to(eql, 'The description here.');
});
});
describe('A doclet with no name and a typed @property tag', function() {
it('should have an `isa` property set to "property"', function() {
var doclet = doclets[6].toObject();
expect(doclet).to(have_property, 'isa');
expect(doclet.isa).to(eql, 'property');
});
it('should have a `type` property set to the given type', function() {
var doclet = doclets[6].toObject();
expect(doclet).to(have_property, 'type');
expect(doclet.type).to(eql, 'Function');
});
it('should have a `name` property set to the name in the code', function() {
var doclet = doclets[6].toObject();
expect(doclet).to(have_property, 'name');
expect(doclet.name).to(eql, 'onShow');
});
});
});
})();
(function testarea() {
/** @namespace foo */
/** @constructor bar */
/** @namespace foo */
var foo = {}, onShow, callbacks = [function(){}];
/** @constructor bar */
/** @property foo.fah */
/** @property foo.fah */
/** @property {string|number} bar.bah Here is a description. */
/** @property bar.bah */
/** @constructor Zub
@property {string} zip
*/
/** @constructor Zub
@property {string} zip
*/
/** @variable zub - The description here. */
/** @property {Function} */
onShow = callbacks[0];
})();

View File

@ -14,7 +14,7 @@
doclets = jsdoc.parser.result;
});
describe('A doclet with a named method tag attached to a namespace', function() {
describe('A doclet with a named @method attached to a namespace', function() {
it('should have an `isa` property set to "method"', function() {
var doclet = doclets[2].toObject();
expect(doclet).to(have_property, 'isa');
@ -34,7 +34,7 @@
});
});
describe('A doclet with a named method tag attached to a constructor', function() {
describe('A doclet with a named @method attached to a constructor', function() {
it('should have an `isa` property set to "method"', function() {
var doclet = doclets[3].toObject();
expect(doclet).to(have_property, 'isa');
@ -54,6 +54,20 @@
});
});
describe('A doclet with a named @function tag', function() {
it('should have an `isa` property set to "method"', function() {
var doclet = doclets[4].toObject();
expect(doclet).to(have_property, 'isa');
expect(doclet.isa).to(eql, 'method');
});
it('should have a `name` property set to the given name"', function() {
var doclet = doclets[4].toObject();
expect(doclet).to(have_property, 'name');
expect(doclet.name).to(eql, 'zub');
});
});
});
})();
@ -67,4 +81,6 @@
/** @method bar.bah */
/** @function zub */
})();

View File

@ -0,0 +1,56 @@
(function() {
var jsdoc,
doclets;
JSpec.describe('@example', function() {
before(function() {
// docsets can only be created by parsers
jsdoc = {
tag: require('jsdoc/tag'),
parser: require('jsdoc/parser')
};
jsdoc.parser.parseFiles(BASEDIR + 'test/tests/17_tag_example.js');
doclets = jsdoc.parser.result.map(function($){ return $.toObject(); });
});
describe('A doclet with a @example tag', function() {
it('should have an `example` property', function() {
var doclet = doclets[0];
expect(doclet).to(have_property, 'example');
});
});
describe('the value of the `example` property', function() {
it('should preserve all whitespace', function() {
var doclet = doclets[0];
expect(doclet.example).to(eql, ' var myresult;\n myresult = foo(a, b);\n');
});
});
describe('A doclet with a2 @example tags', function() {
it('should have an `example` property with length of 2', function() {
var doclet = doclets[1];
expect(doclet).to(have_property, 'example');
expect(doclet.example.length).to(eql, 2);
});
});
});
})();
(function testarea() {
/**
* @function foo
* @example
* var myresult;
* myresult = foo(a, b);
*/
/**
* @function bar
* @example one fish
* @example two fish
*/
})();