eslint-plugin-jsdoc 63.0.8 → 63.0.10

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.
@@ -413,9 +413,6 @@ export function mayBeUndefinedTypeTag(tag: import("comment-parser").Spec | null
413
413
  * @returns {void}
414
414
  */
415
415
  export function overrideTagStructure(structuredTags: import("./iterateJsdoc.js").StructuredTags, tagMap?: import("./getDefaultTagStructureForMode.js").TagStructure): void;
416
- /**
417
- * @param {string} tag
418
- */
419
416
  /**
420
417
  * Parses GCC Generic/Template types
421
418
  * @see {@link https://github.com/google/closure-compiler/wiki/Generic-Types}
@@ -33,25 +33,110 @@ var _default = exports.default = (0, _iterateJsdoc.default)(({
33
33
  /** @type {number[]} */
34
34
  const indexes = [];
35
35
  const unescapedInlineTagRegex = /(?:^|\s)@(\w+)/gv;
36
- for (const [idx, descLine] of (description.startsWith('\n') ? description.slice(1) : description).split('\n').entries()) {
37
- descLine.replaceAll(unescapedInlineTagRegex, (_, tagName) => {
38
- if (allowedInlineTags.includes(tagName)) {
39
- return _;
36
+ const scopedPackageNameRegex = /^@[\w.\-]+\/[\w.\-]+/v;
37
+ const declarationReferenceInlineTags = new Set(['inheritDoc', 'link', 'linkcode', 'linkplain']);
38
+
39
+ /**
40
+ * @param {string} desc
41
+ * @param {number} atSignIndex
42
+ * @returns {string}
43
+ */
44
+ const getInlineTagName = (desc, atSignIndex) => {
45
+ const inlineTagStart = desc.lastIndexOf('{@', atSignIndex);
46
+ if (inlineTagStart === -1) {
47
+ return '';
48
+ }
49
+ const inlineTagEnd = desc.indexOf('}', inlineTagStart);
50
+ if (inlineTagEnd === -1 || inlineTagEnd <= atSignIndex) {
51
+ return '';
52
+ }
53
+ return desc.slice(inlineTagStart + 2).match(/^\w+/v)?.[0] || '';
54
+ };
55
+
56
+ /**
57
+ * @param {string} desc
58
+ * @param {string} match
59
+ * @param {number} offset
60
+ * @returns {boolean}
61
+ */
62
+ const shouldIgnoreMatch = (desc, match, offset) => {
63
+ const atSignIndex = offset + match.lastIndexOf('@');
64
+ const inlineTagName = getInlineTagName(desc, atSignIndex);
65
+ return declarationReferenceInlineTags.has(inlineTagName) && scopedPackageNameRegex.test(desc.slice(atSignIndex));
66
+ };
67
+
68
+ /**
69
+ * @param {string} tagName
70
+ * @returns {[
71
+ * RegExp,
72
+ * (description: string) => string
73
+ * ]}
74
+ */
75
+ const escapeInlineTags = tagName => {
76
+ const regex = new RegExp(`(^|\\s)@${
77
+ // No need to escape, as contains only safe characters
78
+ tagName}`, 'gv');
79
+ return [regex,
80
+ /**
81
+ * @param {string} desc
82
+ */
83
+ desc => {
84
+ return desc.replaceAll(regex, (match, prefix, offset) => {
85
+ if (shouldIgnoreMatch(desc, match, offset)) {
86
+ return match;
87
+ }
88
+ return fixType === 'backticks' ? prefix + '`@' + tagName + '`' : prefix + '\\@' + tagName;
89
+ });
90
+ }];
91
+ };
92
+
93
+ /**
94
+ * @param {string} desc
95
+ * @returns {string}
96
+ */
97
+ const getUnescapedInlineTagName = desc => {
98
+ unescapedInlineTagRegex.lastIndex = 0;
99
+ let match;
100
+ while ((match = unescapedInlineTagRegex.exec(desc)) !== null) {
101
+ const [fullMatch, tagName] = match;
102
+ if (allowedInlineTags.includes(tagName) || shouldIgnoreMatch(desc, fullMatch, match.index)) {
103
+ continue;
104
+ }
105
+ return tagName;
106
+ }
107
+ return '';
108
+ };
109
+ const normalizedDescription = description.startsWith('\n') ? description.slice(1) : description;
110
+ let nextLineStartOffset = 0;
111
+ for (const [idx, descLine] of normalizedDescription.split('\n').entries()) {
112
+ const lineStartOffset = nextLineStartOffset;
113
+
114
+ // +1 for the `\n` removed by split.
115
+ nextLineStartOffset += descLine.length + 1;
116
+ descLine.replaceAll(unescapedInlineTagRegex, (match, tagName, offset) => {
117
+ if (allowedInlineTags.includes(tagName) ||
118
+ // Run ignore-detection against the full description text so that
119
+ // multi-line inline tags (e.g. `{@link` on one line and
120
+ // `@scope/pkg#Member}` on the next) are recognized as being inside an
121
+ // inline tag rather than scanned per-line.
122
+ shouldIgnoreMatch(normalizedDescription, match, lineStartOffset + offset)) {
123
+ return match;
40
124
  }
41
125
  tagNames.push(tagName);
42
126
  indexes.push(idx);
43
- return _;
127
+ return match;
44
128
  });
45
129
  }
46
130
  for (const [idx, tagName] of tagNames.entries()) {
47
131
  utils.reportJSDoc(`Unexpected inline JSDoc tag. Did you mean to use {@${tagName}}, \\@${tagName}, or \`@${tagName}\`?`, {
48
132
  line: indexes[idx] + 1
49
133
  }, enableFixer ? () => {
134
+ // `tagName` and `fixType` are constant here, so compute the escaper
135
+ // once rather than rebuilding the RegExp + closure for every line.
136
+ const [, escapeInlineTag] = escapeInlineTags(tagName);
50
137
  utils.setBlockDescription((info, seedTokens, descLines) => {
51
138
  return descLines.map(desc => {
52
- const newDesc = desc.replaceAll(new RegExp(`(^|\\s)@${
53
- // No need to escape, as contains only safe characters
54
- tagName}`, 'gv'), fixType === 'backticks' ? '$1`@' + tagName + '`' : '$1\\@' + tagName);
139
+ const newDesc = escapeInlineTag(desc);
55
140
  return {
56
141
  number: 0,
57
142
  source: '',
@@ -65,26 +150,6 @@ var _default = exports.default = (0, _iterateJsdoc.default)(({
65
150
  });
66
151
  } : null);
67
152
  }
68
-
69
- /**
70
- * @param {string} tagName
71
- * @returns {[
72
- * RegExp,
73
- * (description: string) => string
74
- * ]}
75
- */
76
- const escapeInlineTags = tagName => {
77
- const regex = new RegExp(`(^|\\s)@${
78
- // No need to escape, as contains only safe characters
79
- tagName}`, 'gv');
80
- return [regex,
81
- /**
82
- * @param {string} desc
83
- */
84
- desc => {
85
- return desc.replaceAll(regex, fixType === 'backticks' ? '$1`@' + tagName + '`' : '$1\\@' + tagName);
86
- }];
87
- };
88
153
  for (const tag of jsdoc.tags) {
89
154
  if (tag.tag === 'example') {
90
155
  continue;
@@ -95,10 +160,7 @@ var _default = exports.default = (0, _iterateJsdoc.default)(({
95
160
  while (/** @type {string[]} */utils.getTagDescription(tag, true)
96
161
  // eslint-disable-next-line no-loop-func -- Safe
97
162
  .some(desc => {
98
- tagName = unescapedInlineTagRegex.exec(desc)?.[1] ?? '';
99
- if (allowedInlineTags.includes(tagName)) {
100
- return false;
101
- }
163
+ tagName = getUnescapedInlineTagName(desc);
102
164
  return tagName;
103
165
  })) {
104
166
  const line = utils.setTagDescription(tag, ...escapeInlineTags(tagName)) + tag.source[0].number;
@@ -1 +1 @@
1
- {"version":3,"file":"escapeInlineTags.cjs","names":["_iterateJsdoc","_interopRequireDefault","require","e","__esModule","default","_default","exports","iterateJsdoc","context","jsdoc","settings","utils","mode","allowedInlineTags","enableFixer","fixType","options","description","getDescription","tagNames","indexes","unescapedInlineTagRegex","idx","descLine","startsWith","slice","split","entries","replaceAll","_","tagName","includes","push","reportJSDoc","line","setBlockDescription","info","seedTokens","descLines","map","desc","newDesc","RegExp","number","source","tokens","postDelimiter","trim","escapeInlineTags","regex","tag","tags","getTagDescription","some","exec","setTagDescription","iterateAllJsdocs","meta","docs","url","fixable","schema","additionalProperties","properties","items","type","enum","module"],"sources":["../../src/rules/escapeInlineTags.js"],"sourcesContent":["import iterateJsdoc from '../iterateJsdoc.js';\n\nexport default iterateJsdoc(({\n context,\n jsdoc,\n settings,\n utils,\n}) => {\n const {\n mode,\n } = settings;\n\n if (mode !== 'typescript') {\n return;\n }\n\n const {\n allowedInlineTags = [],\n enableFixer = false,\n fixType = 'backslash',\n } = context.options[0] || {};\n\n const {\n description,\n } = utils.getDescription();\n\n /** @type {string[]} */\n const tagNames = [];\n\n /** @type {number[]} */\n const indexes = [];\n\n const unescapedInlineTagRegex = /(?:^|\\s)@(\\w+)/gv;\n for (const [\n idx,\n descLine,\n ] of (\n description.startsWith('\\n') ? description.slice(1) : description\n ).split('\\n').entries()\n ) {\n descLine.replaceAll(unescapedInlineTagRegex, (_, tagName) => {\n if (allowedInlineTags.includes(tagName)) {\n return _;\n }\n\n tagNames.push(tagName);\n indexes.push(idx);\n\n return _;\n });\n }\n\n for (const [\n idx,\n tagName,\n ] of tagNames.entries()) {\n utils.reportJSDoc(\n `Unexpected inline JSDoc tag. Did you mean to use {@${tagName}}, \\\\@${tagName}, or \\`@${tagName}\\`?`,\n {\n line: indexes[idx] + 1,\n },\n enableFixer ?\n () => {\n utils.setBlockDescription((info, seedTokens, descLines) => {\n return descLines.map((desc) => {\n const newDesc = desc.replaceAll(\n new RegExp(`(^|\\\\s)@${\n // No need to escape, as contains only safe characters\n tagName\n }`, 'gv'),\n fixType === 'backticks' ? '$1`@' + tagName + '`' : '$1\\\\@' + tagName,\n );\n\n return {\n number: 0,\n source: '',\n tokens: seedTokens({\n ...info,\n description: newDesc,\n postDelimiter: newDesc.trim() ? ' ' : '',\n }),\n };\n });\n });\n } :\n null,\n );\n }\n\n /**\n * @param {string} tagName\n * @returns {[\n * RegExp,\n * (description: string) => string\n * ]}\n */\n const escapeInlineTags = (tagName) => {\n const regex = new RegExp(`(^|\\\\s)@${\n // No need to escape, as contains only safe characters\n tagName\n }`, 'gv');\n\n return [\n regex,\n /**\n * @param {string} desc\n */\n (desc) => {\n return desc.replaceAll(\n regex,\n fixType === 'backticks' ? '$1`@' + tagName + '`' : '$1\\\\@' + tagName,\n );\n },\n ];\n };\n\n for (const tag of jsdoc.tags) {\n if (tag.tag === 'example') {\n continue;\n }\n\n /** @type {string} */\n let tagName = '';\n while (/** @type {string[]} */ (\n utils.getTagDescription(tag, true)\n // eslint-disable-next-line no-loop-func -- Safe\n ).some((desc) => {\n tagName = unescapedInlineTagRegex.exec(desc)?.[1] ?? '';\n if (allowedInlineTags.includes(tagName)) {\n return false;\n }\n\n return tagName;\n })) {\n const line = utils.setTagDescription(tag, ...escapeInlineTags(tagName)) +\n tag.source[0].number;\n utils.reportJSDoc(\n `Unexpected inline JSDoc tag. Did you mean to use {@${tagName}}, \\\\@${tagName}, or \\`@${tagName}\\`?`,\n {\n line,\n },\n enableFixer ? () => {} : null,\n true,\n );\n }\n }\n}, {\n iterateAllJsdocs: true,\n meta: {\n docs: {\n description: 'Reports use of JSDoc tags in non-tag positions (in the default \"typescript\" mode).',\n url: 'https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/escape-inline-tags.md#repos-sticky-header',\n },\n fixable: 'code',\n schema: [\n {\n additionalProperties: false,\n properties: {\n allowedInlineTags: {\n description: 'A listing of tags you wish to allow unescaped. Defaults to an empty array.',\n items: {\n type: 'string',\n },\n type: 'array',\n },\n enableFixer: {\n description: 'Whether to enable the fixer. Defaults to `false`.',\n type: 'boolean',\n },\n fixType: {\n description: `How to escape the inline tag.\n\nMay be \"backticks\" to enclose tags in backticks (treating as code segments), or\n\"backslash\" to escape tags with a backslash, i.e., \\`\\\\@\\`\n\nDefaults to \"backslash\".`,\n enum: [\n 'backticks',\n 'backslash',\n ],\n type: 'string',\n },\n },\n type: 'object',\n },\n ],\n type: 'suggestion',\n },\n});\n"],"mappings":";;;;;;AAAA,IAAAA,aAAA,GAAAC,sBAAA,CAAAC,OAAA;AAA8C,SAAAD,uBAAAE,CAAA,WAAAA,CAAA,IAAAA,CAAA,CAAAC,UAAA,GAAAD,CAAA,KAAAE,OAAA,EAAAF,CAAA;AAAA,IAAAG,QAAA,GAAAC,OAAA,CAAAF,OAAA,GAE/B,IAAAG,qBAAY,EAAC,CAAC;EAC3BC,OAAO;EACPC,KAAK;EACLC,QAAQ;EACRC;AACF,CAAC,KAAK;EACJ,MAAM;IACJC;EACF,CAAC,GAAGF,QAAQ;EAEZ,IAAIE,IAAI,KAAK,YAAY,EAAE;IACzB;EACF;EAEA,MAAM;IACJC,iBAAiB,GAAG,EAAE;IACtBC,WAAW,GAAG,KAAK;IACnBC,OAAO,GAAG;EACZ,CAAC,GAAGP,OAAO,CAACQ,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;EAE5B,MAAM;IACJC;EACF,CAAC,GAAGN,KAAK,CAACO,cAAc,CAAC,CAAC;;EAE1B;EACA,MAAMC,QAAQ,GAAG,EAAE;;EAEnB;EACA,MAAMC,OAAO,GAAG,EAAE;EAElB,MAAMC,uBAAuB,GAAG,kBAAkB;EAClD,KAAK,MAAM,CACTC,GAAG,EACHC,QAAQ,CACT,IAAI,CACDN,WAAW,CAACO,UAAU,CAAC,IAAI,CAAC,GAAGP,WAAW,CAACQ,KAAK,CAAC,CAAC,CAAC,GAAGR,WAAW,EACjES,KAAK,CAAC,IAAI,CAAC,CAACC,OAAO,CAAC,CAAC,EACvB;IACAJ,QAAQ,CAACK,UAAU,CAACP,uBAAuB,EAAE,CAACQ,CAAC,EAAEC,OAAO,KAAK;MAC3D,IAAIjB,iBAAiB,CAACkB,QAAQ,CAACD,OAAO,CAAC,EAAE;QACvC,OAAOD,CAAC;MACV;MAEAV,QAAQ,CAACa,IAAI,CAACF,OAAO,CAAC;MACtBV,OAAO,CAACY,IAAI,CAACV,GAAG,CAAC;MAEjB,OAAOO,CAAC;IACV,CAAC,CAAC;EACJ;EAEA,KAAK,MAAM,CACTP,GAAG,EACHQ,OAAO,CACR,IAAIX,QAAQ,CAACQ,OAAO,CAAC,CAAC,EAAE;IACvBhB,KAAK,CAACsB,WAAW,CACf,sDAAsDH,OAAO,SAASA,OAAO,WAAWA,OAAO,KAAK,EACpG;MACEI,IAAI,EAAEd,OAAO,CAACE,GAAG,CAAC,GAAG;IACvB,CAAC,EACDR,WAAW,GACT,MAAM;MACJH,KAAK,CAACwB,mBAAmB,CAAC,CAACC,IAAI,EAAEC,UAAU,EAAEC,SAAS,KAAK;QACzD,OAAOA,SAAS,CAACC,GAAG,CAAEC,IAAI,IAAK;UAC7B,MAAMC,OAAO,GAAGD,IAAI,CAACZ,UAAU,CAC7B,IAAIc,MAAM,CAAC;UACT;UACAZ,OAAO,EACP,EAAE,IAAI,CAAC,EACTf,OAAO,KAAK,WAAW,GAAG,MAAM,GAAGe,OAAO,GAAG,GAAG,GAAG,OAAO,GAAGA,OAC/D,CAAC;UAED,OAAO;YACLa,MAAM,EAAE,CAAC;YACTC,MAAM,EAAE,EAAE;YACVC,MAAM,EAAER,UAAU,CAAC;cACjB,GAAGD,IAAI;cACPnB,WAAW,EAAEwB,OAAO;cACpBK,aAAa,EAAEL,OAAO,CAACM,IAAI,CAAC,CAAC,GAAG,GAAG,GAAG;YACxC,CAAC;UACH,CAAC;QACH,CAAC,CAAC;MACJ,CAAC,CAAC;IACJ,CAAC,GACD,IACJ,CAAC;EACH;;EAEA;AACF;AACA;AACA;AACA;AACA;AACA;EACE,MAAMC,gBAAgB,GAAIlB,OAAO,IAAK;IACpC,MAAMmB,KAAK,GAAG,IAAIP,MAAM,CAAC;IACvB;IACAZ,OAAO,EACP,EAAE,IAAI,CAAC;IAET,OAAO,CACLmB,KAAK;IACL;AACN;AACA;IACOT,IAAI,IAAK;MACR,OAAOA,IAAI,CAACZ,UAAU,CACpBqB,KAAK,EACLlC,OAAO,KAAK,WAAW,GAAG,MAAM,GAAGe,OAAO,GAAG,GAAG,GAAG,OAAO,GAAGA,OAC/D,CAAC;IACH,CAAC,CACF;EACH,CAAC;EAED,KAAK,MAAMoB,GAAG,IAAIzC,KAAK,CAAC0C,IAAI,EAAE;IAC5B,IAAID,GAAG,CAACA,GAAG,KAAK,SAAS,EAAE;MACzB;IACF;;IAEA;IACA,IAAIpB,OAAO,GAAG,EAAE;IAChB,OAAO,uBACLnB,KAAK,CAACyC,iBAAiB,CAACF,GAAG,EAAE,IAAI;IACnC;IAAA,CACEG,IAAI,CAAEb,IAAI,IAAK;MACfV,OAAO,GAAGT,uBAAuB,CAACiC,IAAI,CAACd,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE;MACvD,IAAI3B,iBAAiB,CAACkB,QAAQ,CAACD,OAAO,CAAC,EAAE;QACvC,OAAO,KAAK;MACd;MAEA,OAAOA,OAAO;IAChB,CAAC,CAAC,EAAE;MACF,MAAMI,IAAI,GAAGvB,KAAK,CAAC4C,iBAAiB,CAACL,GAAG,EAAE,GAAGF,gBAAgB,CAAClB,OAAO,CAAC,CAAC,GACnEoB,GAAG,CAACN,MAAM,CAAC,CAAC,CAAC,CAACD,MAAM;MACxBhC,KAAK,CAACsB,WAAW,CACf,sDAAsDH,OAAO,SAASA,OAAO,WAAWA,OAAO,KAAK,EACpG;QACEI;MACF,CAAC,EACDpB,WAAW,GAAG,MAAM,CAAC,CAAC,GAAG,IAAI,EAC7B,IACF,CAAC;IACH;EACF;AACF,CAAC,EAAE;EACD0C,gBAAgB,EAAE,IAAI;EACtBC,IAAI,EAAE;IACJC,IAAI,EAAE;MACJzC,WAAW,EAAE,oFAAoF;MACjG0C,GAAG,EAAE;IACP,CAAC;IACDC,OAAO,EAAE,MAAM;IACfC,MAAM,EAAE,CACN;MACEC,oBAAoB,EAAE,KAAK;MAC3BC,UAAU,EAAE;QACVlD,iBAAiB,EAAE;UACjBI,WAAW,EAAE,4EAA4E;UACzF+C,KAAK,EAAE;YACLC,IAAI,EAAE;UACR,CAAC;UACDA,IAAI,EAAE;QACR,CAAC;QACDnD,WAAW,EAAE;UACXG,WAAW,EAAE,mDAAmD;UAChEgD,IAAI,EAAE;QACR,CAAC;QACDlD,OAAO,EAAE;UACPE,WAAW,EAAE;AACzB;AACA;AACA;AACA;AACA,yBAAyB;UACbiD,IAAI,EAAE,CACJ,WAAW,EACX,WAAW,CACZ;UACDD,IAAI,EAAE;QACR;MACF,CAAC;MACDA,IAAI,EAAE;IACR,CAAC,CACF;IACDA,IAAI,EAAE;EACR;AACF,CAAC,CAAC;AAAAE,MAAA,CAAA7D,OAAA,GAAAA,OAAA,CAAAF,OAAA","ignoreList":[]}
1
+ {"version":3,"file":"escapeInlineTags.cjs","names":["_iterateJsdoc","_interopRequireDefault","require","e","__esModule","default","_default","exports","iterateJsdoc","context","jsdoc","settings","utils","mode","allowedInlineTags","enableFixer","fixType","options","description","getDescription","tagNames","indexes","unescapedInlineTagRegex","scopedPackageNameRegex","declarationReferenceInlineTags","Set","getInlineTagName","desc","atSignIndex","inlineTagStart","lastIndexOf","inlineTagEnd","indexOf","slice","match","shouldIgnoreMatch","offset","inlineTagName","has","test","escapeInlineTags","tagName","regex","RegExp","replaceAll","prefix","getUnescapedInlineTagName","lastIndex","exec","fullMatch","includes","index","normalizedDescription","startsWith","nextLineStartOffset","idx","descLine","split","entries","lineStartOffset","length","push","reportJSDoc","line","escapeInlineTag","setBlockDescription","info","seedTokens","descLines","map","newDesc","number","source","tokens","postDelimiter","trim","tag","tags","getTagDescription","some","setTagDescription","iterateAllJsdocs","meta","docs","url","fixable","schema","additionalProperties","properties","items","type","enum","module"],"sources":["../../src/rules/escapeInlineTags.js"],"sourcesContent":["import iterateJsdoc from '../iterateJsdoc.js';\n\nexport default iterateJsdoc(({\n context,\n jsdoc,\n settings,\n utils,\n}) => {\n const {\n mode,\n } = settings;\n\n if (mode !== 'typescript') {\n return;\n }\n\n const {\n allowedInlineTags = [],\n enableFixer = false,\n fixType = 'backslash',\n } = context.options[0] || {};\n\n const {\n description,\n } = utils.getDescription();\n\n /** @type {string[]} */\n const tagNames = [];\n\n /** @type {number[]} */\n const indexes = [];\n\n const unescapedInlineTagRegex = /(?:^|\\s)@(\\w+)/gv;\n\n const scopedPackageNameRegex = /^@[\\w.\\-]+\\/[\\w.\\-]+/v;\n\n const declarationReferenceInlineTags = new Set([\n 'inheritDoc',\n 'link',\n 'linkcode',\n 'linkplain',\n ]);\n\n /**\n * @param {string} desc\n * @param {number} atSignIndex\n * @returns {string}\n */\n const getInlineTagName = (desc, atSignIndex) => {\n const inlineTagStart = desc.lastIndexOf('{@', atSignIndex);\n\n if (inlineTagStart === -1) {\n return '';\n }\n\n const inlineTagEnd = desc.indexOf('}', inlineTagStart);\n\n if (inlineTagEnd === -1 || inlineTagEnd <= atSignIndex) {\n return '';\n }\n\n return desc.slice(inlineTagStart + 2).match(/^\\w+/v)?.[0] || '';\n };\n\n /**\n * @param {string} desc\n * @param {string} match\n * @param {number} offset\n * @returns {boolean}\n */\n const shouldIgnoreMatch = (desc, match, offset) => {\n const atSignIndex = offset + match.lastIndexOf('@');\n const inlineTagName = getInlineTagName(desc, atSignIndex);\n\n return declarationReferenceInlineTags.has(inlineTagName) &&\n scopedPackageNameRegex.test(desc.slice(atSignIndex));\n };\n\n /**\n * @param {string} tagName\n * @returns {[\n * RegExp,\n * (description: string) => string\n * ]}\n */\n const escapeInlineTags = (tagName) => {\n const regex = new RegExp(`(^|\\\\s)@${\n // No need to escape, as contains only safe characters\n tagName\n }`, 'gv');\n\n return [\n regex,\n /**\n * @param {string} desc\n */\n (desc) => {\n return desc.replaceAll(\n regex,\n (match, prefix, offset) => {\n if (shouldIgnoreMatch(desc, match, offset)) {\n return match;\n }\n\n return fixType === 'backticks' ?\n prefix + '`@' + tagName + '`' :\n prefix + '\\\\@' + tagName;\n },\n );\n },\n ];\n };\n\n /**\n * @param {string} desc\n * @returns {string}\n */\n const getUnescapedInlineTagName = (desc) => {\n unescapedInlineTagRegex.lastIndex = 0;\n\n let match;\n while ((match = unescapedInlineTagRegex.exec(desc)) !== null) {\n const [\n fullMatch,\n tagName,\n ] = match;\n\n if (\n allowedInlineTags.includes(tagName) ||\n shouldIgnoreMatch(desc, fullMatch, match.index)\n ) {\n continue;\n }\n\n return tagName;\n }\n\n return '';\n };\n\n const normalizedDescription = description.startsWith('\\n') ?\n description.slice(1) :\n description;\n\n let nextLineStartOffset = 0;\n for (const [\n idx,\n descLine,\n ] of normalizedDescription.split('\\n').entries()\n ) {\n const lineStartOffset = nextLineStartOffset;\n\n // +1 for the `\\n` removed by split.\n nextLineStartOffset += descLine.length + 1;\n\n descLine.replaceAll(unescapedInlineTagRegex, (match, tagName, offset) => {\n if (\n allowedInlineTags.includes(tagName) ||\n // Run ignore-detection against the full description text so that\n // multi-line inline tags (e.g. `{@link` on one line and\n // `@scope/pkg#Member}` on the next) are recognized as being inside an\n // inline tag rather than scanned per-line.\n shouldIgnoreMatch(\n normalizedDescription,\n match,\n lineStartOffset + offset,\n )\n ) {\n return match;\n }\n\n tagNames.push(tagName);\n indexes.push(idx);\n\n return match;\n });\n }\n\n for (const [\n idx,\n tagName,\n ] of tagNames.entries()) {\n utils.reportJSDoc(\n `Unexpected inline JSDoc tag. Did you mean to use {@${tagName}}, \\\\@${tagName}, or \\`@${tagName}\\`?`,\n {\n line: indexes[idx] + 1,\n },\n enableFixer ?\n () => {\n // `tagName` and `fixType` are constant here, so compute the escaper\n // once rather than rebuilding the RegExp + closure for every line.\n const [\n ,\n escapeInlineTag,\n ] = escapeInlineTags(tagName);\n\n utils.setBlockDescription((info, seedTokens, descLines) => {\n return descLines.map((desc) => {\n const newDesc = escapeInlineTag(desc);\n\n return {\n number: 0,\n source: '',\n tokens: seedTokens({\n ...info,\n description: newDesc,\n postDelimiter: newDesc.trim() ? ' ' : '',\n }),\n };\n });\n });\n } :\n null,\n );\n }\n\n for (const tag of jsdoc.tags) {\n if (tag.tag === 'example') {\n continue;\n }\n\n /** @type {string} */\n let tagName = '';\n while (/** @type {string[]} */ (\n utils.getTagDescription(tag, true)\n // eslint-disable-next-line no-loop-func -- Safe\n ).some((desc) => {\n tagName = getUnescapedInlineTagName(desc);\n\n return tagName;\n })) {\n const line = utils.setTagDescription(tag, ...escapeInlineTags(tagName)) +\n tag.source[0].number;\n utils.reportJSDoc(\n `Unexpected inline JSDoc tag. Did you mean to use {@${tagName}}, \\\\@${tagName}, or \\`@${tagName}\\`?`,\n {\n line,\n },\n enableFixer ? () => {} : null,\n true,\n );\n }\n }\n}, {\n iterateAllJsdocs: true,\n meta: {\n docs: {\n description: 'Reports use of JSDoc tags in non-tag positions (in the default \"typescript\" mode).',\n url: 'https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/escape-inline-tags.md#repos-sticky-header',\n },\n fixable: 'code',\n schema: [\n {\n additionalProperties: false,\n properties: {\n allowedInlineTags: {\n description: 'A listing of tags you wish to allow unescaped. Defaults to an empty array.',\n items: {\n type: 'string',\n },\n type: 'array',\n },\n enableFixer: {\n description: 'Whether to enable the fixer. Defaults to `false`.',\n type: 'boolean',\n },\n fixType: {\n description: `How to escape the inline tag.\n\nMay be \"backticks\" to enclose tags in backticks (treating as code segments), or\n\"backslash\" to escape tags with a backslash, i.e., \\`\\\\@\\`\n\nDefaults to \"backslash\".`,\n enum: [\n 'backticks',\n 'backslash',\n ],\n type: 'string',\n },\n },\n type: 'object',\n },\n ],\n type: 'suggestion',\n },\n});\n"],"mappings":"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","ignoreList":[]}
@@ -267,11 +267,7 @@ var _default = exports.default = (0, _iterateJsdoc.default)(({
267
267
  const hasNamepathPosition = (tagMustHaveNamePosition !== false || utils.tagMightHaveNamepath(tag.tag)) && Boolean(tag.name);
268
268
  if (hasNamepathPosition) {
269
269
  if (mode !== 'jsdoc' && tag.tag === 'template') {
270
- if (!tryParsePathIgnoreError(
271
- // May be an issue with the commas of
272
- // `utils.parseClosureTemplateTag`, so first try a raw
273
- // value; we really need a proper parser instead, however.
274
- tag.name.trim().replace(/^\[?(?<name>.*?)=.*$/v, '$<name>'), mode)) {
270
+ if (!tryParsePathIgnoreError(tag.name.trim(), mode)) {
275
271
  for (const namepath of utils.parseClosureTemplateTag(tag)) {
276
272
  validNamepathParsing(namepath);
277
273
  }
@@ -1 +1 @@
1
- {"version":3,"file":"validTypes.cjs","names":["_iterateJsdoc","_interopRequireDefault","require","_jsdoccomment","e","__esModule","default","inlineTags","Set","asExpression","suppressTypes","tryParsePathIgnoreError","path","mode","parseNamePath","includeSpecial","tryParseNameIgnoreError","name","parseName","_default","exports","iterateJsdoc","context","jsdoc","report","settings","utils","allowEmptyNamepaths","options","tag","tags","validNamepathParsing","namepath","tagName","handled","endChar","slice","includes","startsWith","test","startChar","charAt","validTypeParsing","type","parsedTypes","tryParse","undefined","classContext","parse","traverse","node","typ","right","meta","position","problems","length","msg","reduce","str","message","thisNamepath","getTagDescription","replace","trim","thatNamepath","value","has","otherModeMaps","filter","mde","map","getTagStructureForMode","tagMightHaveNamePosition","modeInfo","description","mightHaveTypePosition","tagMightHaveTypePosition","tagMustHaveNamePosition","mustHaveTypePosition","tagMustHaveTypePosition","tagMissingRequiredTypeOrNamepath","hasTypePosition","Boolean","hasNamepathPosition","tagMightHaveNamepath","parseClosureTemplateTag","hasNamePosition","tagMightHaveName","inlineTag","text","namepathOrURL","iterateAllJsdocs","docs","url","schema","additionalProperties","properties","module"],"sources":["../../src/rules/validTypes.js"],"sourcesContent":["import iterateJsdoc from '../iterateJsdoc.js';\nimport {\n parse,\n parseName,\n parseNamePath,\n traverse,\n tryParse,\n} from '@es-joy/jsdoccomment';\n\nconst inlineTags = new Set([\n // Typdoc\n 'include', 'includeCode',\n // TSDoc\n 'inheritDoc',\n 'inheritdoc',\n 'label',\n // JSDoc\n 'link',\n 'linkcode', 'linkplain',\n 'tutorial',\n]);\n\nconst asExpression = /as\\s+/v;\n\nconst suppressTypes = new Set([\n // https://github.com/google/closure-compiler/wiki/@suppress-annotations\n // https://github.com/google/closure-compiler/blob/master/src/com/google/javascript/jscomp/parsing/ParserConfig.properties#L154\n 'accessControls',\n 'checkDebuggerStatement',\n 'checkEs5InheritanceCorrectnessConditions',\n 'checkPrototypalTypes',\n 'checkRegExp',\n 'checkTypes',\n 'checkVars',\n 'closureClassChecks',\n 'closureDepMethodUsageChecks',\n 'const',\n 'constantProperty',\n 'dangerousUnrecognizedTypeError',\n 'deprecated',\n 'duplicate',\n 'es5Strict',\n 'externsValidation',\n 'extraProvide',\n 'extraRequire',\n 'globalThis',\n 'invalidCasts',\n 'lateProvide',\n 'legacyGoogScopeRequire',\n 'lintChecks',\n 'lintVarDeclarations',\n 'messageConventions',\n 'misplacedTypeAnnotation',\n 'missingOverride',\n 'missingPolyfill',\n 'missingProperties',\n 'missingProvide',\n 'missingRequire',\n 'missingReturn',\n 'missingSourcesWarnings',\n 'moduleLoad',\n 'msgDescriptions',\n 'nonStandardJsDocs',\n 'partialAlias',\n 'polymer',\n 'reportUnknownTypes',\n 'strictCheckTypes',\n 'strictMissingProperties',\n 'strictModuleDepCheck',\n 'strictPrimitiveOperators',\n 'suspiciousCode',\n\n // Not documented in enum\n 'switch',\n 'transitionalSuspiciousCodeWarnings',\n 'undefinedNames',\n 'undefinedVars',\n 'underscore',\n 'unknownDefines',\n 'untranspilableFeatures',\n 'unusedLocalVariables',\n\n // Not documented?\n 'unusedPrivateMembers',\n 'uselessCode',\n 'useOfGoogProvide',\n 'visibility',\n 'with',\n]);\n\n/**\n * @param {string} path\n * @param {import('jsdoc-type-pratt-parser').ParseMode|\"permissive\"} mode\n * @returns {boolean}\n */\nconst tryParsePathIgnoreError = (path, mode) => {\n try {\n parseNamePath(\n path,\n mode === 'permissive' ? 'jsdoc' : mode,\n {\n includeSpecial: true,\n },\n );\n\n return true;\n } catch {\n // Keep the original error for including the whole type\n }\n\n return false;\n};\n\n/**\n * @param {string} name\n * @param {import('jsdoc-type-pratt-parser').ParseMode} mode\n * @returns {boolean}\n */\nconst tryParseNameIgnoreError = (name, mode) => {\n try {\n parseName(name, mode);\n\n return true;\n } catch {\n // Keep the original error for including the whole type\n }\n\n return false;\n};\n\nexport default iterateJsdoc(({\n context,\n jsdoc,\n report,\n settings,\n utils,\n// eslint-disable-next-line complexity\n}) => {\n const {\n allowEmptyNamepaths = false,\n } = context.options[0] || {};\n const {\n mode,\n } = settings;\n\n for (const tag of jsdoc.tags) {\n /**\n * @param {string} namepath\n * @param {string} [tagName]\n * @returns {boolean}\n */\n const validNamepathParsing = function (namepath, tagName) {\n if (\n tryParsePathIgnoreError(namepath, mode)\n ) {\n return true;\n }\n\n let handled = false;\n\n if (tagName) {\n switch (tagName) {\n case 'memberof':\n case 'memberof!': {\n const endChar = namepath.slice(-1);\n if ([\n '#', '.', '~',\n ].includes(endChar)) {\n handled = tryParsePathIgnoreError(namepath.slice(0, -1), mode);\n }\n\n break;\n }\n\n case 'module': case 'requires': {\n if (!namepath.startsWith('module:')) {\n handled = tryParsePathIgnoreError(`module:${namepath}`, mode);\n }\n\n break;\n }\n\n case 'prop':\n case 'property': {\n if (mode === 'jsdoc' && (/^\\d+$/v).test(namepath)) {\n handled = true;\n }\n\n break;\n }\n\n case 'borrows': {\n const startChar = namepath.charAt(0);\n if ([\n '#', '.', '~',\n ].includes(startChar)) {\n handled = tryParsePathIgnoreError(namepath.slice(1), mode);\n }\n }\n }\n }\n\n if (!handled) {\n report(`Syntax error in namepath: ${namepath}`, null, tag);\n\n return false;\n }\n\n return true;\n };\n\n /**\n * @param {string} type\n * @returns {boolean}\n */\n const validTypeParsing = function (type) {\n let parsedTypes;\n try {\n if (mode === 'permissive') {\n parsedTypes = tryParse(type, undefined, {\n classContext: true,\n });\n } else {\n parsedTypes = parse(type, mode, {\n classContext: true,\n });\n }\n } catch {\n report(`Syntax error in type: ${type}`, null, tag);\n\n return false;\n }\n\n if (mode === 'closure' || mode === 'typescript') {\n traverse(parsedTypes, (node) => {\n const {\n type: typ,\n } = node;\n\n if (\n (typ === 'JsdocTypeObjectField' || typ === 'JsdocTypeKeyValue') &&\n node.right?.type === 'JsdocTypeNullable' &&\n node.right?.meta?.position === 'suffix'\n ) {\n report(`Syntax error in type: ${node.right.type}`, null, tag);\n }\n });\n }\n\n return true;\n };\n\n if (tag.problems.length) {\n const msg = tag.problems.reduce((str, {\n message,\n }) => {\n return str + '; ' + message;\n }, '').slice(2);\n report(`Invalid name: ${msg}`, null, tag);\n continue;\n }\n\n if (tag.tag === 'import') {\n // A named import will look like a type, but not be valid; we also don't\n // need to check the name/namepath\n continue;\n }\n\n if (tag.tag === 'borrows') {\n const thisNamepath = /** @type {string} */ (\n utils.getTagDescription(tag)\n ).replace(asExpression, '')\n .trim();\n\n if (!asExpression.test(/** @type {string} */ (\n utils.getTagDescription(tag)\n )) || !thisNamepath) {\n report(`@borrows must have an \"as\" expression. Found \"${utils.getTagDescription(tag)}\"`, null, tag);\n\n continue;\n }\n\n if (validNamepathParsing(thisNamepath, 'borrows')) {\n const thatNamepath = tag.name;\n\n validNamepathParsing(thatNamepath);\n }\n\n continue;\n }\n\n if (tag.tag === 'suppress' && mode === 'closure') {\n let parsedTypes;\n\n try {\n parsedTypes = tryParse(tag.type);\n } catch {\n // Ignore\n }\n\n if (parsedTypes) {\n traverse(parsedTypes, (node) => {\n let type;\n if ('value' in node && typeof node.value === 'string') {\n type = node.value;\n }\n\n if (type !== undefined && !suppressTypes.has(type)) {\n report(`Syntax error in suppress type: ${type}`, null, tag);\n }\n });\n }\n }\n\n const otherModeMaps = /** @type {import('../jsdocUtils.js').ParserMode[]} */ ([\n 'jsdoc', 'typescript', 'closure', 'permissive',\n ]).filter(\n (mde) => {\n return mde !== mode;\n },\n ).map((mde) => {\n return utils.getTagStructureForMode(mde);\n });\n\n const tagMightHaveNamePosition = utils.tagMightHaveNamePosition(tag.tag, otherModeMaps);\n if (tagMightHaveNamePosition !== true && tag.name) {\n const modeInfo = tagMightHaveNamePosition === false ? '' : ` in \"${mode}\" mode`;\n report(`@${tag.tag} should not have a name${modeInfo}.`, null, tag);\n\n continue;\n }\n\n // Documentation like `@returns {@link SomeType}` is technically ambiguous. Specifically it\n // could either be intepreted as a type `\"@link SomeType\"` or a description `\"{@link SomeType}\"`.\n // However this is a good heuristic.\n if (tag.type.trim().startsWith('@')) {\n tag.description = `{${tag.type}} ${tag.description}`;\n tag.type = '';\n }\n\n const mightHaveTypePosition = utils.tagMightHaveTypePosition(tag.tag, otherModeMaps);\n if (mightHaveTypePosition !== true && tag.type) {\n const modeInfo = mightHaveTypePosition === false ? '' : ` in \"${mode}\" mode`;\n report(`@${tag.tag} should not have a bracketed type${modeInfo}.`, null, tag);\n\n continue;\n }\n\n // REQUIRED NAME\n const tagMustHaveNamePosition = utils.tagMustHaveNamePosition(tag.tag, otherModeMaps);\n\n // Don't handle `@param` here though it does require name as handled by\n // `require-param-name` (`@property` would similarly seem to require one,\n // but is handled by `require-property-name`)\n if (tagMustHaveNamePosition !== false && !tag.name && !allowEmptyNamepaths && ![\n 'arg', 'argument', 'param',\n 'prop', 'property',\n ].includes(tag.tag) &&\n (tag.tag !== 'see' || !utils.getTagDescription(tag).includes('{@link'))\n ) {\n const modeInfo = tagMustHaveNamePosition === true ? '' : ` in \"${mode}\" mode`;\n report(`Tag @${tag.tag} must have a name/namepath${modeInfo}.`, null, tag);\n\n continue;\n }\n\n // REQUIRED TYPE\n const mustHaveTypePosition = utils.tagMustHaveTypePosition(tag.tag, otherModeMaps);\n if (mustHaveTypePosition !== false && !tag.type &&\n // Auto-added to settings and has own rule already, so don't duplicate\n tag.tag !== 'next'\n ) {\n const modeInfo = mustHaveTypePosition === true ? '' : ` in \"${mode}\" mode`;\n report(`Tag @${tag.tag} must have a type${modeInfo}.`, null, tag);\n\n continue;\n }\n\n // REQUIRED TYPE OR NAME/NAMEPATH\n const tagMissingRequiredTypeOrNamepath = utils.tagMissingRequiredTypeOrNamepath(tag, otherModeMaps);\n if (tagMissingRequiredTypeOrNamepath !== false && !allowEmptyNamepaths) {\n const modeInfo = tagMissingRequiredTypeOrNamepath === true ? '' : ` in \"${mode}\" mode`;\n report(`Tag @${tag.tag} must have either a type or namepath${modeInfo}.`, null, tag);\n\n continue;\n }\n\n // VALID TYPE\n const hasTypePosition = mightHaveTypePosition === true && Boolean(tag.type);\n if (hasTypePosition && (tag.type !== 'const' || tag.tag !== 'type')) {\n validTypeParsing(tag.type);\n }\n\n // VALID NAME/NAMEPATH\n const hasNamepathPosition = (\n tagMustHaveNamePosition !== false ||\n utils.tagMightHaveNamepath(tag.tag)\n ) && Boolean(tag.name);\n\n if (hasNamepathPosition) {\n if (mode !== 'jsdoc' && tag.tag === 'template') {\n if (!tryParsePathIgnoreError(\n // May be an issue with the commas of\n // `utils.parseClosureTemplateTag`, so first try a raw\n // value; we really need a proper parser instead, however.\n tag.name.trim().replace(/^\\[?(?<name>.*?)=.*$/v, '$<name>'),\n mode,\n )) {\n for (const namepath of utils.parseClosureTemplateTag(tag)) {\n validNamepathParsing(namepath);\n }\n }\n } else {\n validNamepathParsing(tag.name, tag.tag);\n }\n }\n\n const hasNamePosition = utils.tagMightHaveName(tag.tag) &&\n Boolean(tag.name);\n if (\n hasNamePosition &&\n mode === 'typescript' &&\n !tryParseNameIgnoreError(tag.name, mode)\n ) {\n report(`Syntax error in name: ${tag.name}`, null, tag);\n } else if (hasNamePosition && mode !== 'typescript') {\n validNamepathParsing(tag.name, tag.tag);\n }\n\n for (const inlineTag of tag.inlineTags) {\n if (inlineTags.has(inlineTag.tag) && !inlineTag.text && !inlineTag.namepathOrURL) {\n report(`Inline tag \"${inlineTag.tag}\" missing content`, null, tag);\n }\n }\n }\n\n for (const inlineTag of jsdoc.inlineTags) {\n if (inlineTags.has(inlineTag.tag) && !inlineTag.text && !inlineTag.namepathOrURL) {\n report(`Inline tag \"${inlineTag.tag}\" missing content`);\n }\n }\n}, {\n iterateAllJsdocs: true,\n meta: {\n docs: {\n description: 'Requires all types/namepaths to be valid JSDoc, Closure compiler, or TypeScript types (configurable in settings).',\n url: 'https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/valid-types.md#repos-sticky-header',\n },\n schema: [\n {\n additionalProperties: false,\n properties: {\n allowEmptyNamepaths: {\n default: false,\n description: `Set to \\`false\\` to bulk disallow\nempty name paths with namepath groups 2 and 4 (these might often be\nexpected to have an accompanying name path, though they have some\nindicative value without one; these may also allow names to be defined\nin another manner elsewhere in the block); you can use\n\\`settings.jsdoc.structuredTags\\` with the \\`required\\` key set to \"name\" if you\nwish to require name paths on a tag-by-tag basis. Defaults to \\`true\\`.`,\n type: 'boolean',\n },\n },\n type: 'object',\n },\n ],\n type: 'suggestion',\n },\n});\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"file":"validTypes.cjs","names":["_iterateJsdoc","_interopRequireDefault","require","_jsdoccomment","e","__esModule","default","inlineTags","Set","asExpression","suppressTypes","tryParsePathIgnoreError","path","mode","parseNamePath","includeSpecial","tryParseNameIgnoreError","name","parseName","_default","exports","iterateJsdoc","context","jsdoc","report","settings","utils","allowEmptyNamepaths","options","tag","tags","validNamepathParsing","namepath","tagName","handled","endChar","slice","includes","startsWith","test","startChar","charAt","validTypeParsing","type","parsedTypes","tryParse","undefined","classContext","parse","traverse","node","typ","right","meta","position","problems","length","msg","reduce","str","message","thisNamepath","getTagDescription","replace","trim","thatNamepath","value","has","otherModeMaps","filter","mde","map","getTagStructureForMode","tagMightHaveNamePosition","modeInfo","description","mightHaveTypePosition","tagMightHaveTypePosition","tagMustHaveNamePosition","mustHaveTypePosition","tagMustHaveTypePosition","tagMissingRequiredTypeOrNamepath","hasTypePosition","Boolean","hasNamepathPosition","tagMightHaveNamepath","parseClosureTemplateTag","hasNamePosition","tagMightHaveName","inlineTag","text","namepathOrURL","iterateAllJsdocs","docs","url","schema","additionalProperties","properties","module"],"sources":["../../src/rules/validTypes.js"],"sourcesContent":["import iterateJsdoc from '../iterateJsdoc.js';\nimport {\n parse,\n parseName,\n parseNamePath,\n traverse,\n tryParse,\n} from '@es-joy/jsdoccomment';\n\nconst inlineTags = new Set([\n // Typdoc\n 'include', 'includeCode',\n // TSDoc\n 'inheritDoc',\n 'inheritdoc',\n 'label',\n // JSDoc\n 'link',\n 'linkcode', 'linkplain',\n 'tutorial',\n]);\n\nconst asExpression = /as\\s+/v;\n\nconst suppressTypes = new Set([\n // https://github.com/google/closure-compiler/wiki/@suppress-annotations\n // https://github.com/google/closure-compiler/blob/master/src/com/google/javascript/jscomp/parsing/ParserConfig.properties#L154\n 'accessControls',\n 'checkDebuggerStatement',\n 'checkEs5InheritanceCorrectnessConditions',\n 'checkPrototypalTypes',\n 'checkRegExp',\n 'checkTypes',\n 'checkVars',\n 'closureClassChecks',\n 'closureDepMethodUsageChecks',\n 'const',\n 'constantProperty',\n 'dangerousUnrecognizedTypeError',\n 'deprecated',\n 'duplicate',\n 'es5Strict',\n 'externsValidation',\n 'extraProvide',\n 'extraRequire',\n 'globalThis',\n 'invalidCasts',\n 'lateProvide',\n 'legacyGoogScopeRequire',\n 'lintChecks',\n 'lintVarDeclarations',\n 'messageConventions',\n 'misplacedTypeAnnotation',\n 'missingOverride',\n 'missingPolyfill',\n 'missingProperties',\n 'missingProvide',\n 'missingRequire',\n 'missingReturn',\n 'missingSourcesWarnings',\n 'moduleLoad',\n 'msgDescriptions',\n 'nonStandardJsDocs',\n 'partialAlias',\n 'polymer',\n 'reportUnknownTypes',\n 'strictCheckTypes',\n 'strictMissingProperties',\n 'strictModuleDepCheck',\n 'strictPrimitiveOperators',\n 'suspiciousCode',\n\n // Not documented in enum\n 'switch',\n 'transitionalSuspiciousCodeWarnings',\n 'undefinedNames',\n 'undefinedVars',\n 'underscore',\n 'unknownDefines',\n 'untranspilableFeatures',\n 'unusedLocalVariables',\n\n // Not documented?\n 'unusedPrivateMembers',\n 'uselessCode',\n 'useOfGoogProvide',\n 'visibility',\n 'with',\n]);\n\n/**\n * @param {string} path\n * @param {import('jsdoc-type-pratt-parser').ParseMode|\"permissive\"} mode\n * @returns {boolean}\n */\nconst tryParsePathIgnoreError = (path, mode) => {\n try {\n parseNamePath(\n path,\n mode === 'permissive' ? 'jsdoc' : mode,\n {\n includeSpecial: true,\n },\n );\n\n return true;\n } catch {\n // Keep the original error for including the whole type\n }\n\n return false;\n};\n\n/**\n * @param {string} name\n * @param {import('jsdoc-type-pratt-parser').ParseMode} mode\n * @returns {boolean}\n */\nconst tryParseNameIgnoreError = (name, mode) => {\n try {\n parseName(name, mode);\n\n return true;\n } catch {\n // Keep the original error for including the whole type\n }\n\n return false;\n};\n\nexport default iterateJsdoc(({\n context,\n jsdoc,\n report,\n settings,\n utils,\n// eslint-disable-next-line complexity\n}) => {\n const {\n allowEmptyNamepaths = false,\n } = context.options[0] || {};\n const {\n mode,\n } = settings;\n\n for (const tag of jsdoc.tags) {\n /**\n * @param {string} namepath\n * @param {string} [tagName]\n * @returns {boolean}\n */\n const validNamepathParsing = function (namepath, tagName) {\n if (\n tryParsePathIgnoreError(namepath, mode)\n ) {\n return true;\n }\n\n let handled = false;\n\n if (tagName) {\n switch (tagName) {\n case 'memberof':\n case 'memberof!': {\n const endChar = namepath.slice(-1);\n if ([\n '#', '.', '~',\n ].includes(endChar)) {\n handled = tryParsePathIgnoreError(namepath.slice(0, -1), mode);\n }\n\n break;\n }\n\n case 'module': case 'requires': {\n if (!namepath.startsWith('module:')) {\n handled = tryParsePathIgnoreError(`module:${namepath}`, mode);\n }\n\n break;\n }\n\n case 'prop':\n case 'property': {\n if (mode === 'jsdoc' && (/^\\d+$/v).test(namepath)) {\n handled = true;\n }\n\n break;\n }\n\n case 'borrows': {\n const startChar = namepath.charAt(0);\n if ([\n '#', '.', '~',\n ].includes(startChar)) {\n handled = tryParsePathIgnoreError(namepath.slice(1), mode);\n }\n }\n }\n }\n\n if (!handled) {\n report(`Syntax error in namepath: ${namepath}`, null, tag);\n\n return false;\n }\n\n return true;\n };\n\n /**\n * @param {string} type\n * @returns {boolean}\n */\n const validTypeParsing = function (type) {\n let parsedTypes;\n try {\n if (mode === 'permissive') {\n parsedTypes = tryParse(type, undefined, {\n classContext: true,\n });\n } else {\n parsedTypes = parse(type, mode, {\n classContext: true,\n });\n }\n } catch {\n report(`Syntax error in type: ${type}`, null, tag);\n\n return false;\n }\n\n if (mode === 'closure' || mode === 'typescript') {\n traverse(parsedTypes, (node) => {\n const {\n type: typ,\n } = node;\n\n if (\n (typ === 'JsdocTypeObjectField' || typ === 'JsdocTypeKeyValue') &&\n node.right?.type === 'JsdocTypeNullable' &&\n node.right?.meta?.position === 'suffix'\n ) {\n report(`Syntax error in type: ${node.right.type}`, null, tag);\n }\n });\n }\n\n return true;\n };\n\n if (tag.problems.length) {\n const msg = tag.problems.reduce((str, {\n message,\n }) => {\n return str + '; ' + message;\n }, '').slice(2);\n report(`Invalid name: ${msg}`, null, tag);\n continue;\n }\n\n if (tag.tag === 'import') {\n // A named import will look like a type, but not be valid; we also don't\n // need to check the name/namepath\n continue;\n }\n\n if (tag.tag === 'borrows') {\n const thisNamepath = /** @type {string} */ (\n utils.getTagDescription(tag)\n ).replace(asExpression, '')\n .trim();\n\n if (!asExpression.test(/** @type {string} */ (\n utils.getTagDescription(tag)\n )) || !thisNamepath) {\n report(`@borrows must have an \"as\" expression. Found \"${utils.getTagDescription(tag)}\"`, null, tag);\n\n continue;\n }\n\n if (validNamepathParsing(thisNamepath, 'borrows')) {\n const thatNamepath = tag.name;\n\n validNamepathParsing(thatNamepath);\n }\n\n continue;\n }\n\n if (tag.tag === 'suppress' && mode === 'closure') {\n let parsedTypes;\n\n try {\n parsedTypes = tryParse(tag.type);\n } catch {\n // Ignore\n }\n\n if (parsedTypes) {\n traverse(parsedTypes, (node) => {\n let type;\n if ('value' in node && typeof node.value === 'string') {\n type = node.value;\n }\n\n if (type !== undefined && !suppressTypes.has(type)) {\n report(`Syntax error in suppress type: ${type}`, null, tag);\n }\n });\n }\n }\n\n const otherModeMaps = /** @type {import('../jsdocUtils.js').ParserMode[]} */ ([\n 'jsdoc', 'typescript', 'closure', 'permissive',\n ]).filter(\n (mde) => {\n return mde !== mode;\n },\n ).map((mde) => {\n return utils.getTagStructureForMode(mde);\n });\n\n const tagMightHaveNamePosition = utils.tagMightHaveNamePosition(tag.tag, otherModeMaps);\n if (tagMightHaveNamePosition !== true && tag.name) {\n const modeInfo = tagMightHaveNamePosition === false ? '' : ` in \"${mode}\" mode`;\n report(`@${tag.tag} should not have a name${modeInfo}.`, null, tag);\n\n continue;\n }\n\n // Documentation like `@returns {@link SomeType}` is technically ambiguous. Specifically it\n // could either be intepreted as a type `\"@link SomeType\"` or a description `\"{@link SomeType}\"`.\n // However this is a good heuristic.\n if (tag.type.trim().startsWith('@')) {\n tag.description = `{${tag.type}} ${tag.description}`;\n tag.type = '';\n }\n\n const mightHaveTypePosition = utils.tagMightHaveTypePosition(tag.tag, otherModeMaps);\n if (mightHaveTypePosition !== true && tag.type) {\n const modeInfo = mightHaveTypePosition === false ? '' : ` in \"${mode}\" mode`;\n report(`@${tag.tag} should not have a bracketed type${modeInfo}.`, null, tag);\n\n continue;\n }\n\n // REQUIRED NAME\n const tagMustHaveNamePosition = utils.tagMustHaveNamePosition(tag.tag, otherModeMaps);\n\n // Don't handle `@param` here though it does require name as handled by\n // `require-param-name` (`@property` would similarly seem to require one,\n // but is handled by `require-property-name`)\n if (tagMustHaveNamePosition !== false && !tag.name && !allowEmptyNamepaths && ![\n 'arg', 'argument', 'param',\n 'prop', 'property',\n ].includes(tag.tag) &&\n (tag.tag !== 'see' || !utils.getTagDescription(tag).includes('{@link'))\n ) {\n const modeInfo = tagMustHaveNamePosition === true ? '' : ` in \"${mode}\" mode`;\n report(`Tag @${tag.tag} must have a name/namepath${modeInfo}.`, null, tag);\n\n continue;\n }\n\n // REQUIRED TYPE\n const mustHaveTypePosition = utils.tagMustHaveTypePosition(tag.tag, otherModeMaps);\n if (mustHaveTypePosition !== false && !tag.type &&\n // Auto-added to settings and has own rule already, so don't duplicate\n tag.tag !== 'next'\n ) {\n const modeInfo = mustHaveTypePosition === true ? '' : ` in \"${mode}\" mode`;\n report(`Tag @${tag.tag} must have a type${modeInfo}.`, null, tag);\n\n continue;\n }\n\n // REQUIRED TYPE OR NAME/NAMEPATH\n const tagMissingRequiredTypeOrNamepath = utils.tagMissingRequiredTypeOrNamepath(tag, otherModeMaps);\n if (tagMissingRequiredTypeOrNamepath !== false && !allowEmptyNamepaths) {\n const modeInfo = tagMissingRequiredTypeOrNamepath === true ? '' : ` in \"${mode}\" mode`;\n report(`Tag @${tag.tag} must have either a type or namepath${modeInfo}.`, null, tag);\n\n continue;\n }\n\n // VALID TYPE\n const hasTypePosition = mightHaveTypePosition === true && Boolean(tag.type);\n if (hasTypePosition && (tag.type !== 'const' || tag.tag !== 'type')) {\n validTypeParsing(tag.type);\n }\n\n // VALID NAME/NAMEPATH\n const hasNamepathPosition = (\n tagMustHaveNamePosition !== false ||\n utils.tagMightHaveNamepath(tag.tag)\n ) && Boolean(tag.name);\n\n if (hasNamepathPosition) {\n if (mode !== 'jsdoc' && tag.tag === 'template') {\n if (!tryParsePathIgnoreError(tag.name.trim(), mode)) {\n for (const namepath of utils.parseClosureTemplateTag(tag)) {\n validNamepathParsing(namepath);\n }\n }\n } else {\n validNamepathParsing(tag.name, tag.tag);\n }\n }\n\n const hasNamePosition = utils.tagMightHaveName(tag.tag) &&\n Boolean(tag.name);\n if (\n hasNamePosition &&\n mode === 'typescript' &&\n !tryParseNameIgnoreError(tag.name, mode)\n ) {\n report(`Syntax error in name: ${tag.name}`, null, tag);\n } else if (hasNamePosition && mode !== 'typescript') {\n validNamepathParsing(tag.name, tag.tag);\n }\n\n for (const inlineTag of tag.inlineTags) {\n if (inlineTags.has(inlineTag.tag) && !inlineTag.text && !inlineTag.namepathOrURL) {\n report(`Inline tag \"${inlineTag.tag}\" missing content`, null, tag);\n }\n }\n }\n\n for (const inlineTag of jsdoc.inlineTags) {\n if (inlineTags.has(inlineTag.tag) && !inlineTag.text && !inlineTag.namepathOrURL) {\n report(`Inline tag \"${inlineTag.tag}\" missing content`);\n }\n }\n}, {\n iterateAllJsdocs: true,\n meta: {\n docs: {\n description: 'Requires all types/namepaths to be valid JSDoc, Closure compiler, or TypeScript types (configurable in settings).',\n url: 'https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/valid-types.md#repos-sticky-header',\n },\n schema: [\n {\n additionalProperties: false,\n properties: {\n allowEmptyNamepaths: {\n default: false,\n description: `Set to \\`false\\` to bulk disallow\nempty name paths with namepath groups 2 and 4 (these might often be\nexpected to have an accompanying name path, though they have some\nindicative value without one; these may also allow names to be defined\nin another manner elsewhere in the block); you can use\n\\`settings.jsdoc.structuredTags\\` with the \\`required\\` key set to \"name\" if you\nwish to require name paths on a tag-by-tag basis. Defaults to \\`true\\`.`,\n type: 'boolean',\n },\n },\n type: 'object',\n },\n ],\n type: 'suggestion',\n },\n});\n"],"mappings":"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","ignoreList":[]}
package/package.json CHANGED
@@ -179,5 +179,5 @@
179
179
  "test-cov": "TIMING=1 c8 --reporter text pnpm run test-no-cov",
180
180
  "test-index": "pnpm run test-no-cov test/rules/index.js"
181
181
  },
182
- "version": "63.0.8"
182
+ "version": "63.0.10"
183
183
  }
package/src/jsdocUtils.js CHANGED
@@ -1577,6 +1577,42 @@ const isInlineTag = (tag) => {
1577
1577
  };
1578
1578
  */
1579
1579
 
1580
+ /**
1581
+ * Splits a `@template` tag's names on commas that separate template entries,
1582
+ * ignoring commas nested within a type expression so that default values such
1583
+ * as `[T=Record<string, unknown>]` are not split apart.
1584
+ *
1585
+ * Only `<`, `(` and `{` are treated as nesting: a comma within them is part of
1586
+ * a type (generic arguments, function params, object type). Square brackets are
1587
+ * deliberately not counted, since `[...]` is the optional/default wrapper in
1588
+ * which commas do separate entries, e.g. `[T=string, U=number]`.
1589
+ * @param {string} str
1590
+ * @returns {string[]}
1591
+ */
1592
+ const splitTopLevelCommas = (str) => {
1593
+ const parts = [];
1594
+ let depth = 0;
1595
+ let current = '';
1596
+ for (const char of str) {
1597
+ if (char === '<' || char === '{' || char === '(') {
1598
+ depth++;
1599
+ } else if (char === '>' || char === '}' || char === ')') {
1600
+ depth = Math.max(0, depth - 1);
1601
+ }
1602
+
1603
+ if (char === ',' && depth === 0) {
1604
+ parts.push(current);
1605
+ current = '';
1606
+ } else {
1607
+ current += char;
1608
+ }
1609
+ }
1610
+
1611
+ parts.push(current);
1612
+
1613
+ return parts;
1614
+ };
1615
+
1580
1616
  /**
1581
1617
  * Parses GCC Generic/Template types
1582
1618
  * @see {@link https://github.com/google/closure-compiler/wiki/Generic-Types}
@@ -1585,8 +1621,7 @@ const isInlineTag = (tag) => {
1585
1621
  * @returns {string[]}
1586
1622
  */
1587
1623
  const parseClosureTemplateTag = (tag) => {
1588
- return tag.name
1589
- .split(',')
1624
+ return splitTopLevelCommas(tag.name)
1590
1625
  .map((type) => {
1591
1626
  return type.trim().replace(/^\[?(?<name>.*?)=.*$/v, '$<name>');
1592
1627
  });
@@ -31,22 +31,148 @@ export default iterateJsdoc(({
31
31
  const indexes = [];
32
32
 
33
33
  const unescapedInlineTagRegex = /(?:^|\s)@(\w+)/gv;
34
+
35
+ const scopedPackageNameRegex = /^@[\w.\-]+\/[\w.\-]+/v;
36
+
37
+ const declarationReferenceInlineTags = new Set([
38
+ 'inheritDoc',
39
+ 'link',
40
+ 'linkcode',
41
+ 'linkplain',
42
+ ]);
43
+
44
+ /**
45
+ * @param {string} desc
46
+ * @param {number} atSignIndex
47
+ * @returns {string}
48
+ */
49
+ const getInlineTagName = (desc, atSignIndex) => {
50
+ const inlineTagStart = desc.lastIndexOf('{@', atSignIndex);
51
+
52
+ if (inlineTagStart === -1) {
53
+ return '';
54
+ }
55
+
56
+ const inlineTagEnd = desc.indexOf('}', inlineTagStart);
57
+
58
+ if (inlineTagEnd === -1 || inlineTagEnd <= atSignIndex) {
59
+ return '';
60
+ }
61
+
62
+ return desc.slice(inlineTagStart + 2).match(/^\w+/v)?.[0] || '';
63
+ };
64
+
65
+ /**
66
+ * @param {string} desc
67
+ * @param {string} match
68
+ * @param {number} offset
69
+ * @returns {boolean}
70
+ */
71
+ const shouldIgnoreMatch = (desc, match, offset) => {
72
+ const atSignIndex = offset + match.lastIndexOf('@');
73
+ const inlineTagName = getInlineTagName(desc, atSignIndex);
74
+
75
+ return declarationReferenceInlineTags.has(inlineTagName) &&
76
+ scopedPackageNameRegex.test(desc.slice(atSignIndex));
77
+ };
78
+
79
+ /**
80
+ * @param {string} tagName
81
+ * @returns {[
82
+ * RegExp,
83
+ * (description: string) => string
84
+ * ]}
85
+ */
86
+ const escapeInlineTags = (tagName) => {
87
+ const regex = new RegExp(`(^|\\s)@${
88
+ // No need to escape, as contains only safe characters
89
+ tagName
90
+ }`, 'gv');
91
+
92
+ return [
93
+ regex,
94
+ /**
95
+ * @param {string} desc
96
+ */
97
+ (desc) => {
98
+ return desc.replaceAll(
99
+ regex,
100
+ (match, prefix, offset) => {
101
+ if (shouldIgnoreMatch(desc, match, offset)) {
102
+ return match;
103
+ }
104
+
105
+ return fixType === 'backticks' ?
106
+ prefix + '`@' + tagName + '`' :
107
+ prefix + '\\@' + tagName;
108
+ },
109
+ );
110
+ },
111
+ ];
112
+ };
113
+
114
+ /**
115
+ * @param {string} desc
116
+ * @returns {string}
117
+ */
118
+ const getUnescapedInlineTagName = (desc) => {
119
+ unescapedInlineTagRegex.lastIndex = 0;
120
+
121
+ let match;
122
+ while ((match = unescapedInlineTagRegex.exec(desc)) !== null) {
123
+ const [
124
+ fullMatch,
125
+ tagName,
126
+ ] = match;
127
+
128
+ if (
129
+ allowedInlineTags.includes(tagName) ||
130
+ shouldIgnoreMatch(desc, fullMatch, match.index)
131
+ ) {
132
+ continue;
133
+ }
134
+
135
+ return tagName;
136
+ }
137
+
138
+ return '';
139
+ };
140
+
141
+ const normalizedDescription = description.startsWith('\n') ?
142
+ description.slice(1) :
143
+ description;
144
+
145
+ let nextLineStartOffset = 0;
34
146
  for (const [
35
147
  idx,
36
148
  descLine,
37
- ] of (
38
- description.startsWith('\n') ? description.slice(1) : description
39
- ).split('\n').entries()
149
+ ] of normalizedDescription.split('\n').entries()
40
150
  ) {
41
- descLine.replaceAll(unescapedInlineTagRegex, (_, tagName) => {
42
- if (allowedInlineTags.includes(tagName)) {
43
- return _;
151
+ const lineStartOffset = nextLineStartOffset;
152
+
153
+ // +1 for the `\n` removed by split.
154
+ nextLineStartOffset += descLine.length + 1;
155
+
156
+ descLine.replaceAll(unescapedInlineTagRegex, (match, tagName, offset) => {
157
+ if (
158
+ allowedInlineTags.includes(tagName) ||
159
+ // Run ignore-detection against the full description text so that
160
+ // multi-line inline tags (e.g. `{@link` on one line and
161
+ // `@scope/pkg#Member}` on the next) are recognized as being inside an
162
+ // inline tag rather than scanned per-line.
163
+ shouldIgnoreMatch(
164
+ normalizedDescription,
165
+ match,
166
+ lineStartOffset + offset,
167
+ )
168
+ ) {
169
+ return match;
44
170
  }
45
171
 
46
172
  tagNames.push(tagName);
47
173
  indexes.push(idx);
48
174
 
49
- return _;
175
+ return match;
50
176
  });
51
177
  }
52
178
 
@@ -61,15 +187,16 @@ export default iterateJsdoc(({
61
187
  },
62
188
  enableFixer ?
63
189
  () => {
190
+ // `tagName` and `fixType` are constant here, so compute the escaper
191
+ // once rather than rebuilding the RegExp + closure for every line.
192
+ const [
193
+ ,
194
+ escapeInlineTag,
195
+ ] = escapeInlineTags(tagName);
196
+
64
197
  utils.setBlockDescription((info, seedTokens, descLines) => {
65
198
  return descLines.map((desc) => {
66
- const newDesc = desc.replaceAll(
67
- new RegExp(`(^|\\s)@${
68
- // No need to escape, as contains only safe characters
69
- tagName
70
- }`, 'gv'),
71
- fixType === 'backticks' ? '$1`@' + tagName + '`' : '$1\\@' + tagName,
72
- );
199
+ const newDesc = escapeInlineTag(desc);
73
200
 
74
201
  return {
75
202
  number: 0,
@@ -87,33 +214,6 @@ export default iterateJsdoc(({
87
214
  );
88
215
  }
89
216
 
90
- /**
91
- * @param {string} tagName
92
- * @returns {[
93
- * RegExp,
94
- * (description: string) => string
95
- * ]}
96
- */
97
- const escapeInlineTags = (tagName) => {
98
- const regex = new RegExp(`(^|\\s)@${
99
- // No need to escape, as contains only safe characters
100
- tagName
101
- }`, 'gv');
102
-
103
- return [
104
- regex,
105
- /**
106
- * @param {string} desc
107
- */
108
- (desc) => {
109
- return desc.replaceAll(
110
- regex,
111
- fixType === 'backticks' ? '$1`@' + tagName + '`' : '$1\\@' + tagName,
112
- );
113
- },
114
- ];
115
- };
116
-
117
217
  for (const tag of jsdoc.tags) {
118
218
  if (tag.tag === 'example') {
119
219
  continue;
@@ -125,10 +225,7 @@ export default iterateJsdoc(({
125
225
  utils.getTagDescription(tag, true)
126
226
  // eslint-disable-next-line no-loop-func -- Safe
127
227
  ).some((desc) => {
128
- tagName = unescapedInlineTagRegex.exec(desc)?.[1] ?? '';
129
- if (allowedInlineTags.includes(tagName)) {
130
- return false;
131
- }
228
+ tagName = getUnescapedInlineTagName(desc);
132
229
 
133
230
  return tagName;
134
231
  })) {