package compiler_test import ( "context" "fmt" "strings" "testing" "github.com/microsoft/typescript-go/internal/bundled" "github.com/microsoft/typescript-go/internal/compiler" "github.com/microsoft/typescript-go/internal/core" "github.com/microsoft/typescript-go/internal/tsoptions" "github.com/microsoft/typescript-go/internal/vfs/vfstest" ) // generateLongLineTS generates TypeScript source code that produces a single very long line. // This simulates generated code (e.g., from code generators) that has no line breaks, // which triggers O(n²) behavior in source map generation due to // GetECMALineAndUTF16CharacterOfPosition scanning from line start for each position. func generateLongLineTS(numProperties int) string { // Build a large object literal all on one line, with no line breaks. var b strings.Builder b.WriteString("export const data: Record = {") for i := range numProperties { if i > 0 { b.WriteString(", ") } fmt.Fprintf(&b, "prop_%d: %d", i, i) } b.WriteString("};") return b.String() } func BenchmarkEmitLongLines(b *testing.B) { if !bundled.Embedded { b.Skip("bundled files are not embedded") } for _, numProps := range []int{1000, 5000, 10000} { b.Run(fmt.Sprintf("props_%d", numProps), func(b *testing.B) { source := generateLongLineTS(numProps) fs := vfstest.FromMap(map[string]string{ "/dev/src/index.ts": source, }, true /*useCaseSensitiveFileNames*/) fs = bundled.WrapFS(fs) opts := core.CompilerOptions{ Target: core.ScriptTargetES2015, SourceMap: core.TSTrue, OutDir: "/dev/out", } host := compiler.NewCompilerHost("/dev/src", fs, bundled.LibPath(), nil, nil) p := compiler.NewProgram(compiler.ProgramOptions{ Config: &tsoptions.ParsedCommandLine{ ParsedConfig: &core.ParsedOptions{ FileNames: []string{"/dev/src/index.ts"}, CompilerOptions: &opts, }, }, Host: host, }) // Discard written files — we only care about emit performance. nopWriteFile := func(fileName string, text string, data *compiler.WriteFileData) error { return nil } b.ResetTimer() b.ReportAllocs() for b.Loop() { p.Emit(context.Background(), compiler.EmitOptions{ WriteFile: nopWriteFile, }) } }) } } func BenchmarkEmitManyFiles(b *testing.B) { if !bundled.Embedded { b.Skip("bundled files are not embedded") } // Simulate many files with moderately long single-line content. numFiles := 200 numPropsPerFile := 500 files := make(map[string]string, numFiles) fileNames := make([]string, 0, numFiles) for i := range numFiles { name := fmt.Sprintf("/dev/src/file_%d.ts", i) files[name] = generateLongLineTS(numPropsPerFile) fileNames = append(fileNames, name) } fs := vfstest.FromMap(files, true) fs = bundled.WrapFS(fs) opts := core.CompilerOptions{ Target: core.ScriptTargetES2015, SourceMap: core.TSTrue, OutDir: "/dev/out", } host := compiler.NewCompilerHost("/dev/src", fs, bundled.LibPath(), nil, nil) p := compiler.NewProgram(compiler.ProgramOptions{ Config: &tsoptions.ParsedCommandLine{ ParsedConfig: &core.ParsedOptions{ FileNames: fileNames, CompilerOptions: &opts, }, }, Host: host, }) nopWriteFile := func(fileName string, text string, data *compiler.WriteFileData) error { return nil } b.ResetTimer() b.ReportAllocs() for b.Loop() { p.Emit(context.Background(), compiler.EmitOptions{ WriteFile: nopWriteFile, }) } } // BenchmarkEmitLongLinesWithLineBreaks is a control benchmark that emits the same amount // of code but WITH line breaks, showing that the issue is specific to long lines. func BenchmarkEmitLongLinesWithLineBreaks(b *testing.B) { if !bundled.Embedded { b.Skip("bundled files are not embedded") } numProperties := 10000 // Same content but with newlines between each property. var sb strings.Builder sb.WriteString("export const data: Record = {\n") for i := range numProperties { if i > 0 { sb.WriteString(",\n") } fmt.Fprintf(&sb, " prop_%d: %d", i, i) } sb.WriteString("\n};\n") source := sb.String() fs := vfstest.FromMap(map[string]string{ "/dev/src/index.ts": source, }, true) fs = bundled.WrapFS(fs) opts := core.CompilerOptions{ Target: core.ScriptTargetES2015, SourceMap: core.TSTrue, OutDir: "/dev/out", } host := compiler.NewCompilerHost("/dev/src", fs, bundled.LibPath(), nil, nil) p := compiler.NewProgram(compiler.ProgramOptions{ Config: &tsoptions.ParsedCommandLine{ ParsedConfig: &core.ParsedOptions{ FileNames: []string{"/dev/src/index.ts"}, CompilerOptions: &opts, }, }, Host: host, }) nopWriteFile := func(fileName string, text string, data *compiler.WriteFileData) error { return nil } b.ResetTimer() b.ReportAllocs() for b.Loop() { p.Emit(context.Background(), compiler.EmitOptions{ WriteFile: nopWriteFile, }) } }