@chatsift/discord-utils 0.6.0 → 0.6.1
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/dist/__tests__/embed.test.d.ts +2 -0
- package/dist/__tests__/embed.test.d.ts.map +1 -0
- package/dist/__tests__/sortChannels.test.d.ts +2 -0
- package/dist/__tests__/sortChannels.test.d.ts.map +1 -0
- package/dist/embed.d.ts +73 -0
- package/dist/embed.d.ts.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3 -7
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +3 -7
- package/dist/index.mjs.map +1 -1
- package/dist/sortChannels.d.ts +17 -0
- package/dist/sortChannels.d.ts.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"embed.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/embed.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sortChannels.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/sortChannels.test.ts"],"names":[],"mappings":""}
|
package/dist/embed.d.ts
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import type { APIEmbed, APIEmbedField } from 'discord-api-types/v10';
|
|
2
|
+
/**
|
|
3
|
+
* Limits commonly encountered with Discord's API
|
|
4
|
+
*/
|
|
5
|
+
export declare const MESSAGE_LIMITS: {
|
|
6
|
+
/**
|
|
7
|
+
* How long a message can be in characters
|
|
8
|
+
*/
|
|
9
|
+
readonly CONTENT: 4000;
|
|
10
|
+
/**
|
|
11
|
+
* How many embeds can be in a message
|
|
12
|
+
*/
|
|
13
|
+
readonly EMBED_COUNT: 10;
|
|
14
|
+
/**
|
|
15
|
+
* Embed specific limits
|
|
16
|
+
*/
|
|
17
|
+
readonly EMBEDS: {
|
|
18
|
+
/**
|
|
19
|
+
* How long an embed title can be in characters
|
|
20
|
+
*/
|
|
21
|
+
readonly TITLE: 256;
|
|
22
|
+
/**
|
|
23
|
+
* How long an embed description can be in characters
|
|
24
|
+
*/
|
|
25
|
+
readonly DESCRIPTION: 4096;
|
|
26
|
+
/**
|
|
27
|
+
* How long an embed footer can be in characters
|
|
28
|
+
*/
|
|
29
|
+
readonly FOOTER: 2048;
|
|
30
|
+
/**
|
|
31
|
+
* How long an embed author can be in characters
|
|
32
|
+
*/
|
|
33
|
+
readonly AUTHOR: 256;
|
|
34
|
+
/**
|
|
35
|
+
* How many fields an embed can have
|
|
36
|
+
*/
|
|
37
|
+
readonly FIELD_COUNT: 25;
|
|
38
|
+
/**
|
|
39
|
+
* Field specific limits
|
|
40
|
+
*/
|
|
41
|
+
readonly FIELDS: {
|
|
42
|
+
/**
|
|
43
|
+
* How long a field name can be in characters
|
|
44
|
+
*/
|
|
45
|
+
readonly NAME: 256;
|
|
46
|
+
/**
|
|
47
|
+
* How long a field value can be in characters
|
|
48
|
+
*/
|
|
49
|
+
readonly VALUE: 1024;
|
|
50
|
+
};
|
|
51
|
+
};
|
|
52
|
+
};
|
|
53
|
+
/**
|
|
54
|
+
* Adds the given fields to an embed - mutating it
|
|
55
|
+
*
|
|
56
|
+
* @param embed - The embed to add fields to
|
|
57
|
+
* @param fields - The fields to add
|
|
58
|
+
*/
|
|
59
|
+
export declare function addFields(embed: APIEmbed, ...fields: APIEmbedField[]): APIEmbed;
|
|
60
|
+
/**
|
|
61
|
+
* Cuts off text after the given length - appending "..." at the end
|
|
62
|
+
*
|
|
63
|
+
* @param text - The text to cut off
|
|
64
|
+
* @param total - The maximum length of the text
|
|
65
|
+
*/
|
|
66
|
+
export declare function ellipsis(text: string, total: number): string;
|
|
67
|
+
/**
|
|
68
|
+
* Returns a fully truncated embed - safe to use with Discord's API - does not mutate the given embed
|
|
69
|
+
*
|
|
70
|
+
* @param embed - The embed to truncate
|
|
71
|
+
*/
|
|
72
|
+
export declare function truncateEmbed(embed: APIEmbed): APIEmbed;
|
|
73
|
+
//# sourceMappingURL=embed.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"embed.d.ts","sourceRoot":"","sources":["../src/embed.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAErE;;GAEG;AACH,eAAO,MAAM,cAAc;IAC1B;;OAEG;;IAEH;;OAEG;;IAEH;;OAEG;;QAEF;;WAEG;;QAEH;;WAEG;;QAEH;;WAEG;;QAEH;;WAEG;;QAEH;;WAEG;;QAEH;;WAEG;;YAEF;;eAEG;;YAEH;;eAEG;;;;CAII,CAAC;AAEX;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,QAAQ,EAAE,GAAG,MAAM,EAAE,aAAa,EAAE,GAAG,QAAQ,CAG/E;AAED;;;;;GAKG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAW5D;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,QAAQ,GAAG,QAAQ,CA2BvD"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,mBAAmB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -133,13 +133,13 @@ function sortChannels(unsorted) {
|
|
|
133
133
|
if (a.type === import_v10.ChannelType.GuildCategory && b.type === import_v10.ChannelType.GuildText) {
|
|
134
134
|
return 1;
|
|
135
135
|
}
|
|
136
|
-
return a.position - b.position;
|
|
136
|
+
return (a.position ?? 0) - (b.position ?? 0);
|
|
137
137
|
});
|
|
138
138
|
const channels = [];
|
|
139
139
|
for (const top of sortedTopLevel ?? []) {
|
|
140
140
|
channels.push(top);
|
|
141
141
|
if (top.type === import_v10.ChannelType.GuildCategory) {
|
|
142
|
-
const categoryChannels = (grouped[top.id] ?? []).sort((a, b) => a.position - b.position);
|
|
142
|
+
const categoryChannels = (grouped[top.id] ?? []).sort((a, b) => (a.position ?? 0) - (b.position ?? 0));
|
|
143
143
|
channels.push(...categoryChannels);
|
|
144
144
|
for (const channel of categoryChannels) {
|
|
145
145
|
const channelThreads = threads.filter((thread) => thread.parent_id === channel.id).sort((a, b) => Number(BigInt(b.id) - BigInt(a.id)));
|
|
@@ -150,11 +150,7 @@ function sortChannels(unsorted) {
|
|
|
150
150
|
channels.push(...channelThreads);
|
|
151
151
|
}
|
|
152
152
|
}
|
|
153
|
-
return channels.length ? channels : filtered.sort((a, b) =>
|
|
154
|
-
const aPos = "position" in a ? a.position ?? 0 : 0;
|
|
155
|
-
const bPos = "position" in b ? b.position ?? 0 : 0;
|
|
156
|
-
return aPos - bPos;
|
|
157
|
-
});
|
|
153
|
+
return channels.length ? channels : filtered.sort((a, b) => (a.position ?? 0) - (b.position ?? 0));
|
|
158
154
|
}
|
|
159
155
|
__name(sortChannels, "sortChannels");
|
|
160
156
|
// Annotate the CommonJS export names for ESM import in node:
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/embed.ts","../src/sortChannels.ts"],"sourcesContent":["export * from './embed.js';\nexport * from './sortChannels.js';\n","import type { APIEmbed, APIEmbedField } from 'discord-api-types/v10';\n\n/**\n * Limits commonly encountered with Discord's API\n */\nexport const MESSAGE_LIMITS = {\n\t/**\n\t * How long a message can be in characters\n\t */\n\tCONTENT: 4_000,\n\t/**\n\t * How many embeds can be in a message\n\t */\n\tEMBED_COUNT: 10,\n\t/**\n\t * Embed specific limits\n\t */\n\tEMBEDS: {\n\t\t/**\n\t\t * How long an embed title can be in characters\n\t\t */\n\t\tTITLE: 256,\n\t\t/**\n\t\t * How long an embed description can be in characters\n\t\t */\n\t\tDESCRIPTION: 4_096,\n\t\t/**\n\t\t * How long an embed footer can be in characters\n\t\t */\n\t\tFOOTER: 2_048,\n\t\t/**\n\t\t * How long an embed author can be in characters\n\t\t */\n\t\tAUTHOR: 256,\n\t\t/**\n\t\t * How many fields an embed can have\n\t\t */\n\t\tFIELD_COUNT: 25,\n\t\t/**\n\t\t * Field specific limits\n\t\t */\n\t\tFIELDS: {\n\t\t\t/**\n\t\t\t * How long a field name can be in characters\n\t\t\t */\n\t\t\tNAME: 256,\n\t\t\t/**\n\t\t\t * How long a field value can be in characters\n\t\t\t */\n\t\t\tVALUE: 1_024,\n\t\t},\n\t},\n} as const;\n\n/**\n * Adds the given fields to an embed - mutating it\n *\n * @param embed - The embed to add fields to\n * @param fields - The fields to add\n */\nexport function addFields(embed: APIEmbed, ...fields: APIEmbedField[]): APIEmbed {\n\t(embed.fields ??= []).push(...fields);\n\treturn embed;\n}\n\n/**\n * Cuts off text after the given length - appending \"...\" at the end\n *\n * @param text - The text to cut off\n * @param total - The maximum length of the text\n */\nexport function ellipsis(text: string, total: number): string {\n\tif (text.length <= total) {\n\t\treturn text;\n\t}\n\n\tconst keep = total - 3;\n\tif (keep < 1) {\n\t\treturn text.slice(0, total);\n\t}\n\n\treturn `${text.slice(0, keep)}...`;\n}\n\n/**\n * Returns a fully truncated embed - safe to use with Discord's API - does not mutate the given embed\n *\n * @param embed - The embed to truncate\n */\nexport function truncateEmbed(embed: APIEmbed): APIEmbed {\n\t// @ts-expect-error - Because of the explicit undefined\n\treturn {\n\t\t...embed,\n\t\tdescription: embed.description ? ellipsis(embed.description, MESSAGE_LIMITS.EMBEDS.DESCRIPTION) : undefined,\n\t\ttitle: embed.title ? ellipsis(embed.title, MESSAGE_LIMITS.EMBEDS.TITLE) : undefined,\n\t\tauthor: embed.author\n\t\t\t? {\n\t\t\t\t\t...embed.author,\n\t\t\t\t\tname: ellipsis(embed.author.name, MESSAGE_LIMITS.EMBEDS.AUTHOR),\n\t\t\t\t}\n\t\t\t: undefined,\n\t\tfooter: embed.footer\n\t\t\t? {\n\t\t\t\t\t...embed.footer,\n\t\t\t\t\ttext: ellipsis(embed.footer.text, MESSAGE_LIMITS.EMBEDS.FOOTER),\n\t\t\t\t}\n\t\t\t: undefined,\n\t\tfields: embed.fields\n\t\t\t? embed.fields\n\t\t\t\t\t.map((field) => ({\n\t\t\t\t\t\tname: ellipsis(field.name, MESSAGE_LIMITS.EMBEDS.FIELDS.NAME),\n\t\t\t\t\t\tvalue: ellipsis(field.value, MESSAGE_LIMITS.EMBEDS.FIELDS.VALUE),\n\t\t\t\t\t}))\n\t\t\t\t\t.slice(0, MESSAGE_LIMITS.EMBEDS.FIELD_COUNT)\n\t\t\t: [],\n\t};\n}\n","import
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/embed.ts","../src/sortChannels.ts"],"sourcesContent":["export * from './embed.js';\nexport * from './sortChannels.js';\n","import type { APIEmbed, APIEmbedField } from 'discord-api-types/v10';\n\n/**\n * Limits commonly encountered with Discord's API\n */\nexport const MESSAGE_LIMITS = {\n\t/**\n\t * How long a message can be in characters\n\t */\n\tCONTENT: 4_000,\n\t/**\n\t * How many embeds can be in a message\n\t */\n\tEMBED_COUNT: 10,\n\t/**\n\t * Embed specific limits\n\t */\n\tEMBEDS: {\n\t\t/**\n\t\t * How long an embed title can be in characters\n\t\t */\n\t\tTITLE: 256,\n\t\t/**\n\t\t * How long an embed description can be in characters\n\t\t */\n\t\tDESCRIPTION: 4_096,\n\t\t/**\n\t\t * How long an embed footer can be in characters\n\t\t */\n\t\tFOOTER: 2_048,\n\t\t/**\n\t\t * How long an embed author can be in characters\n\t\t */\n\t\tAUTHOR: 256,\n\t\t/**\n\t\t * How many fields an embed can have\n\t\t */\n\t\tFIELD_COUNT: 25,\n\t\t/**\n\t\t * Field specific limits\n\t\t */\n\t\tFIELDS: {\n\t\t\t/**\n\t\t\t * How long a field name can be in characters\n\t\t\t */\n\t\t\tNAME: 256,\n\t\t\t/**\n\t\t\t * How long a field value can be in characters\n\t\t\t */\n\t\t\tVALUE: 1_024,\n\t\t},\n\t},\n} as const;\n\n/**\n * Adds the given fields to an embed - mutating it\n *\n * @param embed - The embed to add fields to\n * @param fields - The fields to add\n */\nexport function addFields(embed: APIEmbed, ...fields: APIEmbedField[]): APIEmbed {\n\t(embed.fields ??= []).push(...fields);\n\treturn embed;\n}\n\n/**\n * Cuts off text after the given length - appending \"...\" at the end\n *\n * @param text - The text to cut off\n * @param total - The maximum length of the text\n */\nexport function ellipsis(text: string, total: number): string {\n\tif (text.length <= total) {\n\t\treturn text;\n\t}\n\n\tconst keep = total - 3;\n\tif (keep < 1) {\n\t\treturn text.slice(0, total);\n\t}\n\n\treturn `${text.slice(0, keep)}...`;\n}\n\n/**\n * Returns a fully truncated embed - safe to use with Discord's API - does not mutate the given embed\n *\n * @param embed - The embed to truncate\n */\nexport function truncateEmbed(embed: APIEmbed): APIEmbed {\n\t// @ts-expect-error - Because of the explicit undefined\n\treturn {\n\t\t...embed,\n\t\tdescription: embed.description ? ellipsis(embed.description, MESSAGE_LIMITS.EMBEDS.DESCRIPTION) : undefined,\n\t\ttitle: embed.title ? ellipsis(embed.title, MESSAGE_LIMITS.EMBEDS.TITLE) : undefined,\n\t\tauthor: embed.author\n\t\t\t? {\n\t\t\t\t\t...embed.author,\n\t\t\t\t\tname: ellipsis(embed.author.name, MESSAGE_LIMITS.EMBEDS.AUTHOR),\n\t\t\t\t}\n\t\t\t: undefined,\n\t\tfooter: embed.footer\n\t\t\t? {\n\t\t\t\t\t...embed.footer,\n\t\t\t\t\ttext: ellipsis(embed.footer.text, MESSAGE_LIMITS.EMBEDS.FOOTER),\n\t\t\t\t}\n\t\t\t: undefined,\n\t\tfields: embed.fields\n\t\t\t? embed.fields\n\t\t\t\t\t.map((field) => ({\n\t\t\t\t\t\tname: ellipsis(field.name, MESSAGE_LIMITS.EMBEDS.FIELDS.NAME),\n\t\t\t\t\t\tvalue: ellipsis(field.value, MESSAGE_LIMITS.EMBEDS.FIELDS.VALUE),\n\t\t\t\t\t}))\n\t\t\t\t\t.slice(0, MESSAGE_LIMITS.EMBEDS.FIELD_COUNT)\n\t\t\t: [],\n\t};\n}\n","import { ChannelType } from 'discord-api-types/v10';\n\nconst GUILD_TEXT_TYPES = [ChannelType.GuildText, ChannelType.GuildNews, ChannelType.GuildForum];\nconst THREAD_TYPES = [ChannelType.PublicThread, ChannelType.PrivateThread, ChannelType.AnnouncementThread];\n\n/**\n * The minimal channel shape `sortChannels` actually reads from -- callers aren't required to hand it a full\n * over-the-wire `APIChannel`, just anything with these fields (e.g. a dashboard's slimmer cached projection).\n */\nexport interface SortableChannelLike {\n\tid: string;\n\tparent_id?: string | null;\n\tposition?: number;\n\ttype: ChannelType;\n}\n\n/**\n * Sorts an array of text, category channels, and threads. Generic over `TChannel` so the input shape is\n * preserved on the way out instead of being widened/narrowed to a specific Discord API union.\n */\nexport function sortChannels<TChannel extends SortableChannelLike>(unsorted: TChannel[]): TChannel[] {\n\tconst filtered = unsorted.filter(\n\t\t(channel) =>\n\t\t\tGUILD_TEXT_TYPES.includes(channel.type) ||\n\t\t\tchannel.type === ChannelType.GuildCategory ||\n\t\t\tTHREAD_TYPES.includes(channel.type),\n\t);\n\n\t// Separate threads from other channels\n\tconst threads = filtered.filter((channel) => THREAD_TYPES.includes(channel.type));\n\tconst nonThreads = filtered.filter((channel) => !THREAD_TYPES.includes(channel.type));\n\n\t// Group the non-thread channels by their category - or \"top\" if they aren't in one\n\tconst grouped = Object.groupBy(nonThreads, (channel) => channel.parent_id ?? 'top');\n\n\t// Sort the top level channels - text channels are above category channels, otherwise use their position\n\tconst sortedTopLevel = grouped['top']\n\t\t?.filter((channel) => !channel.parent_id)\n\t\t.sort((a, b) => {\n\t\t\tif (a.type === ChannelType.GuildText && b.type === ChannelType.GuildCategory) {\n\t\t\t\treturn -1;\n\t\t\t}\n\n\t\t\tif (a.type === ChannelType.GuildCategory && b.type === ChannelType.GuildText) {\n\t\t\t\treturn 1;\n\t\t\t}\n\n\t\t\treturn (a.position ?? 0) - (b.position ?? 0);\n\t\t});\n\n\tconst channels: TChannel[] = [];\n\tfor (const top of sortedTopLevel ?? []) {\n\t\tchannels.push(top);\n\n\t\tif (top.type === ChannelType.GuildCategory) {\n\t\t\t// Add channels in this category\n\t\t\tconst categoryChannels = (grouped[top.id] ?? []).sort((a, b) => (a.position ?? 0) - (b.position ?? 0));\n\t\t\tchannels.push(...categoryChannels);\n\n\t\t\t// Add threads for each channel in the category\n\t\t\tfor (const channel of categoryChannels) {\n\t\t\t\tconst channelThreads = threads\n\t\t\t\t\t.filter((thread) => thread.parent_id === channel.id)\n\t\t\t\t\t.sort((a, b) => Number(BigInt(b.id) - BigInt(a.id)));\n\t\t\t\tchannels.push(...channelThreads);\n\t\t\t}\n\t\t} else {\n\t\t\t// Add threads for top-level channels\n\t\t\tconst channelThreads = threads\n\t\t\t\t.filter((thread) => thread.parent_id === top.id)\n\t\t\t\t.sort((a, b) => Number(BigInt(b.id) - BigInt(a.id)));\n\t\t\tchannels.push(...channelThreads);\n\t\t}\n\t}\n\n\treturn channels.length ? channels : filtered.sort((a, b) => (a.position ?? 0) - (b.position ?? 0));\n}\n"],"mappings":"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","names":[]}
|
package/dist/index.mjs
CHANGED
|
@@ -105,13 +105,13 @@ function sortChannels(unsorted) {
|
|
|
105
105
|
if (a.type === ChannelType.GuildCategory && b.type === ChannelType.GuildText) {
|
|
106
106
|
return 1;
|
|
107
107
|
}
|
|
108
|
-
return a.position - b.position;
|
|
108
|
+
return (a.position ?? 0) - (b.position ?? 0);
|
|
109
109
|
});
|
|
110
110
|
const channels = [];
|
|
111
111
|
for (const top of sortedTopLevel ?? []) {
|
|
112
112
|
channels.push(top);
|
|
113
113
|
if (top.type === ChannelType.GuildCategory) {
|
|
114
|
-
const categoryChannels = (grouped[top.id] ?? []).sort((a, b) => a.position - b.position);
|
|
114
|
+
const categoryChannels = (grouped[top.id] ?? []).sort((a, b) => (a.position ?? 0) - (b.position ?? 0));
|
|
115
115
|
channels.push(...categoryChannels);
|
|
116
116
|
for (const channel of categoryChannels) {
|
|
117
117
|
const channelThreads = threads.filter((thread) => thread.parent_id === channel.id).sort((a, b) => Number(BigInt(b.id) - BigInt(a.id)));
|
|
@@ -122,11 +122,7 @@ function sortChannels(unsorted) {
|
|
|
122
122
|
channels.push(...channelThreads);
|
|
123
123
|
}
|
|
124
124
|
}
|
|
125
|
-
return channels.length ? channels : filtered.sort((a, b) =>
|
|
126
|
-
const aPos = "position" in a ? a.position ?? 0 : 0;
|
|
127
|
-
const bPos = "position" in b ? b.position ?? 0 : 0;
|
|
128
|
-
return aPos - bPos;
|
|
129
|
-
});
|
|
125
|
+
return channels.length ? channels : filtered.sort((a, b) => (a.position ?? 0) - (b.position ?? 0));
|
|
130
126
|
}
|
|
131
127
|
__name(sortChannels, "sortChannels");
|
|
132
128
|
export {
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/embed.ts","../src/sortChannels.ts"],"sourcesContent":["import type { APIEmbed, APIEmbedField } from 'discord-api-types/v10';\n\n/**\n * Limits commonly encountered with Discord's API\n */\nexport const MESSAGE_LIMITS = {\n\t/**\n\t * How long a message can be in characters\n\t */\n\tCONTENT: 4_000,\n\t/**\n\t * How many embeds can be in a message\n\t */\n\tEMBED_COUNT: 10,\n\t/**\n\t * Embed specific limits\n\t */\n\tEMBEDS: {\n\t\t/**\n\t\t * How long an embed title can be in characters\n\t\t */\n\t\tTITLE: 256,\n\t\t/**\n\t\t * How long an embed description can be in characters\n\t\t */\n\t\tDESCRIPTION: 4_096,\n\t\t/**\n\t\t * How long an embed footer can be in characters\n\t\t */\n\t\tFOOTER: 2_048,\n\t\t/**\n\t\t * How long an embed author can be in characters\n\t\t */\n\t\tAUTHOR: 256,\n\t\t/**\n\t\t * How many fields an embed can have\n\t\t */\n\t\tFIELD_COUNT: 25,\n\t\t/**\n\t\t * Field specific limits\n\t\t */\n\t\tFIELDS: {\n\t\t\t/**\n\t\t\t * How long a field name can be in characters\n\t\t\t */\n\t\t\tNAME: 256,\n\t\t\t/**\n\t\t\t * How long a field value can be in characters\n\t\t\t */\n\t\t\tVALUE: 1_024,\n\t\t},\n\t},\n} as const;\n\n/**\n * Adds the given fields to an embed - mutating it\n *\n * @param embed - The embed to add fields to\n * @param fields - The fields to add\n */\nexport function addFields(embed: APIEmbed, ...fields: APIEmbedField[]): APIEmbed {\n\t(embed.fields ??= []).push(...fields);\n\treturn embed;\n}\n\n/**\n * Cuts off text after the given length - appending \"...\" at the end\n *\n * @param text - The text to cut off\n * @param total - The maximum length of the text\n */\nexport function ellipsis(text: string, total: number): string {\n\tif (text.length <= total) {\n\t\treturn text;\n\t}\n\n\tconst keep = total - 3;\n\tif (keep < 1) {\n\t\treturn text.slice(0, total);\n\t}\n\n\treturn `${text.slice(0, keep)}...`;\n}\n\n/**\n * Returns a fully truncated embed - safe to use with Discord's API - does not mutate the given embed\n *\n * @param embed - The embed to truncate\n */\nexport function truncateEmbed(embed: APIEmbed): APIEmbed {\n\t// @ts-expect-error - Because of the explicit undefined\n\treturn {\n\t\t...embed,\n\t\tdescription: embed.description ? ellipsis(embed.description, MESSAGE_LIMITS.EMBEDS.DESCRIPTION) : undefined,\n\t\ttitle: embed.title ? ellipsis(embed.title, MESSAGE_LIMITS.EMBEDS.TITLE) : undefined,\n\t\tauthor: embed.author\n\t\t\t? {\n\t\t\t\t\t...embed.author,\n\t\t\t\t\tname: ellipsis(embed.author.name, MESSAGE_LIMITS.EMBEDS.AUTHOR),\n\t\t\t\t}\n\t\t\t: undefined,\n\t\tfooter: embed.footer\n\t\t\t? {\n\t\t\t\t\t...embed.footer,\n\t\t\t\t\ttext: ellipsis(embed.footer.text, MESSAGE_LIMITS.EMBEDS.FOOTER),\n\t\t\t\t}\n\t\t\t: undefined,\n\t\tfields: embed.fields\n\t\t\t? embed.fields\n\t\t\t\t\t.map((field) => ({\n\t\t\t\t\t\tname: ellipsis(field.name, MESSAGE_LIMITS.EMBEDS.FIELDS.NAME),\n\t\t\t\t\t\tvalue: ellipsis(field.value, MESSAGE_LIMITS.EMBEDS.FIELDS.VALUE),\n\t\t\t\t\t}))\n\t\t\t\t\t.slice(0, MESSAGE_LIMITS.EMBEDS.FIELD_COUNT)\n\t\t\t: [],\n\t};\n}\n","import
|
|
1
|
+
{"version":3,"sources":["../src/embed.ts","../src/sortChannels.ts"],"sourcesContent":["import type { APIEmbed, APIEmbedField } from 'discord-api-types/v10';\n\n/**\n * Limits commonly encountered with Discord's API\n */\nexport const MESSAGE_LIMITS = {\n\t/**\n\t * How long a message can be in characters\n\t */\n\tCONTENT: 4_000,\n\t/**\n\t * How many embeds can be in a message\n\t */\n\tEMBED_COUNT: 10,\n\t/**\n\t * Embed specific limits\n\t */\n\tEMBEDS: {\n\t\t/**\n\t\t * How long an embed title can be in characters\n\t\t */\n\t\tTITLE: 256,\n\t\t/**\n\t\t * How long an embed description can be in characters\n\t\t */\n\t\tDESCRIPTION: 4_096,\n\t\t/**\n\t\t * How long an embed footer can be in characters\n\t\t */\n\t\tFOOTER: 2_048,\n\t\t/**\n\t\t * How long an embed author can be in characters\n\t\t */\n\t\tAUTHOR: 256,\n\t\t/**\n\t\t * How many fields an embed can have\n\t\t */\n\t\tFIELD_COUNT: 25,\n\t\t/**\n\t\t * Field specific limits\n\t\t */\n\t\tFIELDS: {\n\t\t\t/**\n\t\t\t * How long a field name can be in characters\n\t\t\t */\n\t\t\tNAME: 256,\n\t\t\t/**\n\t\t\t * How long a field value can be in characters\n\t\t\t */\n\t\t\tVALUE: 1_024,\n\t\t},\n\t},\n} as const;\n\n/**\n * Adds the given fields to an embed - mutating it\n *\n * @param embed - The embed to add fields to\n * @param fields - The fields to add\n */\nexport function addFields(embed: APIEmbed, ...fields: APIEmbedField[]): APIEmbed {\n\t(embed.fields ??= []).push(...fields);\n\treturn embed;\n}\n\n/**\n * Cuts off text after the given length - appending \"...\" at the end\n *\n * @param text - The text to cut off\n * @param total - The maximum length of the text\n */\nexport function ellipsis(text: string, total: number): string {\n\tif (text.length <= total) {\n\t\treturn text;\n\t}\n\n\tconst keep = total - 3;\n\tif (keep < 1) {\n\t\treturn text.slice(0, total);\n\t}\n\n\treturn `${text.slice(0, keep)}...`;\n}\n\n/**\n * Returns a fully truncated embed - safe to use with Discord's API - does not mutate the given embed\n *\n * @param embed - The embed to truncate\n */\nexport function truncateEmbed(embed: APIEmbed): APIEmbed {\n\t// @ts-expect-error - Because of the explicit undefined\n\treturn {\n\t\t...embed,\n\t\tdescription: embed.description ? ellipsis(embed.description, MESSAGE_LIMITS.EMBEDS.DESCRIPTION) : undefined,\n\t\ttitle: embed.title ? ellipsis(embed.title, MESSAGE_LIMITS.EMBEDS.TITLE) : undefined,\n\t\tauthor: embed.author\n\t\t\t? {\n\t\t\t\t\t...embed.author,\n\t\t\t\t\tname: ellipsis(embed.author.name, MESSAGE_LIMITS.EMBEDS.AUTHOR),\n\t\t\t\t}\n\t\t\t: undefined,\n\t\tfooter: embed.footer\n\t\t\t? {\n\t\t\t\t\t...embed.footer,\n\t\t\t\t\ttext: ellipsis(embed.footer.text, MESSAGE_LIMITS.EMBEDS.FOOTER),\n\t\t\t\t}\n\t\t\t: undefined,\n\t\tfields: embed.fields\n\t\t\t? embed.fields\n\t\t\t\t\t.map((field) => ({\n\t\t\t\t\t\tname: ellipsis(field.name, MESSAGE_LIMITS.EMBEDS.FIELDS.NAME),\n\t\t\t\t\t\tvalue: ellipsis(field.value, MESSAGE_LIMITS.EMBEDS.FIELDS.VALUE),\n\t\t\t\t\t}))\n\t\t\t\t\t.slice(0, MESSAGE_LIMITS.EMBEDS.FIELD_COUNT)\n\t\t\t: [],\n\t};\n}\n","import { ChannelType } from 'discord-api-types/v10';\n\nconst GUILD_TEXT_TYPES = [ChannelType.GuildText, ChannelType.GuildNews, ChannelType.GuildForum];\nconst THREAD_TYPES = [ChannelType.PublicThread, ChannelType.PrivateThread, ChannelType.AnnouncementThread];\n\n/**\n * The minimal channel shape `sortChannels` actually reads from -- callers aren't required to hand it a full\n * over-the-wire `APIChannel`, just anything with these fields (e.g. a dashboard's slimmer cached projection).\n */\nexport interface SortableChannelLike {\n\tid: string;\n\tparent_id?: string | null;\n\tposition?: number;\n\ttype: ChannelType;\n}\n\n/**\n * Sorts an array of text, category channels, and threads. Generic over `TChannel` so the input shape is\n * preserved on the way out instead of being widened/narrowed to a specific Discord API union.\n */\nexport function sortChannels<TChannel extends SortableChannelLike>(unsorted: TChannel[]): TChannel[] {\n\tconst filtered = unsorted.filter(\n\t\t(channel) =>\n\t\t\tGUILD_TEXT_TYPES.includes(channel.type) ||\n\t\t\tchannel.type === ChannelType.GuildCategory ||\n\t\t\tTHREAD_TYPES.includes(channel.type),\n\t);\n\n\t// Separate threads from other channels\n\tconst threads = filtered.filter((channel) => THREAD_TYPES.includes(channel.type));\n\tconst nonThreads = filtered.filter((channel) => !THREAD_TYPES.includes(channel.type));\n\n\t// Group the non-thread channels by their category - or \"top\" if they aren't in one\n\tconst grouped = Object.groupBy(nonThreads, (channel) => channel.parent_id ?? 'top');\n\n\t// Sort the top level channels - text channels are above category channels, otherwise use their position\n\tconst sortedTopLevel = grouped['top']\n\t\t?.filter((channel) => !channel.parent_id)\n\t\t.sort((a, b) => {\n\t\t\tif (a.type === ChannelType.GuildText && b.type === ChannelType.GuildCategory) {\n\t\t\t\treturn -1;\n\t\t\t}\n\n\t\t\tif (a.type === ChannelType.GuildCategory && b.type === ChannelType.GuildText) {\n\t\t\t\treturn 1;\n\t\t\t}\n\n\t\t\treturn (a.position ?? 0) - (b.position ?? 0);\n\t\t});\n\n\tconst channels: TChannel[] = [];\n\tfor (const top of sortedTopLevel ?? []) {\n\t\tchannels.push(top);\n\n\t\tif (top.type === ChannelType.GuildCategory) {\n\t\t\t// Add channels in this category\n\t\t\tconst categoryChannels = (grouped[top.id] ?? []).sort((a, b) => (a.position ?? 0) - (b.position ?? 0));\n\t\t\tchannels.push(...categoryChannels);\n\n\t\t\t// Add threads for each channel in the category\n\t\t\tfor (const channel of categoryChannels) {\n\t\t\t\tconst channelThreads = threads\n\t\t\t\t\t.filter((thread) => thread.parent_id === channel.id)\n\t\t\t\t\t.sort((a, b) => Number(BigInt(b.id) - BigInt(a.id)));\n\t\t\t\tchannels.push(...channelThreads);\n\t\t\t}\n\t\t} else {\n\t\t\t// Add threads for top-level channels\n\t\t\tconst channelThreads = threads\n\t\t\t\t.filter((thread) => thread.parent_id === top.id)\n\t\t\t\t.sort((a, b) => Number(BigInt(b.id) - BigInt(a.id)));\n\t\t\tchannels.push(...channelThreads);\n\t\t}\n\t}\n\n\treturn channels.length ? channels : filtered.sort((a, b) => (a.position ?? 0) - (b.position ?? 0));\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { ChannelType } from 'discord-api-types/v10';
|
|
2
|
+
/**
|
|
3
|
+
* The minimal channel shape `sortChannels` actually reads from -- callers aren't required to hand it a full
|
|
4
|
+
* over-the-wire `APIChannel`, just anything with these fields (e.g. a dashboard's slimmer cached projection).
|
|
5
|
+
*/
|
|
6
|
+
export interface SortableChannelLike {
|
|
7
|
+
id: string;
|
|
8
|
+
parent_id?: string | null;
|
|
9
|
+
position?: number;
|
|
10
|
+
type: ChannelType;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Sorts an array of text, category channels, and threads. Generic over `TChannel` so the input shape is
|
|
14
|
+
* preserved on the way out instead of being widened/narrowed to a specific Discord API union.
|
|
15
|
+
*/
|
|
16
|
+
export declare function sortChannels<TChannel extends SortableChannelLike>(unsorted: TChannel[]): TChannel[];
|
|
17
|
+
//# sourceMappingURL=sortChannels.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sortChannels.d.ts","sourceRoot":"","sources":["../src/sortChannels.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAKpD;;;GAGG;AACH,MAAM,WAAW,mBAAmB;IACnC,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,WAAW,CAAC;CAClB;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,QAAQ,SAAS,mBAAmB,EAAE,QAAQ,EAAE,QAAQ,EAAE,GAAG,QAAQ,EAAE,CAwDnG"}
|