/if allow "rule" and "right" to be optional

This commit is contained in:
Wolfsblvt 2024-09-22 07:42:51 +02:00
parent a1af768b02
commit aea95adf60

View File

@ -11,7 +11,7 @@ import { commonEnumProviders, enumIcons } from './slash-commands/SlashCommandCom
import { SlashCommandEnumValue, enumTypes } from './slash-commands/SlashCommandEnumValue.js'; import { SlashCommandEnumValue, enumTypes } from './slash-commands/SlashCommandEnumValue.js';
import { PARSER_FLAG, SlashCommandParser } from './slash-commands/SlashCommandParser.js'; import { PARSER_FLAG, SlashCommandParser } from './slash-commands/SlashCommandParser.js';
import { SlashCommandScope } from './slash-commands/SlashCommandScope.js'; import { SlashCommandScope } from './slash-commands/SlashCommandScope.js';
import { isFalseBoolean, convertValueType } from './utils.js'; import { isFalseBoolean, convertValueType, isTrueBoolean } from './utils.js';
/** @typedef {import('./slash-commands/SlashCommandParser.js').NamedArguments} NamedArguments */ /** @typedef {import('./slash-commands/SlashCommandParser.js').NamedArguments} NamedArguments */
/** @typedef {import('./slash-commands/SlashCommand.js').UnnamedArguments} UnnamedArguments */ /** @typedef {import('./slash-commands/SlashCommand.js').UnnamedArguments} UnnamedArguments */
@ -463,7 +463,7 @@ function existsGlobalVariable(name) {
/** /**
* Parses boolean operands from command arguments. * Parses boolean operands from command arguments.
* @param {object} args Command arguments * @param {object} args Command arguments
* @returns {{a: string | number, b: string | number, rule: string}} Boolean operands * @returns {{a: string | number, b: string | number?, rule: string}} Boolean operands
*/ */
export function parseBooleanOperands(args) { export function parseBooleanOperands(args) {
// Resolution order: numeric literal, local variable, global variable, string literal // Resolution order: numeric literal, local variable, global variable, string literal
@ -472,6 +472,9 @@ export function parseBooleanOperands(args) {
*/ */
function getOperand(operand) { function getOperand(operand) {
if (operand === undefined) { if (operand === undefined) {
return undefined;
}
if (operand === '') {
return ''; return '';
} }
@ -500,9 +503,9 @@ export function parseBooleanOperands(args) {
return stringLiteral || ''; return stringLiteral || '';
} }
const left = getOperand(args.a || args.left || args.first || args.x); const left = getOperand(args.a ?? args.left ?? args.first ?? args.x);
const right = getOperand(args.b || args.right || args.second || args.y); const right = getOperand(args.b ?? args.right ?? args.second ?? args.y);
const rule = args.rule; const rule = args.rule ?? 'eq';
return { a: left, b: right, rule }; return { a: left, b: right, rule };
} }
@ -511,16 +514,22 @@ export function parseBooleanOperands(args) {
* Evaluates a boolean comparison rule. * Evaluates a boolean comparison rule.
* @param {string} rule Boolean comparison rule * @param {string} rule Boolean comparison rule
* @param {string|number} a The left operand * @param {string|number} a The left operand
* @param {string|number} b The right operand * @param {string|number?} b The right operand
* @returns {boolean} True if the rule yields true, false otherwise * @returns {boolean} True if the rule yields true, false otherwise
*/ */
export function evalBoolean(rule, a, b) { export function evalBoolean(rule, a, b) {
if (!rule) { let result = false;
toastr.warning('The rule must be specified for the boolean comparison.', 'Invalid command');
throw new Error('Invalid command.'); if (b === undefined && rule === 'eq') {
// If right-hand side was not provided, whe just check if the left side is truthy
if (isTrueBoolean(String(a))) return true;
if (isFalseBoolean(String(a))) return false;
return !!a;
} }
let result = false; // Restore old behavior, where b cannot be undefined
b = b ?? '';
if (typeof a === 'number' && typeof b === 'number') { if (typeof a === 'number' && typeof b === 'number') {
// only do numeric comparison if both operands are numbers // only do numeric comparison if both operands are numbers
const aNumber = Number(a); const aNumber = Number(a);
@ -582,7 +591,7 @@ export function evalBoolean(rule, a, b) {
break; break;
default: default:
toastr.error('Unknown boolean comparison rule for type string.', 'Invalid /if command'); toastr.error('Unknown boolean comparison rule for type string.', 'Invalid /if command');
throw new Error('Invalid command.'); throw new Error('Unknown boolean comparison rule for type string.');
} }
} }
@ -1264,21 +1273,18 @@ export function registerVariableCommands() {
typeList: [ARGUMENT_TYPE.VARIABLE_NAME, ARGUMENT_TYPE.STRING, ARGUMENT_TYPE.NUMBER], typeList: [ARGUMENT_TYPE.VARIABLE_NAME, ARGUMENT_TYPE.STRING, ARGUMENT_TYPE.NUMBER],
isRequired: true, isRequired: true,
enumProvider: commonEnumProviders.variables('all'), enumProvider: commonEnumProviders.variables('all'),
forceEnum: false,
}), }),
SlashCommandNamedArgument.fromProps({ SlashCommandNamedArgument.fromProps({
name: 'right', name: 'right',
description: 'right operand', description: 'right operand',
typeList: [ARGUMENT_TYPE.VARIABLE_NAME, ARGUMENT_TYPE.STRING, ARGUMENT_TYPE.NUMBER], typeList: [ARGUMENT_TYPE.VARIABLE_NAME, ARGUMENT_TYPE.STRING, ARGUMENT_TYPE.NUMBER],
isRequired: true,
enumProvider: commonEnumProviders.variables('all'), enumProvider: commonEnumProviders.variables('all'),
forceEnum: false,
}), }),
SlashCommandNamedArgument.fromProps({ SlashCommandNamedArgument.fromProps({
name: 'rule', name: 'rule',
description: 'comparison rule', description: 'comparison rule',
typeList: [ARGUMENT_TYPE.STRING], typeList: [ARGUMENT_TYPE.STRING],
isRequired: true, defaultValue: 'eq',
enumList: [ enumList: [
new SlashCommandEnumValue('gt', 'a > b'), new SlashCommandEnumValue('gt', 'a > b'),
new SlashCommandEnumValue('gte', 'a >= b'), new SlashCommandEnumValue('gte', 'a >= b'),
@ -1290,12 +1296,12 @@ export function registerVariableCommands() {
new SlashCommandEnumValue('in', 'a includes b'), new SlashCommandEnumValue('in', 'a includes b'),
new SlashCommandEnumValue('nin', 'a not includes b'), new SlashCommandEnumValue('nin', 'a not includes b'),
], ],
forceEnum: true,
}), }),
SlashCommandNamedArgument.fromProps({ SlashCommandNamedArgument.fromProps({
name: 'else', name: 'else',
description: 'command to execute if not true', description: 'command to execute if not true',
typeList: [ARGUMENT_TYPE.CLOSURE, ARGUMENT_TYPE.SUBCOMMAND], typeList: [ARGUMENT_TYPE.CLOSURE, ARGUMENT_TYPE.SUBCOMMAND],
isRequired: false,
}), }),
], ],
unnamedArgumentList: [ unnamedArgumentList: [
@ -1313,6 +1319,11 @@ export function registerVariableCommands() {
<div> <div>
Numeric values and string literals for left and right operands supported. Numeric values and string literals for left and right operands supported.
</div> </div>
<div>
If the rule is not provided, it defaults to <code>eq</code>.<br />
If no right operand is provided, it defaults to checking the <code>left</code> value to be truthy.
A non-empty string or non-zero number is considered truthy, as is the value <code>true</code>.
</div>
<div> <div>
<strong>Available rules:</strong> <strong>Available rules:</strong>
<ul> <ul>
@ -1334,6 +1345,13 @@ export function registerVariableCommands() {
<pre><code class="language-stscript">/if left=score right=10 rule=gte "/speak You win"</code></pre> <pre><code class="language-stscript">/if left=score right=10 rule=gte "/speak You win"</code></pre>
triggers a /speak command if the value of "score" is greater or equals 10. triggers a /speak command if the value of "score" is greater or equals 10.
</li> </li>
<li>
<pre><code class="language-stscript">/if left={{lastMessage}} rule=in right=surprise {: /echo SURPISE! :}</code></pre>
executes a subcommand defined as a closure if the given value contains a specified word.
<li>
<pre><code class="language-stscript">/if left=myContent {: /echo "My content had some content." :}</code></pre>
executes the defined subcommand, if the provided value of left is truthy (contains some kind of contant that is not empty or false)
</li>
</ul> </ul>
</div> </div>
`, `,