Repository: twitch-apis/twitch-js (js)

Issue:
bug v2: Emotes should be Array and not Object of unique keys
## Expected behaviour

Emotes should contain full set of emotes in message

example
```javascript
emotes: [{ emote: '496', start: 0, end: 1 }, { emote: '496', start: 4, end: 5 } ],
```
or

```javascript
emotes: { '496': [  { start: 0, end: 1 },  { start: 4, end: 5 }]}
```

## Actual behaviour

First occurence only of emote is in emote object

```javascript
emotes: { '496': { start: 0, end: 1 } },
```

## Steps to reproduce

1. Send message with emotes `:D Lorem Ipsum :D`
2. `console.log(message.tags.emotes)`


## Your environment

* Operating system(s):
* TwitchJS version: 2.0.0-beta.12
* NodeJS version: 10.7.0
* Browser(s): n/a


Pull request description:
Bugfix: duplicate emotes
Resolves #142.

Patch:
diff --git a/docs/reference/typedef.md b/docs/reference/typedef.md
index d24170f..11ddc91 100644
--- a/docs/reference/typedef.md
+++ b/docs/reference/typedef.md
@@ -292,7 +292,7 @@ USERSTATE tags
 <tr>
     <td>badges</td><td><code><a href="typedef#BadgesTag">BadgesTag</a></code></td>
     </tr><tr>
-    <td>emotes</td><td><code>Object.&lt;number, EmoteTag&gt;</code></td>
+    <td>emotes</td><td><code><a href="typedef#EmoteTag">Array.&lt;EmoteTag&gt;</a></code></td>
     </tr><tr>
     <td>emoteSets</td><td><code>Array.&lt;string&gt;</code></td>
     </tr><tr>
@@ -361,14 +361,19 @@ Emote tag
 <table>
   <thead>
     <tr>
-      <th>Name</th><th>Type</th>
+      <th>Name</th><th>Type</th><th>Description</th>
     </tr>
   </thead>
   <tbody>
 <tr>
-    <td>start</td><td><code>number</code></td>
+    <td>id</td><td><code>string</code></td><td><p>ID</p>
+</td>
     </tr><tr>
-    <td>end</td><td><code>number</code></td>
+    <td>start</td><td><code>number</code></td><td><p>Starting index</p>
+</td>
+    </tr><tr>
+    <td>end</td><td><code>number</code></td><td><p>Ending index</p>
+</td>
     </tr>  </tbody>
 </table>
 
diff --git a/src/Chat/utils/parsers/tags.js b/src/Chat/utils/parsers/tags.js
index 14f4ad5..721e19d 100644
--- a/src/Chat/utils/parsers/tags.js
+++ b/src/Chat/utils/parsers/tags.js
@@ -115,7 +115,7 @@ const userNoticeEvent = tags => {
  * USERSTATE tags
  * @typedef {Object} UserStateTags
  * @property {BadgesTag} badges
- * @property {Object<number, EmoteTag>} emotes
+ * @property {Array<EmoteTag>} emotes
  * @property {Array<string>} emoteSets
  * @property {boolean} isModerator
  * @property {boolean} isSubscriber
diff --git a/src/Chat/utils/parsers/types.js b/src/Chat/utils/parsers/types.js
index 2762471..a26acbe 100644
--- a/src/Chat/utils/parsers/types.js
+++ b/src/Chat/utils/parsers/types.js
@@ -49,23 +49,29 @@ const badges = maybeBadges => {
 }
 
 const emotes = maybeEmotes => {
+  if (typeof maybeEmotes !== 'string') {
+    return []
+  }
+
   /**
    * Emote tag
    * @typedef {Object} EmoteTag
-   * @property {number} start
-   * @property {number} end
+   * @property {string} id ID
+   * @property {number} start Starting index
+   * @property {number} end Ending index
    * @see https://dev.twitch.tv/docs/irc/tags/#privmsg-twitch-tags
    */
-  return typeof maybeEmotes === 'string'
-    ? maybeEmotes.split('/').reduce((parsed, emote) => {
-        const [key, value] = emote.split(':')
-        const [start, end] = value.split('-')
-        return {
-          ...parsed,
-          [key]: { start: parseInt(start, 10), end: parseInt(end, 10) },
-        }
-      }, {})
-    : {}
+  return maybeEmotes.split('/').reduce((emoteTag, emoteIndices) => {
+    const [id, indices] = emoteIndices.split(':')
+
+    return [
+      ...emoteTag,
+      ...indices.split(',').map(index => {
+        const [start, end] = index.split('-')
+        return { id, start: parseInt(start, 10), end: parseInt(end, 10) }
+      }),
+    ]
+  }, [])
 }
 
 const emoteSets = maybeEmoteSets => {


Test patch:
diff --git a/src/Chat/__tests__/__snapshots__/index.test.js.snap b/src/Chat/__tests__/__snapshots__/index.test.js.snap
index 12154f0..e3dffb6 100644
--- a/src/Chat/__tests__/__snapshots__/index.test.js.snap
+++ b/src/Chat/__tests__/__snapshots__/index.test.js.snap
@@ -154,7 +154,7 @@ Array [
           "10337",
           "12239",
         ],
-        "emotes": Object {},
+        "emotes": Array [],
         "isModerator": true,
         "isSubGifter": false,
         "isSubscriber": true,
@@ -787,7 +787,7 @@ Object {
     "color": true,
     "displayName": "dallas",
     "emoteSets": undefined,
-    "emotes": Object {},
+    "emotes": Array [],
     "id": "b34ccfc7-4977-403a-8a94-33c6bac34fb8",
     "isModerator": false,
     "isSubGifter": false,
@@ -869,16 +869,23 @@ Object {
     "color": "#0D4200",
     "displayName": "dallas",
     "emoteSets": undefined,
-    "emotes": Object {
-      "1902": Object {
-        "end": 10,
-        "start": 6,
-      },
-      "25": Object {
+    "emotes": Array [
+      Object {
         "end": 4,
+        "id": "25",
         "start": 0,
       },
-    },
+      Object {
+        "end": 16,
+        "id": "25",
+        "start": 12,
+      },
+      Object {
+        "end": 10,
+        "id": "1902",
+        "start": 6,
+      },
+    ],
     "id": "b34ccfc7-4977-403a-8a94-33c6bac34fb8",
     "isModerator": false,
     "isSubGifter": false,
@@ -918,7 +925,7 @@ Object {
     "color": "#9ACD32",
     "displayName": "TestChannel",
     "emoteSets": undefined,
-    "emotes": Object {},
+    "emotes": Array [],
     "id": "3d830f12-795c-447d-af3c-ea05e40fbddb",
     "isModerator": false,
     "isSubGifter": false,
@@ -966,7 +973,7 @@ Object {
     "color": "#008000",
     "displayName": "ronni",
     "emoteSets": undefined,
-    "emotes": Object {},
+    "emotes": Array [],
     "id": "db25007f-7a18-43eb-9379-80131e44d633",
     "isModerator": false,
     "isSubGifter": false,
@@ -1008,12 +1015,13 @@ Object {
     "color": true,
     "displayName": "SevenTest1",
     "emoteSets": undefined,
-    "emotes": Object {
-      "30259": Object {
+    "emotes": Array [
+      Object {
         "end": 6,
+        "id": "30259",
         "start": 0,
       },
-    },
+    ],
     "id": "37feed0f-b9c7-4c3a-b475-21c6c6d21c3d",
     "isModerator": false,
     "isSubGifter": false,
@@ -1059,7 +1067,7 @@ Object {
     "color": true,
     "displayName": "Nefarious_Ned",
     "emoteSets": undefined,
-    "emotes": Object {},
+    "emotes": Array [],
     "id": "761a4698-b867-4668-9658-c3844c7b8637",
     "isModerator": false,
     "isSubGifter": true,
@@ -1107,7 +1115,7 @@ Object {
     "color": "#008000",
     "displayName": "ronni",
     "emoteSets": undefined,
-    "emotes": Object {},
+    "emotes": Array [],
     "id": "db25007f-7a18-43eb-9379-80131e44d633",
     "isModerator": false,
     "isSubGifter": false,
@@ -1157,7 +1165,7 @@ Object {
     "color": "#0000FF",
     "displayName": "TWW2",
     "emoteSets": undefined,
-    "emotes": Object {},
+    "emotes": Array [],
     "id": "e9176cd8-5e22-4684-ad40-ce53c2561c5e",
     "isModerator": false,
     "isSubGifter": false,
@@ -1202,12 +1210,13 @@ Object {
     "color": true,
     "displayName": "SevenTest1",
     "emoteSets": undefined,
-    "emotes": Object {
-      "30259": Object {
+    "emotes": Array [
+      Object {
         "end": 6,
+        "id": "30259",
         "start": 0,
       },
-    },
+    ],
     "id": "37feed0f-b9c7-4c3a-b475-21c6c6d21c3d",
     "isModerator": false,
     "isSubGifter": false,
@@ -1281,7 +1290,7 @@ Object {
       "10337",
       "12239",
     ],
-    "emotes": Object {},
+    "emotes": Array [],
     "isModerator": true,
     "isSubGifter": false,
     "isSubscriber": true,