eslint-plugin-jsdoc 61.4.0 → 61.4.1

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.
@@ -11,6 +11,27 @@ var _commentParser = require("comment-parser");
11
11
  * It contains some customizations to align based on the tags, and some custom options.
12
12
  */
13
13
 
14
+ /**
15
+ * Detects if a line starts with a markdown list marker
16
+ * Supports: -, *, numbered lists (1., 2., etc.)
17
+ * This explicitly excludes hyphens that are part of JSDoc tag syntax
18
+ * @param {string} text - The text to check
19
+ * @param {boolean} isFirstLineOfTag - True if this is the first line (tag line)
20
+ * @returns {boolean} - True if the text starts with a list marker
21
+ */
22
+ const startsWithListMarker = (text, isFirstLineOfTag = false) => {
23
+ // On the first line of a tag, the hyphen is typically the JSDoc separator,
24
+ // not a list marker
25
+ if (isFirstLineOfTag) {
26
+ return false;
27
+ }
28
+
29
+ // Match lines that start with optional whitespace, then a list marker
30
+ // - or * followed by a space
31
+ // or a number followed by . or ) and a space
32
+ return /^\s*(?:[\-*]|\d+(?:\.|\)))\s+/v.test(text);
33
+ };
34
+
14
35
  /**
15
36
  * @typedef {{
16
37
  * hasNoTypes: boolean,
@@ -139,6 +160,54 @@ const space = len => {
139
160
  return ''.padStart(len, ' ');
140
161
  };
141
162
 
163
+ /**
164
+ * Check if a tag or any of its lines contain list markers
165
+ * @param {import('./iterateJsdoc.js').Integer} index - Current line index
166
+ * @param {import('comment-parser').Line[]} source - All source lines
167
+ * @returns {{hasListMarker: boolean, tagStartIndex: import('./iterateJsdoc.js').Integer}}
168
+ */
169
+ const checkForListMarkers = (index, source) => {
170
+ let hasListMarker = false;
171
+ let tagStartIndex = index;
172
+ while (tagStartIndex > 0 && source[tagStartIndex].tokens.tag === '') {
173
+ tagStartIndex--;
174
+ }
175
+ for (let idx = tagStartIndex; idx <= index; idx++) {
176
+ const isFirstLine = idx === tagStartIndex;
177
+ if (source[idx]?.tokens?.description && startsWithListMarker(source[idx].tokens.description, isFirstLine)) {
178
+ hasListMarker = true;
179
+ break;
180
+ }
181
+ }
182
+ return {
183
+ hasListMarker,
184
+ tagStartIndex
185
+ };
186
+ };
187
+
188
+ /**
189
+ * Calculate extra indentation for list items relative to the first continuation line
190
+ * @param {import('./iterateJsdoc.js').Integer} index - Current line index
191
+ * @param {import('./iterateJsdoc.js').Integer} tagStartIndex - Index of the tag line
192
+ * @param {import('comment-parser').Line[]} source - All source lines
193
+ * @returns {string} - Extra indentation spaces
194
+ */
195
+ const calculateListExtraIndent = (index, tagStartIndex, source) => {
196
+ // Find the first continuation line to use as baseline
197
+ let firstContinuationIndent = null;
198
+ for (let idx = tagStartIndex + 1; idx < source.length; idx++) {
199
+ if (source[idx].tokens.description && !source[idx].tokens.tag) {
200
+ firstContinuationIndent = source[idx].tokens.postDelimiter.length;
201
+ break;
202
+ }
203
+ }
204
+
205
+ // Calculate the extra indentation of current line relative to the first continuation line
206
+ const currentOriginalIndent = source[index].tokens.postDelimiter.length;
207
+ const extraIndent = firstContinuationIndent !== null && currentOriginalIndent > firstContinuationIndent ? ' '.repeat(currentOriginalIndent - firstContinuationIndent) : '';
208
+ return extraIndent;
209
+ };
210
+
142
211
  /**
143
212
  * @param {{
144
213
  * customSpacings: import('../src/rules/checkLineAlignment.js').CustomSpacings,
@@ -288,7 +357,17 @@ const alignTransform = ({
288
357
  if (shouldAlign(tags, index, source)) {
289
358
  alignTokens(tokens, typelessInfo);
290
359
  if (!disableWrapIndent && indentTag) {
291
- tokens.postDelimiter += wrapIndent;
360
+ const {
361
+ hasListMarker,
362
+ tagStartIndex
363
+ } = checkForListMarkers(index, source);
364
+ if (hasListMarker && index > tagStartIndex) {
365
+ const extraIndent = calculateListExtraIndent(index, tagStartIndex, source);
366
+ tokens.postDelimiter += wrapIndent + extraIndent;
367
+ } else {
368
+ // Normal case: add wrapIndent after the aligned delimiter
369
+ tokens.postDelimiter += wrapIndent;
370
+ }
292
371
  }
293
372
  }
294
373
  return {
@@ -1 +1 @@
1
- {"version":3,"file":"alignTransform.cjs","names":["_commentParser","require","rewireSource","util","zeroWidth","name","start","tag","type","shouldAlign","tags","index","source","tokens","replace","includesTag","includes","iterator","previousTag","getWidth","width","Math","max","length","delimiter","getTypelessInfo","fields","hasNoTypes","every","maxNamedTagLength","map","filter","maxUnnamedTagLength","space","len","padStart","alignTransform","customSpacings","disableWrapIndent","indent","preserveMainDescriptionPostDelimiter","wrapIndent","intoTags","alignTokens","typelessInfo","nothingAfter","delim","description","postName","postType","postTag","untypedNameAdjustment","untypedTypeAdjustment","spacings","postDelimiter","update","line","indentTag","isEmpty","end","postHyphenSpacing","postHyphen","hyphenSpacing","reduce","tagIndentMode","ret","_default","exports","default","module"],"sources":["../src/alignTransform.js"],"sourcesContent":["/**\n * Transform based on https://github.com/syavorsky/comment-parser/blob/master/src/transforms/align.ts\n *\n * It contains some customizations to align based on the tags, and some custom options.\n */\n\nimport {\n // `comment-parser/primitives` export\n util,\n} from 'comment-parser';\n\n/**\n * @typedef {{\n * hasNoTypes: boolean,\n * maxNamedTagLength: import('./iterateJsdoc.js').Integer,\n * maxUnnamedTagLength: import('./iterateJsdoc.js').Integer\n * }} TypelessInfo\n */\n\nconst {\n rewireSource,\n} = util;\n\n/**\n * @typedef {{\n * name: import('./iterateJsdoc.js').Integer,\n * start: import('./iterateJsdoc.js').Integer,\n * tag: import('./iterateJsdoc.js').Integer,\n * type: import('./iterateJsdoc.js').Integer\n * }} Width\n */\n\n/** @type {Width} */\nconst zeroWidth = {\n name: 0,\n start: 0,\n tag: 0,\n type: 0,\n};\n\n/**\n * @param {string[]} tags\n * @param {import('./iterateJsdoc.js').Integer} index\n * @param {import('comment-parser').Line[]} source\n * @returns {boolean}\n */\nconst shouldAlign = (tags, index, source) => {\n const tag = source[index].tokens.tag.replace('@', '');\n const includesTag = tags.includes(tag);\n\n if (includesTag) {\n return true;\n }\n\n if (tag !== '') {\n return false;\n }\n\n for (let iterator = index; iterator >= 0; iterator--) {\n const previousTag = source[iterator].tokens.tag.replace('@', '');\n\n if (previousTag !== '') {\n if (tags.includes(previousTag)) {\n return true;\n }\n\n return false;\n }\n }\n\n return true;\n};\n\n/**\n * @param {string[]} tags\n * @returns {(\n * width: Width,\n * line: {\n * tokens: import('comment-parser').Tokens\n * },\n * index: import('./iterateJsdoc.js').Integer,\n * source: import('comment-parser').Line[]\n * ) => Width}\n */\nconst getWidth = (tags) => {\n return (width, {\n tokens,\n }, index, source) => {\n if (!shouldAlign(tags, index, source)) {\n return width;\n }\n\n return {\n name: Math.max(width.name, tokens.name.length),\n start: tokens.delimiter === '/**' ? tokens.start.length : width.start,\n tag: Math.max(width.tag, tokens.tag.length),\n type: Math.max(width.type, tokens.type.length),\n };\n };\n};\n\n/**\n * @param {{\n * description: string;\n * tags: import('comment-parser').Spec[];\n * problems: import('comment-parser').Problem[];\n * }} fields\n * @returns {TypelessInfo}\n */\nconst getTypelessInfo = (fields) => {\n const hasNoTypes = fields.tags.every(({\n type,\n }) => {\n return !type;\n });\n const maxNamedTagLength = Math.max(...fields.tags.map(({\n name,\n tag,\n }) => {\n return name.length === 0 ? -1 : tag.length;\n }).filter((length) => {\n return length !== -1;\n })) + 1;\n const maxUnnamedTagLength = Math.max(...fields.tags.map(({\n name,\n tag,\n }) => {\n return name.length === 0 ? tag.length : -1;\n }).filter((length) => {\n return length !== -1;\n })) + 1;\n return {\n hasNoTypes,\n maxNamedTagLength,\n maxUnnamedTagLength,\n };\n};\n\n/**\n * @param {import('./iterateJsdoc.js').Integer} len\n * @returns {string}\n */\nconst space = (len) => {\n return ''.padStart(len, ' ');\n};\n\n/**\n * @param {{\n * customSpacings: import('../src/rules/checkLineAlignment.js').CustomSpacings,\n * tags: string[],\n * indent: string,\n * preserveMainDescriptionPostDelimiter: boolean,\n * wrapIndent: string,\n * disableWrapIndent: boolean,\n * }} cfg\n * @returns {(\n * block: import('comment-parser').Block\n * ) => import('comment-parser').Block}\n */\nconst alignTransform = ({\n customSpacings,\n disableWrapIndent,\n indent,\n preserveMainDescriptionPostDelimiter,\n tags,\n wrapIndent,\n}) => {\n let intoTags = false;\n /** @type {Width} */\n let width;\n\n /**\n * @param {import('comment-parser').Tokens} tokens\n * @param {TypelessInfo} typelessInfo\n * @returns {import('comment-parser').Tokens}\n */\n const alignTokens = (tokens, typelessInfo) => {\n const nothingAfter = {\n delim: false,\n name: false,\n tag: false,\n type: false,\n };\n\n if (tokens.description === '') {\n nothingAfter.name = true;\n tokens.postName = '';\n\n if (tokens.name === '') {\n nothingAfter.type = true;\n tokens.postType = '';\n\n if (tokens.type === '') {\n nothingAfter.tag = true;\n tokens.postTag = '';\n\n /* c8 ignore next: Never happens because the !intoTags return. But it's here for consistency with the original align transform */\n if (tokens.tag === '') {\n nothingAfter.delim = true;\n }\n }\n }\n }\n\n let untypedNameAdjustment = 0;\n let untypedTypeAdjustment = 0;\n if (typelessInfo.hasNoTypes) {\n nothingAfter.tag = true;\n tokens.postTag = '';\n if (tokens.name === '') {\n untypedNameAdjustment = typelessInfo.maxNamedTagLength - tokens.tag.length;\n } else {\n untypedNameAdjustment = typelessInfo.maxNamedTagLength > typelessInfo.maxUnnamedTagLength ? 0 :\n Math.max(0, typelessInfo.maxUnnamedTagLength - (tokens.tag.length + tokens.name.length + 1));\n untypedTypeAdjustment = typelessInfo.maxNamedTagLength - tokens.tag.length;\n }\n }\n\n // Todo: Avoid fixing alignment of blocks with multiline wrapping of type\n if (tokens.tag === '' && tokens.type) {\n return tokens;\n }\n\n const spacings = {\n postDelimiter: customSpacings?.postDelimiter || 1,\n postName: customSpacings?.postName || 1,\n postTag: customSpacings?.postTag || 1,\n postType: customSpacings?.postType || 1,\n };\n\n tokens.postDelimiter = nothingAfter.delim ? '' : space(spacings.postDelimiter);\n\n if (!nothingAfter.tag) {\n tokens.postTag = space(width.tag - tokens.tag.length + spacings.postTag);\n }\n\n if (!nothingAfter.type) {\n tokens.postType = space(width.type - tokens.type.length + spacings.postType + untypedTypeAdjustment);\n }\n\n if (!nothingAfter.name) {\n // If post name is empty for all lines (name width 0), don't add post name spacing.\n tokens.postName = width.name === 0 ? '' : space(width.name - tokens.name.length + spacings.postName + untypedNameAdjustment);\n }\n\n return tokens;\n };\n\n /**\n * @param {import('comment-parser').Line} line\n * @param {import('./iterateJsdoc.js').Integer} index\n * @param {import('comment-parser').Line[]} source\n * @param {TypelessInfo} typelessInfo\n * @param {string|false} indentTag\n * @returns {import('comment-parser').Line}\n */\n const update = (line, index, source, typelessInfo, indentTag) => {\n /** @type {import('comment-parser').Tokens} */\n const tokens = {\n ...line.tokens,\n };\n\n if (tokens.tag !== '') {\n intoTags = true;\n }\n\n const isEmpty =\n tokens.tag === '' &&\n tokens.name === '' &&\n tokens.type === '' &&\n tokens.description === '';\n\n // dangling '*/'\n if (tokens.end === '*/' && isEmpty) {\n tokens.start = indent + ' ';\n\n return {\n ...line,\n tokens,\n };\n }\n\n switch (tokens.delimiter) {\n case '*':\n tokens.start = indent + ' ';\n break;\n case '/**':\n tokens.start = indent;\n break;\n default:\n tokens.delimiter = '';\n\n // compensate delimiter\n tokens.start = indent + ' ';\n }\n\n if (!intoTags) {\n if (tokens.description === '') {\n tokens.postDelimiter = '';\n } else if (!preserveMainDescriptionPostDelimiter) {\n tokens.postDelimiter = ' ';\n }\n\n return {\n ...line,\n tokens,\n };\n }\n\n const postHyphenSpacing = customSpacings?.postHyphen ?? 1;\n const hyphenSpacing = /^\\s*-\\s+/v;\n tokens.description = tokens.description.replace(\n hyphenSpacing, '-' + ''.padStart(postHyphenSpacing, ' '),\n );\n\n // Not align.\n if (shouldAlign(tags, index, source)) {\n alignTokens(tokens, typelessInfo);\n if (!disableWrapIndent && indentTag) {\n tokens.postDelimiter += wrapIndent;\n }\n }\n\n return {\n ...line,\n tokens,\n };\n };\n\n return ({\n source,\n ...fields\n }) => {\n width = source.reduce(getWidth(tags), {\n ...zeroWidth,\n });\n\n const typelessInfo = getTypelessInfo(fields);\n\n let tagIndentMode = false;\n\n return rewireSource({\n ...fields,\n source: source.map((line, index) => {\n const indentTag = !disableWrapIndent && tagIndentMode && !line.tokens.tag && line.tokens.description;\n const ret = update(line, index, source, typelessInfo, indentTag);\n\n if (!disableWrapIndent && line.tokens.tag) {\n tagIndentMode = true;\n }\n\n return ret;\n }),\n });\n };\n};\n\nexport default alignTransform;\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"file":"alignTransform.cjs","names":["_commentParser","require","startsWithListMarker","text","isFirstLineOfTag","test","rewireSource","util","zeroWidth","name","start","tag","type","shouldAlign","tags","index","source","tokens","replace","includesTag","includes","iterator","previousTag","getWidth","width","Math","max","length","delimiter","getTypelessInfo","fields","hasNoTypes","every","maxNamedTagLength","map","filter","maxUnnamedTagLength","space","len","padStart","checkForListMarkers","hasListMarker","tagStartIndex","idx","isFirstLine","description","calculateListExtraIndent","firstContinuationIndent","postDelimiter","currentOriginalIndent","extraIndent","repeat","alignTransform","customSpacings","disableWrapIndent","indent","preserveMainDescriptionPostDelimiter","wrapIndent","intoTags","alignTokens","typelessInfo","nothingAfter","delim","postName","postType","postTag","untypedNameAdjustment","untypedTypeAdjustment","spacings","update","line","indentTag","isEmpty","end","postHyphenSpacing","postHyphen","hyphenSpacing","reduce","tagIndentMode","ret","_default","exports","default","module"],"sources":["../src/alignTransform.js"],"sourcesContent":["/**\n * Transform based on https://github.com/syavorsky/comment-parser/blob/master/src/transforms/align.ts\n *\n * It contains some customizations to align based on the tags, and some custom options.\n */\n\nimport {\n // `comment-parser/primitives` export\n util,\n} from 'comment-parser';\n\n/**\n * Detects if a line starts with a markdown list marker\n * Supports: -, *, numbered lists (1., 2., etc.)\n * This explicitly excludes hyphens that are part of JSDoc tag syntax\n * @param {string} text - The text to check\n * @param {boolean} isFirstLineOfTag - True if this is the first line (tag line)\n * @returns {boolean} - True if the text starts with a list marker\n */\nconst startsWithListMarker = (text, isFirstLineOfTag = false) => {\n // On the first line of a tag, the hyphen is typically the JSDoc separator,\n // not a list marker\n if (isFirstLineOfTag) {\n return false;\n }\n\n // Match lines that start with optional whitespace, then a list marker\n // - or * followed by a space\n // or a number followed by . or ) and a space\n return /^\\s*(?:[\\-*]|\\d+(?:\\.|\\)))\\s+/v.test(text);\n};\n\n/**\n * @typedef {{\n * hasNoTypes: boolean,\n * maxNamedTagLength: import('./iterateJsdoc.js').Integer,\n * maxUnnamedTagLength: import('./iterateJsdoc.js').Integer\n * }} TypelessInfo\n */\n\nconst {\n rewireSource,\n} = util;\n\n/**\n * @typedef {{\n * name: import('./iterateJsdoc.js').Integer,\n * start: import('./iterateJsdoc.js').Integer,\n * tag: import('./iterateJsdoc.js').Integer,\n * type: import('./iterateJsdoc.js').Integer\n * }} Width\n */\n\n/** @type {Width} */\nconst zeroWidth = {\n name: 0,\n start: 0,\n tag: 0,\n type: 0,\n};\n\n/**\n * @param {string[]} tags\n * @param {import('./iterateJsdoc.js').Integer} index\n * @param {import('comment-parser').Line[]} source\n * @returns {boolean}\n */\nconst shouldAlign = (tags, index, source) => {\n const tag = source[index].tokens.tag.replace('@', '');\n const includesTag = tags.includes(tag);\n\n if (includesTag) {\n return true;\n }\n\n if (tag !== '') {\n return false;\n }\n\n for (let iterator = index; iterator >= 0; iterator--) {\n const previousTag = source[iterator].tokens.tag.replace('@', '');\n\n if (previousTag !== '') {\n if (tags.includes(previousTag)) {\n return true;\n }\n\n return false;\n }\n }\n\n return true;\n};\n\n/**\n * @param {string[]} tags\n * @returns {(\n * width: Width,\n * line: {\n * tokens: import('comment-parser').Tokens\n * },\n * index: import('./iterateJsdoc.js').Integer,\n * source: import('comment-parser').Line[]\n * ) => Width}\n */\nconst getWidth = (tags) => {\n return (width, {\n tokens,\n }, index, source) => {\n if (!shouldAlign(tags, index, source)) {\n return width;\n }\n\n return {\n name: Math.max(width.name, tokens.name.length),\n start: tokens.delimiter === '/**' ? tokens.start.length : width.start,\n tag: Math.max(width.tag, tokens.tag.length),\n type: Math.max(width.type, tokens.type.length),\n };\n };\n};\n\n/**\n * @param {{\n * description: string;\n * tags: import('comment-parser').Spec[];\n * problems: import('comment-parser').Problem[];\n * }} fields\n * @returns {TypelessInfo}\n */\nconst getTypelessInfo = (fields) => {\n const hasNoTypes = fields.tags.every(({\n type,\n }) => {\n return !type;\n });\n const maxNamedTagLength = Math.max(...fields.tags.map(({\n name,\n tag,\n }) => {\n return name.length === 0 ? -1 : tag.length;\n }).filter((length) => {\n return length !== -1;\n })) + 1;\n const maxUnnamedTagLength = Math.max(...fields.tags.map(({\n name,\n tag,\n }) => {\n return name.length === 0 ? tag.length : -1;\n }).filter((length) => {\n return length !== -1;\n })) + 1;\n return {\n hasNoTypes,\n maxNamedTagLength,\n maxUnnamedTagLength,\n };\n};\n\n/**\n * @param {import('./iterateJsdoc.js').Integer} len\n * @returns {string}\n */\nconst space = (len) => {\n return ''.padStart(len, ' ');\n};\n\n/**\n * Check if a tag or any of its lines contain list markers\n * @param {import('./iterateJsdoc.js').Integer} index - Current line index\n * @param {import('comment-parser').Line[]} source - All source lines\n * @returns {{hasListMarker: boolean, tagStartIndex: import('./iterateJsdoc.js').Integer}}\n */\nconst checkForListMarkers = (index, source) => {\n let hasListMarker = false;\n let tagStartIndex = index;\n while (tagStartIndex > 0 && source[tagStartIndex].tokens.tag === '') {\n tagStartIndex--;\n }\n\n for (let idx = tagStartIndex; idx <= index; idx++) {\n const isFirstLine = (idx === tagStartIndex);\n if (source[idx]?.tokens?.description && startsWithListMarker(source[idx].tokens.description, isFirstLine)) {\n hasListMarker = true;\n break;\n }\n }\n\n return {\n hasListMarker,\n tagStartIndex,\n };\n};\n\n/**\n * Calculate extra indentation for list items relative to the first continuation line\n * @param {import('./iterateJsdoc.js').Integer} index - Current line index\n * @param {import('./iterateJsdoc.js').Integer} tagStartIndex - Index of the tag line\n * @param {import('comment-parser').Line[]} source - All source lines\n * @returns {string} - Extra indentation spaces\n */\nconst calculateListExtraIndent = (index, tagStartIndex, source) => {\n // Find the first continuation line to use as baseline\n let firstContinuationIndent = null;\n for (let idx = tagStartIndex + 1; idx < source.length; idx++) {\n if (source[idx].tokens.description && !source[idx].tokens.tag) {\n firstContinuationIndent = source[idx].tokens.postDelimiter.length;\n break;\n }\n }\n\n // Calculate the extra indentation of current line relative to the first continuation line\n const currentOriginalIndent = source[index].tokens.postDelimiter.length;\n const extraIndent = firstContinuationIndent !== null && currentOriginalIndent > firstContinuationIndent ?\n ' '.repeat(currentOriginalIndent - firstContinuationIndent) :\n '';\n\n return extraIndent;\n};\n\n/**\n * @param {{\n * customSpacings: import('../src/rules/checkLineAlignment.js').CustomSpacings,\n * tags: string[],\n * indent: string,\n * preserveMainDescriptionPostDelimiter: boolean,\n * wrapIndent: string,\n * disableWrapIndent: boolean,\n * }} cfg\n * @returns {(\n * block: import('comment-parser').Block\n * ) => import('comment-parser').Block}\n */\nconst alignTransform = ({\n customSpacings,\n disableWrapIndent,\n indent,\n preserveMainDescriptionPostDelimiter,\n tags,\n wrapIndent,\n}) => {\n let intoTags = false;\n /** @type {Width} */\n let width;\n\n /**\n * @param {import('comment-parser').Tokens} tokens\n * @param {TypelessInfo} typelessInfo\n * @returns {import('comment-parser').Tokens}\n */\n const alignTokens = (tokens, typelessInfo) => {\n const nothingAfter = {\n delim: false,\n name: false,\n tag: false,\n type: false,\n };\n\n if (tokens.description === '') {\n nothingAfter.name = true;\n tokens.postName = '';\n\n if (tokens.name === '') {\n nothingAfter.type = true;\n tokens.postType = '';\n\n if (tokens.type === '') {\n nothingAfter.tag = true;\n tokens.postTag = '';\n\n /* c8 ignore next: Never happens because the !intoTags return. But it's here for consistency with the original align transform */\n if (tokens.tag === '') {\n nothingAfter.delim = true;\n }\n }\n }\n }\n\n let untypedNameAdjustment = 0;\n let untypedTypeAdjustment = 0;\n if (typelessInfo.hasNoTypes) {\n nothingAfter.tag = true;\n tokens.postTag = '';\n if (tokens.name === '') {\n untypedNameAdjustment = typelessInfo.maxNamedTagLength - tokens.tag.length;\n } else {\n untypedNameAdjustment = typelessInfo.maxNamedTagLength > typelessInfo.maxUnnamedTagLength ? 0 :\n Math.max(0, typelessInfo.maxUnnamedTagLength - (tokens.tag.length + tokens.name.length + 1));\n untypedTypeAdjustment = typelessInfo.maxNamedTagLength - tokens.tag.length;\n }\n }\n\n // Todo: Avoid fixing alignment of blocks with multiline wrapping of type\n if (tokens.tag === '' && tokens.type) {\n return tokens;\n }\n\n const spacings = {\n postDelimiter: customSpacings?.postDelimiter || 1,\n postName: customSpacings?.postName || 1,\n postTag: customSpacings?.postTag || 1,\n postType: customSpacings?.postType || 1,\n };\n\n tokens.postDelimiter = nothingAfter.delim ? '' : space(spacings.postDelimiter);\n\n if (!nothingAfter.tag) {\n tokens.postTag = space(width.tag - tokens.tag.length + spacings.postTag);\n }\n\n if (!nothingAfter.type) {\n tokens.postType = space(width.type - tokens.type.length + spacings.postType + untypedTypeAdjustment);\n }\n\n if (!nothingAfter.name) {\n // If post name is empty for all lines (name width 0), don't add post name spacing.\n tokens.postName = width.name === 0 ? '' : space(width.name - tokens.name.length + spacings.postName + untypedNameAdjustment);\n }\n\n return tokens;\n };\n\n /**\n * @param {import('comment-parser').Line} line\n * @param {import('./iterateJsdoc.js').Integer} index\n * @param {import('comment-parser').Line[]} source\n * @param {TypelessInfo} typelessInfo\n * @param {string|false} indentTag\n * @returns {import('comment-parser').Line}\n */\n const update = (line, index, source, typelessInfo, indentTag) => {\n /** @type {import('comment-parser').Tokens} */\n const tokens = {\n ...line.tokens,\n };\n\n if (tokens.tag !== '') {\n intoTags = true;\n }\n\n const isEmpty =\n tokens.tag === '' &&\n tokens.name === '' &&\n tokens.type === '' &&\n tokens.description === '';\n\n // dangling '*/'\n if (tokens.end === '*/' && isEmpty) {\n tokens.start = indent + ' ';\n\n return {\n ...line,\n tokens,\n };\n }\n\n switch (tokens.delimiter) {\n case '*':\n tokens.start = indent + ' ';\n break;\n case '/**':\n tokens.start = indent;\n break;\n default:\n tokens.delimiter = '';\n\n // compensate delimiter\n tokens.start = indent + ' ';\n }\n\n if (!intoTags) {\n if (tokens.description === '') {\n tokens.postDelimiter = '';\n } else if (!preserveMainDescriptionPostDelimiter) {\n tokens.postDelimiter = ' ';\n }\n\n return {\n ...line,\n tokens,\n };\n }\n\n const postHyphenSpacing = customSpacings?.postHyphen ?? 1;\n const hyphenSpacing = /^\\s*-\\s+/v;\n tokens.description = tokens.description.replace(\n hyphenSpacing, '-' + ''.padStart(postHyphenSpacing, ' '),\n );\n\n // Not align.\n if (shouldAlign(tags, index, source)) {\n alignTokens(tokens, typelessInfo);\n\n if (!disableWrapIndent && indentTag) {\n const {\n hasListMarker,\n tagStartIndex,\n } = checkForListMarkers(index, source);\n\n if (hasListMarker && index > tagStartIndex) {\n const extraIndent = calculateListExtraIndent(index, tagStartIndex, source);\n tokens.postDelimiter += wrapIndent + extraIndent;\n } else {\n // Normal case: add wrapIndent after the aligned delimiter\n tokens.postDelimiter += wrapIndent;\n }\n }\n }\n\n return {\n ...line,\n tokens,\n };\n };\n\n return ({\n source,\n ...fields\n }) => {\n width = source.reduce(getWidth(tags), {\n ...zeroWidth,\n });\n\n const typelessInfo = getTypelessInfo(fields);\n\n let tagIndentMode = false;\n\n return rewireSource({\n ...fields,\n source: source.map((line, index) => {\n const indentTag = !disableWrapIndent && tagIndentMode && !line.tokens.tag && line.tokens.description;\n const ret = update(line, index, source, typelessInfo, indentTag);\n\n if (!disableWrapIndent && line.tokens.tag) {\n tagIndentMode = true;\n }\n\n return ret;\n }),\n });\n };\n};\n\nexport default alignTransform;\n"],"mappings":"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","ignoreList":[]}
@@ -12,6 +12,53 @@ const {
12
12
  flow: commentFlow
13
13
  } = _commentParser.transforms;
14
14
 
15
+ /**
16
+ * Detects if a line starts with a markdown list marker
17
+ * Supports: -, *, numbered lists (1., 2., etc.)
18
+ * This explicitly excludes hyphens that are part of JSDoc tag syntax
19
+ * @param {string} text - The text to check
20
+ * @param {boolean} isFirstLineOfTag - True if this is the first line (tag line)
21
+ * @returns {boolean} - True if the text starts with a list marker
22
+ */
23
+ const startsWithListMarker = (text, isFirstLineOfTag = false) => {
24
+ // On the first line of a tag, the hyphen is typically the JSDoc separator,
25
+ // not a list marker
26
+ if (isFirstLineOfTag) {
27
+ return false;
28
+ }
29
+
30
+ // Match lines that start with optional whitespace, then a list marker
31
+ // - or * followed by a space
32
+ // or a number followed by . or ) and a space
33
+ return /^\s*(?:[\-*]|\d+(?:\.|\)))\s+/v.test(text);
34
+ };
35
+
36
+ /**
37
+ * Checks if we should allow extra indentation beyond wrapIndent.
38
+ * This is true for list continuation lines (lines with more indent than wrapIndent
39
+ * that follow a list item).
40
+ * @param {import('comment-parser').Spec} tag - The tag being checked
41
+ * @param {import('../iterateJsdoc.js').Integer} idx - Current line index (0-based in tag.source.slice(1))
42
+ * @returns {boolean} - True if extra indentation should be allowed
43
+ */
44
+ const shouldAllowExtraIndent = (tag, idx) => {
45
+ // Check if any previous line in this tag had a list marker
46
+ // idx is 0-based in the continuation lines (tag.source.slice(1))
47
+ // So tag.source[0] is the tag line, tag.source[idx+1] is current line
48
+ let hasSeenListMarker = false;
49
+
50
+ // Check all lines from the tag line onwards
51
+ for (let lineIdx = 0; lineIdx <= idx + 1; lineIdx++) {
52
+ const line = tag.source[lineIdx];
53
+ const isFirstLine = lineIdx === 0;
54
+ if (line?.tokens?.description && startsWithListMarker(line.tokens.description, isFirstLine)) {
55
+ hasSeenListMarker = true;
56
+ break;
57
+ }
58
+ }
59
+ return hasSeenListMarker;
60
+ };
61
+
15
62
  /**
16
63
  * @typedef {{
17
64
  * postDelimiter: import('../iterateJsdoc.js').Integer,
@@ -250,7 +297,14 @@ var _default = exports.default = (0, _iterateJsdoc.default)(({
250
297
  }
251
298
 
252
299
  // Don't include a single separating space/tab
253
- if (!disableWrapIndent && tokens.postDelimiter.slice(1) !== wrapIndent) {
300
+ const actualIndent = tokens.postDelimiter.slice(1);
301
+ const hasCorrectWrapIndent = actualIndent === wrapIndent;
302
+
303
+ // Allow extra indentation if this line or previous lines contain list markers
304
+ // This preserves nested list structure
305
+ const hasExtraIndent = actualIndent.length > wrapIndent.length && actualIndent.startsWith(wrapIndent);
306
+ const isInListContext = shouldAllowExtraIndent(tag, idx - 1);
307
+ if (!disableWrapIndent && !hasCorrectWrapIndent && !(hasExtraIndent && isInListContext)) {
254
308
  utils.reportJSDoc('Expected wrap indent', {
255
309
  line: tag.source[0].number + idx
256
310
  }, () => {
@@ -1 +1 @@
1
- {"version":3,"file":"checkLineAlignment.cjs","names":["_alignTransform","_interopRequireDefault","require","_iterateJsdoc","_commentParser","e","__esModule","default","flow","commentFlow","transforms","checkNotAlignedPerTag","utils","tag","customSpacings","spacerProps","contentProps","mightHaveNamepath","tagMightHaveNameOrNamepath","tokens","source","followedBySpace","idx","callbck","nextIndex","slice","some","spacerProp","innerIdx","contentProp","spacePropVal","ret","postHyphenSpacing","postHyphen","exactHyphenSpacing","RegExp","hasNoHyphen","test","description","hasExactHyphenSpacing","ok","contentPropVal","spacerPropVal","spacing","length","fix","entries","padStart","hasSpace","contentPrp","hyphenSpacing","replace","setTag","reportJSDoc","checkAlignment","disableWrapIndent","indent","jsdoc","jsdocNode","preserveMainDescriptionPostDelimiter","report","tags","wrapIndent","transform","alignTransform","transformedJsdoc","comment","value","formatted","stringify","trimStart","fixer","replaceText","_default","exports","iterateJsdoc","context","applicableTags","options","includes","foundTags","getPresentTags","type","name","postDelimiter","line","number","charAt","iterateAllJsdocs","meta","docs","url","fixable","schema","enum","additionalProperties","properties","postName","postTag","postType","items","module"],"sources":["../../src/rules/checkLineAlignment.js"],"sourcesContent":["import alignTransform from '../alignTransform.js';\nimport iterateJsdoc from '../iterateJsdoc.js';\nimport {\n transforms,\n} from 'comment-parser';\n\nconst {\n flow: commentFlow,\n} = transforms;\n\n/**\n * @typedef {{\n * postDelimiter: import('../iterateJsdoc.js').Integer,\n * postHyphen: import('../iterateJsdoc.js').Integer,\n * postName: import('../iterateJsdoc.js').Integer,\n * postTag: import('../iterateJsdoc.js').Integer,\n * postType: import('../iterateJsdoc.js').Integer,\n * }} CustomSpacings\n */\n\n/**\n * @param {import('../iterateJsdoc.js').Utils} utils\n * @param {import('comment-parser').Spec & {\n * line: import('../iterateJsdoc.js').Integer\n * }} tag\n * @param {CustomSpacings} customSpacings\n */\nconst checkNotAlignedPerTag = (utils, tag, customSpacings) => {\n /*\n start +\n delimiter +\n postDelimiter +\n tag +\n postTag +\n type +\n postType +\n name +\n postName +\n description +\n end +\n lineEnd\n */\n\n /**\n * @typedef {\"tag\"|\"type\"|\"name\"|\"description\"} ContentProp\n */\n\n /** @type {(\"postDelimiter\"|\"postTag\"|\"postType\"|\"postName\")[]} */\n let spacerProps;\n /** @type {ContentProp[]} */\n let contentProps;\n const mightHaveNamepath = utils.tagMightHaveNameOrNamepath(tag.tag);\n if (mightHaveNamepath) {\n spacerProps = [\n 'postDelimiter', 'postTag', 'postType', 'postName',\n ];\n contentProps = [\n 'tag', 'type', 'name', 'description',\n ];\n } else {\n spacerProps = [\n 'postDelimiter', 'postTag', 'postType',\n ];\n contentProps = [\n 'tag', 'type', 'description',\n ];\n }\n\n const {\n tokens,\n } = tag.source[0];\n\n /**\n * @param {import('../iterateJsdoc.js').Integer} idx\n * @param {(notRet: boolean, contentProp: ContentProp) => void} [callbck]\n */\n const followedBySpace = (idx, callbck) => {\n const nextIndex = idx + 1;\n\n return spacerProps.slice(nextIndex).some((spacerProp, innerIdx) => {\n const contentProp = contentProps[nextIndex + innerIdx];\n\n const spacePropVal = tokens[spacerProp];\n\n const ret = spacePropVal;\n\n if (callbck) {\n callbck(!ret, contentProp);\n }\n\n return ret && (callbck || !contentProp);\n });\n };\n\n const postHyphenSpacing = customSpacings?.postHyphen ?? 1;\n const exactHyphenSpacing = new RegExp(`^\\\\s*-\\\\s{${postHyphenSpacing},${postHyphenSpacing}}(?!\\\\s)`, 'v');\n const hasNoHyphen = !(/^\\s*-(?!$)(?=\\s)/v).test(tokens.description);\n const hasExactHyphenSpacing = exactHyphenSpacing.test(\n tokens.description,\n );\n\n // If checking alignment on multiple lines, need to check other `source`\n // items\n // Go through `post*` spacing properties and exit to indicate problem if\n // extra spacing detected\n const ok = !spacerProps.some((spacerProp, idx) => {\n const contentProp = contentProps[idx];\n const contentPropVal = tokens[contentProp];\n const spacerPropVal = tokens[spacerProp];\n const spacing = customSpacings?.[spacerProp] || 1;\n\n // There will be extra alignment if...\n\n // 1. The spaces don't match the space it should have (1 or custom spacing) OR\n return spacerPropVal.length !== spacing && spacerPropVal.length !== 0 ||\n\n // 2. There is a (single) space, no immediate content, and yet another\n // space is found subsequently (not separated by intervening content)\n spacerPropVal && !contentPropVal && followedBySpace(idx);\n }) && (hasNoHyphen || hasExactHyphenSpacing);\n if (ok) {\n return;\n }\n\n const fix = () => {\n for (const [\n idx,\n spacerProp,\n ] of spacerProps.entries()) {\n const contentProp = contentProps[idx];\n const contentPropVal = tokens[contentProp];\n\n if (contentPropVal) {\n const spacing = customSpacings?.[spacerProp] || 1;\n tokens[spacerProp] = ''.padStart(spacing, ' ');\n followedBySpace(idx, (hasSpace, contentPrp) => {\n if (hasSpace) {\n tokens[contentPrp] = '';\n }\n });\n } else {\n tokens[spacerProp] = '';\n }\n }\n\n if (!hasExactHyphenSpacing) {\n const hyphenSpacing = /^\\s*-\\s+/v;\n tokens.description = tokens.description.replace(\n hyphenSpacing, '-' + ''.padStart(postHyphenSpacing, ' '),\n );\n }\n\n utils.setTag(tag, tokens);\n };\n\n utils.reportJSDoc('Expected JSDoc block lines to not be aligned.', tag, fix, true);\n};\n\n/**\n * @param {object} cfg\n * @param {CustomSpacings} cfg.customSpacings\n * @param {string} cfg.indent\n * @param {import('comment-parser').Block} cfg.jsdoc\n * @param {import('eslint').Rule.Node & {\n * range: [number, number]\n * }} cfg.jsdocNode\n * @param {boolean} cfg.preserveMainDescriptionPostDelimiter\n * @param {import('../iterateJsdoc.js').Report} cfg.report\n * @param {string[]} cfg.tags\n * @param {import('../iterateJsdoc.js').Utils} cfg.utils\n * @param {string} cfg.wrapIndent\n * @param {boolean} cfg.disableWrapIndent\n * @returns {void}\n */\nconst checkAlignment = ({\n customSpacings,\n disableWrapIndent,\n indent,\n jsdoc,\n jsdocNode,\n preserveMainDescriptionPostDelimiter,\n report,\n tags,\n utils,\n wrapIndent,\n}) => {\n const transform = commentFlow(\n alignTransform({\n customSpacings,\n disableWrapIndent,\n indent,\n preserveMainDescriptionPostDelimiter,\n tags,\n wrapIndent,\n }),\n );\n const transformedJsdoc = transform(jsdoc);\n\n const comment = '/*' +\n /**\n * @type {import('eslint').Rule.Node & {\n * range: [number, number], value: string\n * }}\n */ (jsdocNode).value + '*/';\n\n const formatted = utils.stringify(transformedJsdoc)\n .trimStart();\n\n if (comment !== formatted) {\n report(\n 'Expected JSDoc block lines to be aligned.',\n /** @type {import('eslint').Rule.ReportFixer} */ (fixer) => {\n return fixer.replaceText(jsdocNode, formatted);\n },\n );\n }\n};\n\nexport default iterateJsdoc(({\n context,\n indent,\n jsdoc,\n jsdocNode,\n report,\n utils,\n}) => {\n const {\n customSpacings,\n disableWrapIndent = false,\n preserveMainDescriptionPostDelimiter,\n tags: applicableTags = [\n 'param', 'arg', 'argument', 'property', 'prop', 'returns', 'return', 'template',\n ],\n wrapIndent = '',\n } = context.options[1] || {};\n\n if (context.options[0] === 'always') {\n // Skip if it contains only a single line.\n if (!(\n /**\n * @type {import('eslint').Rule.Node & {\n * range: [number, number], value: string\n * }}\n */\n (jsdocNode).value.includes('\\n')\n )) {\n return;\n }\n\n checkAlignment({\n customSpacings,\n disableWrapIndent,\n indent,\n jsdoc,\n jsdocNode,\n preserveMainDescriptionPostDelimiter,\n report,\n tags: applicableTags,\n utils,\n wrapIndent,\n });\n\n return;\n }\n\n const foundTags = utils.getPresentTags(applicableTags);\n if (context.options[0] !== 'any') {\n for (const tag of foundTags) {\n checkNotAlignedPerTag(\n utils,\n /**\n * @type {import('comment-parser').Spec & {\n * line: import('../iterateJsdoc.js').Integer\n * }}\n */\n (tag),\n customSpacings,\n );\n }\n }\n\n for (const tag of foundTags) {\n if (tag.source.length > 1) {\n let idx = 0;\n for (const {\n tokens,\n // Avoid the tag line\n } of tag.source.slice(1)) {\n idx++;\n\n if (\n !tokens.description ||\n // Avoid first lines after multiline type\n tokens.type ||\n tokens.name\n ) {\n continue;\n }\n\n // Don't include a single separating space/tab\n if (!disableWrapIndent && tokens.postDelimiter.slice(1) !== wrapIndent) {\n utils.reportJSDoc('Expected wrap indent', {\n line: tag.source[0].number + idx,\n }, () => {\n tokens.postDelimiter = tokens.postDelimiter.charAt(0) + wrapIndent;\n });\n return;\n }\n }\n }\n }\n}, {\n iterateAllJsdocs: true,\n meta: {\n docs: {\n description: 'Reports invalid alignment of JSDoc block lines.',\n url: 'https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/check-line-alignment.md#repos-sticky-header',\n },\n fixable: 'whitespace',\n schema: [\n {\n description: `If the string value is\n\\`\"always\"\\` then a problem is raised when the lines are not aligned.\nIf it is \\`\"never\"\\` then a problem should be raised when there is more than\none space between each line's parts. If it is \\`\"any\"\\`, no alignment is made.\nDefaults to \\`\"never\"\\`.\n\nNote that in addition to alignment, the \"never\" and \"always\" options will both\nensure that at least one space is present after the asterisk delimiter.`,\n enum: [\n 'always', 'never', 'any',\n ],\n type: 'string',\n },\n {\n additionalProperties: false,\n properties: {\n customSpacings: {\n additionalProperties: false,\n description: `An object with any of the following spacing keys set to an integer.\nIf a spacing is not defined, it defaults to one.`,\n properties: {\n postDelimiter: {\n description: 'Affects spacing after the asterisk (e.g., `* @param`)',\n type: 'integer',\n },\n postHyphen: {\n description: 'Affects spacing after any hyphens in the description (e.g., `* @param {someType} name - A description`)',\n type: 'integer',\n },\n postName: {\n description: 'Affects spacing after the name (e.g., `* @param {someType} name `)',\n type: 'integer',\n },\n postTag: {\n description: 'Affects spacing after the tag (e.g., `* @param `)',\n type: 'integer',\n },\n postType: {\n description: 'Affects spacing after the type (e.g., `* @param {someType} `)',\n type: 'integer',\n },\n },\n type: 'object',\n },\n disableWrapIndent: {\n description: 'Disables `wrapIndent`; existing wrap indentation is preserved without changes.',\n type: 'boolean',\n },\n preserveMainDescriptionPostDelimiter: {\n default: false,\n description: `A boolean to determine whether to preserve the post-delimiter spacing of the\nmain description. If \\`false\\` or unset, will be set to a single space.`,\n type: 'boolean',\n },\n tags: {\n description: `Use this to change the tags which are sought for alignment changes. Defaults to an array of\n\\`['param', 'arg', 'argument', 'property', 'prop', 'returns', 'return', 'template']\\`.`,\n items: {\n type: 'string',\n },\n type: 'array',\n },\n wrapIndent: {\n description: `The indent that will be applied for tag text after the first line.\nDefault to the empty string (no indent).`,\n type: 'string',\n },\n },\n type: 'object',\n },\n ],\n type: 'layout',\n },\n});\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"file":"checkLineAlignment.cjs","names":["_alignTransform","_interopRequireDefault","require","_iterateJsdoc","_commentParser","e","__esModule","default","flow","commentFlow","transforms","startsWithListMarker","text","isFirstLineOfTag","test","shouldAllowExtraIndent","tag","idx","hasSeenListMarker","lineIdx","line","source","isFirstLine","tokens","description","checkNotAlignedPerTag","utils","customSpacings","spacerProps","contentProps","mightHaveNamepath","tagMightHaveNameOrNamepath","followedBySpace","callbck","nextIndex","slice","some","spacerProp","innerIdx","contentProp","spacePropVal","ret","postHyphenSpacing","postHyphen","exactHyphenSpacing","RegExp","hasNoHyphen","hasExactHyphenSpacing","ok","contentPropVal","spacerPropVal","spacing","length","fix","entries","padStart","hasSpace","contentPrp","hyphenSpacing","replace","setTag","reportJSDoc","checkAlignment","disableWrapIndent","indent","jsdoc","jsdocNode","preserveMainDescriptionPostDelimiter","report","tags","wrapIndent","transform","alignTransform","transformedJsdoc","comment","value","formatted","stringify","trimStart","fixer","replaceText","_default","exports","iterateJsdoc","context","applicableTags","options","includes","foundTags","getPresentTags","type","name","actualIndent","postDelimiter","hasCorrectWrapIndent","hasExtraIndent","startsWith","isInListContext","number","charAt","iterateAllJsdocs","meta","docs","url","fixable","schema","enum","additionalProperties","properties","postName","postTag","postType","items","module"],"sources":["../../src/rules/checkLineAlignment.js"],"sourcesContent":["import alignTransform from '../alignTransform.js';\nimport iterateJsdoc from '../iterateJsdoc.js';\nimport {\n transforms,\n} from 'comment-parser';\n\nconst {\n flow: commentFlow,\n} = transforms;\n\n/**\n * Detects if a line starts with a markdown list marker\n * Supports: -, *, numbered lists (1., 2., etc.)\n * This explicitly excludes hyphens that are part of JSDoc tag syntax\n * @param {string} text - The text to check\n * @param {boolean} isFirstLineOfTag - True if this is the first line (tag line)\n * @returns {boolean} - True if the text starts with a list marker\n */\nconst startsWithListMarker = (text, isFirstLineOfTag = false) => {\n // On the first line of a tag, the hyphen is typically the JSDoc separator,\n // not a list marker\n if (isFirstLineOfTag) {\n return false;\n }\n\n // Match lines that start with optional whitespace, then a list marker\n // - or * followed by a space\n // or a number followed by . or ) and a space\n return /^\\s*(?:[\\-*]|\\d+(?:\\.|\\)))\\s+/v.test(text);\n};\n\n/**\n * Checks if we should allow extra indentation beyond wrapIndent.\n * This is true for list continuation lines (lines with more indent than wrapIndent\n * that follow a list item).\n * @param {import('comment-parser').Spec} tag - The tag being checked\n * @param {import('../iterateJsdoc.js').Integer} idx - Current line index (0-based in tag.source.slice(1))\n * @returns {boolean} - True if extra indentation should be allowed\n */\nconst shouldAllowExtraIndent = (tag, idx) => {\n // Check if any previous line in this tag had a list marker\n // idx is 0-based in the continuation lines (tag.source.slice(1))\n // So tag.source[0] is the tag line, tag.source[idx+1] is current line\n let hasSeenListMarker = false;\n\n // Check all lines from the tag line onwards\n for (let lineIdx = 0; lineIdx <= idx + 1; lineIdx++) {\n const line = tag.source[lineIdx];\n const isFirstLine = lineIdx === 0;\n if (line?.tokens?.description && startsWithListMarker(line.tokens.description, isFirstLine)) {\n hasSeenListMarker = true;\n break;\n }\n }\n\n return hasSeenListMarker;\n};\n\n/**\n * @typedef {{\n * postDelimiter: import('../iterateJsdoc.js').Integer,\n * postHyphen: import('../iterateJsdoc.js').Integer,\n * postName: import('../iterateJsdoc.js').Integer,\n * postTag: import('../iterateJsdoc.js').Integer,\n * postType: import('../iterateJsdoc.js').Integer,\n * }} CustomSpacings\n */\n\n/**\n * @param {import('../iterateJsdoc.js').Utils} utils\n * @param {import('comment-parser').Spec & {\n * line: import('../iterateJsdoc.js').Integer\n * }} tag\n * @param {CustomSpacings} customSpacings\n */\nconst checkNotAlignedPerTag = (utils, tag, customSpacings) => {\n /*\n start +\n delimiter +\n postDelimiter +\n tag +\n postTag +\n type +\n postType +\n name +\n postName +\n description +\n end +\n lineEnd\n */\n\n /**\n * @typedef {\"tag\"|\"type\"|\"name\"|\"description\"} ContentProp\n */\n\n /** @type {(\"postDelimiter\"|\"postTag\"|\"postType\"|\"postName\")[]} */\n let spacerProps;\n /** @type {ContentProp[]} */\n let contentProps;\n const mightHaveNamepath = utils.tagMightHaveNameOrNamepath(tag.tag);\n if (mightHaveNamepath) {\n spacerProps = [\n 'postDelimiter', 'postTag', 'postType', 'postName',\n ];\n contentProps = [\n 'tag', 'type', 'name', 'description',\n ];\n } else {\n spacerProps = [\n 'postDelimiter', 'postTag', 'postType',\n ];\n contentProps = [\n 'tag', 'type', 'description',\n ];\n }\n\n const {\n tokens,\n } = tag.source[0];\n\n /**\n * @param {import('../iterateJsdoc.js').Integer} idx\n * @param {(notRet: boolean, contentProp: ContentProp) => void} [callbck]\n */\n const followedBySpace = (idx, callbck) => {\n const nextIndex = idx + 1;\n\n return spacerProps.slice(nextIndex).some((spacerProp, innerIdx) => {\n const contentProp = contentProps[nextIndex + innerIdx];\n\n const spacePropVal = tokens[spacerProp];\n\n const ret = spacePropVal;\n\n if (callbck) {\n callbck(!ret, contentProp);\n }\n\n return ret && (callbck || !contentProp);\n });\n };\n\n const postHyphenSpacing = customSpacings?.postHyphen ?? 1;\n const exactHyphenSpacing = new RegExp(`^\\\\s*-\\\\s{${postHyphenSpacing},${postHyphenSpacing}}(?!\\\\s)`, 'v');\n const hasNoHyphen = !(/^\\s*-(?!$)(?=\\s)/v).test(tokens.description);\n const hasExactHyphenSpacing = exactHyphenSpacing.test(\n tokens.description,\n );\n\n // If checking alignment on multiple lines, need to check other `source`\n // items\n // Go through `post*` spacing properties and exit to indicate problem if\n // extra spacing detected\n const ok = !spacerProps.some((spacerProp, idx) => {\n const contentProp = contentProps[idx];\n const contentPropVal = tokens[contentProp];\n const spacerPropVal = tokens[spacerProp];\n const spacing = customSpacings?.[spacerProp] || 1;\n\n // There will be extra alignment if...\n\n // 1. The spaces don't match the space it should have (1 or custom spacing) OR\n return spacerPropVal.length !== spacing && spacerPropVal.length !== 0 ||\n\n // 2. There is a (single) space, no immediate content, and yet another\n // space is found subsequently (not separated by intervening content)\n spacerPropVal && !contentPropVal && followedBySpace(idx);\n }) && (hasNoHyphen || hasExactHyphenSpacing);\n if (ok) {\n return;\n }\n\n const fix = () => {\n for (const [\n idx,\n spacerProp,\n ] of spacerProps.entries()) {\n const contentProp = contentProps[idx];\n const contentPropVal = tokens[contentProp];\n\n if (contentPropVal) {\n const spacing = customSpacings?.[spacerProp] || 1;\n tokens[spacerProp] = ''.padStart(spacing, ' ');\n followedBySpace(idx, (hasSpace, contentPrp) => {\n if (hasSpace) {\n tokens[contentPrp] = '';\n }\n });\n } else {\n tokens[spacerProp] = '';\n }\n }\n\n if (!hasExactHyphenSpacing) {\n const hyphenSpacing = /^\\s*-\\s+/v;\n tokens.description = tokens.description.replace(\n hyphenSpacing, '-' + ''.padStart(postHyphenSpacing, ' '),\n );\n }\n\n utils.setTag(tag, tokens);\n };\n\n utils.reportJSDoc('Expected JSDoc block lines to not be aligned.', tag, fix, true);\n};\n\n/**\n * @param {object} cfg\n * @param {CustomSpacings} cfg.customSpacings\n * @param {string} cfg.indent\n * @param {import('comment-parser').Block} cfg.jsdoc\n * @param {import('eslint').Rule.Node & {\n * range: [number, number]\n * }} cfg.jsdocNode\n * @param {boolean} cfg.preserveMainDescriptionPostDelimiter\n * @param {import('../iterateJsdoc.js').Report} cfg.report\n * @param {string[]} cfg.tags\n * @param {import('../iterateJsdoc.js').Utils} cfg.utils\n * @param {string} cfg.wrapIndent\n * @param {boolean} cfg.disableWrapIndent\n * @returns {void}\n */\nconst checkAlignment = ({\n customSpacings,\n disableWrapIndent,\n indent,\n jsdoc,\n jsdocNode,\n preserveMainDescriptionPostDelimiter,\n report,\n tags,\n utils,\n wrapIndent,\n}) => {\n const transform = commentFlow(\n alignTransform({\n customSpacings,\n disableWrapIndent,\n indent,\n preserveMainDescriptionPostDelimiter,\n tags,\n wrapIndent,\n }),\n );\n const transformedJsdoc = transform(jsdoc);\n\n const comment = '/*' +\n /**\n * @type {import('eslint').Rule.Node & {\n * range: [number, number], value: string\n * }}\n */ (jsdocNode).value + '*/';\n\n const formatted = utils.stringify(transformedJsdoc)\n .trimStart();\n\n if (comment !== formatted) {\n report(\n 'Expected JSDoc block lines to be aligned.',\n /** @type {import('eslint').Rule.ReportFixer} */ (fixer) => {\n return fixer.replaceText(jsdocNode, formatted);\n },\n );\n }\n};\n\nexport default iterateJsdoc(({\n context,\n indent,\n jsdoc,\n jsdocNode,\n report,\n utils,\n}) => {\n const {\n customSpacings,\n disableWrapIndent = false,\n preserveMainDescriptionPostDelimiter,\n tags: applicableTags = [\n 'param', 'arg', 'argument', 'property', 'prop', 'returns', 'return', 'template',\n ],\n wrapIndent = '',\n } = context.options[1] || {};\n\n if (context.options[0] === 'always') {\n // Skip if it contains only a single line.\n if (!(\n /**\n * @type {import('eslint').Rule.Node & {\n * range: [number, number], value: string\n * }}\n */\n (jsdocNode).value.includes('\\n')\n )) {\n return;\n }\n\n checkAlignment({\n customSpacings,\n disableWrapIndent,\n indent,\n jsdoc,\n jsdocNode,\n preserveMainDescriptionPostDelimiter,\n report,\n tags: applicableTags,\n utils,\n wrapIndent,\n });\n\n return;\n }\n\n const foundTags = utils.getPresentTags(applicableTags);\n if (context.options[0] !== 'any') {\n for (const tag of foundTags) {\n checkNotAlignedPerTag(\n utils,\n /**\n * @type {import('comment-parser').Spec & {\n * line: import('../iterateJsdoc.js').Integer\n * }}\n */\n (tag),\n customSpacings,\n );\n }\n }\n\n for (const tag of foundTags) {\n if (tag.source.length > 1) {\n let idx = 0;\n for (const {\n tokens,\n // Avoid the tag line\n } of tag.source.slice(1)) {\n idx++;\n\n if (\n !tokens.description ||\n // Avoid first lines after multiline type\n tokens.type ||\n tokens.name\n ) {\n continue;\n }\n\n // Don't include a single separating space/tab\n const actualIndent = tokens.postDelimiter.slice(1);\n const hasCorrectWrapIndent = actualIndent === wrapIndent;\n\n // Allow extra indentation if this line or previous lines contain list markers\n // This preserves nested list structure\n const hasExtraIndent = actualIndent.length > wrapIndent.length &&\n actualIndent.startsWith(wrapIndent);\n const isInListContext = shouldAllowExtraIndent(tag, idx - 1);\n\n if (!disableWrapIndent && !hasCorrectWrapIndent &&\n !(hasExtraIndent && isInListContext)) {\n utils.reportJSDoc('Expected wrap indent', {\n line: tag.source[0].number + idx,\n }, () => {\n tokens.postDelimiter = tokens.postDelimiter.charAt(0) + wrapIndent;\n });\n return;\n }\n }\n }\n }\n}, {\n iterateAllJsdocs: true,\n meta: {\n docs: {\n description: 'Reports invalid alignment of JSDoc block lines.',\n url: 'https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/check-line-alignment.md#repos-sticky-header',\n },\n fixable: 'whitespace',\n schema: [\n {\n description: `If the string value is\n\\`\"always\"\\` then a problem is raised when the lines are not aligned.\nIf it is \\`\"never\"\\` then a problem should be raised when there is more than\none space between each line's parts. If it is \\`\"any\"\\`, no alignment is made.\nDefaults to \\`\"never\"\\`.\n\nNote that in addition to alignment, the \"never\" and \"always\" options will both\nensure that at least one space is present after the asterisk delimiter.`,\n enum: [\n 'always', 'never', 'any',\n ],\n type: 'string',\n },\n {\n additionalProperties: false,\n properties: {\n customSpacings: {\n additionalProperties: false,\n description: `An object with any of the following spacing keys set to an integer.\nIf a spacing is not defined, it defaults to one.`,\n properties: {\n postDelimiter: {\n description: 'Affects spacing after the asterisk (e.g., `* @param`)',\n type: 'integer',\n },\n postHyphen: {\n description: 'Affects spacing after any hyphens in the description (e.g., `* @param {someType} name - A description`)',\n type: 'integer',\n },\n postName: {\n description: 'Affects spacing after the name (e.g., `* @param {someType} name `)',\n type: 'integer',\n },\n postTag: {\n description: 'Affects spacing after the tag (e.g., `* @param `)',\n type: 'integer',\n },\n postType: {\n description: 'Affects spacing after the type (e.g., `* @param {someType} `)',\n type: 'integer',\n },\n },\n type: 'object',\n },\n disableWrapIndent: {\n description: 'Disables `wrapIndent`; existing wrap indentation is preserved without changes.',\n type: 'boolean',\n },\n preserveMainDescriptionPostDelimiter: {\n default: false,\n description: `A boolean to determine whether to preserve the post-delimiter spacing of the\nmain description. If \\`false\\` or unset, will be set to a single space.`,\n type: 'boolean',\n },\n tags: {\n description: `Use this to change the tags which are sought for alignment changes. Defaults to an array of\n\\`['param', 'arg', 'argument', 'property', 'prop', 'returns', 'return', 'template']\\`.`,\n items: {\n type: 'string',\n },\n type: 'array',\n },\n wrapIndent: {\n description: `The indent that will be applied for tag text after the first line.\nDefault to the empty string (no indent).`,\n type: 'string',\n },\n },\n type: 'object',\n },\n ],\n type: 'layout',\n },\n});\n"],"mappings":"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","ignoreList":[]}
@@ -10,10 +10,11 @@ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e
10
10
  * Checks if a node or its children contain Promise rejection patterns
11
11
  * @param {import('eslint').Rule.Node} node
12
12
  * @param {boolean} [innerFunction]
13
+ * @param {boolean} [isAsync]
13
14
  * @returns {boolean}
14
15
  */
15
16
  // eslint-disable-next-line complexity -- Temporary
16
- const hasRejectValue = (node, innerFunction) => {
17
+ const hasRejectValue = (node, innerFunction, isAsync) => {
17
18
  if (!node) {
18
19
  return false;
19
20
  }
@@ -25,15 +26,19 @@ const hasRejectValue = (node, innerFunction) => {
25
26
  // For inner functions in async contexts, check if they throw
26
27
  // (they could be called and cause rejection)
27
28
  if (innerFunction) {
28
- // Check the inner function's body for throw statements
29
- return hasRejectValue(/** @type {import('eslint').Rule.Node} */node.body, false);
29
+ // Check inner functions for throws - if called from async context, throws become rejections
30
+ const innerIsAsync = node.async;
31
+ // Pass isAsync=true if the inner function is async OR if we're already in an async context
32
+ return hasRejectValue(/** @type {import('eslint').Rule.Node} */node.body, false, innerIsAsync || isAsync);
30
33
  }
31
- return hasRejectValue(/** @type {import('eslint').Rule.Node} */node.body, true);
34
+
35
+ // This is the top-level function we're checking
36
+ return hasRejectValue(/** @type {import('eslint').Rule.Node} */node.body, true, node.async);
32
37
  }
33
38
  case 'BlockStatement':
34
39
  {
35
40
  return node.body.some(bodyNode => {
36
- return hasRejectValue(/** @type {import('eslint').Rule.Node} */bodyNode, innerFunction);
41
+ return hasRejectValue(/** @type {import('eslint').Rule.Node} */bodyNode, innerFunction, isAsync);
37
42
  });
38
43
  }
39
44
  case 'CallExpression':
@@ -64,15 +69,15 @@ const hasRejectValue = (node, innerFunction) => {
64
69
  case 'WhileStatement':
65
70
  case 'WithStatement':
66
71
  {
67
- return hasRejectValue(/** @type {import('eslint').Rule.Node} */node.body, innerFunction);
72
+ return hasRejectValue(/** @type {import('eslint').Rule.Node} */node.body, innerFunction, isAsync);
68
73
  }
69
74
  case 'ExpressionStatement':
70
75
  {
71
- return hasRejectValue(/** @type {import('eslint').Rule.Node} */node.expression, innerFunction);
76
+ return hasRejectValue(/** @type {import('eslint').Rule.Node} */node.expression, innerFunction, isAsync);
72
77
  }
73
78
  case 'IfStatement':
74
79
  {
75
- return hasRejectValue(/** @type {import('eslint').Rule.Node} */node.consequent, innerFunction) || hasRejectValue(/** @type {import('eslint').Rule.Node} */node.alternate, innerFunction);
80
+ return hasRejectValue(/** @type {import('eslint').Rule.Node} */node.consequent, innerFunction, isAsync) || hasRejectValue(/** @type {import('eslint').Rule.Node} */node.alternate, innerFunction, isAsync);
76
81
  }
77
82
  case 'NewExpression':
78
83
  {
@@ -81,7 +86,7 @@ const hasRejectValue = (node, innerFunction) => {
81
86
  const executor = node.arguments[0];
82
87
  if (executor.type === 'ArrowFunctionExpression' || executor.type === 'FunctionExpression') {
83
88
  // Check if the executor has reject() calls
84
- return hasRejectValue(/** @type {import('eslint').Rule.Node} */executor.body, false);
89
+ return hasRejectValue(/** @type {import('eslint').Rule.Node} */executor.body, false, false);
85
90
  }
86
91
  }
87
92
  return false;
@@ -89,7 +94,7 @@ const hasRejectValue = (node, innerFunction) => {
89
94
  case 'ReturnStatement':
90
95
  {
91
96
  if (node.argument) {
92
- return hasRejectValue(/** @type {import('eslint').Rule.Node} */node.argument, innerFunction);
97
+ return hasRejectValue(/** @type {import('eslint').Rule.Node} */node.argument, innerFunction, isAsync);
93
98
  }
94
99
  return false;
95
100
  }
@@ -97,7 +102,7 @@ const hasRejectValue = (node, innerFunction) => {
97
102
  {
98
103
  return node.cases.some(someCase => {
99
104
  return someCase.consequent.some(nde => {
100
- return hasRejectValue(/** @type {import('eslint').Rule.Node} */nde, innerFunction);
105
+ return hasRejectValue(/** @type {import('eslint').Rule.Node} */nde, innerFunction, isAsync);
101
106
  });
102
107
  });
103
108
  }
@@ -105,11 +110,11 @@ const hasRejectValue = (node, innerFunction) => {
105
110
  // Throw statements in async functions become rejections
106
111
  case 'ThrowStatement':
107
112
  {
108
- return true;
113
+ return isAsync === true;
109
114
  }
110
115
  case 'TryStatement':
111
116
  {
112
- return hasRejectValue(/** @type {import('eslint').Rule.Node} */node.handler && node.handler.body, innerFunction) || hasRejectValue(/** @type {import('eslint').Rule.Node} */node.finalizer, innerFunction);
117
+ return hasRejectValue(/** @type {import('eslint').Rule.Node} */node.handler && node.handler.body, innerFunction, isAsync) || hasRejectValue(/** @type {import('eslint').Rule.Node} */node.finalizer, innerFunction, isAsync);
113
118
  }
114
119
  default:
115
120
  {
@@ -1 +1 @@
1
- {"version":3,"file":"requireRejects.cjs","names":["_iterateJsdoc","_interopRequireDefault","require","e","__esModule","default","hasRejectValue","node","innerFunction","type","body","some","bodyNode","callee","object","name","property","expression","consequent","alternate","arguments","length","executor","argument","cases","someCase","nde","handler","finalizer","canSkip","utils","hasATag","avoidDocs","_default","exports","iterateJsdoc","report","tagName","getPreferredTagName","tags","getTags","iteratingFunction","isIteratingFunction","tag","missingRejectsTag","shouldReport","isAsync","contextDefaults","meta","docs","description","url","schema","additionalProperties","properties","contexts","items","anyOf","comment","context","exemptedBy","module"],"sources":["../../src/rules/requireRejects.js"],"sourcesContent":["import iterateJsdoc from '../iterateJsdoc.js';\n\n/**\n * Checks if a node or its children contain Promise rejection patterns\n * @param {import('eslint').Rule.Node} node\n * @param {boolean} [innerFunction]\n * @returns {boolean}\n */\n// eslint-disable-next-line complexity -- Temporary\nconst hasRejectValue = (node, innerFunction) => {\n if (!node) {\n return false;\n }\n\n switch (node.type) {\n case 'ArrowFunctionExpression':\n case 'FunctionDeclaration':\n case 'FunctionExpression': {\n // For inner functions in async contexts, check if they throw\n // (they could be called and cause rejection)\n if (innerFunction) {\n // Check the inner function's body for throw statements\n return hasRejectValue(/** @type {import('eslint').Rule.Node} */ (node.body), false);\n }\n\n return hasRejectValue(/** @type {import('eslint').Rule.Node} */ (node.body), true);\n }\n\n case 'BlockStatement': {\n return node.body.some((bodyNode) => {\n return hasRejectValue(/** @type {import('eslint').Rule.Node} */ (bodyNode), innerFunction);\n });\n }\n\n case 'CallExpression': {\n // Check for Promise.reject()\n if (node.callee.type === 'MemberExpression' &&\n node.callee.object.type === 'Identifier' &&\n node.callee.object.name === 'Promise' &&\n node.callee.property.type === 'Identifier' &&\n node.callee.property.name === 'reject') {\n return true;\n }\n\n // Check for reject() call (in Promise executor context)\n if (node.callee.type === 'Identifier' && node.callee.name === 'reject') {\n return true;\n }\n\n // Check if this is calling an inner function that might reject\n if (innerFunction && node.callee.type === 'Identifier') {\n // We found a function call inside - check if it could be calling a function that rejects\n // We'll handle this in function body traversal\n return false;\n }\n\n return false;\n }\n\n case 'DoWhileStatement':\n case 'ForInStatement':\n case 'ForOfStatement':\n case 'ForStatement':\n case 'LabeledStatement':\n case 'WhileStatement':\n\n case 'WithStatement': {\n return hasRejectValue(/** @type {import('eslint').Rule.Node} */ (node.body), innerFunction);\n }\n\n case 'ExpressionStatement': {\n return hasRejectValue(/** @type {import('eslint').Rule.Node} */ (node.expression), innerFunction);\n }\n\n case 'IfStatement': {\n return hasRejectValue(/** @type {import('eslint').Rule.Node} */ (node.consequent), innerFunction) || hasRejectValue(/** @type {import('eslint').Rule.Node} */ (node.alternate), innerFunction);\n }\n\n case 'NewExpression': {\n // Check for new Promise((resolve, reject) => { reject(...) })\n if (node.callee.type === 'Identifier' && node.callee.name === 'Promise' && node.arguments.length > 0) {\n const executor = node.arguments[0];\n if (executor.type === 'ArrowFunctionExpression' || executor.type === 'FunctionExpression') {\n // Check if the executor has reject() calls\n return hasRejectValue(/** @type {import('eslint').Rule.Node} */ (executor.body), false);\n }\n }\n\n return false;\n }\n\n case 'ReturnStatement': {\n if (node.argument) {\n return hasRejectValue(/** @type {import('eslint').Rule.Node} */ (node.argument), innerFunction);\n }\n\n return false;\n }\n\n case 'SwitchStatement': {\n return node.cases.some(\n (someCase) => {\n return someCase.consequent.some((nde) => {\n return hasRejectValue(/** @type {import('eslint').Rule.Node} */ (nde), innerFunction);\n });\n },\n );\n }\n\n // Throw statements in async functions become rejections\n case 'ThrowStatement': {\n return true;\n }\n\n case 'TryStatement': {\n return hasRejectValue(/** @type {import('eslint').Rule.Node} */ (node.handler && node.handler.body), innerFunction) ||\n hasRejectValue(/** @type {import('eslint').Rule.Node} */ (node.finalizer), innerFunction);\n }\n\n default: {\n return false;\n }\n }\n};\n\n/**\n * We can skip checking for a rejects value, in case the documentation is inherited\n * or the method is abstract.\n * @param {import('../iterateJsdoc.js').Utils} utils\n * @returns {boolean}\n */\nconst canSkip = (utils) => {\n return utils.hasATag([\n 'abstract',\n 'virtual',\n 'type',\n ]) ||\n utils.avoidDocs();\n};\n\nexport default iterateJsdoc(({\n node,\n report,\n utils,\n}) => {\n if (canSkip(utils)) {\n return;\n }\n\n const tagName = /** @type {string} */ (utils.getPreferredTagName({\n tagName: 'rejects',\n }));\n if (!tagName) {\n return;\n }\n\n const tags = utils.getTags(tagName);\n const iteratingFunction = utils.isIteratingFunction();\n\n const [\n tag,\n ] = tags;\n const missingRejectsTag = typeof tag === 'undefined' || tag === null;\n\n const shouldReport = () => {\n if (!missingRejectsTag) {\n return false;\n }\n\n // Check if this is an async function or returns a Promise\n const isAsync = utils.isAsync();\n if (!isAsync && !iteratingFunction) {\n return false;\n }\n\n // For async functions, check for throw statements\n // For regular functions, check for Promise.reject or reject calls\n return hasRejectValue(/** @type {import('eslint').Rule.Node} */ (node));\n };\n\n if (shouldReport()) {\n report('Promise-rejecting function requires `@reject` tag');\n }\n}, {\n contextDefaults: true,\n meta: {\n docs: {\n description: 'Requires that Promise rejections are documented with `@rejects` tags.',\n url: 'https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/require-rejects.md#repos-sticky-header',\n },\n schema: [\n {\n additionalProperties: false,\n properties: {\n contexts: {\n description: `Set this to an array of strings representing the AST context\n(or objects with optional \\`context\\` and \\`comment\\` properties) where you wish\nthe rule to be applied.\n\n\\`context\\` defaults to \\`any\\` and \\`comment\\` defaults to no specific comment context.\n\nOverrides the default contexts (\\`ArrowFunctionExpression\\`, \\`FunctionDeclaration\\`,\n\\`FunctionExpression\\`).`,\n items: {\n anyOf: [\n {\n type: 'string',\n },\n {\n additionalProperties: false,\n properties: {\n comment: {\n type: 'string',\n },\n context: {\n type: 'string',\n },\n },\n type: 'object',\n },\n ],\n },\n type: 'array',\n },\n exemptedBy: {\n description: `Array of tags (e.g., \\`['type']\\`) whose presence on the\ndocument block avoids the need for a \\`@rejects\\`. Defaults to an array\nwith \\`abstract\\`, \\`virtual\\`, and \\`type\\`. If you set this array, it will overwrite the default,\nso be sure to add back those tags if you wish their presence to cause\nexemption of the rule.`,\n items: {\n type: 'string',\n },\n type: 'array',\n },\n },\n type: 'object',\n },\n ],\n type: 'suggestion',\n },\n});\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"file":"requireRejects.cjs","names":["_iterateJsdoc","_interopRequireDefault","require","e","__esModule","default","hasRejectValue","node","innerFunction","isAsync","type","innerIsAsync","async","body","some","bodyNode","callee","object","name","property","expression","consequent","alternate","arguments","length","executor","argument","cases","someCase","nde","handler","finalizer","canSkip","utils","hasATag","avoidDocs","_default","exports","iterateJsdoc","report","tagName","getPreferredTagName","tags","getTags","iteratingFunction","isIteratingFunction","tag","missingRejectsTag","shouldReport","contextDefaults","meta","docs","description","url","schema","additionalProperties","properties","contexts","items","anyOf","comment","context","exemptedBy","module"],"sources":["../../src/rules/requireRejects.js"],"sourcesContent":["import iterateJsdoc from '../iterateJsdoc.js';\n\n/**\n * Checks if a node or its children contain Promise rejection patterns\n * @param {import('eslint').Rule.Node} node\n * @param {boolean} [innerFunction]\n * @param {boolean} [isAsync]\n * @returns {boolean}\n */\n// eslint-disable-next-line complexity -- Temporary\nconst hasRejectValue = (node, innerFunction, isAsync) => {\n if (!node) {\n return false;\n }\n\n switch (node.type) {\n case 'ArrowFunctionExpression':\n case 'FunctionDeclaration':\n case 'FunctionExpression': {\n // For inner functions in async contexts, check if they throw\n // (they could be called and cause rejection)\n if (innerFunction) {\n // Check inner functions for throws - if called from async context, throws become rejections\n const innerIsAsync = node.async;\n // Pass isAsync=true if the inner function is async OR if we're already in an async context\n return hasRejectValue(/** @type {import('eslint').Rule.Node} */ (node.body), false, innerIsAsync || isAsync);\n }\n\n // This is the top-level function we're checking\n return hasRejectValue(/** @type {import('eslint').Rule.Node} */ (node.body), true, node.async);\n }\n\n case 'BlockStatement': {\n return node.body.some((bodyNode) => {\n return hasRejectValue(/** @type {import('eslint').Rule.Node} */ (bodyNode), innerFunction, isAsync);\n });\n }\n\n case 'CallExpression': {\n // Check for Promise.reject()\n if (node.callee.type === 'MemberExpression' &&\n node.callee.object.type === 'Identifier' &&\n node.callee.object.name === 'Promise' &&\n node.callee.property.type === 'Identifier' &&\n node.callee.property.name === 'reject') {\n return true;\n }\n\n // Check for reject() call (in Promise executor context)\n if (node.callee.type === 'Identifier' && node.callee.name === 'reject') {\n return true;\n }\n\n // Check if this is calling an inner function that might reject\n if (innerFunction && node.callee.type === 'Identifier') {\n // We found a function call inside - check if it could be calling a function that rejects\n // We'll handle this in function body traversal\n return false;\n }\n\n return false;\n }\n\n case 'DoWhileStatement':\n case 'ForInStatement':\n case 'ForOfStatement':\n case 'ForStatement':\n case 'LabeledStatement':\n case 'WhileStatement':\n\n case 'WithStatement': {\n return hasRejectValue(/** @type {import('eslint').Rule.Node} */ (node.body), innerFunction, isAsync);\n }\n\n case 'ExpressionStatement': {\n return hasRejectValue(/** @type {import('eslint').Rule.Node} */ (node.expression), innerFunction, isAsync);\n }\n\n case 'IfStatement': {\n return hasRejectValue(/** @type {import('eslint').Rule.Node} */ (node.consequent), innerFunction, isAsync) || hasRejectValue(/** @type {import('eslint').Rule.Node} */ (node.alternate), innerFunction, isAsync);\n }\n\n case 'NewExpression': {\n // Check for new Promise((resolve, reject) => { reject(...) })\n if (node.callee.type === 'Identifier' && node.callee.name === 'Promise' && node.arguments.length > 0) {\n const executor = node.arguments[0];\n if (executor.type === 'ArrowFunctionExpression' || executor.type === 'FunctionExpression') {\n // Check if the executor has reject() calls\n return hasRejectValue(/** @type {import('eslint').Rule.Node} */ (executor.body), false, false);\n }\n }\n\n return false;\n }\n\n case 'ReturnStatement': {\n if (node.argument) {\n return hasRejectValue(/** @type {import('eslint').Rule.Node} */ (node.argument), innerFunction, isAsync);\n }\n\n return false;\n }\n\n case 'SwitchStatement': {\n return node.cases.some(\n (someCase) => {\n return someCase.consequent.some((nde) => {\n return hasRejectValue(/** @type {import('eslint').Rule.Node} */ (nde), innerFunction, isAsync);\n });\n },\n );\n }\n\n // Throw statements in async functions become rejections\n case 'ThrowStatement': {\n return isAsync === true;\n }\n\n case 'TryStatement': {\n return hasRejectValue(/** @type {import('eslint').Rule.Node} */ (node.handler && node.handler.body), innerFunction, isAsync) ||\n hasRejectValue(/** @type {import('eslint').Rule.Node} */ (node.finalizer), innerFunction, isAsync);\n }\n\n default: {\n return false;\n }\n }\n};\n\n/**\n * We can skip checking for a rejects value, in case the documentation is inherited\n * or the method is abstract.\n * @param {import('../iterateJsdoc.js').Utils} utils\n * @returns {boolean}\n */\nconst canSkip = (utils) => {\n return utils.hasATag([\n 'abstract',\n 'virtual',\n 'type',\n ]) ||\n utils.avoidDocs();\n};\n\nexport default iterateJsdoc(({\n node,\n report,\n utils,\n}) => {\n if (canSkip(utils)) {\n return;\n }\n\n const tagName = /** @type {string} */ (utils.getPreferredTagName({\n tagName: 'rejects',\n }));\n if (!tagName) {\n return;\n }\n\n const tags = utils.getTags(tagName);\n const iteratingFunction = utils.isIteratingFunction();\n\n const [\n tag,\n ] = tags;\n const missingRejectsTag = typeof tag === 'undefined' || tag === null;\n\n const shouldReport = () => {\n if (!missingRejectsTag) {\n return false;\n }\n\n // Check if this is an async function or returns a Promise\n const isAsync = utils.isAsync();\n if (!isAsync && !iteratingFunction) {\n return false;\n }\n\n // For async functions, check for throw statements\n // For regular functions, check for Promise.reject or reject calls\n return hasRejectValue(/** @type {import('eslint').Rule.Node} */ (node));\n };\n\n if (shouldReport()) {\n report('Promise-rejecting function requires `@reject` tag');\n }\n}, {\n contextDefaults: true,\n meta: {\n docs: {\n description: 'Requires that Promise rejections are documented with `@rejects` tags.',\n url: 'https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/require-rejects.md#repos-sticky-header',\n },\n schema: [\n {\n additionalProperties: false,\n properties: {\n contexts: {\n description: `Set this to an array of strings representing the AST context\n(or objects with optional \\`context\\` and \\`comment\\` properties) where you wish\nthe rule to be applied.\n\n\\`context\\` defaults to \\`any\\` and \\`comment\\` defaults to no specific comment context.\n\nOverrides the default contexts (\\`ArrowFunctionExpression\\`, \\`FunctionDeclaration\\`,\n\\`FunctionExpression\\`).`,\n items: {\n anyOf: [\n {\n type: 'string',\n },\n {\n additionalProperties: false,\n properties: {\n comment: {\n type: 'string',\n },\n context: {\n type: 'string',\n },\n },\n type: 'object',\n },\n ],\n },\n type: 'array',\n },\n exemptedBy: {\n description: `Array of tags (e.g., \\`['type']\\`) whose presence on the\ndocument block avoids the need for a \\`@rejects\\`. Defaults to an array\nwith \\`abstract\\`, \\`virtual\\`, and \\`type\\`. If you set this array, it will overwrite the default,\nso be sure to add back those tags if you wish their presence to cause\nexemption of the rule.`,\n items: {\n type: 'string',\n },\n type: 'array',\n },\n },\n type: 'object',\n },\n ],\n type: 'suggestion',\n },\n});\n"],"mappings":"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","ignoreList":[]}
package/package.json CHANGED
@@ -192,5 +192,5 @@
192
192
  "test-cov": "TIMING=1 c8 --reporter text pnpm run test-no-cov",
193
193
  "test-index": "pnpm run test-no-cov test/rules/index.js"
194
194
  },
195
- "version": "61.4.0"
195
+ "version": "61.4.1"
196
196
  }
@@ -9,6 +9,27 @@ import {
9
9
  util,
10
10
  } from 'comment-parser';
11
11
 
12
+ /**
13
+ * Detects if a line starts with a markdown list marker
14
+ * Supports: -, *, numbered lists (1., 2., etc.)
15
+ * This explicitly excludes hyphens that are part of JSDoc tag syntax
16
+ * @param {string} text - The text to check
17
+ * @param {boolean} isFirstLineOfTag - True if this is the first line (tag line)
18
+ * @returns {boolean} - True if the text starts with a list marker
19
+ */
20
+ const startsWithListMarker = (text, isFirstLineOfTag = false) => {
21
+ // On the first line of a tag, the hyphen is typically the JSDoc separator,
22
+ // not a list marker
23
+ if (isFirstLineOfTag) {
24
+ return false;
25
+ }
26
+
27
+ // Match lines that start with optional whitespace, then a list marker
28
+ // - or * followed by a space
29
+ // or a number followed by . or ) and a space
30
+ return /^\s*(?:[\-*]|\d+(?:\.|\)))\s+/v.test(text);
31
+ };
32
+
12
33
  /**
13
34
  * @typedef {{
14
35
  * hasNoTypes: boolean,
@@ -144,6 +165,59 @@ const space = (len) => {
144
165
  return ''.padStart(len, ' ');
145
166
  };
146
167
 
168
+ /**
169
+ * Check if a tag or any of its lines contain list markers
170
+ * @param {import('./iterateJsdoc.js').Integer} index - Current line index
171
+ * @param {import('comment-parser').Line[]} source - All source lines
172
+ * @returns {{hasListMarker: boolean, tagStartIndex: import('./iterateJsdoc.js').Integer}}
173
+ */
174
+ const checkForListMarkers = (index, source) => {
175
+ let hasListMarker = false;
176
+ let tagStartIndex = index;
177
+ while (tagStartIndex > 0 && source[tagStartIndex].tokens.tag === '') {
178
+ tagStartIndex--;
179
+ }
180
+
181
+ for (let idx = tagStartIndex; idx <= index; idx++) {
182
+ const isFirstLine = (idx === tagStartIndex);
183
+ if (source[idx]?.tokens?.description && startsWithListMarker(source[idx].tokens.description, isFirstLine)) {
184
+ hasListMarker = true;
185
+ break;
186
+ }
187
+ }
188
+
189
+ return {
190
+ hasListMarker,
191
+ tagStartIndex,
192
+ };
193
+ };
194
+
195
+ /**
196
+ * Calculate extra indentation for list items relative to the first continuation line
197
+ * @param {import('./iterateJsdoc.js').Integer} index - Current line index
198
+ * @param {import('./iterateJsdoc.js').Integer} tagStartIndex - Index of the tag line
199
+ * @param {import('comment-parser').Line[]} source - All source lines
200
+ * @returns {string} - Extra indentation spaces
201
+ */
202
+ const calculateListExtraIndent = (index, tagStartIndex, source) => {
203
+ // Find the first continuation line to use as baseline
204
+ let firstContinuationIndent = null;
205
+ for (let idx = tagStartIndex + 1; idx < source.length; idx++) {
206
+ if (source[idx].tokens.description && !source[idx].tokens.tag) {
207
+ firstContinuationIndent = source[idx].tokens.postDelimiter.length;
208
+ break;
209
+ }
210
+ }
211
+
212
+ // Calculate the extra indentation of current line relative to the first continuation line
213
+ const currentOriginalIndent = source[index].tokens.postDelimiter.length;
214
+ const extraIndent = firstContinuationIndent !== null && currentOriginalIndent > firstContinuationIndent ?
215
+ ' '.repeat(currentOriginalIndent - firstContinuationIndent) :
216
+ '';
217
+
218
+ return extraIndent;
219
+ };
220
+
147
221
  /**
148
222
  * @param {{
149
223
  * customSpacings: import('../src/rules/checkLineAlignment.js').CustomSpacings,
@@ -316,8 +390,20 @@ const alignTransform = ({
316
390
  // Not align.
317
391
  if (shouldAlign(tags, index, source)) {
318
392
  alignTokens(tokens, typelessInfo);
393
+
319
394
  if (!disableWrapIndent && indentTag) {
320
- tokens.postDelimiter += wrapIndent;
395
+ const {
396
+ hasListMarker,
397
+ tagStartIndex,
398
+ } = checkForListMarkers(index, source);
399
+
400
+ if (hasListMarker && index > tagStartIndex) {
401
+ const extraIndent = calculateListExtraIndent(index, tagStartIndex, source);
402
+ tokens.postDelimiter += wrapIndent + extraIndent;
403
+ } else {
404
+ // Normal case: add wrapIndent after the aligned delimiter
405
+ tokens.postDelimiter += wrapIndent;
406
+ }
321
407
  }
322
408
  }
323
409
 
@@ -8,6 +8,54 @@ const {
8
8
  flow: commentFlow,
9
9
  } = transforms;
10
10
 
11
+ /**
12
+ * Detects if a line starts with a markdown list marker
13
+ * Supports: -, *, numbered lists (1., 2., etc.)
14
+ * This explicitly excludes hyphens that are part of JSDoc tag syntax
15
+ * @param {string} text - The text to check
16
+ * @param {boolean} isFirstLineOfTag - True if this is the first line (tag line)
17
+ * @returns {boolean} - True if the text starts with a list marker
18
+ */
19
+ const startsWithListMarker = (text, isFirstLineOfTag = false) => {
20
+ // On the first line of a tag, the hyphen is typically the JSDoc separator,
21
+ // not a list marker
22
+ if (isFirstLineOfTag) {
23
+ return false;
24
+ }
25
+
26
+ // Match lines that start with optional whitespace, then a list marker
27
+ // - or * followed by a space
28
+ // or a number followed by . or ) and a space
29
+ return /^\s*(?:[\-*]|\d+(?:\.|\)))\s+/v.test(text);
30
+ };
31
+
32
+ /**
33
+ * Checks if we should allow extra indentation beyond wrapIndent.
34
+ * This is true for list continuation lines (lines with more indent than wrapIndent
35
+ * that follow a list item).
36
+ * @param {import('comment-parser').Spec} tag - The tag being checked
37
+ * @param {import('../iterateJsdoc.js').Integer} idx - Current line index (0-based in tag.source.slice(1))
38
+ * @returns {boolean} - True if extra indentation should be allowed
39
+ */
40
+ const shouldAllowExtraIndent = (tag, idx) => {
41
+ // Check if any previous line in this tag had a list marker
42
+ // idx is 0-based in the continuation lines (tag.source.slice(1))
43
+ // So tag.source[0] is the tag line, tag.source[idx+1] is current line
44
+ let hasSeenListMarker = false;
45
+
46
+ // Check all lines from the tag line onwards
47
+ for (let lineIdx = 0; lineIdx <= idx + 1; lineIdx++) {
48
+ const line = tag.source[lineIdx];
49
+ const isFirstLine = lineIdx === 0;
50
+ if (line?.tokens?.description && startsWithListMarker(line.tokens.description, isFirstLine)) {
51
+ hasSeenListMarker = true;
52
+ break;
53
+ }
54
+ }
55
+
56
+ return hasSeenListMarker;
57
+ };
58
+
11
59
  /**
12
60
  * @typedef {{
13
61
  * postDelimiter: import('../iterateJsdoc.js').Integer,
@@ -298,7 +346,17 @@ export default iterateJsdoc(({
298
346
  }
299
347
 
300
348
  // Don't include a single separating space/tab
301
- if (!disableWrapIndent && tokens.postDelimiter.slice(1) !== wrapIndent) {
349
+ const actualIndent = tokens.postDelimiter.slice(1);
350
+ const hasCorrectWrapIndent = actualIndent === wrapIndent;
351
+
352
+ // Allow extra indentation if this line or previous lines contain list markers
353
+ // This preserves nested list structure
354
+ const hasExtraIndent = actualIndent.length > wrapIndent.length &&
355
+ actualIndent.startsWith(wrapIndent);
356
+ const isInListContext = shouldAllowExtraIndent(tag, idx - 1);
357
+
358
+ if (!disableWrapIndent && !hasCorrectWrapIndent &&
359
+ !(hasExtraIndent && isInListContext)) {
302
360
  utils.reportJSDoc('Expected wrap indent', {
303
361
  line: tag.source[0].number + idx,
304
362
  }, () => {
@@ -4,10 +4,11 @@ import iterateJsdoc from '../iterateJsdoc.js';
4
4
  * Checks if a node or its children contain Promise rejection patterns
5
5
  * @param {import('eslint').Rule.Node} node
6
6
  * @param {boolean} [innerFunction]
7
+ * @param {boolean} [isAsync]
7
8
  * @returns {boolean}
8
9
  */
9
10
  // eslint-disable-next-line complexity -- Temporary
10
- const hasRejectValue = (node, innerFunction) => {
11
+ const hasRejectValue = (node, innerFunction, isAsync) => {
11
12
  if (!node) {
12
13
  return false;
13
14
  }
@@ -19,16 +20,19 @@ const hasRejectValue = (node, innerFunction) => {
19
20
  // For inner functions in async contexts, check if they throw
20
21
  // (they could be called and cause rejection)
21
22
  if (innerFunction) {
22
- // Check the inner function's body for throw statements
23
- return hasRejectValue(/** @type {import('eslint').Rule.Node} */ (node.body), false);
23
+ // Check inner functions for throws - if called from async context, throws become rejections
24
+ const innerIsAsync = node.async;
25
+ // Pass isAsync=true if the inner function is async OR if we're already in an async context
26
+ return hasRejectValue(/** @type {import('eslint').Rule.Node} */ (node.body), false, innerIsAsync || isAsync);
24
27
  }
25
28
 
26
- return hasRejectValue(/** @type {import('eslint').Rule.Node} */ (node.body), true);
29
+ // This is the top-level function we're checking
30
+ return hasRejectValue(/** @type {import('eslint').Rule.Node} */ (node.body), true, node.async);
27
31
  }
28
32
 
29
33
  case 'BlockStatement': {
30
34
  return node.body.some((bodyNode) => {
31
- return hasRejectValue(/** @type {import('eslint').Rule.Node} */ (bodyNode), innerFunction);
35
+ return hasRejectValue(/** @type {import('eslint').Rule.Node} */ (bodyNode), innerFunction, isAsync);
32
36
  });
33
37
  }
34
38
 
@@ -65,15 +69,15 @@ const hasRejectValue = (node, innerFunction) => {
65
69
  case 'WhileStatement':
66
70
 
67
71
  case 'WithStatement': {
68
- return hasRejectValue(/** @type {import('eslint').Rule.Node} */ (node.body), innerFunction);
72
+ return hasRejectValue(/** @type {import('eslint').Rule.Node} */ (node.body), innerFunction, isAsync);
69
73
  }
70
74
 
71
75
  case 'ExpressionStatement': {
72
- return hasRejectValue(/** @type {import('eslint').Rule.Node} */ (node.expression), innerFunction);
76
+ return hasRejectValue(/** @type {import('eslint').Rule.Node} */ (node.expression), innerFunction, isAsync);
73
77
  }
74
78
 
75
79
  case 'IfStatement': {
76
- return hasRejectValue(/** @type {import('eslint').Rule.Node} */ (node.consequent), innerFunction) || hasRejectValue(/** @type {import('eslint').Rule.Node} */ (node.alternate), innerFunction);
80
+ return hasRejectValue(/** @type {import('eslint').Rule.Node} */ (node.consequent), innerFunction, isAsync) || hasRejectValue(/** @type {import('eslint').Rule.Node} */ (node.alternate), innerFunction, isAsync);
77
81
  }
78
82
 
79
83
  case 'NewExpression': {
@@ -82,7 +86,7 @@ const hasRejectValue = (node, innerFunction) => {
82
86
  const executor = node.arguments[0];
83
87
  if (executor.type === 'ArrowFunctionExpression' || executor.type === 'FunctionExpression') {
84
88
  // Check if the executor has reject() calls
85
- return hasRejectValue(/** @type {import('eslint').Rule.Node} */ (executor.body), false);
89
+ return hasRejectValue(/** @type {import('eslint').Rule.Node} */ (executor.body), false, false);
86
90
  }
87
91
  }
88
92
 
@@ -91,7 +95,7 @@ const hasRejectValue = (node, innerFunction) => {
91
95
 
92
96
  case 'ReturnStatement': {
93
97
  if (node.argument) {
94
- return hasRejectValue(/** @type {import('eslint').Rule.Node} */ (node.argument), innerFunction);
98
+ return hasRejectValue(/** @type {import('eslint').Rule.Node} */ (node.argument), innerFunction, isAsync);
95
99
  }
96
100
 
97
101
  return false;
@@ -101,7 +105,7 @@ const hasRejectValue = (node, innerFunction) => {
101
105
  return node.cases.some(
102
106
  (someCase) => {
103
107
  return someCase.consequent.some((nde) => {
104
- return hasRejectValue(/** @type {import('eslint').Rule.Node} */ (nde), innerFunction);
108
+ return hasRejectValue(/** @type {import('eslint').Rule.Node} */ (nde), innerFunction, isAsync);
105
109
  });
106
110
  },
107
111
  );
@@ -109,12 +113,12 @@ const hasRejectValue = (node, innerFunction) => {
109
113
 
110
114
  // Throw statements in async functions become rejections
111
115
  case 'ThrowStatement': {
112
- return true;
116
+ return isAsync === true;
113
117
  }
114
118
 
115
119
  case 'TryStatement': {
116
- return hasRejectValue(/** @type {import('eslint').Rule.Node} */ (node.handler && node.handler.body), innerFunction) ||
117
- hasRejectValue(/** @type {import('eslint').Rule.Node} */ (node.finalizer), innerFunction);
120
+ return hasRejectValue(/** @type {import('eslint').Rule.Node} */ (node.handler && node.handler.body), innerFunction, isAsync) ||
121
+ hasRejectValue(/** @type {import('eslint').Rule.Node} */ (node.finalizer), innerFunction, isAsync);
118
122
  }
119
123
 
120
124
  default: {