import buildDebug from 'debug' ; import _ from 'lodash' ; import Path from 'path' ; import { logger } from '@verdaccio/logger' ; import { Config , IPlugin } from '@verdaccio/types' ; const debug = buildDebug ( 'verdaccio:plugin:loader' ) ; export const MODULE_NOT_FOUND = 'MODULE_NOT_FOUND' ; param { * } path return { Object } function tryLoad ( path ) { try { return require ( path ) ; } catch ( err ) { if ( err . code === MODULE_NOT_FOUND ) { return null ; } throw err ; } } function mergeConfig ( appConfig , pluginConfig ) { return _ . merge ( appConfig , pluginConfig ) ; } function isValid ( plugin ) { return _ . isFunction ( plugin ) || _ . isFunction ( plugin . default ) ; } function isES6 ( plugin ) { return Object . keys ( plugin ) . includes ( 'default' ) ; } param { * } config param { * } pluginConfigs param { * } params param { * } sanityCheck return { Array } export function loadPlugin < T extends IPlugin < T > > ( config , pluginConfigs = { } , params , sanityCheck , prefix = 'verdaccio' ) { return Object . keys ( pluginConfigs ) . map ( ( pluginId ) : IPlugin < T > => { let plugin ; const localPlugin = Path . resolve ( __dirname + '/../plugins' , pluginId ) ; plugin = tryLoad ( localPlugin ) ; if ( plugin === null && config . plugins ) { const pluginDir = config . plugins ; const externalFilePlugin = Path . resolve ( pluginDir , pluginId ) ; plugin = tryLoad ( externalFilePlugin ) ; if ( plugin === null && pluginId . match ( /^[^\.\/]/ ) ) { plugin = tryLoad ( Path . resolve ( pluginDir , `${ prefix }-${ pluginId }` ) ) ; if ( ! plugin ) { plugin = tryLoad ( Path . resolve ( pluginDir , `sinopia-${ pluginId }` ) ) ; } } } if ( plugin === null && pluginId . match ( /^[^\.\/]/ ) ) { plugin = tryLoad ( `${ prefix }-${ pluginId }` ) ; if ( ! plugin ) { plugin = tryLoad ( `sinopia-${ pluginId }` ) ; } } if ( plugin === null ) { plugin = tryLoad ( pluginId ) ; } if ( plugin === null && pluginId . match ( /^\.\.?($|\/)/ ) ) { plugin = tryLoad ( Path . resolve ( Path . dirname ( config . config_path ) , pluginId ) ) ; } if ( plugin === null ) { logger . error ( { content : pluginId , prefix } , 'plugin not found. try npm install @{prefix}-@{content}' ) ; throw Error ( `
        ${ prefix }-${ pluginId } plugin not found. try "npm install ${ prefix }-${ pluginId }"` ) ; } if ( ! isValid ( plugin ) ) { logger . error ( { content : pluginId } , '@{prefix}-@{content} plugin does not have the right code structure' ) ; throw Error ( `"${ pluginId }" plugin does not have the right code structure` ) ; } try { plugin = isES6 ( plugin ) ? new plugin . default ( mergeConfig ( config , pluginConfigs [ pluginId ] ) , params ) : plugin ( pluginConfigs [ pluginId ] , params ) ; } catch ( error ) { plugin = null ; logger . error ( { error , pluginId } , 'error loading a plugin @{pluginId}: @{error}' ) ; } if ( plugin === null || ! sanityCheck ( plugin ) ) { logger . error ( { content : pluginId , prefix } , "@{prefix}-@{content} doesn't look like a valid plugin" ) ; throw Error ( `sanity check has failed, "${ pluginId }" is not a valid plugin` ) ; } debug ( 'Plugin successfully loaded: %o-%o' , pluginId , prefix ) ; return plugin ; } ) ; }