-
-
Notifications
You must be signed in to change notification settings - Fork 338
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
syntax/typedjson: expose shfmt's "typed JSON" as Go APIs
Create a new package with docs, copy the code, and expose the API. The following changes were made to the API: * Name the main APIs Encode and Decode. * Added options structs, to give us flexibility in the future. * The "pretty" option is now an Indent string, like encoding/json. Note that we now require "Type" keys to come first in each object. This is not required right now, nor is it enforced by our decoder yet, but it will be necessary to implement a performant decoder. This is because we can only decode fields once we know the type; if the "Type" key comes later, we must decode twice or buffer tokens. The typed JSON encoding also changes slightly: since we want Encode and Decode to work on syntax.Node rather than syntax.File, the root node needs to include a "Type" JSON key as well. This also makes shfmt's --to-json behave nicer on empty files; rather than emitting `{}` lacking any information at all, it now emits an empty file node in tthe form of `{"Type":"File"}`. Finally, we apply some minor refactors to the code and tests. Fixes #885.
- Loading branch information
Showing
7 changed files
with
163 additions
and
94 deletions.
There are no files selected for viewing
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
// Copyright (c) 2017, Daniel Martí <mvdan@mvdan.cc> | ||
// See LICENSE for licensing information | ||
|
||
package typedjson_test | ||
|
||
import ( | ||
"bytes" | ||
"flag" | ||
"os" | ||
"path/filepath" | ||
"strings" | ||
"testing" | ||
|
||
qt "github.com/frankban/quicktest" | ||
|
||
"mvdan.cc/sh/v3/syntax" | ||
"mvdan.cc/sh/v3/syntax/typedjson" | ||
) | ||
|
||
var update = flag.Bool("u", false, "update output files") | ||
|
||
func TestRoundtrip(t *testing.T) { | ||
t.Parallel() | ||
|
||
dir := filepath.Join("testdata", "roundtrip") | ||
shellPaths, err := filepath.Glob(filepath.Join(dir, "*.sh")) | ||
qt.Assert(t, err, qt.IsNil) | ||
for _, shellPath := range shellPaths { | ||
shellPath := shellPath // do not reuse the range var | ||
name := strings.TrimSuffix(filepath.Base(shellPath), ".sh") | ||
jsonPath := filepath.Join(dir, name+".json") | ||
t.Run(name, func(t *testing.T) { | ||
shellInput, err := os.ReadFile(shellPath) | ||
qt.Assert(t, err, qt.IsNil) | ||
jsonInput, err := os.ReadFile(jsonPath) | ||
if !*update { // allow it to not exist | ||
qt.Assert(t, err, qt.IsNil) | ||
} | ||
sb := new(strings.Builder) | ||
|
||
// Parse the shell source and check that it is well formatted. | ||
parser := syntax.NewParser(syntax.KeepComments(true)) | ||
node, err := parser.Parse(bytes.NewReader(shellInput), "") | ||
qt.Assert(t, err, qt.IsNil) | ||
|
||
printer := syntax.NewPrinter() | ||
sb.Reset() | ||
err = printer.Print(sb, node) | ||
qt.Assert(t, err, qt.IsNil) | ||
qt.Assert(t, sb.String(), qt.Equals, string(shellInput)) | ||
|
||
// Validate writing the pretty JSON. | ||
sb.Reset() | ||
encOpts := typedjson.EncodeOptions{Indent: "\t"} | ||
err = encOpts.Encode(sb, node) | ||
qt.Assert(t, err, qt.IsNil) | ||
got := sb.String() | ||
if *update { | ||
err := os.WriteFile(jsonPath, []byte(got), 0o666) | ||
qt.Assert(t, err, qt.IsNil) | ||
} else { | ||
qt.Assert(t, got, qt.Equals, string(jsonInput)) | ||
} | ||
|
||
// Ensure we don't use the originally parsed node again. | ||
node = nil | ||
|
||
// Validate reading the pretty JSON and check that it formats the same. | ||
node2, err := typedjson.Decode(bytes.NewReader(jsonInput)) | ||
qt.Assert(t, err, qt.IsNil) | ||
|
||
sb.Reset() | ||
err = printer.Print(sb, node2) | ||
qt.Assert(t, err, qt.IsNil) | ||
qt.Assert(t, sb.String(), qt.Equals, string(shellInput)) | ||
|
||
// Validate that emitting the JSON again produces the same result. | ||
sb.Reset() | ||
err = encOpts.Encode(sb, node2) | ||
qt.Assert(t, err, qt.IsNil) | ||
got = sb.String() | ||
qt.Assert(t, got, qt.Equals, string(jsonInput)) | ||
t.Parallel() | ||
}) | ||
} | ||
} |
1 change: 1 addition & 0 deletions
1
cmd/shfmt/testdata/json.json → ...ax/typedjson/testdata/roundtrip/file.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,5 @@ | ||
{ | ||
"Type": "File", | ||
"Pos": { | ||
"Offset": 0, | ||
"Line": 1, | ||
|
File renamed without changes.