diff --git a/.README/rules/require-template.md b/.README/rules/require-template.md
index f90cad4c..a76b30ef 100644
--- a/.README/rules/require-template.md
+++ b/.README/rules/require-template.md
@@ -20,8 +20,8 @@ or
Note that in the latter TypeScript-flavor JavaScript example, there is no way
for us to firmly distinguish between `D` and `V` as type parameters or as some
-other identifiers, so we use an algorithm that any single capital letters
-are assumed to be templates.
+other identifiers, so we use an algorithm that assumes that any single capital
+letters are templates.
## Options
diff --git a/docs/rules/require-template.md b/docs/rules/require-template.md
index 581270a5..df907df9 100644
--- a/docs/rules/require-template.md
+++ b/docs/rules/require-template.md
@@ -22,8 +22,8 @@ or
Note that in the latter TypeScript-flavor JavaScript example, there is no way
for us to firmly distinguish between `D` and `V` as type parameters or as some
-other identifiers, so we use an algorithm that any single capital letters
-are assumed to be templates.
+other identifiers, so we use an algorithm that assumes that any single capital
+letters are templates.
@@ -199,6 +199,18 @@ export default class {
add: (x: NumType, y: NumType) => NumType;
}
// Message: Missing @template NumType
+
+/**
+ * @callback
+ * @param {[D, V | undefined]} someParam
+ */
+// Message: Missing @template D
+
+/**
+ * @callback
+ * @returns {[D, V | undefined]}
+ */
+// Message: Missing @template D
````
@@ -323,5 +335,24 @@ export default class {
zeroValue: NumType;
add: (x: NumType, y: NumType) => NumType;
}
+
+/**
+ * @callback
+ * @template D
+ * @template V
+ * @param {[D, V | undefined]} someParam
+ */
+
+/**
+ * @callback
+ * @template D
+ * @template V
+ * @returns {[D, V | undefined]}
+ */
+
+/**
+ * @callback
+ * @returns {[Something | undefined]}
+ */
````
diff --git a/src/rules/requireTemplate.js b/src/rules/requireTemplate.js
index 8cdf8a59..7e01c247 100644
--- a/src/rules/requireTemplate.js
+++ b/src/rules/requireTemplate.js
@@ -89,12 +89,6 @@ export default iterateJsdoc(({
}
};
- const typedefTags = utils.getTags('typedef');
- if (!typedefTags.length || typedefTags.length >= 2) {
- handleTypes();
- return;
- }
-
const usedNameToTag = new Map();
/**
@@ -124,23 +118,45 @@ export default iterateJsdoc(({
});
};
- const potentialTypedef = typedefTags[0];
- checkForUsedTypes(potentialTypedef);
+ /**
+ * @param {string[]} tagNames
+ */
+ const checkTagsAndTemplates = (tagNames) => {
+ for (const tagName of tagNames) {
+ const preferredTagName = /** @type {string} */ (utils.getPreferredTagName({
+ tagName,
+ }));
+ const matchingTags = utils.getTags(preferredTagName);
+ for (const matchingTag of matchingTags) {
+ checkForUsedTypes(matchingTag);
+ }
+ }
+
+ // Could check against whitelist/blacklist
+ for (const usedName of usedNames) {
+ if (!templateNames.includes(usedName)) {
+ report(`Missing @template ${usedName}`, null, usedNameToTag.get(usedName));
+ }
+ }
+ };
- const tagName = /** @type {string} */ (utils.getPreferredTagName({
- tagName: 'property',
- }));
- const propertyTags = utils.getTags(tagName);
- for (const propertyTag of propertyTags) {
- checkForUsedTypes(propertyTag);
+ const callbackTags = utils.getTags('callback');
+ const functionTags = utils.getTags('function');
+ if (callbackTags.length || functionTags.length) {
+ checkTagsAndTemplates(['param', 'returns']);
+ return;
}
- // Could check against whitelist/blacklist
- for (const usedName of usedNames) {
- if (!templateNames.includes(usedName)) {
- report(`Missing @template ${usedName}`, null, usedNameToTag.get(usedName));
- }
+ const typedefTags = utils.getTags('typedef');
+ if (!typedefTags.length || typedefTags.length >= 2) {
+ handleTypes();
+ return;
}
+
+ const potentialTypedef = typedefTags[0];
+ checkForUsedTypes(potentialTypedef);
+
+ checkTagsAndTemplates(['property']);
}, {
iterateAllJsdocs: true,
meta: {
diff --git a/test/rules/assertions/requireTemplate.js b/test/rules/assertions/requireTemplate.js
index c2f713a2..ccfb6a36 100644
--- a/test/rules/assertions/requireTemplate.js
+++ b/test/rules/assertions/requireTemplate.js
@@ -365,6 +365,42 @@ export default {
parser: typescriptEslintParser
},
},
+ {
+ code: `
+ /**
+ * @callback
+ * @param {[D, V | undefined]} someParam
+ */
+ `,
+ errors: [
+ {
+ line: 4,
+ message: 'Missing @template D',
+ },
+ {
+ line: 4,
+ message: 'Missing @template V',
+ },
+ ],
+ },
+ {
+ code: `
+ /**
+ * @callback
+ * @returns {[D, V | undefined]}
+ */
+ `,
+ errors: [
+ {
+ line: 4,
+ message: 'Missing @template D',
+ },
+ {
+ line: 4,
+ message: 'Missing @template V',
+ },
+ ],
+ },
],
valid: [
{
@@ -568,5 +604,33 @@ export default {
parser: typescriptEslintParser
},
},
+ {
+ code: `
+ /**
+ * @callback
+ * @template D
+ * @template V
+ * @param {[D, V | undefined]} someParam
+ */
+ `,
+ },
+ {
+ code: `
+ /**
+ * @callback
+ * @template D
+ * @template V
+ * @returns {[D, V | undefined]}
+ */
+ `,
+ },
+ {
+ code: `
+ /**
+ * @callback
+ * @returns {[Something | undefined]}
+ */
+ `,
+ },
],
};