// Copyright 2020 The Gitea Authors. All rights reserved. // Copyright 2015 Kenneth Shaw // SPDX-License-Identifier: MIT //go:build ignore package main import ( "flag" "fmt" "go/format" "io" "log" "net/http" "os" "regexp" "sort" "strconv" "strings" "unicode/utf8" "code.gitea.io/gitea/modules/json" ) const ( gemojiURL = "https://raw.githubusercontent.com/github/gemoji/master/db/emoji.json" maxUnicodeVersion = 15 ) var flagOut = flag.String("o", "modules/emoji/emoji_data.go", "out") // Gemoji is a set of emoji data. type Gemoji []Emoji // Emoji represents a single emoji and associated data. type Emoji struct { Emoji string `json:"emoji"` Description string `json:"description,omitempty"` Aliases []string `json:"aliases"` UnicodeVersion string `json:"unicode_version,omitempty"` SkinTones bool `json:"skin_tones,omitempty"` } // Don't include some fields in JSON func (e Emoji) MarshalJSON() ([]byte, error) { type emoji Emoji x := emoji(e) x.UnicodeVersion = "" x.Description = "" x.SkinTones = false return json.Marshal(x) } func main() { flag.Parse() // generate data buf, err := generate() if err != nil { log.Fatalf("generate err: %v", err) } // write err = os.WriteFile(*flagOut, buf, 0o644) if err != nil { log.Fatalf("WriteFile err: %v", err) } } var replacer = strings.NewReplacer( "main.Gemoji", "Gemoji", "main.Emoji", "\n", "}}", "},\n}", ", Description:", ", ", ", Aliases:", ", ", ", UnicodeVersion:", ", ", ", SkinTones:", ", ", ) var emojiRE = regexp.MustCompile(`\{Emoji:"([^"]*)"`) func generate() ([]byte, error) { // load gemoji data res, err := http.Get(gemojiURL) if err != nil { return nil, err } defer res.Body.Close() // read all body, err := io.ReadAll(res.Body) if err != nil { return nil, err } // unmarshal var data Gemoji err = json.Unmarshal(body, &data) if err != nil { return nil, err } skinTones := make(map[string]string) skinTones["\U0001f3fb"] = "Light Skin Tone" skinTones["\U0001f3fc"] = "Medium-Light Skin Tone" skinTones["\U0001f3fd"] = "Medium Skin Tone" skinTones["\U0001f3fe"] = "Medium-Dark Skin Tone" skinTones["\U0001f3ff"] = "Dark Skin Tone" var tmp Gemoji // filter out emoji that require greater than max unicode version for i := range data { val, _ := strconv.ParseFloat(data[i].UnicodeVersion, 64) if int(val) <= maxUnicodeVersion { tmp = append(tmp, data[i]) } } data = tmp sort.Slice(data, func(i, j int) bool { return data[i].Aliases[0] < data[j].Aliases[0] }) aliasMap := make(map[string]int, len(data)) for i, e := range data { if e.Emoji == "" || len(e.Aliases) == 0 { continue } for _, a := range e.Aliases { if a == "" { continue } aliasMap[a] = i } } // gitea customizations i, ok := aliasMap["tada"] if ok { data[i].Aliases = append(data[i].Aliases, "hooray") } i, ok = aliasMap["laughing"] if ok { data[i].Aliases = append(data[i].Aliases, "laugh") } // write a JSON file to use with tribute (write before adding skin tones since we can't support them there yet) file, _ := json.Marshal(data) _ = os.WriteFile("assets/emoji.json", file, 0o644) // Add skin tones to emoji that support it var ( s []string newEmoji string newDescription string newData Emoji ) for i := range data { if data[i].SkinTones { for k, v := range skinTones { s = strings.Split(data[i].Emoji, "") if utf8.RuneCountInString(data[i].Emoji) == 1 { s = append(s, k) } else { // insert into slice after first element because all emoji that support skin tones // have that modifier placed at this spot s = append(s, "") copy(s[2:], s[1:]) s[1] = k } newEmoji = strings.Join(s, "") newDescription = data[i].Description + ": " + v newAlias := data[i].Aliases[0] + "_" + strings.ReplaceAll(v, " ", "_") newData = Emoji{newEmoji, newDescription, []string{newAlias}, "12.0", false} data = append(data, newData) } } } sort.Slice(data, func(i, j int) bool { return data[i].Aliases[0] < data[j].Aliases[0] }) // add header str := replacer.Replace(fmt.Sprintf(hdr, gemojiURL, data)) // change the format of the unicode string str = emojiRE.ReplaceAllStringFunc(str, func(s string) string { var err error s, err = strconv.Unquote(s[len("{Emoji:"):]) if err != nil { panic(err) } return "{" + strconv.QuoteToASCII(s) }) // format return format.Source([]byte(str)) } const hdr = ` // Copyright 2020 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT package emoji // Code generated by build/generate-emoji.go. DO NOT EDIT. // Sourced from %s var GemojiData = %#v `