all repos

json2go @ c2472d6f39fc78b9f1054066eab3331441856d1b

convert json to go type annotations

json2go/json2go.go (view raw)

Oleksandr Smirnov Oleksandr Smirnov
olexsmir@gmail.com
refactor: use an actual parser instead of reflection..., 11 days ago
1
package json2go
2
3
import (
4
	"errors"
5
	"unicode"
6
	"unicode/utf8"
7
	"unsafe"
8
)
9
10
var (
11
	// ErrInvalidJSON json input could not be parsed.
12
	ErrInvalidJSON = errors.New("invalid json")
13
14
	// ErrInvalidStructName struct name provided is not a valid Go identifier.
15
	ErrInvalidStructName = errors.New("invalid struct name")
16
)
17
18
// Transform converts a JSON string to Go struct type definitions.
19
//
20
// The structName must be a valid Go identifier.
21
// Set includeTags to true to generate `json:"field_name"` tags on struct fields.
22
// Returns the Go code as a string, or an error if JSON parsing fails.
23
func Transform(structName, jsonStr string, includeTags bool) (string, error) {
24
	if !isValidIdentifier(structName) {
25
		return "", ErrInvalidStructName
26
	}
27
28
	input := unsafe.Slice(unsafe.StringData(jsonStr), len(jsonStr))
29
	lexer := NewLexer(input)
30
	parser := NewParser(lexer)
31
	v, err := parser.Parse()
32
	if err != nil {
33
		return "", errors.Join(ErrInvalidJSON, err)
34
	}
35
36
	return NewTranspiler().Transpile(structName, v, includeTags)
37
}
38
39
func isValidIdentifier(s string) bool {
40
	if len(s) == 0 {
41
		return false
42
	}
43
44
	r, size := utf8.DecodeRuneInString(s)
45
	if !unicode.IsLetter(r) && r != '_' {
46
		return false
47
	}
48
49
	for _, r := range s[size:] {
50
		if !unicode.IsLetter(r) && !unicode.IsDigit(r) && r != '_' {
51
			return false
52
		}
53
	}
54
55
	return true
56
}