mirror of
https://github.com/SillyTavern/SillyTavern.git
synced 2025-03-06 12:47:57 +01:00
Add type conversion for /setvar commands with index
This commit is contained in:
parent
7aaabbd2bb
commit
3746f08590
@ -36,6 +36,8 @@ export const enumIcons = {
|
||||
|
||||
true: '✔️',
|
||||
false: '❌',
|
||||
null: '🚫',
|
||||
undefined: '❓',
|
||||
|
||||
// Value types
|
||||
boolean: '🔲',
|
||||
@ -230,4 +232,19 @@ export const commonEnumProviders = {
|
||||
enumTypes.enum, '💉');
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets somewhat recognizable STscript types.
|
||||
*
|
||||
* @returns {SlashCommandEnumValue[]}
|
||||
*/
|
||||
types: () => [
|
||||
new SlashCommandEnumValue('string', null, enumTypes.type, enumIcons.string),
|
||||
new SlashCommandEnumValue('number', null, enumTypes.type, enumIcons.number),
|
||||
new SlashCommandEnumValue('boolean', null, enumTypes.type, enumIcons.boolean),
|
||||
new SlashCommandEnumValue('array', null, enumTypes.type, enumIcons.array),
|
||||
new SlashCommandEnumValue('object', null, enumTypes.type, enumIcons.dictionary),
|
||||
new SlashCommandEnumValue('null', null, enumTypes.type, enumIcons.null),
|
||||
new SlashCommandEnumValue('undefined', null, enumTypes.type, enumIcons.undefined),
|
||||
],
|
||||
};
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { SlashCommandClosure } from './SlashCommandClosure.js';
|
||||
import { convertValueType } from '../utils.js';
|
||||
|
||||
export class SlashCommandScope {
|
||||
/**@type {string[]}*/ variableNames = [];
|
||||
@ -55,7 +56,8 @@ export class SlashCommandScope {
|
||||
if (this.existsVariableInScope(key)) throw new SlashCommandScopeVariableExistsError(`Variable named "${key}" already exists.`);
|
||||
this.variables[key] = value;
|
||||
}
|
||||
setVariable(key, value, index = null) {
|
||||
setVariable(key, value, index = null, type = null) {
|
||||
value = convertValueType(value, type);
|
||||
if (this.existsVariableInScope(key)) {
|
||||
if (index !== null && index !== undefined) {
|
||||
let v = this.variables[key];
|
||||
|
@ -4,6 +4,7 @@ import { isMobile } from './RossAscends-mods.js';
|
||||
import { collapseNewlines } from './power-user.js';
|
||||
import { debounce_timeout } from './constants.js';
|
||||
import { Popup, POPUP_RESULT, POPUP_TYPE } from './popup.js';
|
||||
import { SlashCommandClosure } from './slash-commands/SlashCommandClosure.js';
|
||||
|
||||
/**
|
||||
* Pagination status string template.
|
||||
@ -33,6 +34,74 @@ export function isValidUrl(value) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts string to a value of a given type. Includes pythonista-friendly aliases.
|
||||
* @param {string|SlashCommandClosure} value String value
|
||||
* @param {string} type Type to convert to
|
||||
* @returns {any} Converted value
|
||||
*/
|
||||
export function convertValueType(value, type) {
|
||||
if (value instanceof SlashCommandClosure || typeof type !== 'string') {
|
||||
return value;
|
||||
}
|
||||
|
||||
type = type.trim().toLowerCase();
|
||||
|
||||
switch (type) {
|
||||
case 'string':
|
||||
case 'str':
|
||||
return String(value);
|
||||
|
||||
case 'null':
|
||||
return null;
|
||||
|
||||
case 'undefined':
|
||||
case 'none':
|
||||
return undefined;
|
||||
|
||||
case 'number':
|
||||
return Number(value);
|
||||
|
||||
case 'int':
|
||||
return parseInt(value, 10);
|
||||
|
||||
case 'float':
|
||||
return parseFloat(value);
|
||||
|
||||
case 'boolean':
|
||||
case 'bool':
|
||||
return isTrueBoolean(value);
|
||||
|
||||
case 'list':
|
||||
case 'array':
|
||||
try {
|
||||
const parsedArray = JSON.parse(value);
|
||||
if (Array.isArray(parsedArray)) {
|
||||
return parsedArray;
|
||||
}
|
||||
throw new Error('Value is not an array.');
|
||||
} catch {
|
||||
return [];
|
||||
}
|
||||
|
||||
case 'object':
|
||||
case 'dict':
|
||||
case 'dictionary':
|
||||
try {
|
||||
const parsedObject = JSON.parse(value);
|
||||
if (typeof parsedObject === 'object') {
|
||||
return parsedObject;
|
||||
}
|
||||
throw new Error('Value is not an object.');
|
||||
} catch {
|
||||
return {};
|
||||
}
|
||||
|
||||
default:
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses ranges like 10-20 or 10.
|
||||
* Range is inclusive. Start must be less than end.
|
||||
|
@ -11,7 +11,7 @@ import { commonEnumProviders, enumIcons } from './slash-commands/SlashCommandCom
|
||||
import { SlashCommandEnumValue, enumTypes } from './slash-commands/SlashCommandEnumValue.js';
|
||||
import { PARSER_FLAG, SlashCommandParser } from './slash-commands/SlashCommandParser.js';
|
||||
import { SlashCommandScope } from './slash-commands/SlashCommandScope.js';
|
||||
import { isFalseBoolean } from './utils.js';
|
||||
import { isFalseBoolean, convertValueType } from './utils.js';
|
||||
|
||||
/** @typedef {import('./slash-commands/SlashCommandParser.js').NamedArguments} NamedArguments */
|
||||
/** @typedef {import('./slash-commands/SlashCommand.js').UnnamedArguments} UnnamedArguments */
|
||||
@ -51,6 +51,7 @@ function setLocalVariable(name, value, args = {}) {
|
||||
|
||||
if (args.index !== undefined) {
|
||||
try {
|
||||
value = convertValueType(value, args.type);
|
||||
let localVariable = JSON.parse(chat_metadata.variables[name] ?? 'null');
|
||||
const numIndex = Number(args.index);
|
||||
if (Number.isNaN(numIndex)) {
|
||||
@ -100,6 +101,7 @@ function getGlobalVariable(name, args = {}) {
|
||||
function setGlobalVariable(name, value, args = {}) {
|
||||
if (args.index !== undefined) {
|
||||
try {
|
||||
value = convertValueType(value, args.type);
|
||||
let globalVariable = JSON.parse(extension_settings.variables.global[name] ?? 'null');
|
||||
const numIndex = Number(args.index);
|
||||
if (Number.isNaN(numIndex)) {
|
||||
@ -667,23 +669,28 @@ function parseNumericSeries(value, scope = null) {
|
||||
}
|
||||
|
||||
function performOperation(value, operation, singleOperand = false, scope = null) {
|
||||
if (!value) {
|
||||
return 0;
|
||||
function getResult() {
|
||||
if (!value) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const array = parseNumericSeries(value, scope);
|
||||
|
||||
if (array.length === 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const result = singleOperand ? operation(array[0]) : operation(array);
|
||||
|
||||
if (isNaN(result) || !isFinite(result)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
const array = parseNumericSeries(value, scope);
|
||||
|
||||
if (array.length === 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const result = singleOperand ? operation(array[0]) : operation(array);
|
||||
|
||||
if (isNaN(result) || !isFinite(result)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return result;
|
||||
const result = getResult();
|
||||
return String(result);
|
||||
}
|
||||
|
||||
function addValuesCallback(args, value) {
|
||||
@ -836,7 +843,7 @@ function varCallback(args, value) {
|
||||
if (typeof key != 'string') throw new Error('Key must be a string');
|
||||
if (args._hasUnnamedArgument) {
|
||||
const val = typeof value[0] == 'string' ? value.join(' ') : value[0];
|
||||
args._scope.setVariable(key, val, args.index);
|
||||
args._scope.setVariable(key, val, args.index, args.type);
|
||||
return val;
|
||||
} else {
|
||||
return args._scope.getVariable(key, args.index);
|
||||
@ -846,7 +853,7 @@ function varCallback(args, value) {
|
||||
if (typeof key != 'string') throw new Error('Key must be a string');
|
||||
if (value.length > 0) {
|
||||
const val = typeof value[0] == 'string' ? value.join(' ') : value[0];
|
||||
args._scope.setVariable(key, val, args.index);
|
||||
args._scope.setVariable(key, val, args.index, args.type);
|
||||
return val;
|
||||
} else {
|
||||
return args._scope.getVariable(key, args.index);
|
||||
@ -901,6 +908,14 @@ export function registerVariableCommands() {
|
||||
new SlashCommandNamedArgument(
|
||||
'index', 'list index', [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.STRING], false,
|
||||
),
|
||||
SlashCommandNamedArgument.fromProps({
|
||||
name: 'type',
|
||||
description: 'type of the value when used with index',
|
||||
forceEnum: true,
|
||||
enumProvider: commonEnumProviders.types,
|
||||
isRequired: false,
|
||||
defaultValue: 'string',
|
||||
}),
|
||||
],
|
||||
unnamedArgumentList: [
|
||||
new SlashCommandArgument(
|
||||
@ -910,6 +925,7 @@ export function registerVariableCommands() {
|
||||
helpString: `
|
||||
<div>
|
||||
Set a local variable value and pass it down the pipe. The <code>index</code> argument is optional.
|
||||
To perform a type conversion when using <code>index</code>, use the <code>type</code> argument.
|
||||
</div>
|
||||
<div>
|
||||
<strong>Example:</strong>
|
||||
@ -917,6 +933,9 @@ export function registerVariableCommands() {
|
||||
<li>
|
||||
<pre><code class="language-stscript">/setvar key=color green</code></pre>
|
||||
</li>
|
||||
<li>
|
||||
<pre><code class="language-stscript">/setvar key=colors index=3 type=string blue</code></pre>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
`,
|
||||
@ -1015,6 +1034,14 @@ export function registerVariableCommands() {
|
||||
new SlashCommandNamedArgument(
|
||||
'index', 'list index', [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.STRING], false,
|
||||
),
|
||||
SlashCommandNamedArgument.fromProps({
|
||||
name: 'type',
|
||||
description: 'type of the value when used with index',
|
||||
forceEnum: true,
|
||||
enumProvider: commonEnumProviders.types,
|
||||
isRequired: false,
|
||||
defaultValue: 'string',
|
||||
}),
|
||||
],
|
||||
unnamedArgumentList: [
|
||||
new SlashCommandArgument(
|
||||
@ -1024,6 +1051,7 @@ export function registerVariableCommands() {
|
||||
helpString: `
|
||||
<div>
|
||||
Set a global variable value and pass it down the pipe. The <code>index</code> argument is optional.
|
||||
To perform a type conversion when using <code>index</code>, use the <code>type</code> argument.
|
||||
</div>
|
||||
<div>
|
||||
<strong>Example:</strong>
|
||||
@ -1031,6 +1059,9 @@ export function registerVariableCommands() {
|
||||
<li>
|
||||
<pre><code class="language-stscript">/setglobalvar key=color green</code></pre>
|
||||
</li>
|
||||
<li>
|
||||
<pre><code class="language-stscript">/setglobalvar key=colors index=3 type=string blue</code></pre>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
`,
|
||||
@ -1247,16 +1278,16 @@ export function registerVariableCommands() {
|
||||
}),
|
||||
new SlashCommandNamedArgument(
|
||||
'rule', 'comparison rule', [ARGUMENT_TYPE.STRING], true, false, null, [
|
||||
new SlashCommandEnumValue('gt', 'a > b'),
|
||||
new SlashCommandEnumValue('gte', 'a >= b'),
|
||||
new SlashCommandEnumValue('lt', 'a < b'),
|
||||
new SlashCommandEnumValue('lte', 'a <= b'),
|
||||
new SlashCommandEnumValue('eq', 'a == b'),
|
||||
new SlashCommandEnumValue('neq', 'a !== b'),
|
||||
new SlashCommandEnumValue('not', '!a'),
|
||||
new SlashCommandEnumValue('in', 'a includes b'),
|
||||
new SlashCommandEnumValue('nin', 'a not includes b'),
|
||||
],
|
||||
new SlashCommandEnumValue('gt', 'a > b'),
|
||||
new SlashCommandEnumValue('gte', 'a >= b'),
|
||||
new SlashCommandEnumValue('lt', 'a < b'),
|
||||
new SlashCommandEnumValue('lte', 'a <= b'),
|
||||
new SlashCommandEnumValue('eq', 'a == b'),
|
||||
new SlashCommandEnumValue('neq', 'a !== b'),
|
||||
new SlashCommandEnumValue('not', '!a'),
|
||||
new SlashCommandEnumValue('in', 'a includes b'),
|
||||
new SlashCommandEnumValue('nin', 'a not includes b'),
|
||||
],
|
||||
),
|
||||
new SlashCommandNamedArgument(
|
||||
'else', 'command to execute if not true', [ARGUMENT_TYPE.CLOSURE, ARGUMENT_TYPE.SUBCOMMAND], false,
|
||||
@ -1325,16 +1356,16 @@ export function registerVariableCommands() {
|
||||
}),
|
||||
new SlashCommandNamedArgument(
|
||||
'rule', 'comparison rule', [ARGUMENT_TYPE.STRING], true, false, null, [
|
||||
new SlashCommandEnumValue('gt', 'a > b'),
|
||||
new SlashCommandEnumValue('gte', 'a >= b'),
|
||||
new SlashCommandEnumValue('lt', 'a < b'),
|
||||
new SlashCommandEnumValue('lte', 'a <= b'),
|
||||
new SlashCommandEnumValue('eq', 'a == b'),
|
||||
new SlashCommandEnumValue('neq', 'a !== b'),
|
||||
new SlashCommandEnumValue('not', '!a'),
|
||||
new SlashCommandEnumValue('in', 'a includes b'),
|
||||
new SlashCommandEnumValue('nin', 'a not includes b'),
|
||||
],
|
||||
new SlashCommandEnumValue('gt', 'a > b'),
|
||||
new SlashCommandEnumValue('gte', 'a >= b'),
|
||||
new SlashCommandEnumValue('lt', 'a < b'),
|
||||
new SlashCommandEnumValue('lte', 'a <= b'),
|
||||
new SlashCommandEnumValue('eq', 'a == b'),
|
||||
new SlashCommandEnumValue('neq', 'a !== b'),
|
||||
new SlashCommandEnumValue('not', '!a'),
|
||||
new SlashCommandEnumValue('in', 'a includes b'),
|
||||
new SlashCommandEnumValue('nin', 'a not includes b'),
|
||||
],
|
||||
),
|
||||
new SlashCommandNamedArgument(
|
||||
'guard', 'disable loop iteration limit', [ARGUMENT_TYPE.STRING], false, false, null, commonEnumProviders.boolean('onOff')(),
|
||||
@ -2030,6 +2061,14 @@ export function registerVariableCommands() {
|
||||
false, // isRequired
|
||||
false, // acceptsMultiple
|
||||
),
|
||||
SlashCommandNamedArgument.fromProps({
|
||||
name: 'type',
|
||||
description: 'type of the value when used with index',
|
||||
forceEnum: true,
|
||||
enumProvider: commonEnumProviders.types,
|
||||
isRequired: false,
|
||||
defaultValue: 'string',
|
||||
}),
|
||||
],
|
||||
unnamedArgumentList: [
|
||||
SlashCommandArgument.fromProps({
|
||||
|
Loading…
x
Reference in New Issue
Block a user