adding recursive alias resolving from rafalwrzeszcz

This commit is contained in:
Jannon 2012-03-15 20:09:50 -07:00
parent 68f264f468
commit a2259ac14c
7 changed files with 129 additions and 20 deletions

View File

@ -64,8 +64,9 @@ exports.attachTo = function(parser) {
else if (e.code && e.code.name) { // we need to get the symbol name from code
newDoclet.addTag('name', e.code.name);
if (!newDoclet.memberof && e.astnode) {
var memberofName,
scope;
var memberofName = null,
basename = null,
scope = '';
if ( /^((module.)?exports|this)(\.|$)/.test(newDoclet.name) ) {
var nameStartsWith = RegExp.$1;
@ -102,9 +103,18 @@ exports.attachTo = function(parser) {
}
else {
memberofName = this.astnodeToMemberof(e.astnode);
if(memberofName instanceof Array) {
basename = memberofName[1];
memberofName = memberofName[0];
}
}
if (memberofName) { newDoclet.addTag( 'memberof', memberofName); }
if (memberofName) {
newDoclet.addTag( 'memberof', memberofName);
if (basename) {
newDoclet.name = newDoclet.name.replace(new RegExp('^' + RegExp.escape(basename) + '.'), '');
}
}
else {
if (currentModule) {
if (!newDoclet.scope) newDoclet.addTag( 'inner');

View File

@ -159,23 +159,39 @@ exports.Parser.tkn = tkn;
* @returns {string} The long name of the node that this is a member of.
*/
exports.Parser.prototype.astnodeToMemberof = function(node) {
var memberof = {};
var id,
doclet;
if (node.type === Token.VAR || node.type === Token.FUNCTION || node.type == tkn.NAMEDFUNCTIONSTATEMENT) {
if (node.enclosingFunction) { // an inner var or func
memberof.id = 'astnode'+node.enclosingFunction.hashCode();
memberof.doclet = this.refs[memberof.id];
if (!memberof.doclet) {
id = 'astnode'+node.enclosingFunction.hashCode();
doclet = this.refs[id];
if (!doclet) {
return '<anonymous>~';
}
return (memberof.doclet.longname||memberof.doclet.name) + '~';
return (doclet.longname||doclet.name) + '~';
}
}
else {
memberof.id = 'astnode'+node.parent.hashCode();
memberof.doclet = this.refs[memberof.id];
if (!memberof.doclet) return ''; // global?
return memberof.doclet.longname||memberof.doclet.name;
//check local references for aliases
var scope = node,
basename = getBasename(nodeToString(node.left));
while(scope.enclosingFunction) {
id = 'astnode'+scope.enclosingFunction.hashCode();
doclet = this.refs[id];
if (doclet && doclet.meta.vars && basename in doclet.meta.vars) {
var alias = doclet.meta.vars[basename];
if (alias !== false) {
return [alias, basename];
}
}
// move up
scope = scope.enclosingFunction;
}
id = 'astnode'+node.parent.hashCode();
doclet = this.refs[id];
if (!doclet) return ''; // global?
return doclet.longname||doclet.name;
}
}
@ -258,7 +274,7 @@ exports.Parser.prototype.resolveVar = function(node, basename) {
if (!enclosingFunction) { return ''; } // global
doclet = this.refs['astnode'+enclosingFunction.hashCode()];
if ( doclet && doclet.meta.vars && ~doclet.meta.vars.indexOf(basename) ) {
if ( doclet && doclet.meta.vars && basename in doclet.meta.vars ) {
return doclet.longname;
}
@ -330,7 +346,7 @@ function visitNode(node) {
finishers: [currentParser.addDocletRef]
};
var basename = e.code.name.replace(/^([$a-z_][$a-z_0-9]*).*?$/i, '$1');
var basename = getBasename(e.code.name);
if (basename !== 'this') e.code.funcscope = currentParser.resolveVar(node, basename);
}
@ -371,11 +387,12 @@ function visitNode(node) {
// keep track of vars in a function scope
if (node.enclosingFunction) {
var func = 'astnode'+node.enclosingFunction.hashCode(),
funcDoc = currentParser.refs[func];
funcDoc = currentParser.refs[func];
if (funcDoc) {
funcDoc.meta.vars = funcDoc.meta.vars || [];
funcDoc.meta.vars.push(e.code.name);
funcDoc.meta.vars = funcDoc.meta.vars || {};
funcDoc.meta.vars[e.code.name] = false;
e.finishers.push(makeVarsFinisher(funcDoc));
}
}
}
@ -399,12 +416,13 @@ function visitNode(node) {
funcDoc = currentParser.refs[func];
if (funcDoc) {
funcDoc.meta.vars = funcDoc.meta.vars || [];
funcDoc.meta.vars.push(e.code.name);
funcDoc.meta.vars = funcDoc.meta.vars || {};
funcDoc.meta.vars[e.code.name] = false;
e.finishers.push(makeVarsFinisher(funcDoc));
}
}
var basename = e.code.name.replace(/^([$a-z_][$a-z_0-9]*).*?$/i, '$1');
var basename = getBasename(e.code.name)
e.code.funcscope = currentParser.resolveVar(node, basename);
}
@ -567,6 +585,31 @@ function isValidJsdoc(commentSrc) {
return commentSrc && commentSrc.indexOf('/***') !== 0; /*** ignore comments that start with many stars ***/
}
/** @private
* @memberof module:src/parser.Parser
*/
function makeVarsFinisher(funcDoc) {
var func = function(e) {
//no need to evaluate all things related to funcDoc again, just use it
if (funcDoc && e.doclet && e.doclet.alias) {
funcDoc.meta.vars[e.code.name] = e.doclet.longname;
}
}
return func;
}
/** @private
* @memberof module:src/parser.Parser
* @param {string} name Full symbol name.
* @return {string} Basename.
*/
function getBasename(name) {
if (name !== undefined) {
return name.replace(/^([$a-z_][$a-z_0-9]*).*?$/i, '$1');
}
return name;
}
/**
Fired whenever the parser encounters a JSDoc comment in the current source code.
@event jsdocCommentFound

View File

@ -0,0 +1,19 @@
/**
* @namespace
*/
var A = {};
(function(ns) {
/**
* @namespace
* @alias A.F
*/
var f = {};
/**
* @return {String}
*/
f.method = function(){};
ns.F = f;
})(A);

View File

@ -0,0 +1,19 @@
/**
* @namespace
*/
var A = {};
/**
* @namespace
* @alias A.F
*/
var f = {};
(function(ns) {
/**
* @return {String}
*/
f.method = function(){};
ns.F = f;
})(A);

View File

@ -109,6 +109,8 @@ testFile('test/t/cases/alias.js');
testFile('test/t/cases/alias2.js');
testFile('test/t/cases/alias3.js');
testFile('test/t/cases/aliasglobal.js');
testFile('test/t/cases/aliasresolve.js');
testFile('test/t/cases/aliasresolve2.js');
testFile('test/t/cases/also.js');
testFile('test/t/cases/augmentstag.js');
testFile('test/t/cases/authortag.js');

View File

@ -0,0 +1,8 @@
(function() {
var docSet = testhelpers.getDocSetFromFile('test/cases/aliasresolve.js'),
method = docSet.getByLongname('A.F.method');
test('When a local reference has alias, put all members into aliased definition.', function() {
assert.equal(method.length, 1, 'Local modifications are visible to outside.');
});
})();

View File

@ -0,0 +1,8 @@
(function() {
var docSet = testhelpers.getDocSetFromFile('test/cases/aliasresolve.js'),
method = docSet.getByLongname('A.F.method');
test('When a reference in an outer scope has alias, put all members into aliased definition.', function() {
assert.equal(method.length, 1, 'Local modifications are visible to outside.');
});
})();