all repos — emoji @ 6ca9a8e9d7e7ee71fa9e8f61328dfae9deb85e1a

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