diff --git a/docs/rules/no-undefined-types.md b/docs/rules/no-undefined-types.md index 608a4f255..131b4f2e8 100644 --- a/docs/rules/no-undefined-types.md +++ b/docs/rules/no-undefined-types.md @@ -807,6 +807,15 @@ function quux(foo) { quux(0); +function quux() { + const foo = 1; + /** {@link foo} */ + const bar = foo; + console.log(bar); +} + +quux(); + /** * @import BadImportIgnoredByThisRule */ diff --git a/src/rules/noUndefinedTypes.js b/src/rules/noUndefinedTypes.js index 3642f1278..2a3399bf5 100644 --- a/src/rules/noUndefinedTypes.js +++ b/src/rules/noUndefinedTypes.js @@ -222,6 +222,21 @@ export default iterateJsdoc(({ // Program scope inside const cjsOrESMScope = globalScope.childScopes[0]?.block?.type === 'Program'; + /** + * @param {import("eslint").Scope.Scope | null} scope + * @returns {Set} + */ + const getValidRuntimeIdentifiers = (scope) => { + const result = new Set() + while (scope) { + for (const {name} of scope.variables) { + result.add(name) + } + scope = scope.upper + } + return result + }; + const allDefinedTypes = new Set(globalScope.variables.map(({ name, }) => { @@ -247,6 +262,7 @@ export default iterateJsdoc(({ .concat(importTags) .concat(definedTypes) .concat(/** @type {string[]} */ (definedPreferredTypes)) + .concat(...getValidRuntimeIdentifiers(node && sourceCode.getScope(node))) .concat( settings.mode === 'jsdoc' ? [] : diff --git a/test/rules/assertions/noUndefinedTypes.js b/test/rules/assertions/noUndefinedTypes.js index cc34f1581..285a7912f 100644 --- a/test/rules/assertions/noUndefinedTypes.js +++ b/test/rules/assertions/noUndefinedTypes.js @@ -1482,6 +1482,18 @@ export default /** @type {import('../index.js').TestCases} */ ({ 'no-unused-vars': 'error', }, }, + { + code: ` + function quux() { + const foo = 1; + /** {@link foo} */ + const bar = foo; + console.log(bar); + } + + quux(); + `, + }, { code: ` /**