SillyTavern/public/scripts/slash-commands/SlashCommandScope.js

118 lines
4.0 KiB
JavaScript

import { SlashCommandClosure } from './SlashCommandClosure.js';
import { convertValueType } from '../utils.js';
export class SlashCommandScope {
/**@type {string[]}*/ variableNames = [];
get allVariableNames() {
const names = [...this.variableNames, ...(this.parent?.allVariableNames ?? [])];
return names.filter((it,idx)=>idx == names.indexOf(it));
}
// @ts-ignore
/**@type {object.<string, string|SlashCommandClosure>}*/ variables = {};
// @ts-ignore
/**@type {object.<string, string|SlashCommandClosure>}*/ macros = {};
/**@type {{key:string, value:string|SlashCommandClosure}[]} */
get macroList() {
return [...Object.keys(this.macros).map(key=>({ key, value:this.macros[key] })), ...(this.parent?.macroList ?? [])];
}
/**@type {SlashCommandScope}*/ parent;
/**@type {string}*/ #pipe;
get pipe() {
return this.#pipe ?? this.parent?.pipe;
}
set pipe(value) {
this.#pipe = value;
}
constructor(parent) {
this.parent = parent;
}
getCopy() {
const scope = new SlashCommandScope(this.parent);
scope.variableNames = [...this.variableNames];
scope.variables = Object.assign({}, this.variables);
scope.macros = Object.assign({}, this.macros);
scope.#pipe = this.#pipe;
return scope;
}
setMacro(key, value, overwrite = true) {
if (overwrite || !this.macroList.find(it=>it.key == key)) {
this.macros[key] = value;
}
}
existsVariableInScope(key) {
return Object.keys(this.variables).includes(key);
}
existsVariable(key) {
return Object.keys(this.variables).includes(key) || this.parent?.existsVariable(key);
}
letVariable(key, value = undefined) {
if (this.existsVariableInScope(key)) throw new SlashCommandScopeVariableExistsError(`Variable named "${key}" already exists.`);
this.variables[key] = value;
}
setVariable(key, value, index = null, type = null) {
if (this.existsVariableInScope(key)) {
if (index !== null && index !== undefined) {
let v = this.variables[key];
try {
v = JSON.parse(v);
const numIndex = Number(index);
if (Number.isNaN(numIndex)) {
v[index] = convertValueType(value, type);
} else {
v[numIndex] = convertValueType(value, type);
}
v = JSON.stringify(v);
} catch {
v[index] = convertValueType(value, type);
}
this.variables[key] = v;
} else {
this.variables[key] = value;
}
return value;
}
if (this.parent) {
return this.parent.setVariable(key, value, index, type);
}
throw new SlashCommandScopeVariableNotFoundError(`No such variable: "${key}"`);
}
getVariable(key, index = null) {
if (this.existsVariableInScope(key)) {
if (index !== null && index !== undefined) {
let v = this.variables[key];
try { v = JSON.parse(v); } catch { /* empty */ }
const numIndex = Number(index);
if (Number.isNaN(numIndex)) {
v = v[index];
} else {
v = v[numIndex];
}
if (typeof v == 'object') return JSON.stringify(v);
return v ?? '';
} else {
const value = this.variables[key];
return (value?.trim?.() === '' || isNaN(Number(value))) ? (value || '') : Number(value);
}
}
if (this.parent) {
return this.parent.getVariable(key, index);
}
throw new SlashCommandScopeVariableNotFoundError(`No such variable: "${key}"`);
}
}
export class SlashCommandScopeVariableExistsError extends Error {}
export class SlashCommandScopeVariableNotFoundError extends Error {}