mirror of
https://github.com/jsdoc/jsdoc.git
synced 2025-12-08 19:46:11 +00:00
make implementations inherit the docs from interfaces where appropriate (#864)
This commit is contained in:
parent
16b8aa0a73
commit
3663224f2b
@ -159,6 +159,7 @@ function explicitlyInherits(doclets) {
|
||||
return inherits;
|
||||
}
|
||||
|
||||
// TODO: try to reduce overlap with similar methods
|
||||
function getInheritedAdditions(doclets, docs, documented) {
|
||||
var additionIndexes;
|
||||
var additions = [];
|
||||
@ -276,7 +277,7 @@ function updateMixes(mixedDoclet, mixedLongname) {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: try to reduce overlap with getInheritedAdditions
|
||||
// TODO: try to reduce overlap with similar methods
|
||||
function getMixedInAdditions(mixinDoclets, allDoclets, commentedDoclets) {
|
||||
var additionIndexes;
|
||||
var additions = [];
|
||||
@ -322,6 +323,99 @@ function getMixedInAdditions(mixinDoclets, allDoclets, commentedDoclets) {
|
||||
return additions;
|
||||
}
|
||||
|
||||
function updateImplements(implDoclets, implementedLongname) {
|
||||
if ( !Array.isArray(implDoclets) ) {
|
||||
implDoclets = [implDoclets];
|
||||
}
|
||||
|
||||
implDoclets.forEach(function(implDoclet) {
|
||||
if ( !hasOwnProp.call(implDoclet, 'implements') ) {
|
||||
implDoclet.implements = [];
|
||||
}
|
||||
|
||||
implDoclet.implements.push(implementedLongname);
|
||||
});
|
||||
}
|
||||
|
||||
// TODO: try to reduce overlap with similar methods
|
||||
function getImplementedAdditions(implDoclets, allDoclets, commentedDoclets) {
|
||||
var additionIndexes;
|
||||
var additions = [];
|
||||
var doclet;
|
||||
var idx;
|
||||
var implementations;
|
||||
var implExists;
|
||||
var implementationDoclet;
|
||||
var interfaceDoclets;
|
||||
|
||||
// interfaceDoclets will be undefined if the implemented symbol isn't documented
|
||||
implDoclets = implDoclets || [];
|
||||
|
||||
for (var i = 0, ii = implDoclets.length; i < ii; i++) {
|
||||
doclet = implDoclets[i];
|
||||
implementations = doclet.implements;
|
||||
|
||||
if (implementations) {
|
||||
// reset the lookup table of added doclet indexes by longname
|
||||
additionIndexes = {};
|
||||
|
||||
for (var j = 0, jj = implementations.length; j < jj; j++) {
|
||||
interfaceDoclets = getMembers(implementations[j], allDoclets, ['instance']);
|
||||
|
||||
for (var k = 0, kk = interfaceDoclets.length; k < kk; k++) {
|
||||
implementationDoclet = doop(interfaceDoclets[k]);
|
||||
|
||||
reparentDoclet(doclet, implementationDoclet);
|
||||
updateImplements(implementationDoclet, interfaceDoclets[k].longname);
|
||||
|
||||
// If there's no implementation, move along.
|
||||
implExists = hasOwnProp.call(allDoclets.index.longname,
|
||||
implementationDoclet.longname);
|
||||
if (!implExists) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Add the interface's docs unless the implementation is already documented.
|
||||
if ( !hasOwnProp.call(commentedDoclets, implementationDoclet.longname) ) {
|
||||
updateAddedDoclets(implementationDoclet, additions, additionIndexes);
|
||||
}
|
||||
// If the implementation used an @inheritdoc or @override tag, add the
|
||||
// interface's docs, and ignore the existing doclets.
|
||||
else if ( explicitlyInherits(commentedDoclets[implementationDoclet.longname]) ) {
|
||||
// Ignore any existing doclets. (This is safe because we only get here if
|
||||
// `implementationDoclet.longname` is an own property of
|
||||
// `commentedDoclets`.)
|
||||
addDocletProperty(commentedDoclets[implementationDoclet.longname], 'ignore',
|
||||
true);
|
||||
|
||||
updateAddedDoclets(implementationDoclet, additions, additionIndexes);
|
||||
|
||||
// Remove property that's no longer accurate.
|
||||
if (implementationDoclet.virtual) {
|
||||
delete implementationDoclet.virtual;
|
||||
}
|
||||
// Remove properties that we no longer need.
|
||||
if (implementationDoclet.inheritdoc) {
|
||||
delete implementationDoclet.inheritdoc;
|
||||
}
|
||||
if (implementationDoclet.override) {
|
||||
delete implementationDoclet.override;
|
||||
}
|
||||
}
|
||||
// If there's an implementation, and it's documented, update the doclets to
|
||||
// indicate what the implementation is implementing.
|
||||
else {
|
||||
updateImplements(commentedDoclets[implementationDoclet.longname],
|
||||
interfaceDoclets[k].longname);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return additions;
|
||||
}
|
||||
|
||||
function augment(doclets, propertyName, docletFinder) {
|
||||
var index = doclets.index.longname;
|
||||
var dependencies = sort( mapDependencies(index, propertyName) );
|
||||
@ -389,94 +483,8 @@ exports.addMixedIn = function(doclets) {
|
||||
* @param {!Object} doclets.index - The doclet index added by {@link module:jsdoc/borrow.indexAll}.
|
||||
* @return {void}
|
||||
*/
|
||||
exports.addImplemented = function(docs) {
|
||||
var docMap = {};
|
||||
var interfaces = {};
|
||||
var implemented = {};
|
||||
var memberInfo = {};
|
||||
|
||||
docs.forEach(function(doc) {
|
||||
var memberof = doc.memberof || doc.name;
|
||||
|
||||
if (!hasOwnProp.call(docMap, memberof)) {
|
||||
docMap[memberof] = [];
|
||||
}
|
||||
docMap[memberof].push(doc);
|
||||
|
||||
if (doc.kind === 'interface') {
|
||||
interfaces[doc.longname] = doc;
|
||||
}
|
||||
else if (doc.implements && doc.implements.length) {
|
||||
if (!hasOwnProp.call(implemented, doc.memberof)) {
|
||||
implemented[memberof] = [];
|
||||
}
|
||||
implemented[memberof].push(doc);
|
||||
}
|
||||
});
|
||||
|
||||
// create an dictionary of interface doclets
|
||||
Object.keys(interfaces).forEach(function(ifaceName) {
|
||||
var iface = interfaces[ifaceName];
|
||||
if (hasOwnProp.call(docMap, iface.name)) {
|
||||
docMap[iface.name].forEach(function(doc) {
|
||||
var members = memberInfo[doc.memberof];
|
||||
|
||||
if (!members) {
|
||||
members = memberInfo[doc.memberof] = {};
|
||||
}
|
||||
members[doc.name] = doc;
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
Object.keys(implemented).forEach(function(key) {
|
||||
// implemented classes namespace.
|
||||
var owner = implemented[key];
|
||||
|
||||
owner.forEach(function(klass) {
|
||||
// class's interfaces
|
||||
klass.implements.forEach(function(impl) {
|
||||
var interfaceMember;
|
||||
var interfaceMembers = memberInfo[impl];
|
||||
var member;
|
||||
var members;
|
||||
|
||||
// mark the interface as being implemented by the class
|
||||
if (hasOwnProp.call(interfaces, impl)) {
|
||||
interfaces[impl].implementations = interfaces[impl].implementations || [];
|
||||
interfaces[impl].implementations.push(klass.longname);
|
||||
}
|
||||
|
||||
// if the interface has no members, skip to the next owner
|
||||
if (!interfaceMembers) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!hasOwnProp.call(docMap, klass.longname)) {
|
||||
docMap[klass.longname] = [];
|
||||
}
|
||||
members = docMap[klass.longname];
|
||||
|
||||
for (var i = 0, len = members.length; i < len; i++) {
|
||||
member = members[i];
|
||||
interfaceMember = interfaceMembers && interfaceMembers[member.name];
|
||||
|
||||
// if we didn't find the member name in the interface, skip to the next member
|
||||
if (!interfaceMember) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// mark members that implement an interface
|
||||
member.implements = member.implements || [];
|
||||
member.implements.push(interfaceMember.longname);
|
||||
|
||||
// mark interface members that the symbol implements
|
||||
interfaceMember.implementations = interfaceMember.implementations || [];
|
||||
interfaceMember.implementations.push(member.longname);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
exports.addImplemented = function(doclets) {
|
||||
augment(doclets, 'implements', getImplementedAdditions);
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@ -6,6 +6,9 @@ describe('@implements tag', function() {
|
||||
var myTester = docSet.getByLongname('MyTester')[0];
|
||||
var myIncompleteWorker = docSet.getByLongname('MyWorker')[0];
|
||||
var beforeEachMethod = docSet.getByLongname('MyTester#beforeEach')[0];
|
||||
var itMethod = docSet.getByLongname('MyTester#it').filter(function($) {
|
||||
return !$.undocumented;
|
||||
})[0];
|
||||
var processMethod = docSet.getByLongname('MyWorker#process')[0];
|
||||
|
||||
it('MyTester has an "implements" array', function() {
|
||||
@ -20,6 +23,10 @@ describe('@implements tag', function() {
|
||||
expect(beforeEachMethod.implements[0]).toBe('ITester#beforeEach');
|
||||
});
|
||||
|
||||
it('MyTester#it inherits the docs from ITester#it', function() {
|
||||
expect(itMethod.description).toBe('it method.');
|
||||
});
|
||||
|
||||
it('MyWorker\'s process() method does not implement an interface', function() {
|
||||
expect(processMethod.implements).toBeUndefined();
|
||||
});
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user