Skip to content

Commit 675fd75

Browse files
CopilotjakebaileyDanielRosenwasserweswigham
authored
Fix comment formatting bug that mangled */ tokens (#1401)
Co-authored-by: copilot-swe-agent[bot] <[email protected]> Co-authored-by: jakebailey <[email protected]> Co-authored-by: DanielRosenwasser <[email protected]> Co-authored-by: weswigham <[email protected]>
1 parent 2ff976e commit 675fd75

File tree

2 files changed

+72
-1
lines changed

2 files changed

+72
-1
lines changed

internal/format/comment_test.go

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
package format_test
2+
3+
import (
4+
"strings"
5+
"testing"
6+
7+
"github.com/microsoft/typescript-go/internal/ast"
8+
"github.com/microsoft/typescript-go/internal/core"
9+
"github.com/microsoft/typescript-go/internal/format"
10+
"github.com/microsoft/typescript-go/internal/parser"
11+
"gotest.tools/v3/assert"
12+
)
13+
14+
func TestCommentFormatting(t *testing.T) {
15+
t.Parallel()
16+
17+
t.Run("format comment issue reproduction", func(t *testing.T) {
18+
t.Parallel()
19+
ctx := format.WithFormatCodeSettings(t.Context(), &format.FormatCodeSettings{
20+
EditorSettings: format.EditorSettings{
21+
TabSize: 4,
22+
IndentSize: 4,
23+
BaseIndentSize: 4,
24+
NewLineCharacter: "\n",
25+
ConvertTabsToSpaces: true,
26+
IndentStyle: format.IndentStyleSmart,
27+
TrimTrailingWhitespace: true,
28+
},
29+
InsertSpaceBeforeTypeAnnotation: core.TSTrue,
30+
}, "\n")
31+
32+
// Original code that causes the bug
33+
originalText := `class C {
34+
/**
35+
*
36+
*/
37+
async x() {}
38+
}`
39+
40+
sourceFile := parser.ParseSourceFile(ast.SourceFileParseOptions{
41+
FileName: "/test.ts",
42+
Path: "/test.ts",
43+
}, originalText, core.ScriptKindTS)
44+
45+
// Apply formatting once
46+
edits := format.FormatDocument(ctx, sourceFile)
47+
firstFormatted := applyBulkEdits(originalText, edits)
48+
49+
// 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")
53+
54+
// Apply formatting a second time to test stability
55+
sourceFile2 := parser.ParseSourceFile(ast.SourceFileParseOptions{
56+
FileName: "/test.ts",
57+
Path: "/test.ts",
58+
}, firstFormatted, core.ScriptKindTS)
59+
60+
edits2 := format.FormatDocument(ctx, sourceFile2)
61+
secondFormatted := applyBulkEdits(firstFormatted, edits2)
62+
63+
// 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")
66+
})
67+
}
68+
69+
func contains(s, substr string) bool {
70+
return len(substr) > 0 && strings.Contains(s, substr)
71+
}

internal/format/span.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -922,7 +922,7 @@ func (w *formatSpanWorker) indentMultilineComment(commentRange core.TextRange, i
922922
for line := startLine; line < endLine; line++ {
923923
endOfLine := scanner.GetEndLinePosition(w.sourceFile, line)
924924
parts = append(parts, core.NewTextRange(startPos, endOfLine))
925-
startPos = int(scanner.GetLineStarts(w.sourceFile)[line])
925+
startPos = int(scanner.GetLineStarts(w.sourceFile)[line+1])
926926
}
927927

928928
if indentFinalLine {

0 commit comments

Comments
 (0)