vendor tsgo
This commit is contained in:
188
tools/tsgo/internal/jsonrpc/jsonrpc.go
Normal file
188
tools/tsgo/internal/jsonrpc/jsonrpc.go
Normal file
@@ -0,0 +1,188 @@
|
||||
// Package jsonrpc provides generic JSON-RPC 2.0 types and utilities
|
||||
// that can be shared between LSP and other JSON-RPC based protocols.
|
||||
package jsonrpc
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/microsoft/typescript-go/internal/json"
|
||||
)
|
||||
|
||||
// JSONRPCVersion represents the JSON-RPC version field, always "2.0".
|
||||
type JSONRPCVersion struct{}
|
||||
|
||||
const jsonRPCVersion = `"2.0"`
|
||||
|
||||
func (JSONRPCVersion) MarshalJSON() ([]byte, error) {
|
||||
return []byte(jsonRPCVersion), nil
|
||||
}
|
||||
|
||||
var ErrInvalidJSONRPCVersion = errors.New("invalid JSON-RPC version")
|
||||
|
||||
func (*JSONRPCVersion) UnmarshalJSON(data []byte) error {
|
||||
if string(data) != jsonRPCVersion {
|
||||
return ErrInvalidJSONRPCVersion
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ID represents a JSON-RPC message ID, which can be either a string or integer.
|
||||
type ID struct {
|
||||
str string
|
||||
int int32
|
||||
}
|
||||
|
||||
// NewID creates an ID from an IntegerOrString value.
|
||||
func NewID(rawValue IntegerOrString) *ID {
|
||||
if rawValue.String != nil {
|
||||
return &ID{str: *rawValue.String}
|
||||
}
|
||||
return &ID{int: *rawValue.Integer}
|
||||
}
|
||||
|
||||
// NewIDString creates a string ID.
|
||||
func NewIDString(str string) *ID {
|
||||
return &ID{str: str}
|
||||
}
|
||||
|
||||
// NewIDInt creates an integer ID.
|
||||
func NewIDInt(i int32) *ID {
|
||||
return &ID{int: i}
|
||||
}
|
||||
|
||||
func (id *ID) String() string {
|
||||
if id.str != "" {
|
||||
return id.str
|
||||
}
|
||||
return strconv.Itoa(int(id.int))
|
||||
}
|
||||
|
||||
func (id *ID) MarshalJSON() ([]byte, error) {
|
||||
if id.str != "" {
|
||||
return json.Marshal(id.str)
|
||||
}
|
||||
return json.Marshal(id.int)
|
||||
}
|
||||
|
||||
func (id *ID) UnmarshalJSON(data []byte) error {
|
||||
*id = ID{}
|
||||
if len(data) > 0 && data[0] == '"' {
|
||||
return json.Unmarshal(data, &id.str)
|
||||
}
|
||||
return json.Unmarshal(data, &id.int)
|
||||
}
|
||||
|
||||
func (id *ID) TryInt() (int32, bool) {
|
||||
if id == nil || id.str != "" {
|
||||
return 0, false
|
||||
}
|
||||
return id.int, true
|
||||
}
|
||||
|
||||
func (id *ID) MustInt() int32 {
|
||||
if id.str != "" {
|
||||
panic("ID is not an integer")
|
||||
}
|
||||
return id.int
|
||||
}
|
||||
|
||||
// IntegerOrString is a helper type for creating IDs.
|
||||
type IntegerOrString struct {
|
||||
Integer *int32
|
||||
String *string
|
||||
}
|
||||
|
||||
// ResponseError represents a JSON-RPC error response.
|
||||
type ResponseError struct {
|
||||
Code int32 `json:"code"`
|
||||
Message string `json:"message"`
|
||||
Data any `json:"data,omitzero"`
|
||||
}
|
||||
|
||||
func (r *ResponseError) String() string {
|
||||
if r == nil {
|
||||
return ""
|
||||
}
|
||||
data, err := json.Marshal(r.Data)
|
||||
if err != nil {
|
||||
return fmt.Sprintf("[%d]: %s\n%v", r.Code, r.Message, data)
|
||||
}
|
||||
return fmt.Sprintf("[%d]: %s", r.Code, r.Message)
|
||||
}
|
||||
|
||||
func (r *ResponseError) Error() string {
|
||||
return r.String()
|
||||
}
|
||||
|
||||
// Standard JSON-RPC error codes.
|
||||
const (
|
||||
CodeParseError int32 = -32700
|
||||
CodeInvalidRequest int32 = -32600
|
||||
CodeMethodNotFound int32 = -32601
|
||||
CodeInvalidParams int32 = -32602
|
||||
CodeInternalError int32 = -32603
|
||||
)
|
||||
|
||||
// MessageKind indicates what type of message this is.
|
||||
type MessageKind int
|
||||
|
||||
const (
|
||||
MessageKindNotification MessageKind = iota
|
||||
MessageKindRequest
|
||||
MessageKindResponse
|
||||
)
|
||||
|
||||
// Message represents a raw JSON-RPC message that can be a request, notification, or response.
|
||||
// Unlike lsproto.Message, this keeps params/result as raw JSON for generic handling.
|
||||
type Message struct {
|
||||
JSONRPC JSONRPCVersion `json:"jsonrpc"`
|
||||
ID *ID `json:"id,omitzero"`
|
||||
Method string `json:"method,omitzero"`
|
||||
Params json.Value `json:"params,omitzero"`
|
||||
Result json.Value `json:"result,omitzero"`
|
||||
Error *ResponseError `json:"error,omitzero"`
|
||||
}
|
||||
|
||||
// Kind returns the kind of message this is.
|
||||
func (m *Message) Kind() MessageKind {
|
||||
if m.ID != nil && m.Method == "" {
|
||||
return MessageKindResponse
|
||||
}
|
||||
if m.ID == nil {
|
||||
return MessageKindNotification
|
||||
}
|
||||
return MessageKindRequest
|
||||
}
|
||||
|
||||
// IsRequest returns true if this message is a request (has ID and method).
|
||||
func (m *Message) IsRequest() bool {
|
||||
return m.ID != nil && m.Method != ""
|
||||
}
|
||||
|
||||
// IsNotification returns true if this message is a notification (has method but no ID).
|
||||
func (m *Message) IsNotification() bool {
|
||||
return m.ID == nil && m.Method != ""
|
||||
}
|
||||
|
||||
// IsResponse returns true if this message is a response (has ID but no method).
|
||||
func (m *Message) IsResponse() bool {
|
||||
return m.ID != nil && m.Method == ""
|
||||
}
|
||||
|
||||
// RequestMessage is a convenience type for creating request/notification messages.
|
||||
type RequestMessage struct {
|
||||
JSONRPC JSONRPCVersion `json:"jsonrpc"`
|
||||
ID *ID `json:"id,omitzero"`
|
||||
Method string `json:"method"`
|
||||
Params any `json:"params,omitzero"`
|
||||
}
|
||||
|
||||
// ResponseMessage is a convenience type for creating response messages.
|
||||
type ResponseMessage struct {
|
||||
JSONRPC JSONRPCVersion `json:"jsonrpc"`
|
||||
ID *ID `json:"id,omitzero"`
|
||||
Result any `json:"result,omitzero"`
|
||||
Error *ResponseError `json:"error,omitzero"`
|
||||
}
|
||||
Reference in New Issue
Block a user