STscript allow named arguments to be an array - Use named args definition and "acceptsMultiple" to build arrays of values, if provided - Add a debug warning if non-multiple named args are provided multiple times
| @@ -15,13 +15,13 @@ import { SlashCommandScope } from './SlashCommandScope.js'; | |||
| 15 | * _abortController:SlashCommandAbortController, | 15 | * _abortController:SlashCommandAbortController, |
| 16 | * _debugController:SlashCommandDebugController, | 16 | * _debugController:SlashCommandDebugController, |
| 17 | * _hasUnnamedArgument:boolean, | 17 | * _hasUnnamedArgument:boolean, |
| 18 | * [id:string]:string|SlashCommandClosure, | 18 | * [id:string]:string|SlashCommandClosure|(string|SlashCommandClosure)[], |
| 19 | * }} NamedArguments | 19 | * }} NamedArguments |
| 20 | */ | 20 | */ |
| 21 | 21 | ||
| 22 | /** | 22 | /** |
| 23 | * Alternative object for local JSDocs, where you don't need existing pipe, scope, etc. arguments | 23 | * Alternative object for local JSDocs, where you don't need existing pipe, scope, etc. arguments |
| 24 | * @typedef {{[id:string]:string|SlashCommandClosure}} NamedArgumentsCapture | 24 | * @typedef {{[id:string]:string|SlashCommandClosure|(string|SlashCommandClosure)[]}} NamedArgumentsCapture |
| 25 | */ | 25 | */ |
| 26 | 26 | ||
| 27 | /** | 27 | /** |
| @@ -2,6 +2,7 @@ import { substituteParams } from '../../script.js'; | |||
| 2 | import { delay, escapeRegex, uuidv4 } from '../utils.js'; | 2 | import { delay, escapeRegex, uuidv4 } from '../utils.js'; |
| 3 | import { SlashCommand } from './SlashCommand.js'; | 3 | import { SlashCommand } from './SlashCommand.js'; |
| 4 | import { SlashCommandAbortController } from './SlashCommandAbortController.js'; | 4 | import { SlashCommandAbortController } from './SlashCommandAbortController.js'; |
| 5 | import { SlashCommandNamedArgument } from './SlashCommandArgument.js'; | ||
| 5 | import { SlashCommandBreak } from './SlashCommandBreak.js'; | 6 | import { SlashCommandBreak } from './SlashCommandBreak.js'; |
| 6 | import { SlashCommandBreakController } from './SlashCommandBreakController.js'; | 7 | import { SlashCommandBreakController } from './SlashCommandBreakController.js'; |
| 7 | import { SlashCommandBreakPoint } from './SlashCommandBreakPoint.js'; | 8 | import { SlashCommandBreakPoint } from './SlashCommandBreakPoint.js'; |
| @@ -53,7 +54,7 @@ export class SlashCommandClosure { | |||
| 53 | * | 54 | * |
| 54 | * @param {string} text | 55 | * @param {string} text |
| 55 | * @param {SlashCommandScope} scope | 56 | * @param {SlashCommandScope} scope |
| 56 | * @returns | 57 | * @returns {string|SlashCommandClosure|(string|SlashCommandClosure)[]} |
| 57 | */ | 58 | */ |
| 58 | substituteParams(text, scope = null) { | 59 | substituteParams(text, scope = null) { |
| 59 | let isList = false; | 60 | let isList = false; |
| @@ -379,6 +380,52 @@ export class SlashCommandClosure { | |||
| 379 | * @param {import('./SlashCommand.js').NamedArguments} args | 380 | * @param {import('./SlashCommand.js').NamedArguments} args |
| 380 | */ | 381 | */ |
| 381 | async substituteNamedArguments(executor, args) { | 382 | async substituteNamedArguments(executor, args) { |
| 383 | /** | ||
| 384 | * Handles the assignment of named arguments, considering if they accept multiple values | ||
| 385 | * @param {string} name The name of the argument, as defined for the command execution | ||
| 386 | * @param {string|SlashCommandClosure|(string|SlashCommandClosure)[]} value The value to be assigned | ||
| 387 | */ | ||
| 388 | const assign = (name, value) => { | ||
| 389 | // If an array is supposed to be assigned, assign it one by one | ||
| 390 | if (Array.isArray(value)) { | ||
| 391 | for (const val of value) { | ||
| 392 | assign(name, val); | ||
| 393 | } | ||
| 394 | return; | ||
| 395 | } | ||
| 396 | |||
| 397 | const definition = executor.command.namedArgumentList.find(x => x.name == name); | ||
| 398 | |||
| 399 | // Prefer definition name if a valid named args defintion is found | ||
| 400 | name = definition?.name ?? name; | ||
| 401 | |||
| 402 | // Unescape named argument | ||
| 403 | if (value && typeof value == 'string') { | ||
| 404 | value = value | ||
| 405 | .replace(/\\\{/g, '{') | ||
| 406 | .replace(/\\\}/g, '}'); | ||
| 407 | } | ||
| 408 | |||
| 409 | // If the named argument accepts multiple values, we have to make sure to build an array correctly | ||
| 410 | if (definition?.acceptsMultiple) { | ||
| 411 | if (args[name] !== undefined) { | ||
| 412 | // If there already is something for that named arg, make the value is an array and add to it | ||
| 413 | let currentValue = args[name]; | ||
| 414 | if (!Array.isArray(currentValue)) { | ||
| 415 | currentValue = [currentValue]; | ||
| 416 | } | ||
| 417 | currentValue.push(value); | ||
| 418 | args[name] = currentValue; | ||
| 419 | } else { | ||
| 420 | // If there is nothing in there, just assign it as singular value, until multiple values are found | ||
| 421 | args[name] = value; | ||
| 422 | } | ||
| 423 | } else { | ||
| 424 | args[name] !== undefined && console.debug(`Named argument assigned multiple times: ${name}`); | ||
| 425 | args[name] = value; | ||
| 426 | } | ||
| 427 | }; | ||
| 428 | |||
| 382 | // substitute named arguments | 429 | // substitute named arguments |
| 383 | for (const arg of executor.namedArgumentList) { | 430 | for (const arg of executor.namedArgumentList) { |
| 384 | if (arg.value instanceof SlashCommandClosure) { | 431 | if (arg.value instanceof SlashCommandClosure) { |
| @@ -390,19 +437,12 @@ export class SlashCommandClosure { | |||
| 390 | closure.debugController = this.debugController; | 437 | closure.debugController = this.debugController; |
| 391 | } | 438 | } |
| 392 | if (closure.executeNow) { | 439 | if (closure.executeNow) { |
| 393 | args[arg.name] = (await closure.execute())?.pipe; | 440 | assign(arg.name, (await closure.execute())?.pipe); |
| 394 | } else { | 441 | } else { |
| 395 | args[arg.name] = closure; | 442 | assign(arg.name, closure); |
| 396 | } | 443 | } |
| 397 | } else { | 444 | } else { |
| 398 | args[arg.name] = this.substituteParams(arg.value); | 445 | assign(arg.name, this.substituteParams(arg.value)); |
| 399 | } | ||
| 400 | // unescape named argument | ||
| 401 | if (typeof args[arg.name] == 'string') { | ||
| 402 | args[arg.name] = args[arg.name] | ||
| 403 | ?.replace(/\\\{/g, '{') | ||
| 404 | ?.replace(/\\\}/g, '}') | ||
| 405 | ; | ||
| 406 | } | 446 | } |
| 407 | } | 447 | } |
| 408 | } | 448 | } |
| @@ -424,6 +464,7 @@ export class SlashCommandClosure { | |||
| 424 | } else { | 464 | } else { |
| 425 | value = []; | 465 | value = []; |
| 426 | for (let i = 0; i < executor.unnamedArgumentList.length; i++) { | 466 | for (let i = 0; i < executor.unnamedArgumentList.length; i++) { |
| 467 | /** @type {string|SlashCommandClosure|(string|SlashCommandClosure)[]} */ | ||
| 427 | let v = executor.unnamedArgumentList[i].value; | 468 | let v = executor.unnamedArgumentList[i].value; |
| 428 | if (v instanceof SlashCommandClosure) { | 469 | if (v instanceof SlashCommandClosure) { |
| 429 | /**@type {SlashCommandClosure}*/ | 470 | /**@type {SlashCommandClosure}*/ |