From 7500b00ab203de8b176ad17eebd69ae46a464561 Mon Sep 17 00:00:00 2001 From: Brett Zamir Date: Sun, 29 Dec 2019 17:50:44 +0800 Subject: [PATCH] feat(`require-param-*`, `require-returns-*`, `require-returns`): allows `contexts` option to be set to "any" to check virtual function docs like `@callback` or `@function` with `@interface`; fixes #406 --- README.md | 290 ++++++++++++++++++++++++ src/iterateJsdoc.js | 4 +- src/rules/requireReturns.js | 4 +- test/rules/assertions/requireReturns.js | 193 ++++++++++++++++ 4 files changed, 487 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 8303d4ec3..26eef0aa9 100644 --- a/README.md +++ b/README.md @@ -7884,6 +7884,29 @@ function quux (foo) { } // Message: Missing JSDoc @param "foo" description. +/** + * @param foo + */ +function quux (foo) { + +} +// Options: [{"contexts":["any"]}] +// Message: Missing JSDoc @param "foo" description. + +/** + * @function + * @param foo + */ +// Options: [{"contexts":["any"]}] +// Message: Missing JSDoc @param "foo" description. + +/** + * @callback + * @param foo + */ +// Options: [{"contexts":["any"]}] +// Message: Missing JSDoc @param "foo" description. + /** * @arg foo */ @@ -7919,6 +7942,24 @@ function quux (foo) { function quux (foo) { } + +/** + * @param foo Foo. + */ +function quux (foo) { + +} +// Options: [{"contexts":["any"]}] + +/** + * @function + * @param foo + */ + +/** + * @callback + * @param foo + */ ```` @@ -7971,6 +8012,29 @@ function quux (foo) { } // Message: There must be an identifier after @param tag. +/** + * @param {string} + */ +function quux (foo) { + +} +// Options: [{"contexts":["any"]}] +// Message: There must be an identifier after @param tag. + +/** + * @function + * @param {string} + */ +// Options: [{"contexts":["any"]}] +// Message: There must be an identifier after @param tag. + +/** + * @callback + * @param {string} + */ +// Options: [{"contexts":["any"]}] +// Message: There must be an identifier after @param tag. + /** * @param foo */ @@ -7991,12 +8055,30 @@ function quux (foo) { } +/** + * @param foo + */ +function quux (foo) { + +} +// Options: [{"contexts":["any"]}] + /** * @param {string} foo */ function quux (foo) { } + +/** + * @function + * @param + */ + +/** + * @callback + * @param + */ ```` @@ -8037,6 +8119,29 @@ function quux (foo) { } // Message: Missing JSDoc @param "foo" type. +/** + * @param foo + */ +function quux (foo) { + +} +// Options: [{"contexts":["any"]}] +// Message: Missing JSDoc @param "foo" type. + +/** + * @function + * @param foo + */ +// Options: [{"contexts":["any"]}] +// Message: Missing JSDoc @param "foo" type. + +/** + * @callback + * @param foo + */ +// Options: [{"contexts":["any"]}] +// Message: Missing JSDoc @param "foo" type. + /** * @arg foo */ @@ -8072,6 +8177,24 @@ function quux (foo) { function quux (foo) { } + +/** + * @param {number} foo + */ +function quux (foo) { + +} +// Options: [{"contexts":["any"]}] + +/** + * @function + * @param foo + */ + +/** + * @callback + * @param foo + */ ```` @@ -9364,6 +9487,29 @@ function quux (foo) { } // Message: Missing JSDoc @returns description. +/** + * @returns {string} + */ +function quux (foo) { + +} +// Options: [{"contexts":["any"]}] +// Message: Missing JSDoc @returns description. + +/** + * @function + * @returns {string} + */ +// Options: [{"contexts":["any"]}] +// Message: Missing JSDoc @returns description. + +/** + * @callback + * @returns {string} + */ +// Options: [{"contexts":["any"]}] +// Message: Missing JSDoc @returns description. + /** * @return */ @@ -9400,6 +9546,14 @@ function quux () { } +/** + * @returns Foo. + */ +function quux () { + +} +// Options: [{"contexts":["any"]}] + /** * @returns {undefined} */ @@ -9413,6 +9567,16 @@ function quux () { function quux () { } + +/** + * @function + * @returns + */ + +/** + * @callback + * @returns + */ ```` @@ -9462,6 +9626,29 @@ function quux () { } // Message: Missing JSDoc @returns type. +/** + * @returns Foo. + */ +function quux () { + +} +// Options: [{"contexts":["any"]}] +// Message: Missing JSDoc @returns type. + +/** + * @function + * @returns Foo. + */ +// Options: [{"contexts":["any"]}] +// Message: Missing JSDoc @returns type. + +/** + * @callback + * @returns Foo. + */ +// Options: [{"contexts":["any"]}] +// Message: Missing JSDoc @returns type. + /** * @return Foo. */ @@ -9490,6 +9677,24 @@ The following patterns are not considered problems: function quux () { } + +/** + * @returns {number} + */ +function quux () { + +} +// Options: [{"contexts":["any"]}] + +/** + * @function + * @returns Foo. + */ + +/** + * @callback + * @returns Foo. + */ ```` @@ -9631,6 +9836,26 @@ function quux () { // Options: [{"forceRequireReturn":true}] // Message: Missing JSDoc @returns declaration. +/** + * + */ +function quux () { +} +// Options: [{"contexts":["any"],"forceRequireReturn":true}] +// Message: Missing JSDoc @returns declaration. + +/** + * @function + */ +// Options: [{"contexts":["any"],"forceRequireReturn":true}] +// Message: Missing JSDoc @returns declaration. + +/** + * @callback + */ +// Options: [{"contexts":["any"],"forceRequireReturn":true}] +// Message: Missing JSDoc @returns declaration. + const language = { /** * @param {string} name @@ -9649,6 +9874,20 @@ async function quux () { // Options: [{"forceReturnsWithAsync":true}] // Message: Missing JSDoc @returns declaration. +/** + * @function + * @async + */ +// Options: [{"contexts":["any"],"forceReturnsWithAsync":true}] +// Message: Missing JSDoc @returns declaration. + +/** + * @callback + * @async + */ +// Options: [{"contexts":["any"],"forceReturnsWithAsync":true}] +// Message: Missing JSDoc @returns declaration. + /** * @returns {undefined} * @returns {void} @@ -9707,6 +9946,15 @@ function quux () { return foo; } +/** + * @returns Foo. + */ +function quux () { + + return foo; +} +// Options: [{"contexts":["any"]}] + /** * */ @@ -9976,6 +10224,48 @@ async function foo(a) { async function foo(a) { return; } + +/** + * + */ +// Options: [{"contexts":["any"]}] + +/** + * @async + */ +// Options: [{"contexts":["any"]}] + +/** + * @function + */ +// Options: [{"forceRequireReturn":true}] + +/** + * @callback + */ +// Options: [{"forceRequireReturn":true}] + +/** + * @function + * @async + */ +// Options: [{"forceReturnsWithAsync":true}] + +/** + * @callback + * @async + */ +// Options: [{"forceReturnsWithAsync":true}] + +/** + * @function + */ +// Options: [{"contexts":["any"],"forceReturnsWithAsync":true}] + +/** + * @callback + */ +// Options: [{"contexts":["any"],"forceReturnsWithAsync":true}] ```` diff --git a/src/iterateJsdoc.js b/src/iterateJsdoc.js index 0ca2d403b..5b5d736de 100644 --- a/src/iterateJsdoc.js +++ b/src/iterateJsdoc.js @@ -147,11 +147,11 @@ const getUtils = ( }; utils.isConstructor = () => { - return node.parent && node.parent.kind === 'constructor'; + return node && node.parent && node.parent.kind === 'constructor'; }; utils.isSetter = () => { - return node.parent.kind === 'set'; + return node && node.parent.kind === 'set'; }; utils.getJsdocNamesDeep = (tagName) => { diff --git a/src/rules/requireReturns.js b/src/rules/requireReturns.js index 68b883c65..d6db8a60f 100644 --- a/src/rules/requireReturns.js +++ b/src/rules/requireReturns.js @@ -75,7 +75,7 @@ export default iterateJsdoc(({ 'ArrowFunctionExpression', 'FunctionDeclaration', 'FunctionExpression', - ].includes(node.type); + ].includes(node && node.type); // In case the code returns something, we expect a return value in JSDoc. const [tag] = tags; @@ -93,7 +93,7 @@ export default iterateJsdoc(({ } const isAsync = !iteratingFunction && utils.hasTag('async') || - iteratingFunction && (utils.hasTag('async') || utils.isAsync()); + iteratingFunction && utils.isAsync(); if (forceReturnsWithAsync && isAsync) { return true; diff --git a/test/rules/assertions/requireReturns.js b/test/rules/assertions/requireReturns.js index 584ec7d02..b8906729c 100644 --- a/test/rules/assertions/requireReturns.js +++ b/test/rules/assertions/requireReturns.js @@ -207,6 +207,59 @@ export default { forceRequireReturn: true, }], }, + { + code: ` + /** + * + */ + function quux () { + } + `, + errors: [ + { + line: 2, + message: 'Missing JSDoc @returns declaration.', + }, + ], + options: [{ + contexts: ['any'], + forceRequireReturn: true, + }], + }, + { + code: ` + /** + * @function + */ + `, + errors: [ + { + line: 2, + message: 'Missing JSDoc @returns declaration.', + }, + ], + options: [{ + contexts: ['any'], + forceRequireReturn: true, + }], + }, + { + code: ` + /** + * @callback + */ + `, + errors: [ + { + line: 2, + message: 'Missing JSDoc @returns declaration.', + }, + ], + options: [{ + contexts: ['any'], + forceRequireReturn: true, + }], + }, { code: ` const language = { @@ -246,6 +299,42 @@ export default { ecmaVersion: 8, }, }, + { + code: ` + /** + * @function + * @async + */ + `, + errors: [ + { + line: 2, + message: 'Missing JSDoc @returns declaration.', + }, + ], + options: [{ + contexts: ['any'], + forceReturnsWithAsync: true, + }], + }, + { + code: ` + /** + * @callback + * @async + */ + `, + errors: [ + { + line: 2, + message: 'Missing JSDoc @returns declaration.', + }, + ], + options: [{ + contexts: ['any'], + forceReturnsWithAsync: true, + }], + }, { code: ` /** @@ -364,6 +453,22 @@ export default { } `, }, + { + code: ` + /** + * @returns Foo. + */ + function quux () { + + return foo; + } + `, + options: [ + { + contexts: ['any'], + }, + ], + }, { code: ` /** @@ -795,5 +900,93 @@ export default { ecmaVersion: 8, }, }, + { + code: ` + /** + * + */ + `, + options: [ + { + contexts: ['any'], + }, + ], + }, + { + code: ` + /** + * @async + */ + `, + options: [ + { + contexts: ['any'], + }, + ], + }, + { + code: ` + /** + * @function + */ + `, + options: [{ + forceRequireReturn: true, + }], + }, + { + code: ` + /** + * @callback + */ + `, + options: [{ + forceRequireReturn: true, + }], + }, + { + code: ` + /** + * @function + * @async + */ + `, + options: [{ + forceReturnsWithAsync: true, + }], + }, + { + code: ` + /** + * @callback + * @async + */ + `, + options: [{ + forceReturnsWithAsync: true, + }], + }, + { + code: ` + /** + * @function + */ + `, + options: [{ + contexts: ['any'], + forceReturnsWithAsync: true, + }], + }, + { + code: ` + /** + * @callback + */ + `, + options: [{ + contexts: ['any'], + forceReturnsWithAsync: true, + }], + }, ], };