Louis 1143bd3846
refactor: jan extensions (#799)
* refactor: rename plugin to extension
2023-12-01 11:30:29 +07:00

136 lines
4.2 KiB
TypeScript

/**
* Provides access to the extensions stored by Extension Store
* @typedef {Object} extensionManager
* @prop {getExtension} getExtension
* @prop {getAllExtensions} getAllExtensions
* @prop {getActiveExtensions} getActiveExtensions
* @prop {installExtensions} installExtensions
* @prop {removeExtension} removeExtension
*/
import { writeFileSync } from 'fs'
import Extension from './extension'
import { ExtensionManager } from './../managers/extension'
/**
* @module store
* @private
*/
/**
* Register of installed extensions
* @type {Object.<string, Extension>} extension - List of installed extensions
*/
const extensions: Record<string, Extension> = {}
/**
* Get a extension from the stored extensions.
* @param {string} name Name of the extension to retrieve
* @returns {Extension} Retrieved extension
* @alias extensionManager.getExtension
*/
export function getExtension(name: string) {
if (!Object.prototype.hasOwnProperty.call(extensions, name)) {
throw new Error(`Extension ${name} does not exist`)
}
return extensions[name]
}
/**
* Get list of all extension objects.
* @returns {Array.<Extension>} All extension objects
* @alias extensionManager.getAllExtensions
*/
export function getAllExtensions() {
return Object.values(extensions)
}
/**
* Get list of active extension objects.
* @returns {Array.<Extension>} Active extension objects
* @alias extensionManager.getActiveExtensions
*/
export function getActiveExtensions() {
return Object.values(extensions).filter((extension) => extension.active)
}
/**
* Remove extension from store and maybe save stored extensions to file
* @param {string} name Name of the extension to remove
* @param {boolean} persist Whether to save the changes to extensions to file
* @returns {boolean} Whether the delete was successful
* @alias extensionManager.removeExtension
*/
export function removeExtension(name: string, persist = true) {
const del = delete extensions[name]
if (persist) persistExtensions()
return del
}
/**
* Add extension to store and maybe save stored extensions to file
* @param {Extension} extension Extension to add to store
* @param {boolean} persist Whether to save the changes to extensions to file
* @returns {void}
*/
export function addExtension(extension: Extension, persist = true) {
if (extension.name) extensions[extension.name] = extension
if (persist) {
persistExtensions()
extension.subscribe('pe-persist', persistExtensions)
}
}
/**
* Save stored extensions to file
* @returns {void}
*/
export function persistExtensions() {
const persistData: Record<string, Extension> = {}
for (const name in extensions) {
persistData[name] = extensions[name]
}
writeFileSync(
ExtensionManager.instance.getExtensionsFile(),
JSON.stringify(persistData),
'utf8'
)
}
/**
* Create and install a new extension for the given specifier.
* @param {Array.<installOptions | string>} extensions A list of NPM specifiers, or installation configuration objects.
* @param {boolean} [store=true] Whether to store the installed extensions in the store
* @returns {Promise.<Array.<Extension>>} New extension
* @alias extensionManager.installExtensions
*/
export async function installExtensions(extensions: any, store = true) {
const installed: Extension[] = []
for (const ext of extensions) {
// Set install options and activation based on input type
const isObject = typeof ext === 'object'
const spec = isObject ? [ext.specifier, ext] : [ext]
const activate = isObject ? ext.activate !== false : true
// Install and possibly activate extension
const extension = new Extension(...spec)
await extension._install()
if (activate) extension.setActive(true)
// Add extension to store if needed
if (store) addExtension(extension)
installed.push(extension)
}
// Return list of all installed extensions
return installed
}
/**
* @typedef {Object.<string, any>} installOptions The {@link https://www.npmjs.com/package/pacote|pacote}
* options used to install the extension with some extra options.
* @param {string} specifier the NPM specifier that identifies the package.
* @param {boolean} [activate] Whether this extension should be activated after installation. Defaults to true.
*/