@@ -25,6 +25,17 @@ const maskCodeBlocks = (str) => {
2525 } ) ;
2626} ;
2727
28+ /**
29+ * @param {string[] } lines
30+ * @param {number } lineIndex
31+ * @returns {number }
32+ */
33+ const getLineNumber = ( lines , lineIndex ) => {
34+ const precedingText = lines . slice ( 0 , lineIndex ) . join ( '\n' ) ;
35+ const lineBreaks = precedingText . match ( / \n / gv) || [ ] ;
36+ return lineBreaks . length + 1 ;
37+ } ;
38+
2839export default iterateJsdoc ( ( {
2940 context,
3041 jsdocNode,
@@ -47,47 +58,64 @@ export default iterateJsdoc(({
4758 // and the very first line of the main description
4859 const lines = text . split ( '\n' ) ;
4960 let hasSeenContent = false ;
61+ let currentSectionIndent = null ;
5062
5163 for ( const [
5264 lineIndex ,
5365 line ,
5466 ] of lines . entries ( ) ) {
5567 // Check for indentation (two or more spaces after *)
56- const indentMatch = line . match ( / ^ (?: \/ ? \* * | [ \t ] * ) \* ( [ \t ] { 2 , } ) / gv ) ;
68+ const indentMatch = line . match ( / ^ (?: \/ ? \* * | [ \t ] * ) \* ( [ \t ] { 2 , } ) / v ) ;
5769
5870 if ( indentMatch ) {
5971 // Check what comes after the indentation
6072 const afterIndent = line . slice ( indentMatch [ 0 ] . length ) ;
73+ const indentAmount = indentMatch [ 1 ] . length ;
6174
6275 // If this is a tag line with indentation, always report
6376 if ( / ^ @ \w + / v. test ( afterIndent ) ) {
64- // Count newlines before this line
65- const precedingText = lines . slice ( 0 , lineIndex ) . join ( '\n' ) ;
66- const lineBreaks = precedingText . match ( / \n / gv) || [ ] ;
6777 report ( 'There must be no indentation.' , null , {
68- line : lineBreaks . length + 1 ,
78+ line : getLineNumber ( lines , lineIndex ) ,
6979 } ) ;
7080 return ;
7181 }
7282
7383 // If we haven't seen any content yet (main description first line) and there's content, report
7484 if ( ! hasSeenContent && afterIndent . trim ( ) . length > 0 ) {
75- // Count newlines before this line
76- const precedingText = lines . slice ( 0 , lineIndex ) . join ( '\n' ) ;
77- const lineBreaks = precedingText . match ( / \n / gv) || [ ] ;
7885 report ( 'There must be no indentation.' , null , {
79- line : lineBreaks . length + 1 ,
86+ line : getLineNumber ( lines , lineIndex ) ,
8087 } ) ;
8188 return ;
8289 }
8390
84- // Otherwise, allow it (continuation lines)
91+ // For continuation lines, check consistency
92+ if ( hasSeenContent && afterIndent . trim ( ) . length > 0 ) {
93+ if ( currentSectionIndent === null ) {
94+ // First indented line in this section, set the indent level
95+ currentSectionIndent = indentAmount ;
96+ } else if ( indentAmount < currentSectionIndent ) {
97+ // Indentation is less than the established level (inconsistent)
98+ report ( 'There must be no indentation.' , null , {
99+ line : getLineNumber ( lines , lineIndex ) ,
100+ } ) ;
101+ return ;
102+ }
103+ }
104+ } else if ( / ^ \s * \* \s + \S / v. test ( line ) ) {
105+ // No indentation on this line, reset section indent tracking
106+ // (unless it's just whitespace or a closing comment)
107+ currentSectionIndent = null ;
85108 }
86109
87110 // Track if we've seen any content (non-whitespace after the *)
88111 if ( / ^ \s * \* \s + \S / v. test ( line ) ) {
89112 hasSeenContent = true ;
90113 }
114+
115+ // Reset section indent when we encounter a tag
116+ if ( / @ \w + / v. test ( line ) ) {
117+ currentSectionIndent = null ;
118+ }
91119 }
92120 } else {
93121 const reg = / ^ (?: \/ ? \* * | [ \t ] * ) \* [ \t ] { 2 } / gmv;
0 commit comments