loading up the forgejo repo on tangled to test page performance
1// Copyright 2020 The Gitea Authors. All rights reserved.
2// Copyright 2015 Kenneth Shaw
3// SPDX-License-Identifier: MIT
4
5//go:build ignore
6
7package main
8
9import (
10 "flag"
11 "fmt"
12 "go/format"
13 "io"
14 "log"
15 "net/http"
16 "os"
17 "regexp"
18 "sort"
19 "strconv"
20 "strings"
21 "unicode/utf8"
22
23 "forgejo.org/modules/json"
24)
25
26const (
27 gemojiURL = "https://raw.githubusercontent.com/github/gemoji/master/db/emoji.json"
28 maxUnicodeVersion = 15
29)
30
31var flagOut = flag.String("o", "modules/emoji/emoji_data.go", "out")
32
33// Gemoji is a set of emoji data.
34type Gemoji []Emoji
35
36// Emoji represents a single emoji and associated data.
37type Emoji struct {
38 Emoji string `json:"emoji"`
39 Description string `json:"description,omitempty"`
40 Aliases []string `json:"aliases"`
41 UnicodeVersion string `json:"unicode_version,omitempty"`
42 SkinTones bool `json:"skin_tones,omitempty"`
43}
44
45// Don't include some fields in JSON
46func (e Emoji) MarshalJSON() ([]byte, error) {
47 type emoji Emoji
48 x := emoji(e)
49 x.UnicodeVersion = ""
50 x.Description = ""
51 x.SkinTones = false
52 return json.Marshal(x)
53}
54
55func main() {
56 flag.Parse()
57
58 // generate data
59 buf, err := generate()
60 if err != nil {
61 log.Fatalf("generate err: %v", err)
62 }
63
64 // write
65 err = os.WriteFile(*flagOut, buf, 0o644)
66 if err != nil {
67 log.Fatalf("WriteFile err: %v", err)
68 }
69}
70
71var replacer = strings.NewReplacer(
72 "main.Gemoji", "Gemoji",
73 "main.Emoji", "\n",
74 "}}", "},\n}",
75 ", Description:", ", ",
76 ", Aliases:", ", ",
77 ", UnicodeVersion:", ", ",
78 ", SkinTones:", ", ",
79)
80
81var emojiRE = regexp.MustCompile(`\{Emoji:"([^"]*)"`)
82
83func generate() ([]byte, error) {
84 // load gemoji data
85 res, err := http.Get(gemojiURL)
86 if err != nil {
87 return nil, err
88 }
89 defer res.Body.Close()
90
91 // read all
92 body, err := io.ReadAll(res.Body)
93 if err != nil {
94 return nil, err
95 }
96
97 // unmarshal
98 var data Gemoji
99 err = json.Unmarshal(body, &data)
100 if err != nil {
101 return nil, err
102 }
103
104 skinTones := make(map[string]string)
105
106 skinTones["\U0001f3fb"] = "Light Skin Tone"
107 skinTones["\U0001f3fc"] = "Medium-Light Skin Tone"
108 skinTones["\U0001f3fd"] = "Medium Skin Tone"
109 skinTones["\U0001f3fe"] = "Medium-Dark Skin Tone"
110 skinTones["\U0001f3ff"] = "Dark Skin Tone"
111
112 var tmp Gemoji
113
114 // filter out emoji that require greater than max unicode version
115 for i := range data {
116 val, _ := strconv.ParseFloat(data[i].UnicodeVersion, 64)
117 if int(val) <= maxUnicodeVersion {
118 tmp = append(tmp, data[i])
119 }
120 }
121 data = tmp
122
123 sort.Slice(data, func(i, j int) bool {
124 return data[i].Aliases[0] < data[j].Aliases[0]
125 })
126
127 aliasMap := make(map[string]int, len(data))
128
129 for i, e := range data {
130 if e.Emoji == "" || len(e.Aliases) == 0 {
131 continue
132 }
133 for _, a := range e.Aliases {
134 if a == "" {
135 continue
136 }
137 aliasMap[a] = i
138 }
139 }
140
141 // Forgejo customizations
142 i, ok := aliasMap["tada"]
143 if ok {
144 data[i].Aliases = append(data[i].Aliases, "hooray")
145 }
146 i, ok = aliasMap["laughing"]
147 if ok {
148 data[i].Aliases = append(data[i].Aliases, "laugh")
149 }
150
151 // write a JSON file to use with tribute (write before adding skin tones since we can't support them there yet)
152 file, _ := json.Marshal(data)
153 _ = os.WriteFile("assets/emoji.json", file, 0o644)
154
155 // Add skin tones to emoji that support it
156 var (
157 s []string
158 newEmoji string
159 newDescription string
160 newData Emoji
161 )
162
163 for i := range data {
164 if data[i].SkinTones {
165 for k, v := range skinTones {
166 s = strings.Split(data[i].Emoji, "")
167
168 if utf8.RuneCountInString(data[i].Emoji) == 1 {
169 s = append(s, k)
170 } else {
171 // insert into slice after first element because all emoji that support skin tones
172 // have that modifier placed at this spot
173 s = append(s, "")
174 copy(s[2:], s[1:])
175 s[1] = k
176 }
177
178 newEmoji = strings.Join(s, "")
179 newDescription = data[i].Description + ": " + v
180 newAlias := data[i].Aliases[0] + "_" + strings.ReplaceAll(v, " ", "_")
181
182 newData = Emoji{newEmoji, newDescription, []string{newAlias}, "12.0", false}
183 data = append(data, newData)
184 }
185 }
186 }
187
188 sort.Slice(data, func(i, j int) bool {
189 return data[i].Aliases[0] < data[j].Aliases[0]
190 })
191
192 // add header
193 str := replacer.Replace(fmt.Sprintf(hdr, gemojiURL, data))
194
195 // change the format of the unicode string
196 str = emojiRE.ReplaceAllStringFunc(str, func(s string) string {
197 var err error
198 s, err = strconv.Unquote(s[len("{Emoji:"):])
199 if err != nil {
200 panic(err)
201 }
202 return "{" + strconv.QuoteToASCII(s)
203 })
204
205 // format
206 return format.Source([]byte(str))
207}
208
209const hdr = `
210// Copyright 2020 The Gitea Authors. All rights reserved.
211// SPDX-License-Identifier: MIT
212
213
214package emoji
215
216// Code generated by build/generate-emoji.go. DO NOT EDIT.
217// Sourced from %s
218var GemojiData = %#v
219`