vendor tsgo
This commit is contained in:
124
tools/tsgo/internal/api/server.go
Normal file
124
tools/tsgo/internal/api/server.go
Normal 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)
|
||||
}
|
||||
Reference in New Issue
Block a user