add more information to the doclet index (#725)

We now index doclets as follows:

+ all doclets by longname
+ all documented symbols by longname
+ all doclets with `borrowed` properties

By expanding the index, we reduce the number of times that `jsdoc/augment` and `jsdoc/borrow` must iterate over all doclets. As a result, large docsets are processed much more quickly.
This commit is contained in:
Jeff Williams 2014-08-16 08:58:17 -07:00
parent 46d89d169c
commit b6bfcadf00
2 changed files with 92 additions and 61 deletions

View File

@ -70,7 +70,7 @@ function getMembers(longname, docs) {
return members;
}
function getAdditions(doclets, docs, longnames) {
function getAdditions(doclets, docs, documented) {
var doop = require('jsdoc/util/doop');
var additions = [];
@ -92,8 +92,7 @@ function getAdditions(doclets, docs, longnames) {
for (var k = 0, kk = members.length; k < kk; k++) {
member = doop(members[k]);
if(!member.inherited)
{
if (!member.inherited) {
member.inherits = member.longname;
}
member.inherited = true;
@ -103,46 +102,41 @@ function getAdditions(doclets, docs, longnames) {
parts[0] = doc.longname;
member.longname = parts.join('#');
// if the child doesn't override the parent member, add the parent member
if (longnames.indexOf(member.longname) === -1) {
// only add the ancestor's docs if the ancestor's symbol is overridden, but the
// override is not documented
if ( !hasOwnProp.call(documented, member.longname) ) {
additions.push(member);
}
}
}
}
}
return additions;
}
exports.addInherited = function(docs) {
var dependencies = mapDependencies(docs.index);
var index = docs.index.longname;
var dependencies = mapDependencies(index);
var sorted = sort(dependencies);
var longnames = [];
// only build the list of longnames if we'll actually need it
if (sorted.length) {
longnames = docs.map(function(doc) {
// keep the ancestor's docs for a symbol if a local override is not documented
if (doc.longname && !doc.undocumented) {
return doc.longname;
}
});
}
sorted.forEach(function(name) {
var doclets = docs.index[name];
var additions = getAdditions(doclets, docs, longnames);
var doclets = index[name];
var additions = getAdditions(doclets, docs, docs.index.documented);
additions.forEach(function(doc) {
var name = doc.longname;
if ( !hasOwnProp.call(docs.index, name) ) {
docs.index[name] = [];
if ( !hasOwnProp.call(index, name) ) {
index[name] = [];
}
docs.index[name].push(doc);
index[name].push(doc);
docs.push(doc);
});
});
};
// TODO: move as much of this as possible to jsdoc/borrow.indexAll
exports.addImplemented = function(docs) {
var docMap = {};
var interfaces = {};

View File

@ -8,21 +8,79 @@
var doop = require('jsdoc/util/doop');
var logger = require('jsdoc/util/logger');
var SCOPE = require('jsdoc/name').SCOPE;
var hasOwnProp = Object.prototype.hasOwnProperty;
exports.indexAll = function(docs) {
var lookupTable = {};
// TODO: add the index at parse time, so we don't have to iterate over all the doclets again
exports.indexAll = function(doclets) {
var borrowed = [];
var doclet;
var documented = {};
var longname = {};
docs.forEach(function(doc) {
if ( !hasOwnProp.call(lookupTable, doc.longname) ) {
lookupTable[doc.longname] = [];
for (var i = 0, l = doclets.length; i < l; i++) {
doclet = doclets[i];
// track all doclets by longname
if ( !hasOwnProp.call(longname, doclet.longname) ) {
longname[doclet.longname] = [];
}
lookupTable[doc.longname].push(doc);
});
docs.index = lookupTable;
longname[doclet.longname].push(doclet);
// track longnames of documented symbols
if (!doclet.undocumented) {
if ( !hasOwnProp.call(documented, doclet.longname) ) {
documented[doclet.longname] = [];
}
documented[doclet.longname].push(doclet);
}
// track doclets with a `borrowed` property
if ( hasOwnProp.call(doclet, 'borrowed') ) {
borrowed.push(doclet);
}
}
doclets.index = {
borrowed: borrowed,
documented: documented,
longname: longname
};
};
function cloneBorrowedDoclets(doclet, doclets) {
doclet.borrowed.forEach(function(borrowed) {
var borrowedDoclets = doclets.index.longname[borrowed.from];
var borrowedAs = borrowed.as || borrowed.from;
var clonedDoclets;
var parts;
var scopePunc;
if (borrowedDoclets) {
borrowedAs = borrowedAs.replace(/^prototype\./, SCOPE.PUNC.INSTANCE);
clonedDoclets = doop(borrowedDoclets).forEach(function(clone) {
// TODO: this will fail on longnames like '"Foo#bar".baz'
parts = borrowedAs.split(SCOPE.PUNC.INSTANCE);
if (parts.length === 2) {
clone.scope = SCOPE.NAMES.INSTANCE;
scopePunc = SCOPE.PUNC.INSTANCE;
}
else {
clone.scope = SCOPE.NAMES.STATIC;
scopePunc = SCOPE.PUNC.STATIC;
}
clone.name = parts.pop();
clone.memberof = doclet.longname;
clone.longname = clone.memberof + scopePunc + clone.name;
doclets.push(clone);
});
}
});
}
// requires docs to have been indexed: docs.index must be defined here
/**
Take a copy of the docs for borrowed symbols and attach them to the
@ -30,41 +88,20 @@ exports.indexAll = function(docs) {
moving docs from the "borrowed" array and into the general docs, then
deleting the "borrowed" array.
*/
exports.resolveBorrows = function(docs) {
/*eslint max-nested-callbacks:[2, 3] */
if (!docs.index) {
exports.resolveBorrows = function(doclets) {
var doclet;
if (!doclets.index) {
logger.error('Unable to resolve borrowed symbols, because the docs have not been indexed.');
return;
}
docs.forEach(function(doc) {
if (doc.borrowed) {
doc.borrowed.forEach(function(b, i) {
var lent = docs.index[b.from], // lent is an array
asName = b.as || b.from;
for (var i = 0, l = doclets.index.borrowed.length; i < l; i++) {
doclet = doclets.index.borrowed[i];
if (lent) {
var cloned = doop(lent);
cloneBorrowedDoclets(doclet, doclets);
delete doclet.borrowed;
}
cloned.forEach(function(clone) {
asName = asName.replace(/^prototype\./, '#');
var parts = asName.split('#');
if (parts.length === 2) { clone.scope = 'instance'; }
else { clone.scope = 'static'; }
asName = parts.pop();
clone.name = asName;
clone.memberof = doc.longname;
clone.longname = clone.memberof + (clone.scope === 'instance' ? '#' : '.') +
clone.name;
docs.push(clone);
});
}
});
delete doc.borrowed;
}
});
doclets.index.borrowed = [];
};