From c4292869c932affe19f6d6e6e2ef0533811d2454 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 22 Oct 2025 18:40:12 +0000 Subject: [PATCH 1/3] Initial plan From 85973bf61358fcba0d23816f0e0095f57be073ea Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 22 Oct 2025 18:55:26 +0000 Subject: [PATCH 2/3] Add failing test and fix slice bounds panic in formatting Co-authored-by: jakebailey <5341706+jakebailey@users.noreply.github.com> --- internal/format/comment_test.go | 39 +++++++++++++++++++++++++++++++++ internal/format/span.go | 13 ++++++++++- 2 files changed, 51 insertions(+), 1 deletion(-) diff --git a/internal/format/comment_test.go b/internal/format/comment_test.go index 50762ab56d..ddd4dce876 100644 --- a/internal/format/comment_test.go +++ b/internal/format/comment_test.go @@ -106,3 +106,42 @@ func TestCommentFormatting(t *testing.T) { func contains(s, substr string) bool { return len(substr) > 0 && strings.Contains(s, substr) } + +func TestSliceBoundsPanic(t *testing.T) { + t.Parallel() + + t.Run("format code with trailing semicolon should not panic", func(t *testing.T) { + t.Parallel() + ctx := format.WithFormatCodeSettings(t.Context(), &format.FormatCodeSettings{ + EditorSettings: format.EditorSettings{ + TabSize: 4, + IndentSize: 4, + BaseIndentSize: 4, + NewLineCharacter: "\n", + ConvertTabsToSpaces: true, + IndentStyle: format.IndentStyleSmart, + TrimTrailingWhitespace: true, + }, + InsertSpaceBeforeTypeAnnotation: core.TSTrue, + }, "\n") + + // Code from the issue that causes slice bounds panic + originalText := `const _enableDisposeWithListenerWarning = false + // || Boolean("TRUE") // causes a linter warning so that it cannot be pushed + ; +` + + sourceFile := parser.ParseSourceFile(ast.SourceFileParseOptions{ + FileName: "/test.ts", + Path: "/test.ts", + }, originalText, core.ScriptKindTS) + + // This should not panic + edits := format.FormatDocument(ctx, sourceFile) + formatted := applyBulkEdits(originalText, edits) + + // Basic sanity checks + assert.Check(t, len(formatted) > 0, "formatted text should not be empty") + assert.Check(t, contains(formatted, "_enableDisposeWithListenerWarning"), "should preserve variable name") + }) +} diff --git a/internal/format/span.go b/internal/format/span.go index c8d0096bed..98ab15d3b2 100644 --- a/internal/format/span.go +++ b/internal/format/span.go @@ -883,7 +883,12 @@ func (w *formatSpanWorker) characterToColumn(startLinePosition int, characterInL } func (w *formatSpanWorker) indentationIsDifferent(indentationString string, startLinePosition int) bool { - return indentationString != w.sourceFile.Text()[startLinePosition:startLinePosition+len(indentationString)] + // Check bounds to prevent slice panic + endPosition := startLinePosition + len(indentationString) + if endPosition > len(w.sourceFile.Text()) { + return true + } + return indentationString != w.sourceFile.Text()[startLinePosition:endPosition] } func (w *formatSpanWorker) indentTriviaItems(trivia []TextRangeWithKind, commentIndentation int, indentNextTokenOrTrivia bool, indentSingleLine func(item TextRangeWithKind)) bool { @@ -969,6 +974,12 @@ func (w *formatSpanWorker) indentMultilineComment(commentRange core.TextRange, i } func getIndentationString(indentation int, options *FormatCodeSettings) string { + // Handle negative indentation (e.g., Constants.Unknown = -1) + // Return empty string like TypeScript's repeatString does when count is negative + if indentation < 0 { + return "" + } + // go's `strings.Repeat` already has static, global caching for repeated tabs and spaces, so there's no need to cache here like in strada if !options.ConvertTabsToSpaces { tabs := int(math.Floor(float64(indentation) / float64(options.TabSize))) From 15c35f4cac24fd26e9ae006756cd3aa06ac76d2d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 22 Oct 2025 18:57:42 +0000 Subject: [PATCH 3/3] Run formatter to fix trailing whitespace Co-authored-by: jakebailey <5341706+jakebailey@users.noreply.github.com> --- internal/format/span.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/format/span.go b/internal/format/span.go index 98ab15d3b2..a44b5764b6 100644 --- a/internal/format/span.go +++ b/internal/format/span.go @@ -979,7 +979,7 @@ func getIndentationString(indentation int, options *FormatCodeSettings) string { if indentation < 0 { return "" } - + // go's `strings.Repeat` already has static, global caching for repeated tabs and spaces, so there's no need to cache here like in strada if !options.ConvertTabsToSpaces { tabs := int(math.Floor(float64(indentation) / float64(options.TabSize)))