-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathgojsonvalidator.go
143 lines (124 loc) · 3.2 KB
/
gojsonvalidator.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
package main
import (
"fmt"
"flag"
"os"
"github.com/xeipuuv/gojsonschema"
"sync"
"path/filepath"
"io/ioutil"
"io"
)
var interactive bool
var verbose bool
var schemaFile string
var testMode bool = false
var exitCode int
type Documents []gojsonschema.JSONLoader
type ResultTuple struct {
*gojsonschema.Result
err error
source string
}
func (d Documents) String() string {
return "";
}
func (d*Documents) Set(value string) error {
if _,err := os.Stat(value); err != nil {
return err
}
absolutePath,err := filepath.Abs(value)
if err != nil {
return err
}
*d = append(*d,gojsonschema.NewReferenceLoader("file://"+absolutePath))
return nil
}
var documents Documents
func main() {
parseArguments()
absSchemaFile,err := filepath.Abs(schemaFile)
if err != nil {
fmt.Fprintln(os.Stderr,"An error occurred while loading "+schemaFile +" from the file system.")
exit(1)
}
rawSchema := gojsonschema.NewReferenceLoader("file://"+absSchemaFile)
schema,err := gojsonschema.NewSchema(rawSchema)
if err != nil {
fmt.Fprintln(os.Stderr,"An error occured while passing the following schema file: "+schemaFile)
fmt.Fprintln(os.Stderr,err.Error())
exit(1)
}
if interactive {
getDocumentFromReader(os.Stdin)
}
results := validateDocuments(schema,documents)
exit(printResults(results))
}
func exit(code int) {
if !testMode {
os.Exit(code)
} else {
exitCode = code
}
}
func parseArguments() {
flag.BoolVar(&verbose, "v", false, "Print verbose output about all files.")
flag.BoolVar(&interactive,"i",false,"Parse a single JSON document from STDIN. (Works in conjunction with -f)")
flag.StringVar(&schemaFile, "s", "schema.json", "Schema file to validate documents with.")
flag.Var(&documents,"f","One or more document files to validate.")
flag.Parse()
}
func getDocumentFromReader(input io.Reader) {
if interactive {
if bytes,err := ioutil.ReadAll(input); err == nil {
documents = append(documents,gojsonschema.NewBytesLoader(bytes))
}
}
}
func printResults(results []ResultTuple) (exitCode int){
prependGuard := func(line string) string {
if line == "" {
return line
}
return "| " + line
}
for _, result := range results {
if result.err != nil {
fmt.Fprintf(os.Stderr,"An error occured %s %s\n", prependGuard(result.source),result.err.Error())
exitCode = 1
} else if result.Valid() {
if verbose {
fmt.Fprintf(os.Stdout,"JSON is valid %s\n", prependGuard(result.source))
}
} else {
fmt.Fprintf(os.Stderr,"JSON is invalid %s\n", prependGuard(result.source))
for _,err := range result.Errors() {
fmt.Fprintf(os.Stderr,"- %s\n",err)
}
exitCode = 1
}
}
return
}
func validateDocuments(schema *gojsonschema.Schema,documents []gojsonschema.JSONLoader) []ResultTuple {
results := make([]ResultTuple, len(documents))
var done sync.WaitGroup
done.Add(len(documents))
for index, document := range documents {
go func(i int,d gojsonschema.JSONLoader) {
validation, err := schema.Validate(d)
var result ResultTuple
result.Result = validation
result.err = err
jref,_ := d.JsonReference()
if jref.String() != "" {
result.source = jref.String()
}
results[i] = result
done.Done()
}(index,document)
}
done.Wait()
return results
}