diff --git a/src/plugins/inputs/mode.js b/src/plugins/inputs/mode.js index 074629ef..1503b54b 100644 --- a/src/plugins/inputs/mode.js +++ b/src/plugins/inputs/mode.js @@ -23,7 +23,9 @@ exports.input = function ({irc, nick}, chan, cmd, args) { return; } - if (args.length === 0) { + const target = args.filter((arg) => arg !== ""); + + if (target.length === 0) { chan.pushMessage( this, new Msg({ @@ -44,9 +46,13 @@ exports.input = function ({irc, nick}, chan, cmd, args) { devoice: "-v", }[cmd]; - args.forEach(function (target) { - irc.raw("MODE", chan.name, mode, target); - }); + const limit = parseInt(irc.network.supports("MODES")) || target.length; + + for (let i = 0; i < target.length; i += limit) { + const targets = target.slice(i, i + limit); + const amode = `${mode[0]}${mode[1].repeat(targets.length)}`; + irc.raw("MODE", chan.name, amode, ...targets); + } return; } diff --git a/test/commands/mode.js b/test/commands/mode.js index ab27a9a4..a6ea9bad 100644 --- a/test/commands/mode.js +++ b/test/commands/mode.js @@ -17,15 +17,38 @@ describe("Commands", function () { }); const testableNetwork = { + firstCommand: null, lastCommand: null, nick: "xPaw", irc: { + network: { + supports(type) { + if (type.toUpperCase() === "MODES") { + return "4"; + } + }, + }, raw(...args) { + testableNetwork.firstCommand = testableNetwork.lastCommand; testableNetwork.lastCommand = args.join(" "); }, }, }; + const testableNetworkNoSupports = Object.assign({}, testableNetwork, { + irc: { + network: { + supports() { + return null; + }, + }, + raw(...args) { + testableNetworkNoSupports.firstCommand = testableNetworkNoSupports.lastCommand; + testableNetworkNoSupports.lastCommand = args.join(" "); + }, + }, + }); + it("should not mess with the given target", function () { const test = function (expected, args) { ModeCommand.input(testableNetwork, channel, "mode", Array.from(args)); @@ -81,10 +104,34 @@ describe("Commands", function () { ModeCommand.input(testableNetwork, channel, "devoice", ["xPaw"]); expect(testableNetwork.lastCommand).to.equal("MODE #thelounge -v xPaw"); + }); - // Multiple arguments are supported, sent as separate commands - ModeCommand.input(testableNetwork, channel, "devoice", ["xPaw", "Max-P"]); - expect(testableNetwork.lastCommand).to.equal("MODE #thelounge -v Max-P"); + it("should use ISUPPORT MODES on shorthand commands", function () { + ModeCommand.input(testableNetwork, channel, "voice", ["xPaw", "Max-P"]); + expect(testableNetwork.lastCommand).to.equal("MODE #thelounge +vv xPaw Max-P"); + + // since the limit for modes on tests is 4, it should send two commands + ModeCommand.input(testableNetwork, channel, "devoice", [ + "xPaw", + "Max-P", + "hey", + "idk", + "thelounge", + ]); + expect(testableNetwork.firstCommand).to.equal( + "MODE #thelounge -vvvv xPaw Max-P hey idk" + ); + expect(testableNetwork.lastCommand).to.equal("MODE #thelounge -v thelounge"); + }); + + it("should fallback to all modes at once for shorthand commands", function () { + ModeCommand.input(testableNetworkNoSupports, channel, "voice", ["xPaw"]); + expect(testableNetworkNoSupports.lastCommand).to.equal("MODE #thelounge +v xPaw"); + + ModeCommand.input(testableNetworkNoSupports, channel, "devoice", ["xPaw", "Max-P"]); + expect(testableNetworkNoSupports.lastCommand).to.equal( + "MODE #thelounge -vv xPaw Max-P" + ); }); }); });