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,124 @@
package api
import (
"context"
"fmt"
"io"
"github.com/microsoft/typescript-go/internal/bundled"
"github.com/microsoft/typescript-go/internal/lsp/lsproto"
"github.com/microsoft/typescript-go/internal/project"
"github.com/microsoft/typescript-go/internal/vfs/osvfs"
)
// StdioServerOptions configures the STDIO-based API server.
type StdioServerOptions struct {
In io.ReadCloser
Out io.WriteCloser
Err io.Writer
Cwd string
DefaultLibraryPath string
// PipePath, if set, listens on a named pipe (Windows) or Unix domain
// socket instead of using In/Out for communication.
PipePath string
// Callbacks specifies which filesystem operations should be delegated
// to the client (e.g., "readFile", "fileExists"). Empty means no callbacks.
Callbacks []string
// Async enables JSON-RPC protocol with async connection handling.
// When false (default), uses MessagePack protocol with sync connection.
Async bool
// CollectTiming enables per-request server processing-time measurement.
// When enabled, the server accumulates each request's processing time into
// running totals and a recent-request ring buffer. Response messages are
// left unchanged; the client folds this data into its own timing snapshot
// on demand via getServerTiming / resetServerTiming requests.
CollectTiming bool
}
// StdioServer runs an API session over STDIO using MessagePack protocol.
// This is the entry point for the synchronous STDIO-based API used by
// native TypeScript tooling integration.
type StdioServer struct {
options *StdioServerOptions
}
// NewStdioServer creates a new STDIO-based API server.
func NewStdioServer(options *StdioServerOptions) *StdioServer {
if options.Cwd == "" {
panic("StdioServerOptions.Cwd is required")
}
return &StdioServer{
options: options,
}
}
// Run starts the server and blocks until the connection closes.
func (s *StdioServer) Run(ctx context.Context) error {
var transport Transport
if s.options.PipePath != "" {
t, err := NewPipeTransport(s.options.PipePath)
if err != nil {
return fmt.Errorf("failed to create pipe transport: %w", err)
}
defer t.Close()
transport = t
} else {
t := NewStdioTransport(s.options.In, s.options.Out)
defer t.Close()
transport = t
}
fs := bundled.WrapFS(osvfs.FS())
// Wrap the base FS with callbackFS if callbacks are requested
var callbackFS *callbackFS
if len(s.options.Callbacks) > 0 {
callbackFS = newCallbackFS(fs, s.options.Callbacks)
fs = callbackFS
}
projectSession := project.NewSession(&project.SessionInit{
BackgroundCtx: ctx,
Logger: nil, // TODO: Add logging support
FS: fs,
Options: &project.SessionOptions{
CurrentDirectory: s.options.Cwd,
DefaultLibraryPath: s.options.DefaultLibraryPath,
PositionEncoding: lsproto.PositionEncodingKindUTF8,
LoggingEnabled: false,
},
})
session := NewSession(projectSession, &SessionOptions{
UseBinaryResponses: !s.options.Async, // Only msgpack uses binary responses
})
defer session.Close()
// Accept connection from transport
rwc, err := transport.Accept()
if err != nil {
return fmt.Errorf("failed to accept connection: %w", err)
}
// Create protocol and connection based on async mode
var conn Conn
if s.options.Async {
protocol := NewJSONRPCProtocol(rwc)
asyncConn := NewAsyncConnWithProtocol(rwc, protocol, session)
asyncConn.SetCollectTiming(s.options.CollectTiming)
conn = asyncConn
} else {
protocol := NewMessagePackProtocol(rwc)
syncConn := NewSyncConn(rwc, protocol, session)
syncConn.SetCollectTiming(s.options.CollectTiming)
conn = syncConn
}
// If callbacks are enabled, set the connection on the FS
if callbackFS != nil {
callbackFS.SetConnection(ctx, conn)
}
return conn.Run(ctx)
}