eslint-plugin-jsdoc 60.1.1 → 60.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"preferImportTag.cjs","names":["_iterateJsdoc","_interopRequireWildcard","require","_jsdoccomment","_parseImportsExports","e","t","WeakMap","r","n","__esModule","o","i","f","__proto__","default","has","get","set","hasOwnProperty","call","Object","defineProperty","getOwnPropertyDescriptor","_default","exports","iterateJsdoc","context","jsdoc","settings","sourceCode","utils","mode","enableFixer","exemptTypedefs","outputType","options","allComments","getAllComments","comments","filter","comment","test","value","map","commentNode","commentParserToESTree","parseComment","typedefs","flatMap","doc","tags","tag","isNamepathDefiningTag","imports","delimiter","iterateInlineImports","potentialType","type","parsedType","tryParseType","parseType","traverse","nde","parentNode","element","currentNode","pathSegments","nodes","extraPathSegments","quotes","propertyOrBrackets","unshift","right","pathType","meta","quote","getFixer","matchingName","extrPathSegments","node","at","keys","key","length","newNode","shift","left","nameNode","src","source","tokens","stringify","unusedPathSegments","findMatchingTypedef","undefined","pthSegments","find","typedef","typedefNode","namepathMatch","pathSegment","push","matchingTypedef","reportJSDoc","name","slice","findMatchingImport","imprt","parsedImport","parseImportsExports","estreeToString","replace","trim","namedImportsModuleSpecifier","namedImports","values","namedImportNames","names","namespaceImports","namespaceImportsDefault","namespaceImportsNamespace","namespace","namespaceImportsModuleSpecifier","lastPathSegment","includes","matchingImport","lastPthSegment","fixer","programNode","getNodeByRangeIndex","insertTextBefore","lstPathSegment","mightHaveTypePosition","tagMightHaveTypePosition","hasTypePosition","Boolean","iterateAllJsdocs","docs","description","url","fixable","schema","additionalProperties","properties","enum","module"],"sources":["../../src/rules/preferImportTag.js"],"sourcesContent":["import iterateJsdoc, {\n parseComment,\n} from '../iterateJsdoc.js';\nimport {\n commentParserToESTree,\n estreeToString,\n // getJSDocComment,\n parse as parseType,\n stringify,\n traverse,\n tryParse as tryParseType,\n} from '@es-joy/jsdoccomment';\nimport {\n parseImportsExports,\n} from 'parse-imports-exports';\n\nexport default iterateJsdoc(({\n context,\n jsdoc,\n settings,\n sourceCode,\n utils,\n}) => {\n const {\n mode,\n } = settings;\n\n const {\n enableFixer = true,\n exemptTypedefs = true,\n outputType = 'namespaced-import',\n } = context.options[0] || {};\n\n const allComments = sourceCode.getAllComments();\n const comments = allComments\n .filter((comment) => {\n return (/^\\*(?!\\*)/v).test(comment.value);\n })\n .map((commentNode) => {\n return commentParserToESTree(\n parseComment(commentNode, ''), mode === 'permissive' ? 'typescript' : mode,\n );\n });\n\n const typedefs = comments\n .flatMap((doc) => {\n return doc.tags.filter(({\n tag,\n }) => {\n return utils.isNamepathDefiningTag(tag);\n });\n });\n\n const imports = comments\n .flatMap((doc) => {\n return doc.tags.filter(({\n tag,\n }) => {\n return tag === 'import';\n });\n }).map((tag) => {\n // Causes problems with stringification otherwise\n tag.delimiter = '';\n return tag;\n });\n\n /**\n * @param {import('@es-joy/jsdoccomment').JsdocTagWithInline} tag\n */\n const iterateInlineImports = (tag) => {\n const potentialType = tag.type;\n let parsedType;\n try {\n parsedType = mode === 'permissive' ?\n tryParseType(/** @type {string} */ (potentialType)) :\n parseType(/** @type {string} */ (potentialType), mode);\n } catch {\n return;\n }\n\n traverse(parsedType, (nde, parentNode) => {\n // @ts-expect-error Adding our own property for use below\n nde.parentNode = parentNode;\n });\n\n traverse(parsedType, (nde) => {\n const {\n element,\n type,\n } = /** @type {import('jsdoc-type-pratt-parser').ImportResult} */ (nde);\n if (type !== 'JsdocTypeImport') {\n return;\n }\n\n let currentNode = nde;\n\n /** @type {string[]} */\n const pathSegments = [];\n\n /** @type {import('jsdoc-type-pratt-parser').NamePathResult[]} */\n const nodes = [];\n\n /** @type {string[]} */\n const extraPathSegments = [];\n\n /** @type {(import('jsdoc-type-pratt-parser').QuoteStyle|undefined)[]} */\n const quotes = [];\n\n const propertyOrBrackets = /** @type {import('jsdoc-type-pratt-parser').NamePathResult['pathType'][]} */ ([]);\n\n // @ts-expect-error Referencing our own property added above\n while (currentNode && currentNode.parentNode) {\n // @ts-expect-error Referencing our own property added above\n currentNode = currentNode.parentNode;\n /* c8 ignore next 3 -- Guard */\n if (currentNode.type !== 'JsdocTypeNamePath') {\n break;\n }\n\n pathSegments.unshift(currentNode.right.value);\n nodes.unshift(currentNode);\n propertyOrBrackets.unshift(currentNode.pathType);\n quotes.unshift(currentNode.right.meta.quote);\n }\n\n /**\n * @param {string} matchingName\n * @param {string[]} extrPathSegments\n */\n const getFixer = (matchingName, extrPathSegments) => {\n return () => {\n /** @type {import('jsdoc-type-pratt-parser').NamePathResult|undefined} */\n let node = nodes.at(0);\n if (!node) {\n // Not really a NamePathResult, but will be converted later anyways\n node = /** @type {import('jsdoc-type-pratt-parser').NamePathResult} */ (\n /** @type {unknown} */\n (nde)\n );\n }\n\n const keys = /** @type {(keyof import('jsdoc-type-pratt-parser').NamePathResult)[]} */ (\n Object.keys(node)\n );\n\n for (const key of keys) {\n delete node[key];\n }\n\n if (extrPathSegments.length) {\n let newNode = /** @type {import('jsdoc-type-pratt-parser').NamePathResult} */ (\n /** @type {unknown} */\n (node)\n );\n while (extrPathSegments.length && newNode) {\n newNode.type = 'JsdocTypeNamePath';\n newNode.right = {\n meta: {\n quote: quotes.shift(),\n },\n type: 'JsdocTypeProperty',\n value: /** @type {string} */ (extrPathSegments.shift()),\n };\n\n newNode.pathType = /** @type {import('jsdoc-type-pratt-parser').NamePathResult['pathType']} */ (\n propertyOrBrackets.shift()\n );\n // @ts-expect-error Temporary\n newNode.left = {};\n newNode = /** @type {import('jsdoc-type-pratt-parser').NamePathResult} */ (\n newNode.left\n );\n }\n\n const nameNode = /** @type {import('jsdoc-type-pratt-parser').NameResult} */ (\n /** @type {unknown} */\n (newNode)\n );\n nameNode.type = 'JsdocTypeName';\n nameNode.value = matchingName;\n } else {\n const newNode = /** @type {import('jsdoc-type-pratt-parser').NameResult} */ (\n /** @type {unknown} */\n (node)\n );\n newNode.type = 'JsdocTypeName';\n newNode.value = matchingName;\n }\n\n for (const src of tag.source) {\n if (src.tokens.type) {\n src.tokens.type = `{${stringify(parsedType)}}`;\n break;\n }\n }\n };\n };\n\n /** @type {string[]} */\n let unusedPathSegments = [];\n\n const findMatchingTypedef = () => {\n // Don't want typedefs to find themselves\n if (!exemptTypedefs) {\n return undefined;\n }\n\n const pthSegments = [\n ...pathSegments,\n ];\n return typedefs.find((typedef) => {\n let typedefNode = typedef.parsedType;\n let namepathMatch;\n while (typedefNode && typedefNode.type === 'JsdocTypeNamePath') {\n const pathSegment = pthSegments.shift();\n if (!pathSegment) {\n namepathMatch = false;\n break;\n }\n\n if (typedefNode.right.value !== pathSegment) {\n if (namepathMatch === true) {\n // It stopped matching, so stop\n break;\n }\n\n extraPathSegments.push(pathSegment);\n namepathMatch = false;\n continue;\n }\n\n namepathMatch = true;\n\n unusedPathSegments = pthSegments;\n\n typedefNode = typedefNode.left;\n }\n\n return namepathMatch &&\n // `import('eslint')` matches\n typedefNode &&\n typedefNode.type === 'JsdocTypeImport' &&\n typedefNode.element.value === element.value;\n });\n };\n\n // Check @typedef's first as should be longest match, allowing\n // for shorter abbreviations\n const matchingTypedef = findMatchingTypedef();\n if (matchingTypedef) {\n utils.reportJSDoc(\n 'Inline `import()` found; using `@typedef`',\n tag,\n enableFixer ? getFixer(matchingTypedef.name, [\n ...extraPathSegments,\n ...unusedPathSegments.slice(-1),\n ...unusedPathSegments.slice(0, -1),\n ]) : null,\n );\n return;\n }\n\n const findMatchingImport = () => {\n for (const imprt of imports) {\n const parsedImport = parseImportsExports(\n estreeToString(imprt).replace(/^\\s*@/v, '').trim(),\n );\n\n const namedImportsModuleSpecifier = Object.keys(parsedImport.namedImports || {})[0];\n\n const namedImports = Object.values(parsedImport.namedImports || {})[0]?.[0];\n const namedImportNames = (namedImports && namedImports.names && Object.keys(namedImports.names)) ?? [];\n\n const namespaceImports = Object.values(parsedImport.namespaceImports || {})[0]?.[0];\n\n const namespaceImportsDefault = namespaceImports && namespaceImports.default;\n const namespaceImportsNamespace = namespaceImports && namespaceImports.namespace;\n const namespaceImportsModuleSpecifier = Object.keys(parsedImport.namespaceImports || {})[0];\n\n const lastPathSegment = pathSegments.at(-1);\n\n if (\n (namespaceImportsDefault &&\n namespaceImportsModuleSpecifier === element.value) ||\n (element.value === namedImportsModuleSpecifier && (\n (lastPathSegment && namedImportNames.includes(lastPathSegment)) ||\n lastPathSegment === 'default'\n )) ||\n (namespaceImportsNamespace &&\n namespaceImportsModuleSpecifier === element.value)\n ) {\n return {\n namedImportNames,\n namedImports,\n namedImportsModuleSpecifier,\n namespaceImports,\n namespaceImportsDefault,\n namespaceImportsModuleSpecifier,\n namespaceImportsNamespace,\n };\n }\n }\n\n return undefined;\n };\n\n const matchingImport = findMatchingImport();\n if (matchingImport) {\n const {\n namedImportNames,\n namedImports,\n namedImportsModuleSpecifier,\n namespaceImportsNamespace,\n } = matchingImport;\n if (!namedImportNames.length && namedImportsModuleSpecifier && namedImports.default) {\n utils.reportJSDoc(\n 'Inline `import()` found; prefer `@import`',\n tag,\n enableFixer ? getFixer(namedImports.default, []) : null,\n );\n return;\n }\n\n const lastPthSegment = pathSegments.at(-1);\n if (lastPthSegment && namedImportNames.includes(lastPthSegment)) {\n utils.reportJSDoc(\n 'Inline `import()` found; prefer `@import`',\n tag,\n enableFixer ? getFixer(lastPthSegment, pathSegments.slice(0, -1)) : null,\n );\n return;\n }\n\n if (namespaceImportsNamespace) {\n utils.reportJSDoc(\n 'Inline `import()` found; prefer `@import`',\n tag,\n enableFixer ? getFixer(namespaceImportsNamespace, [\n ...pathSegments,\n ]) : null,\n );\n return;\n }\n }\n\n if (!pathSegments.length) {\n utils.reportJSDoc(\n 'Inline `import()` found; prefer `@import`',\n tag,\n enableFixer ? (fixer) => {\n getFixer(element.value, [])();\n\n const programNode = sourceCode.getNodeByRangeIndex(0);\n return fixer.insertTextBefore(\n /** @type {import('estree').Program} */ (programNode),\n `/** @import * as ${element.value} from '${element.value}'; */`,\n );\n } : null,\n );\n return;\n }\n\n const lstPathSegment = pathSegments.at(-1);\n if (lstPathSegment && lstPathSegment === 'default') {\n utils.reportJSDoc(\n 'Inline `import()` found; prefer `@import`',\n tag,\n enableFixer ? (fixer) => {\n getFixer(element.value, [])();\n\n const programNode = sourceCode.getNodeByRangeIndex(0);\n return fixer.insertTextBefore(\n /** @type {import('estree').Program} */ (programNode),\n `/** @import ${element.value} from '${element.value}'; */`,\n );\n } : null,\n );\n return;\n }\n\n utils.reportJSDoc(\n 'Inline `import()` found; prefer `@import`',\n tag,\n enableFixer ? (fixer) => {\n if (outputType === 'namespaced-import') {\n getFixer(element.value, [\n ...pathSegments,\n ])();\n } else {\n getFixer(\n /** @type {string} */ (pathSegments.at(-1)),\n pathSegments.slice(0, -1),\n )();\n }\n\n const programNode = sourceCode.getNodeByRangeIndex(0);\n return fixer.insertTextBefore(\n /** @type {import('estree').Program} */ (programNode),\n outputType === 'namespaced-import' ?\n `/** @import * as ${element.value} from '${element.value}'; */` :\n `/** @import { ${pathSegments.at(-1)} } from '${element.value}'; */`,\n );\n } : null,\n );\n });\n };\n\n for (const tag of jsdoc.tags) {\n const mightHaveTypePosition = utils.tagMightHaveTypePosition(tag.tag);\n const hasTypePosition = mightHaveTypePosition === true && Boolean(tag.type);\n if (hasTypePosition && (!exemptTypedefs || !utils.isNamepathDefiningTag(tag.tag))) {\n iterateInlineImports(tag);\n }\n }\n}, {\n iterateAllJsdocs: true,\n meta: {\n docs: {\n description: 'Prefer `@import` tags to inline `import()` statements.',\n url: 'https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/prefer-import-tag.md#repos-sticky-header',\n },\n fixable: 'code',\n schema: [\n {\n additionalProperties: false,\n properties: {\n enableFixer: {\n description: 'Whether or not to enable the fixer to add `@import` tags.',\n type: 'boolean',\n },\n exemptTypedefs: {\n description: 'Whether to allow `import()` statements within `@typedef`',\n type: 'boolean',\n },\n\n // We might add `typedef` and `typedef-local-only`, but also raises\n // question of how deep the generated typedef should be\n outputType: {\n description: 'What kind of `@import` to generate when no matching `@typedef` or `@import` is found',\n enum: [\n 'named-import',\n 'namespaced-import',\n ],\n type: 'string',\n },\n },\n type: 'object',\n },\n ],\n type: 'suggestion',\n },\n});\n"],"mappings":"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","ignoreList":[]}
@@ -0,0 +1,3 @@
1
+ declare const _default: import("eslint").Rule.RuleModule;
2
+ export default _default;
3
+ //# sourceMappingURL=preferImportTag.d.ts.map
package/dist/rules.d.ts CHANGED
@@ -1250,6 +1250,10 @@ export interface Rules {
1250
1250
  | []
1251
1251
  | [
1252
1252
  {
1253
+ /**
1254
+ * Whether to check typedefs for use within the file
1255
+ */
1256
+ checkUsedTypedefs?: boolean;
1253
1257
  /**
1254
1258
  * This array can be populated to indicate other types which
1255
1259
  * are automatically considered as defined (in addition to globals, etc.).
@@ -1259,7 +1263,7 @@ export interface Rules {
1259
1263
  /**
1260
1264
  * Whether to disable reporting of errors. Defaults to
1261
1265
  * `false`. This may be set to `true` in order to take advantage of only
1262
- * marking defined variables as used.
1266
+ * marking defined variables as used or checking used typedefs.
1263
1267
  */
1264
1268
  disableReporting?: boolean;
1265
1269
  /**
@@ -1272,6 +1276,26 @@ export interface Rules {
1272
1276
  }
1273
1277
  ];
1274
1278
 
1279
+ /** Prefer `@import` tags to inline `import()` statements. */
1280
+ "jsdoc/prefer-import-tag":
1281
+ | []
1282
+ | [
1283
+ {
1284
+ /**
1285
+ * Whether or not to enable the fixer to add `@import` tags.
1286
+ */
1287
+ enableFixer?: boolean;
1288
+ /**
1289
+ * Whether to allow `import()` statements within `@typedef`
1290
+ */
1291
+ exemptTypedefs?: boolean;
1292
+ /**
1293
+ * What kind of `@import` to generate when no matching `@typedef` or `@import` is found
1294
+ */
1295
+ outputType?: "named-import" | "namespaced-import";
1296
+ }
1297
+ ];
1298
+
1275
1299
  /** Reports use of `any` or `*` type */
1276
1300
  "jsdoc/reject-any-type": [];
1277
1301
 
package/package.json CHANGED
@@ -172,5 +172,5 @@
172
172
  "test-cov": "TIMING=1 c8 --reporter text pnpm run test-no-cov",
173
173
  "test-index": "pnpm run test-no-cov test/rules/index.js"
174
174
  },
175
- "version": "60.1.1"
175
+ "version": "60.3.0"
176
176
  }
package/src/index-cjs.js CHANGED
@@ -37,6 +37,7 @@ import noMultiAsterisks from './rules/noMultiAsterisks.js';
37
37
  import noRestrictedSyntax from './rules/noRestrictedSyntax.js';
38
38
  import noTypes from './rules/noTypes.js';
39
39
  import noUndefinedTypes from './rules/noUndefinedTypes.js';
40
+ import preferImportTag from './rules/preferImportTag.js';
40
41
  import requireAsteriskPrefix from './rules/requireAsteriskPrefix.js';
41
42
  import requireDescription from './rules/requireDescription.js';
42
43
  import requireDescriptionCompleteSentence from './rules/requireDescriptionCompleteSentence.js';
@@ -111,6 +112,7 @@ index.rules = {
111
112
  'no-restricted-syntax': noRestrictedSyntax,
112
113
  'no-types': noTypes,
113
114
  'no-undefined-types': noUndefinedTypes,
115
+ 'prefer-import-tag': preferImportTag,
114
116
  'reject-any-type': buildRejectOrPreferRuleDefinition({
115
117
  description: 'Reports use of `any` or `*` type',
116
118
  overrideSettings: {
@@ -283,6 +285,7 @@ const createRecommendedRuleset = (warnOrError, flatName) => {
283
285
  'jsdoc/no-restricted-syntax': 'off',
284
286
  'jsdoc/no-types': 'off',
285
287
  'jsdoc/no-undefined-types': warnOrError,
288
+ 'jsdoc/prefer-import-tag': 'off',
286
289
  'jsdoc/reject-any-type': warnOrError,
287
290
  'jsdoc/reject-function-type': warnOrError,
288
291
  'jsdoc/require-asterisk-prefix': 'off',
package/src/index.js CHANGED
@@ -43,6 +43,7 @@ import noMultiAsterisks from './rules/noMultiAsterisks.js';
43
43
  import noRestrictedSyntax from './rules/noRestrictedSyntax.js';
44
44
  import noTypes from './rules/noTypes.js';
45
45
  import noUndefinedTypes from './rules/noUndefinedTypes.js';
46
+ import preferImportTag from './rules/preferImportTag.js';
46
47
  import requireAsteriskPrefix from './rules/requireAsteriskPrefix.js';
47
48
  import requireDescription from './rules/requireDescription.js';
48
49
  import requireDescriptionCompleteSentence from './rules/requireDescriptionCompleteSentence.js';
@@ -117,6 +118,7 @@ index.rules = {
117
118
  'no-restricted-syntax': noRestrictedSyntax,
118
119
  'no-types': noTypes,
119
120
  'no-undefined-types': noUndefinedTypes,
121
+ 'prefer-import-tag': preferImportTag,
120
122
  'reject-any-type': buildRejectOrPreferRuleDefinition({
121
123
  description: 'Reports use of `any` or `*` type',
122
124
  overrideSettings: {
@@ -289,6 +291,7 @@ const createRecommendedRuleset = (warnOrError, flatName) => {
289
291
  'jsdoc/no-restricted-syntax': 'off',
290
292
  'jsdoc/no-types': 'off',
291
293
  'jsdoc/no-undefined-types': warnOrError,
294
+ 'jsdoc/prefer-import-tag': 'off',
292
295
  'jsdoc/reject-any-type': warnOrError,
293
296
  'jsdoc/reject-function-type': warnOrError,
294
297
  'jsdoc/require-asterisk-prefix': 'off',
@@ -92,6 +92,10 @@ import esquery from 'esquery';
92
92
  * parseClosureTemplateTag: ParseClosureTemplateTag,
93
93
  * getPreferredTagNameObject: GetPreferredTagNameObject,
94
94
  * pathDoesNotBeginWith: import('./jsdocUtils.js').PathDoesNotBeginWith
95
+ * isNamepathDefiningTag: IsNamepathX,
96
+ * isNamepathReferencingTag: IsNamepathX,
97
+ * isNamepathOrUrlReferencingTag: IsNamepathX,
98
+ * tagMightHaveNamepath: IsNamepathX,
95
99
  * }} BasicUtils
96
100
  */
97
101
 
@@ -116,7 +120,7 @@ import esquery from 'esquery';
116
120
  * @callback ReportJSDoc
117
121
  * @param {string} msg
118
122
  * @param {null|import('comment-parser').Spec|{line: Integer, column?: Integer}} [tag]
119
- * @param {(() => void)|null} [handler]
123
+ * @param {((fixer: import('eslint').Rule.RuleFixer) => import('eslint').Rule.Fix|void)|null} [handler]
120
124
  * @param {boolean} [specRewire]
121
125
  * @param {undefined|{
122
126
  * [key: string]: string
@@ -566,7 +570,8 @@ const {
566
570
  * hasNonComment: number,
567
571
  * hasNonCommentBeforeTag: {
568
572
  * [key: string]: boolean|number
569
- * }
573
+ * },
574
+ * foundTypedefValues: string[]
570
575
  * }} StateObject
571
576
  */
572
577
 
@@ -599,6 +604,24 @@ const getBasicUtils = (context, {
599
604
  /** @type {BasicUtils} */
600
605
  const utils = {};
601
606
 
607
+ for (const method of [
608
+ 'isNamepathDefiningTag',
609
+ 'isNamepathReferencingTag',
610
+ 'isNamepathOrUrlReferencingTag',
611
+ 'tagMightHaveNamepath',
612
+ ]) {
613
+ /** @type {IsNamepathX} */
614
+ utils[
615
+ /** @type {"isNamepathDefiningTag"|"isNamepathReferencingTag"|"isNamepathOrUrlReferencingTag"|"tagMightHaveNamepath"} */ (
616
+ method
617
+ )] = (tagName) => {
618
+ return jsdocUtils[
619
+ /** @type {"isNamepathDefiningTag"|"isNamepathReferencingTag"|"isNamepathOrUrlReferencingTag"|"tagMightHaveNamepath"} */
620
+ (method)
621
+ ](tagName);
622
+ };
623
+ }
624
+
602
625
  /** @type {ReportSettings} */
603
626
  utils.reportSettings = (message) => {
604
627
  context.report({
@@ -771,7 +794,8 @@ const getUtils = (
771
794
  report(msg, handler ? /** @type {import('eslint').Rule.ReportFixer} */ (
772
795
  fixer,
773
796
  ) => {
774
- handler();
797
+ const extraFix = handler(fixer);
798
+
775
799
  const replacement = utils.stringify(jsdoc, specRewire);
776
800
 
777
801
  if (!replacement) {
@@ -780,21 +804,38 @@ const getUtils = (
780
804
  0, jsdocNode.range[0],
781
805
  ).search(/\n[ \t]*$/v);
782
806
  if (lastLineBreakPos > -1) {
783
- return fixer.removeRange([
784
- lastLineBreakPos, jsdocNode.range[1],
785
- ]);
807
+ return [
808
+ fixer.removeRange([
809
+ lastLineBreakPos, jsdocNode.range[1],
810
+ ]),
811
+ /* c8 ignore next 2 -- Guard */
812
+ ...(extraFix ? [
813
+ extraFix,
814
+ ] : []),
815
+ ];
786
816
  }
787
817
 
788
- return fixer.removeRange(
789
- (/\s/v).test(text.charAt(jsdocNode.range[1])) ?
790
- [
791
- jsdocNode.range[0], jsdocNode.range[1] + 1,
792
- ] :
793
- jsdocNode.range,
794
- );
818
+ return [
819
+ fixer.removeRange(
820
+ (/\s/v).test(text.charAt(jsdocNode.range[1])) ?
821
+ [
822
+ jsdocNode.range[0], jsdocNode.range[1] + 1,
823
+ ] :
824
+ jsdocNode.range,
825
+ ),
826
+ /* c8 ignore next 2 -- Guard */
827
+ ...(extraFix ? [
828
+ extraFix,
829
+ ] : []),
830
+ ];
795
831
  }
796
832
 
797
- return fixer.replaceText(jsdocNode, replacement);
833
+ return [
834
+ fixer.replaceText(jsdocNode, replacement),
835
+ ...(extraFix ? [
836
+ extraFix,
837
+ ] : []),
838
+ ];
798
839
  } : null, tag, data);
799
840
  };
800
841
 
@@ -1525,24 +1566,6 @@ const getUtils = (
1525
1566
  };
1526
1567
  }
1527
1568
 
1528
- for (const method of [
1529
- 'isNamepathDefiningTag',
1530
- 'isNamepathReferencingTag',
1531
- 'isNamepathOrUrlReferencingTag',
1532
- 'tagMightHaveNamepath',
1533
- ]) {
1534
- /** @type {IsNamepathX} */
1535
- utils[
1536
- /** @type {"isNamepathDefiningTag"|"isNamepathReferencingTag"|"isNamepathOrUrlReferencingTag"|"tagMightHaveNamepath"} */ (
1537
- method
1538
- )] = (tagName) => {
1539
- return jsdocUtils[
1540
- /** @type {"isNamepathDefiningTag"|"isNamepathReferencingTag"|"isNamepathOrUrlReferencingTag"|"tagMightHaveNamepath"} */
1541
- (method)
1542
- ](tagName);
1543
- };
1544
- }
1545
-
1546
1569
  /** @type {GetTagStructureForMode} */
1547
1570
  utils.getTagStructureForMode = (mde) => {
1548
1571
  return jsdocUtils.getTagStructureForMode(mde, settings.structuredTags);
@@ -59,8 +59,12 @@ export default iterateJsdoc(({
59
59
  report,
60
60
  settings,
61
61
  sourceCode,
62
+ state,
62
63
  utils,
63
64
  }) => {
65
+ /** @type {string[]} */
66
+ const foundTypedefValues = [];
67
+
64
68
  const {
65
69
  scopeManager,
66
70
  } = sourceCode;
@@ -73,11 +77,13 @@ export default iterateJsdoc(({
73
77
  const
74
78
  /**
75
79
  * @type {{
80
+ * checkUsedTypedefs: boolean
76
81
  * definedTypes: string[],
77
82
  * disableReporting: boolean,
78
- * markVariablesAsUsed: boolean
83
+ * markVariablesAsUsed: boolean,
79
84
  * }}
80
85
  */ {
86
+ checkUsedTypedefs = false,
81
87
  definedTypes = [],
82
88
  disableReporting = false,
83
89
  markVariablesAsUsed = true,
@@ -128,14 +134,16 @@ export default iterateJsdoc(({
128
134
  return commentNode.value.replace(/^\s*globals/v, '').trim().split(/,\s*/v);
129
135
  }).concat(Object.keys(context.languageOptions.globals ?? []));
130
136
 
131
- const typedefDeclarations = comments
137
+ const typedefs = comments
132
138
  .flatMap((doc) => {
133
139
  return doc.tags.filter(({
134
140
  tag,
135
141
  }) => {
136
142
  return utils.isNamepathDefiningTag(tag);
137
143
  });
138
- })
144
+ });
145
+
146
+ const typedefDeclarations = typedefs
139
147
  .map((tag) => {
140
148
  return tag.name;
141
149
  });
@@ -204,9 +212,9 @@ export default iterateJsdoc(({
204
212
  return [];
205
213
  }
206
214
 
207
- const jsdoc = parseComment(commentNode, '');
215
+ const jsdc = parseComment(commentNode, '');
208
216
 
209
- return jsdoc.tags.filter((tag) => {
217
+ return jsdc.tags.filter((tag) => {
210
218
  return tag.tag === 'template';
211
219
  });
212
220
  };
@@ -510,10 +518,74 @@ export default iterateJsdoc(({
510
518
  context.markVariableAsUsed(val);
511
519
  }
512
520
  }
521
+
522
+ if (checkUsedTypedefs && typedefDeclarations.includes(val)) {
523
+ foundTypedefValues.push(val);
524
+ }
513
525
  }
514
526
  });
515
527
  }
528
+
529
+ state.foundTypedefValues = foundTypedefValues;
516
530
  }, {
531
+ // We use this method rather than checking at end of handler above because
532
+ // in that case, it is invoked too many times and would thus report errors
533
+ // too many times.
534
+ exit ({
535
+ context,
536
+ state,
537
+ utils,
538
+ }) {
539
+ const {
540
+ checkUsedTypedefs = false,
541
+ } = context.options[0] || {};
542
+
543
+ if (!checkUsedTypedefs) {
544
+ return;
545
+ }
546
+
547
+ const allComments = context.sourceCode.getAllComments();
548
+ const comments = allComments
549
+ .filter((comment) => {
550
+ return (/^\*(?!\*)/v).test(comment.value);
551
+ })
552
+ .map((commentNode) => {
553
+ return {
554
+ doc: parseComment(commentNode, ''),
555
+ loc: commentNode.loc,
556
+ };
557
+ });
558
+ const typedefs = comments
559
+ .flatMap(({
560
+ doc,
561
+ loc,
562
+ }) => {
563
+ const tags = doc.tags.filter(({
564
+ tag,
565
+ }) => {
566
+ return utils.isNamepathDefiningTag(tag);
567
+ });
568
+ if (!tags.length) {
569
+ return [];
570
+ }
571
+
572
+ return {
573
+ loc,
574
+ tags,
575
+ };
576
+ });
577
+
578
+ for (const typedef of typedefs) {
579
+ if (
580
+ !state.foundTypedefValues.includes(typedef.tags[0].name)
581
+ ) {
582
+ context.report({
583
+ loc: /** @type {import('@eslint/core').SourceLocation} */ (typedef.loc),
584
+ message: 'This typedef was not used within the file',
585
+ });
586
+ }
587
+ }
588
+ },
517
589
  iterateAllJsdocs: true,
518
590
  meta: {
519
591
  docs: {
@@ -524,6 +596,10 @@ export default iterateJsdoc(({
524
596
  {
525
597
  additionalProperties: false,
526
598
  properties: {
599
+ checkUsedTypedefs: {
600
+ description: 'Whether to check typedefs for use within the file',
601
+ type: 'boolean',
602
+ },
527
603
  definedTypes: {
528
604
  description: `This array can be populated to indicate other types which
529
605
  are automatically considered as defined (in addition to globals, etc.).
@@ -536,7 +612,7 @@ Defaults to an empty array.`,
536
612
  disableReporting: {
537
613
  description: `Whether to disable reporting of errors. Defaults to
538
614
  \`false\`. This may be set to \`true\` in order to take advantage of only
539
- marking defined variables as used.`,
615
+ marking defined variables as used or checking used typedefs.`,
540
616
  type: 'boolean',
541
617
  },
542
618
  markVariablesAsUsed: {