Added support for @mixin tag.

This commit is contained in:
Michael Mathews 2010-07-30 21:38:31 +01:00
parent 6d3143143e
commit cad6e9c01a
8 changed files with 98 additions and 81 deletions

View File

@ -261,7 +261,7 @@
var name = '',
taggedName = '',
kind = '',
taggedIsa = '',
taggedKind = '',
memberof = '',
taggedMemberof = '',
isFile = false, // TODO this should be handled by an event handler in tag dictionary
@ -300,7 +300,7 @@
if (kind && kind !== tags[i].value) {
throw new DocTagConflictError('Symbol has too many isas, cannot be both: ' + kind + ' and ' + tags[i].value);
}
taggedIsa = kind = tags[i].value;
taggedKind = kind = tags[i].value;
}
else if (tags[i].name === 'memberof') {
if (memberof) {
@ -337,6 +337,19 @@
}
}
if ( /^\s*(\S+)\s*=>\s*(\S+)/.test(taggedName) ) {
taggedName = RegExp.$1;
var refersto = RegExp.$2;
tags.setTag('name', taggedName);
taggedKind = 'mixin';
tags.setTag('kind', taggedKind);
tags.addTag('refersto', refersto);
}
if (name && !taggedName) {
tags.addTag('name', name);
}
@ -345,7 +358,7 @@
tags.addTag('name', 'file:'+meta.file);
}
if (kind && !taggedIsa) {
if (kind && !taggedKind) {
tags.addTag('kind', kind);
}

View File

@ -11,9 +11,8 @@
(function() {
var Token = Packages.org.mozilla.javascript.Token,
currentModule = '';
var jsdoc = {
currentModule = '',
jsdoc = {
tagDictionary: require('jsdoc/tagdictionary')
};
@ -54,7 +53,7 @@
[prefix, scope, name] = exports.shorten(name);
}
else { // like @name bar, @memberof foo
if ( /([.~#])$/.test(memberof) ) { // like @memberof foo# or @memberof foo~
if ( /([#.~])$/.test(memberof) ) { // like @memberof foo# or @memberof foo~
path = memberof + name;
scope = RegExp.$1;
doclet.setTag('scope', puncToScope[scope]);
@ -153,77 +152,65 @@
return [prefix, scope, name];
}
/** Given an AST node, return the path to the enclosing node. */
function getEnclosingPath(node) {
var enclosingNode,
enclosingDoc;
if (node.parent && node.parent.type === Token.OBJECTLIT) {
if (enclosingNode = node.parent) {
enclosingDoc = exports.docFromNode(enclosingNode);
}
}
else {
if ( enclosingNode = node.getEnclosingFunction() ) {
enclosingDoc = exports.docFromNode(enclosingNode);
}
}
if (enclosingDoc) {
return (enclosingDoc.tagValue('path') || '').replace(/\.prototype\.?/g, '#');
}
function docToPath(doclet, tagName) {
// TODO protect quoted parts of the path that may contain the string "prototype"
return (doclet.tagValue(tagName) || '').replace(/\.prototype\.?/g, '#');
}
/**
Resolve how to document the `this.` portion of a symbol name.
Apply information about how nested this AST node is to what we know about
the name.
*/
exports.resolveThis = function(name, node, doclet) {
exports.resolvePath = function(name, node, doclet) {
var enclosing,
enclosingDoc,
enclosingPath,
memberof = (doclet.tagValue('memberof') || '').replace(/\.prototype\.?/g, '#');
memberof;
// documented member of an undocumented object literal?
// like foo = { /** a bar. */ bar: 1};
if (node.parent && node.parent.type === Token.OBJECTLIT) {
if ( enclosingPath = getEnclosingPath(node) ) {
if ( enclosingDoc = exports.docFromNode(node.parent) ) {
if ( enclosingPath = docToPath(enclosingDoc, 'path') ) {
name = enclosingPath + (/([#.~])$/.test(enclosingPath) ? '' : '.') + name;
}
}
}
// what's all this then?
else if ( name.indexOf('this.') === 0 ) {
memberof = docToPath(doclet, 'memberof');
// need to examine the source code to determine the full path :(
if (!memberof || memberof === 'this') {
enclosing = node.getEnclosingFunction()
enclosingDoc = exports.docFromNode(enclosing);
if (enclosingDoc) {
if (enclosingDoc) { // documented enclosing symbol
if (enclosingDoc.tagValue('scope') === 'inner') {
memberof = ''; // inner functions have `this` scope of global
memberof = ''; // inner functions always have `this` resolve to the global object
}
else {
memberof = enclosingDoc.tagValue('path');
memberof = docToPath(enclosingDoc, 'path');
}
}
else {
memberof = '';
}
if (enclosing && !memberof) {
memberof = ''; // [[anonymousFunction]]
if (enclosing && !memberof) { // inside an anonymous function, this resolves to the global object
memberof = '';
name = name.slice(5); // remove `this.`
}
else if (!enclosing) {
memberof = ''; // [[globalObject]]
memberof = ''; // no enclosing function, this resolves to the global object
}
if (memberof || !enclosing) {
// `this` refers to nearest non-inner member in the name path
if (enclosingDoc && enclosingDoc.tagValue('kind') !== 'constructor') {
var parts = memberof.split(/[#~.]/);
var parts = memberof.split(/[#.~]/);
var suffix = parts.pop();
memberof = memberof.slice(0, -suffix.length); // remove suffix from memberof
}
var joiner = (memberof === '')? '' : (/[#~.]$/.test(memberof))? '' : '#';
var joiner = (memberof === '')? '' : (/[#.~]$/.test(memberof))? '' : '#';
name = memberof + joiner + name.slice(5); // replace `this.` with memberof
}
}
@ -276,7 +263,7 @@
return null;
}
// tuples, like [ [noderef, doclet], [noderef, doclet] ]
// a linking map, like [ [noderef, doclet], [noderef, doclet] ]
exports.refs = [];
function getTypeName(node) {

View File

@ -62,7 +62,7 @@
// this thing may have commented members, so keep a ref to the thing but don't add it to the doclets list
thisDoclet = jsdoc.doclet.makeDoclet('[[undocumented]]', node, currentSourceName);
nodeName = jsdoc.name.resolveThis(node.name, node, thisDoclet);
nodeName = jsdoc.name.resolvePath(node.name, node, thisDoclet);
thisDoclet.setName(nodeName);
jsdoc.name.refs.push([
node,
@ -97,7 +97,7 @@
}
if (!thisDocletName) { // guess name from the source code
nodeName = jsdoc.name.resolveThis(nodeName, node, thisDoclet);
nodeName = jsdoc.name.resolvePath(nodeName, node, thisDoclet);
thisDoclet.setName(nodeName);
jsdoc.doclets.addDoclet(thisDoclet);
@ -109,7 +109,7 @@
// this thing may have commented members, so keep a ref to the thing but don't add it to the doclets list
thisDoclet = jsdoc.doclet.makeDoclet('[[undocumented]]', node, currentSourceName);
nodeName = jsdoc.name.resolveThis(nodeName, node, thisDoclet);
nodeName = jsdoc.name.resolvePath(nodeName, node, thisDoclet);
thisDoclet.setName(nodeName);
jsdoc.name.refs.push([

View File

@ -33,7 +33,7 @@ exports.jsdocSchema = {
"kind": {
"type": "string",
"maxItems": 1,
"enum": ["constructor", "module", "event", "namespace", "method", "property", "enum", "class", "interface", "constant", "file", "version"]
"enum": ["constructor", "module", "event", "namespace", "method", "property", "enum", "class", "interface", "constant", "mixin", "file", "version"]
},
"access": {
"type": "string",

View File

@ -135,6 +135,19 @@
return false;
}
function setTag(tagName, tagValue) {
var i = this.length;
while(i--) {
if (this[i].name === tagName) {
this[i].value = tagValue;
return true;
}
}
this.addTag(tagName, tagValue);
return false;
}
/**
Given the source of a jsdoc comment, finds the tags.
@private
@ -146,6 +159,7 @@
var tags = [];
tags.addTag = addTag;
tags.hasTag = hasTag;
tags.setTag = setTag;
// split out the basic tags, keep surrounding whitespace
commentSrc

View File

@ -466,4 +466,12 @@
new TagDefinition('see', {
isExported: true
});
/** Syntax: @refersto <text>
@property {module:jsdoc/tagdictionary~TagDefinition} refersto
@memberOf module:jsdoc/tagdictionary~tagDefinitions
*/
new TagDefinition('refersto', {
isExported: true
});
})();

19
test/samples/tag_name.js Normal file
View File

@ -0,0 +1,19 @@
/**
@name Tipsy
@kind property
*/
/**
@name Tubbie.LaLa
@kind property
*/
/**
@name Tubbie."and.don't.forget#Po!"
@kind property
*/
/**
@name Custards.0
@kind property
*/

View File

@ -10,7 +10,7 @@
tag: require('jsdoc/tag'),
parser: require('jsdoc/parser')
};
jsdoc.parser.parseFiles(BASEDIR + 'test/tests/08_tag_name.js');
jsdoc.parser.parseFiles(BASEDIR + 'test/samples/tag_name.js');
doclets = jsdoc.parser.result;
});
@ -47,27 +47,3 @@
});
});
})();
(function testarea() {
/**
@name Tipsy
@kind property
*/
/**
@name Tubbie.LaLa
@kind property
*/
/**
@name Tubbie."and.don't.forget#Po!"
@kind property
*/
/**
@name Custards.0
@kind property
*/
})();