1package main
2
3import "unicode"
4
5// The javascript reserved words cannot be used as unquoted keys
6var reservedWords = map[string]bool{
7	"break":      true,
8	"case":       true,
9	"catch":      true,
10	"class":      true,
11	"const":      true,
12	"continue":   true,
13	"debugger":   true,
14	"default":    true,
15	"delete":     true,
16	"do":         true,
17	"else":       true,
18	"export":     true,
19	"extends":    true,
20	"false":      true,
21	"finally":    true,
22	"for":        true,
23	"function":   true,
24	"if":         true,
25	"import":     true,
26	"in":         true,
27	"instanceof": true,
28	"new":        true,
29	"null":       true,
30	"return":     true,
31	"super":      true,
32	"switch":     true,
33	"this":       true,
34	"throw":      true,
35	"true":       true,
36	"try":        true,
37	"typeof":     true,
38	"var":        true,
39	"void":       true,
40	"while":      true,
41	"with":       true,
42	"yield":      true,
43}
44
45// validIdentifier checks to see if a string is a valid
46// JavaScript identifier
47// E.g:
48//     justLettersAndNumbers1 -> true
49//     a key with spaces      -> false
50//     1startsWithANumber	  -> false
51func validIdentifier(s string) bool {
52	if reservedWords[s] || s == "" {
53		return false
54	}
55
56	for i, r := range s {
57		if i == 0 && !validFirstRune(r) {
58			return false
59		}
60		if i != 0 && !validSecondaryRune(r) {
61			return false
62		}
63	}
64
65	return true
66}
67
68// validFirstRune returns true for runes that are valid
69// as the first rune in an identifier.
70// E.g:
71//     'r' -> true
72//     '7' -> false
73func validFirstRune(r rune) bool {
74	return unicode.In(r,
75		unicode.Lu,
76		unicode.Ll,
77		unicode.Lm,
78		unicode.Lo,
79		unicode.Nl,
80	) || r == '$' || r == '_'
81}
82
83// validSecondaryRune returns true for runes that are valid
84// as anything other than the first rune in an identifier.
85func validSecondaryRune(r rune) bool {
86	return validFirstRune(r) ||
87		unicode.In(r, unicode.Mn, unicode.Mc, unicode.Nd, unicode.Pc)
88}
89