vendor tsgo
This commit is contained in:
191
tools/tsgo/internal/compiler/emit_test.go
Normal file
191
tools/tsgo/internal/compiler/emit_test.go
Normal file
@@ -0,0 +1,191 @@
|
||||
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<string, number> = {")
|
||||
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<string, number> = {\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,
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user