refactor: inline UTF-8 BOM skip instead of utfbom dependency

per ccoVeille's review, front matter only needs UTF-8 BOM handling, not
the full utfbom package. replace utfbom.Skip with a small unexported
stripUTF8BOM helper and add a stdin-path regression test alongside the
existing file-path one. utfbom stays in go.mod since decoder_csv_object.go
still uses it for CSV decoding.
This commit is contained in:
StressTestor 2026-07-02 01:57:10 -06:00
parent 64525c3d82
commit 87bf67c368
2 changed files with 67 additions and 6 deletions

View File

@ -2,13 +2,26 @@ package yqlib
import (
"bufio"
"bytes"
"errors"
"io"
"os"
"github.com/dimchansky/utfbom"
)
var utf8BOM = []byte{0xEF, 0xBB, 0xBF}
// stripUTF8BOM returns a reader that skips a leading UTF-8 BOM, if present.
func stripUTF8BOM(r io.Reader) io.Reader {
br := bufio.NewReader(r)
peek, err := br.Peek(3)
if err == nil && bytes.Equal(peek, utf8BOM) {
_, _ = br.Discard(3)
}
return br
}
type frontMatterHandler interface {
Split() error
GetYamlFrontMatterFilename() string
@ -45,15 +58,13 @@ func (f *frontMatterHandlerImpl) Split() error {
var reader *bufio.Reader
var err error
if f.originalFilename == "-" {
cleanReader, _ := utfbom.Skip(os.Stdin)
reader = bufio.NewReader(cleanReader)
reader = bufio.NewReader(stripUTF8BOM(os.Stdin))
} else {
file, err := os.Open(f.originalFilename) // #nosec
if err != nil {
return err
}
cleanReader, _ := utfbom.Skip(file)
reader = bufio.NewReader(cleanReader)
reader = bufio.NewReader(stripUTF8BOM(file))
}
f.contentReader = reader

View File

@ -193,6 +193,56 @@ yaml: doc
fmHandler.CleanUp()
}
func TestFrontMatterSplitWithBOMFromStdin(t *testing.T) {
// Regression test for https://github.com/mikefarah/yq/issues/2496
// A UTF-8 BOM must also be skipped when reading front matter from stdin.
originalStdin := os.Stdin
defer func() { os.Stdin = originalStdin }()
r, w, err := os.Pipe()
if err != nil {
panic(err)
}
os.Stdin = r
defer safelyCloseFile(r)
go func() {
_, writeErr := w.WriteString("\ufeff---\na: apple\nb: banana\n---\nnot a\nyaml: doc\n")
if writeErr != nil {
t.Errorf("failed to write front matter to the stdin pipe: %v", writeErr)
}
safelyCloseFile(w)
}()
expectedYamlFm := `---
a: apple
b: banana
`
expectedContent := `---
not a
yaml: doc
`
fmHandler := NewFrontMatterHandler("-")
err = fmHandler.Split()
if err != nil {
panic(err)
}
yamlFm := readFile(fmHandler.GetYamlFrontMatterFilename())
test.AssertResult(t, expectedYamlFm, yamlFm)
contentBytes, err := io.ReadAll(fmHandler.GetContentReader())
if err != nil {
panic(err)
}
test.AssertResult(t, expectedContent, string(contentBytes))
fmHandler.CleanUp()
}
func TestFrontMatterSplitWithArray(t *testing.T) {
file := createTestFile(`[1,2,3]
---