2024-09-25 23:18:37 +02:00
import { disableExtension , enableExtension , extension _settings , extensionNames } from './extensions.js' ;
import { SlashCommand } from './slash-commands/SlashCommand.js' ;
import { ARGUMENT _TYPE , SlashCommandArgument , SlashCommandNamedArgument } from './slash-commands/SlashCommandArgument.js' ;
import { SlashCommandClosure } from './slash-commands/SlashCommandClosure.js' ;
import { commonEnumProviders } from './slash-commands/SlashCommandCommonEnumsProvider.js' ;
2024-09-25 23:33:00 +02:00
import { enumTypes , SlashCommandEnumValue } from './slash-commands/SlashCommandEnumValue.js' ;
2024-09-25 23:18:37 +02:00
import { SlashCommandParser } from './slash-commands/SlashCommandParser.js' ;
import { equalsIgnoreCaseAndAccents , isFalseBoolean , isTrueBoolean } from './utils.js' ;
/ * *
* @ param { 'enable' | 'disable' | 'toggle' } action - The action to perform on the extension
* @ returns { ( args : { [ key : string ] : string | SlashCommandClosure } , extensionName : string | SlashCommandClosure ) => Promise < string > }
* /
function getExtensionActionCallback ( action ) {
return async ( args , extensionName ) => {
if ( args ? . reload instanceof SlashCommandClosure ) throw new Error ( '\'reload\' argument cannot be a closure.' ) ;
if ( typeof extensionName !== 'string' ) throw new Error ( 'Extension name must be a string. Closures or arrays are not allowed.' ) ;
if ( ! extensionName ) {
toastr . warning ( ` Extension name must be provided as an argument to ${ action } this extension. ` ) ;
return '' ;
}
2024-09-25 23:53:26 +02:00
const reload = ! isFalseBoolean ( args ? . reload ) ;
2024-09-25 23:33:00 +02:00
const internalExtensionName = findExtension ( extensionName ) ;
2024-09-25 23:18:37 +02:00
if ( ! internalExtensionName ) {
toastr . warning ( ` Extension ${ extensionName } does not exist. ` ) ;
return '' ;
}
const isEnabled = ! extension _settings . disabledExtensions . includes ( internalExtensionName ) ;
if ( action === 'enable' && isEnabled ) {
toastr . info ( ` Extension ${ extensionName } is already enabled. ` ) ;
return internalExtensionName ;
}
if ( action === 'disable' && ! isEnabled ) {
toastr . info ( ` Extension ${ extensionName } is already disabled. ` ) ;
return internalExtensionName ;
}
if ( action === 'toggle' ) {
action = isEnabled ? 'disable' : 'enable' ;
}
2024-09-25 23:53:26 +02:00
if ( reload ) {
toastr . info ( ` ${ action . charAt ( 0 ) . toUpperCase ( ) + action . slice ( 1 ) } ing extension ${ extensionName } and reloading... ` ) ;
// Clear input, so it doesn't stay because the command didn't "finish",
// and wait for a bit to both show the toast and let the clear bubble through.
$ ( '#send_textarea' ) . val ( '' ) [ 0 ] . dispatchEvent ( new Event ( 'input' , { bubbles : true } ) ) ;
await new Promise ( resolve => setTimeout ( resolve , 100 ) ) ;
}
2024-09-25 23:18:37 +02:00
if ( action === 'enable' ) {
await enableExtension ( internalExtensionName , reload ) ;
} else {
await disableExtension ( internalExtensionName , reload ) ;
}
toastr . success ( ` Extension ${ extensionName } ${ action } d. ` ) ;
2024-09-25 23:53:26 +02:00
console . info ( ` Extension ${ action } ed: ${ extensionName } ` ) ;
if ( ! reload ) {
console . info ( 'Reload not requested, so page needs to be reloaded manually for changes to take effect.' ) ;
}
2024-09-25 23:18:37 +02:00
return internalExtensionName ;
} ;
}
2024-09-25 23:33:00 +02:00
/ * *
* Finds an extension by name , allowing omission of the "third-party/" prefix .
*
* @ param { string } name - The name of the extension to find
* @ returns { string ? } - The matched extension name or undefined if not found
* /
function findExtension ( name ) {
return extensionNames . find ( extName => {
return equalsIgnoreCaseAndAccents ( extName , name ) || equalsIgnoreCaseAndAccents ( extName , ` third-party/ ${ name } ` ) ;
} ) ;
}
/ * *
* Provides an array of SlashCommandEnumValue objects based on the extension names .
* Each object contains the name of the extension and a description indicating if it is a third - party extension .
*
* @ returns { SlashCommandEnumValue [ ] } An array of SlashCommandEnumValue objects
* /
const extensionNamesEnumProvider = ( ) => extensionNames . map ( name => {
const isThirdParty = name . startsWith ( 'third-party/' ) ;
if ( isThirdParty ) name = name . slice ( 'third-party/' . length ) ;
const description = isThirdParty ? 'third party extension' : null ;
return new SlashCommandEnumValue ( name , description , ! isThirdParty ? enumTypes . name : enumTypes . enum ) ;
} ) ;
2024-09-25 23:18:37 +02:00
export function registerExtensionSlashCommands ( ) {
SlashCommandParser . addCommandObject ( SlashCommand . fromProps ( {
name : 'extension-enable' ,
callback : getExtensionActionCallback ( 'enable' ) ,
2024-09-25 23:53:26 +02:00
returns : 'The internal extension name' ,
2024-09-25 23:18:37 +02:00
namedArgumentList : [
SlashCommandNamedArgument . fromProps ( {
name : 'reload' ,
description : 'Whether to reload the page after enabling the extension' ,
typeList : [ ARGUMENT _TYPE . BOOLEAN ] ,
defaultValue : 'true' ,
enumList : commonEnumProviders . boolean ( 'trueFalse' ) ( ) ,
} ) ,
] ,
unnamedArgumentList : [
SlashCommandArgument . fromProps ( {
description : 'Extension name' ,
typeList : [ ARGUMENT _TYPE . STRING ] ,
isRequired : true ,
2024-09-25 23:33:00 +02:00
enumProvider : extensionNamesEnumProvider ,
2024-09-25 23:18:37 +02:00
forceEnum : true ,
} ) ,
] ,
helpString : `
< div >
Enables a specified extension .
< / d i v >
< div >
By default , the page will be reloaded automatically , stopping any further commands . < br / >
If < code > reload = false < / c o d e > n a m e d a r g u m e n t i s p a s s e d , t h e p a g e w i l l n o t b e r e l o a d e d , a n d t h e e x t e n s i o n w i l l s t a y d i s a b l e d u n t i l r e f r e s h e d .
The page either needs to be refreshed , or < code > / r e l o a d - p a g e < / c o d e > h a s t o b e c a l l e d .
< / d i v >
< div >
< strong > Example : < / s t r o n g >
< ul >
< li >
< pre > < code class = "language-stscript" > / e x t e n s i o n - e n a b l e S u m m a r i z e < / c o d e > < / p r e >
< / l i >
< / u l >
< / d i v >
` ,
} ) ) ;
SlashCommandParser . addCommandObject ( SlashCommand . fromProps ( {
name : 'extension-disable' ,
2024-09-25 23:53:26 +02:00
callback : getExtensionActionCallback ( 'disable' ) ,
returns : 'The internal extension name' ,
2024-09-25 23:18:37 +02:00
namedArgumentList : [
SlashCommandNamedArgument . fromProps ( {
name : 'reload' ,
description : 'Whether to reload the page after disabling the extension' ,
typeList : [ ARGUMENT _TYPE . BOOLEAN ] ,
defaultValue : 'true' ,
enumList : commonEnumProviders . boolean ( 'trueFalse' ) ( ) ,
} ) ,
] ,
unnamedArgumentList : [
SlashCommandArgument . fromProps ( {
description : 'Extension name' ,
typeList : [ ARGUMENT _TYPE . STRING ] ,
isRequired : true ,
2024-09-25 23:33:00 +02:00
enumProvider : extensionNamesEnumProvider ,
2024-09-25 23:18:37 +02:00
forceEnum : true ,
} ) ,
] ,
helpString : `
< div >
Disables a specified extension .
< / d i v >
< div >
By default , the page will be reloaded automatically , stopping any further commands . < br / >
If < code > reload = false < / c o d e > n a m e d a r g u m e n t i s p a s s e d , t h e p a g e w i l l n o t b e r e l o a d e d , a n d t h e e x t e n s i o n w i l l s t a y e n a b l e d u n t i l r e f r e s h e d .
The page either needs to be refreshed , or < code > / r e l o a d - p a g e < / c o d e > h a s t o b e c a l l e d .
< / d i v >
< div >
< strong > Example : < / s t r o n g >
< ul >
< li >
< pre > < code class = "language-stscript" > / e x t e n s i o n - d i s a b l e S u m m a r i z e < / c o d e > < / p r e >
< / l i >
< / u l >
< / d i v >
` ,
} ) ) ;
SlashCommandParser . addCommandObject ( SlashCommand . fromProps ( {
name : 'extension-toggle' ,
callback : async ( args , extensionName ) => {
if ( args ? . state instanceof SlashCommandClosure ) throw new Error ( '\'state\' argument cannot be a closure.' ) ;
if ( typeof extensionName !== 'string' ) throw new Error ( 'Extension name must be a string. Closures or arrays are not allowed.' ) ;
const action = isTrueBoolean ( args ? . state ) ? 'enable' :
isFalseBoolean ( args ? . state ) ? 'disable' :
'toggle' ;
return await getExtensionActionCallback ( action ) ( args , extensionName ) ;
} ,
2024-09-25 23:53:26 +02:00
returns : 'The internal extension name' ,
2024-09-25 23:18:37 +02:00
namedArgumentList : [
SlashCommandNamedArgument . fromProps ( {
name : 'reload' ,
description : 'Whether to reload the page after toggling the extension' ,
typeList : [ ARGUMENT _TYPE . BOOLEAN ] ,
defaultValue : 'true' ,
enumList : commonEnumProviders . boolean ( 'trueFalse' ) ( ) ,
} ) ,
SlashCommandNamedArgument . fromProps ( {
name : 'state' ,
description : 'Explicitly set the state of the extension (true to enable, false to disable). If not provided, the state will be toggled to the opposite of the current state.' ,
typeList : [ ARGUMENT _TYPE . BOOLEAN ] ,
enumList : commonEnumProviders . boolean ( 'trueFalse' ) ( ) ,
} ) ,
] ,
unnamedArgumentList : [
SlashCommandArgument . fromProps ( {
description : 'Extension name' ,
typeList : [ ARGUMENT _TYPE . STRING ] ,
isRequired : true ,
2024-09-25 23:33:00 +02:00
enumProvider : extensionNamesEnumProvider ,
2024-09-25 23:18:37 +02:00
forceEnum : true ,
} ) ,
] ,
helpString : `
< div >
Toggles the state of a specified extension .
< / d i v >
< div >
By default , the page will be reloaded automatically , stopping any further commands . < br / >
If < code > reload = false < / c o d e > n a m e d a r g u m e n t i s p a s s e d , t h e p a g e w i l l n o t b e r e l o a d e d , a n d t h e e x t e n s i o n w i l l s t a y i n i t s c u r r e n t s t a t e u n t i l r e f r e s h e d .
The page either needs to be refreshed , or < code > / r e l o a d - p a g e < / c o d e > h a s t o b e c a l l e d .
< / d i v >
< div >
< strong > Example : < / s t r o n g >
< ul >
< li >
< pre > < code class = "language-stscript" > / e x t e n s i o n - t o g g l e S u m m a r i z e < / c o d e > < / p r e >
< / l i >
< li >
< pre > < code class = "language-stscript" > / e x t e n s i o n - t o g g l e S u m m a r i z e s t a t e = t r u e < / c o d e > < / p r e >
< / l i >
< / u l >
< / d i v >
` ,
} ) ) ;
SlashCommandParser . addCommandObject ( SlashCommand . fromProps ( {
name : 'extension-state' ,
callback : async ( _ , extensionName ) => {
if ( typeof extensionName !== 'string' ) throw new Error ( 'Extension name must be a string. Closures or arrays are not allowed.' ) ;
2024-09-25 23:33:00 +02:00
const internalExtensionName = findExtension ( extensionName ) ;
2024-09-25 23:18:37 +02:00
if ( ! internalExtensionName ) {
toastr . warning ( ` Extension ${ extensionName } does not exist. ` ) ;
return '' ;
}
const isEnabled = ! extension _settings . disabledExtensions . includes ( internalExtensionName ) ;
return String ( isEnabled ) ;
} ,
2024-09-27 00:19:45 +02:00
returns : 'The state of the extension, whether it is enabled.' ,
2024-09-25 23:18:37 +02:00
unnamedArgumentList : [
SlashCommandArgument . fromProps ( {
description : 'Extension name' ,
typeList : [ ARGUMENT _TYPE . STRING ] ,
isRequired : true ,
2024-09-25 23:33:00 +02:00
enumProvider : extensionNamesEnumProvider ,
2024-09-25 23:18:37 +02:00
forceEnum : true ,
} ) ,
] ,
helpString : `
< div >
Returns the state of a specified extension ( true if enabled , false if disabled ) .
< / d i v >
< div >
< strong > Example : < / s t r o n g >
< ul >
< li >
< pre > < code class = "language-stscript" > / e x t e n s i o n - s t a t e S u m m a r i z e < / c o d e > < / p r e >
< / l i >
< / u l >
< / d i v >
` ,
} ) ) ;
SlashCommandParser . addCommandObject ( SlashCommand . fromProps ( {
name : 'extension-exists' ,
aliases : [ 'extension-installed' ] ,
callback : async ( _ , extensionName ) => {
if ( typeof extensionName !== 'string' ) throw new Error ( 'Extension name must be a string. Closures or arrays are not allowed.' ) ;
2024-09-25 23:33:00 +02:00
const exists = findExtension ( extensionName ) !== undefined ;
2024-09-25 23:18:37 +02:00
return exists ? 'true' : 'false' ;
} ,
2024-09-27 00:13:44 +02:00
returns : 'Whether the extension exists and is installed.' ,
2024-09-25 23:18:37 +02:00
unnamedArgumentList : [
SlashCommandArgument . fromProps ( {
description : 'Extension name' ,
typeList : [ ARGUMENT _TYPE . STRING ] ,
isRequired : true ,
2024-09-25 23:33:00 +02:00
enumProvider : extensionNamesEnumProvider ,
2024-09-25 23:18:37 +02:00
} ) ,
] ,
helpString : `
< div >
Checks if a specified extension exists .
< / d i v >
< div >
< strong > Example : < / s t r o n g >
< ul >
< li >
2024-09-25 23:33:00 +02:00
< pre > < code class = "language-stscript" > / e x t e n s i o n - e x i s t s S i l l y T a v e r n - L A L i b < / c o d e > < / p r e >
2024-09-25 23:18:37 +02:00
< / l i >
< / u l >
< / d i v >
` ,
} ) ) ;
SlashCommandParser . addCommandObject ( SlashCommand . fromProps ( {
name : 'reload-page' ,
callback : async ( ) => {
toastr . info ( 'Reloading the page...' ) ;
location . reload ( ) ;
return '' ;
} ,
helpString : 'Reloads the current page. All further commands will not be processed.' ,
} ) ) ;
}