diff --git a/.README/README.md b/.README/README.md index 6cbcce042..6ed3de84e 100644 --- a/.README/README.md +++ b/.README/README.md @@ -473,8 +473,8 @@ While at their simplest, these can be an array of string selectors, one can also supply an object with `context` (in place of the string) and one of two properties: -1. For `require-jsdoc`, there is also an `inlineCommentBlock` property. See - that rule for details. +1. For `require-jsdoc`, there are also `inlineCommentBlock` and + `minLineCount` properties. See that rule for details. 1. For `no-missing-syntax` and `no-restricted-syntax`, there is also a `message` property which allows customization of the message to be shown when the rule is triggered. diff --git a/.README/rules/require-jsdoc.md b/.README/rules/require-jsdoc.md index 96fe3b70f..4700415cc 100644 --- a/.README/rules/require-jsdoc.md +++ b/.README/rules/require-jsdoc.md @@ -41,7 +41,8 @@ contexts where you wish the rule to be applied (e.g., `Property` for properties). If specified as an object, it should have a `context` property and can have an `inlineCommentBlock` property which, if set to `true`, will add an inline `/** */` instead of the regular, multi-line, indented jsdoc -block which will otherwise be added. Defaults to an empty array. +block which will otherwise be added. Defaults to an empty array. Contexts +may also have their own `minLineCount` property. Note that you may need to disable `require` items (e.g., `MethodDefinition`) if you are specifying a more precise form in `contexts` (e.g., `MethodDefinition:not([accessibility="private"] > FunctionExpression`). @@ -95,7 +96,8 @@ Defaults to `true`. ##### `minLineCount` An integer to indicate a minimum number of lines expected for a node in order -for it to require documentation. Defaults to 0. +for it to require documentation. Defaults to `undefined`. This option will +apply to any context; see `contexts` for line counts per context. ||| |---|---| diff --git a/README.md b/README.md index 2ff127aaf..10245a069 100644 --- a/README.md +++ b/README.md @@ -569,8 +569,8 @@ While at their simplest, these can be an array of string selectors, one can also supply an object with `context` (in place of the string) and one of two properties: -1. For `require-jsdoc`, there is also an `inlineCommentBlock` property. See - that rule for details. +1. For `require-jsdoc`, there are also `inlineCommentBlock` and + `minLineCount` properties. See that rule for details. 1. For `no-missing-syntax` and `no-restricted-syntax`, there is also a `message` property which allows customization of the message to be shown when the rule is triggered. @@ -12821,7 +12821,8 @@ contexts where you wish the rule to be applied (e.g., `Property` for properties). If specified as an object, it should have a `context` property and can have an `inlineCommentBlock` property which, if set to `true`, will add an inline `/** */` instead of the regular, multi-line, indented jsdoc -block which will otherwise be added. Defaults to an empty array. +block which will otherwise be added. Defaults to an empty array. Contexts +may also have their own `minLineCount` property. Note that you may need to disable `require` items (e.g., `MethodDefinition`) if you are specifying a more precise form in `contexts` (e.g., `MethodDefinition:not([accessibility="private"] > FunctionExpression`). @@ -12889,7 +12890,8 @@ Defaults to `true`. ##### minLineCount An integer to indicate a minimum number of lines expected for a node in order -for it to require documentation. Defaults to 0. +for it to require documentation. Defaults to `undefined`. This option will +apply to any context; see `contexts` for line counts per context. ||| |---|---| @@ -13691,6 +13693,33 @@ function quux () { function b () {} // "jsdoc/require-jsdoc": ["error"|"warn", {"minLineCount":2}] // Message: Missing JSDoc comment. + +function quux () { + return 3; +} + +var a = {}; +// "jsdoc/require-jsdoc": ["error"|"warn", {"contexts":[{"context":"FunctionDeclaration","minLineCount":2},{"context":"VariableDeclaration","minLineCount":2}],"require":{"FunctionDeclaration":false}}] +// Message: Missing JSDoc comment. + +function quux () { + return 3; +} + +var a = { + b: 1, + c: 2 +}; +// "jsdoc/require-jsdoc": ["error"|"warn", {"contexts":[{"context":"FunctionDeclaration","minLineCount":4},{"context":"VariableDeclaration","minLineCount":2}],"require":{"FunctionDeclaration":false}}] +// Message: Missing JSDoc comment. + +class A { + setId(newId: number): void { + this.id = id; + } +} +// "jsdoc/require-jsdoc": ["error"|"warn", {"contexts":[{"context":"MethodDefinition","minLineCount":3}],"require":{"ClassDeclaration":false,"FunctionExpression":false,"MethodDefinition":false}}] +// Message: Missing JSDoc comment. ```` The following patterns are not considered problems: @@ -14511,6 +14540,23 @@ export class User { function b () {} // "jsdoc/require-jsdoc": ["error"|"warn", {"minLineCount":4}] + +function quux () { + return 3; +} + +var a = { + b: 1, + c: 2 +}; +// "jsdoc/require-jsdoc": ["error"|"warn", {"contexts":[{"context":"FunctionDeclaration","minLineCount":4},{"context":"VariableDeclaration","minLineCount":5}],"require":{"FunctionDeclaration":false}}] + +class A { + setId(newId: number): void { + this.id = id; + } +} +// "jsdoc/require-jsdoc": ["error"|"warn", {"contexts":[{"context":"MethodDefinition","minLineCount":4}],"require":{"ClassDeclaration":false,"FunctionExpression":false,"MethodDefinition":false}}] ```` diff --git a/src/jsdocUtils.js b/src/jsdocUtils.js index acdd7a790..6bcffaa1a 100644 --- a/src/jsdocUtils.js +++ b/src/jsdocUtils.js @@ -271,7 +271,7 @@ const getFunctionParameterNames = ( throw new Error(`Unsupported function signature format: \`${param.type}\`.`); }; - return (functionNode.params || functionNode.value.params).map((param) => { + return functionNode.params.map((param) => { return getParamName(param); }); }; diff --git a/src/rules/requireJsdoc.js b/src/rules/requireJsdoc.js index 6e524c27f..a18392280 100644 --- a/src/rules/requireJsdoc.js +++ b/src/rules/requireJsdoc.js @@ -59,6 +59,9 @@ const OPTIONS_SCHEMA = { inlineCommentBlock: { type: 'boolean', }, + minLineCount: { + type: 'integer', + }, }, type: 'object', }, @@ -83,7 +86,6 @@ const OPTIONS_SCHEMA = { type: 'string', }, minLineCount: { - default: 0, type: 'integer', }, publicOnly: { @@ -168,7 +170,7 @@ const getOptions = (context) => { exemptEmptyFunctions = false, enableFixer = true, fixerMessage = '', - minLineCount = 0, + minLineCount = undefined, } = context.options[0] || {}; return { @@ -225,10 +227,31 @@ export default { const checkJsDoc = (info, handler, node) => { if ( // Optimize - minLineCount && - (sourceCode.getText(node).match(/\n/gu)?.length ?? 0) < minLineCount + minLineCount !== undefined || contexts.some(({ + minLineCount: count, + }) => { + return count !== undefined; + }) ) { - return; + const underMinLine = (count) => { + return count !== undefined && count > + (sourceCode.getText(node).match(/\n/gu)?.length ?? 0) + 1; + }; + + if (underMinLine(minLineCount)) { + return; + } + + const { + minLineCount: contextMinLineCount, + } = contexts.find(({ + context: ctxt, + }) => { + return ctxt === (info.selector || node.type); + }) || {}; + if (underMinLine(contextMinLineCount)) { + return; + } } const jsDocNode = getJSDocComment(sourceCode, node, settings); @@ -387,14 +410,6 @@ export default { }, FunctionExpression (node) { - if (hasOption('MethodDefinition') && node.parent.type === 'MethodDefinition') { - checkJsDoc({ - isFunctionContext: true, - }, null, node); - - return; - } - if (!hasOption('FunctionExpression')) { return; } @@ -412,6 +427,17 @@ export default { }, null, node); } }, + + MethodDefinition (node) { + if (!hasOption('MethodDefinition')) { + return; + } + + checkJsDoc({ + isFunctionContext: true, + selector: 'MethodDefinition', + }, null, node.value); + }, }; }, meta: { diff --git a/test/rules/assertions/requireJsdoc.js b/test/rules/assertions/requireJsdoc.js index 8c00619a0..4680b7bc1 100644 --- a/test/rules/assertions/requireJsdoc.js +++ b/test/rules/assertions/requireJsdoc.js @@ -3912,6 +3912,137 @@ function quux (foo) { function b () {} `, }, + { + code: ` + function quux () { + return 3; + } + + var a = {}; + `, + errors: [ + { + line: 2, + message: 'Missing JSDoc comment.', + }, + ], + options: [ + { + contexts: [ + { + context: 'FunctionDeclaration', + minLineCount: 2, + }, + { + context: 'VariableDeclaration', + minLineCount: 2, + }, + ], + require: { + FunctionDeclaration: false, + }, + }, + ], + output: ` + /** + * + */ + function quux () { + return 3; + } + + var a = {}; + `, + }, + { + code: ` + function quux () { + return 3; + } + + var a = { + b: 1, + c: 2 + }; + `, + errors: [ + { + line: 6, + message: 'Missing JSDoc comment.', + }, + ], + options: [ + { + contexts: [ + { + context: 'FunctionDeclaration', + minLineCount: 4, + }, + { + context: 'VariableDeclaration', + minLineCount: 2, + }, + ], + require: { + FunctionDeclaration: false, + }, + }, + ], + output: ` + function quux () { + return 3; + } + + /** + * + */ + var a = { + b: 1, + c: 2 + }; + `, + }, + { + code: ` + class A { + setId(newId: number): void { + this.id = id; + } + } + `, + errors: [ + { + line: 3, + message: 'Missing JSDoc comment.', + }, + ], + options: [ + { + contexts: [ + { + context: 'MethodDefinition', + minLineCount: 3, + }, + ], + require: { + ClassDeclaration: false, + FunctionExpression: false, + MethodDefinition: false, + }, + }, + ], + output: ` + class A { + /** + * + */ + setId(newId: number): void { + this.id = id; + } + } + `, + parser: require.resolve('@typescript-eslint/parser'), + }, ], valid: [ { @@ -5874,5 +6005,59 @@ function quux (foo) { }, ], }, + { + code: ` + function quux () { + return 3; + } + + var a = { + b: 1, + c: 2 + }; + `, + options: [ + { + contexts: [ + { + context: 'FunctionDeclaration', + minLineCount: 4, + }, + { + context: 'VariableDeclaration', + minLineCount: 5, + }, + ], + require: { + FunctionDeclaration: false, + }, + }, + ], + }, + { + code: ` + class A { + setId(newId: number): void { + this.id = id; + } + } + `, + options: [ + { + contexts: [ + { + context: 'MethodDefinition', + minLineCount: 4, + }, + ], + require: { + ClassDeclaration: false, + FunctionExpression: false, + MethodDefinition: false, + }, + }, + ], + parser: require.resolve('@typescript-eslint/parser'), + }, ], };