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