package gqlerrors
import (
"fmt"
"regexp"
"strings"
"github.com/graphql-go/graphql/language/ast"
"github.com/graphql-go/graphql/language/location"
"github.com/graphql-go/graphql/language/source"
)
func NewSyntaxError(s *source.Source, position int, description string) *Error {
l := location.GetLocation(s, position)
return NewError(
fmt.Sprintf("Syntax Error %s (%d:%d) %s\n\n%s", s.Name, l.Line, l.Column, description, highlightSourceAtLocation(s, l)),
[]ast.Node{},
"",
s,
[]int{position},
nil,
)
}
// printCharCode here is slightly different from lexer.printCharCode()
func printCharCode(code rune) string {
// print as ASCII for printable range
if code >= 0x0020 {
return fmt.Sprintf(`%c`, code)
}
// Otherwise print the escaped form. e.g. `"\\u0007"`
return fmt.Sprintf(`\u%04X`, code)
}
func printLine(str string) string {
strSlice := []string{}
for _, runeValue := range str {
strSlice = append(strSlice, printCharCode(runeValue))
}
return fmt.Sprintf(`%s`, strings.Join(strSlice, ""))
}
func highlightSourceAtLocation(s *source.Source, l location.SourceLocation) string {
line := l.Line
prevLineNum := fmt.Sprintf("%d", (line - 1))
lineNum := fmt.Sprintf("%d", line)
nextLineNum := fmt.Sprintf("%d", (line + 1))
padLen := len(nextLineNum)
lines := regexp.MustCompile("\r\n|[\n\r]").Split(string(s.Body), -1)
var highlight string
if line >= 2 {
highlight += fmt.Sprintf("%s: %s\n", lpad(padLen, prevLineNum), printLine(lines[line-2]))
}
highlight += fmt.Sprintf("%s: %s\n", lpad(padLen, lineNum), printLine(lines[line-1]))
for i := 1; i < (2 + padLen + l.Column); i++ {
highlight += " "
}
highlight += "^\n"
if line < len(lines) {
highlight += fmt.Sprintf("%s: %s\n", lpad(padLen, nextLineNum), printLine(lines[line]))
}
return highlight
}
func lpad(l int, s string) string {
var r string
for i := 1; i < (l - len(s) + 1); i++ {
r += " "
}
return r + s
}