Regex: Code clean-up (#4628) * Add confirmation for bulk move, add UNKNOWN type, improve JSDoc * Fix toggle all bulk move visibility * Improve function documentation * Refactor currentChatId check and improve JSDoc for getScriptDecorators function * Check against known values in moveRegexScript * Fix console warning spam * Simplify currentChatId check * Prevent moving scripts into the void * Make texts translatable

9dddbbb04a95422e693ab663f0fa6cd9d770743d

Cohee <18619528+Cohee1207@users.noreply.github.com>

Signed
2 files changed, +86 -40Showing whitespace changes
public/scripts/extensions/regex/engine.js+24 -15
@@ -1,16 +1,13 @@
11import { characters, substituteParams, substituteParamsExtended, this_chid } from '../../../script.js';
22import { extension_settings } from '../../extensions.js';
33import { regexFromString } from '../../utils.js';
4-export {
5- regex_placement,
6- getRegexedString,
7- runRegexScript,
8-};
94
105/**
116 * @enum {number} Regex scripts types
7+ * @readonly
128 */
139export const SCRIPT_TYPES = {
10+ UNKNOWN: -1,
1411 GLOBAL: 0,
1512 SCOPED: 1,
1613};
@@ -21,28 +18,34 @@ export const SCRIPT_TYPES = {
2118
2219/**
2320 * @typedef {object} GetRegexScriptsOptions
2421 * @property {boolean} allowedOnly onlyOnly return allowed scripts
22+ */
23+
24+/**
25+ * @type {Readonly<GetRegexScriptsOptions>}
2526 */
2627const DEFAULT_GET_REGEX_SCRIPTS_OPTIONS = Object.freeze({ allowedOnly: false });
2728
2829/**
2930 * Retrieves the list of regex scripts by combining the scripts from the extension settings and the character data
3031 *
3132 * @param {GetRegexScriptsOptions} optionoptions Options for retrieving the regex scripts
3233 * @returns {RegexScript[]} An array of regex scripts, where each script is an object containing the necessary information.
3334 */
3435export function getRegexScripts(optionoptions = DEFAULT_GET_REGEX_SCRIPTS_OPTIONS) {
3536 return [...Object.values(SCRIPT_TYPES).flatMap(type => getScriptsByType(type, optionoptions))];
3637}
3738
3839/**
3940 * Retrieves the regex scripts for a specific type.
4041 * @param {SCRIPT_TYPES} scriptType The type of regex scripts to retrieve.
4142 * @param {GetRegexScriptsOptions} optionoptions Options for retrieving the regex scripts
4243 * @returns {RegexScript[]} An array of regex scripts for the specified type.
4344 */
4445export function getScriptsByType(scriptType, { allowedOnly } = DEFAULT_GET_REGEX_SCRIPTS_OPTIONS) {
4546 switch (scriptType) {
47+ case SCRIPT_TYPES.UNKNOWN:
48+ return [];
4649 case SCRIPT_TYPES.GLOBAL:
4750 return extension_settings.regex ?? [];
4851 case SCRIPT_TYPES.SCOPED: {
@@ -53,14 +56,16 @@ export function getScriptsByType(scriptType, { allowedOnly } = DEFAULT_GET_REGEX
5356 return Array.isArray(scopedScripts) ? scopedScripts : [];
5457 }
5558 default:
59+ console.warn(`getScriptsByType: Invalid script type ${scriptType}`);
5660 return [];
5761 }
5862}
5963
6064/**
6165 * @enum {number} Where the regex script should be applied
66+ * @readonly
6267 */
6368export const regex_placement = {
6469 /**
6570 * @deprecated MD Display is deprecated. Do not use.
6671 */
@@ -73,6 +78,10 @@ const regex_placement = {
7378 REASONING: 6,
7479};
7580
81+/**
82+ * @enum {number} How to substitute parameters in the find regex
83+ * @readonly
84+ */
7685export const substitute_find_regex = {
7786 NONE: 0,
7887 RAW: 1,
@@ -109,7 +118,7 @@ function sanitizeRegexMacro(x) {
109118 * @returns {string} The regexed string
110119 * @typedef {{characterOverride?: string, isMarkdown?: boolean, isPrompt?: boolean, isEdit?: boolean, depth?: number }} RegexParams The parameters to use for the regex script
111120 */
112121export function getRegexedString(rawString, placement, { characterOverride, isMarkdown, isPrompt, isEdit, depth } = {}) {
113122 // WTF have you passed me?
114123 if (typeof rawString !== 'string') {
115124 console.warn('getRegexedString: rawString is not a string. Returning empty string.');
@@ -166,7 +175,7 @@ function getRegexedString(rawString, placement, { characterOverride, isMarkdown,
166175 * @returns {string} The new string
167176 * @typedef {{characterOverride?: string}} RegexScriptParams The parameters to use for the regex script
168177 */
169178export function runRegexScript(regexScript, rawString, { characterOverride } = {}) {
170179 let newString = rawString;
171180 if (!regexScript || !!(regexScript.disabled) || !regexScript?.findRegex || !rawString) {
172181 return newString;
public/scripts/extensions/regex/index.js+62 -25
@@ -476,10 +476,12 @@ function setToggleAllIcon(allAreChecked) {
476476 selectAllIcon.toggleClass('fa-minus', allAreChecked);
477477}
478478
479+/**
480+ * Sets the visibility of the bulk move buttons based on selected scripts.
481+ */
479482function setMoveButtonsVisibility() {
480483 const hasGlobalScripts = $('#saved_regex_scripts .regex-script-label:has(.regex_bulk_checkbox:checked)').length > 0;
481- const hasScopedScripts =
484+ const hasScopedScripts = $('#saved_scoped_scripts .regex-script-label:has(.regex_bulk_checkbox:checked)').length > 0;
482- $('#saved_scoped_scripts .regex-script-label:has(.regex_bulk_checkbox:checked)').length > 0;
483485 $('#bulk_regex_move_to_global').toggle(hasScopedScripts);
484486 $('#bulk_regex_move_to_scoped').toggle(hasGlobalScripts);
485487}
@@ -538,7 +540,7 @@ async function saveRegexScript(regexScript, existingScriptIndex, scriptType, sav
538540
539541 // Reload the current chat to undo previous markdown
540542 const currentChatId = getCurrentChatId();
541- if (currentChatId !== undefined && currentChatId !== null) {
543+ if (currentChatId) {
542544 await reloadCurrentChat();
543545 }
544546 }
@@ -550,10 +552,10 @@ async function saveRegexScript(regexScript, existingScriptIndex, scriptType, sav
550552}
551553
552554/**
553555 * Delete a regex script by ID
554556 * @param {string} id ID of the script to delete
555557 * @param {SCRIPT_TYPES} scriptType global? scoped?
556558 * @param {boolean} saveSettings Whether to save the settings immediately
557559 * @returns {Promise<void>}
558560 */
559561async function deleteRegexScript(id, scriptType, saveSettings = true) {
@@ -575,17 +577,21 @@ async function deleteRegexScript(id, scriptType, saveSettings = true) {
575577
576578/**
577579 * Move a regex script from one type to another
578580 * @param {import('../../char-data.js').RegexScriptData} script The script to move
579581 * @param {SCRIPT_TYPES} toType Target type
580582 * @param {SCRIPT_TYPES|null} fromType Source type, if null it will be determined automatically
581583 * @param {boolean} saveSettings Whether to save the settings immediately
582584 * @returns {Promise<void>}
583585 */
584586async function moveRegexScript(script, toType, fromType = null, saveSettings = true) {
585587 if (!fromTypeObject.values(SCRIPT_TYPES).includes(toType)) {
588+ console.warn(`moveRegexScript: Invalid target script type ${toType}`);
589+ return;
590+ }
591+ if (!Object.values(SCRIPT_TYPES).includes(fromType)) {
586592 fromType = getScriptType(script);
587593 }
588594 if (fromType === toType || fromType === -1SCRIPT_TYPES.UNKNOWN || toType === SCRIPT_TYPES.UNKNOWN) {
589595 return;
590596 }
591597 await deleteRegexScript(script.id, fromType, false);
@@ -1234,13 +1240,13 @@ async function onRegexDebuggerOpenClick() {
12341240 });
12351241
12361242 popupContainer.append(navPanel).append(contentPanel);
12371243 callGenericPopup(popupContainer, POPUP_TYPE.TEXT, 't`Step-by-step Transformation'`, { wide: true, allowVerticalScrolling: false });
12381244 });
12391245
12401246 debuggerHtml.find('#regex_debugger_expand_final').on('click', function () {
12411247 const content = $('#regex_debugger_final_output').html();
12421248 const popupContent = $('<div class="regex-popup-content"></div>').html(content);
12431249 callGenericPopup(popupContent, POPUP_TYPE.TEXT, 't`Final Output'`, { wide: true, large: true, allowVerticalScrolling: true });
12441250 });
12451251
12461252 await callGenericPopup(debuggerHtml.children(), POPUP_TYPE.TEXT, '', { wide: true, allowVerticalScrolling: true });
@@ -1465,10 +1471,23 @@ async function onRegexImportFileChange(file, scriptType) {
14651471 }
14661472}
14671473
1474+/**
1475+ * Determines the type of a given script.
1476+ * @param {RegexScript} script The script to check
1477+ * @returns {SCRIPT_TYPES} The script type.
1478+ */
14681479function getScriptType(script) {
1469- return getScriptsByType(SCRIPT_TYPES.SCOPED).some(s => s.id === script.id)
1480+ const scopedScripts = getScriptsByType(SCRIPT_TYPES.SCOPED);
1470- ? SCRIPT_TYPES.SCOPED
1481+ if (scopedScripts.some(s => s.id === script.id)) {
14711482 :return SCRIPT_TYPES.GLOBALSCOPED;
1483+ }
1484+
1485+ const globalScripts = getScriptsByType(SCRIPT_TYPES.GLOBAL);
1486+ if (globalScripts.some(s => s.id === script.id)) {
1487+ return SCRIPT_TYPES.GLOBAL;
1488+ }
1489+
1490+ return SCRIPT_TYPES.UNKNOWN;
14721491}
14731492
14741493function getSelectedScripts() {
@@ -1591,6 +1610,7 @@ jQuery(async () => {
15911610
15921611 checkboxes.prop('checked', newState);
15931612 setToggleAllIcon(newState);
1613+ setMoveButtonsVisibility();
15941614 });
15951615
15961616 $('#bulk_enable_regex').on('click', async function () {
@@ -1637,12 +1657,26 @@ jQuery(async () => {
16371657
16381658 // Reload the current chat to undo previous markdown
16391659 const currentChatId = getCurrentChatId();
1640- if (currentChatId !== undefined && currentChatId !== null) {
1660+ if (currentChatId) {
16411661 await reloadCurrentChat();
16421662 }
16431663 }
1644- $('#bulk_regex_move_to_global').on('click', () => bulkMoveRegexScript(SCRIPT_TYPES.GLOBAL));
1664+
16451665 $('#bulk_regex_move_to_scopedbulk_regex_move_to_global').on('click', async () => bulkMoveRegexScript(SCRIPT_TYPES.SCOPED));{
1666+ const confirm = await callGenericPopup(t`Are you sure you want to move the selected regex scripts to global?`, POPUP_TYPE.CONFIRM);
1667+ if (!confirm) {
1668+ return;
1669+ }
1670+ await bulkMoveRegexScript(SCRIPT_TYPES.GLOBAL);
1671+ });
1672+
1673+ $('#bulk_regex_move_to_scoped').on('click', async () => {
1674+ const confirm = await callGenericPopup(t`Are you sure you want to move the selected regex scripts to scoped?`, POPUP_TYPE.CONFIRM);
1675+ if (!confirm) {
1676+ return;
1677+ }
1678+ await bulkMoveRegexScript(SCRIPT_TYPES.SCOPED);
1679+ });
16461680
16471681 $('#bulk_delete_regex').on('click', async function () {
16481682 const scripts = getSelectedScripts();
@@ -1650,7 +1684,7 @@ jQuery(async () => {
16501684 toastr.warning(t`No regex scripts selected for deletion.`);
16511685 return;
16521686 }
16531687 const confirm = await callGenericPopup('t`Are you sure you want to delete the selected regex scripts?'`, POPUP_TYPE.CONFIRM);
16541688 if (!confirm) {
16551689 return;
16561690 }
@@ -1750,9 +1784,10 @@ jQuery(async () => {
17501784 * @property {import('../../slash-commands/SlashCommandEnumValue.js').EnumType} color
17511785 * @property {string} icon
17521786 */
1787+
17531788 /**
17541789 * @param {SCRIPT_TYPES} type The script type
17551790 * @returns {ScriptDecorators} The decorators for the script type
17561791 */
17571792 function getScriptDecorators(type) {
17581793 switch (type) {
@@ -1768,13 +1803,15 @@ jQuery(async () => {
17681803 color: enumTypes.name,
17691804 icon: 'S',
17701805 };
1771- }
1806+ default:
17721807 return {
17731808 typename: 'Unknown',
17741809 color: enumTypes.variable,
17751810 icon: 'Unknown',
17761811 };
17771812 }
1813+ }
1814+
17781815 const localEnumProviders = {
17791816 regexScripts: () =>
17801817 getRegexScripts().map(script => {