chore(wi): Add logSlashCommandWarn utility and integrate into world-info slash commands (#5096)

34688f849345968615e0ea43d298103f65b7feb1

Wolfsblvt <wolfsblvt@gmail.com>

Signed
2 files changed, +52 -6Ignore whitespace
public/scripts/utils.js+27 -0
@@ -2752,6 +2752,33 @@ export function versionCompare(srcVersion, minVersion) {
27522752}
27532753
27542754/**
2755+ * Logs a warning to the console for slash command executions.
2756+ * Strips internal arguments (starting with '_') from the args object for cleaner logging.
2757+ * @param {string} message - The warning message to log.
2758+ * @param {Object} args - The arguments object from the slash command, including named arguments and internal values.
2759+ * @param {{[unnamedArgName: string]: string}} [valueObj=null] - The user-built object containing context for the warning (e.g., { uid: uid }).
2760+ * @returns {void}
2761+ */
2762+export function logSlashCommandWarn(message, args, valueObj = null) {
2763+ if (valueObj !== null && valueObj !== undefined) {
2764+ console.warn(message, valueObj, stripInternalArgs(args));
2765+ } else {
2766+ console.warn(message, stripInternalArgs(args));
2767+ }
2768+ return;
2769+ function stripInternalArgs(args) {
2770+ // strip all args/properties that start with an underscore
2771+ const result = {};
2772+ for (const [key, value] of Object.entries(args)) {
2773+ if (!key.startsWith('_')) {
2774+ result[key] = value;
2775+ }
2776+ }
2777+ return result;
2778+ }
2779+}
2780+
2781+/**
27552782 * Sets up the scroll-to-top button functionality.
27562783 * @param {object} params Parameters object
27572784 * @param {string} params.scrollContainerId Scrollable container element ID
public/scripts/world-info.js+25 -6
@@ -1,7 +1,7 @@
11import { Fuse } from '../lib.js';
22
33import { saveSettings, substituteParams, getRequestHeaders, chat_metadata, this_chid, characters, saveCharacterDebounced, menu_type, eventSource, event_types, getExtensionPromptByName, saveMetadata, getCurrentChatId, extension_prompt_roles, create_save, createOrEditCharacter, name1 } from '../script.js';
44import { download, debounce, initScrollHeight, resetScrollHeight, parseJsonFile, extractDataFromPng, getFileBuffer, getCharaFilename, getSortableDelay, escapeRegex, PAGINATION_TEMPLATE, navigation_option, waitUntilCondition, isTrueBoolean, setValueByPath, flashHighlight, select2ModifyOptions, getSelect2OptionId, dynamicSelect2DataViaAjax, highlightRegex, select2ChoiceClickSubscribe, isFalseBoolean, getSanitizedFilename, checkOverwriteExistingData, getStringHash, parseStringArray, cancelDebounce, findChar, onlyUnique, equalsIgnoreCaseAndAccents, uuidv4, normalizeArray, getUniqueName, logSlashCommandWarn } from './utils.js';
55import { extension_settings, getContext } from './extensions.js';
66import { NOTE_MODULE_NAME, metadata_keys, shouldWIAddPrompt } from './authors-note.js';
77import { isMobile } from './RossAscends-mods.js';
@@ -1059,9 +1059,10 @@ function registerWorldInfoSlashCommands() {
10591059 return getContext().chat.filter(x => !x.is_system).map(x => x.mes);
10601060 }
10611061
1062- async function getEntriesFromFile(file) {
1062+ async function getEntriesFromFile(file, { args = {}, unnamed = null, callbackName = 'getEntriesFromFile' } = {}) {
10631063 if (!file || !world_names.includes(file)) {
10641064 toastr.warning(t`Valid World Info file name is required`);
1065+ logSlashCommandWarn(`${callbackName}: Valid World Info file name is required`, args, unnamed);
10651066 return '';
10661067 }
10671068
@@ -1069,6 +1070,7 @@ function registerWorldInfoSlashCommands() {
10691070
10701071 if (!data || !('entries' in data)) {
10711072 toastr.warning(t`World Info file has an invalid format`);
1073+ logSlashCommandWarn(`${callbackName}: World Info file has an invalid format`, args, unnamed);
10721074 return '';
10731075 }
10741076
@@ -1076,6 +1078,7 @@ function registerWorldInfoSlashCommands() {
10761078
10771079 if (!entries || entries.length === 0) {
10781080 toastr.warning(t`World Info file has no entries`);
1081+ logSlashCommandWarn(`${callbackName}: World Info file has no entries`, args, unnamed);
10791082 return '';
10801083 }
10811084
@@ -1119,6 +1122,7 @@ function registerWorldInfoSlashCommands() {
11191122 const character = findChar({ name: characterIdentifier });
11201123 if (!character) {
11211124 toastr.error(t`Character not found.`);
1125+ logSlashCommandWarn('getCharBookCallback: Character not found', { type, name, create }, { characterIdentifier });
11221126 return '';
11231127 }
11241128 const books = [];
@@ -1160,6 +1164,7 @@ function registerWorldInfoSlashCommands() {
11601164
11611165 if (!chatId) {
11621166 toastr.warning(t`Open a chat to get a name of the chat-bound lorebook`);
1167+ logSlashCommandWarn('getChatBookCallback: Open a chat to get a name of the chat-bound lorebook', args);
11631168 return '';
11641169 }
11651170
@@ -1205,7 +1210,7 @@ function registerWorldInfoSlashCommands() {
12051210 const file = args.file;
12061211 const field = args.field || 'key';
12071212
12081213 const entries = await getEntriesFromFile(file, { args, unnamed: { value }, callbackName: 'findBookEntryCallback' });
12091214
12101215 if (!entries) {
12111216 return '';
@@ -1250,7 +1255,7 @@ function registerWorldInfoSlashCommands() {
12501255 const field = args.field || 'content';
12511256 const tags = getContext().tags;
12521257
12531258 const entries = await getEntriesFromFile(file, { args, unnamed: { uid }, callbackName: 'getEntryFieldCallback' });
12541259
12551260 if (!entries) {
12561261 return '';
@@ -1260,11 +1265,14 @@ function registerWorldInfoSlashCommands() {
12601265
12611266 if (!entry) {
12621267 toastr.warning('Valid UID is required');
1268+ logSlashCommandWarn('getEntryFieldCallback: Valid UID is required', args, { uid });
1269+ console.warn();
12631270 return '';
12641271 }
12651272
12661273 if (!Object.hasOwn(newWorldInfoEntryDefinition, field)) {
12671274 toastr.warning('Valid field name is required');
1275+ logSlashCommandWarn('getEntryFieldCallback: Valid field name is required', args, { uid });
12681276 return '';
12691277 }
12701278
@@ -1313,6 +1321,7 @@ function registerWorldInfoSlashCommands() {
13131321
13141322 if (!data || !('entries' in data)) {
13151323 toastr.warning('Valid World Info file name is required');
1324+ logSlashCommandWarn('createEntryCallback: Valid World Info file name is required', args);
13161325 return '';
13171326 }
13181327
@@ -1358,6 +1367,7 @@ function registerWorldInfoSlashCommands() {
13581367
13591368 if (value === undefined) {
13601369 toastr.warning('Value is required');
1370+ logSlashCommandWarn('setEntryFieldCallback: Value is required', args, { value });
13611371 return '';
13621372 }
13631373
@@ -1367,6 +1377,7 @@ function registerWorldInfoSlashCommands() {
13671377
13681378 if (!data || !('entries' in data)) {
13691379 toastr.warning('Valid World Info file name is required');
1380+ logSlashCommandWarn('setEntryFieldCallback: Valid World Info file name is required', args, { value });
13701381 return '';
13711382 }
13721383
@@ -1374,11 +1385,13 @@ function registerWorldInfoSlashCommands() {
13741385
13751386 if (!entry) {
13761387 toastr.warning('Valid UID is required');
1388+ logSlashCommandWarn('setEntryFieldCallback: Valid UID is required', args, { value });
13771389 return '';
13781390 }
13791391
13801392 if (!Object.hasOwn(newWorldInfoEntryDefinition, field)) {
13811393 toastr.warning('Valid field name is required');
1394+ logSlashCommandWarn('setEntryFieldCallback: Valid field name is required', args, { value });
13821395 return '';
13831396 }
13841397
@@ -1445,7 +1458,7 @@ function registerWorldInfoSlashCommands() {
14451458 const uid = value;
14461459 const effect = args.effect;
14471460
14481461 const entries = await getEntriesFromFile(file, { args, unnamed: { uid }, callbackName: 'getTimedEffectCallback' });
14491462
14501463 if (!entries) {
14511464 return '';
@@ -1456,6 +1469,7 @@ function registerWorldInfoSlashCommands() {
14561469
14571470 if (!entry) {
14581471 toastr.warning('Valid UID is required');
1472+ logSlashCommandWarn('getTimedEffectCallback: Valid UID is required', args, { uid });
14591473 return '';
14601474 }
14611475
@@ -1465,6 +1479,7 @@ function registerWorldInfoSlashCommands() {
14651479
14661480 if (!timedEffects.isValidEffectType(effect)) {
14671481 toastr.warning('Valid effect type is required');
1482+ logSlashCommandWarn('getTimedEffectCallback: Valid effect type is required', args, { uid });
14681483 return '';
14691484 }
14701485
@@ -1488,10 +1503,11 @@ function registerWorldInfoSlashCommands() {
14881503
14891504 if (value === undefined) {
14901505 toastr.warning('New state is required');
1506+ logSlashCommandWarn('setTimedEffectCallback: New state is required', args, { value });
14911507 return '';
14921508 }
14931509
14941510 const entries = await getEntriesFromFile(file, { args, unnamed: { value }, callbackName: 'setTimedEffectCallback' });
14951511
14961512 if (!entries) {
14971513 return '';
@@ -1502,6 +1518,7 @@ function registerWorldInfoSlashCommands() {
15021518
15031519 if (!entry) {
15041520 toastr.warning('Valid UID is required');
1521+ logSlashCommandWarn('setTimedEffectCallback: Valid UID is required', args, { value });
15051522 return '';
15061523 }
15071524
@@ -1511,11 +1528,13 @@ function registerWorldInfoSlashCommands() {
15111528
15121529 if (!timedEffects.isValidEffectType(effect)) {
15131530 toastr.warning('Valid effect type is required');
1531+ logSlashCommandWarn('setTimedEffectCallback: Valid effect type is required', args, { value });
15141532 return '';
15151533 }
15161534
15171535 if (!entry[effect]) {
15181536 toastr.warning('This entry does not have the selected effect. Configure it in the editor first.');
1537+ logSlashCommandWarn('setTimedEffectCallback: This entry does not have the selected effect', args, { value });
15191538 return '';
15201539 }
15211540