diff --git a/lib/jsdoc/augment.js b/lib/jsdoc/augment.js index d195a3e5..0c7c88e0 100644 --- a/lib/jsdoc/augment.js +++ b/lib/jsdoc/augment.js @@ -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 = {}; diff --git a/lib/jsdoc/borrow.js b/lib/jsdoc/borrow.js index 6f93ea99..5c49882b 100644 --- a/lib/jsdoc/borrow.js +++ b/lib/jsdoc/borrow.js @@ -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 = []; };