all repos — emoji @ a87a93aec4b8d9b19ca954cf8507563f91df277c

A minimalistic emoji package for Go (golang)

generator: clean generator code
Enes Çakır enes@cakir.web.tr
Sun, 08 Mar 2020 15:56:13 +0300
commit

a87a93aec4b8d9b19ca954cf8507563f91df277c

parent

84a0a67371e0847129343a1165bdd41e95f5b49d

M internal/generator/emoji.gointernal/generator/unicode.go

@@ -9,11 +9,45 @@

emojipkg "github.com/enescakir/emoji" ) +const emojiListURL = "https://unicode.org/Public/emoji/13.0/emoji-test.txt" + var ( emojiRegex = regexp.MustCompile(`^(?m)(?P<code>[A-Z\d ]+[A-Z\d])\s+;\s+(fully-qualified|component)\s+#\s+.+\s+E\d+\.\d+ (?P<name>.+)$`) toneRegex = regexp.MustCompile(`:\s.*tone,?`) ) +func fetchEmojis() (*groups, error) { + var emojis groups + b, err := fetchData(emojiListURL) + if err != nil { + return nil, err + } + + var grp *group + var subgrp *subgroup + + parseLine := func(line string) { + switch { + case strings.HasPrefix(line, "# group:"): + name := strings.TrimSpace(strings.ReplaceAll(line, "# group:", "")) + grp = emojis.Append(name) + case strings.HasPrefix(line, "# subgroup:"): + name := strings.TrimSpace(strings.ReplaceAll(line, "# subgroup:", "")) + subgrp = grp.Append(name) + case !strings.HasPrefix(line, "#"): + if e := newEmoji(line); e != nil { + subgrp.Append(*e) + } + } + } + + if err = readLines(b, parseLine); err != nil { + return nil, err + } + + return &emojis, nil +} + type groups struct { Groups []*group }

@@ -81,8 +115,8 @@ Code: code,

Tones: []string{}, } e.extractAttr() - e.Constant = generateConstant(e.Constant) - e.Code = generateUnicode(e.Code) + e.generateConstant() + e.generateUnicode() return &e }

@@ -112,17 +146,17 @@ }

e.Constant = c } -func generateConstant(c string) string { - c = clean(c) +func (e *emoji) generateConstant() { + c := clean(e.Constant) c = strings.Title(strings.ToLower(c)) c = removeSpaces(c) - return c + e.Constant = c } -func generateUnicode(code string) string { +func (e *emoji) generateUnicode() { unicodes := []string{} - for _, v := range strings.Split(code, " ") { + for _, v := range strings.Split(e.Code, " ") { u, err := strconv.ParseInt(v, 16, 32) if err != nil { panic(fmt.Errorf("unknown unicode: %v", v))

@@ -130,7 +164,7 @@ }

unicodes = append(unicodes, string(u)) } - return strings.Join(unicodes, "") + e.Code = strings.Join(unicodes, "") } func defaultTone(basic, toned string) string {
A internal/generator/gemoji.go

@@ -0,0 +1,36 @@

+package main + +import "encoding/json" + +const gemojiURL = "https://raw.githubusercontent.com/github/gemoji/master/db/emoji.json" + +type gemoji struct { + Emoji string `json:"emoji"` + Aliases []string `json:"aliases"` +} + +func fetchGemojis() (map[string]string, error) { + b, err := fetchData(gemojiURL) + if err != nil { + return nil, err + } + + var gemojis []gemoji + r := make(map[string]string) + + if err = json.Unmarshal(b, &gemojis); err != nil { + return nil, err + } + + for _, gemoji := range gemojis { + for _, alias := range gemoji.Aliases { + if len(alias) == 0 || len(gemoji.Emoji) == 0 { + continue + } + + r[makeAlias(alias)] = gemoji.Emoji + } + } + + return r, nil +}
M internal/generator/main.gointernal/generator/main.go

@@ -3,7 +3,6 @@

import ( "bufio" "bytes" - "encoding/json" "fmt" "go/format" "io"

@@ -11,32 +10,33 @@ "io/ioutil"

"net/http" "os" "sort" - "strings" "text/template" "time" - "unicode" ) const ( - emojiListUrl = "https://unicode.org/Public/emoji/13.0/emoji-test.txt" - gemojiURL = "https://raw.githubusercontent.com/github/gemoji/master/db/emoji.json" constantsFile = "constants.go" aliasesFile = "map.go" ) -// unicode and gemoji databases don't have alias like that +// customEmojis is the list of emojis which unicode and gemoji databases don't have. var customEmojis = map[string]string{ ":robot_face:": "\U0001f916", // slack } func main() { - emojis, err := fetch() + emojis, err := fetchEmojis() + if err != nil { + panic(err) + } + + gemojis, err := fetchGemojis() if err != nil { panic(err) } constants := generateConstants(emojis) - aliases := generateAliases(emojis) + aliases := generateAliases(emojis, gemojis) if err = save(constantsFile, constants); err != nil { panic(err)

@@ -47,39 +47,49 @@ panic(err)

} } -func fetch() (*groups, error) { - var emojis groups - b, err := fetchData(emojiListUrl) - if err != nil { - return nil, err +func generateConstants(emojis *groups) string { + var res string + for _, grp := range emojis.Groups { + res += fmt.Sprintf("\n// GROUP: %v\n", grp.Name) + for _, subgrp := range grp.Subgroups { + res += fmt.Sprintf("// SUBGROUP: %v\n", subgrp.Name) + for _, c := range subgrp.Constants { + res += emojiConstant(subgrp.Emojis[c]) + } + } } - var grp *group - var subgrp *subgroup + return res +} - parseLine := func(line string) { - switch { - case strings.HasPrefix(line, "# group:"): - name := strings.TrimSpace(strings.ReplaceAll(line, "# group:", "")) - grp = emojis.Append(name) - case strings.HasPrefix(line, "# subgroup:"): - name := strings.TrimSpace(strings.ReplaceAll(line, "# subgroup:", "")) - subgrp = grp.Append(name) - case !strings.HasPrefix(line, "#"): - if e := newEmoji(line); e != nil { - subgrp.Append(*e) - } +func emojiConstant(emojis []emoji) string { + basic := emojis[0] + switch len(emojis) { + case 1: + return fmt.Sprintf("%s Emoji = %+q // %s\n", basic.Constant, basic.Code, basic.Name) + case 6: + oneTonedCode := replaceTones(emojis[1].Code) + defaultTone := defaultTone(basic.Code, oneTonedCode) + + if defaultTone != "" { + return fmt.Sprintf("%s EmojiWithTone = newEmojiWithTone(%+q).withDefaultTone(%+q) // %s\n", + basic.Constant, oneTonedCode, defaultTone, basic.Name) } - } - if err = readLines(b, parseLine); err != nil { - return nil, err + return fmt.Sprintf("%s EmojiWithTone = newEmojiWithTone(%+q) // %s\n", + basic.Constant, oneTonedCode, basic.Name) + case 26: + oneTonedCode := replaceTones(emojis[1].Code) + twoTonedCode := replaceTones(emojis[2].Code) + + return fmt.Sprintf("%s EmojiWithTone = newEmojiWithTone(%+q, %+q) // %s\n", + basic.Constant, oneTonedCode, twoTonedCode, basic.Name) + default: + panic(fmt.Errorf("not expected emoji count for a constant: %v", len(emojis))) } - - return &emojis, nil } -func generateAliases(emojis *groups) string { +func generateAliases(emojis *groups, gemojis map[string]string) string { var aliases []string var emojiMap = make(map[string]string)

@@ -87,7 +97,7 @@ for _, grp := range emojis.Groups {

for _, subgrp := range grp.Subgroups { for _, c := range subgrp.Constants { emoji := subgrp.Emojis[c][0] - alias := ":" + snakeCase(emoji.Constant) + ":" + alias := makeAlias(snakeCase(emoji.Constant)) aliases = append(aliases, alias) emojiMap[alias] = emoji.Code }

@@ -96,11 +106,6 @@ }

// add gemoji aliases { - gemojis, err := fetchGemoji() - if err != nil { - panic(err) - } - for alias, code := range gemojis { _, ok := emojiMap[alias] if !ok {

@@ -121,110 +126,14 @@ emojiMap[alias] = code

} } - var res string + var r string sort.Strings(aliases) for _, alias := range aliases { - res += fmt.Sprintf("%q: %+q,\n", alias, emojiMap[alias]) - } - - return res -} - -func snakeCase(str string) string { - var output strings.Builder - for i, r := range str { - switch { - case unicode.IsUpper(r): - if i != 0 { - output.WriteRune('_') - } - output.WriteRune(unicode.ToLower(r)) - case unicode.IsDigit(r): - if i != 0 && !unicode.IsDigit(rune(str[i-1])) { - output.WriteRune('_') - } - output.WriteRune(r) - default: - output.WriteRune(r) - } - } - - return output.String() -} - -type gemoji struct { - Emoji string `json:"emoji"` - Aliases []string `json:"aliases"` -} - -func fetchGemoji() (map[string]string, error) { - b, err := fetchData(gemojiURL) - if err != nil { - return nil, err - } - - var gemojis []gemoji - r := make(map[string]string) - - if err = json.Unmarshal(b, &gemojis); err != nil { - return nil, err - } - - for _, gemoji := range gemojis { - for _, alias := range gemoji.Aliases { - if len(alias) == 0 || len(gemoji.Emoji) == 0 { - continue - } - - r[":"+alias+":"] = gemoji.Emoji - } - } - - return r, nil -} - -func generateConstants(emojis *groups) string { - var res string - for _, grp := range emojis.Groups { - res += fmt.Sprintf("\n// GROUP: %v\n", grp.Name) - for _, subgrp := range grp.Subgroups { - res += fmt.Sprintf("// SUBGROUP: %v\n", subgrp.Name) - for _, c := range subgrp.Constants { - res += emojiConstant(subgrp.Emojis[c]) - } - } + r += fmt.Sprintf("%q: %+q,\n", alias, emojiMap[alias]) } - return res + return r } - -func emojiConstant(emojis []emoji) string { - basic := emojis[0] - switch len(emojis) { - case 1: - return fmt.Sprintf("%s Emoji = %+q // %s\n", basic.Constant, basic.Code, basic.Name) - case 6: - oneTonedCode := replaceTones(emojis[1].Code) - defaultTone := defaultTone(basic.Code, oneTonedCode) - - if defaultTone != "" { - return fmt.Sprintf("%s EmojiWithTone = newEmojiWithTone(%+q).withDefaultTone(%+q) // %s\n", - basic.Constant, oneTonedCode, defaultTone, basic.Name) - } - - return fmt.Sprintf("%s EmojiWithTone = newEmojiWithTone(%+q) // %s\n", - basic.Constant, oneTonedCode, basic.Name) - case 26: - oneTonedCode := replaceTones(emojis[1].Code) - twoTonedCode := replaceTones(emojis[2].Code) - - return fmt.Sprintf("%s EmojiWithTone = newEmojiWithTone(%+q, %+q) // %s\n", - basic.Constant, oneTonedCode, twoTonedCode, basic.Name) - default: - panic(fmt.Errorf("not expected emoji count for a constant: %v", len(emojis))) - } -} - func save(filename, data string) error { tmpl, err := template.ParseFiles(fmt.Sprintf("internal/generator/%v.tmpl", filename)) if err != nil {

@@ -247,6 +156,9 @@ return err

} content, err := format.Source(w.Bytes()) + if err != nil { + return fmt.Errorf("could not format file: %v", err) + } file, err := os.Create(filename) if err != nil {
M internal/generator/strutil.gointernal/generator/strutil.go

@@ -3,6 +3,7 @@

import ( "regexp" "strings" + "unicode" ) var (

@@ -109,3 +110,30 @@ // removeSpaces removes consecutive whitespaces.

func removeSpaces(str string) string { return whitespaceRegex.ReplaceAllString(str, "") } + +// snakeCase converts string to snake_case from PascalCase +func snakeCase(str string) string { + var output strings.Builder + for i, r := range str { + switch { + case unicode.IsUpper(r): + if i != 0 { + output.WriteRune('_') + } + output.WriteRune(unicode.ToLower(r)) + case unicode.IsDigit(r): + if i != 0 && !unicode.IsDigit(rune(str[i-1])) { + output.WriteRune('_') + } + output.WriteRune(r) + default: + output.WriteRune(r) + } + } + + return output.String() +} + +func makeAlias(str string) string { + return ":" + str + ":" +}