/if allow "rule" and "right" to be optional
| @@ -11,7 +11,7 @@ import { commonEnumProviders, enumIcons } from './slash-commands/SlashCommandCom | |||
| 11 | import { SlashCommandEnumValue, enumTypes } from './slash-commands/SlashCommandEnumValue.js'; | 11 | import { SlashCommandEnumValue, enumTypes } from './slash-commands/SlashCommandEnumValue.js'; |
| 12 | import { PARSER_FLAG, SlashCommandParser } from './slash-commands/SlashCommandParser.js'; | 12 | import { PARSER_FLAG, SlashCommandParser } from './slash-commands/SlashCommandParser.js'; |
| 13 | import { SlashCommandScope } from './slash-commands/SlashCommandScope.js'; | 13 | import { SlashCommandScope } from './slash-commands/SlashCommandScope.js'; |
| 14 | import { isFalseBoolean, convertValueType } from './utils.js'; | 14 | import { isFalseBoolean, convertValueType, isTrueBoolean } from './utils.js'; |
| 15 | 15 | ||
| 16 | /** @typedef {import('./slash-commands/SlashCommandParser.js').NamedArguments} NamedArguments */ | 16 | /** @typedef {import('./slash-commands/SlashCommandParser.js').NamedArguments} NamedArguments */ |
| 17 | /** @typedef {import('./slash-commands/SlashCommand.js').UnnamedArguments} UnnamedArguments */ | 17 | /** @typedef {import('./slash-commands/SlashCommand.js').UnnamedArguments} UnnamedArguments */ |
| @@ -463,7 +463,7 @@ function existsGlobalVariable(name) { | |||
| 463 | /** | 463 | /** |
| 464 | * Parses boolean operands from command arguments. | 464 | * Parses boolean operands from command arguments. |
| 465 | * @param {object} args Command arguments | 465 | * @param {object} args Command arguments |
| 466 | * @returns {{a: string | number, b: string | number, rule: string}} Boolean operands | 466 | * @returns {{a: string | number, b: string | number?, rule: string}} Boolean operands |
| 467 | */ | 467 | */ |
| 468 | export function parseBooleanOperands(args) { | 468 | export function parseBooleanOperands(args) { |
| 469 | // Resolution order: numeric literal, local variable, global variable, string literal | 469 | // Resolution order: numeric literal, local variable, global variable, string literal |
| @@ -472,6 +472,9 @@ export function parseBooleanOperands(args) { | |||
| 472 | */ | 472 | */ |
| 473 | function getOperand(operand) { | 473 | function getOperand(operand) { |
| 474 | if (operand === undefined) { | 474 | if (operand === undefined) { |
| 475 | return undefined; | ||
| 476 | } | ||
| 477 | if (operand === '') { | ||
| 475 | return ''; | 478 | return ''; |
| 476 | } | 479 | } |
| 477 | 480 | ||
| @@ -500,9 +503,9 @@ export function parseBooleanOperands(args) { | |||
| 500 | return stringLiteral || ''; | 503 | return stringLiteral || ''; |
| 501 | } | 504 | } |
| 502 | 505 | ||
| 503 | const left = getOperand(args.a || args.left || args.first || args.x); | 506 | const left = getOperand(args.a ?? args.left ?? args.first ?? args.x); |
| 504 | const right = getOperand(args.b || args.right || args.second || args.y); | 507 | const right = getOperand(args.b ?? args.right ?? args.second ?? args.y); |
| 505 | const rule = args.rule; | 508 | const rule = args.rule ?? 'eq'; |
| 506 | 509 | ||
| 507 | return { a: left, b: right, rule }; | 510 | return { a: left, b: right, rule }; |
| 508 | } | 511 | } |
| @@ -511,16 +514,22 @@ export function parseBooleanOperands(args) { | |||
| 511 | * Evaluates a boolean comparison rule. | 514 | * Evaluates a boolean comparison rule. |
| 512 | * @param {string} rule Boolean comparison rule | 515 | * @param {string} rule Boolean comparison rule |
| 513 | * @param {string|number} a The left operand | 516 | * @param {string|number} a The left operand |
| 514 | * @param {string|number} b The right operand | 517 | * @param {string|number?} b The right operand |
| 515 | * @returns {boolean} True if the rule yields true, false otherwise | 518 | * @returns {boolean} True if the rule yields true, false otherwise |
| 516 | */ | 519 | */ |
| 517 | export function evalBoolean(rule, a, b) { | 520 | export function evalBoolean(rule, a, b) { |
| 518 | if (!rule) { | 521 | let result = false; |
| 519 | toastr.warning('The rule must be specified for the boolean comparison.', 'Invalid command'); | 522 | |
| 520 | throw new Error('Invalid command.'); | 523 | if (b === undefined && rule === 'eq') { |
| 524 | // If right-hand side was not provided, whe just check if the left side is truthy | ||
| 525 | if (isTrueBoolean(String(a))) return true; | ||
| 526 | if (isFalseBoolean(String(a))) return false; | ||
| 527 | return !!a; | ||
| 521 | } | 528 | } |
| 522 | 529 | ||
| 523 | let result = false; | 530 | // Restore old behavior, where b cannot be undefined |
| 531 | b = b ?? ''; | ||
| 532 | |||
| 524 | if (typeof a === 'number' && typeof b === 'number') { | 533 | if (typeof a === 'number' && typeof b === 'number') { |
| 525 | // only do numeric comparison if both operands are numbers | 534 | // only do numeric comparison if both operands are numbers |
| 526 | const aNumber = Number(a); | 535 | const aNumber = Number(a); |
| @@ -582,7 +591,7 @@ export function evalBoolean(rule, a, b) { | |||
| 582 | break; | 591 | break; |
| 583 | default: | 592 | default: |
| 584 | toastr.error('Unknown boolean comparison rule for type string.', 'Invalid /if command'); | 593 | toastr.error('Unknown boolean comparison rule for type string.', 'Invalid /if command'); |
| 585 | throw new Error('Invalid command.'); | 594 | throw new Error('Unknown boolean comparison rule for type string.'); |
| 586 | } | 595 | } |
| 587 | } | 596 | } |
| 588 | 597 | ||
| @@ -1264,21 +1273,18 @@ export function registerVariableCommands() { | |||
| 1264 | typeList: [ARGUMENT_TYPE.VARIABLE_NAME, ARGUMENT_TYPE.STRING, ARGUMENT_TYPE.NUMBER], | 1273 | typeList: [ARGUMENT_TYPE.VARIABLE_NAME, ARGUMENT_TYPE.STRING, ARGUMENT_TYPE.NUMBER], |
| 1265 | isRequired: true, | 1274 | isRequired: true, |
| 1266 | enumProvider: commonEnumProviders.variables('all'), | 1275 | enumProvider: commonEnumProviders.variables('all'), |
| 1267 | forceEnum: false, | ||
| 1268 | }), | 1276 | }), |
| 1269 | SlashCommandNamedArgument.fromProps({ | 1277 | SlashCommandNamedArgument.fromProps({ |
| 1270 | name: 'right', | 1278 | name: 'right', |
| 1271 | description: 'right operand', | 1279 | description: 'right operand', |
| 1272 | typeList: [ARGUMENT_TYPE.VARIABLE_NAME, ARGUMENT_TYPE.STRING, ARGUMENT_TYPE.NUMBER], | 1280 | typeList: [ARGUMENT_TYPE.VARIABLE_NAME, ARGUMENT_TYPE.STRING, ARGUMENT_TYPE.NUMBER], |
| 1273 | isRequired: true, | ||
| 1274 | enumProvider: commonEnumProviders.variables('all'), | 1281 | enumProvider: commonEnumProviders.variables('all'), |
| 1275 | forceEnum: false, | ||
| 1276 | }), | 1282 | }), |
| 1277 | SlashCommandNamedArgument.fromProps({ | 1283 | SlashCommandNamedArgument.fromProps({ |
| 1278 | name: 'rule', | 1284 | name: 'rule', |
| 1279 | description: 'comparison rule', | 1285 | description: 'comparison rule', |
| 1280 | typeList: [ARGUMENT_TYPE.STRING], | 1286 | typeList: [ARGUMENT_TYPE.STRING], |
| 1281 | isRequired: true, | 1287 | defaultValue: 'eq', |
| 1282 | enumList: [ | 1288 | enumList: [ |
| 1283 | new SlashCommandEnumValue('gt', 'a > b'), | 1289 | new SlashCommandEnumValue('gt', 'a > b'), |
| 1284 | new SlashCommandEnumValue('gte', 'a >= b'), | 1290 | new SlashCommandEnumValue('gte', 'a >= b'), |
| @@ -1290,12 +1296,12 @@ export function registerVariableCommands() { | |||
| 1290 | new SlashCommandEnumValue('in', 'a includes b'), | 1296 | new SlashCommandEnumValue('in', 'a includes b'), |
| 1291 | new SlashCommandEnumValue('nin', 'a not includes b'), | 1297 | new SlashCommandEnumValue('nin', 'a not includes b'), |
| 1292 | ], | 1298 | ], |
| 1299 | forceEnum: true, | ||
| 1293 | }), | 1300 | }), |
| 1294 | SlashCommandNamedArgument.fromProps({ | 1301 | SlashCommandNamedArgument.fromProps({ |
| 1295 | name: 'else', | 1302 | name: 'else', |
| 1296 | description: 'command to execute if not true', | 1303 | description: 'command to execute if not true', |
| 1297 | typeList: [ARGUMENT_TYPE.CLOSURE, ARGUMENT_TYPE.SUBCOMMAND], | 1304 | typeList: [ARGUMENT_TYPE.CLOSURE, ARGUMENT_TYPE.SUBCOMMAND], |
| 1298 | isRequired: false, | ||
| 1299 | }), | 1305 | }), |
| 1300 | ], | 1306 | ], |
| 1301 | unnamedArgumentList: [ | 1307 | unnamedArgumentList: [ |
| @@ -1314,6 +1320,11 @@ export function registerVariableCommands() { | |||
| 1314 | Numeric values and string literals for left and right operands supported. | 1320 | Numeric values and string literals for left and right operands supported. |
| 1315 | </div> | 1321 | </div> |
| 1316 | <div> | 1322 | <div> |
| 1323 | If the rule is not provided, it defaults to <code>eq</code>.<br /> | ||
| 1324 | If no right operand is provided, it defaults to checking the <code>left</code> value to be truthy. | ||
| 1325 | A non-empty string or non-zero number is considered truthy, as is the value <code>true</code>. | ||
| 1326 | </div> | ||
| 1327 | <div> | ||
| 1317 | <strong>Available rules:</strong> | 1328 | <strong>Available rules:</strong> |
| 1318 | <ul> | 1329 | <ul> |
| 1319 | <li>gt => a > b</li> | 1330 | <li>gt => a > b</li> |
| @@ -1334,6 +1345,13 @@ export function registerVariableCommands() { | |||
| 1334 | <pre><code class="language-stscript">/if left=score right=10 rule=gte "/speak You win"</code></pre> | 1345 | <pre><code class="language-stscript">/if left=score right=10 rule=gte "/speak You win"</code></pre> |
| 1335 | triggers a /speak command if the value of "score" is greater or equals 10. | 1346 | triggers a /speak command if the value of "score" is greater or equals 10. |
| 1336 | </li> | 1347 | </li> |
| 1348 | <li> | ||
| 1349 | <pre><code class="language-stscript">/if left={{lastMessage}} rule=in right=surprise {: /echo SURPISE! :}</code></pre> | ||
| 1350 | executes a subcommand defined as a closure if the given value contains a specified word. | ||
| 1351 | <li> | ||
| 1352 | <pre><code class="language-stscript">/if left=myContent {: /echo "My content had some content." :}</code></pre> | ||
| 1353 | executes the defined subcommand, if the provided value of left is truthy (contains some kind of contant that is not empty or false) | ||
| 1354 | </li> | ||
| 1337 | </ul> | 1355 | </ul> |
| 1338 | </div> | 1356 | </div> |
| 1339 | `, | 1357 | `, |