all repos — emoji @ b2568c98122a7dca67fd44463b0fb4f06d25c3df

A minimalistic emoji package for Go (golang)

internal/generator/main.go (view raw)

  1package main
  2
  3import (
  4	"bufio"
  5	"bytes"
  6	"fmt"
  7	"go/format"
  8	"io"
  9	"io/ioutil"
 10	"net/http"
 11	"os"
 12	"sort"
 13	"text/template"
 14	"time"
 15)
 16
 17const (
 18	constantsFile = "constants.go"
 19	aliasesFile   = "map.go"
 20)
 21
 22// customEmojis is the list of emojis which unicode and gemoji databases don't have.
 23var customEmojis = map[string]string{
 24	":robot_face:": "\U0001f916", // slack
 25}
 26
 27func main() {
 28	emojis, err := fetchEmojis()
 29	if err != nil {
 30		panic(err)
 31	}
 32
 33	gemojis, err := fetchGemojis()
 34	if err != nil {
 35		panic(err)
 36	}
 37
 38	constants := generateConstants(emojis)
 39	aliases := generateAliases(emojis, gemojis)
 40
 41	if err = save(constantsFile, emojiListURL, constants); err != nil {
 42		panic(err)
 43	}
 44
 45	if err = save(aliasesFile, gemojiURL, aliases); err != nil {
 46		panic(err)
 47	}
 48}
 49
 50func generateConstants(emojis *groups) string {
 51	var res string
 52	for _, grp := range emojis.Groups {
 53		res += fmt.Sprintf("\n// GROUP: %v\n", grp.Name)
 54		for _, subgrp := range grp.Subgroups {
 55			res += fmt.Sprintf("// SUBGROUP: %v\n", subgrp.Name)
 56			for _, c := range subgrp.Constants {
 57				res += emojiConstant(subgrp.Emojis[c])
 58			}
 59		}
 60	}
 61
 62	return res
 63}
 64
 65func emojiConstant(emojis []emoji) string {
 66	basic := emojis[0]
 67	switch len(emojis) {
 68	case 1:
 69		return fmt.Sprintf("%s Emoji = %+q // %s\n", basic.Constant, basic.Code, basic.Name)
 70	case 6:
 71		oneTonedCode := replaceTones(emojis[1].Code)
 72		defaultTone := defaultTone(basic.Code, oneTonedCode)
 73
 74		if defaultTone != "" {
 75			return fmt.Sprintf("%s EmojiWithTone = newEmojiWithTone(%+q).withDefaultTone(%+q) // %s\n",
 76				basic.Constant, oneTonedCode, defaultTone, basic.Name)
 77		}
 78
 79		return fmt.Sprintf("%s EmojiWithTone = newEmojiWithTone(%+q) // %s\n",
 80			basic.Constant, oneTonedCode, basic.Name)
 81	case 26:
 82		oneTonedCode := replaceTones(emojis[1].Code)
 83		twoTonedCode := replaceTones(emojis[2].Code)
 84
 85		return fmt.Sprintf("%s EmojiWithTone = newEmojiWithTone(%+q, %+q) // %s\n",
 86			basic.Constant, oneTonedCode, twoTonedCode, basic.Name)
 87	default:
 88		panic(fmt.Errorf("not expected emoji count for a constant: %v", len(emojis)))
 89	}
 90}
 91
 92func generateAliases(emojis *groups, gemojis map[string]string) string {
 93	var aliases []string
 94	var emojiMap = make(map[string]string)
 95
 96	for _, grp := range emojis.Groups {
 97		for _, subgrp := range grp.Subgroups {
 98			for _, c := range subgrp.Constants {
 99				emoji := subgrp.Emojis[c][0]
100				alias := makeAlias(snakeCase(emoji.Constant))
101				aliases = append(aliases, alias)
102				emojiMap[alias] = emoji.Code
103			}
104		}
105	}
106
107	// add gemoji aliases
108	{
109		for alias, code := range gemojis {
110			_, ok := emojiMap[alias]
111			if !ok {
112				aliases = append(aliases, alias)
113			}
114			emojiMap[alias] = code
115		}
116	}
117
118	// add custom emoji aliases
119	{
120		for alias, code := range customEmojis {
121			_, ok := emojiMap[alias]
122			if !ok {
123				aliases = append(aliases, alias)
124			}
125			emojiMap[alias] = code
126		}
127	}
128
129	var r string
130	sort.Strings(aliases)
131	for _, alias := range aliases {
132		r += fmt.Sprintf("%q: %+q,\n", alias, emojiMap[alias])
133	}
134
135	return r
136}
137func save(filename, url, data string) error {
138	tmpl, err := template.ParseFiles(fmt.Sprintf("internal/generator/%v.tmpl", filename))
139	if err != nil {
140		return err
141	}
142
143	d := struct {
144		Link string
145		Date string
146		Data string
147	}{
148		Link: url,
149		Date: time.Now().Format(time.RFC3339),
150		Data: data,
151	}
152
153	var w bytes.Buffer
154	if err = tmpl.Execute(&w, d); err != nil {
155		return err
156	}
157
158	content, err := format.Source(w.Bytes())
159	if err != nil {
160		return fmt.Errorf("could not format file: %v", err)
161	}
162
163	file, err := os.Create(filename)
164	if err != nil {
165		return fmt.Errorf("could not create file: %v", err)
166	}
167	defer file.Close()
168
169	if _, err := file.Write(content); err != nil {
170		return fmt.Errorf("could not write to file: %v", err)
171	}
172	return nil
173}
174
175func fetchData(url string) ([]byte, error) {
176	resp, err := http.Get(url)
177	if err != nil {
178		return nil, err
179	}
180	defer resp.Body.Close()
181
182	// Check server response
183	if resp.StatusCode != http.StatusOK {
184		return nil, fmt.Errorf("bad status: %s", resp.Status)
185	}
186
187	b, err := ioutil.ReadAll(resp.Body)
188	if err != nil {
189		return nil, err
190	}
191
192	return b, nil
193}
194
195func readLines(b []byte, fn func(string)) error {
196	reader := bufio.NewReader(bytes.NewReader(b))
197
198	var line string
199	var err error
200	for {
201		line, err = reader.ReadString('\n')
202		if err != nil {
203			break
204		}
205
206		fn(line)
207	}
208
209	if err != io.EOF {
210		return err
211	}
212
213	return nil
214}