11package tfjson
22
3+ import (
4+ "encoding/json"
5+ "errors"
6+ "fmt"
7+ )
8+
39// Pos represents a position in a config file
410type Pos struct {
511 Line int `json:"line"`
@@ -14,20 +20,115 @@ type Range struct {
1420 End Pos `json:"end"`
1521}
1622
23+ type DiagnosticSeverity string
24+
25+ // These severities map to the tfdiags.Severity values, plus an explicit
26+ // unknown in case that enum grows without us noticing here.
27+ const (
28+ DiagnosticSeverityUnknown DiagnosticSeverity = "unknown"
29+ DiagnosticSeverityError DiagnosticSeverity = "error"
30+ DiagnosticSeverityWarning DiagnosticSeverity = "warning"
31+ )
32+
1733// Diagnostic represents information to be presented to a user about an
1834// error or anomaly in parsing or evaluating configuration
1935type Diagnostic struct {
20- Severity string `json:"severity,omitempty"`
21- Summary string `json:"summary,omitempty"`
22- Detail string `json:"detail,omitempty"`
23- Range * Range `json:"range,omitempty"`
36+ Severity DiagnosticSeverity `json:"severity,omitempty"`
37+
38+ Summary string `json:"summary,omitempty"`
39+ Detail string `json:"detail,omitempty"`
40+ Range * Range `json:"range,omitempty"`
41+
42+ Snippet * DiagnosticSnippet `json:"snippet,omitempty"`
43+ }
44+
45+ // DiagnosticSnippet represents source code information about the diagnostic.
46+ // It is possible for a diagnostic to have a source (and therefore a range) but
47+ // no source code can be found. In this case, the range field will be present and
48+ // the snippet field will not.
49+ type DiagnosticSnippet struct {
50+ // Context is derived from HCL's hcled.ContextString output. This gives a
51+ // high-level summary of the root context of the diagnostic: for example,
52+ // the resource block in which an expression causes an error.
53+ Context * string `json:"context"`
54+
55+ // Code is a possibly-multi-line string of Terraform configuration, which
56+ // includes both the diagnostic source and any relevant context as defined
57+ // by the diagnostic.
58+ Code string `json:"code"`
59+
60+ // StartLine is the line number in the source file for the first line of
61+ // the snippet code block. This is not necessarily the same as the value of
62+ // Range.Start.Line, as it is possible to have zero or more lines of
63+ // context source code before the diagnostic range starts.
64+ StartLine int `json:"start_line"`
65+
66+ // HighlightStartOffset is the character offset into Code at which the
67+ // diagnostic source range starts, which ought to be highlighted as such by
68+ // the consumer of this data.
69+ HighlightStartOffset int `json:"highlight_start_offset"`
70+
71+ // HighlightEndOffset is the character offset into Code at which the
72+ // diagnostic source range ends.
73+ HighlightEndOffset int `json:"highlight_end_offset"`
74+
75+ // Values is a sorted slice of expression values which may be useful in
76+ // understanding the source of an error in a complex expression.
77+ Values []DiagnosticExpressionValue `json:"values"`
78+ }
79+
80+ // DiagnosticExpressionValue represents an HCL traversal string (e.g.
81+ // "var.foo") and a statement about its value while the expression was
82+ // evaluated (e.g. "is a string", "will be known only after apply"). These are
83+ // intended to help the consumer diagnose why an expression caused a diagnostic
84+ // to be emitted.
85+ type DiagnosticExpressionValue struct {
86+ Traversal string `json:"traversal"`
87+ Statement string `json:"statement"`
2488}
2589
2690// ValidateOutput represents JSON output from terraform validate
2791// (available from 0.12 onwards)
2892type ValidateOutput struct {
93+ FormatVersion string `json:"format_version"`
94+
2995 Valid bool `json:"valid"`
3096 ErrorCount int `json:"error_count"`
3197 WarningCount int `json:"warning_count"`
3298 Diagnostics []Diagnostic `json:"diagnostics"`
3399}
100+
101+ // Validate checks to ensure that data is present, and the
102+ // version matches the version supported by this library.
103+ func (vo * ValidateOutput ) Validate () error {
104+ if vo == nil {
105+ return errors .New ("validation output is nil" )
106+ }
107+
108+ if vo .FormatVersion == "" {
109+ // The format was not versioned in the past
110+ return nil
111+ }
112+
113+ supportedVersion := "0.1"
114+ if vo .FormatVersion != supportedVersion {
115+ return fmt .Errorf ("unsupported validation output format version: expected %q, got %q" ,
116+ supportedVersion , vo .FormatVersion )
117+ }
118+
119+ return nil
120+ }
121+
122+ func (vo * ValidateOutput ) UnmarshalJSON (b []byte ) error {
123+ type rawOutput ValidateOutput
124+ var schemas rawOutput
125+
126+ err := json .Unmarshal (b , & schemas )
127+ if err != nil {
128+ return err
129+ }
130+
131+ * vo = * (* ValidateOutput )(& schemas )
132+
133+ return vo .Validate ()
134+ }
0 commit comments