vendor/github.com/pelletier/go-toml/v2/errors.go
changeset 260 445e01aede7e
child 265 05c40b36d3b2
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vendor/github.com/pelletier/go-toml/v2/errors.go	Tue Aug 23 22:39:43 2022 +0200
@@ -0,0 +1,270 @@
+package toml
+
+import (
+	"fmt"
+	"strconv"
+	"strings"
+
+	"github.com/pelletier/go-toml/v2/internal/danger"
+)
+
+// DecodeError represents an error encountered during the parsing or decoding
+// of a TOML document.
+//
+// In addition to the error message, it contains the position in the document
+// where it happened, as well as a human-readable representation that shows
+// where the error occurred in the document.
+type DecodeError struct {
+	message string
+	line    int
+	column  int
+	key     Key
+
+	human string
+}
+
+// StrictMissingError occurs in a TOML document that does not have a
+// corresponding field in the target value. It contains all the missing fields
+// in Errors.
+//
+// Emitted by Decoder when DisallowUnknownFields() was called.
+type StrictMissingError struct {
+	// One error per field that could not be found.
+	Errors []DecodeError
+}
+
+// Error returns the canonical string for this error.
+func (s *StrictMissingError) Error() string {
+	return "strict mode: fields in the document are missing in the target struct"
+}
+
+// String returns a human readable description of all errors.
+func (s *StrictMissingError) String() string {
+	var buf strings.Builder
+
+	for i, e := range s.Errors {
+		if i > 0 {
+			buf.WriteString("\n---\n")
+		}
+
+		buf.WriteString(e.String())
+	}
+
+	return buf.String()
+}
+
+type Key []string
+
+// internal version of DecodeError that is used as the base to create a
+// DecodeError with full context.
+type decodeError struct {
+	highlight []byte
+	message   string
+	key       Key // optional
+}
+
+func (de *decodeError) Error() string {
+	return de.message
+}
+
+func newDecodeError(highlight []byte, format string, args ...interface{}) error {
+	return &decodeError{
+		highlight: highlight,
+		message:   fmt.Errorf(format, args...).Error(),
+	}
+}
+
+// Error returns the error message contained in the DecodeError.
+func (e *DecodeError) Error() string {
+	return "toml: " + e.message
+}
+
+// String returns the human-readable contextualized error. This string is multi-line.
+func (e *DecodeError) String() string {
+	return e.human
+}
+
+// Position returns the (line, column) pair indicating where the error
+// occurred in the document. Positions are 1-indexed.
+func (e *DecodeError) Position() (row int, column int) {
+	return e.line, e.column
+}
+
+// Key that was being processed when the error occurred. The key is present only
+// if this DecodeError is part of a StrictMissingError.
+func (e *DecodeError) Key() Key {
+	return e.key
+}
+
+// decodeErrorFromHighlight creates a DecodeError referencing a highlighted
+// range of bytes from document.
+//
+// highlight needs to be a sub-slice of document, or this function panics.
+//
+// The function copies all bytes used in DecodeError, so that document and
+// highlight can be freely deallocated.
+//
+//nolint:funlen
+func wrapDecodeError(document []byte, de *decodeError) *DecodeError {
+	offset := danger.SubsliceOffset(document, de.highlight)
+
+	errMessage := de.Error()
+	errLine, errColumn := positionAtEnd(document[:offset])
+	before, after := linesOfContext(document, de.highlight, offset, 3)
+
+	var buf strings.Builder
+
+	maxLine := errLine + len(after) - 1
+	lineColumnWidth := len(strconv.Itoa(maxLine))
+
+	// Write the lines of context strictly before the error.
+	for i := len(before) - 1; i > 0; i-- {
+		line := errLine - i
+		buf.WriteString(formatLineNumber(line, lineColumnWidth))
+		buf.WriteString("|")
+
+		if len(before[i]) > 0 {
+			buf.WriteString(" ")
+			buf.Write(before[i])
+		}
+
+		buf.WriteRune('\n')
+	}
+
+	// Write the document line that contains the error.
+
+	buf.WriteString(formatLineNumber(errLine, lineColumnWidth))
+	buf.WriteString("| ")
+
+	if len(before) > 0 {
+		buf.Write(before[0])
+	}
+
+	buf.Write(de.highlight)
+
+	if len(after) > 0 {
+		buf.Write(after[0])
+	}
+
+	buf.WriteRune('\n')
+
+	// Write the line with the error message itself (so it does not have a line
+	// number).
+
+	buf.WriteString(strings.Repeat(" ", lineColumnWidth))
+	buf.WriteString("| ")
+
+	if len(before) > 0 {
+		buf.WriteString(strings.Repeat(" ", len(before[0])))
+	}
+
+	buf.WriteString(strings.Repeat("~", len(de.highlight)))
+
+	if len(errMessage) > 0 {
+		buf.WriteString(" ")
+		buf.WriteString(errMessage)
+	}
+
+	// Write the lines of context strictly after the error.
+
+	for i := 1; i < len(after); i++ {
+		buf.WriteRune('\n')
+		line := errLine + i
+		buf.WriteString(formatLineNumber(line, lineColumnWidth))
+		buf.WriteString("|")
+
+		if len(after[i]) > 0 {
+			buf.WriteString(" ")
+			buf.Write(after[i])
+		}
+	}
+
+	return &DecodeError{
+		message: errMessage,
+		line:    errLine,
+		column:  errColumn,
+		key:     de.key,
+		human:   buf.String(),
+	}
+}
+
+func formatLineNumber(line int, width int) string {
+	format := "%" + strconv.Itoa(width) + "d"
+
+	return fmt.Sprintf(format, line)
+}
+
+func linesOfContext(document []byte, highlight []byte, offset int, linesAround int) ([][]byte, [][]byte) {
+	return beforeLines(document, offset, linesAround), afterLines(document, highlight, offset, linesAround)
+}
+
+func beforeLines(document []byte, offset int, linesAround int) [][]byte {
+	var beforeLines [][]byte
+
+	// Walk the document backward from the highlight to find previous lines
+	// of context.
+	rest := document[:offset]
+backward:
+	for o := len(rest) - 1; o >= 0 && len(beforeLines) <= linesAround && len(rest) > 0; {
+		switch {
+		case rest[o] == '\n':
+			// handle individual lines
+			beforeLines = append(beforeLines, rest[o+1:])
+			rest = rest[:o]
+			o = len(rest) - 1
+		case o == 0:
+			// add the first line only if it's non-empty
+			beforeLines = append(beforeLines, rest)
+
+			break backward
+		default:
+			o--
+		}
+	}
+
+	return beforeLines
+}
+
+func afterLines(document []byte, highlight []byte, offset int, linesAround int) [][]byte {
+	var afterLines [][]byte
+
+	// Walk the document forward from the highlight to find the following
+	// lines of context.
+	rest := document[offset+len(highlight):]
+forward:
+	for o := 0; o < len(rest) && len(afterLines) <= linesAround; {
+		switch {
+		case rest[o] == '\n':
+			// handle individual lines
+			afterLines = append(afterLines, rest[:o])
+			rest = rest[o+1:]
+			o = 0
+
+		case o == len(rest)-1:
+			// add last line only if it's non-empty
+			afterLines = append(afterLines, rest)
+
+			break forward
+		default:
+			o++
+		}
+	}
+
+	return afterLines
+}
+
+func positionAtEnd(b []byte) (row int, column int) {
+	row = 1
+	column = 1
+
+	for _, c := range b {
+		if c == '\n' {
+			row++
+			column = 1
+		} else {
+			column++
+		}
+	}
+
+	return
+}