@@ -47,9 +47,9 @@ func TestCommentFormatting(t *testing.T) {
4747 firstFormatted := applyBulkEdits (originalText , edits )
4848
4949 // Check that the asterisk is not corrupted
50- assert .Check (t , ! contains (firstFormatted , "*/\n /" ), "should not corrupt */ to /" )
51- assert .Check (t , contains (firstFormatted , "*/" ), "should preserve */ token" )
52- assert .Check (t , contains (firstFormatted , "async" ), "should preserve async keyword" )
50+ assert .Check (t , ! strings . Contains (firstFormatted , "*/\n /" ), "should not corrupt */ to /" )
51+ assert .Check (t , strings . Contains (firstFormatted , "*/" ), "should preserve */ token" )
52+ assert .Check (t , strings . Contains (firstFormatted , "async" ), "should preserve async keyword" )
5353
5454 // Apply formatting a second time to test stability
5555 sourceFile2 := parser .ParseSourceFile (ast.SourceFileParseOptions {
@@ -61,8 +61,8 @@ func TestCommentFormatting(t *testing.T) {
6161 secondFormatted := applyBulkEdits (firstFormatted , edits2 )
6262
6363 // Check that second formatting doesn't introduce corruption
64- assert .Check (t , ! contains (secondFormatted , " sync x()" ), "should not corrupt async to sync" )
65- assert .Check (t , contains (secondFormatted , "async" ), "should preserve async keyword on second pass" )
64+ assert .Check (t , ! strings . Contains (secondFormatted , " sync x()" ), "should not corrupt async to sync" )
65+ assert .Check (t , strings . Contains (secondFormatted , "async" ), "should preserve async keyword on second pass" )
6666 })
6767
6868 t .Run ("format JSDoc with tab indentation" , func (t * testing.T ) {
@@ -95,14 +95,149 @@ func TestCommentFormatting(t *testing.T) {
9595 // Check that tabs come before spaces (not spaces before tabs)
9696 // The comment lines should have format: tab followed by space and asterisk
9797 // NOT: space followed by tab and asterisk
98- assert .Check (t , ! contains (formatted , " \t *" ), "should not have space before tab before asterisk" )
99- assert .Check (t , contains (formatted , "\t *" ), "should have tab before space before asterisk" )
98+ assert .Check (t , ! strings . Contains (formatted , " \t *" ), "should not have space before tab before asterisk" )
99+ assert .Check (t , strings . Contains (formatted , "\t *" ), "should have tab before space before asterisk" )
100100
101101 // Verify console.log is properly indented with tabs
102- assert .Check (t , contains (formatted , "\t \t console.log" ), "console.log should be indented with two tabs" )
102+ assert .Check (t , strings .Contains (formatted , "\t \t console.log" ), "console.log should be indented with two tabs" )
103+ })
104+
105+ t .Run ("format comment inside multi-line argument list" , func (t * testing.T ) {
106+ t .Parallel ()
107+ ctx := format .WithFormatCodeSettings (t .Context (), & format.FormatCodeSettings {
108+ EditorSettings : format.EditorSettings {
109+ TabSize : 4 ,
110+ IndentSize : 4 ,
111+ BaseIndentSize : 0 ,
112+ NewLineCharacter : "\n " ,
113+ ConvertTabsToSpaces : false , // Use tabs
114+ IndentStyle : format .IndentStyleSmart ,
115+ TrimTrailingWhitespace : true ,
116+ },
117+ InsertSpaceBeforeTypeAnnotation : core .TSTrue ,
118+ }, "\n " )
119+
120+ // Original code with proper indentation
121+ originalText := "console.log(\n \t \" a\" ,\n \t // the second arg\n \t \" b\" \n );"
122+
123+ sourceFile := parser .ParseSourceFile (ast.SourceFileParseOptions {
124+ FileName : "/test.ts" ,
125+ Path : "/test.ts" ,
126+ }, originalText , core .ScriptKindTS )
127+
128+ // Apply formatting
129+ edits := format .FormatDocument (ctx , sourceFile )
130+ formatted := applyBulkEdits (originalText , edits )
131+
132+ // The comment should remain indented with a tab
133+ assert .Check (t , strings .Contains (formatted , "\t // the second arg" ), "comment should be indented with tab" )
134+ // The comment should not lose its indentation
135+ assert .Check (t , ! strings .Contains (formatted , "\n // the second arg" ), "comment should not lose indentation" )
136+ })
137+
138+ t .Run ("format comment in chained method calls" , func (t * testing.T ) {
139+ t .Parallel ()
140+ ctx := format .WithFormatCodeSettings (t .Context (), & format.FormatCodeSettings {
141+ EditorSettings : format.EditorSettings {
142+ TabSize : 4 ,
143+ IndentSize : 4 ,
144+ BaseIndentSize : 0 ,
145+ NewLineCharacter : "\n " ,
146+ ConvertTabsToSpaces : false , // Use tabs
147+ IndentStyle : format .IndentStyleSmart ,
148+ TrimTrailingWhitespace : true ,
149+ },
150+ InsertSpaceBeforeTypeAnnotation : core .TSTrue ,
151+ }, "\n " )
152+
153+ // Original code with proper indentation
154+ originalText := "foo\n \t .bar()\n \t // A second call\n \t .baz();"
155+
156+ sourceFile := parser .ParseSourceFile (ast.SourceFileParseOptions {
157+ FileName : "/test.ts" ,
158+ Path : "/test.ts" ,
159+ }, originalText , core .ScriptKindTS )
160+
161+ // Apply formatting
162+ edits := format .FormatDocument (ctx , sourceFile )
163+ formatted := applyBulkEdits (originalText , edits )
164+
165+ // The comment should remain indented
166+ assert .Check (t , strings .Contains (formatted , "\t // A second call" ) || strings .Contains (formatted , " // A second call" ), "comment should be indented" )
167+ // The comment should not lose its indentation
168+ assert .Check (t , ! strings .Contains (formatted , "\n // A second call" ), "comment should not lose indentation" )
169+ })
170+
171+ // Regression test for issue #1928 - panic when formatting chained method call with comment
172+ t .Run ("format chained method call with comment (issue #1928)" , func (t * testing.T ) {
173+ t .Parallel ()
174+ ctx := format .WithFormatCodeSettings (t .Context (), & format.FormatCodeSettings {
175+ EditorSettings : format.EditorSettings {
176+ TabSize : 4 ,
177+ IndentSize : 4 ,
178+ BaseIndentSize : 0 ,
179+ NewLineCharacter : "\n " ,
180+ ConvertTabsToSpaces : false , // Use tabs
181+ IndentStyle : format .IndentStyleSmart ,
182+ TrimTrailingWhitespace : true ,
183+ },
184+ InsertSpaceBeforeTypeAnnotation : core .TSTrue ,
185+ }, "\n " )
186+
187+ // This code previously caused a panic with "strings: negative Repeat count"
188+ // because tokenIndentation was -1 and was being used directly for indentation
189+ originalText := "foo\n \t .bar()\n \t // A second call\n \t .baz();"
190+
191+ sourceFile := parser .ParseSourceFile (ast.SourceFileParseOptions {
192+ FileName : "/test.ts" ,
193+ Path : "/test.ts" ,
194+ }, originalText , core .ScriptKindTS )
195+
196+ // Apply formatting - should not panic
197+ edits := format .FormatDocument (ctx , sourceFile )
198+ formatted := applyBulkEdits (originalText , edits )
199+
200+ // Verify the comment maintains proper indentation and doesn't lose it
201+ assert .Check (t , strings .Contains (formatted , "\t // A second call" ) || strings .Contains (formatted , " // A second call" ), "comment should be indented" )
202+ assert .Check (t , ! strings .Contains (formatted , "\n // A second call" ), "comment should not be at column 0" )
103203 })
104204}
105205
106- func contains (s , substr string ) bool {
107- return len (substr ) > 0 && strings .Contains (s , substr )
206+ func TestSliceBoundsPanic (t * testing.T ) {
207+ t .Parallel ()
208+
209+ t .Run ("format code with trailing semicolon should not panic" , func (t * testing.T ) {
210+ t .Parallel ()
211+ ctx := format .WithFormatCodeSettings (t .Context (), & format.FormatCodeSettings {
212+ EditorSettings : format.EditorSettings {
213+ TabSize : 4 ,
214+ IndentSize : 4 ,
215+ BaseIndentSize : 4 ,
216+ NewLineCharacter : "\n " ,
217+ ConvertTabsToSpaces : true ,
218+ IndentStyle : format .IndentStyleSmart ,
219+ TrimTrailingWhitespace : true ,
220+ },
221+ InsertSpaceBeforeTypeAnnotation : core .TSTrue ,
222+ }, "\n " )
223+
224+ // Code from the issue that causes slice bounds panic
225+ originalText := `const _enableDisposeWithListenerWarning = false
226+ // || Boolean("TRUE") // causes a linter warning so that it cannot be pushed
227+ ;
228+ `
229+
230+ sourceFile := parser .ParseSourceFile (ast.SourceFileParseOptions {
231+ FileName : "/test.ts" ,
232+ Path : "/test.ts" ,
233+ }, originalText , core .ScriptKindTS )
234+
235+ // This should not panic
236+ edits := format .FormatDocument (ctx , sourceFile )
237+ formatted := applyBulkEdits (originalText , edits )
238+
239+ // Basic sanity checks
240+ assert .Check (t , len (formatted ) > 0 , "formatted text should not be empty" )
241+ assert .Check (t , strings .Contains (formatted , "_enableDisposeWithListenerWarning" ), "should preserve variable name" )
242+ })
108243}
0 commit comments