@@ -9,6 +9,27 @@ import {
99 util ,
1010} from 'comment-parser' ;
1111
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+
1233/**
1334 * @typedef {{
1435 * hasNoTypes: boolean,
@@ -144,6 +165,59 @@ const space = (len) => {
144165 return '' . padStart ( len , ' ' ) ;
145166} ;
146167
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+
147221/**
148222 * @param {{
149223 * customSpacings: import('../src/rules/checkLineAlignment.js').CustomSpacings,
@@ -316,8 +390,20 @@ const alignTransform = ({
316390 // Not align.
317391 if ( shouldAlign ( tags , index , source ) ) {
318392 alignTokens ( tokens , typelessInfo ) ;
393+
319394 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+ }
321407 }
322408 }
323409
0 commit comments