This now gives an error instead of a panic when encountering
configuration such as described in hashicorp/terraform#5740:
```
resource "aws" "web" {
provider = "aws" {
region = "us-west-2"
}
}
```
We now return an error message - "hcl object keys must be a string"
instead of crashing.
Fixeshashicorp/terraform#5740.
This uses the `printer` package to normalise HCL files. It's inspired by
github.com/fatih/hclfmt - but it differs in that it's intended to be more
generic, re-usable, and follow the semantics of `gofmt` or `go fmt`.
I intend to utilise this in Terraform by implementing `terraform fmt`
sub-command which will normalise all files in the current working directory
(like `go fmt ./..`) or contents over STDIN (with `terraform fmt -` that
could be used by editor plugins). So that Terraform users can benefit from
linting without installing another package/binary.
I hope that by placing most of the logic in the HCL package it should be
easy to implement sub-commands in other projects that also use HCL.
Some notes about the implementation:
- the significant difference from `gofmt` is that STDIN/STDOUT are passed in
and errors aren't logged/written directly to STDERR, which gives consumers
(e.g. Terraform) the ability to set appropriate exit codes
- I chose to use inline fixtures instead of files because there were a
number of times where I needed to reference the contents and group them
together with diff output
- it seemed simplest to construct the expected outputs by looping over the
relevant fixtures and building up a string/byte slice, hope it isn't too
confusing to read
- the test failure reporting is kind of rough because the outputs are so
large, but I didn't want to add another diff function
- I chose to have a separate test for sub-directories rather than making it
the default in the fixtures so that I didn't need to add additional logic
to the fixture rendering
- the fixtures are sorted by filename before any of the tests runs so that
they match the order that they are read from disk by `filepath.Walk()`
Several of the esoteric syntax errors we encounter in Terraform have
bubbled up errors from the decoder. Since all these errors have a Node
in context, they can report their position which makes them _much_ more
helpful to the user, even if the error message itself is confusing.
I tried to move around PosError somewhere but got stuck finding a good
spot for it that doesn't have either a silly name or an import cycle, so
for now I'm just cross referencing into the parser package to reference
the error type.