diff --git a/.README/rules/require-jsdoc.md b/.README/rules/require-jsdoc.md index ef5abc59..9b679702 100644 --- a/.README/rules/require-jsdoc.md +++ b/.README/rules/require-jsdoc.md @@ -113,6 +113,12 @@ apply to any context; see `contexts` for line counts per context. An optional message to add to the inserted JSDoc block. Defaults to the empty string. +### `skipInterveningOverloadedDeclarations` + +If `true`, will skip above uncommented overloaded functions to check +for a comment block (e.g., at the top of a set of overloaded functions). +Defaults to `true`. + ## Context and settings ||| @@ -120,7 +126,7 @@ empty string. |Context|`ArrowFunctionExpression`, `ClassDeclaration`, `ClassExpression`, `FunctionDeclaration`, `FunctionExpression`; others when `contexts` option enabled| |Tags|N/A| |Recommended|true| -|Options|`publicOnly`, `require`, `contexts`, `exemptEmptyConstructors`, `exemptEmptyFunctions`, `enableFixer`, `minLineCount`, `fixerMessage`| +|Options|`publicOnly`, `require`, `contexts`, `exemptEmptyConstructors`, `exemptEmptyFunctions`, `enableFixer`, `minLineCount`, `fixerMessage`, `skipInterveningOverloadedDeclarations`| ## Failing examples diff --git a/docs/rules/require-jsdoc.md b/docs/rules/require-jsdoc.md index f54f21ad..0196e5bf 100644 --- a/docs/rules/require-jsdoc.md +++ b/docs/rules/require-jsdoc.md @@ -15,6 +15,7 @@ * [`enableFixer`](#user-content-require-jsdoc-options-enablefixer) * [`minLineCount`](#user-content-require-jsdoc-options-minlinecount) * [`fixerMessage`](#user-content-require-jsdoc-options-fixermessage) + * [`skipInterveningOverloadedDeclarations`](#user-content-require-jsdoc-options-skipinterveningoverloadeddeclarations) * [Context and settings](#user-content-require-jsdoc-context-and-settings) * [Failing examples](#user-content-require-jsdoc-failing-examples) * [Passing examples](#user-content-require-jsdoc-passing-examples) @@ -157,6 +158,14 @@ apply to any context; see `contexts` for line counts per context. An optional message to add to the inserted JSDoc block. Defaults to the empty string. + + +### skipInterveningOverloadedDeclarations + +If `true`, will skip above uncommented overloaded functions to check +for a comment block (e.g., at the top of a set of overloaded functions). +Defaults to `true`. + ## Context and settings @@ -166,7 +175,7 @@ empty string. |Context|`ArrowFunctionExpression`, `ClassDeclaration`, `ClassExpression`, `FunctionDeclaration`, `FunctionExpression`; others when `contexts` option enabled| |Tags|N/A| |Recommended|true| -|Options|`publicOnly`, `require`, `contexts`, `exemptEmptyConstructors`, `exemptEmptyFunctions`, `enableFixer`, `minLineCount`, `fixerMessage`| +|Options|`publicOnly`, `require`, `contexts`, `exemptEmptyConstructors`, `exemptEmptyFunctions`, `enableFixer`, `minLineCount`, `fixerMessage`, `skipInterveningOverloadedDeclarations`| @@ -1041,6 +1050,32 @@ export class B implements A, B { } // "jsdoc/require-jsdoc": ["error"|"warn", {"contexts":["MethodDefinition"]}] // Message: Missing JSDoc comment. + +/** + * Test function with param. + * @param foo - Test param. + */ +function myFunction(foo: string): void; +/** + * Test function without param. + */ +function myFunction(): void; +function myFunction(foo?: string) {} +// "jsdoc/require-jsdoc": ["error"|"warn", {"skipInterveningOverloadedDeclarations":false}] +// Message: Missing JSDoc comment. + +/** + * Test function without param. + */ +function myFunction(): void; +/** + * Test function with param. + * @param foo - Test param. + */ +function myFunction(foo: string): void; +function myFunction(foo?: string) {} +// "jsdoc/require-jsdoc": ["error"|"warn", {"skipInterveningOverloadedDeclarations":false}] +// Message: Missing JSDoc comment. ```` @@ -1944,6 +1979,7 @@ export function arrayMap>(data: Source, ca export function arrayMap(data: Source, callback: MapCallback): AnyArrayType { return data.map(callback); } +// "jsdoc/require-jsdoc": ["error"|"warn", {"skipInterveningOverloadedDeclarations":true}] export interface A { a: string; @@ -1960,5 +1996,16 @@ export class B implements A { } } // "jsdoc/require-jsdoc": ["error"|"warn", {"contexts":["MethodDefinition"]}] + +/** + * Test function with param. + * @param foo - Test param. + */ +function myFunction(foo: string): void; +/** + * Test function without param. + */ +function myFunction(): void; +function myFunction(foo?: string) {} ```` diff --git a/docs/rules/require-param.md b/docs/rules/require-param.md index 84d3dcb8..281c7190 100644 --- a/docs/rules/require-param.md +++ b/docs/rules/require-param.md @@ -1842,5 +1842,16 @@ const inner = (c: number, d: string): void => { */ function quux (a, b) {} // "jsdoc/require-param": ["error"|"warn", {"ignoreWhenAllParamsMissing":true}] + +/** + * Test function with param. + * @param foo - Test param. + */ +function myFunction(foo: string): void; +/** + * Test function without param. + */ +function myFunction(): void; +function myFunction(foo?: string) {} ```` diff --git a/package.json b/package.json index d5105d43..b3e392b3 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "url": "http://gajus.com" }, "dependencies": { - "@es-joy/jsdoccomment": "~0.53.0", + "@es-joy/jsdoccomment": "~0.54.0", "are-docs-informative": "^0.0.2", "comment-parser": "1.4.1", "debug": "^4.4.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 28d42162..9cfc5218 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -9,8 +9,8 @@ importers: .: dependencies: '@es-joy/jsdoccomment': - specifier: ~0.53.0 - version: 0.53.0 + specifier: ~0.54.0 + version: 0.54.0 are-docs-informative: specifier: ^0.0.2 version: 0.0.2 @@ -778,8 +778,8 @@ packages: resolution: {integrity: sha512-YAdE/IJSpwbOTiaURNCKECdAwqrJuFiZhylmesBcIRawtYKnBR2wxPhoIewMg+Yu+QuYvHfJNReWpoxGBKOChA==} engines: {node: '>=18'} - '@es-joy/jsdoccomment@0.53.0': - resolution: {integrity: sha512-Wyed8Wfn3vMNVwrZrgLMxmqwmlcCE1/RfUAOHFzMJb3QLH03mi9Yv1iOCZjif0yx5EZUeJ+17VD1MHPka9IQjQ==} + '@es-joy/jsdoccomment@0.54.0': + resolution: {integrity: sha512-r+DsSLA9rhdL9+IXySvqi/4VfhVwMlMztv7xJCxki82DvcTSlk4AT878sUKxizUwSJ8UieuCbjjbNi1OL5by+Q==} engines: {node: '>=20.11.0'} '@eslint-community/eslint-utils@4.7.0': @@ -6011,7 +6011,7 @@ snapshots: esquery: 1.6.0 jsdoc-type-pratt-parser: 4.1.0 - '@es-joy/jsdoccomment@0.53.0': + '@es-joy/jsdoccomment@0.54.0': dependencies: '@types/estree': 1.0.8 '@typescript-eslint/types': 8.39.1 diff --git a/src/rules/requireJsdoc.js b/src/rules/requireJsdoc.js index 23d34254..669bc4a2 100644 --- a/src/rules/requireJsdoc.js +++ b/src/rules/requireJsdoc.js @@ -169,6 +169,10 @@ const OPTIONS_SCHEMA = { }, type: 'object', }, + skipInterveningOverloadedDeclarations: { + default: true, + type: 'boolean', + }, }, type: 'object', }; @@ -302,6 +306,7 @@ const getOption = (context, baseObject, option, key) => { * enableFixer: boolean, * exemptEmptyConstructors: boolean, * exemptEmptyFunctions: boolean, + * skipInterveningOverloadedDeclarations: boolean, * fixerMessage: string, * minLineCount: undefined|import('../iterateJsdoc.js').Integer, * publicOnly: boolean|{[key: string]: boolean|undefined} @@ -317,6 +322,7 @@ const getOptions = (context, settings) => { fixerMessage = '', minLineCount = undefined, publicOnly, + skipInterveningOverloadedDeclarations = true, } = context.options[0] || {}; return { @@ -386,6 +392,7 @@ const getOptions = (context, settings) => { /** @type {import('json-schema').JSONSchema4Object} */ (OPTIONS_SCHEMA.properties).require, ), + skipInterveningOverloadedDeclarations, }; }; @@ -411,6 +418,7 @@ export default { fixerMessage, minLineCount, require: requireOption, + skipInterveningOverloadedDeclarations, } = opts; const publicOnly = @@ -476,7 +484,11 @@ export default { } } - const jsDocNode = getJSDocComment(sourceCode, node, settings); + const jsDocNode = getJSDocComment( + sourceCode, node, settings, { + checkOverloads: skipInterveningOverloadedDeclarations, + }, + ); if (jsDocNode) { return; diff --git a/test/rules/assertions/requireJsdoc.js b/test/rules/assertions/requireJsdoc.js index 156d941a..5d547c5d 100644 --- a/test/rules/assertions/requireJsdoc.js +++ b/test/rules/assertions/requireJsdoc.js @@ -4296,6 +4296,92 @@ function quux (foo) { } `, }, + { + code: ` + /** + * Test function with param. + * @param foo - Test param. + */ + function myFunction(foo: string): void; + /** + * Test function without param. + */ + function myFunction(): void; + function myFunction(foo?: string) {} + `, + errors: [ + { + line: 11, + message: 'Missing JSDoc comment.', + }, + ], + languageOptions: { + parser: typescriptEslintParser, + }, + options: [ + { + skipInterveningOverloadedDeclarations: false, + }, + ], + output: ` + /** + * Test function with param. + * @param foo - Test param. + */ + function myFunction(foo: string): void; + /** + * Test function without param. + */ + function myFunction(): void; + /** + * + */ + function myFunction(foo?: string) {} + `, + }, + { + code: ` + /** + * Test function without param. + */ + function myFunction(): void; + /** + * Test function with param. + * @param foo - Test param. + */ + function myFunction(foo: string): void; + function myFunction(foo?: string) {} + `, + errors: [ + { + line: 11, + message: 'Missing JSDoc comment.', + }, + ], + languageOptions: { + parser: typescriptEslintParser, + }, + options: [ + { + skipInterveningOverloadedDeclarations: false, + }, + ], + output: ` + /** + * Test function without param. + */ + function myFunction(): void; + /** + * Test function with param. + * @param foo - Test param. + */ + function myFunction(foo: string): void; + /** + * + */ + function myFunction(foo?: string) {} + `, + }, ], valid: [ { @@ -6442,6 +6528,11 @@ function quux (foo) { languageOptions: { parser: typescriptEslintParser, }, + options: [ + { + skipInterveningOverloadedDeclarations: true, + }, + ], }, { code: ` @@ -6471,5 +6562,22 @@ function quux (foo) { }, ], }, + { + code: ` + /** + * Test function with param. + * @param foo - Test param. + */ + function myFunction(foo: string): void; + /** + * Test function without param. + */ + function myFunction(): void; + function myFunction(foo?: string) {} + `, + languageOptions: { + parser: typescriptEslintParser, + }, + }, ], }); diff --git a/test/rules/assertions/requireParam.js b/test/rules/assertions/requireParam.js index 73c5cff7..5d4d13d5 100644 --- a/test/rules/assertions/requireParam.js +++ b/test/rules/assertions/requireParam.js @@ -3677,5 +3677,23 @@ export default /** @type {import('../index.js').TestCases} */ ({ }, ], }, + { + code: ` + /** + * Test function with param. + * @param foo - Test param. + */ + function myFunction(foo: string): void; + /** + * Test function without param. + */ + function myFunction(): void; + function myFunction(foo?: string) {} + `, + languageOptions: { + parser: typescriptEslintParser, + sourceType: 'module', + }, + }, ], });