Files
upstream-ory-keto/schema/parse_errors.go
upstream-mirror 9456a4e922
Some checks failed
CI / Run lints and checks (push) Failing after 47s
CI / Run tests (push) Failing after 1s
CI / Run race tests (push) Failing after 5s
CI / Build CLI docs (push) Has been skipped
CI / Run buf actions (push) Failing after 5s
CodeQL / Analyze (go) (push) Failing after 3s
CodeQL / Analyze (javascript) (push) Failing after 2s
Docker Image Scanners / scanners (push) Failing after 3s
Format / format (push) Failing after 3s
Synchronize Issue Labels / Synchronize Issue Labels (push) Has been skipped
CI / Generate release (push) Has been skipped
CI / Draft newsletter (push) Has been skipped
CI / Pending approval Slack notification (push) Has been skipped
CI / Send newsletter (push) Has been skipped
snapshot of https://github.com/ory/keto.git (master, 2026-09-16; blobs > 131072B omitted)
2026-09-16 01:08:34 +05:00

130 lines
2.5 KiB
Go

// Copyright © 2023 Ory Corp
// SPDX-License-Identifier: Apache-2.0
package schema
import (
"fmt"
"math"
"strings"
"unicode"
opl "github.com/ory/keto/gen/go/ory/keto/opl/v1alpha1"
"github.com/ory/keto/ketoapi"
)
type (
ParseError struct {
msg string
item item
p *parser
}
)
func max(a, b int) int {
if a > b {
return a
}
return b
}
func (e *ParseError) Error() string {
var s strings.Builder
start := e.toSrcPos(e.item.Start)
end := e.toSrcPos(e.item.End)
rows := e.rows()
startLineIdx := max(start.Line-2, 0)
errorLineIdx := max(start.Line-1, 0)
_, _ = fmt.Fprintf(&s, "error from %d:%d to %d:%d: %s\n\n",
start.Line, start.Col,
end.Line, end.Col,
e.msg)
if len(rows) < start.Line {
s.WriteString("meta error: could not find source position in input\n")
return s.String()
}
for line := startLineIdx; line <= errorLineIdx; line++ {
_, _ = fmt.Fprintf(&s, "%4d | %s\n", line, rows[line])
}
s.WriteString(" | ")
for i, r := range rows[errorLineIdx] {
switch {
case start.Col == i:
s.WriteRune('^')
case start.Col <= i && i <= end.Col-1:
s.WriteRune('~')
case unicode.IsSpace(r):
s.WriteRune(r)
default:
s.WriteRune(' ')
}
}
s.WriteRune('\n')
if errorLineIdx+1 < len(rows) {
_, _ = fmt.Fprintf(&s, "%4d | %s\n", errorLineIdx+1, rows[errorLineIdx+1])
s.WriteRune('\n')
}
return s.String()
}
func (e *ParseError) ToAPI() *ketoapi.ParseError {
return &ketoapi.ParseError{
Message: e.msg,
Start: e.toSrcPos(e.item.Start),
End: e.toSrcPos(e.item.End),
}
}
func (e *ParseError) ToProto() *opl.ParseError {
start := e.toSrcPos(e.item.Start)
end := e.toSrcPos(e.item.End)
return &opl.ParseError{
Message: e.msg,
Start: &opl.SourcePosition{
Line: clampUint32(start.Line),
Column: clampUint32(start.Col),
},
End: &opl.SourcePosition{
Line: clampUint32(end.Line),
Column: clampUint32(end.Col),
},
}
}
// toSrcPos converts the given position in the input to a Line and column
// number.
func (e *ParseError) toSrcPos(pos int) (srcPos ketoapi.SourcePosition) {
srcPos.Line = 1
for _, c := range e.p.lexer.input {
srcPos.Col++
pos--
if pos <= 0 {
break
}
if c == '\n' {
srcPos.Line++
srcPos.Col = 0
}
}
return
}
func clampUint32(v int) uint32 {
switch {
case v < 0:
return 0
case uint64(v) > math.MaxUint32:
return math.MaxUint32
default:
return uint32(v)
}
}
func (e *ParseError) rows() []string {
return strings.Split(e.p.lexer.input, "\n")
}