From 62abd1102fc1b953106f03690766f5b84ccdf39b Mon Sep 17 00:00:00 2001 From: Brett Zamir Date: Sun, 3 Jan 2021 23:00:19 +0800 Subject: [PATCH] fix(`require-jsdoc`): skip past type annotations when seeking backward through decorators; fixes #659 --- README.md | 14 +++++++++ src/eslint/getJSDocComment.js | 43 ++++++++++++++++----------- test/rules/assertions/requireJsdoc.js | 22 ++++++++++++++ 3 files changed, 61 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index 11cb97818..f76967b2e 100644 --- a/README.md +++ b/README.md @@ -10998,6 +10998,20 @@ const foo = { } } // Options: [{"contexts":[":not(Property) > ArrowFunctionExpression"],"require":{"ArrowFunctionExpression":false,"ClassDeclaration":true,"ClassExpression":true}}] + +/** Defines the current user's settings. */ +@Injectable({ + providedIn: 'root', +}) +@State> +({ + name: 'userSettings', + defaults: { + isDev: !environment.production, + }, +}) +export class UserSettingsState { } +// Options: [{"require":{"ClassDeclaration":true}}] ```` diff --git a/src/eslint/getJSDocComment.js b/src/eslint/getJSDocComment.js index 314db01b2..8790d5638 100644 --- a/src/eslint/getJSDocComment.js +++ b/src/eslint/getJSDocComment.js @@ -14,32 +14,39 @@ const isCommentToken = (token) => { return token.type === 'Line' || token.type === 'Block' || token.type === 'Shebang'; }; +const decoratorMetaTokens = new Map([[')', '('], ['>', '<']]); + const getDecorator = (token, sourceCode) => { if (!token) { return false; } - if (token.type === 'Punctuator' && token.value === ')') { - let nested = 0; - let tokenBefore = token; - do { - tokenBefore = sourceCode.getTokenBefore(tokenBefore, {includeComments: true}); - // istanbul ignore if - if (tokenBefore && tokenBefore.type === 'Punctuator') { - if (tokenBefore.value === ')') { - nested++; - } - if (tokenBefore.value === '(') { - if (nested) { - nested--; - } else { - break; + if (token.type === 'Punctuator') { + const tokenClose = token.value; + const tokenOpen = decoratorMetaTokens.get(tokenClose); + if (tokenOpen) { + let nested = 0; + let tokenBefore = token; + do { + tokenBefore = sourceCode.getTokenBefore(tokenBefore, {includeComments: true}); + // istanbul ignore if + if (tokenBefore && tokenBefore.type === 'Punctuator') { + if (tokenBefore.value === tokenClose) { + nested++; + } + if (tokenBefore.value === tokenOpen) { + if (nested) { + nested--; + } else { + break; + } } } - } - } while (tokenBefore); + } while (tokenBefore); - return tokenBefore; + return tokenBefore; + } } + if (token.type === 'Identifier') { const tokenBefore = sourceCode.getTokenBefore(token, {includeComments: true}); if (tokenBefore && tokenBefore.type === 'Punctuator' && tokenBefore.value === '@') { diff --git a/test/rules/assertions/requireJsdoc.js b/test/rules/assertions/requireJsdoc.js index a0c951b79..01fe6de3f 100644 --- a/test/rules/assertions/requireJsdoc.js +++ b/test/rules/assertions/requireJsdoc.js @@ -4231,5 +4231,27 @@ export default { }, }], }, + { + code: ` + /** Defines the current user's settings. */ + @Injectable({ + providedIn: 'root', + }) + @State> + ({ + name: 'userSettings', + defaults: { + isDev: !environment.production, + }, + }) + export class UserSettingsState { } + `, + options: [{ + require: { + ClassDeclaration: true, + }, + }], + parser: require.resolve('@typescript-eslint/parser'), + }, ], };