autodetect generator functions, and support a new @generator tag (#1158)

This commit is contained in:
Jeff Williams 2017-07-04 20:36:42 -07:00
parent cc63e98a8e
commit 133ee8a5af
9 changed files with 119 additions and 4 deletions

View File

@ -337,6 +337,10 @@ var DOCLET_SCHEMA = exports.DOCLET_SCHEMA = {
type: BOOLEAN_OPTIONAL,
optional: true
},
generator: {
type: BOOLEAN,
optional: true
},
ignore: {
type: BOOLEAN,
optional: true

View File

@ -359,6 +359,28 @@ function makePrivatePropertyFinisher(parser) {
};
}
/**
* Create a function that will mark a doclet as a generator function.
*
* @private
* @param {module:jsdoc/src/parser.Parser} parser - The JSDoc parser.
* @return {function} A function that marks a doclet as a generator function.
*/
function makeGeneratorFinisher(parser) {
return function(e) {
var doclet = e.doclet;
if (!doclet) {
return;
}
if (e.code.node.generator || e.code.node.init && e.code.node.init.generator ||
e.code.node.value && e.code.node.value.generator) {
doclet.generator = true;
}
};
}
// TODO: docs
function SymbolFound(node, filename, extras) {
var self = this;
@ -683,7 +705,9 @@ Visitor.prototype.makeSymbolFoundEvent = function(node, parser, filename) {
// handle rest parameters
makeRestParamFinisher(parser),
// handle async functions
makeAsyncFunctionFinisher(parser)
makeAsyncFunctionFinisher(parser),
// handle generator functions
makeGeneratorFinisher(parser)
];
e = new SymbolFound(node, filename, extras);
@ -731,7 +755,9 @@ Visitor.prototype.makeSymbolFoundEvent = function(node, parser, filename) {
// handle rest parameters
makeRestParamFinisher(parser),
// handle async functions
makeAsyncFunctionFinisher(parser)
makeAsyncFunctionFinisher(parser),
// handle generator functions
makeGeneratorFinisher(parser)
];
// for constructors, we attempt to merge the constructor's docs into the class's docs
if (node.kind === 'constructor') {
@ -774,8 +800,13 @@ Visitor.prototype.makeSymbolFoundEvent = function(node, parser, filename) {
// like: var i = 0;
case Syntax.VariableDeclarator:
// handle async functions
extras.finishers = [makeAsyncFunctionFinisher(parser)];
extras.finishers = [
// handle async functions
makeAsyncFunctionFinisher(parser),
// handle generator functions
makeGeneratorFinisher(parser)
];
e = new SymbolFound(node, filename, extras);

View File

@ -437,6 +437,12 @@ var baseTags = exports.baseTags = {
},
synonyms: ['func', 'method']
},
generator: {
mustNotHaveValue: true,
onTagged: function(doclet, tag) {
doclet.generator = true;
}
},
global: {
mustNotHaveValue: true,
onTagged: function(doclet, tag) {

View File

@ -637,6 +637,10 @@ exports.getAttribs = function(d) {
attribs.push('async');
}
if (d.generator) {
attribs.push('generator');
}
if (d.virtual) {
attribs.push('abstract');
}

28
test/fixtures/generators.js vendored Normal file
View File

@ -0,0 +1,28 @@
'use strict';
/** Generate unique IDs starting at 0. */
function* startsAt0() {
var index = 0;
while (true) {
yield index++;
}
}
/** Generate unique IDs starting at 1. */
var startsAt1 = function* startsAt1() {
var index = 1;
while (true) {
yield index++;
}
};
/** Generator class. */
class Generator {
/** Generate unique IDs starting at 2. */
* startsAt2() {
var index = 2;
while (true) {
yield index++;
}
}
}

7
test/fixtures/generatortag.js vendored Normal file
View File

@ -0,0 +1,7 @@
'use strict';
/**
* Sample generator function.
* @function idMaker
* @generator
*/

View File

@ -0,0 +1,20 @@
'use strict';
describe('generator functions', function() {
var docSet = jasmine.getDocSetFromFile('test/fixtures/generators.js');
var startsAt0 = docSet.getByLongname('startsAt0')[0];
var startsAt1 = docSet.getByLongname('startsAt1')[0];
var startsAt2 = docSet.getByLongname('Generator#startsAt2')[0];
it('should flag generator functions', function() {
expect(startsAt0.generator).toBe(true);
});
it('should flag generator functions assigned to variables', function() {
expect(startsAt1.generator).toBe(true);
});
it('should flag generator functions that are method definitions', function() {
expect(startsAt2.generator).toBe(true);
});
});

View File

@ -728,6 +728,11 @@ describe("jsdoc/util/templateHelper", function() {
doTests(tests, 'async');
});
it('should detect if a doclet is a generator function', function() {
var tests = { '@generator': 'generator' };
doTests(tests, 'generator');
});
it("should detect multiple attributes", function() {
var fdsaFoo = new doclet.Doclet('/** @const module:fdsa~FOO\n@readonly\n@private */', {});
attribs = helper.getAttribs(fdsaFoo);

View File

@ -0,0 +1,10 @@
'use strict';
describe('@generator tag', function() {
var docSet = jasmine.getDocSetFromFile('test/fixtures/generatortag.js');
var idMaker = docSet.getByLongname('idMaker')[0];
it('should mark the symbol as a generator function', function() {
expect(idMaker.generator).toBe(true);
});
});