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); 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? Does a tag with the given name exist in this doclet?
@method Doclet#hasTag @method Doclet#hasTag
@ -249,7 +265,8 @@
if (tagAbout.setsDocletAccess) { if (tagAbout.setsDocletAccess) {
tags[tags.length] = parse_tag.fromText('access '+tags[i].name); 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'); tags[tags.length] = parse_tag.fromText('attribute constant');
} }
else if (tags[i].name === 'readonly') { else if (tags[i].name === 'readonly') {
@ -319,7 +336,11 @@
tags[tags.length] = parse_tag.fromText('memberof ' + memberof); 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) { function postprocess(doclet) {
if ( doclet.hasTag('class') && !doclet.hasTag('constructor') ) { if ( doclet.hasTag('class') && !doclet.hasTag('constructor') ) {
doclet.tags[doclet.tags.length] = parse_tag.fromText('isa 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'); 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) { function DocTagConflictError(message) {

View File

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

View File

@ -42,7 +42,7 @@
this.pdesc = ''; this.pdesc = '';
// raw is like: "tagname andsometagtext" // 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) { if (parts) {
this.name = (parts[1] || '').toLowerCase(); // like @name this.name = (parts[1] || '').toLowerCase(); // like @name
@ -54,11 +54,9 @@
var tagAbout = tagDictionary.lookUp(this.name); var tagAbout = tagDictionary.lookUp(this.name);
if (!tagAbout.keepsWhitespace) { if (!tagAbout.keepsWhitespace) {
this.value = trim(tagText); tagText = trim(tagText);
}
else {
this.value = tagText;
} }
this.value = tagText;
if (tagAbout.canHaveType) { if (tagAbout.canHaveType) {
var [ var [

View File

@ -48,8 +48,9 @@
isExported : false, // this tag should appear as a top level property in the doclet? 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 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 setsDocletName : false, // this tag can be used to name the doclet
setsDocletAccess: false, setsDocletAccess: false, // the name of this tag becomes the access of the doclet
isDocspace : false, // the name of this tag becomes the docspace for the doclet name, like "event:" 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} canHaveType : false, // this tag can have a {type}
canHavePname : false, // this tag can have a parameter-type name canHavePname : false, // this tag can have a parameter-type name
canHavePdesc : false, // this tag can have a parameter-type desc canHavePdesc : false, // this tag can have a parameter-type desc
@ -74,7 +75,7 @@
// } // }
// @desc <text> // @desc <text>
new TagDefinition('desc', { new TagDefinition('desc', { // t
isExported: true isExported: true
}); });
@ -94,18 +95,18 @@
}); });
// @memberof <text> // @memberof <text>
new TagDefinition('memberof', { new TagDefinition('memberof', { //t
isExported: true isExported: true
}); });
// @namespace <docletName> // @namespace <docletName>
new TagDefinition('namespace', { new TagDefinition('namespace', { //t
setsDocletIsa: true, setsDocletIsa: true,
setsDocletName: true setsDocletName: true
}); });
// @constructor <docletName> // @constructor <docletName>
new TagDefinition('constructor', { new TagDefinition('constructor', { //t
setsDocletIsa: true, setsDocletIsa: true,
setsDocletName: true setsDocletName: true
}); });
@ -123,14 +124,14 @@
}); });
// @file|overview|fileoverview <docletName> // @file|overview|fileoverview <docletName>
new TagDefinition('file', { new TagDefinition('file', { //t
setsDocletIsa: true, setsDocletIsa: true,
setsDocletName: true, setsDocletName: true,
isDocspace: true setsDocletDocspace: true
}); });
// @method <docletType> <docletName> <docletDesc> // @method <docletType> <docletName> <docletDesc>
new TagDefinition('method', { new TagDefinition('method', { //t
canHaveType: true, canHaveType: true,
canHavePname: true, canHavePname: true,
canHavePdesc: true, canHavePdesc: true,
@ -138,25 +139,26 @@
}); });
// @property <docletType> <docletName> <docletDesc> // @property <docletType> <docletName> <docletDesc>
new TagDefinition('property', { new TagDefinition('property', { //t
canHaveType: true, canHaveType: true,
canHavePname: true, canHavePname: true,
canHavePdesc: true, canHavePdesc: true,
setsDocletName: true setsDocletName: true,
setsDocletType: true
}); });
// @event <docletName> // @event <docletName>
new TagDefinition('event', { new TagDefinition('event', {
setsDocletIsa: true, setsDocletIsa: true,
setsDocletName: true, setsDocletName: true,
isDocspace: true setsDocletDocspace: true
}); });
// @module <docletName> // @module <docletName>
new TagDefinition('module', { new TagDefinition('module', {
setsDocletIsa: true, setsDocletIsa: true,
setsDocletName: true, setsDocletName: true,
isDocspace: true setsDocletDocspace: true
}); });
// @example <text> // @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/05_jsdoc_doclet.js');
load(BASEDIR + '/test/tests/06_jsdoc_tag.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/09_tag_desc.js');
load(BASEDIR + '/test/tests/10_tag_constructor.js'); load(BASEDIR + '/test/tests/10_tag_constructor.js');
load(BASEDIR + '/test/tests/11_tag_namespace.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/14_tag_member.js');
load(BASEDIR + '/test/tests/15_tag_type.js'); load(BASEDIR + '/test/tests/15_tag_type.js');
load(BASEDIR + '/test/tests/16_tag_return.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'); 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; 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() { it('should have an `isa` property set to "property"', function() {
var doclet = doclets[2].toObject(); var doclet = doclets[2].toObject();
expect(doclet).to(have_property, 'isa'); 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() { it('should have an `isa` property set to "property"', function() {
var doclet = doclets[3].toObject(); var doclet = doclets[3].toObject();
expect(doclet).to(have_property, 'isa'); expect(doclet).to(have_property, 'isa');
@ -47,36 +47,89 @@
expect(doclet.name).to(eql, 'bah'); 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(); var doclet = doclets[3].toObject();
expect(doclet).to(have_property, 'memberof'); expect(doclet).to(have_property, 'type');
expect(doclet.memberof).to(eql, 'bar'); 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() { it('should be a constructor', function() {
var doclet = doclets[4].toObject(); var doclet = doclets[4].toObject();
expect(doclet).to(have_property, 'isa'); expect(doclet).to(have_property, 'isa');
expect(doclet.isa).to(eql, 'constructor'); 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() { (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; 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() { it('should have an `isa` property set to "method"', function() {
var doclet = doclets[2].toObject(); var doclet = doclets[2].toObject();
expect(doclet).to(have_property, 'isa'); 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() { it('should have an `isa` property set to "method"', function() {
var doclet = doclets[3].toObject(); var doclet = doclets[3].toObject();
expect(doclet).to(have_property, 'isa'); 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 */ /** @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
*/
})();