1. 1 : const Resolver = require("./Resolver");
  2. 2 :
  3. 3 : /* eslint-disable no-throw-literal, class-methods-use-this */
  4. 4 : /**
  5. 5 : * The resolver that is used for arguments.
  6. 6 : * @extends Resolver
  7. 7 : */
  8. 8 : class ArgResolver extends Resolver {
  9. 9 :
  10. 10 : /**
  11. 11 : * Resolves a message
  12. 12 : * @param {string} arg This arg
  13. 13 : * @param {Object} currentUsage This current usage
  14. 14 : * @param {number} possible This possible usage id
  15. 15 : * @param {boolean} repeat If it is a looping/repeating arg
  16. 16 : * @param {Message} msg The message that triggered the command
  17. 17 : * @returns {external:Message}
  18. 18 : */
  19. 19 : message(...args) {
  20. 20 : return this.msg(...args);
  21. 21 : }
  22. 22 :
  23. 23 : /**
  24. 24 : * Resolves a message
  25. 25 : * @param {string} arg This arg
  26. 26 : * @param {Object} currentUsage This current usage
  27. 27 : * @param {number} possible This possible usage id
  28. 28 : * @param {boolean} repeat If it is a looping/repeating arg
  29. 29 : * @param {Message} msg The message that triggered the command
  30. 30 : * @returns {external:Message}
  31. 31 : */
  32. 32 : async msg(arg, currentUsage, possible, repeat, msg) {
  33. 33 : const message = await super.msg(arg, msg.channel);
  34. 34 : if (message) return message;
  35. 35 : if (currentUsage.type === "optional" && !repeat) return null;
  36. 36 : throw `${currentUsage.possibles[possible].name} must be a valid message id.`;
  37. 37 : }
  38. 38 :
  39. 39 : messages(...args) {
  40. 40 : return this.msgs(...args);
  41. 41 : }
  42. 42 :
  43. 43 : async msgs(arg, currentUsage, possible, repeat, msg) {
  44. 44 : const messages = await super.messages(arg, msg.channel, currentUsage.possibles[possible].min);
  45. 45 : if (messages.size > 0) return messages;
  46. 46 : if (currentUsage.type === "optional" && !repeat) return null;
  47. 47 : throw `${currentUsage.possibles[possible].name} must be a valid message id.`;
  48. 48 : }
  49. 49 :
  50. 50 : /**
  51. 51 : * Resolves a user
  52. 52 : * @param {string} arg This arg
  53. 53 : * @param {Object} currentUsage This current usage
  54. 54 : * @param {number} possible This possible usage id
  55. 55 : * @param {boolean} repeat If it is a looping/repeating arg
  56. 56 : * @returns {external:User}
  57. 57 : */
  58. 58 : mention(...args) {
  59. 59 : return this.user(...args);
  60. 60 : }
  61. 61 :
  62. 62 : /**
  63. 63 : * Resolves a user
  64. 64 : * @param {string} arg This arg
  65. 65 : * @param {Object} currentUsage This current usage
  66. 66 : * @param {number} possible This possible usage id
  67. 67 : * @param {boolean} repeat If it is a looping/repeating arg
  68. 68 : * @returns {external:User}
  69. 69 : */
  70. 70 : async user(arg, currentUsage, possible, repeat) {
  71. 71 : const user = await super.user(arg);
  72. 72 : if (user) return user;
  73. 73 : if (currentUsage.type === "optional" && !repeat) return null;
  74. 74 : throw `${currentUsage.possibles[possible].name} must be a mention or valid user id.`;
  75. 75 : }
  76. 76 :
  77. 77 : /**
  78. 78 : * Resolves a member
  79. 79 : * @param {string} arg This arg
  80. 80 : * @param {Object} currentUsage This current usage
  81. 81 : * @param {number} possible This possible usage id
  82. 82 : * @param {boolean} repeat If it is a looping/repeating arg
  83. 83 : * @param {Message} msg The message that triggered the command
  84. 84 : * @returns {external:GuildMember}
  85. 85 : */
  86. 86 : async member(arg, currentUsage, possible, repeat, msg) {
  87. 87 : const member = await super.member(arg, msg.guild);
  88. 88 : if (member) return member;
  89. 89 : if (currentUsage.type === "optional" && !repeat) return null;
  90. 90 : throw `${currentUsage.possibles[possible].name} must be a mention or valid user id.`;
  91. 91 : }
  92. 92 :
  93. 93 : /**
  94. 94 : * Resolves a channel
  95. 95 : * @param {string} arg This arg
  96. 96 : * @param {Object} currentUsage This current usage
  97. 97 : * @param {number} possible This possible usage id
  98. 98 : * @param {boolean} repeat If it is a looping/repeating arg
  99. 99 : * @returns {external:Channel}
  100. 100 : */
  101. 101 : async channel(arg, currentUsage, possible, repeat) {
  102. 102 : const channel = await super.channel(arg);
  103. 103 : if (channel) return channel;
  104. 104 : if (currentUsage.type === "optional" && !repeat) return null;
  105. 105 : throw `${currentUsage.possibles[possible].name} must be a channel tag or valid channel id.`;
  106. 106 : }
  107. 107 :
  108. 108 : /**
  109. 109 : * Resolves a guild
  110. 110 : * @param {string} arg This arg
  111. 111 : * @param {Object} currentUsage This current usage
  112. 112 : * @param {number} possible This possible usage id
  113. 113 : * @param {boolean} repeat If it is a looping/repeating arg
  114. 114 : * @returns {external:Guild}
  115. 115 : */
  116. 116 : async guild(arg, currentUsage, possible, repeat) {
  117. 117 : const guild = await super.guild(arg);
  118. 118 : if (guild) return guild;
  119. 119 : if (currentUsage.type === "optional" && !repeat) return null;
  120. 120 : throw `${currentUsage.possibles[possible].name} must be a valid guild id.`;
  121. 121 : }
  122. 122 :
  123. 123 : /**
  124. 124 : * Resolves a role
  125. 125 : * @param {string} arg This arg
  126. 126 : * @param {Object} currentUsage This current usage
  127. 127 : * @param {number} possible This possible usage id
  128. 128 : * @param {boolean} repeat If it is a looping/repeating arg
  129. 129 : * @param {Message} msg The message that triggered the command
  130. 130 : * @returns {external:Role}
  131. 131 : */
  132. 132 : async role(arg, currentUsage, possible, repeat, msg) {
  133. 133 : const role = await super.role(arg, msg.guild);
  134. 134 : if (role) return role;
  135. 135 : if (currentUsage.type === "optional" && !repeat) return null;
  136. 136 : throw `${currentUsage.possibles[possible].name} must be a role mention or role id.`;
  137. 137 : }
  138. 138 :
  139. 139 : /**
  140. 140 : * Resolves a literal
  141. 141 : * @param {string} arg This arg
  142. 142 : * @param {Object} currentUsage This current usage
  143. 143 : * @param {number} possible This possible usage id
  144. 144 : * @param {boolean} repeat If it is a looping/repeating arg
  145. 145 : * @returns {string}
  146. 146 : */
  147. 147 : async literal(arg, currentUsage, possible, repeat) {
  148. 148 : if (arg.toLowerCase() === currentUsage.possibles[possible].name.toLowerCase()) return arg.toLowerCase();
  149. 149 : if (currentUsage.type === "optional" && !repeat) return null;
  150. 150 : throw [
  151. 151 : `Your option did not literally match the only possibility: (${currentUsage.possibles.map(poss => poss.name).join(", ")})`,
  152. 152 : "This is likely caused by a mistake in the usage string.",
  153. 153 : ].join("\n");
  154. 154 : }
  155. 155 :
  156. 156 : /**
  157. 157 : * Resolves a boolean
  158. 158 : * @param {string} arg This arg
  159. 159 : * @param {Object} currentUsage This current usage
  160. 160 : * @param {number} possible This possible usage id
  161. 161 : * @param {boolean} repeat If it is a looping/repeating arg
  162. 162 : * @returns {boolean}
  163. 163 : */
  164. 164 : bool(...args) {
  165. 165 : return this.boolean(...args);
  166. 166 : }
  167. 167 :
  168. 168 : /**
  169. 169 : * Resolves a boolean
  170. 170 : * @param {string} arg This arg
  171. 171 : * @param {Object} currentUsage This current usage
  172. 172 : * @param {number} possible This possible usage id
  173. 173 : * @param {boolean} repeat If it is a looping/repeating arg
  174. 174 : * @returns {boolean}
  175. 175 : */
  176. 176 : async boolean(arg, currentUsage, possible, repeat) {
  177. 177 : const boolean = await super.boolean(arg);
  178. 178 : if (boolean !== null) return boolean;
  179. 179 : if (currentUsage.type === "optional" && !repeat) return null;
  180. 180 : throw `${currentUsage.possibles[possible].name} must be true or false.`;
  181. 181 : }
  182. 182 :
  183. 183 : /**
  184. 184 : * Resolves a string
  185. 185 : * @param {string} arg This arg
  186. 186 : * @param {Object} currentUsage This current usage
  187. 187 : * @param {number} possible This possible usage id
  188. 188 : * @param {boolean} repeat If it is a looping/repeating arg
  189. 189 : * @returns {string}
  190. 190 : */
  191. 191 : str(...args) {
  192. 192 : return this.string(...args);
  193. 193 : }
  194. 194 :
  195. 195 : /**
  196. 196 : * Resolves a string
  197. 197 : * @param {string} arg This arg
  198. 198 : * @param {Object} currentUsage This current usage
  199. 199 : * @param {number} possible This possible usage id
  200. 200 : * @param {boolean} repeat If it is a looping/repeating arg
  201. 201 : * @returns {string}
  202. 202 : */
  203. 203 : async string(arg, currentUsage, possible, repeat) {
  204. 204 : const { min, max } = currentUsage.possibles[possible];
  205. 205 : if (min && max) {
  206. 206 : if (arg.length >= min && arg.length <= max) return arg;
  207. 207 : if (currentUsage.type === "optional" && !repeat) return null;
  208. 208 : if (min === max) throw `${currentUsage.possibles[possible].name} must be exactly ${min} characters.`;
  209. 209 : throw `${currentUsage.possibles[possible].name} must be between ${min} and ${max} characters.`;
  210. 210 : } else if (min) {
  211. 211 : if (arg.length >= min) return arg;
  212. 212 : if (currentUsage.type === "optional" && !repeat) return null;
  213. 213 : throw `${currentUsage.possibles[possible].name} must be longer than ${min} characters.`;
  214. 214 : } else if (max) {
  215. 215 : if (arg.length <= max) return arg;
  216. 216 : if (currentUsage.type === "optional" && !repeat) return null;
  217. 217 : throw `${currentUsage.possibles[possible].name} must be shorter than ${max} characters.`;
  218. 218 : }
  219. 219 : return arg;
  220. 220 : }
  221. 221 :
  222. 222 : /**
  223. 223 : * Resolves a integer
  224. 224 : * @param {string} arg This arg
  225. 225 : * @param {Object} currentUsage This current usage
  226. 226 : * @param {number} possible This possible usage id
  227. 227 : * @param {boolean} repeat If it is a looping/repeating arg
  228. 228 : * @returns {number}
  229. 229 : */
  230. 230 : int(...args) {
  231. 231 : return this.integer(...args);
  232. 232 : }
  233. 233 :
  234. 234 : /**
  235. 235 : * Resolves a integer
  236. 236 : * @param {string} arg This arg
  237. 237 : * @param {Object} currentUsage This current usage
  238. 238 : * @param {number} possible This possible usage id
  239. 239 : * @param {boolean} repeat If it is a looping/repeating arg
  240. 240 : * @returns {number}
  241. 241 : */
  242. 242 : async integer(arg, currentUsage, possible, repeat) {
  243. 243 : const { min, max } = currentUsage.possibles[possible];
  244. 244 : arg = await super.integer(arg);
  245. 245 : if (arg === null) {
  246. 246 : if (currentUsage.type === "optional" && !repeat) return null;
  247. 247 : throw `${currentUsage.possibles[possible].name} must be an integer.`;
  248. 248 : } else if (min && max) {
  249. 249 : if (arg >= min && arg <= max) return arg;
  250. 250 : if (currentUsage.type === "optional" && !repeat) return null;
  251. 251 : if (min === max) throw `${currentUsage.possibles[possible].name} must be exactly ${min}\nSo why didn't the dev use a literal?`;
  252. 252 : throw `${currentUsage.possibles[possible].name} must be between ${min} and ${max}.`;
  253. 253 : } else if (min) {
  254. 254 : if (arg >= min) return arg;
  255. 255 : if (currentUsage.type === "optional" && !repeat) return null;
  256. 256 : throw `${currentUsage.possibles[possible].name} must be greater than ${min}.`;
  257. 257 : } else if (max) {
  258. 258 : if (arg <= max) return arg;
  259. 259 : if (currentUsage.type === "optional" && !repeat) return null;
  260. 260 : throw `${currentUsage.possibles[possible].name} must be less than ${max}.`;
  261. 261 : }
  262. 262 : return arg;
  263. 263 : }
  264. 264 :
  265. 265 : /**
  266. 266 : * Resolves a number
  267. 267 : * @param {string} arg This arg
  268. 268 : * @param {Object} currentUsage This current usage
  269. 269 : * @param {number} possible This possible usage id
  270. 270 : * @param {boolean} repeat If it is a looping/repeating arg
  271. 271 : * @returns {number}
  272. 272 : */
  273. 273 : num(...args) {
  274. 274 : return this.float(...args);
  275. 275 : }
  276. 276 :
  277. 277 : /**
  278. 278 : * Resolves a number
  279. 279 : * @param {string} arg This arg
  280. 280 : * @param {Object} currentUsage This current usage
  281. 281 : * @param {number} possible This possible usage id
  282. 282 : * @param {boolean} repeat If it is a looping/repeating arg
  283. 283 : * @returns {number}
  284. 284 : */
  285. 285 : number(...args) {
  286. 286 : return this.float(...args);
  287. 287 : }
  288. 288 :
  289. 289 : /**
  290. 290 : * Resolves a number
  291. 291 : * @param {string} arg This arg
  292. 292 : * @param {Object} currentUsage This current usage
  293. 293 : * @param {number} possible This possible usage id
  294. 294 : * @param {boolean} repeat If it is a looping/repeating arg
  295. 295 : * @returns {number}
  296. 296 : */
  297. 297 : async float(arg, currentUsage, possible, repeat) {
  298. 298 : const { min, max } = currentUsage.possibles[possible];
  299. 299 : arg = await super.float(arg);
  300. 300 : if (arg === null) {
  301. 301 : if (currentUsage.type === "optional" && !repeat) return null;
  302. 302 : throw `${currentUsage.possibles[possible].name} must be a valid number.`;
  303. 303 : } else if (min && max) {
  304. 304 : if (arg >= min && arg <= max) return arg;
  305. 305 : if (currentUsage.type === "optional" && !repeat) return null;
  306. 306 : if (min === max) throw `${currentUsage.possibles[possible].name} must be exactly ${min}\nSo why didn't the dev use a literal?`;
  307. 307 : throw `${currentUsage.possibles[possible].name} must be between ${min} and ${max}.`;
  308. 308 : } else if (min) {
  309. 309 : if (arg >= min) return arg;
  310. 310 : if (currentUsage.type === "optional" && !repeat) return null;
  311. 311 : throw `${currentUsage.possibles[possible].name} must be greater than ${min}.`;
  312. 312 : } else if (max) {
  313. 313 : if (arg <= max) return arg;
  314. 314 : if (currentUsage.type === "optional" && !repeat) return null;
  315. 315 : throw `${currentUsage.possibles[possible].name} must be less than ${max}.`;
  316. 316 : }
  317. 317 : return arg;
  318. 318 : }
  319. 319 :
  320. 320 : /**
  321. 321 : * Resolves a hyperlink
  322. 322 : * @param {string} arg This arg
  323. 323 : * @param {Object} currentUsage This current usage
  324. 324 : * @param {number} possible This possible usage id
  325. 325 : * @param {boolean} repeat If it is a looping/repeating arg
  326. 326 : * @returns {string}
  327. 327 : */
  328. 328 : async url(arg, currentUsage, possible, repeat) {
  329. 329 : const hyperlink = await super.url(arg);
  330. 330 : if (hyperlink !== null) return hyperlink;
  331. 331 : if (currentUsage.type === "optional" && !repeat) return null;
  332. 332 : throw `${currentUsage.possibles[possible].name} must be a valid url.`;
  333. 333 : }
  334. 334 :
  335. 335 : }
  336. 336 :
  337. 337 : module.exports = ArgResolver;