all repos — emoji @ cf2567abaf2c0088ccf0492340530c25b6bcef19

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	"strings"
 13	"text/template"
 14	"time"
 15)
 16
 17const (
 18	emojiListUrl = "https://unicode.org/Public/emoji/13.0/emoji-test.txt"
 19)
 20
 21func main() {
 22	emojis, err := fetch()
 23	if err != nil {
 24		panic(err)
 25	}
 26
 27	constants := generate(emojis)
 28
 29	if err = save(constants); err != nil {
 30		panic(err)
 31	}
 32}
 33
 34func fetch() (*groups, error) {
 35	var emojis groups
 36	b, err := fetchData(emojiListUrl)
 37	if err != nil {
 38		return nil, err
 39	}
 40
 41	var grp *group
 42	var subgrp *subgroup
 43
 44	parseLine := func(line string) {
 45		switch {
 46		case strings.HasPrefix(line, "# group:"):
 47			name := strings.TrimSpace(strings.ReplaceAll(line, "# group:", ""))
 48			grp = emojis.Append(name)
 49		case strings.HasPrefix(line, "# subgroup:"):
 50			name := strings.TrimSpace(strings.ReplaceAll(line, "# subgroup:", ""))
 51			subgrp = grp.Append(name)
 52		case !strings.HasPrefix(line, "#"):
 53			if e := newEmoji(line); e != nil {
 54				subgrp.Append(*e)
 55			}
 56		}
 57	}
 58
 59	if err = readLines(b, parseLine); err != nil {
 60		return nil, err
 61	}
 62
 63	return &emojis, nil
 64}
 65
 66func generate(emojis *groups) string {
 67	var res string
 68	for _, grp := range emojis.Groups {
 69		res += fmt.Sprintf("\n// GROUP: %v\n", grp.Name)
 70		for _, subgrp := range grp.Subgroups {
 71			res += fmt.Sprintf("// SUBGROUP: %v\n", subgrp.Name)
 72			for _, c := range subgrp.Constants {
 73				res += emojiConstant(subgrp.Emojis[c])
 74			}
 75		}
 76	}
 77
 78	return res
 79}
 80
 81func emojiConstant(emojis []emoji) string {
 82	basic := emojis[0]
 83	switch len(emojis) {
 84	case 1:
 85		return fmt.Sprintf("%s Emoji = %+q // %s\n", basic.Constant, basic.Code, basic.Name)
 86	case 6:
 87		oneTonedCode := replaceTones(emojis[1].Code)
 88		defaultTone := defaultTone(basic.Code, oneTonedCode)
 89
 90		if defaultTone != "" {
 91			return fmt.Sprintf("%s EmojiWithTone = newEmojiWithTone(%+q).withDefaultTone(%+q) // %s\n", basic.Constant, oneTonedCode, defaultTone, basic.Name)
 92		}
 93
 94		return fmt.Sprintf("%s EmojiWithTone = newEmojiWithTone(%+q) // %s\n", basic.Constant, oneTonedCode, basic.Name)
 95	case 26:
 96		oneTonedCode := replaceTones(emojis[1].Code)
 97		twoTonedCode := replaceTones(emojis[2].Code)
 98
 99		return fmt.Sprintf("%s EmojiWithTone = newEmojiWithTone(%+q, %+q) // %s\n", basic.Constant, oneTonedCode, twoTonedCode, basic.Name)
100	default:
101		panic(fmt.Errorf("not expected emoji count for a constant: %v", len(emojis)))
102	}
103}
104
105func save(constants string) error {
106	tmpl, err := template.ParseFiles("internal/generator/constants.go.tmpl")
107	if err != nil {
108		return err
109	}
110
111	data := struct {
112		Link      string
113		Date      string
114		Constants string
115	}{
116		Link:      emojiListUrl,
117		Date:      time.Now().Format(time.RFC3339),
118		Constants: constants,
119	}
120	var w bytes.Buffer
121	if err = tmpl.Execute(&w, data); err != nil {
122		return err
123	}
124
125	content, err := format.Source(w.Bytes())
126
127	file, err := os.Create("constants.go")
128	if err != nil {
129		return fmt.Errorf("could not create file: %v", err)
130	}
131	defer file.Close()
132
133	if _, err := file.Write(content); err != nil {
134		return fmt.Errorf("could not write to file: %v", err)
135	}
136	return nil
137}
138
139func fetchData(url string) ([]byte, error) {
140	resp, err := http.Get(url)
141	if err != nil {
142		return nil, err
143	}
144	defer resp.Body.Close()
145
146	// Check server response
147	if resp.StatusCode != http.StatusOK {
148		return nil, fmt.Errorf("bad status: %s", resp.Status)
149	}
150
151	b, err := ioutil.ReadAll(resp.Body)
152	if err != nil {
153		return nil, err
154	}
155
156	return b, nil
157}
158
159func readLines(b []byte, fn func(string)) error {
160	reader := bufio.NewReader(bytes.NewReader(b))
161
162	var line string
163	var err error
164	for {
165		line, err = reader.ReadString('\n')
166		if err != nil {
167			break
168		}
169
170		fn(line)
171	}
172
173	if err != io.EOF {
174		return err
175	}
176
177	return nil
178}