@mkody/twitch-emoticons 3.0.0-beta.1 → 3.0.0-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -2,10 +2,15 @@
2
2
 
3
3
  Gets Twitch, BTTV, FFZ and 7TV emotes as well as parsing text to emotes!
4
4
 
5
+ > [!IMPORTANT]
6
+ > This branch is for the **currently pre-released** 3.0 version.
7
+ > If you want to see the latest stable version (as of this commit),
8
+ > [switch to the `version/2.9` branch](https://github.com/mkody/twitch-emoticons/tree/version/2.9).
9
+
5
10
 
6
11
  ## Migrate to 3.x
7
12
 
8
- **This release introduces some breaking changes!**
13
+ **This release introduces breaking changes!**
9
14
 
10
15
  <details>
11
16
  <summary>Click here to toggle for details</summary>
@@ -86,9 +91,9 @@ console.log(parser.parse('Hello CoolCat!')) // <- Doesn't require :colons: and r
86
91
  </details>
87
92
 
88
93
 
89
- ## Pre-requisites
94
+ ## Prerequisites
90
95
 
91
- To fetch Twitch emotes you need to [create an app here](https://dev.twitch.tv/console/apps/create), it's free.
96
+ To fetch "native" Twitch emotes, you need to [create an app here](https://dev.twitch.tv/console/apps/create), it's free.
92
97
  If you are only using BetterTTV, FrankerFaceZ and 7TV you don't need to provide Twitch app keys.
93
98
 
94
99
  You must use a Twitch user ID instead of the username to fetch users' emotes.
@@ -97,21 +102,155 @@ You can use [this page to manually convert them](https://s.kdy.ch/twitchid/).
97
102
 
98
103
  ## Install
99
104
 
105
+ From [npm] ([browse on npmx]; use the `@next` tag):
106
+
100
107
  ```sh
101
- npm install @mkody/twitch-emoticons
108
+ npm install @mkody/twitch-emoticons@next
109
+ # or
110
+ pnpm add @mkody/twitch-emoticons@next
111
+ # or
112
+ yarn add @mkody/twitch-emoticons@next
102
113
  # or
103
- pnpm add @mkody/twitch-emoticons
114
+ deno add npm:@mkody/twitch-emoticons@next
115
+ ```
116
+
117
+ From [jsr]:
118
+
119
+ ```sh
120
+ npx jsr add @mkody/twitch-emoticons
104
121
  # or
105
- yarn add @mkody/twitch-emoticons
122
+ pnpm add jsr:@mkody/twitch-emoticons
106
123
  # or
107
- deno add npm:@mkody/twitch-emoticons
124
+ yarn add jsr:@mkody/twitch-emoticons
125
+ # or (version has to be specified while it's a pre-release)
126
+ deno add jsr:@mkody/twitch-emoticons@3.0.0-beta.1
127
+ ```
128
+
129
+ [npm]: https://www.npmjs.com/package/@mkody/twitch-emoticons/v/3.0.0-beta.1
130
+ [browse on npmx]: https://npmx.dev/package/@mkody/twitch-emoticons/v/3.0.0-beta.1
131
+ [jsr]: https://jsr.io/@mkody/twitch-emoticons@3.0.0-beta.1
132
+
133
+
134
+ ## Quick docs
135
+
136
+ <details>
137
+ <summary>Click here to toggle the docs</summary>
138
+
139
+ Here's some quick documentation to explain our two classes, the principal methods, and the settings.
140
+
141
+ > **NOTE:**
142
+ > If you want a more complete documentation, see: https://mkody.github.io/twitch-emoticons/
143
+
144
+
145
+ ### Grab emotes with `EmoteFetcher`
146
+
147
+ First, you need to load a list of emotes, and for that you create a new `EmoteFetcher` object:
148
+
149
+ ```js
150
+ const fetcher = new EmoteFetcher({
151
+ // If you want to use emotes from twitch.tv, you'll need to be authenticated to use their API. You have two options:
152
+ // Option 1: Provide your app ID and secret here (get them at https://dev.twitch.tv/console/apps).
153
+ twitchAppID, // <string>
154
+ twitchAppSecret, // <string>
155
+ // Option 2: If you need a different way to auth or already use `@twurple/api`, you can provide your ApiClient object here.
156
+ apiClient, // <ApiClient>
157
+
158
+ // Force emotes to be static (non-animated).
159
+ forceStatic, // <boolean> - Default: false
160
+
161
+ // Theme mode (background color) preference for Twitch emotes.
162
+ twitchThemeMode // <'dark' | 'light'> - Default: 'dark'
163
+ })
164
+ ```
165
+
166
+ And then you need to make the calls to load what you want.
167
+
168
+ There is one method per platform; all of them return Promises (so you can use `await` or callback chains):
169
+
170
+ - `fetcher.fetchTwitchEmotes()`
171
+ - `fetcher.fetchBTTVEmotes()`
172
+ - `fetcher.fetchFFZEmotes()`
173
+ - `fetcher.fetchSevenTVEmotes()`
174
+
175
+ The first parameter is the Twitch user ID of the channel you want to load emotes from.
176
+ If not provided or it's `null`/falsy, it loads what we call "global emotes", which are available to all users of the platform.
177
+
178
+ Do note that `fetchSevenTVEmotes()` accepts a second parameter with an object:
179
+
180
+ - `format`: Set the image type used, either `webp` or `avif`. Default: `webp`
181
+
182
+ So if you want to load all global emotes, you can do it that way:
183
+
184
+ ```js
185
+ await fetcher.fetchTwitchEmotes()
186
+ await fetcher.fetchBTTVEmotes()
187
+ await fetcher.fetchFFZEmotes()
188
+ await fetcher.fetchSevenTVEmotes(null, { format: 'avif' }) // Example of loading images in AVIF here
189
+ ```
190
+
191
+
192
+ ### Parse strings to include emotes with `EmoteParser`
193
+
194
+ And now that we have our list of emotes that we can expect to find, let's use it!
195
+ Let's create our `EmoteParser` object:
196
+
197
+ ```js
198
+ const parser = new EmoteParser(
199
+ // The first parameter is our EmoteFetcher, the object that holds the list of fetched emotes.
200
+ fetcher, // <EmoteFetcher>
201
+
202
+ // The second parameter is an *optional* object with settings.
203
+ {
204
+ // What output should be used when you parse messages? There are two ways to set that up:
205
+ // Option 1: Use one of the provided templates:
206
+ // - `html`: `<img alt="{name}" title="{name}" class="twitch-emote" src="{link}">`
207
+ // - `markdown`: `![{name}]({link} "{name}")`
208
+ // - `bbcode`: `[img]{link}[/img]`
209
+ // - `plain`: `{link}`
210
+ type, // <'html' | 'markdown' | 'bbcode' | 'plain'> - Default: 'html'
211
+ // Option 2: Make your own template; it has priority over option 1. You can use those: `{link}`, `{name}`, `{size}`, `{creator}`.
212
+ template, // <string> - Default: ''
213
+
214
+ // You can customize the regular expression used to find possible emotes.
215
+ match, // <RegExp>
216
+ },
217
+ )
218
+ ```
219
+
220
+ Now that you have an EmoteParser object, you can do two things with it:
221
+ look up an `Emote` or parse text and get the output as set by `type` or `template`.
222
+
223
+ To grab a specific emote, you can do `fetcher.emotes.get('...')`, with the case-sensitive name of the emote in place of the ellipsis.
224
+ From there, you can read properties like `.code`, `.animated`, `.imageType`, or `.type`,
225
+ but you can also use the `.toLink()` method to… get a link!
226
+
227
+ To parse text, you use the `parser.parse()` method.
228
+ The first parameter is the input text. There's also an optional second parameter
229
+ where you can provide a few settings (which can overwrite the same ones set in the `EmoteFetcher`).
230
+
231
+ ```js
232
+ const parsed = parser.parse(
233
+ // The text to parse.
234
+ text, // <string>
235
+
236
+ // The second parameter is an *optional* object with the settings.
237
+ {
238
+ // Size (scale) for emotes. It varies by provider, and not all share the same resolution in pixels. Play with this value if you'd like, but no guarantees!
239
+ size, // <number>
240
+
241
+ // Force emotes to be static (non-animated).
242
+ forceStatic, // <boolean> - Default: what's in EmoteFetcher or false
243
+
244
+ // Theme mode (background color) preference for Twitch emotes.
245
+ twitchThemeMode // <'dark' | 'light'> - Default: what's in EmoteFetcher or 'dark'
246
+ },
247
+ )
108
248
  ```
109
249
 
110
- See this package on [npm] ([npmx]) or [jsr].
250
+ And that's it for the essentials!
251
+ You can go through the examples below if you need to see more complete code and direct usage.
111
252
 
112
- [npm]: https://www.npmjs.com/package/@mkody/twitch-emoticons
113
- [npmx]: https://npmx.dev/package/@mkody/twitch-emoticons
114
- [jsr]: https://jsr.io/@mkody/twitch-emoticons
253
+ </details>
115
254
 
116
255
 
117
256
  ## Examples
@@ -152,13 +291,20 @@ console.log(parsed)
152
291
 
153
292
  ### 2. Bring your own `@twurple/api`
154
293
 
155
- If you already use [Twurple](https://twurple.js.org/) in your project and manage authentification
156
- (i.e. with user tokens), you can reuse it in this project by setting `apiClient` with your
294
+ If you already use [Twurple](https://twurple.js.org/) in your project and manage authentication
295
+ (i.e., with user tokens), you can reuse it in this project by setting `apiClient` with your
157
296
  [ApiClient](https://twurple.js.org/reference/api/classes/ApiClient.html) object.
158
297
 
159
298
  ```js
299
+ import { ApiClient } from '@twurple/api'
300
+ import { StaticAuthProvider } from '@twurple/auth'
301
+ import { EmoteFetcher } from '@mkody/twitch-emoticons'
302
+
303
+ const authProvider = new StaticAuthProvider('<your app ID>', '<access token>')
304
+ const myCustomApiClient = new ApiClient({ authProvider })
305
+
160
306
  const fetcher = new EmoteFetcher({
161
- apiClient: yourOwnTwurpleApiClientHere,
307
+ apiClient: myCustomApiClient,
162
308
  })
163
309
  ```
164
310
 
@@ -186,6 +332,7 @@ const parser = new EmoteParser(fetcher, {
186
332
  match: /([a-zA-Z0-9_\-]+)/g,
187
333
  })
188
334
 
335
+ // Fetch all emotes at once and wait for all of them to complete
189
336
  Promise.all([
190
337
  // Twitch global
191
338
  fetcher.fetchTwitchEmotes(),
@@ -203,18 +350,20 @@ Promise.all([
203
350
  fetcher.fetchFFZEmotes(),
204
351
  // FFZ channel
205
352
  fetcher.fetchFFZEmotes(channelId),
206
- ]).then(() => {
207
- const globalEmotes = parser.parse('EZ Clap way too easy LUL now for the last boss monkaS LaterSooner')
208
- console.log(globalEmotes)
209
- // <img class="emote" alt="EZ" src="https://cdn.7tv.app/emote/63071b80942ffb69e13d700f/1x.webp"> <img class="emote" alt="Clap" src="https://cdn.7tv.app/emote/62fc0a0c4a75fd54bd3520a9/1x.webp"> way too easy <img class="emote" alt="LUL" src="https://static-cdn.jtvnw.net/emoticons/v2/425618/default/dark/1.0"> now for the last boss <img class="emote" alt="monkaS" src="https://cdn.betterttv.net/emote/56e9f494fff3cc5c35e5287e/1x.webp"> <img class="emote" alt="LaterSooner" src="https://cdn.frankerfacez.com/emote/149346/1">
210
-
211
- const channelEmotes = parser.parse('KEKW that was 3Head TeriPoint')
212
- console.log(channelEmotes)
213
- // <img class="emote" alt="KEKW" src="https://cdn.betterttv.net/emote/5e9c6c187e090362f8b0b9e8/1x.webp"> that was <img class="emote" alt="3Head" src="https://cdn.frankerfacez.com/emote/274406/1"> <img class="emote" alt="TeriPoint" src="https://cdn.7tv.app/emote/61dc299b600369a98b38ebef/1x.webp">
214
- }).catch((err) => {
215
- console.error('Error loading emotes...')
216
- console.error(err)
217
- })
353
+ ])
354
+ .then(() => {
355
+ const globalEmotes = parser.parse('EZ Clap way too easy LUL now for the last boss monkaS LaterSooner')
356
+ console.log(globalEmotes)
357
+ // <img class="emote" alt="EZ" src="https://cdn.7tv.app/emote/63071b80942ffb69e13d700f/1x.webp"> <img class="emote" alt="Clap" src="https://cdn.7tv.app/emote/62fc0a0c4a75fd54bd3520a9/1x.webp"> way too easy <img class="emote" alt="LUL" src="https://static-cdn.jtvnw.net/emoticons/v2/425618/default/dark/1.0"> now for the last boss <img class="emote" alt="monkaS" src="https://cdn.betterttv.net/emote/56e9f494fff3cc5c35e5287e/1x.webp"> <img class="emote" alt="LaterSooner" src="https://cdn.frankerfacez.com/emote/149346/1">
358
+
359
+ const channelEmotes = parser.parse('KEKW that was 3Head TeriPoint')
360
+ console.log(channelEmotes)
361
+ // <img class="emote" alt="KEKW" src="https://cdn.betterttv.net/emote/5e9c6c187e090362f8b0b9e8/1x.webp"> that was <img class="emote" alt="3Head" src="https://cdn.frankerfacez.com/emote/274406/1"> <img class="emote" alt="TeriPoint" src="https://cdn.7tv.app/emote/61dc299b600369a98b38ebef/1x.webp">
362
+ })
363
+ .catch((err) => {
364
+ console.error('Error loading emotes...')
365
+ console.error(err)
366
+ })
218
367
  ```
219
368
 
220
369
 
@@ -226,6 +375,8 @@ By default, we allow animated emotes to be used,
226
375
  but you can override this at the `EmoteFetcher` level:
227
376
 
228
377
  ```js
378
+ import { EmoteFetcher } from '@mkody/twitch-emoticons'
379
+
229
380
  const fetcher = new EmoteFetcher({
230
381
  twitchAppID: '<your app ID>',
231
382
  twitchAppSecret: '<your app secret>',
@@ -271,6 +422,8 @@ By default, emotes are fetched for dark backgrounds,
271
422
  but you can specify a preference at the `EmoteFetcher` level:
272
423
 
273
424
  ```js
425
+ import { EmoteFetcher } from '@mkody/twitch-emoticons'
426
+
274
427
  // For dark backgrounds (default)
275
428
  const fetcherDark = new EmoteFetcher({
276
429
  twitchAppID: '<your app ID>',
@@ -316,9 +469,13 @@ console.log(kappa)
316
469
 
317
470
  7TV v3 delivers emotes in either WEBP or AVIF.
318
471
 
319
- By default we'll return WEBP emotes but you can override this.
472
+ By default we'll return WEBP emotes, but you can override this.
320
473
 
321
474
  ```js
475
+ // (setup)
476
+ import { EmoteFetcher } from '@mkody/twitch-emoticons'
477
+ const fetcher = new EmoteFetcher()
478
+
322
479
  // Fetch global emotes in AVIF (channel id has to be `null` for global)
323
480
  await fetcher.fetchSevenTVEmotes(null, { format: 'avif' })
324
481
 
@@ -338,6 +495,10 @@ await fetcher.fetchSevenTVEmotes(24377667, { format: 'avif' })
338
495
  This can be useful to save the emotes in a cache or for offline content.
339
496
 
340
497
  ```js
498
+ // (setup)
499
+ import { EmoteFetcher } from '@mkody/twitch-emoticons'
500
+ const fetcher = new EmoteFetcher()
501
+
341
502
  // First fetch some emotes
342
503
  await fetcher.fetchSevenTVEmotes(null, { format: 'avif' })
343
504
 
@@ -362,6 +523,7 @@ fetcher.fromObject(emotes)
362
523
  - [Changelog](https://github.com/mkody/twitch-emoticons/releases)
363
524
 
364
525
  This library uses the following:
526
+
365
527
  - [Twurple](https://twurple.js.org/) and the [Twitch API](https://dev.twitch.tv/)
366
528
  - [BetterTTV API](https://betterttv.com/developers/api)
367
529
  - [FrankerFaceZ API](https://api.frankerfacez.com/docs/)
@@ -160,11 +160,12 @@ var BTTVEmote = class _BTTVEmote extends Emote_default {
160
160
  * @returns {object} - Object representation of the BTTVEmote.
161
161
  */
162
162
  toObject() {
163
- return Object.assign({}, super.toObject(), {
163
+ return {
164
+ ...super.toObject(),
164
165
  animated: this.animated,
165
166
  ownerName: this.ownerName,
166
167
  type: this.type
167
- });
168
+ };
168
169
  }
169
170
  /**
170
171
  * Converts an emote Object into a BTTVEmote
@@ -199,16 +200,22 @@ var Collection = class extends Map {
199
200
  */
200
201
  find(propOrFunc, value) {
201
202
  if (typeof propOrFunc === "string") {
202
- if (typeof value === "undefined") return null;
203
+ if (value === void 0) {
204
+ return null;
205
+ }
203
206
  for (const item of this.values()) {
204
- if (item[propOrFunc] === value) return item;
207
+ if (item[propOrFunc] === value) {
208
+ return item;
209
+ }
205
210
  }
206
211
  return null;
207
212
  }
208
213
  if (typeof propOrFunc === "function") {
209
214
  let i = 0;
210
215
  for (const item of this.values()) {
211
- if (propOrFunc(item, i, this)) return item;
216
+ if (propOrFunc(item, i, this)) {
217
+ return item;
218
+ }
212
219
  i++;
213
220
  }
214
221
  return null;
@@ -223,11 +230,15 @@ var Collection = class extends Map {
223
230
  * @returns {Collection} - A new collection with the filtered items.
224
231
  */
225
232
  filter(func, thisArg) {
226
- if (thisArg) func = func.bind(thisArg);
233
+ if (thisArg) {
234
+ func = func.bind(thisArg);
235
+ }
227
236
  const results = new this.constructor();
228
237
  let i = 0;
229
238
  for (const [key, item] of this) {
230
- if (func(item, i, this)) results.set(key, item);
239
+ if (func(item, i, this)) {
240
+ results.set(key, item);
241
+ }
231
242
  i++;
232
243
  }
233
244
  return results;
@@ -240,7 +251,9 @@ var Collection = class extends Map {
240
251
  * @returns {any[]} - An array with the mapped items.
241
252
  */
242
253
  map(func, thisArg) {
243
- if (thisArg) func = func.bind(thisArg);
254
+ if (thisArg) {
255
+ func = func.bind(thisArg);
256
+ }
244
257
  const array = new Array(this.size);
245
258
  let i = 0;
246
259
  for (const item of this.values()) {
@@ -334,13 +347,14 @@ var FFZEmote = class _FFZEmote extends Emote_default {
334
347
  * @returns {object} - Object representation of the FFZEmote.
335
348
  */
336
349
  toObject() {
337
- return Object.assign({}, super.toObject(), {
350
+ return {
351
+ ...super.toObject(),
338
352
  animated: this.animated,
339
353
  sizes: this.sizes,
340
354
  ownerName: this.ownerName,
341
355
  type: this.type,
342
356
  modifier: this.modifier
343
- });
357
+ };
344
358
  }
345
359
  /**
346
360
  * Converts an emote Object into a FFZEmote
@@ -411,13 +425,14 @@ var SevenTVEmote = class _SevenTVEmote extends Emote_default {
411
425
  * @returns {object} - Object representation of the SevenTVEmote.
412
426
  */
413
427
  toObject() {
414
- return Object.assign({}, super.toObject(), {
428
+ return {
429
+ ...super.toObject(),
415
430
  animated: this.animated,
416
431
  sizes: this.sizes,
417
432
  ownerName: this.ownerName,
418
433
  type: this.type,
419
434
  imageType: this.imageType
420
- });
435
+ };
421
436
  }
422
437
  /**
423
438
  * Converts an emote Object into a SevenTVEmote
@@ -490,11 +505,12 @@ var TwitchEmote = class _TwitchEmote extends Emote_default {
490
505
  * @returns {object} - Object representation of the TwitchEmote.
491
506
  */
492
507
  toObject() {
493
- return Object.assign({}, super.toObject(), {
508
+ return {
509
+ ...super.toObject(),
494
510
  animated: this.animated,
495
511
  set: this.set,
496
512
  type: this.type
497
- });
513
+ };
498
514
  }
499
515
  /**
500
516
  * Converts an emote Object into a TwitchEmote
@@ -607,11 +623,14 @@ var EmoteFetcher = class {
607
623
  * @returns {Promise<object[]>} - A promise that resolves to an array of raw BTTV emote data.
608
624
  */
609
625
  _getRawBTTVEmotes(id) {
610
- const endpoint = !id ? Constants_default.BTTV.Global : Constants_default.BTTV.Channel(id);
626
+ const endpoint = id ? Constants_default.BTTV.Channel(id) : Constants_default.BTTV.Global;
611
627
  return fetch(endpoint).then((response) => response.json()).then((data) => {
612
- if (data instanceof Array) return data;
613
- if (data && data.channelEmotes && data.sharedEmotes) {
614
- return [...data.channelEmotes, ...data.sharedEmotes];
628
+ if (Array.isArray(data)) return data;
629
+ if (data?.channelEmotes && data?.sharedEmotes) {
630
+ return [
631
+ ...data.channelEmotes,
632
+ ...data.sharedEmotes
633
+ ];
615
634
  }
616
635
  return data || [];
617
636
  });
@@ -682,7 +701,7 @@ var EmoteFetcher = class {
682
701
  * @returns {Promise<object[]>} - A promise that resolves to an array of raw 7TV emote data.
683
702
  */
684
703
  _getRawSevenTVEmotes(id) {
685
- const endpoint = !id ? Constants_default.SevenTV.Global : Constants_default.SevenTV.Channel(id);
704
+ const endpoint = id ? Constants_default.SevenTV.Channel(id) : Constants_default.SevenTV.Global;
686
705
  return fetch(endpoint).then((response) => response.json());
687
706
  }
688
707
  /**
@@ -774,7 +793,7 @@ var EmoteFetcher = class {
774
793
  format = "webp"
775
794
  } = options || {};
776
795
  return this._getRawSevenTVEmotes(channel).then((rawEmotes) => {
777
- if ("emotes" in rawEmotes) {
796
+ if (Object.hasOwn(rawEmotes, "emotes")) {
778
797
  for (const data of rawEmotes.emotes) {
779
798
  this._cacheSevenTVEmote(channel, data, format);
780
799
  }
@@ -828,7 +847,7 @@ var EmoteParser = class {
828
847
  * - `{name}` The name of the emote.
829
848
  * - `{size}` The size index of the image.
830
849
  * - `{creator}` The channel/owner name of the emote.
831
- * @param {string} [options.type='html'] - The type of the parser.
850
+ * @param {'html' | 'markdown' | 'bbcode' | 'plain'} [options.type='html'] - The type of the parser.
832
851
  * Can be one of `html`, `markdown`, `bbcode`, or `plain`.
833
852
  * If the `template` option is provided, this is ignored.
834
853
  * @param {RegExp} [options.match=/(\w+)/g] - The regular expression that matches an emote.
@@ -836,14 +855,12 @@ var EmoteParser = class {
836
855
  */
837
856
  constructor(fetcher, options = {}) {
838
857
  this.fetcher = fetcher;
839
- this.options = Object.assign(
840
- {
841
- template: "",
842
- type: "html",
843
- match: /(\w+)/g
844
- },
845
- options
846
- );
858
+ this.options = {
859
+ template: "",
860
+ type: "html",
861
+ match: /(\w+)/g,
862
+ ...options
863
+ };
847
864
  this._validateOptions(this.options);
848
865
  }
849
866
  /**
@@ -856,8 +873,8 @@ var EmoteParser = class {
856
873
  * - `{name}` The name of the emote.
857
874
  * - `{size}` The size of the image.
858
875
  * - `{creator}` The channel/owner name of the emote.
859
- * @param {string} [options.type] - The type of the parser.
860
- * Can be one of `html`, `markdown`,`bbcode`, or `plain`.
876
+ * @param {'html' | 'markdown' | 'bbcode' | 'plain'} [options.type] - The type of the parser.
877
+ * Can be one of `html`, `markdown`, `bbcode`, or `plain`.
861
878
  * If the `template` option is provided, this is ignored.
862
879
  * @param {RegExp} [options.match] - The regular expression that matches an emote.
863
880
  * Must be a global regex, with one capture group for the emote code.
@@ -897,7 +914,7 @@ var EmoteParser = class {
897
914
  if (emote.modifier) return "";
898
915
  const template = this.options.template || Constants_default.Templates[this.options.type];
899
916
  const link = emote.toLink({ size, forceStatic, themeMode });
900
- const res = template.replace(/{link}/g, link).replace(/{name}/g, emote.code).replace(/{size}/g, size).replace(/{creator}/g, emote.ownerName || "global");
917
+ const res = template.replaceAll("{link}", link).replaceAll("{name}", emote.code).replaceAll("{size}", size).replaceAll("{creator}", emote.ownerName || "global");
901
918
  return res;
902
919
  });
903
920
  return parsed;