/** * 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.} extension - List of installed extensions */ const extensions: Record = {} /** * 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.} All extension objects * @alias extensionManager.getAllExtensions */ export function getAllExtensions() { return Object.values(extensions) } /** * Get list of active extension objects. * @returns {Array.} 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 = {} 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.} 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.>} 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.} 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. */