mirror of
https://github.com/jsdoc/jsdoc.git
synced 2025-12-08 19:46:11 +00:00
support modules that export a single non-constructor function (#384)
This commit is contained in:
parent
450f3944bc
commit
e5be860cc4
@ -54,6 +54,7 @@ exports.attachTo = function(parser) {
|
||||
}
|
||||
});
|
||||
|
||||
// TODO: for clarity, decompose into smaller functions
|
||||
function newSymbolDoclet(docletSrc, e) {
|
||||
var memberofName = null,
|
||||
newDoclet = getNewDoclet(parser, docletSrc, e);
|
||||
@ -132,9 +133,16 @@ exports.attachTo = function(parser) {
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (currentModule) {
|
||||
if (!newDoclet.scope){newDoclet.addTag( 'inner');}
|
||||
if (!newDoclet.memberof && newDoclet.scope !== 'global'){newDoclet.addTag( 'memberof', currentModule);}
|
||||
// add @inner and @memberof tags unless the current module exports only this symbol
|
||||
if (currentModule && currentModule !== newDoclet.name) {
|
||||
// add @inner unless the current module exports only this symbol
|
||||
if (!newDoclet.scope) {
|
||||
newDoclet.addTag('inner');
|
||||
}
|
||||
|
||||
if (!newDoclet.memberof && newDoclet.scope !== 'global') {
|
||||
newDoclet.addTag('memberof', currentModule);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -147,7 +155,9 @@ exports.attachTo = function(parser) {
|
||||
|
||||
//resolveProperties(newDoclet);
|
||||
|
||||
if (!newDoclet.memberof) {
|
||||
// set the scope to global unless a) the doclet is a memberof something or b) the current
|
||||
// module exports only this symbol
|
||||
if (!newDoclet.memberof && currentModule !== newDoclet.name) {
|
||||
newDoclet.scope = 'global';
|
||||
}
|
||||
|
||||
|
||||
@ -186,6 +186,20 @@ var find = exports.find = function(data, spec) {
|
||||
return data(spec).get();
|
||||
};
|
||||
|
||||
/**
|
||||
* Check whether a symbol is a function and is the only symbol exported by a module (as in
|
||||
* `module.exports = function() {};`).
|
||||
*
|
||||
* @private
|
||||
* @param {module:jsdoc/doclet.Doclet} doclet - The doclet for the symbol.
|
||||
* @return {boolean} `true` if the symbol is a function and is the only symbol exported by a module;
|
||||
* otherwise, `false`.
|
||||
*/
|
||||
function isModuleFunction(doclet) {
|
||||
return doclet.longname && doclet.longname === doclet.name &&
|
||||
doclet.longname.indexOf('module:') === 0 && doclet.kind === 'function';
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve all of the following types of members from a set of doclets:
|
||||
*
|
||||
@ -201,7 +215,7 @@ var find = exports.find = function(data, spec) {
|
||||
* `events`, and `namespaces` properties. Each property contains an array of objects.
|
||||
*/
|
||||
exports.getMembers = function(data) {
|
||||
return {
|
||||
var members = {
|
||||
classes: find( data, {kind: 'class'} ),
|
||||
externals: find( data, {kind: 'external'} ),
|
||||
events: find( data, {kind: 'event'} ),
|
||||
@ -213,6 +227,17 @@ exports.getMembers = function(data) {
|
||||
modules: find( data, {kind: 'module'} ),
|
||||
namespaces: find( data, {kind: 'namespace'} )
|
||||
};
|
||||
|
||||
// functions that are also modules (as in "module.exports = function() {};") are not globals
|
||||
members.globals = members.globals.filter(function(doclet) {
|
||||
if ( isModuleFunction(doclet) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
return members;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -565,16 +590,16 @@ exports.createLink = function(doclet) {
|
||||
var longname;
|
||||
var filename;
|
||||
|
||||
if (containers.indexOf(doclet.kind) < 0) {
|
||||
if ( containers.indexOf(doclet.kind) !== -1 || isModuleFunction(doclet) ) {
|
||||
longname = doclet.longname;
|
||||
url = getFilename(longname);
|
||||
}
|
||||
else {
|
||||
longname = doclet.longname;
|
||||
filename = getFilename(doclet.memberof || exports.globalName);
|
||||
|
||||
url = filename + '#' + getNamespace(doclet.kind) + doclet.name;
|
||||
}
|
||||
else {
|
||||
longname = doclet.longname;
|
||||
url = getFilename(longname);
|
||||
}
|
||||
|
||||
return url;
|
||||
};
|
||||
|
||||
@ -149,6 +149,33 @@ function generateSourceFiles(sourceFiles) {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Look for classes or functions with the same name as modules (which indicates that the module
|
||||
* exports only that class or function), then attach the classes or functions to the `module`
|
||||
* property of the appropriate module doclets. The name of each class or function is also updated
|
||||
* for display purposes. This function mutates the original arrays.
|
||||
*
|
||||
* @private
|
||||
* @param {Array.<module:jsdoc/doclet.Doclet>} doclets - The array of classes and functions to
|
||||
* check.
|
||||
* @param {Array.<module:jsdoc/doclet.Doclet>} modules - The array of module doclets to search.
|
||||
*/
|
||||
function attachModuleSymbols(doclets, modules) {
|
||||
var symbols = {};
|
||||
|
||||
// build a lookup table
|
||||
doclets.forEach(function(symbol) {
|
||||
symbols[symbol.longname] = symbol;
|
||||
});
|
||||
|
||||
return modules.map(function(module) {
|
||||
if (symbols[module.longname]) {
|
||||
module.module = symbols[module.longname];
|
||||
module.module.name = module.module.name.replace('module:', 'require("') + '")';
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the navigation sidebar.
|
||||
* @param {object} members The members that will be used to create the sidebar.
|
||||
@ -193,22 +220,14 @@ function buildNav(members) {
|
||||
}
|
||||
|
||||
if (members.classes.length) {
|
||||
|
||||
members.classes.forEach(function(c) {
|
||||
var moduleSameName = find({kind: 'module', longname: c.longname});
|
||||
if (moduleSameName.length) {
|
||||
c.name = c.name.replace('module:', 'require("')+'")';
|
||||
moduleSameName[0].module = c;
|
||||
}
|
||||
|
||||
if ( !hasOwnProp.call(seen, c.longname) ) {
|
||||
hasClassList = true;
|
||||
classNav += '<li>'+linkto(c.longname, c.name)+'</li>';
|
||||
}
|
||||
seen[c.longname] = true;
|
||||
});
|
||||
|
||||
if (hasClassList) {
|
||||
if (classNav !== '') {
|
||||
nav += '<h3>Classes</h3><ul>';
|
||||
nav += classNav;
|
||||
nav += '</ul>';
|
||||
@ -427,6 +446,8 @@ exports.publish = function(taffyData, opts, tutorials) {
|
||||
|
||||
// once for all
|
||||
view.nav = buildNav(members);
|
||||
attachModuleSymbols( find({ kind: ['class', 'function'], longname: {left: 'module:'} }),
|
||||
members.modules );
|
||||
|
||||
// only output pretty-printed source files if requested; do this before generating any other
|
||||
// pages, so the other pages can link to the source files
|
||||
|
||||
10
test/fixtures/moduleisfunction.js
vendored
Normal file
10
test/fixtures/moduleisfunction.js
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
/**
|
||||
* This is a module called foo.
|
||||
* @module foo
|
||||
*/
|
||||
|
||||
/**
|
||||
* The module exports a single function.
|
||||
* @param {string} bar
|
||||
*/
|
||||
module.exports = function(bar) {};
|
||||
5
test/specs/documentation/moduleisconstructor.js
Normal file
5
test/specs/documentation/moduleisconstructor.js
Normal file
@ -0,0 +1,5 @@
|
||||
/*global describe: true, expect: true, it: true, xdescribe: true */
|
||||
|
||||
xdescribe('module that exports a constructor', function() {
|
||||
// TODO
|
||||
});
|
||||
23
test/specs/documentation/moduleisfunction.js
Normal file
23
test/specs/documentation/moduleisfunction.js
Normal file
@ -0,0 +1,23 @@
|
||||
/*global describe: true, expect: true, it: true, jasmine: true */
|
||||
|
||||
describe('module that exports a function that is not a constructor', function() {
|
||||
var docSet = jasmine.getDocSetFromFile('test/fixtures/moduleisfunction.js');
|
||||
var functions = docSet.doclets.filter(function(doclet) {
|
||||
return doclet.kind === 'function';
|
||||
});
|
||||
|
||||
it('should include one doclet whose kind is "function"', function() {
|
||||
expect(functions.length).toBe(1);
|
||||
expect(functions[0].kind).toBe('function');
|
||||
});
|
||||
|
||||
describe('function doclet', function() {
|
||||
it('should not include a "scope" property', function() {
|
||||
expect(functions[0].scope).not.toBeDefined();
|
||||
});
|
||||
|
||||
it('should not include a "memberof" property', function() {
|
||||
expect(functions[0].memberof).not.toBeDefined();
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -379,6 +379,7 @@ describe("jsdoc/util/templateHelper", function() {
|
||||
{kind: 'constant'}, // global
|
||||
{kind: 'typedef'}, // global
|
||||
{kind: 'constant', memberof: 'module:one/two'}, // not global
|
||||
{kind: 'function', name: 'module:foo', longname: 'module:foo'} // not global
|
||||
];
|
||||
var array = classes.concat(externals.concat(events.concat(mixins.concat(modules.concat(namespaces.concat(misc))))));
|
||||
var data = require('taffydb').taffy(array);
|
||||
@ -439,7 +440,7 @@ describe("jsdoc/util/templateHelper", function() {
|
||||
});
|
||||
|
||||
it("globals are detected", function() {
|
||||
compareObjectArrays(misc.slice(0, -1), members.globals);
|
||||
compareObjectArrays(misc.slice(0, -2), members.globals);
|
||||
});
|
||||
});
|
||||
|
||||
@ -1259,6 +1260,18 @@ describe("jsdoc/util/templateHelper", function() {
|
||||
|
||||
expect(url).toEqual('_.html#"*foo"');
|
||||
});
|
||||
|
||||
it('should create a url for a function that is the only symbol exported by a module.',
|
||||
function() {
|
||||
var mockDoclet = {
|
||||
kind: 'function',
|
||||
longname: 'module:bar',
|
||||
name: 'module:bar'
|
||||
};
|
||||
var url = helper.createLink(mockDoclet);
|
||||
|
||||
expect(url).toEqual('module-bar.html');
|
||||
});
|
||||
});
|
||||
|
||||
describe("resolveAuthorLinks", function() {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user