Skip to content

Commit

Permalink
optimize: ensure with new fix that we avoid checking back too far
Browse files Browse the repository at this point in the history
  • Loading branch information
brettz9 committed Jan 24, 2021
1 parent 6bda6b4 commit e13a03a
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 1 deletion.
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10565,6 +10565,13 @@ export class User {
}
// Options: [{"contexts":["ClassProperty:has(Decorator[expression.callee.name=\"Input\"])"]}]
// Message: Missing JSDoc comment.

@Input()
export class UserSettingsState {
method () {}
}
// Options: [{"require":{"MethodDefinition":true}}]
// Message: Missing JSDoc comment.
````

The following patterns are not considered problems:
Expand Down
34 changes: 33 additions & 1 deletion src/eslint/getJSDocComment.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,23 +16,29 @@ const isCommentToken = (token) => {

const decoratorMetaTokens = new Map([[')', '('], ['>', '<']]);

// eslint-disable-next-line complexity
const getDecorator = (token, sourceCode) => {
if (!token) {
return false;
}

if (token.type === 'Punctuator') {
const tokenClose = token.value;
const tokenOpen = decoratorMetaTokens.get(tokenClose);
if (tokenOpen) {
let nested = 0;
let tokenBefore = token;
let exitEarlyUnlessTyped = false;
do {
tokenBefore = sourceCode.getTokenBefore(tokenBefore, {includeComments: true});
// istanbul ignore if
if (tokenBefore && tokenBefore.type === 'Punctuator') {
if (tokenBefore.value === tokenClose) {
nested++;
} else if (tokenBefore.value === tokenOpen) {
if (tokenOpen === '(') {
exitEarlyUnlessTyped = true;
}
if (nested) {
nested--;
} else {
Expand All @@ -42,7 +48,33 @@ const getDecorator = (token, sourceCode) => {
}
} while (tokenBefore);

return getDecorator(tokenBefore, sourceCode);
// Because our token retrieval doesn't give us as much info as AST, and
// because decorators can be nested and fairly complex, besides finding
// any decorators, we also want to avoid checking backwards indefinitely
// in a potentially large document, so we exit early if parentheses are
// not preceded by a type where we have to keep checking backward for
// now (such as a regular call expression) or if a decorator is found.
if (exitEarlyUnlessTyped) {
// Check for `@someDecorator(`
const identifier = sourceCode.getTokenBefore(tokenBefore, {includeComments: true});
if (identifier && identifier.type === 'Identifier') {
const before = sourceCode.getTokenBefore(identifier, {includeComments: true});
if (before && before.type === 'Punctuator' && before.value === '@') {
// Decorator found
return before;
}
}

// If decorators may have `:`, we might need to check for those as with typed.
if (!identifier || identifier.type !== 'Punctuator' || identifier.value !== '>') {
// Should not be a decorator
return false;
}

// Could be a typed decorator, so keep checking for one
}

return getDecorator(tokenBefore, sourceCode, true);
}
if (token.value === '@') {
return token;
Expand Down
29 changes: 29 additions & 0 deletions test/rules/assertions/requireJsdoc.js
Original file line number Diff line number Diff line change
Expand Up @@ -2763,6 +2763,35 @@ function quux (foo) {
`,
parser: require.resolve('@typescript-eslint/parser'),
},
{
code: `
@Input()
export class UserSettingsState {
method () {}
}
`,
errors: [
{
line: 4,
message: 'Missing JSDoc comment.',
},
],
options: [{
require: {
MethodDefinition: true,
},
}],
output: `
/**
*
*/
@Input()
export class UserSettingsState {
method () {}
}
`,
parser: require.resolve('@typescript-eslint/parser'),
},
],
valid: [{
code: `
Expand Down

0 comments on commit e13a03a

Please sign in to comment.