Files
gitea/services/sourcegraph/graphql.go
2026-02-03 19:14:07 -10:00

238 lines
5.4 KiB
Go

// Copyright 2025 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package sourcegraph
import (
"encoding/json"
"fmt"
)
// GraphQL queries for Sourcegraph API
const hoverQuery = `
query Hover($repo: String!, $rev: String!, $path: String!, $line: Int!, $char: Int!) {
repository(name: $repo) {
commit(rev: $rev) {
blob(path: $path) {
lsif {
hover(line: $line, character: $char) {
markdown {
text
}
range {
start { line character }
end { line character }
}
}
}
}
}
}
}
`
const definitionQuery = `
query Definition($repo: String!, $rev: String!, $path: String!, $line: Int!, $char: Int!) {
repository(name: $repo) {
commit(rev: $rev) {
blob(path: $path) {
lsif {
definitions(line: $line, character: $char) {
nodes {
resource {
path
repository {
name
}
commit {
oid
}
}
range {
start { line character }
end { line character }
}
}
}
}
}
}
}
}
`
const referencesQuery = `
query References($repo: String!, $rev: String!, $path: String!, $line: Int!, $char: Int!) {
repository(name: $repo) {
commit(rev: $rev) {
blob(path: $path) {
lsif {
references(line: $line, character: $char, first: 100) {
nodes {
resource {
path
repository {
name
}
commit {
oid
}
}
range {
start { line character }
end { line character }
}
}
}
}
}
}
}
}
`
const syncRepoMutation = `
mutation SyncRepo($repo: String!) {
scheduleRepositoryPermissionsSync(repository: $repo) {
alwaysNil
}
}
`
// Response parsing structures
type hoverResponse struct {
Repository *struct {
Commit *struct {
Blob *struct {
LSIF *struct {
Hover *struct {
Markdown *struct {
Text string `json:"text"`
} `json:"markdown"`
Range *struct {
Start struct {
Line int `json:"line"`
Character int `json:"character"`
} `json:"start"`
End struct {
Line int `json:"line"`
Character int `json:"character"`
} `json:"end"`
} `json:"range"`
} `json:"hover"`
} `json:"lsif"`
} `json:"blob"`
} `json:"commit"`
} `json:"repository"`
}
type locationsResponse struct {
Repository *struct {
Commit *struct {
Blob *struct {
LSIF *struct {
Definitions *locationNodes `json:"definitions,omitempty"`
References *locationNodes `json:"references,omitempty"`
} `json:"lsif"`
} `json:"blob"`
} `json:"commit"`
} `json:"repository"`
}
type locationNodes struct {
Nodes []struct {
Resource struct {
Path string `json:"path"`
Repository struct {
Name string `json:"name"`
} `json:"repository"`
Commit struct {
OID string `json:"oid"`
} `json:"commit"`
} `json:"resource"`
Range struct {
Start struct {
Line int `json:"line"`
Character int `json:"character"`
} `json:"start"`
End struct {
Line int `json:"line"`
Character int `json:"character"`
} `json:"end"`
} `json:"range"`
} `json:"nodes"`
}
func parseHoverResponse(data json.RawMessage) (*HoverResult, error) {
var resp hoverResponse
if err := json.Unmarshal(data, &resp); err != nil {
return nil, fmt.Errorf("failed to parse hover response: %w", err)
}
if resp.Repository == nil || resp.Repository.Commit == nil ||
resp.Repository.Commit.Blob == nil || resp.Repository.Commit.Blob.LSIF == nil ||
resp.Repository.Commit.Blob.LSIF.Hover == nil {
return nil, nil // No hover info available
}
hover := resp.Repository.Commit.Blob.LSIF.Hover
result := &HoverResult{}
if hover.Markdown != nil {
result.Contents = hover.Markdown.Text
}
if hover.Range != nil {
result.Range = &Range{
Start: Position{
Line: hover.Range.Start.Line,
Character: hover.Range.Start.Character,
},
End: Position{
Line: hover.Range.End.Line,
Character: hover.Range.End.Character,
},
}
}
return result, nil
}
func parseLocationsResponse(data json.RawMessage, field string) ([]Location, error) {
var resp locationsResponse
if err := json.Unmarshal(data, &resp); err != nil {
return nil, fmt.Errorf("failed to parse locations response: %w", err)
}
if resp.Repository == nil || resp.Repository.Commit == nil ||
resp.Repository.Commit.Blob == nil || resp.Repository.Commit.Blob.LSIF == nil {
return nil, nil
}
var nodes *locationNodes
switch field {
case "definitions":
nodes = resp.Repository.Commit.Blob.LSIF.Definitions
case "references":
nodes = resp.Repository.Commit.Blob.LSIF.References
}
if nodes == nil {
return nil, nil
}
locations := make([]Location, 0, len(nodes.Nodes))
for _, node := range nodes.Nodes {
locations = append(locations, Location{
Repo: node.Resource.Repository.Name,
Path: node.Resource.Path,
Line: node.Range.Start.Line,
Character: node.Range.Start.Character,
})
}
return locations, nil
}