package api import ( "errors" "fmt" "github.com/microsoft/typescript-go/internal/ast" "github.com/microsoft/typescript-go/internal/checker" "github.com/microsoft/typescript-go/internal/core" "github.com/microsoft/typescript-go/internal/diagnostics" "github.com/microsoft/typescript-go/internal/jsnum" "github.com/microsoft/typescript-go/internal/json" "github.com/microsoft/typescript-go/internal/locale" "github.com/microsoft/typescript-go/internal/ls/lsconv" "github.com/microsoft/typescript-go/internal/lsp/lsproto" "github.com/microsoft/typescript-go/internal/project" "github.com/microsoft/typescript-go/internal/tspath" ) var ( ErrInvalidRequest = errors.New("api: invalid request") ErrClientError = errors.New("api: client error") ) type Method string type ( SnapshotID uint64 ProjectID string SymbolID uint64 TypeID uint32 SignatureID uint64 NodeHandle string ) func ProjectHandle(p *project.Project) ProjectID { return ProjectID(p.ID()) } func SymbolHandle(symbol *ast.Symbol) SymbolID { return SymbolID(ast.GetSymbolId(symbol)) } func TypeHandle(t *checker.Type) TypeID { return TypeID(t.Id()) } func SignatureHandle(sig *checker.Signature) SignatureID { return SignatureID(sig.Id()) } func parseProjectHandle(handle ProjectID) tspath.Path { return tspath.Path(handle) } const ( MethodRelease Method = "release" // MethodGetServerTiming retrieves the server's collected per-request // processing-time totals and recent-request ring buffer. It is handled by // the connection itself (not the session) and is not recorded in the timing // it reports. MethodGetServerTiming Method = "getServerTiming" // MethodResetServerTiming clears the server's collected timing totals and // recent-request ring buffer. Like MethodGetServerTiming, it is handled by // the connection itself and is not recorded. MethodResetServerTiming Method = "resetServerTiming" MethodInitialize Method = "initialize" MethodUpdateSnapshot Method = "updateSnapshot" MethodParseConfigFile Method = "parseConfigFile" MethodGetDefaultProjectForFile Method = "getDefaultProjectForFile" MethodGetSymbolAtPosition Method = "getSymbolAtPosition" MethodGetSymbolsAtPositions Method = "getSymbolsAtPositions" MethodGetSymbolAtLocation Method = "getSymbolAtLocation" MethodGetSymbolsAtLocations Method = "getSymbolsAtLocations" MethodGetTypeOfSymbol Method = "getTypeOfSymbol" MethodGetTypesOfSymbols Method = "getTypesOfSymbols" MethodGetDeclaredTypeOfSymbol Method = "getDeclaredTypeOfSymbol" MethodGetSourceFile Method = "getSourceFile" MethodGetSourceFileNames Method = "getSourceFileNames" MethodGetSourceFileMetadata Method = "getSourceFileMetadata" MethodResolveName Method = "resolveName" MethodGetSignaturesOfType Method = "getSignaturesOfType" MethodGetResolvedSignature Method = "getResolvedSignature" MethodGetTypeAtLocation Method = "getTypeAtLocation" MethodGetTypeAtLocations Method = "getTypeAtLocations" MethodGetTypeAtPosition Method = "getTypeAtPosition" MethodGetTypesAtPositions Method = "getTypesAtPositions" // Symbol sub-property methods MethodGetParentOfSymbol Method = "getParentOfSymbol" MethodGetMembersOfSymbol Method = "getMembersOfSymbol" MethodGetExportsOfSymbol Method = "getExportsOfSymbol" MethodGetExportSymbolOfSymbol Method = "getExportSymbolOfSymbol" // Type sub-property methods MethodGetSymbolOfType Method = "getSymbolOfType" MethodGetTargetOfType Method = "getTargetOfType" MethodGetFreshTypeOfType Method = "getFreshTypeOfType" MethodGetRegularTypeOfType Method = "getRegularTypeOfType" MethodGetTypesOfType Method = "getTypesOfType" MethodGetTypeParametersOfType Method = "getTypeParametersOfType" MethodGetOuterTypeParametersOfType Method = "getOuterTypeParametersOfType" MethodGetLocalTypeParametersOfType Method = "getLocalTypeParametersOfType" MethodGetAliasTypeArgumentsOfType Method = "getAliasTypeArgumentsOfType" MethodGetAliasSymbolOfType Method = "getAliasSymbolOfType" MethodGetObjectTypeOfType Method = "getObjectTypeOfType" MethodGetIndexTypeOfType Method = "getIndexTypeOfType" MethodGetCheckTypeOfType Method = "getCheckTypeOfType" MethodGetExtendsTypeOfType Method = "getExtendsTypeOfType" MethodGetBaseTypeOfType Method = "getBaseTypeOfType" MethodGetConstraintOfType Method = "getConstraintOfType" // Signature sub-property methods MethodGetTypeParametersOfSignature Method = "getTypeParametersOfSignature" MethodGetParametersOfSignature Method = "getParametersOfSignature" MethodGetThisParameterOfSignature Method = "getThisParameterOfSignature" MethodGetTargetOfSignature Method = "getTargetOfSignature" // Checker methods MethodGetContextualType Method = "getContextualType" MethodGetBaseTypeOfLiteralType Method = "getBaseTypeOfLiteralType" MethodGetNonNullableType Method = "getNonNullableType" MethodGetTypeFromTypeNode Method = "getTypeFromTypeNode" MethodGetWidenedType Method = "getWidenedType" MethodGetParameterType Method = "getParameterType" MethodIsArrayLikeType Method = "isArrayLikeType" MethodIsTypeAssignableTo Method = "isTypeAssignableTo" MethodGetShorthandAssignmentValueSymbol Method = "getShorthandAssignmentValueSymbol" MethodGetTypeOfSymbolAtLocation Method = "getTypeOfSymbolAtLocation" MethodTypeToTypeNode Method = "typeToTypeNode" MethodSignatureToSignatureDeclaration Method = "signatureToSignatureDeclaration" MethodTypeToString Method = "typeToString" MethodIsContextSensitive Method = "isContextSensitive" MethodGetReturnTypeOfSignature Method = "getReturnTypeOfSignature" MethodGetRestTypeOfSignature Method = "getRestTypeOfSignature" MethodGetTypePredicateOfSignature Method = "getTypePredicateOfSignature" MethodGetBaseTypes Method = "getBaseTypes" MethodGetPropertiesOfType Method = "getPropertiesOfType" MethodGetApparentType Method = "getApparentType" MethodGetPropertyOfType Method = "getPropertyOfType" MethodGetIndexInfosOfType Method = "getIndexInfosOfType" MethodGetConstraintOfTypeParameter Method = "getConstraintOfTypeParameter" MethodGetBaseConstraintOfType Method = "getBaseConstraintOfType" MethodGetTypeArguments Method = "getTypeArguments" MethodGetTrueTypeOfConditionalType Method = "getTrueTypeOfConditionalType" MethodGetFalseTypeOfConditionalType Method = "getFalseTypeOfConditionalType" MethodGetConstantValue Method = "getConstantValue" MethodGetSignatureFromDeclaration Method = "getSignatureFromDeclaration" MethodGetExportSpecifierLocalTarget Method = "getExportSpecifierLocalTargetSymbol" MethodGetAliasedSymbol Method = "getAliasedSymbol" MethodGetImmediateAliasedSymbol Method = "getImmediateAliasedSymbol" MethodGetExportsOfModule Method = "getExportsOfModule" MethodGetMemberInModuleExports Method = "getMemberInModuleExports" MethodGetJSDocTags Method = "getJsDocTags" MethodGetDocumentationComment Method = "getDocumentationComment" MethodIsArrayType Method = "isArrayType" MethodIsTupleType Method = "isTupleType" // Reference methods MethodGetReferencesToSymbolInFile Method = "getReferencesToSymbolInFile" MethodGetReferencedSymbolsForNode Method = "getReferencedSymbolsForNode" MethodGetSignatureUsages Method = "getSignatureUsages" // Language service methods MethodGetCompletionsAtPosition Method = "getCompletionsAtPosition" // Diagnostic methods MethodGetSyntacticDiagnostics Method = "getSyntacticDiagnostics" MethodGetBindDiagnostics Method = "getBindDiagnostics" MethodGetSemanticDiagnostics Method = "getSemanticDiagnostics" MethodGetSuggestionDiagnostics Method = "getSuggestionDiagnostics" MethodGetDeclarationDiagnostics Method = "getDeclarationDiagnostics" MethodGetProgramDiagnostics Method = "getProgramDiagnostics" MethodGetGlobalDiagnostics Method = "getGlobalDiagnostics" MethodGetConfigFileParsingDiagnostics Method = "getConfigFileParsingDiagnostics" // Emitter methods MethodPrintNode Method = "printNode" // Intrinsic type getters MethodGetAnyType Method = "getAnyType" MethodGetStringType Method = "getStringType" MethodGetNumberType Method = "getNumberType" MethodGetBooleanType Method = "getBooleanType" MethodGetVoidType Method = "getVoidType" MethodGetUndefinedType Method = "getUndefinedType" MethodGetNullType Method = "getNullType" MethodGetNeverType Method = "getNeverType" MethodGetUnknownType Method = "getUnknownType" MethodGetBigIntType Method = "getBigIntType" MethodGetESSymbolType Method = "getESSymbolType" // Well-known per-checker symbols MethodGetWellKnownSymbols Method = "getWellKnownSymbols" // Well-known per-checker signatures MethodGetWellKnownSignatures Method = "getWellKnownSignatures" // Profiling methods MethodStartCPUProfile Method = "startCPUProfile" MethodStopCPUProfile Method = "stopCPUProfile" MethodSaveHeapProfile Method = "saveHeapProfile" ) // InitializeResponse is returned by the initialize method. type InitializeResponse struct { // UseCaseSensitiveFileNames indicates whether the host file system is case-sensitive. UseCaseSensitiveFileNames bool `json:"useCaseSensitiveFileNames"` // CurrentDirectory is the server's current working directory. CurrentDirectory string `json:"currentDirectory"` } // DocumentIdentifier identifies a document by either a file name (plain string) or a URI object. // On the wire it is string | { uri: string }. type DocumentIdentifier struct { FileName string `json:"fileName,omitempty"` URI lsproto.DocumentUri `json:"uri,omitempty"` } var _ json.UnmarshalerFrom = (*DocumentIdentifier)(nil) func (d *DocumentIdentifier) UnmarshalJSONFrom(dec *json.Decoder) error { // Try reading as a plain string first tok, err := dec.ReadToken() if err != nil { return err } switch tok.Kind() { case '"': d.FileName = tok.String() return nil case '{': // Read the object fields for dec.PeekKind() != '}' { key, err := dec.ReadToken() if err != nil { return err } isURI := key.String() == "uri" val, err := dec.ReadToken() if err != nil { return err } if isURI { d.URI = lsproto.DocumentUri(val.String()) } } // Consume the closing brace if _, err := dec.ReadToken(); err != nil { return err } return nil default: return fmt.Errorf("DocumentIdentifier: expected string or object, got %v", tok.Kind()) } } func (d DocumentIdentifier) ToFileName() string { if d.URI != "" { return d.URI.FileName() } return d.FileName } // ToURI returns the document URI for this identifier. An explicitly provided URI // is returned as-is; a file name is first normalized to an absolute path against // cwd before being converted to a URI. func (d DocumentIdentifier) ToURI(cwd string) lsproto.DocumentUri { if d.URI != "" { return d.URI } return lsconv.FileNameToDocumentURI(tspath.GetNormalizedAbsolutePath(d.FileName, cwd)) } func (d DocumentIdentifier) ToAbsoluteFileName(cwd string) string { if d.URI != "" { return d.URI.FileName() } return tspath.GetNormalizedAbsolutePath(d.FileName, cwd) } func (d DocumentIdentifier) String() string { if d.URI != "" { return string(d.URI) } return d.FileName } // APIFileChangeSummary lists documents that have been changed, created, or deleted. type APIFileChangeSummary struct { Changed []DocumentIdentifier `json:"changed,omitempty"` Created []DocumentIdentifier `json:"created,omitempty"` Deleted []DocumentIdentifier `json:"deleted,omitempty"` } // APIFileChanges describes file changes to apply when updating a snapshot. // Either InvalidateAll is true (discard all caches) or Changed/Created/Deleted // list individual documents. type APIFileChanges struct { InvalidateAll bool `json:"invalidateAll,omitempty"` Changed []DocumentIdentifier `json:"changed,omitempty"` Created []DocumentIdentifier `json:"created,omitempty"` Deleted []DocumentIdentifier `json:"deleted,omitempty"` } // UpdateSnapshotParams are the parameters for creating a new snapshot. // All fields are optional. With no fields set, the server adopts the latest LSP state. type UpdateSnapshotParams struct { // OpenProjects lists tsconfig.json files to open/load in the new snapshot. // Opens are ref-counted and persist across snapshots until closed. OpenProjects []DocumentIdentifier `json:"openProjects,omitempty"` // CloseProjects lists tsconfig.json files to release in the new snapshot. // A project is only unloaded once every API client that opened it closes it. CloseProjects []DocumentIdentifier `json:"closeProjects,omitempty"` // FileChanges describes file system changes since the last snapshot. FileChanges *APIFileChanges `json:"fileChanges,omitempty"` // OpenFiles lists files to keep open for the API client, mirroring LSP's // textDocument/didOpen. For each file, ancestor directories are searched for a // tsconfig that contains it; if found, that configured project is loaded and // becomes the file's default project. Otherwise the file is loaded into the // inferred project (e.g. a node_modules d.ts not in any project's import graph). // Opens persist across snapshots until the file is closed. OpenFiles []DocumentIdentifier `json:"openFiles,omitempty"` // CloseFiles lists files to release in the new snapshot. A file is only fully // closed once every API client that opened it closes it. CloseFiles []DocumentIdentifier `json:"closeFiles,omitempty"` } // ProjectFileChanges describes what source files changed within a single project. type ProjectFileChanges struct { // ChangedFiles lists source file paths whose content differs. ChangedFiles []tspath.Path `json:"changedFiles,omitempty"` // DeletedFiles lists source file paths removed from the project's program. DeletedFiles []tspath.Path `json:"deletedFiles,omitempty"` } // SnapshotChanges describes what changed between the previous latest snapshot // and the newly created snapshot. Changes are reported per-project so clients // can track cache refs at the (snapshot, project) level. type SnapshotChanges struct { // ChangedProjects maps project handles to the file changes within that project. // Projects not listed here (and not in RemovedProjects) are unchanged. ChangedProjects map[ProjectID]*ProjectFileChanges `json:"changedProjects,omitempty"` // RemovedProjects lists project handles that were present in the previous // snapshot but absent from the new one. RemovedProjects []ProjectID `json:"removedProjects,omitempty"` } // UpdateSnapshotResponse is returned by updateSnapshot. type UpdateSnapshotResponse struct { // Snapshot is the handle for the newly created snapshot. Snapshot SnapshotID `json:"snapshot"` // Projects is the list of projects in the snapshot. Projects []*ProjectResponse `json:"projects"` // Changes describes source file differences from the previous snapshot. // Nil for the first snapshot in a session. Changes *SnapshotChanges `json:"changes,omitempty"` } var unmarshalers = map[Method]func([]byte) (any, error){ MethodRelease: unmarshallerFor[ReleaseParams], MethodInitialize: noParams, MethodUpdateSnapshot: unmarshallerFor[UpdateSnapshotParams], MethodParseConfigFile: unmarshallerFor[ParseConfigFileParams], MethodGetDefaultProjectForFile: unmarshallerFor[GetDefaultProjectForFileParams], MethodGetSourceFile: unmarshallerFor[GetSourceFileParams], MethodGetSourceFileNames: unmarshallerFor[GetSourceFileNamesParams], MethodGetSourceFileMetadata: unmarshallerFor[GetSourceFileParams], MethodGetSymbolAtPosition: unmarshallerFor[GetSymbolAtPositionParams], MethodGetSymbolsAtPositions: unmarshallerFor[GetSymbolsAtPositionsParams], MethodGetSymbolAtLocation: unmarshallerFor[GetSymbolAtLocationParams], MethodGetSymbolsAtLocations: unmarshallerFor[GetSymbolsAtLocationsParams], MethodGetTypeOfSymbol: unmarshallerFor[GetTypeOfSymbolParams], MethodGetTypesOfSymbols: unmarshallerFor[GetTypesOfSymbolsParams], MethodGetDeclaredTypeOfSymbol: unmarshallerFor[GetTypeOfSymbolParams], MethodResolveName: unmarshallerFor[ResolveNameParams], MethodGetSignaturesOfType: unmarshallerFor[GetSignaturesOfTypeParams], MethodGetResolvedSignature: unmarshallerFor[GetResolvedSignatureParams], MethodGetTypeAtLocation: unmarshallerFor[GetTypeAtLocationParams], MethodGetTypeAtLocations: unmarshallerFor[GetTypeAtLocationsParams], MethodGetTypeAtPosition: unmarshallerFor[GetTypeAtPositionParams], MethodGetTypesAtPositions: unmarshallerFor[GetTypesAtPositionsParams], MethodGetParentOfSymbol: unmarshallerFor[GetSymbolPropertyParams], MethodGetMembersOfSymbol: unmarshallerFor[GetSymbolPropertyParams], MethodGetExportsOfSymbol: unmarshallerFor[GetSymbolPropertyParams], MethodGetExportSymbolOfSymbol: unmarshallerFor[GetSymbolPropertyParams], MethodGetSymbolOfType: unmarshallerFor[GetTypePropertyParams], MethodGetTargetOfType: unmarshallerFor[GetTypePropertyParams], MethodGetFreshTypeOfType: unmarshallerFor[GetTypePropertyParams], MethodGetRegularTypeOfType: unmarshallerFor[GetTypePropertyParams], MethodGetTypesOfType: unmarshallerFor[GetTypePropertyParams], MethodGetTypeParametersOfType: unmarshallerFor[GetTypePropertyParams], MethodGetOuterTypeParametersOfType: unmarshallerFor[GetTypePropertyParams], MethodGetLocalTypeParametersOfType: unmarshallerFor[GetTypePropertyParams], MethodGetAliasTypeArgumentsOfType: unmarshallerFor[GetTypePropertyParams], MethodGetAliasSymbolOfType: unmarshallerFor[GetTypePropertyParams], MethodGetObjectTypeOfType: unmarshallerFor[GetTypePropertyParams], MethodGetIndexTypeOfType: unmarshallerFor[GetTypePropertyParams], MethodGetCheckTypeOfType: unmarshallerFor[GetTypePropertyParams], MethodGetExtendsTypeOfType: unmarshallerFor[GetTypePropertyParams], MethodGetBaseTypeOfType: unmarshallerFor[GetTypePropertyParams], MethodGetConstraintOfType: unmarshallerFor[GetTypePropertyParams], MethodGetTrueTypeOfConditionalType: unmarshallerFor[GetTypePropertyParams], MethodGetFalseTypeOfConditionalType: unmarshallerFor[GetTypePropertyParams], MethodGetTypeParametersOfSignature: unmarshallerFor[GetSignaturePropertyParams], MethodGetParametersOfSignature: unmarshallerFor[GetSignaturePropertyParams], MethodGetThisParameterOfSignature: unmarshallerFor[GetSignaturePropertyParams], MethodGetTargetOfSignature: unmarshallerFor[GetSignaturePropertyParams], MethodGetContextualType: unmarshallerFor[GetContextualTypeParams], MethodGetBaseTypeOfLiteralType: unmarshallerFor[GetBaseTypeOfLiteralTypeParams], MethodGetNonNullableType: unmarshallerFor[GetNonNullableTypeParams], MethodGetTypeFromTypeNode: unmarshallerFor[GetTypeFromTypeNodeParams], MethodGetWidenedType: unmarshallerFor[GetWidenedTypeParams], MethodGetParameterType: unmarshallerFor[GetParameterTypeParams], MethodIsArrayLikeType: unmarshallerFor[IsArrayLikeTypeParams], MethodIsTypeAssignableTo: unmarshallerFor[IsTypeAssignableToParams], MethodGetShorthandAssignmentValueSymbol: unmarshallerFor[GetTypeAtLocationParams], MethodGetTypeOfSymbolAtLocation: unmarshallerFor[GetTypeOfSymbolAtLocationParams], MethodTypeToTypeNode: unmarshallerFor[TypeToTypeNodeParams], MethodSignatureToSignatureDeclaration: unmarshallerFor[SignatureToSignatureDeclarationParams], MethodTypeToString: unmarshallerFor[TypeToTypeNodeParams], MethodIsContextSensitive: unmarshallerFor[GetContextualTypeParams], MethodGetReturnTypeOfSignature: unmarshallerFor[CheckerSignatureParams], MethodGetRestTypeOfSignature: unmarshallerFor[CheckerSignatureParams], MethodGetTypePredicateOfSignature: unmarshallerFor[CheckerSignatureParams], MethodGetBaseTypes: unmarshallerFor[CheckerTypeParams], MethodGetPropertiesOfType: unmarshallerFor[CheckerTypeParams], MethodGetApparentType: unmarshallerFor[CheckerTypeParams], MethodGetPropertyOfType: unmarshallerFor[GetPropertyOfTypeParams], MethodGetIndexInfosOfType: unmarshallerFor[CheckerTypeParams], MethodGetConstraintOfTypeParameter: unmarshallerFor[CheckerTypeParams], MethodGetBaseConstraintOfType: unmarshallerFor[CheckerTypeParams], MethodGetTypeArguments: unmarshallerFor[CheckerTypeParams], MethodGetConstantValue: unmarshallerFor[CheckerNodeParams], MethodGetSignatureFromDeclaration: unmarshallerFor[CheckerNodeParams], MethodGetExportSpecifierLocalTarget: unmarshallerFor[CheckerNodeParams], MethodGetAliasedSymbol: unmarshallerFor[CheckerSymbolParams], MethodGetImmediateAliasedSymbol: unmarshallerFor[CheckerSymbolParams], MethodGetExportsOfModule: unmarshallerFor[CheckerSymbolParams], MethodGetMemberInModuleExports: unmarshallerFor[GetMemberInModuleExportsParams], MethodGetJSDocTags: unmarshallerFor[CheckerSymbolParams], MethodGetDocumentationComment: unmarshallerFor[CheckerSymbolParams], MethodIsArrayType: unmarshallerFor[CheckerTypeParams], MethodIsTupleType: unmarshallerFor[CheckerTypeParams], MethodGetReferencesToSymbolInFile: unmarshallerFor[GetReferencesToSymbolInFileParams], MethodGetReferencedSymbolsForNode: unmarshallerFor[GetReferencedSymbolsForNodeParams], MethodGetSignatureUsages: unmarshallerFor[GetSignatureUsagesParams], MethodGetCompletionsAtPosition: unmarshallerFor[GetCompletionsAtPositionParams], MethodPrintNode: unmarshallerFor[PrintNodeParams], MethodGetAnyType: unmarshallerFor[GetIntrinsicTypeParams], MethodGetStringType: unmarshallerFor[GetIntrinsicTypeParams], MethodGetNumberType: unmarshallerFor[GetIntrinsicTypeParams], MethodGetBooleanType: unmarshallerFor[GetIntrinsicTypeParams], MethodGetVoidType: unmarshallerFor[GetIntrinsicTypeParams], MethodGetUndefinedType: unmarshallerFor[GetIntrinsicTypeParams], MethodGetNullType: unmarshallerFor[GetIntrinsicTypeParams], MethodGetNeverType: unmarshallerFor[GetIntrinsicTypeParams], MethodGetUnknownType: unmarshallerFor[GetIntrinsicTypeParams], MethodGetBigIntType: unmarshallerFor[GetIntrinsicTypeParams], MethodGetESSymbolType: unmarshallerFor[GetIntrinsicTypeParams], MethodGetWellKnownSymbols: unmarshallerFor[GetIntrinsicTypeParams], MethodGetWellKnownSignatures: unmarshallerFor[GetIntrinsicTypeParams], MethodGetSyntacticDiagnostics: unmarshallerFor[GetDiagnosticsParams], MethodGetBindDiagnostics: unmarshallerFor[GetDiagnosticsParams], MethodGetSemanticDiagnostics: unmarshallerFor[GetDiagnosticsParams], MethodGetSuggestionDiagnostics: unmarshallerFor[GetDiagnosticsParams], MethodGetDeclarationDiagnostics: unmarshallerFor[GetDiagnosticsParams], MethodGetProgramDiagnostics: unmarshallerFor[GetProjectDiagnosticsParams], MethodGetGlobalDiagnostics: unmarshallerFor[GetProjectDiagnosticsParams], MethodGetConfigFileParsingDiagnostics: unmarshallerFor[GetProjectDiagnosticsParams], MethodStartCPUProfile: unmarshallerFor[ProfileParams], MethodStopCPUProfile: noParams, MethodSaveHeapProfile: unmarshallerFor[ProfileParams], } type ParseConfigFileParams struct { File DocumentIdentifier `json:"file"` } // ReleaseParams are the parameters for the release method. type ReleaseParams struct { Snapshot SnapshotID `json:"snapshot"` } type ProfileParams struct { Dir string `json:"dir"` } type ProfileResult struct { File string `json:"file"` } type ConfigFileResponse struct { FileNames []string `json:"fileNames"` Options *core.CompilerOptions `json:"options"` } type GetDefaultProjectForFileParams struct { Snapshot SnapshotID `json:"snapshot"` File DocumentIdentifier `json:"file"` } type ProjectResponse struct { Id ProjectID `json:"id"` ConfigFileName string `json:"configFileName"` RootFiles []string `json:"rootFiles"` CompilerOptions *core.CompilerOptions `json:"compilerOptions"` } func NewProjectResponse(p *project.Project) *ProjectResponse { if p == nil || p.CommandLine == nil { panic("NewProjectResponse called with unloaded project") } return &ProjectResponse{ Id: ProjectHandle(p), ConfigFileName: p.Name(), RootFiles: p.CommandLine.FileNames(), CompilerOptions: p.CommandLine.CompilerOptions(), } } type GetSymbolAtPositionParams struct { Snapshot SnapshotID `json:"snapshot"` Project ProjectID `json:"project"` File DocumentIdentifier `json:"file"` Position uint32 `json:"position"` } type GetSymbolsAtPositionsParams struct { Snapshot SnapshotID `json:"snapshot"` Project ProjectID `json:"project"` File DocumentIdentifier `json:"file"` Positions []uint32 `json:"positions"` } type GetSymbolAtLocationParams struct { Snapshot SnapshotID `json:"snapshot"` Project ProjectID `json:"project"` Location NodeHandle `json:"location"` } type GetSymbolsAtLocationsParams struct { Snapshot SnapshotID `json:"snapshot"` Project ProjectID `json:"project"` Locations []NodeHandle `json:"locations"` } type SymbolResponse struct { Id SymbolID `json:"id"` Project ProjectID `json:"project"` Name string `json:"name"` Flags uint32 `json:"flags"` CheckFlags uint32 `json:"checkFlags"` Declarations []NodeHandle `json:"declarations,omitempty"` ValueDeclaration NodeHandle `json:"valueDeclaration,omitempty"` Parent SymbolID `json:"parent,omitzero"` ExportSymbol SymbolID `json:"exportSymbol,omitzero"` } func symbolHandles(symbols []*ast.Symbol) []SymbolID { if len(symbols) == 0 { return nil } handles := make([]SymbolID, len(symbols)) for i, t := range symbols { handles[i] = SymbolHandle(t) } return handles } type GetTypeOfSymbolParams struct { Snapshot SnapshotID `json:"snapshot"` Project ProjectID `json:"project"` Symbol SymbolID `json:"symbol"` } type GetTypesOfSymbolsParams struct { Snapshot SnapshotID `json:"snapshot"` Project ProjectID `json:"project"` Symbols []SymbolID `json:"symbols"` } type TypeResponse struct { Id TypeID `json:"id"` Flags uint32 `json:"flags"` ObjectFlags uint32 `json:"objectFlags,omitempty"` // LiteralType data Value any `json:"value"` // ObjectType / TypeReference / StringMappingType / IndexType target Target TypeID `json:"target,omitzero"` // InterfaceType type parameters TypeParameters []TypeID `json:"typeParameters,omitempty"` OuterTypeParameters []TypeID `json:"outerTypeParameters,omitempty"` LocalTypeParameters []TypeID `json:"localTypeParameters,omitempty"` // TupleType data ElementFlags []checker.ElementFlags `json:"elementFlags,omitempty"` FixedLength *int `json:"fixedLength,omitempty"` TupleReadonly *bool `json:"readonly,omitempty"` // IndexedAccessType data ObjectType TypeID `json:"objectType,omitzero"` IndexType TypeID `json:"indexType,omitzero"` // ConditionalType data CheckType TypeID `json:"checkType,omitzero"` ExtendsType TypeID `json:"extendsType,omitzero"` // SubstitutionType data BaseType TypeID `json:"baseType,omitzero"` SubstConstraint TypeID `json:"substConstraint,omitzero"` // TemplateLiteralType text segments Texts []string `json:"texts,omitempty"` // FreshableType data (LiteralType and computed enum types) FreshType TypeID `json:"freshType,omitzero"` RegularType TypeID `json:"regularType,omitzero"` // TypeParameter data IsThisType bool `json:"isThisType,omitempty"` // IntrinsicType data IntrinsicName string `json:"intrinsicName,omitempty"` // TypeAlias data AliasTypeArguments []TypeID `json:"aliasTypeArguments,omitempty"` AliasSymbol SymbolID `json:"aliasSymbol,omitzero"` // Symbol associated with structured types Symbol SymbolID `json:"symbol,omitzero"` } func newTypeResponse(t *checker.Type, id TypeID) *TypeResponse { resp := &TypeResponse{ Id: id, Flags: uint32(t.Flags()), } if t.Symbol() != nil { resp.Symbol = SymbolHandle(t.Symbol()) } if t.Alias() != nil { resp.AliasTypeArguments = typeHandles(t.Alias().TypeArguments()) if t.Alias().Symbol() != nil { resp.AliasSymbol = SymbolHandle(t.Alias().Symbol()) } } switch flags := t.Flags(); { case flags&checker.TypeFlagsFreshable != 0: lit := t.AsLiteralType() if flags&checker.TypeFlagsLiteral != 0 { resp.Value = literalValueToJSON(lit.Value()) } if lit.FreshType() != nil { resp.FreshType = TypeHandle(lit.FreshType()) } if lit.RegularType() != nil { resp.RegularType = TypeHandle(lit.RegularType()) } case flags&checker.TypeFlagsObject != 0: resp.ObjectFlags = uint32(t.ObjectFlags()) objectFlags := t.ObjectFlags() if objectFlags&checker.ObjectFlagsReference != 0 { var ref *checker.TypeReference if objectFlags&checker.ObjectFlagsTuple != 0 { tuple := t.AsTupleType() ref = tuple.AsTypeReference() resp.ElementFlags = tuple.ElementFlags() fixedLen := tuple.FixedLength() resp.FixedLength = &fixedLen isReadonly := tuple.IsReadonly() resp.TupleReadonly = &isReadonly } else { ref = t.AsTypeReference() } if ref.Target() != nil { resp.Target = TypeHandle(ref.Target()) } } if objectFlags&checker.ObjectFlagsClassOrInterface != 0 { iface := t.AsInterfaceType() resp.TypeParameters = typeHandles(iface.TypeParameters()) resp.OuterTypeParameters = typeHandles(iface.OuterTypeParameters()) resp.LocalTypeParameters = typeHandles(iface.LocalTypeParameters()) } case flags&checker.TypeFlagsUnionOrIntersection != 0: // types omitted; fetched via separate request case flags&checker.TypeFlagsIndex != 0: resp.Target = TypeHandle(t.AsIndexType().Target()) case flags&checker.TypeFlagsIndexedAccess != 0: data := t.AsIndexedAccessType() resp.ObjectType = TypeHandle(data.ObjectType()) resp.IndexType = TypeHandle(data.IndexType()) case flags&checker.TypeFlagsConditional != 0: data := t.AsConditionalType() resp.CheckType = TypeHandle(data.CheckType()) resp.ExtendsType = TypeHandle(data.ExtendsType()) case flags&checker.TypeFlagsSubstitution != 0: data := t.AsSubstitutionType() resp.BaseType = TypeHandle(data.BaseType()) resp.SubstConstraint = TypeHandle(data.SubstConstraint()) case flags&checker.TypeFlagsTemplateLiteral != 0: tl := t.AsTemplateLiteralType() resp.Texts = tl.Texts() // types omitted; fetched via separate request case flags&checker.TypeFlagsStringMapping != 0: resp.Target = TypeHandle(t.AsStringMappingType().Target()) case flags&checker.TypeFlagsTypeParameter != 0: resp.IsThisType = t.AsTypeParameter().IsThisType() case flags&checker.TypeFlagsIntrinsic != 0: resp.IntrinsicName = t.AsIntrinsicType().IntrinsicName() } return resp } func typeHandles(types []*checker.Type) []TypeID { if len(types) == 0 { return nil } handles := make([]TypeID, len(types)) for i, t := range types { handles[i] = TypeHandle(t) } return handles } func literalValueToJSON(value any) any { switch v := value.(type) { case string: return v case jsnum.Number: return float64(v) case bool: return v case jsnum.PseudoBigInt: // Encode bigint literals as a signed decimal string (e.g. "-123"); the // API client decodes this back into a real bigint. JSON has no bigint. return v.String() default: return nil } } type SignatureResponse struct { Id SignatureID `json:"id"` Flags uint32 `json:"flags"` Declaration NodeHandle `json:"declaration,omitempty"` TypeParameters []TypeID `json:"typeParameters,omitempty"` Parameters []SymbolID `json:"parameters,omitempty"` ThisParameter SymbolID `json:"thisParameter,omitzero"` Target SignatureID `json:"target,omitzero"` } type GetSourceFileParams struct { Snapshot SnapshotID `json:"snapshot"` Project ProjectID `json:"project"` File DocumentIdentifier `json:"file"` } type GetSourceFileNamesParams struct { Snapshot SnapshotID `json:"snapshot"` Project ProjectID `json:"project"` } // SourceFileMetadata carries program-stored metadata about a single source file. type SourceFileMetadata struct { IsDefaultLibrary bool `json:"isDefaultLibrary"` IsFromExternalLibrary bool `json:"isFromExternalLibrary"` PackageJsonType string `json:"packageJsonType"` PackageJsonDirectory string `json:"packageJsonDirectory"` ImpliedNodeFormat core.ResolutionMode `json:"impliedNodeFormat"` } type ResolveNameParams struct { Snapshot SnapshotID `json:"snapshot"` Project ProjectID `json:"project"` Name string `json:"name"` Location NodeHandle `json:"location,omitempty"` // Optional: node handle for location context File *DocumentIdentifier `json:"file,omitempty"` // Optional: file for location context (alternative to Location) Position *uint32 `json:"position,omitempty"` // Optional: position in file for location context (with File) Meaning uint32 `json:"meaning"` // SymbolFlags for what kind of symbol to find ExcludeGlobals bool `json:"excludeGlobals,omitempty"` // Whether to exclude global symbols } // GetTypePropertyParams is used for all type sub-property endpoints. type GetTypePropertyParams struct { Snapshot SnapshotID `json:"snapshot"` Project ProjectID `json:"project"` Type TypeID `json:"objectId"` } // GetSymbolPropertyParams is used for all symbol sub-property endpoints. type GetSymbolPropertyParams struct { Snapshot SnapshotID `json:"snapshot"` Project ProjectID `json:"project"` Symbol SymbolID `json:"objectId"` } // GetSignaturePropertyParams is used for all signature sub-property endpoints. type GetSignaturePropertyParams struct { Snapshot SnapshotID `json:"snapshot"` Project ProjectID `json:"project"` Signature SignatureID `json:"objectId"` } // GetContextualTypeParams returns the contextual type for a node. type GetContextualTypeParams struct { Snapshot SnapshotID `json:"snapshot"` Project ProjectID `json:"project"` Location NodeHandle `json:"location"` } // GetTypeOfSymbolAtLocationParams returns the narrowed type of a symbol at a specific location. type GetTypeOfSymbolAtLocationParams struct { Snapshot SnapshotID `json:"snapshot"` Project ProjectID `json:"project"` Symbol SymbolID `json:"symbol"` Location NodeHandle `json:"location"` } // GetReferencesToSymbolInFileParams are the parameters for the getReferencesToSymbolInFile method. type GetReferencesToSymbolInFileParams struct { Snapshot SnapshotID `json:"snapshot"` Project ProjectID `json:"project"` File DocumentIdentifier `json:"file"` Symbol SymbolID `json:"symbol"` } // GetReferencedSymbolsForNodeParams are the parameters for the getReferencedSymbolsForNode method. type GetReferencedSymbolsForNodeParams struct { Snapshot SnapshotID `json:"snapshot"` Project ProjectID `json:"project"` Node NodeHandle `json:"node"` Position int `json:"position"` } // ReferencedSymbolEntry represents a symbol definition and its references. type ReferencedSymbolEntry struct { Definition NodeHandle `json:"definition"` Symbol *SymbolResponse `json:"symbol,omitempty"` References []NodeHandle `json:"references"` } // GetSignatureUsagesParams are the parameters for the getSignatureUsages method. type GetSignatureUsagesParams struct { Snapshot SnapshotID `json:"snapshot"` Project ProjectID `json:"project"` SignatureDecl NodeHandle `json:"signatureDecl"` } // SignatureUsageResponse represents a single usage of a signature as a name-call pair. type SignatureUsageResponse struct { Name NodeHandle `json:"name"` Call NodeHandle `json:"call,omitempty"` } // GetCompletionsAtPositionParams are the parameters for the getCompletionsAtPosition method. type GetCompletionsAtPositionParams struct { Snapshot SnapshotID `json:"snapshot"` Project ProjectID `json:"project"` File DocumentIdentifier `json:"file"` Position uint32 `json:"position"` TriggerCharacter *string `json:"triggerCharacter,omitempty"` IncludeSymbol bool `json:"includeSymbol,omitempty"` } // CompletionEntryLabelDetailsResponse holds additional label display text for a completion entry. type CompletionEntryLabelDetailsResponse struct { Detail *string `json:"detail,omitempty"` Description *string `json:"description,omitempty"` } // CompletionEntryResponse represents a single completion item. type CompletionEntryResponse struct { Name string `json:"name"` Kind uint32 `json:"kind,omitempty"` SortText *string `json:"sortText,omitempty"` InsertText *string `json:"insertText,omitempty"` FilterText *string `json:"filterText,omitempty"` Detail *string `json:"detail,omitempty"` LabelDetails *CompletionEntryLabelDetailsResponse `json:"labelDetails,omitempty"` Symbol *SymbolResponse `json:"symbol,omitempty"` } // CompletionInfoResponse wraps a list of completion entries. type CompletionInfoResponse struct { IsIncomplete bool `json:"isIncomplete"` Entries []*CompletionEntryResponse `json:"entries"` } // GetIntrinsicTypeParams is used for intrinsic type getters (anyType, stringType, etc.). type GetIntrinsicTypeParams struct { Snapshot SnapshotID `json:"snapshot"` Project ProjectID `json:"project"` } // WellKnownSymbolsResponse carries the handle ids of the per-checker singleton // symbols (unknown, undefined, arguments) so the client can identify them by id // without a round-trip on every check. type WellKnownSymbolsResponse struct { Unknown SymbolID `json:"unknown"` Undefined SymbolID `json:"undefined"` Arguments SymbolID `json:"arguments"` } // WellKnownSignaturesResponse carries the handle id of the per-checker singleton // unknown signature (the signature the checker yields when a call cannot be // resolved) so the client can identify it by id without a round-trip on every check. type WellKnownSignaturesResponse struct { Unknown SignatureID `json:"unknown"` } // GetBaseTypeOfLiteralTypeParams returns the base type of a literal type. type GetBaseTypeOfLiteralTypeParams struct { Snapshot SnapshotID `json:"snapshot"` Project ProjectID `json:"project"` Type TypeID `json:"type"` } // GetNonNullableTypeParams are the parameters for the getNonNullableType method. type GetNonNullableTypeParams struct { Snapshot SnapshotID `json:"snapshot"` Project ProjectID `json:"project"` Type TypeID `json:"type"` } // GetTypeFromTypeNodeParams are the parameters for the getTypeFromTypeNode method. type GetTypeFromTypeNodeParams struct { Snapshot SnapshotID `json:"snapshot"` Project ProjectID `json:"project"` Location NodeHandle `json:"location"` } // GetWidenedTypeParams are the parameters for the getWidenedType method. type GetWidenedTypeParams struct { Snapshot SnapshotID `json:"snapshot"` Project ProjectID `json:"project"` Type TypeID `json:"type"` } // GetParameterTypeParams are the parameters for the getParameterType method. type GetParameterTypeParams struct { Snapshot SnapshotID `json:"snapshot"` Project ProjectID `json:"project"` Signature SignatureID `json:"signature"` Index int32 `json:"index"` } // IsArrayLikeTypeParams checks whether a type is array-like. type IsArrayLikeTypeParams struct { Snapshot SnapshotID `json:"snapshot"` Project ProjectID `json:"project"` Type TypeID `json:"type"` } // IsTypeAssignableToParams checks assignability between two types. type IsTypeAssignableToParams struct { Snapshot SnapshotID `json:"snapshot"` Project ProjectID `json:"project"` Source TypeID `json:"source"` Target TypeID `json:"target"` } type GetSignaturesOfTypeParams struct { Snapshot SnapshotID `json:"snapshot"` Project ProjectID `json:"project"` Type TypeID `json:"type"` Kind int32 `json:"kind"` } type GetResolvedSignatureParams struct { Snapshot SnapshotID `json:"snapshot"` Project ProjectID `json:"project"` Location NodeHandle `json:"location"` } type GetTypeAtLocationParams struct { Snapshot SnapshotID `json:"snapshot"` Project ProjectID `json:"project"` Location NodeHandle `json:"location"` } type GetTypeAtLocationsParams struct { Snapshot SnapshotID `json:"snapshot"` Project ProjectID `json:"project"` Locations []NodeHandle `json:"locations"` } type GetTypeAtPositionParams struct { Snapshot SnapshotID `json:"snapshot"` Project ProjectID `json:"project"` File DocumentIdentifier `json:"file"` Position uint32 `json:"position"` } type GetTypesAtPositionsParams struct { Snapshot SnapshotID `json:"snapshot"` Project ProjectID `json:"project"` File DocumentIdentifier `json:"file"` Positions []uint32 `json:"positions"` } // TypeToTypeNodeParams are the parameters for the typeToTypeNode method. type TypeToTypeNodeParams struct { Snapshot SnapshotID `json:"snapshot"` Project ProjectID `json:"project"` Type TypeID `json:"type"` Location NodeHandle `json:"location,omitempty"` Flags int32 `json:"flags,omitempty"` } // SignatureToSignatureDeclarationParams are the parameters for the signatureToSignatureDeclaration method. type SignatureToSignatureDeclarationParams struct { Snapshot SnapshotID `json:"snapshot"` Project ProjectID `json:"project"` Signature SignatureID `json:"signature"` Kind int32 `json:"kind"` Location NodeHandle `json:"location,omitempty"` Flags int32 `json:"flags,omitempty"` } // PrintNodeParams are the parameters for the printNode method. type PrintNodeParams struct { Data string `json:"data"` // base64-encoded binary AST data PreserveSourceNewlines bool `json:"preserveSourceNewlines,omitempty"` NeverAsciiEscape bool `json:"neverAsciiEscape,omitempty"` TerminateUnterminatedLiterals bool `json:"terminateUnterminatedLiterals,omitempty"` } // CheckerTypeParams are parameters for checker methods that operate on a type. type CheckerTypeParams struct { Snapshot SnapshotID `json:"snapshot"` Project ProjectID `json:"project"` Type TypeID `json:"type"` } // GetPropertyOfTypeParams are parameters for getPropertyOfType (a named property of a type). type GetPropertyOfTypeParams struct { Snapshot SnapshotID `json:"snapshot"` Project ProjectID `json:"project"` Type TypeID `json:"type"` Name string `json:"name"` } // GetMemberInModuleExportsParams are parameters for getMemberInModuleExports. type GetMemberInModuleExportsParams struct { Snapshot SnapshotID `json:"snapshot"` Project ProjectID `json:"project"` Symbol SymbolID `json:"symbol"` Name string `json:"name"` } // CheckerNodeParams are parameters for checker methods that operate on a node location. type CheckerNodeParams struct { Snapshot SnapshotID `json:"snapshot"` Project ProjectID `json:"project"` Location NodeHandle `json:"location"` } // CheckerSymbolParams are parameters for checker methods that operate on a symbol. type CheckerSymbolParams struct { Snapshot SnapshotID `json:"snapshot"` Project ProjectID `json:"project"` Symbol SymbolID `json:"symbol"` } // JSDocTagInfo is a single JSDoc tag, mirroring Strada's JSDocTagInfo but with the tag text // rendered as a plain string rather than SymbolDisplayPart[]. type JSDocTagInfo struct { Name string `json:"name"` Text string `json:"text,omitempty"` } // CheckerSignatureParams are parameters for checker methods that operate on a signature. type CheckerSignatureParams struct { Snapshot SnapshotID `json:"snapshot"` Project ProjectID `json:"project"` Signature SignatureID `json:"signature"` } // TypePredicateResponse is the response for getTypePredicateOfSignature. type TypePredicateResponse struct { Kind int32 `json:"kind"` ParameterIndex int32 `json:"parameterIndex"` ParameterName string `json:"parameterName,omitempty"` Type *TypeResponse `json:"type,omitempty"` } // IndexInfoResponse represents a single index signature. type IndexInfoResponse struct { KeyType TypeResponse `json:"keyType"` ValueType TypeResponse `json:"valueType"` IsReadonly bool `json:"isReadonly,omitempty"` Declaration NodeHandle `json:"declaration,omitempty"` } // SourceFileResponse contains the binary-encoded AST data for a source file. // The Data field is base64-encoded binary data in the encoder's format. type SourceFileResponse struct { Data string `json:"data"` } // GetDiagnosticsParams are parameters for per-file diagnostic methods. type GetDiagnosticsParams struct { Snapshot SnapshotID `json:"snapshot"` Project ProjectID `json:"project"` File *DocumentIdentifier `json:"file,omitempty"` } // GetProjectDiagnosticsParams are parameters for project-wide diagnostic methods. type GetProjectDiagnosticsParams struct { Snapshot SnapshotID `json:"snapshot"` Project ProjectID `json:"project"` } // DiagnosticResponse is the API response for a single diagnostic. type DiagnosticResponse struct { // FileName is the path of the file this diagnostic belongs to, if any. FileName string `json:"fileName,omitempty"` // Pos is the start position of the diagnostic in the source file. Pos int `json:"pos"` // End is the end position of the diagnostic in the source file. End int `json:"end"` // Code is the diagnostic error code. Code int32 `json:"code"` // Category is the diagnostic category (error, warning, suggestion, message). Category diagnostics.Category `json:"category"` // Text is the localized diagnostic message text. Text string `json:"text"` // ReportsUnnecessary indicates this diagnostic highlights unnecessary code. ReportsUnnecessary bool `json:"reportsUnnecessary,omitzero"` // ReportsDeprecated indicates this diagnostic highlights deprecated code. ReportsDeprecated bool `json:"reportsDeprecated,omitzero"` // MessageChain contains chained diagnostic messages, if any. MessageChain []*DiagnosticResponse `json:"messageChain,omitempty"` // RelatedInformation contains related diagnostic information, if any. RelatedInformation []*DiagnosticResponse `json:"relatedInformation,omitempty"` } // NewDiagnosticResponse converts an ast.Diagnostic to a DiagnosticResponse. func NewDiagnosticResponse(d *ast.Diagnostic) *DiagnosticResponse { pos := d.Pos() end := d.End() file := d.File() if file != nil { positionMap := file.GetPositionMap() pos = positionMap.UTF8ToUTF16(pos) end = positionMap.UTF8ToUTF16(end) } resp := &DiagnosticResponse{ Pos: pos, End: end, Code: d.Code(), Category: d.Category(), Text: d.Localize(locale.Default), ReportsUnnecessary: d.ReportsUnnecessary(), ReportsDeprecated: d.ReportsDeprecated(), } if file != nil { resp.FileName = file.FileName() } if chain := d.MessageChain(); len(chain) > 0 { resp.MessageChain = make([]*DiagnosticResponse, len(chain)) for i, c := range chain { resp.MessageChain[i] = NewDiagnosticResponse(c) } } if related := d.RelatedInformation(); len(related) > 0 { resp.RelatedInformation = make([]*DiagnosticResponse, len(related)) for i, r := range related { resp.RelatedInformation[i] = NewDiagnosticResponse(r) } } return resp } // NewDiagnosticResponses converts a slice of ast.Diagnostics to DiagnosticResponses. func NewDiagnosticResponses(diags []*ast.Diagnostic) []*DiagnosticResponse { if len(diags) == 0 { return nil } result := make([]*DiagnosticResponse, len(diags)) for i, d := range diags { result[i] = NewDiagnosticResponse(d) } return result } func unmarshalPayload(method string, payload json.Value) (any, error) { unmarshaler, ok := unmarshalers[Method(method)] if !ok { return nil, fmt.Errorf("unknown API method %q", method) } return unmarshaler(payload) } func unmarshallerFor[T any](data []byte) (any, error) { var v T if err := json.Unmarshal(data, &v); err != nil { return nil, fmt.Errorf("failed to unmarshal %T: %w", (*T)(nil), err) } return &v, nil } func noParams(data []byte) (any, error) { return nil, nil }