mirror of
https://github.com/SillyTavern/SillyTavern.git
synced 2025-03-03 03:17:54 +01:00
/if allow "rule" and "right" to be optional
This commit is contained in:
parent
a1af768b02
commit
aea95adf60
@ -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>
|
||||||
`,
|
`,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user