Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 64 additions & 24 deletions lib/discord.js
Original file line number Diff line number Diff line change
Expand Up @@ -257,10 +257,61 @@ async function sendDiscordMessage(channelId, text, options = {}) {
// Convert Slack markdown to Discord markdown
let discordText = text.replace(/<(https?:\/\/[^|>]+)\|([^>]+)>/g, '[$2]($1)');

// Convert common Slack emoji codes to Unicode emoji for Discord
// Use a single regex-based replacement for better performance with large messages
const emojiMap = {
':notes:': '🎵',
':lock:': '🔒',
':star:': '⭐',
':stopwatch:': '⏱️',
':cricket:': '🦗',
':musical_note:': '🎵',
':headphones:': '🎧',
':speaker:': '🔊',
':mute:': '🔇',
':loud_sound:': '🔊',
':sound:': '🔉',
':fire:': '🔥',
':thumbsup:': '👍',
':thumbsdown:': '👎',
':clap:': '👏',
':party_popper:': '🎉',
':tada:': '🎉',
':warning:': '⚠️',
':x:': '❌',
':white_check_mark:': '✅',
':checkmark:': '✅',
':question:': '❓',
':exclamation:': '❗',
':sparkles:': '✨'
};
Comment on lines +262 to +287
Copy link

Copilot AI Feb 15, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The emojiMap is being recreated on every function call. For better performance, move this map to module-level scope (outside the function, similar to how trackMessages is declared at the top). This will eliminate the overhead of recreating the same object every time a Discord message is sent, which can be significant when sending multiple messages in quick succession (like during bulk operations).

Copilot uses AI. Check for mistakes.
discordText = discordText.replace(/:[a-z_]+:/g, (match) => emojiMap[match] || match);
Copy link

Copilot AI Feb 15, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The regex pattern /:[a-z_]+:/g only matches emoji codes containing lowercase letters and underscores. This won't match emoji codes with numbers (e.g., :100:, :1234:), uppercase letters, or other special characters that might be used in Slack emoji codes. Consider using a more inclusive pattern like /:[a-z0-9_]+:/gi to handle these cases, or document this as an intentional limitation if only lowercase letter-based emoji codes are expected.

Suggested change
discordText = discordText.replace(/:[a-z_]+:/g, (match) => emojiMap[match] || match);
discordText = discordText.replace(/:[a-z0-9_]+:/gi, (match) => emojiMap[match] || match);

Copilot uses AI. Check for mistakes.

// Discord has a 2000 char limit, split into chunks if needed
const maxLength = 1900; // Leave some margin
// Use 1800 as max to have buffer for edge cases with Unicode
const maxLength = 1800;
let messages = [];

// Helper function to send a chunk safely (splitting further if needed)
const sendChunkSafe = async (chunk) => {
if (chunk.length <= maxLength) {
const message = await channel.send(chunk);
messages.push(message);
return;
}
// Chunk is still too long, split it
let remaining = chunk;
while (remaining.length > 0) {
const piece = remaining.substring(0, maxLength);
const message = await channel.send(piece);
messages.push(message);
remaining = remaining.substring(maxLength);
if (remaining.length > 0) {
await new Promise(resolve => setTimeout(resolve, 300));
}
}
};
Comment on lines +260 to +313
Copy link

Copilot AI Feb 15, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new emoji conversion and message chunking logic lacks test coverage. Consider adding tests to verify: 1) emoji codes are correctly converted to Unicode emoji, 2) messages over 1800 characters are properly split into multiple chunks without data loss, 3) the sendChunkSafe helper correctly handles messages that need recursive splitting, 4) edge cases like exact-length lines (line.length === maxLength) are handled properly. The existing test/discord.test.mjs file contains patterns for Discord logic testing that can be followed.

Copilot uses AI. Check for mistakes.

if (discordText.length <= maxLength) {
// Single message
const message = await channel.send(discordText);
Expand All @@ -274,44 +325,33 @@ async function sendDiscordMessage(channelId, text, options = {}) {

for (let i = 0; i < lines.length; i++) {
const line = lines[i];
const potentialLength = currentChunk.length + line.length + 1; // +1 for newline

if ((currentChunk + line + '\n').length > maxLength) {
// Send current chunk
if (potentialLength > maxLength) {
// Send current chunk if it has content
if (currentChunk.trim().length > 0) {
const message = await channel.send(currentChunk);
messages.push(message);
await sendChunkSafe(currentChunk);
chunkCount++;
currentChunk = '';
// Small delay between messages
await new Promise(resolve => setTimeout(resolve, 500));
await new Promise(resolve => setTimeout(resolve, 300));
}

// Handle oversized single lines by splitting them
if (line.length > maxLength) {
// Split the line into smaller chunks
let remainingLine = line;
while (remainingLine.length > 0) {
const chunk = remainingLine.substring(0, maxLength);
const message = await channel.send(chunk);
messages.push(message);
chunkCount++;
remainingLine = remainingLine.substring(maxLength);
if (remainingLine.length > 0) {
await new Promise(resolve => setTimeout(resolve, 500));
}
}
// Skip adding to currentChunk since we already sent it
// Handle oversized or exact-length lines (>= to avoid adding newline that exceeds limit)
if (line.length >= maxLength) {
await sendChunkSafe(line);
chunkCount++;
await new Promise(resolve => setTimeout(resolve, 300));
continue;
}
}

currentChunk += line + '\n';
}

// Send remaining chunk
// Send remaining chunk (with safety check)
if (currentChunk.trim().length > 0) {
const message = await channel.send(currentChunk);
messages.push(message);
await sendChunkSafe(currentChunk);
chunkCount++;
}

Expand Down
46 changes: 23 additions & 23 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading