Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Util.splitMessage with char: RegExp will include regular expression in output #7674

Closed
dshepsis opened this issue Mar 16, 2022 · 2 comments · Fixed by #7780
Closed

Util.splitMessage with char: RegExp will include regular expression in output #7674

dshepsis opened this issue Mar 16, 2022 · 2 comments · Fixed by #7780

Comments

@dshepsis
Copy link

Which package is this bug report for?

discord.js

Issue description

To reproduce, run the following or similar:

splitMessage('aaa-bbb-ccc--ddd-eee', { maxLength: 10, char: /-+/})

The output will be something like:

Array(3) [ "aaa/-+/bbb", "ccc/-+/ddd", "eee" ]

As you can see, the toString() form of the RegExp was included in some of the output strings where it matched part of the input string.

The expected output would be:

Array(3) [ "aaa-bbb", "ccc--ddd", "eee" ]

This seems to be caused by this line: https://github.com/discordjs/discord.js/blob/main/packages/discord.js/src/util/Util.js#L95

      msg += (msg && msg !== prepend ? char : '') + chunk;

This line works fine if char is a string, but if char is a RegExp, it really should insert the exact string that char matched in that location, rather than char itself. Fixing this will probably require using String#matchAll/RegExp.exec and a different algorithm, though I'm not sure what that would bee off the top of my head.

Code sample

Util.splitMessage('aaa-bbb-ccc-ddd-eee', { maxLength: 10, char: /-+/})

Package version

13.6.0

Node.js version

v16.13.1

Operating system

Windows

Priority this issue should have

Medium (should be fixed soon)

Which partials do you have configured?

Not applicable (subpackage bug)

Which gateway intents are you subscribing to?

Not applicable (subpackage bug)

I have tested this issue on a development release

No response

@dshepsis
Copy link
Author

Apologies for not creating a formal PR, but I did create this function for my own use-case, which I think may be helpful in creating a fix for this issue. It only supports a single regex, as opposed to an array of them, but I don't think this would be too difficult to change by using a RegExp.exec loop instead of sting.matchAll.

/**
 * A function for splitting a string into fixed-length parts. Designed as a
 * workaround to an issue in the discord.js Util.splitMessage function
 * https://github.com/discordjs/discord.js/issues/7674
 * @param {string} text The string to split into multiple messages, each of
 * which will be no longer than maxLength
 * @param {object} [options]
 * @param {number} [options.maxLength] The maximum number of characters in each
 * string in the returned array
 * @param {RegExp} [options.regex] A global regex which matches the delimeters on
 * which to split text when needed to keep each part within maxLength
 * @param {string} [options.prepend] A string to add before each part iff
 * text is split into multiple parts
 * @param {string} [options.append] A string to add after each part iff text
 * is split into multiple parts
 * @returns {string[]} An array of strings which are substrings of text, split
 * using options.regex, combined such that each part is as long as possible
 * while not exceeding options.maxLength.
 */
export function splitMessageRegex(text, {
	maxLength = 2_000,
	regex = /\n/g,
	prepend = '',
	append = '',
} = {}) {
	if (text.length <= maxLength) return [text];
	const parts = [];
	let curPart = prepend;
	let chunkStartIndex = 0;

	let prevDelim = '';

	function addChunk(chunkEndIndex, nextDelim) {
		const nextChunk = text.substring(chunkStartIndex, chunkEndIndex);
		const nextChunkLen = nextChunk.length;

		// If a single part would exceed the length limit by itself, throw an error:
		if (prepend.length + nextChunkLen + append.length > maxLength) {
			throw new RangeError('SPLIT_MAX_LEN');
		}

		// The length of the current part if the next chunk were added to it:
		const lengthWithChunk = (
			curPart.length + prevDelim.length + nextChunkLen + append.length
		);

		// If adding the next chunk to the current part would cause it to exceed
		// the maximum length, push the current part and reset it for next time:
		if (lengthWithChunk > maxLength) {
			parts.push(curPart + append);
			curPart = prepend + nextChunk;
		}
		else {
			curPart += prevDelim + nextChunk;
		}
		prevDelim = nextDelim;
		chunkStartIndex = chunkEndIndex + prevDelim.length;
	}

	for (const match of text.matchAll(regex)) {
		addChunk(match.index, match[0]);
	}
	addChunk(text.length - 1, '');
	parts.push(curPart + append);
	return parts;
}

dshepsis added a commit to dshepsis/Autoride that referenced this issue Mar 24, 2022
Finished the switch from Keyv to guild-config JSON files.
More-or-less finished the implementation of URL monitoring and URL
detection in embed-message.
Added Replyable module to help with some util functions that could be used for
both interactions and normal message replies.
Added splitMessageRegex module, which is a substitue for
DiscordJS/util.splitMessage which has a bug: discordjs/discord.js#7674
Added paginatedReply module, which is a clean way to send information
that may not fit in a single message. This is combined with
splitMessageRegex for a relatively easy way to send unlimited-length
messages (such as with /http-monitor list) without flooding a guild
channel or bashing Discord's API.
@Jiralite
Copy link
Member

Thank you for the bug report.

We're moving in the direction of removing this method. discord.js doesn't even use this method anywhere, despite being a utility method in the library. Taking a string and splitting it into a specified chunk (or chunks) is really what the developer should be doing. This method used to be an option whilst sending a message which was eventually removed in version 13 (see #5918) and now for version 14, we will be completely removing it.

@kyranet kyranet added the has PR label Apr 12, 2022
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Jun 29, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants