Skip to content

Commit

Permalink
encoding/json: fix positions when Decoder.Extract finds bad syntax
Browse files Browse the repository at this point in the history
In such a scenario, such as when decoding JSONL files as a stream
of newline-delimited JSON values, we would simply use encoding/json's
Decoder.InputOffset, which is the end of the last returned token.
Or in our case, the end of the last fully decoded RawMessage,
which is the previous value in the JSONL rather than the current one.

Copy the new mechanism that Extract gained to deal with json.SyntaxError
into Decoder.Extract, with some tweaks as we can reuse our token.File.
While here, simplify the code a bit; there is no need to use errors.As,
as the encoding/json docs guarantee that SyntaxError is not wrapped.

Fixes #2776.

Signed-off-by: Daniel Martí <[email protected]>
Change-Id: I41d6661d3a4ba59d72ab061f261356700f45aeda
Reviewed-on: https://review.gerrithub.io/c/cue-lang/cue/+/1199103
Unity-Result: CUE porcuepine <[email protected]>
Reviewed-by: Roger Peppe <[email protected]>
TryBot-Result: CUEcueckoo <[email protected]>
  • Loading branch information
mvdan committed Aug 12, 2024
1 parent 5e19deb commit a093c9b
Show file tree
Hide file tree
Showing 2 changed files with 11 additions and 13 deletions.
5 changes: 1 addition & 4 deletions cmd/cue/cmd/testdata/script/json_syntax_error.txtar
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,7 @@ stderr 'x3.json:1:1'
stderr 'x4.json:1:1'

! exec cue export x5.jsonl
# TODO(mvdan): the position below seems to be incorrect,
# as it points to the end of the previous value instead.
stderr 'x5.jsonl:6:2'
# stderr 'x5.jsonl:8:12'
stderr 'x5.jsonl:8:12'

-- x1.json --
{
Expand Down
19 changes: 10 additions & 9 deletions encoding/json/json.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,13 +88,11 @@ func extract(path string, b []byte) (ast.Expr, error) {
var x interface{}
err := json.Unmarshal(b, &x)

if len(b) > 0 {
var synErr *json.SyntaxError
if errors.As(err, &synErr) {
tokFile := token.NewFile(path, 0, len(b))
tokFile.SetLinesForContent(b)
p = tokFile.Pos(int(synErr.Offset-1), token.NoRelPos)
}
// If encoding/json has a position, prefer that, as it relates to json.Unmarshal's error message.
if synErr, ok := err.(*json.SyntaxError); ok && len(b) > 0 {
tokFile := token.NewFile(path, 0, len(b))
tokFile.SetLinesForContent(b)
p = tokFile.Pos(int(synErr.Offset-1), token.NoRelPos)
}

return nil, errors.Wrapf(err, p, "invalid JSON for file %q", path)
Expand Down Expand Up @@ -153,11 +151,14 @@ func (d *Decoder) extract() (ast.Expr, error) {
return nil, err
}
if err != nil {
pos := d.tokFile.Pos(int(d.dec.InputOffset()), 0)
pos := token.NoPos
// When decoding into a RawMessage, encoding/json should only error due to syntax errors.
if synErr, ok := err.(*json.SyntaxError); ok {
pos = d.tokFile.Pos(int(synErr.Offset-1), token.NoRelPos)
}
return nil, errors.Wrapf(err, pos, "invalid JSON for file %q", d.path)
}
expr, err := parser.ParseExpr(d.path, []byte(raw))

if err != nil {
return nil, err
}
Expand Down

0 comments on commit a093c9b

Please sign in to comment.