forked from tomnomnom/gron
-
Notifications
You must be signed in to change notification settings - Fork 0
/
identifier.go
88 lines (81 loc) · 1.85 KB
/
identifier.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
package main
import "unicode"
// The javascript reserved words cannot be used as unquoted keys
var reservedWords = map[string]bool{
"break": true,
"case": true,
"catch": true,
"class": true,
"const": true,
"continue": true,
"debugger": true,
"default": true,
"delete": true,
"do": true,
"else": true,
"export": true,
"extends": true,
"false": true,
"finally": true,
"for": true,
"function": true,
"if": true,
"import": true,
"in": true,
"instanceof": true,
"new": true,
"null": true,
"return": true,
"super": true,
"switch": true,
"this": true,
"throw": true,
"true": true,
"try": true,
"typeof": true,
"var": true,
"void": true,
"while": true,
"with": true,
"yield": true,
}
// validIdentifier checks to see if a string is a valid
// JavaScript identifier
// E.g:
// justLettersAndNumbers1 -> true
// a key with spaces -> false
// 1startsWithANumber -> false
func validIdentifier(s string) bool {
if reservedWords[s] || s == "" {
return false
}
for i, r := range s {
if i == 0 && !validFirstRune(r) {
return false
}
if i != 0 && !validSecondaryRune(r) {
return false
}
}
return true
}
// validFirstRune returns true for runes that are valid
// as the first rune in an identifier.
// E.g:
// 'r' -> true
// '7' -> false
func validFirstRune(r rune) bool {
return unicode.In(r,
unicode.Lu,
unicode.Ll,
unicode.Lm,
unicode.Lo,
unicode.Nl,
) || r == '$' || r == '_'
}
// validSecondaryRune returns true for runes that are valid
// as anything other than the first rune in an identifier.
func validSecondaryRune(r rune) bool {
return validFirstRune(r) ||
unicode.In(r, unicode.Mn, unicode.Mc, unicode.Nd, unicode.Pc)
}