nl_tokens: Returns a promise .
pl_tokens: function installPluginsFromConfigXML ( args ) { events . emit ( 'verbose' , 'Checking for saved plugins that haven\'t been added to the project' ) ; const projectRoot = cordova_util . getProjectRoot ( ) ; const pluginsRoot = path . join ( projectRoot , 'plugins' ) ; const pkgJsonPath = path . join ( projectRoot , 'package.json' ) ; const confXmlPath = cordova_util . projectConfig ( projectRoot ) ; let pkgJson = { } ; let indent = '  ' ; if ( fs . existsSync ( pkgJsonPath ) ) { const fileData = fs . readFileSync ( pkgJsonPath , 'utf8' ) ; indent = detectIndent ( fileData ) . indent ; pkgJson = JSON . parse ( fileData ) ; } pkgJson . devDependencies = pkgJson . devDependencies || { } ; pkgJson . cordova = pkgJson . cordova || { } ; pkgJson . cordova . plugins = pkgJson . cordova . plugins || { } ; const pkgPluginIDs = Object . keys ( pkgJson . cordova . plugins ) ; const pkgSpecs = Object . assign ( { } , pkgJson . dependencies , pkgJson . devDependencies ) ; // Check for plugins listed in config.xml const cfg = new ConfigParser ( confXmlPath ) ; const cfgPluginIDs = cfg . getPluginIdList ( ) ; cfgPluginIDs . forEach ( plID => { // If package.json includes the plugin, we use that config // Otherwise, we need to add the plugin to package.json if ( ! pkgPluginIDs . includes ( plID ) ) { events . emit ( 'info' , ` ${ plID } ` ) ; const cfgPlugin = cfg . getPlugin ( plID ) ; // If config.xml has a spec for the plugin and package.json has not, // add the spec to devDependencies of package.json if ( cfgPlugin . spec && ! ( plID <mask> pkgSpecs ) ) { pkgJson . devDependencies [ plID ] = cfgPlugin . spec ; } pkgJson . cordova . plugins [ plID ] = Object . assign ( { } , cfgPlugin . variables ) ; } } ) ; // Now that plugins have been updated, re-fetch them from package.json const pluginIDs = Object . keys ( pkgJson . cordova . plugins ) ; if ( pluginIDs . length !== pkgPluginIDs . length ) { // We've modified package.json and need to save it fs . outputJsonSync ( pkgJsonPath , pkgJson , { indent : indent , encoding : 'utf8' } ) ; } const specs = Object . assign ( { } , pkgJson . dependencies , pkgJson . devDependencies ) ; const plugins = pluginIDs . map ( plID => ( { name : plID , spec : specs [ plID ] , variables : pkgJson . cordova . plugins [ plID ] || { } } ) ) ; let pluginName = '' ; // CB-9560 : Run `plugin add` serially, one plugin after another // We need to wait for the plugin and its dependencies to be installed // before installing the next root plugin otherwise we can have common // plugin dependencies installed twice which throws a nasty error. return promiseutil . Q_chainmap_graceful ( plugins , function ( pluginConfig ) { pluginName = pluginConfig . name ; const pluginPath = path . join ( pluginsRoot , pluginName ) ; if ( fs . existsSync ( pluginPath ) ) { // Plugin already exists return Promise . resolve ( ) ; } events . emit ( 'log' , ` ${ pluginName } ` ) ; // Install from given URL if defined or using a plugin id. If spec isn't a valid version or version range, // assume it is the location to install from. // CB-10761 If plugin spec is not specified, use plugin name var installFrom = pluginConfig . spec || pluginName ; if ( pluginConfig . spec && semver . validRange ( pluginConfig . spec , true ) ) { installFrom = pluginName + '@' + pluginConfig . spec ; } // Add feature preferences as CLI variables if have any var options = { cli_variables : pluginConfig . variables , searchpath : args . searchpath , save : args . save || false } ; const plugin = require ( './plugin' ) ; return plugin ( 'add' , installFrom , options ) ; } , function ( error ) { // CB-10921 emit a warning in case of error var msg = 'Failed to restore plugin "' + pluginName + '" from config.xml. ' + 'You might need to try adding it again. Error: ' + error ; process . exitCode = 1 ; events . emit ( 'warn' , msg ) ; } ) ; }