gitlab-org--gitlab-foss/workhorse/internal/lsif_transformer/parser/docs.go

145 lines
2.5 KiB
Go

package parser
import (
"archive/zip"
"bufio"
"encoding/json"
"io"
"strings"
)
const maxScanTokenSize = 1024 * 1024
type Line struct {
Type string `json:"label"`
}
type Docs struct {
Root string
Entries map[Id]string
DocRanges map[Id][]Id
Ranges *Ranges
}
type Document struct {
Id Id `json:"id"`
Uri string `json:"uri"`
}
type DocumentRange struct {
OutV Id `json:"outV"`
RangeIds []Id `json:"inVs"`
}
type Metadata struct {
Root string `json:"projectRoot"`
}
func NewDocs() (*Docs, error) {
ranges, err := NewRanges()
if err != nil {
return nil, err
}
return &Docs{
Root: "file:///",
Entries: make(map[Id]string),
DocRanges: make(map[Id][]Id),
Ranges: ranges,
}, nil
}
func (d *Docs) Parse(r io.Reader) error {
scanner := bufio.NewScanner(r)
buf := make([]byte, 0, bufio.MaxScanTokenSize)
scanner.Buffer(buf, maxScanTokenSize)
for scanner.Scan() {
if err := d.process(scanner.Bytes()); err != nil {
return err
}
}
return scanner.Err()
}
func (d *Docs) process(line []byte) error {
l := Line{}
if err := json.Unmarshal(line, &l); err != nil {
return err
}
switch l.Type {
case "metaData":
if err := d.addMetadata(line); err != nil {
return err
}
case "document":
if err := d.addDocument(line); err != nil {
return err
}
case "contains":
if err := d.addDocRanges(line); err != nil {
return err
}
default:
return d.Ranges.Read(l.Type, line)
}
return nil
}
func (d *Docs) Close() error {
return d.Ranges.Close()
}
func (d *Docs) SerializeEntries(w *zip.Writer) error {
for id, path := range d.Entries {
filePath := Lsif + "/" + path + ".json"
f, err := w.Create(filePath)
if err != nil {
return err
}
if err := d.Ranges.Serialize(f, d.DocRanges[id], d.Entries); err != nil {
return err
}
}
return nil
}
func (d *Docs) addMetadata(line []byte) error {
var metadata Metadata
if err := json.Unmarshal(line, &metadata); err != nil {
return err
}
d.Root = strings.TrimSpace(metadata.Root) + "/"
return nil
}
func (d *Docs) addDocument(line []byte) error {
var doc Document
if err := json.Unmarshal(line, &doc); err != nil {
return err
}
d.Entries[doc.Id] = strings.TrimPrefix(doc.Uri, d.Root)
return nil
}
func (d *Docs) addDocRanges(line []byte) error {
var docRange DocumentRange
if err := json.Unmarshal(line, &docRange); err != nil {
return err
}
d.DocRanges[docRange.OutV] = append(d.DocRanges[docRange.OutV], docRange.RangeIds...)
return nil
}