vendor tsgo

This commit is contained in:
2026-07-09 16:50:43 -04:00
parent c06ea2e5a4
commit 98978e4930
5804 changed files with 1556156 additions and 101 deletions

View File

@@ -0,0 +1,250 @@
package baseline
import (
"fmt"
"os"
"path/filepath"
"regexp"
"strings"
"sync"
"testing"
"github.com/microsoft/typescript-go/internal/collections"
"github.com/microsoft/typescript-go/internal/repo"
"github.com/microsoft/typescript-go/internal/stringutil"
"github.com/peter-evans/patience"
)
type Options struct {
Subfolder string
IsSubmodule bool
IsSubmoduleAccepted bool
IsSubmoduleTriaged bool
DiffFixupOld func(string) string
DiffFixupNew func(string) string
SkipDiffWithOld bool
}
const NoContent = "<no content>"
func Run(t *testing.T, fileName string, actual string, opts Options) {
origSubfolder := opts.Subfolder
{
subfolder := opts.Subfolder
if opts.IsSubmodule {
subfolder = filepath.Join("submodule", subfolder)
}
localPath := filepath.Join(localRoot, subfolder, fileName)
referencePath := filepath.Join(referenceRoot, subfolder, fileName)
// Record this baseline for tracking unused baselines
recordBaseline(t, filepath.Join(subfolder, fileName))
writeComparison(t, actual, localPath, referencePath, false)
}
if !opts.IsSubmodule || opts.SkipDiffWithOld {
// Not a submodule, no diffs.
return
}
submoduleReference := filepath.Join(submoduleReferenceRoot, fileName)
submoduleExpected := readFileOrNoContent(submoduleReference)
const (
submoduleFolder = "submodule"
submoduleAcceptedFolder = "submoduleAccepted"
submoduleTriagedFolder = "submoduleTriaged"
)
diffFileName := fileName + ".diff"
diffKey := origSubfolder + "/" + diffFileName
isSubmoduleAccepted := opts.IsSubmoduleAccepted || submoduleAcceptedFileNames().Has(diffKey)
isSubmoduleTriaged := opts.IsSubmoduleTriaged || submoduleTriagedFileNames().Has(diffKey)
if isSubmoduleAccepted && isSubmoduleTriaged {
t.Fatalf("diff file %s/%s is in both submoduleAccepted and submoduleTriaged; it should only be in one", origSubfolder, diffFileName)
}
var outRoot string
switch {
case isSubmoduleAccepted:
outRoot = submoduleAcceptedFolder
case isSubmoduleTriaged:
outRoot = submoduleTriagedFolder
default:
outRoot = submoduleFolder
}
allRoots := [3]string{submoduleFolder, submoduleAcceptedFolder, submoduleTriagedFolder}
diff := getBaselineDiff(t, actual, submoduleExpected, fileName, opts.DiffFixupOld, opts.DiffFixupNew)
for _, root := range allRoots {
localPath := filepath.Join(localRoot, root, origSubfolder, diffFileName)
referencePath := filepath.Join(referenceRoot, root, origSubfolder, diffFileName)
// Record this baseline for tracking unused baselines
recordBaseline(t, filepath.Join(root, origSubfolder, diffFileName))
if root == outRoot {
writeComparison(t, diff, localPath, referencePath, false)
} else {
writeComparison(t, NoContent, localPath, referencePath, false)
}
}
}
var submoduleAcceptedFileNames = sync.OnceValue(func() *collections.Set[string] {
return readFileNameSet(filepath.Join(repo.TestDataPath(), "submoduleAccepted.txt"))
})
var submoduleTriagedFileNames = sync.OnceValue(func() *collections.Set[string] {
return readFileNameSet(filepath.Join(repo.TestDataPath(), "submoduleTriaged.txt"))
})
func readFileNameSet(path string) *collections.Set[string] {
var set collections.Set[string]
if content, err := os.ReadFile(path); err == nil {
for line := range strings.SplitSeq(string(content), "\n") {
line = strings.TrimSpace(line)
if line == "" || line[0] == '#' {
continue
}
set.Add(line)
}
} else {
panic(fmt.Sprintf("failed to read file %s: %v", path, err))
}
return &set
}
func readFileOrNoContent(fileName string) string {
content, err := os.ReadFile(fileName)
if err != nil {
return NoContent
}
return string(content)
}
func DiffText(oldName string, newName string, expected string, actual string) string {
lines := patience.Diff(stringutil.SplitLines(expected), stringutil.SplitLines(actual))
return patience.UnifiedDiffTextWithOptions(lines, patience.UnifiedDiffOptions{
Precontext: 3,
Postcontext: 3,
SrcHeader: oldName,
DstHeader: newName,
})
}
func getBaselineDiff(t *testing.T, actual string, expected string, fileName string, fixupOld func(string) string, fixupNew func(string) string) string {
if fixupOld != nil {
expected = fixupOld(expected)
}
if fixupNew != nil {
actual = fixupNew(actual)
}
if actual == expected {
return NoContent
}
s := DiffText("old."+fileName, "new."+fileName, expected, actual)
// If the diff is empty (just headers, no hunks), return NoContent
if !strings.Contains(s, "@@") {
return NoContent
}
// Remove line numbers from unified diff headers; this avoids adding/deleting
// lines in our baselines from causing knock-on header changes later in the diff.
aCurLine := 1
bCurLine := 1
s = fixUnifiedDiff.ReplaceAllStringFunc(s, func(match string) string {
var aLine, aLineCount, bLine, bLineCount int
if _, err := fmt.Sscanf(match, "@@ -%d,%d +%d,%d @@", &aLine, &aLineCount, &bLine, &bLineCount); err != nil {
panic(fmt.Sprintf("failed to parse unified diff header: %v", err))
}
aDiff := aLine - aCurLine
bDiff := bLine - bCurLine
aCurLine = aLine
bCurLine = bLine
// Keep surrounded by @@, to make GitHub's grammar happy.
// https://github.com/textmate/diff.tmbundle/blob/0593bb775eab1824af97ef2172fd38822abd97d7/Syntaxes/Diff.plist#L68
return fmt.Sprintf("@@= skipped -%d, +%d lines =@@", aDiff, bDiff)
})
return s
}
var fixUnifiedDiff = regexp.MustCompile(`@@ -\d+,\d+ \+\d+,\d+ @@`)
func RunAgainstSubmodule(t *testing.T, fileName string, actual string, opts Options) {
// Record this baseline for tracking unused baselines
recordBaseline(t, filepath.Join(opts.Subfolder, fileName))
local := filepath.Join(localRoot, opts.Subfolder, fileName)
reference := filepath.Join(submoduleReferenceRoot, opts.Subfolder, fileName)
writeComparison(t, actual, local, reference, true)
}
func writeComparison(t *testing.T, actualContent string, local, reference string, comparingAgainstSubmodule bool) {
if actualContent == "" {
panic("the generated content was \"\". Return 'baseline.NoContent' if no baselining is required.")
}
if err := os.MkdirAll(filepath.Dir(local), 0o755); err != nil {
t.Error(fmt.Errorf("failed to create directories for the local baseline file %s: %w", local, err))
return
}
if _, err := os.Stat(local); err == nil {
if err := os.Remove(local); err != nil {
t.Error(fmt.Errorf("failed to remove the local baseline file %s: %w", local, err))
return
}
}
expected := NoContent
foundExpected := false
if content, err := os.ReadFile(reference); err == nil {
expected = string(content)
foundExpected = true
}
if expected != actualContent || actualContent == NoContent && foundExpected {
if actualContent == NoContent {
if err := os.WriteFile(local+".delete", []byte{}, 0o644); err != nil {
t.Error(fmt.Errorf("failed to write the local baseline file %s: %w", local+".delete", err))
return
}
} else {
if err := os.WriteFile(local, []byte(actualContent), 0o644); err != nil {
t.Error(fmt.Errorf("failed to write the local baseline file %s: %w", local, err))
return
}
}
if _, err := os.Stat(reference); err != nil {
if comparingAgainstSubmodule {
t.Errorf("the baseline file %s does not exist in the TypeScript submodule", reference)
} else {
t.Errorf("new baseline created at %s.", local)
}
} else if comparingAgainstSubmodule {
t.Errorf("the baseline file %s does not match the reference in the TypeScript submodule", reference)
} else {
t.Errorf("the baseline file %s has changed. (Run `hereby baseline-accept` if the new baseline is correct.)", reference)
}
}
}
var (
localRoot = filepath.Join(repo.TestDataPath(), "baselines", "local")
referenceRoot = filepath.Join(repo.TestDataPath(), "baselines", "reference")
submoduleReferenceRoot = filepath.Join(repo.TypeScriptSubmodulePath(), "tests", "baselines", "reference")
)

View File

@@ -0,0 +1,25 @@
package baseline
import (
"os"
"path/filepath"
"testing"
)
func TestSubmoduleAcceptedFilesExist(t *testing.T) {
t.Parallel()
for name := range submoduleAcceptedFileNames().Keys() {
if _, err := os.Stat(filepath.Join(referenceRoot, "submoduleAccepted", name)); err != nil {
t.Errorf("submoduleAccepted.txt references %q, but the baseline file does not exist", name)
}
}
}
func TestSubmoduleTriagedFilesExist(t *testing.T) {
t.Parallel()
for name := range submoduleTriagedFileNames().Keys() {
if _, err := os.Stat(filepath.Join(referenceRoot, "submoduleTriaged", name)); err != nil {
t.Errorf("submoduleTriaged.txt references %q, but the baseline file does not exist", name)
}
}
}

View File

@@ -0,0 +1,103 @@
package baseline
import (
"bufio"
"fmt"
"hash/fnv"
"os"
"path/filepath"
"runtime"
"testing"
"github.com/microsoft/typescript-go/internal/collections"
)
var (
// recordedBaselines tracks all baseline file paths that were written during the test run.
recordedBaselines collections.SyncSet[string]
// trackingInitialized is set to true when Track() is called.
trackingInitialized bool
// trackingDir is the directory where tracking files should be written.
// If non-empty, baseline tracking is enabled.
// Set by Herebyfile.mjs when running full test suites with tracking enabled.
trackingDir = os.Getenv("TSGO_BASELINE_TRACKING_DIR")
)
// Track sets up baseline tracking and returns a cleanup function that writes the tracking file.
// It should be called from TestMain using defer:
//
// func TestMain(m *testing.M) {
// defer baseline.Track()()
// m.Run()
// }
func Track() func() {
trackingInitialized = true
if trackingDir == "" {
return func() {}
}
// Hash the entire call stack to create a unique filename per calling package.
// This must be done in Track(), not in the deferred cleanup, because
// the deferred function's call stack won't include the caller's info.
var pcs [32]uintptr
n := runtime.Callers(2, pcs[:]) // Skip Track and runtime.Callers
h := fnv.New64a()
frames := runtime.CallersFrames(pcs[:n])
for {
frame, more := frames.Next()
h.Write([]byte(frame.File))
if !more {
break
}
}
trackingPath := filepath.Join(trackingDir, fmt.Sprintf("%016x.txt", h.Sum64()))
return func() {
// After tests complete, write the recorded baselines
writeRecordedBaselines(trackingPath)
}
}
// recordBaseline adds a baseline file path to the recorded set.
// The path should be relative to the baselines/reference directory.
func recordBaseline(t testing.TB, relativePath string) {
if trackingDir != "" {
if !trackingInitialized {
t.Error("baseline: package uses baselines but TestMain did not call baseline.Track(). " +
"Please add a TestMain function with: defer baseline.Track()()")
return
}
recordedBaselines.Add(relativePath)
}
}
// writeRecordedBaselines writes the list of recorded baseline files to a tracking file.
func writeRecordedBaselines(trackingPath string) {
if recordedBaselines.Size() == 0 {
return
}
if err := doWriteRecordedBaselines(trackingPath); err != nil {
fmt.Fprintf(os.Stderr, "baseline: failed to write tracking file %s: %v\n", trackingPath, err)
os.Exit(1)
}
}
func doWriteRecordedBaselines(trackingPath string) error {
f, err := os.Create(trackingPath)
if err != nil {
return err
}
defer f.Close()
w := bufio.NewWriter(f)
for baseline := range recordedBaselines.Keys() {
if _, err := fmt.Fprintln(w, baseline); err != nil {
return err
}
}
return w.Flush()
}