Skip to content

Commit

Permalink
fix(no-undefined-types): detection of AST descendants of template t…
Browse files Browse the repository at this point in the history
…ag; fixes #559, fixes #827
  • Loading branch information
brettz9 committed Jan 3, 2022
1 parent 6ddc79c commit 9962b22
Show file tree
Hide file tree
Showing 3 changed files with 153 additions and 27 deletions.
52 changes: 52 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9896,12 +9896,64 @@ function quux(foo) {

}

/**
* @template T
* @param {T} arg
* @returns {[T]}
*/
function genericFunctionExample(arg) {
const result = /** @type {[T]} */ (new Array());
result[0] = arg;
return result;
}
// Settings: {"jsdoc":{"mode":"closure"}}

/** @typedef QDigestNode */
class A {
/**
* @template {object} T
* @param {(node: QDigestNode) => T} callback
* @returns {T[]}
*/
map(callback) {
/** @type {T[]} */
let vals;
return vals;
}
}
// Settings: {"jsdoc":{"mode":"typescript"}}

/**
* @template T
* @param {T} arg
*/
function example(arg) {

/** @param {T} */
function inner(x) {
}
}
// Settings: {"jsdoc":{"mode":"typescript"}}

/**
* @suppress {visibility}
*/
function foo () {
}
// Settings: {"jsdoc":{"mode":"closure"}}

/**
* @template T
*/
export class Foo {
// cast to T
getType() {
const x = "hello";
const y = /** @type {T} */ (x);
return y;
}
}
// Settings: {"jsdoc":{"mode":"typescript"}}
````


Expand Down
47 changes: 20 additions & 27 deletions src/rules/noUndefinedTypes.js
Original file line number Diff line number Diff line change
Expand Up @@ -92,42 +92,35 @@ export default iterateJsdoc(({
});

const ancestorNodes = [];
let currentScope = scopeManager.acquire(node);

while (currentScope && currentScope.block.type !== 'Program') {
ancestorNodes.push(currentScope.block);
currentScope = currentScope.upper;
let currentNode = node;
// No need for Program node?
while (currentNode?.parent) {
ancestorNodes.push(currentNode);
currentNode = currentNode.parent;
}

const getTemplateTags = function (ancestorNode) {
const commentNode = getJSDocComment(sourceCode, ancestorNode, settings);
if (!commentNode) {
return [];
}

const jsdoc = parseComment(commentNode, '');

return jsdocUtils.filterTags(jsdoc.tags, (tag) => {
return tag.tag === 'template';
});
};

// `currentScope` may be `null` or `Program`, so in such a case,
// we look to present tags instead
let templateTags = ancestorNodes.length ?
const templateTags = ancestorNodes.length ?
ancestorNodes.flatMap((ancestorNode) => {
const commentNode = getJSDocComment(sourceCode, ancestorNode, settings);
if (!commentNode) {
return [];
}

const jsdoc = parseComment(commentNode, '');

return jsdocUtils.filterTags(jsdoc.tags, (tag) => {
return tag.tag === 'template';
});
return getTemplateTags(ancestorNode);
}) :
utils.getPresentTags('template');

const classJsdoc = utils.getClassJsdoc();
if (classJsdoc?.tags) {
templateTags = templateTags.concat(
classJsdoc.tags
.filter(({
tag,
}) => {
return tag === 'template';
}),
);
}

const closureGenericTypes = templateTags.flatMap((tag) => {
return utils.parseClosureTemplateTag(tag);
});
Expand Down
81 changes: 81 additions & 0 deletions test/rules/assertions/noUndefinedTypes.js
Original file line number Diff line number Diff line change
Expand Up @@ -1109,6 +1109,66 @@ export default {
`,
ignoreReadme: true,
},
{
code: `
/**
* @template T
* @param {T} arg
* @returns {[T]}
*/
function genericFunctionExample(arg) {
const result = /** @type {[T]} */ (new Array());
result[0] = arg;
return result;
}
`,
settings: {
jsdoc: {
mode: 'closure',
},
},
},
{
code: `
/** @typedef QDigestNode */
class A {
/**
* @template {object} T
* @param {(node: QDigestNode) => T} callback
* @returns {T[]}
*/
map(callback) {
/** @type {T[]} */
let vals;
return vals;
}
}
`,
settings: {
jsdoc: {
mode: 'typescript',
},
},
},
{
code: `
/**
* @template T
* @param {T} arg
*/
function example(arg) {
/** @param {T} */
function inner(x) {
}
}
`,
settings: {
jsdoc: {
mode: 'typescript',
},
},
},
{
// https://github.com/gajus/eslint-plugin-jsdoc/issues/748
code: `
Expand All @@ -1134,5 +1194,26 @@ export default {
},
},
},
{
code: `
/**
* @template T
*/
export class Foo {
// cast to T
getType() {
const x = "hello";
const y = /** @type {T} */ (x);
return y;
}
}
`,
parser: require.resolve('@babel/eslint-parser'),
settings: {
jsdoc: {
mode: 'typescript',
},
},
},
],
};

0 comments on commit 9962b22

Please sign in to comment.