correctly handle aliases that identify instance members, like @alias Foo#bar (#1385)

This commit is contained in:
Jeff Williams 2017-07-10 15:32:27 -07:00
parent c61f1cdf87
commit 5666f4ccef
4 changed files with 239 additions and 117 deletions

View File

@ -101,8 +101,16 @@ exports.resolve = function(doclet) {
}
doclet.name = name;
// does the doclet have an alias that identifies the memberof? if so, use it
if (doclet.alias) {
about = exports.shorten(name);
if (about.memberof) {
memberof = about.memberof;
}
}
// member of a var in an outer scope?
if (name && !memberof && doclet.meta.code && doclet.meta.code.funcscope) {
else if (name && !memberof && doclet.meta.code && doclet.meta.code.funcscope) {
name = doclet.longname = doclet.meta.code.funcscope + SCOPE.PUNC.INNER + name;
}

44
test/fixtures/alias5.js vendored Normal file
View File

@ -0,0 +1,44 @@
/**
* Toaster singleton.
*
* @class
*/
var Toaster = (function() {
var instance = null;
function Toaster() {}
/**
* Toast an item.
*
* @alias Toaster#toast
* @param {BreadyThing} item - The item to toast.
*/
Toaster.prototype.toast = function(item) {};
/**
* Clean the toaster.
*
* @alias clean
* @memberof Toaster
* @instance
*/
Toaster.prototype.clean = function() {};
return {
/**
* Get the Toaster instance.
*
* @alias Toaster.getInstance
* @returns {Toaster} The Toaster instance.
*/
getInstance: function() {
if (instance === null) {
instance = new Toaster();
delete instance.constructor;
}
return instance;
}
};
})();

View File

@ -45,6 +45,34 @@ describe('aliases', function() {
expect(jacketClass[0].longname).toBe('module:jacket');
});
describe('formats', function() {
var docSet = jasmine.getDocSetFromFile('test/fixtures/alias5.js');
var toast = docSet.getByLongname('Toaster#toast')[0];
var getInstance = docSet.getByLongname('Toaster.getInstance')[0];
var clean = docSet.getByLongname('Toaster#clean')[0];
it('should work when the alias value specifies an instance member', function() {
expect(toast).toBeDefined();
expect(toast.name).toBe('toast');
expect(toast.memberof).toBe('Toaster');
expect(toast.scope).toBe('instance');
});
it('should work when the alias value specifies a static member', function() {
expect(getInstance).toBeDefined();
expect(getInstance.name).toBe('getInstance');
expect(getInstance.memberof).toBe('Toaster');
expect(getInstance.scope).toBe('static');
});
it('should work when the alias value only specifies the short name', function() {
expect(clean).toBeDefined();
expect(clean.name).toBe('clean');
expect(clean.memberof).toBe('Toaster');
expect(clean.scope).toBe('instance');
});
});
it('When a symbol is documented as a static member of <global>, its scope is "global" and not "static".', function() {
var docSet = jasmine.getDocSetFromFile('test/fixtures/aliasglobal.js');
var log = docSet.getByLongname('log')[0];

View File

@ -399,143 +399,185 @@ describe('jsdoc/name', function() {
return new jsdoc.doclet.Doclet(comment, {});
}
// @event testing.
var event = '@event';
var memberOf = '@memberof MyClass';
var name = '@name A';
describe('aliases', function() {
// If `doclet.alias` is defined, `doclet.name` will be set to the same value by the time
// we call `resolve()`. Therefore, we set both `@alias` and `@name` in these tests.
// Test the basic @event that is not nested.
it('unnested @event gets resolved correctly', function() {
var doclet = makeDoclet([event, name]);
it('can resolve aliases that identify instance members', function() {
var doclet = makeDoclet(['@alias Foo#bar', '@name Foo#bar']);
jsdoc.name.resolve(doclet);
jsdoc.name.resolve(doclet);
console.log(JSON.stringify(doclet, null, 2));
expect(doclet.name).toEqual('A');
expect(doclet.memberof).toBeUndefined();
expect(doclet.longname).toEqual('event:A');
expect(doclet.name).toBe('bar');
expect(doclet.memberof).toBe('Foo');
expect(doclet.scope).toBe('instance');
expect(doclet.longname).toBe('Foo#bar');
});
it('can resolve aliases that identify static members', function() {
var doclet = makeDoclet(['@alias Foo.bar', '@name Foo.bar']);
jsdoc.name.resolve(doclet);
expect(doclet.name).toBe('bar');
expect(doclet.memberof).toBe('Foo');
expect(doclet.scope).toBe('static');
expect(doclet.longname).toBe('Foo.bar');
});
it('works when the alias only specifies the short name', function() {
var doclet = makeDoclet(['@alias bar', '@name bar', '@memberof Foo', '@instance']);
jsdoc.name.resolve(doclet);
expect(doclet.name).toBe('bar');
expect(doclet.memberof).toBe('Foo');
expect(doclet.scope).toBe('instance');
expect(doclet.longname).toBe('Foo#bar');
});
});
// test all permutations of @event @name [name] @memberof.
it('@event @name @memberof resolves correctly', function() {
var doclet = makeDoclet([event, name, memberOf]);
describe('events', function() {
var event = '@event';
var memberOf = '@memberof MyClass';
var name = '@name A';
jsdoc.name.resolve(doclet);
// Test the basic @event that is not nested.
it('unnested @event gets resolved correctly', function() {
var doclet = makeDoclet([event, name]);
expect(doclet.name).toEqual('A');
expect(doclet.memberof).toEqual('MyClass');
expect(doclet.longname).toEqual('MyClass.event:A');
});
it('@event @memberof @name resolves correctly', function() {
var doclet = makeDoclet([event, memberOf, name]);
jsdoc.name.resolve(doclet);
jsdoc.name.resolve(doclet);
expect(doclet.name).toEqual('A');
expect(doclet.memberof).toBeUndefined();
expect(doclet.longname).toEqual('event:A');
});
expect(doclet.name).toEqual('A');
expect(doclet.memberof).toEqual('MyClass');
expect(doclet.longname).toEqual('MyClass.event:A');
});
it('@name @event @memberof resolves correctly', function() {
var doclet = makeDoclet([name, event, memberOf]);
// test all permutations of @event @name [name] @memberof.
it('@event @name @memberof resolves correctly', function() {
var doclet = makeDoclet([event, name, memberOf]);
jsdoc.name.resolve(doclet);
jsdoc.name.resolve(doclet);
expect(doclet.name).toEqual('A');
expect(doclet.memberof).toEqual('MyClass');
expect(doclet.longname).toEqual('MyClass.event:A');
});
it('@name @memberof @event resolves correctly', function() {
var doclet = makeDoclet([name, memberOf, event]);
expect(doclet.name).toEqual('A');
expect(doclet.memberof).toEqual('MyClass');
expect(doclet.longname).toEqual('MyClass.event:A');
});
it('@event @memberof @name resolves correctly', function() {
var doclet = makeDoclet([event, memberOf, name]);
jsdoc.name.resolve(doclet);
jsdoc.name.resolve(doclet);
expect(doclet.name).toEqual('A');
expect(doclet.memberof).toEqual('MyClass');
expect(doclet.longname).toEqual('MyClass.event:A');
});
it('@memberof @event @name resolves correctly', function() {
var doclet = makeDoclet([memberOf, event, name]);
expect(doclet.name).toEqual('A');
expect(doclet.memberof).toEqual('MyClass');
expect(doclet.longname).toEqual('MyClass.event:A');
});
it('@name @event @memberof resolves correctly', function() {
var doclet = makeDoclet([name, event, memberOf]);
jsdoc.name.resolve(doclet);
jsdoc.name.resolve(doclet);
expect(doclet.name).toEqual('A');
expect(doclet.memberof).toEqual('MyClass');
expect(doclet.longname).toEqual('MyClass.event:A');
});
it('@memberof @name @event resolves correctly', function() {
var doclet = makeDoclet([memberOf, name, event]);
expect(doclet.name).toEqual('A');
expect(doclet.memberof).toEqual('MyClass');
expect(doclet.longname).toEqual('MyClass.event:A');
});
it('@name @memberof @event resolves correctly', function() {
var doclet = makeDoclet([name, memberOf, event]);
jsdoc.name.resolve(doclet);
jsdoc.name.resolve(doclet);
expect(doclet.name).toEqual('A');
expect(doclet.memberof).toEqual('MyClass');
expect(doclet.longname).toEqual('MyClass.event:A');
expect(doclet.name).toEqual('A');
expect(doclet.memberof).toEqual('MyClass');
expect(doclet.longname).toEqual('MyClass.event:A');
});
it('@memberof @event @name resolves correctly', function() {
var doclet = makeDoclet([memberOf, event, name]);
jsdoc.name.resolve(doclet);
expect(doclet.name).toEqual('A');
expect(doclet.memberof).toEqual('MyClass');
expect(doclet.longname).toEqual('MyClass.event:A');
});
it('@memberof @name @event resolves correctly', function() {
var doclet = makeDoclet([memberOf, name, event]);
jsdoc.name.resolve(doclet);
expect(doclet.name).toEqual('A');
expect(doclet.memberof).toEqual('MyClass');
expect(doclet.longname).toEqual('MyClass.event:A');
});
// test all permutations of @event [name] @memberof
it('@event [name] @memberof resolves correctly', function() {
var doclet = makeDoclet(['@event A', memberOf]);
jsdoc.name.resolve(doclet);
expect(doclet.name).toEqual('A');
expect(doclet.memberof).toEqual('MyClass');
expect(doclet.longname).toEqual('MyClass.event:A');
});
it('@memberof @event [name] resolves correctly', function() {
var doclet = makeDoclet([memberOf, '@event A']);
jsdoc.name.resolve(doclet);
expect(doclet.name).toEqual('A');
expect(doclet.memberof).toEqual('MyClass');
expect(doclet.longname).toEqual('MyClass.event:A');
});
// test full @event A.B
it('full @event definition works', function() {
var doclet = makeDoclet(['@event MyClass.A']);
jsdoc.name.resolve(doclet);
expect(doclet.name).toEqual('A');
expect(doclet.memberof).toEqual('MyClass');
expect(doclet.longname).toEqual('MyClass.event:A');
});
it('full @event definition with event: works', function() {
var doclet = makeDoclet(['@event MyClass.event:A']);
jsdoc.name.resolve(doclet);
expect(doclet.name).toEqual('event:A');
expect(doclet.memberof).toEqual('MyClass');
expect(doclet.longname).toEqual('MyClass.event:A');
});
// a double-nested one just in case
it('@event @name MyClass.EventName @memberof somethingelse works', function() {
var doclet = makeDoclet([event, '@name MyClass.A', '@memberof MyNamespace']);
jsdoc.name.resolve(doclet);
expect(doclet.name).toEqual('A');
expect(doclet.memberof).toEqual('MyNamespace.MyClass');
expect(doclet.longname).toEqual('MyNamespace.MyClass.event:A');
});
});
// test all permutations of @event [name] @memberof
it('@event [name] @memberof resolves correctly', function() {
var doclet = makeDoclet(['@event A', memberOf]);
describe('special names', function() {
// TODO: this test doesn't test what it claims to test! copy-and-paste error?
it('correctly handles a function parameter named "prototype"', function() {
var doclet = makeDoclet([
'@name Bar.prototype.baz',
'@function',
'@memberof module:foo',
'@param {string} qux'
]);
jsdoc.name.resolve(doclet);
jsdoc.name.resolve(doclet);
expect(doclet.name).toEqual('A');
expect(doclet.memberof).toEqual('MyClass');
expect(doclet.longname).toEqual('MyClass.event:A');
});
it('@memberof @event [name] resolves correctly', function() {
var doclet = makeDoclet([memberOf, '@event A']);
jsdoc.name.resolve(doclet);
expect(doclet.name).toEqual('A');
expect(doclet.memberof).toEqual('MyClass');
expect(doclet.longname).toEqual('MyClass.event:A');
});
// test full @event A.B
it('full @event definition works', function() {
var doclet = makeDoclet(['@event MyClass.A']);
jsdoc.name.resolve(doclet);
expect(doclet.name).toEqual('A');
expect(doclet.memberof).toEqual('MyClass');
expect(doclet.longname).toEqual('MyClass.event:A');
});
it('full @event definition with event: works', function() {
var doclet = makeDoclet(['@event MyClass.event:A']);
jsdoc.name.resolve(doclet);
expect(doclet.name).toEqual('event:A');
expect(doclet.memberof).toEqual('MyClass');
expect(doclet.longname).toEqual('MyClass.event:A');
});
// a double-nested one just in case
it('@event @name MyClass.EventName @memberof somethingelse works', function() {
var doclet = makeDoclet([event, '@name MyClass.A', '@memberof MyNamespace']);
jsdoc.name.resolve(doclet);
expect(doclet.name).toEqual('A');
expect(doclet.memberof).toEqual('MyNamespace.MyClass');
expect(doclet.longname).toEqual('MyNamespace.MyClass.event:A');
});
// other cases
it('correctly handles a function parameter named "prototype"', function() {
var doclet = makeDoclet([
'@name Bar.prototype.baz',
'@function',
'@memberof module:foo',
'@param {string} qux'
]);
jsdoc.name.resolve(doclet);
expect(doclet.name).toBe('baz');
expect(doclet.memberof).toBe('module:foo.Bar');
expect(doclet.longname).toBe('module:foo.Bar#baz');
expect(doclet.name).toBe('baz');
expect(doclet.memberof).toBe('module:foo.Bar');
expect(doclet.longname).toBe('module:foo.Bar#baz');
});
});
});
});