diff --git a/src/registry.js b/src/registry.js index 8a185065e..679e54f15 100644 --- a/src/registry.js +++ b/src/registry.js @@ -352,6 +352,7 @@ class CommandoRegistry { * @param {boolean} [types.categoryChannel=true] - Whether to register the built-in category-channel type * @param {boolean} [types.message=true] - Whether to register the built-in message type * @param {boolean} [types.customEmoji=true] - Whether to register the built-in custom-emoji type + * @param {boolean} [types.duration=true] - Whether to register the built-in duration type * @param {boolean} [types.command=true] - Whether to register the built-in command type * @param {boolean} [types.group=true] - Whether to register the built-in group type * @return {CommandoRegistry} @@ -361,7 +362,7 @@ class CommandoRegistry { string: true, integer: true, float: true, boolean: true, user: true, member: true, role: true, channel: true, textChannel: true, voiceChannel: true, categoryChannel: true, message: true, customEmoji: true, - command: true, group: true, ...types + duration: true, command: true, group: true, ...types }; if(types.string) this.registerType(require('./types/string')); if(types.integer) this.registerType(require('./types/integer')); @@ -376,6 +377,7 @@ class CommandoRegistry { if(types.categoryChannel) this.registerType(require('./types/category-channel')); if(types.message) this.registerType(require('./types/message')); if(types.customEmoji) this.registerType(require('./types/custom-emoji')); + if(types.duration) this.registerType(require('./types/duration')); if(types.command) this.registerType(require('./types/command')); if(types.group) this.registerType(require('./types/group')); return this; diff --git a/src/types/duration.js b/src/types/duration.js new file mode 100644 index 000000000..785b7d770 --- /dev/null +++ b/src/types/duration.js @@ -0,0 +1,70 @@ +const ArgumentType = require('./base'); + +class DurationArgumentType extends ArgumentType { + // This.duration::Milliseconds + constructor(client) { + super(client, 'duration'); + this.timeIds = new Set(['mo', 'w', 'd', 'h', 'm', 's', 'ms']); + this.duration = 0; + } + + // Confirms match before continuing. + // Checks if matched number is an int. + // Checks if matched string is in expected set. + validate(value) { + const MATCHES_ALL = value.match(/(\d+)\s*([A-Za-z]+)/g); + + for(let i = 0; i < MATCHES_ALL.length; i++) { + const tempNum = MATCHES_ALL[i].match(/(\d+)/g); + const tempStr = MATCHES_ALL[i].match(/([A-Za-z]+)/g); + if(!tempNum || (tempNum.length !== 1)) return false; + if(!tempStr || (tempStr.length !== 1)) return false; + if(!Number.isInteger(parseInt(tempNum[0]))) return false; + if(!this.timeIds.has(tempStr[0])) return false; + } + return true; + } + + // Separate each time group (Xmo, Yw, Zd, ext.) + // Combine to a single time value (in milliseconds) + // Return time value unless null + parse(value) { + const MATCHES_ALL = value.match(/(\d+)\s*([A-Za-z]+)/g); + let totalTime = 0; + MATCHES_ALL.forEach(dur => { + const tempNum = parseInt(dur.match(/(\d+)/g)[0]); + const tempStr = dur.match(/([A-Za-z]+)/g)[0]; + if(isNaN(tempNum)) totalTime = null; + else totalTime += tempNum * determineTimeType(tempStr); + }); + if(totalTime !== null) { + this.duration = totalTime; + return this.duration; + } else { + return null; + } + } +} + +function determineTimeType(str) { + switch(str) { + case 'mo': + return 30 * 24 * 60 * 60 * 1000; + case 'w': + return 7 * 24 * 60 * 60 * 1000; + case 'd': + return 24 * 60 * 60 * 1000; + case 'h': + return 60 * 60 * 1000; + case 'm': + return 60 * 1000; + case 's': + return 1000; + case 'ms': + return 1; + default: + return null; + } +} + +module.exports = DurationArgumentType;