Skip to content

Instantly share code, notes, and snippets.

@sp3c73r2038
Created May 25, 2020 07:25
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sp3c73r2038/7feb724c892cb30086c9d26b823646ba to your computer and use it in GitHub Desktop.
Save sp3c73r2038/7feb724c892cb30086c9d26b823646ba to your computer and use it in GitHub Desktop.
Quickly check JSON file syntax. Faster than `jq`. Good to use in git pre-commit hook.
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"log"
"os"
)
func must(err error) {
if err != nil {
log.Fatal(err)
}
}
func main() {
args := os.Args[1:]
if len(args) <= 0 {
fmt.Printf("usage: %s <file> \n", os.Args[0])
os.Exit(1)
}
b, err := ioutil.ReadFile(args[0])
must(err)
var v interface{}
err = json.Unmarshal(b, &v)
// https: //adrianhesketh.com/2017/03/18/getting-line-and-character-positions-from-gos-json-unmarshal-errors/
if jsonError, ok := err.(*json.SyntaxError); ok {
line, character, lcErr := lineAndCharacter(string(b), int(jsonError.Offset))
fmt.Fprintf(
os.Stderr,
"Cannot parse JSON schema due to a syntax error at line %d, character %d: %v\n",
line, character, jsonError.Error())
if lcErr != nil {
fmt.Fprintf(
os.Stderr,
"Couldn't find the line and character position of the error due to error %v\n",
lcErr)
}
os.Exit(1)
}
if jsonError, ok := err.(*json.UnmarshalTypeError); ok {
line, character, lcErr := lineAndCharacter(string(b), int(jsonError.Offset))
fmt.Fprintf(
os.Stderr,
"The JSON type '%v' cannot be converted into the Go '%v' type on struct "+
"'%s', field '%v'. See input file line %d, character %d\n",
jsonError.Value, jsonError.Type.Name(), jsonError.Struct,
jsonError.Field, line, character)
if lcErr != nil {
fmt.Fprintf(
os.Stderr,
"Couldn't find the line and character position of the error due to error %v\n",
lcErr)
}
os.Exit(1)
}
os.Exit(0)
}
func lineAndCharacter(input string, offset int) (line int, character int, err error) {
lf := rune(0x0A)
if offset > len(input) || offset < 0 {
return 0, 0, fmt.Errorf("Couldn't find offset %d within the input.", offset)
}
// Humans tend to count from 1.
line = 1
for i, b := range input {
if b == lf {
line++
character = 0
}
character++
if i == offset {
break
}
}
return line, character, nil
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment