2024-05-26 16:19:00 +02:00
import { characters , substituteParams , this _chid } from '../../../script.js' ;
2023-12-02 19:04:51 +01:00
import { extension _settings } from '../../extensions.js' ;
2024-05-17 00:14:07 +02:00
import { regexFromString } from '../../utils.js' ;
2023-07-20 19:32:15 +02:00
export {
regex _placement ,
getRegexedString ,
2023-12-02 21:06:57 +01:00
runRegexScript ,
2023-12-02 20:11:06 +01:00
} ;
2023-07-20 19:32:15 +02:00
2024-01-03 18:53:24 +01:00
/ * *
* @ enum { number } Where the regex script should be applied
* /
2023-07-20 19:32:15 +02:00
const regex _placement = {
2024-01-03 18:53:24 +01:00
/ * *
* @ deprecated MD Display is deprecated . Do not use .
* /
2023-07-20 19:32:15 +02:00
MD _DISPLAY : 0 ,
USER _INPUT : 1 ,
AI _OUTPUT : 2 ,
2023-12-02 21:06:57 +01:00
SLASH _COMMAND : 3 ,
2024-05-08 16:55:33 +02:00
// 4 - sendAs (legacy)
2024-05-08 19:10:52 +02:00
WORLD _INFO : 5 ,
2023-12-02 20:11:06 +01:00
} ;
2023-07-20 19:32:15 +02:00
2024-05-26 16:19:00 +02:00
function getScopedRegex ( ) {
const isAllowed = extension _settings ? . character _allowed _regex ? . includes ( characters ? . [ this _chid ] ? . avatar ) ;
if ( ! isAllowed ) {
return [ ] ;
}
const scripts = characters [ this _chid ] ? . data ? . extensions ? . regex _scripts ;
if ( ! Array . isArray ( scripts ) ) {
return [ ] ;
}
return scripts ;
}
2024-01-03 18:53:24 +01:00
/ * *
* Parent function to fetch a regexed version of a raw string
* @ param { string } rawString The raw string to be regexed
* @ param { regex _placement } placement The placement of the string
* @ param { RegexParams } params The parameters to use for the regex script
* @ returns { string } The regexed string
2024-10-07 19:21:07 +02:00
* @ typedef { { characterOverride ? : string , isMarkdown ? : boolean , isPrompt ? : boolean , isEdit ? : boolean , depth ? : number } } RegexParams The parameters to use for the regex script
2024-01-03 18:53:24 +01:00
* /
2024-10-07 19:21:07 +02:00
function getRegexedString ( rawString , placement , { characterOverride , isMarkdown , isPrompt , isEdit , depth } = { } ) {
2024-01-03 18:53:24 +01:00
// WTF have you passed me?
if ( typeof rawString !== 'string' ) {
console . warn ( 'getRegexedString: rawString is not a string. Returning empty string.' ) ;
return '' ;
}
2023-07-20 19:32:15 +02:00
let finalString = rawString ;
2023-12-02 19:04:51 +01:00
if ( extension _settings . disabledExtensions . includes ( 'regex' ) || ! rawString || placement === undefined ) {
2023-07-20 19:32:15 +02:00
return finalString ;
}
2024-05-26 16:19:00 +02:00
const allRegex = [ ... ( extension _settings . regex ? ? [ ] ) , ... ( getScopedRegex ( ) ? ? [ ] ) ] ;
allRegex . forEach ( ( script ) => {
2023-11-02 23:52:33 +01:00
if (
// Script applies to Markdown and input is Markdown
( script . markdownOnly && isMarkdown ) ||
// Script applies to Generate and input is Generate
( script . promptOnly && isPrompt ) ||
// Script applies to all cases when neither "only"s are true, but there's no need to do it when `isMarkdown`, the as source (chat history) should already be changed beforehand
( ! script . markdownOnly && ! script . promptOnly && ! isMarkdown )
) {
2024-10-07 19:21:07 +02:00
if ( isEdit && ! script . runOnEdit ) {
console . debug ( ` getRegexedString: Skipping script ${ script . scriptName } because it does not run on edit ` ) ;
return ;
}
2024-01-24 21:48:58 +01:00
// Check if the depth is within the min/max depth
if ( typeof depth === 'number' && depth >= 0 ) {
2024-02-04 20:34:17 +01:00
if ( ! isNaN ( script . minDepth ) && script . minDepth !== null && script . minDepth >= 0 && depth < script . minDepth ) {
2024-01-24 21:48:58 +01:00
console . debug ( ` getRegexedString: Skipping script ${ script . scriptName } because depth ${ depth } is less than minDepth ${ script . minDepth } ` ) ;
return ;
}
2024-02-04 20:34:17 +01:00
if ( ! isNaN ( script . maxDepth ) && script . maxDepth !== null && script . maxDepth >= 0 && depth > script . maxDepth ) {
2024-01-24 21:48:58 +01:00
console . debug ( ` getRegexedString: Skipping script ${ script . scriptName } because depth ${ depth } is greater than maxDepth ${ script . maxDepth } ` ) ;
return ;
}
}
2023-11-02 23:52:33 +01:00
if ( script . placement . includes ( placement ) ) {
finalString = runRegexScript ( script , finalString , { characterOverride } ) ;
}
2023-07-20 19:32:15 +02:00
}
} ) ;
return finalString ;
}
2024-01-03 11:28:56 +01:00
/ * *
* Runs the provided regex script on the given string
2024-06-17 07:04:10 +02:00
* @ param { import ( './index.js' ) . RegexScript } regexScript The regex script to run
2024-01-03 11:28:56 +01:00
* @ param { string } rawString The string to run the regex script on
2024-01-03 18:53:24 +01:00
* @ param { RegexScriptParams } params The parameters to use for the regex script
2024-01-03 11:28:56 +01:00
* @ returns { string } The new string
2024-01-03 18:53:24 +01:00
* @ typedef { { characterOverride ? : string } } RegexScriptParams The parameters to use for the regex script
2024-01-03 11:28:56 +01:00
* /
2023-07-20 19:32:15 +02:00
function runRegexScript ( regexScript , rawString , { characterOverride } = { } ) {
let newString = rawString ;
if ( ! regexScript || ! ! ( regexScript . disabled ) || ! regexScript ? . findRegex || ! rawString ) {
return newString ;
}
const findRegex = regexFromString ( regexScript . substituteRegex ? substituteParams ( regexScript . findRegex ) : regexScript . findRegex ) ;
// The user skill issued. Return with nothing.
if ( ! findRegex ) {
return newString ;
}
2024-01-06 06:30:25 +01:00
// Run replacement. Currently does not support the Overlay strategy
2024-05-26 16:19:00 +02:00
newString = rawString . replace ( findRegex , function ( match ) {
2024-01-06 06:30:25 +01:00
const args = [ ... arguments ] ;
2024-01-11 01:41:00 +01:00
const replaceString = regexScript . replaceString . replace ( /{{match}}/gi , '$0' ) ;
2024-03-21 11:12:22 +01:00
const replaceWithGroups = replaceString . replaceAll ( /\$(\d+)/g , ( _ , num ) => {
2024-01-11 01:41:00 +01:00
// Get a full match or a capture group
2024-01-06 06:30:25 +01:00
const match = args [ Number ( num ) ] ;
2024-01-11 01:41:00 +01:00
// No match found - return the empty string
if ( ! match ) {
return '' ;
}
// Remove trim strings from the match
2024-01-06 06:30:25 +01:00
const filteredMatch = filterString ( match , regexScript . trimStrings , { characterOverride } ) ;
// TODO: Handle overlay here
return filteredMatch ;
} ) ;
// Substitute at the end
return substituteParams ( replaceWithGroups ) ;
2024-01-03 18:53:24 +01:00
} ) ;
2023-07-20 19:32:15 +02:00
return newString ;
}
2024-01-03 18:53:24 +01:00
/ * *
* Filters anything to trim from the regex match
* @ param { string } rawString The raw string to filter
* @ param { string [ ] } trimStrings The strings to trim
* @ param { RegexScriptParams } params The parameters to use for the regex filter
* @ returns { string } The filtered string
* /
2023-07-20 19:32:15 +02:00
function filterString ( rawString , trimStrings , { characterOverride } = { } ) {
let finalString = rawString ;
2024-01-06 06:33:52 +01:00
trimStrings . forEach ( ( trimString ) => {
2023-07-20 19:32:15 +02:00
const subTrimString = substituteParams ( trimString , undefined , characterOverride ) ;
2023-12-02 19:04:51 +01:00
finalString = finalString . replaceAll ( subTrimString , '' ) ;
2024-01-06 06:33:52 +01:00
} ) ;
2023-07-20 19:32:15 +02:00
return finalString ;
}