diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 12:36:04 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 12:36:04 +0000 |
commit | b09c6d56832eb1718c07d74abf3bc6ae3fe4e030 (patch) | |
tree | d2caec2610d4ea887803ec9e9c3cd77136c448ba /dependencies/pkg/mod/github.com/goccy/go-yaml@v1.9.6/printer | |
parent | Initial commit. (diff) | |
download | icingadb-upstream.tar.xz icingadb-upstream.zip |
Adding upstream version 1.1.0.upstream/1.1.0upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'dependencies/pkg/mod/github.com/goccy/go-yaml@v1.9.6/printer')
-rw-r--r-- | dependencies/pkg/mod/github.com/goccy/go-yaml@v1.9.6/printer/printer.go | 352 | ||||
-rw-r--r-- | dependencies/pkg/mod/github.com/goccy/go-yaml@v1.9.6/printer/printer_test.go | 223 |
2 files changed, 575 insertions, 0 deletions
diff --git a/dependencies/pkg/mod/github.com/goccy/go-yaml@v1.9.6/printer/printer.go b/dependencies/pkg/mod/github.com/goccy/go-yaml@v1.9.6/printer/printer.go new file mode 100644 index 0000000..d5e25dc --- /dev/null +++ b/dependencies/pkg/mod/github.com/goccy/go-yaml@v1.9.6/printer/printer.go @@ -0,0 +1,352 @@ +package printer + +import ( + "fmt" + "math" + "strings" + + "github.com/fatih/color" + "github.com/goccy/go-yaml/ast" + "github.com/goccy/go-yaml/token" +) + +// Property additional property set for each the token +type Property struct { + Prefix string + Suffix string +} + +// PrintFunc returns property instance +type PrintFunc func() *Property + +// Printer create text from token collection or ast +type Printer struct { + LineNumber bool + LineNumberFormat func(num int) string + MapKey PrintFunc + Anchor PrintFunc + Alias PrintFunc + Bool PrintFunc + String PrintFunc + Number PrintFunc +} + +func defaultLineNumberFormat(num int) string { + return fmt.Sprintf("%2d | ", num) +} + +func (p *Printer) property(tk *token.Token) *Property { + prop := &Property{} + switch tk.PreviousType() { + case token.AnchorType: + if p.Anchor != nil { + return p.Anchor() + } + return prop + case token.AliasType: + if p.Alias != nil { + return p.Alias() + } + return prop + } + switch tk.NextType() { + case token.MappingValueType: + if p.MapKey != nil { + return p.MapKey() + } + return prop + } + switch tk.Type { + case token.BoolType: + if p.Bool != nil { + return p.Bool() + } + return prop + case token.AnchorType: + if p.Anchor != nil { + return p.Anchor() + } + return prop + case token.AliasType: + if p.Anchor != nil { + return p.Alias() + } + return prop + case token.StringType, token.SingleQuoteType, token.DoubleQuoteType: + if p.String != nil { + return p.String() + } + return prop + case token.IntegerType, token.FloatType: + if p.Number != nil { + return p.Number() + } + return prop + default: + } + return prop +} + +// PrintTokens create text from token collection +func (p *Printer) PrintTokens(tokens token.Tokens) string { + if len(tokens) == 0 { + return "" + } + if p.LineNumber { + if p.LineNumberFormat == nil { + p.LineNumberFormat = defaultLineNumberFormat + } + } + texts := []string{} + lineNumber := tokens[0].Position.Line + for _, tk := range tokens { + lines := strings.Split(tk.Origin, "\n") + prop := p.property(tk) + header := "" + if p.LineNumber { + header = p.LineNumberFormat(lineNumber) + } + if len(lines) == 1 { + line := prop.Prefix + lines[0] + prop.Suffix + if len(texts) == 0 { + texts = append(texts, header+line) + lineNumber++ + } else { + text := texts[len(texts)-1] + texts[len(texts)-1] = text + line + } + } else { + for idx, src := range lines { + if p.LineNumber { + header = p.LineNumberFormat(lineNumber) + } + line := prop.Prefix + src + prop.Suffix + if idx == 0 { + if len(texts) == 0 { + texts = append(texts, header+line) + lineNumber++ + } else { + text := texts[len(texts)-1] + texts[len(texts)-1] = text + line + } + } else { + texts = append(texts, fmt.Sprintf("%s%s", header, line)) + lineNumber++ + } + } + } + } + return strings.Join(texts, "\n") +} + +// PrintNode create text from ast.Node +func (p *Printer) PrintNode(node ast.Node) []byte { + return []byte(fmt.Sprintf("%+v\n", node)) +} + +const escape = "\x1b" + +func format(attr color.Attribute) string { + return fmt.Sprintf("%s[%dm", escape, attr) +} + +func (p *Printer) setDefaultColorSet() { + p.Bool = func() *Property { + return &Property{ + Prefix: format(color.FgHiMagenta), + Suffix: format(color.Reset), + } + } + p.Number = func() *Property { + return &Property{ + Prefix: format(color.FgHiMagenta), + Suffix: format(color.Reset), + } + } + p.MapKey = func() *Property { + return &Property{ + Prefix: format(color.FgHiCyan), + Suffix: format(color.Reset), + } + } + p.Anchor = func() *Property { + return &Property{ + Prefix: format(color.FgHiYellow), + Suffix: format(color.Reset), + } + } + p.Alias = func() *Property { + return &Property{ + Prefix: format(color.FgHiYellow), + Suffix: format(color.Reset), + } + } + p.String = func() *Property { + return &Property{ + Prefix: format(color.FgHiGreen), + Suffix: format(color.Reset), + } + } +} + +func (p *Printer) PrintErrorMessage(msg string, isColored bool) string { + if isColored { + return fmt.Sprintf("%s%s%s", + format(color.FgHiRed), + msg, + format(color.Reset), + ) + } + return msg +} + +func (p *Printer) removeLeftSideNewLineChar(src string) string { + return strings.TrimLeft(strings.TrimLeft(strings.TrimLeft(src, "\r"), "\n"), "\r\n") +} + +func (p *Printer) removeRightSideNewLineChar(src string) string { + return strings.TrimRight(strings.TrimRight(strings.TrimRight(src, "\r"), "\n"), "\r\n") +} + +func (p *Printer) removeRightSideWhiteSpaceChar(src string) string { + return p.removeRightSideNewLineChar(strings.TrimRight(src, " ")) +} + +func (p *Printer) newLineCount(s string) int { + src := []rune(s) + size := len(src) + cnt := 0 + for i := 0; i < size; i++ { + c := src[i] + switch c { + case '\r': + if i+1 < size && src[i+1] == '\n' { + i++ + } + cnt++ + case '\n': + cnt++ + } + } + return cnt +} + +func (p *Printer) isNewLineLastChar(s string) bool { + for i := len(s) - 1; i > 0; i-- { + c := s[i] + switch c { + case ' ': + continue + case '\n', '\r': + return true + } + break + } + return false +} + +func (p *Printer) printBeforeTokens(tk *token.Token, minLine, extLine int) token.Tokens { + for { + if tk.Prev == nil { + break + } + if tk.Prev.Position.Line < minLine { + break + } + tk = tk.Prev + } + minTk := tk.Clone() + if minTk.Prev != nil { + // add white spaces to minTk by prev token + prev := minTk.Prev + whiteSpaceLen := len(prev.Origin) - len(strings.TrimRight(prev.Origin, " ")) + minTk.Origin = strings.Repeat(" ", whiteSpaceLen) + minTk.Origin + } + minTk.Origin = p.removeLeftSideNewLineChar(minTk.Origin) + tokens := token.Tokens{minTk} + tk = minTk.Next + for tk != nil && tk.Position.Line <= extLine { + clonedTk := tk.Clone() + tokens.Add(clonedTk) + tk = clonedTk.Next + } + lastTk := tokens[len(tokens)-1] + trimmedOrigin := p.removeRightSideWhiteSpaceChar(lastTk.Origin) + suffix := lastTk.Origin[len(trimmedOrigin):] + lastTk.Origin = trimmedOrigin + + if lastTk.Next != nil && len(suffix) > 1 { + next := lastTk.Next.Clone() + // add suffix to header of next token + if suffix[0] == '\n' || suffix[0] == '\r' { + suffix = suffix[1:] + } + next.Origin = suffix + next.Origin + lastTk.Next = next + } + return tokens +} + +func (p *Printer) printAfterTokens(tk *token.Token, maxLine int) token.Tokens { + tokens := token.Tokens{} + if tk == nil { + return tokens + } + if tk.Position.Line > maxLine { + return tokens + } + minTk := tk.Clone() + minTk.Origin = p.removeLeftSideNewLineChar(minTk.Origin) + tokens.Add(minTk) + tk = minTk.Next + for tk != nil && tk.Position.Line <= maxLine { + clonedTk := tk.Clone() + tokens.Add(clonedTk) + tk = clonedTk.Next + } + return tokens +} + +func (p *Printer) setupErrorTokenFormat(annotateLine int, isColored bool) { + prefix := func(annotateLine, num int) string { + if annotateLine == num { + return fmt.Sprintf("> %2d | ", num) + } + return fmt.Sprintf(" %2d | ", num) + } + p.LineNumber = true + p.LineNumberFormat = func(num int) string { + if isColored { + fn := color.New(color.Bold, color.FgHiWhite).SprintFunc() + return fn(prefix(annotateLine, num)) + } + return prefix(annotateLine, num) + } + if isColored { + p.setDefaultColorSet() + } +} + +func (p *Printer) PrintErrorToken(tk *token.Token, isColored bool) string { + errToken := tk + curLine := tk.Position.Line + curExtLine := curLine + p.newLineCount(p.removeLeftSideNewLineChar(tk.Origin)) + if p.isNewLineLastChar(tk.Origin) { + // if last character ( exclude white space ) is new line character, ignore it. + curExtLine-- + } + + minLine := int(math.Max(float64(curLine-3), 1)) + maxLine := curExtLine + 3 + p.setupErrorTokenFormat(curLine, isColored) + + beforeTokens := p.printBeforeTokens(tk, minLine, curExtLine) + lastTk := beforeTokens[len(beforeTokens)-1] + afterTokens := p.printAfterTokens(lastTk.Next, maxLine) + + beforeSource := p.PrintTokens(beforeTokens) + prefixSpaceNum := len(fmt.Sprintf(" %2d | ", curLine)) + annotateLine := strings.Repeat(" ", prefixSpaceNum+errToken.Position.Column-1) + "^" + afterSource := p.PrintTokens(afterTokens) + return fmt.Sprintf("%s\n%s\n%s", beforeSource, annotateLine, afterSource) +} diff --git a/dependencies/pkg/mod/github.com/goccy/go-yaml@v1.9.6/printer/printer_test.go b/dependencies/pkg/mod/github.com/goccy/go-yaml@v1.9.6/printer/printer_test.go new file mode 100644 index 0000000..2afa74f --- /dev/null +++ b/dependencies/pkg/mod/github.com/goccy/go-yaml@v1.9.6/printer/printer_test.go @@ -0,0 +1,223 @@ +package printer_test + +import ( + "fmt" + "testing" + + "github.com/goccy/go-yaml/lexer" + "github.com/goccy/go-yaml/printer" +) + +func Test_Printer(t *testing.T) { + yml := `--- +text: aaaa +text2: aaaa + bbbb + cccc + dddd + eeee +text3: ffff + gggg + hhhh + iiii + jjjj +bool: true +number: 10 +anchor: &x 1 +alias: *x +` + t.Run("print starting from tokens[3]", func(t *testing.T) { + tokens := lexer.Tokenize(yml) + var p printer.Printer + actual := "\n" + p.PrintErrorToken(tokens[3], false) + expect := ` + 1 | --- +> 2 | text: aaaa + ^ + 3 | text2: aaaa + 4 | bbbb + 5 | cccc + 6 | dddd + 7 | eeee + 8 | ` + if actual != expect { + t.Fatalf("unexpected output: expect:[%s]\n actual:[%s]", expect, actual) + } + }) + t.Run("print starting from tokens[4]", func(t *testing.T) { + tokens := lexer.Tokenize(yml) + var p printer.Printer + actual := "\n" + p.PrintErrorToken(tokens[4], false) + expect := ` + 1 | --- + 2 | text: aaaa +> 3 | text2: aaaa + 4 | bbbb + 5 | cccc + 6 | dddd + 7 | eeee + ^ +` + if actual != expect { + t.Fatalf("unexpected output: expect:[%s]\n actual:[%s]", expect, actual) + } + }) + t.Run("print starting from tokens[6]", func(t *testing.T) { + tokens := lexer.Tokenize(yml) + var p printer.Printer + actual := "\n" + p.PrintErrorToken(tokens[6], false) + expect := ` + 1 | --- + 2 | text: aaaa +> 3 | text2: aaaa + 4 | bbbb + 5 | cccc + 6 | dddd + 7 | eeee + ^ + 8 | text3: ffff + 9 | gggg + 10 | hhhh + 11 | iiii + 12 | jjjj + 13 | ` + if actual != expect { + t.Fatalf("unexpected output: expect:[%s]\n actual:[%s]", expect, actual) + } + }) + t.Run("print error token with document header", func(t *testing.T) { + tokens := lexer.Tokenize(`--- +a: + b: + c: + d: e + f: g + h: i + +--- +`) + expect := ` + 3 | b: + 4 | c: + 5 | d: e +> 6 | f: g + ^ + 7 | h: i + 8 | + 9 | ---` + var p printer.Printer + actual := "\n" + p.PrintErrorToken(tokens[12], false) + if actual != expect { + t.Fatalf("unexpected output: expect:[%s]\n actual:[%s]", expect, actual) + } + }) + t.Run("output with color", func(t *testing.T) { + t.Run("token6", func(t *testing.T) { + tokens := lexer.Tokenize(yml) + var p printer.Printer + t.Logf("\n%s", p.PrintErrorToken(tokens[6], true)) + }) + t.Run("token9", func(t *testing.T) { + tokens := lexer.Tokenize(yml) + var p printer.Printer + t.Logf("\n%s", p.PrintErrorToken(tokens[9], true)) + }) + t.Run("token12", func(t *testing.T) { + tokens := lexer.Tokenize(yml) + var p printer.Printer + t.Logf("\n%s", p.PrintErrorToken(tokens[12], true)) + }) + }) + t.Run("print error message", func(t *testing.T) { + var p printer.Printer + src := "message" + msg := p.PrintErrorMessage(src, false) + if msg != src { + t.Fatal("unexpected result") + } + p.PrintErrorMessage(src, true) + }) +} + +func TestPrinter_Anchor(t *testing.T) { + expected := ` +anchor: &x 1 +alias: *x` + tokens := lexer.Tokenize(expected) + var p printer.Printer + got := p.PrintTokens(tokens) + if expected != got { + t.Fatalf("unexpected output: expect:[%s]\n actual:[%s]", expected, got) + } +} + +func Test_Printer_Multiline(t *testing.T) { + yml := ` +text1: 'aaaa + bbbb + cccc' +text2: "ffff + gggg + hhhh" +text3: hello +` + tc := []struct { + token int + want string + }{ + { + token: 2, + want: ` +> 2 | text1: 'aaaa + 3 | bbbb + 4 | cccc' + ^ + 5 | text2: "ffff + 6 | gggg + 7 | hhhh"`, + }, + {token: 3, + want: ` + 2 | text1: 'aaaa + 3 | bbbb + 4 | cccc' +> 5 | text2: "ffff + 6 | gggg + 7 | hhhh" + ^ + 8 | text3: hello`, + }, + {token: 5, + want: ` + 2 | text1: 'aaaa + 3 | bbbb + 4 | cccc' +> 5 | text2: "ffff + 6 | gggg + 7 | hhhh" + ^ + 8 | text3: hello`, + }, + {token: 6, + want: ` + 5 | text2: "ffff + 6 | gggg + 7 | hhhh" +> 8 | text3: hello + ^ +`, + }, + } + for _, tt := range tc { + name := fmt.Sprintf("print starting from tokens[%d]", tt.token) + t.Run(name, func(t *testing.T) { + tokens := lexer.Tokenize(yml) + var p printer.Printer + got := "\n" + p.PrintErrorToken(tokens[tt.token], false) + want := tt.want + if got != want { + t.Fatalf("PrintErrorToken() got: %s\n want:%s\n", want, got) + } + }) + } +} |