Input: callbackOptions param represents additional optional parameters command could pass back like keepCallback or custom callbackId for example { callbackId : id keepCallback : true status : cordova . callbackStatus . JSON_EXCEPTION } [CODESPLIT] function ( result , callbackOptions ) { callbackOptions = callbackOptions || { } ; var callbackStatus ; // covering both undefined and null. // strict null comparison was causing callbackStatus to be undefined // and then no callback was called because of the check in cordova.callbackFromNative // see CB-8996 Mobilespec app hang on windows if ( callbackOptions . status !== undefined && callbackOptions . status !== null ) { callbackStatus = callbackOptions . status ; } else { callbackStatus = cordova . callbackStatus . OK ; } cordova . callbackSuccess ( callbackOptions . callbackId || callbackId , { status : callbackStatus , message : result , keepCallback : callbackOptions . keepCallback || false } ) ; }


Input: Returns all the platforms that are currently saved into config . xml [CODESPLIT] function getPlatforms ( projectRoot ) { var xml = cordova_util . projectConfig ( projectRoot ) ; var cfg = new ConfigParser ( xml ) ; // If an engine's 'version' property is really its source, map that to the appropriate field. var engines = cfg . getEngines ( ) . map ( function ( engine ) { var result = { name : engine . name } ; if ( semver . validRange ( engine . spec , true ) ) { result . version = engine . spec ; } else { result . src = engine . spec ; } return result ; } ) ; return Promise . resolve ( engines ) ; }


Input: Returns all the plugins that are currently saved into config . xml [CODESPLIT] function getPlugins ( projectRoot ) { var xml = cordova_util . projectConfig ( projectRoot ) ; var cfg = new ConfigParser ( xml ) ; // Map variables object to an array var plugins = cfg . getPlugins ( ) . map ( function ( plugin ) { var result = { name : plugin . name } ; if ( semver . validRange ( plugin . spec , true ) ) { result . version = plugin . spec ; } else { result . src = plugin . spec ; } var variablesObject = plugin . variables ; var variablesArray = [ ] ; if ( variablesObject ) { for ( var variable in variablesObject ) { variablesArray . push ( { name : variable , value : variablesObject [ variable ] } ) ; } } result . variables = variablesArray ; return result ; } ) ; return Promise . resolve ( plugins ) ; }


Input: getPlatformApi () should be the only method of instantiating the PlatformProject classes for now . [CODESPLIT] function getPlatformApi ( platform , platformRootDir ) { // if platformRootDir is not specified, try to detect it first if ( ! platformRootDir ) { var projectRootDir = util . isCordova ( ) ; platformRootDir = projectRootDir && path . join ( projectRootDir , 'platforms' , platform ) ; } if ( ! platformRootDir ) { // If platformRootDir is still undefined, then we're probably is not inside of cordova project throw new Error ( 'Current location is not a Cordova project' ) ; } // CB-11174 Resolve symlinks first before working with root directory platformRootDir = util . convertToRealPathSafe ( platformRootDir ) ; // Make sure the platforms/platform folder exists if ( ! fs . existsSync ( platformRootDir ) ) { throw new Error ( 'The platform "' + platform + '" does not appear to have been added to this project.' ) ; } var platformApi ; var cached = cachedApis [ platformRootDir ] ; var libDir = path . join ( platformRootDir , 'cordova' , 'Api.js' ) ; if ( cached && cached . platform === platform ) { platformApi = cached ; } else { var PlatformApi = util . getPlatformApiFunction ( libDir , platform ) ; platformApi = new PlatformApi ( platform , platformRootDir , events ) ; cachedApis [ platformRootDir ] = platformApi ; } return platformApi ; }


Input: Returns a list of top - level plugins which are ( transitively ) dependent on the given plugin . [CODESPLIT] function ( plugin_id , plugins_dir , platformJson , pluginInfoProvider ) { var depsInfo ; if ( typeof plugins_dir === 'object' ) { depsInfo = plugins_dir ; } else { depsInfo = pkg . generateDependencyInfo ( platformJson , plugins_dir , pluginInfoProvider ) ; } var graph = depsInfo . graph ; var tlps = depsInfo . top_level_plugins ; var dependents = tlps . filter ( function ( tlp ) { return tlp !== plugin_id && graph . getChain ( tlp ) . indexOf ( plugin_id ) >= 0 ; } ) ; return dependents ; }


Input: Returns a list of plugins which the given plugin depends on for which it is the only dependent . In other words if the given plugin were deleted these dangling dependencies should be deleted too . [CODESPLIT] function ( plugin_id , plugins_dir , platformJson , pluginInfoProvider ) { var depsInfo ; if ( typeof plugins_dir === 'object' ) { depsInfo = plugins_dir ; } else { depsInfo = pkg . generateDependencyInfo ( platformJson , plugins_dir , pluginInfoProvider ) ; } var graph = depsInfo . graph ; var dependencies = graph . getChain ( plugin_id ) ; var tlps = depsInfo . top_level_plugins ; var diff_arr = [ ] ; tlps . forEach ( function ( tlp ) { if ( tlp !== plugin_id ) { diff_arr . push ( graph . getChain ( tlp ) ) ; } } ) ; // if this plugin has dependencies, do a set difference to determine which dependencies are not required by other existing plugins diff_arr . unshift ( dependencies ) ; var danglers = underscore . difference . apply ( null , diff_arr ) ; // Ensure no top-level plugins are tagged as danglers. danglers = danglers && danglers . filter ( function ( x ) { return tlps . indexOf ( x ) < 0 ; } ) ; return danglers ; }


Input: This is a local function that creates the new replacement representing the mutation . Used to save code further down . [CODESPLIT] function createReplacement ( manifestFile , originalChange ) { var replacement = { target : manifestFile , parent : originalChange . parent , after : originalChange . after , xmls : originalChange . xmls , versions : originalChange . versions , deviceTarget : originalChange . deviceTarget } ; return replacement ; }


Input: / * A class for holidng the information currently stored in plugin . xml It s inherited from cordova - common s PluginInfo class In addition it overrides getConfigFiles getEditConfigs getFrameworks methods to use windows - specific logic [CODESPLIT] function PluginInfo ( dirname ) { //  We're not using `util.inherit' because original PluginInfo defines //  its' methods inside of constructor CommonPluginInfo . apply ( this , arguments ) ; var parentGetConfigFiles = this . getConfigFiles ; var parentGetEditConfigs = this . getEditConfigs ; this . getEditConfigs = function ( platform ) { var editConfigs = parentGetEditConfigs ( platform ) ; return processChanges ( editConfigs ) ; } ; this . getConfigFiles = function ( platform ) { var configFiles = parentGetConfigFiles ( platform ) ; return processChanges ( configFiles ) ; } ; }


Input: Helper function for checking expected plugin IDs against reality . [CODESPLIT] function checkID ( expectedIdAndVersion , pinfo ) { if ( ! expectedIdAndVersion ) return ; var parsedSpec = pluginSpec . parse ( expectedIdAndVersion ) ; if ( parsedSpec . id !== pinfo . id ) { throw new Error ( 'Expected plugin to have ID "' + parsedSpec . id + '" but got "' + pinfo . id + '".' ) ; } if ( parsedSpec . version && ! semver . satisfies ( pinfo . version , parsedSpec . version ) ) { throw new Error ( 'Expected plugin ' + pinfo . id + ' to satisfy version "' + parsedSpec . version + '" but got "' + pinfo . version + '".' ) ; } }


Input: If a plugin is fund in local search path return a PluginInfo for it . Ignore plugins that don t satisfy the required version spec . If several versions are present in search path return the latest . Examples of accepted plugin_src strings : org . apache . cordova . file org . apache . cordova . file [CODESPLIT] function findLocalPlugin ( plugin_src , searchpath , pluginInfoProvider ) { loadLocalPlugins ( searchpath , pluginInfoProvider ) ; var parsedSpec = pluginSpec . parse ( plugin_src ) ; var versionspec = parsedSpec . version || '*' ; var latest = null ; var versions = localPlugins . plugins [ parsedSpec . id ] ; if ( ! versions ) return null ; versions . forEach ( function ( pinfo ) { // Ignore versions that don't satisfy the the requested version range. // Ignore -dev suffix because latest semver versions doesn't handle it properly (CB-9421) if ( ! semver . satisfies ( pinfo . version . replace ( / -dev$ / , '' ) , versionspec ) ) { return ; } if ( ! latest ) { latest = pinfo ; return ; } if ( semver . gt ( pinfo . version , latest . version ) ) { latest = pinfo ; } } ) ; return latest ; }


Input: Copy or link a plugin from plugin_dir to plugins_dir / plugin_id . if alternative ID of plugin exists in plugins_dir / plugin_id skip copying [CODESPLIT] function copyPlugin ( pinfo , plugins_dir , link ) { var plugin_dir = pinfo . dir ; var dest = path . join ( plugins_dir , pinfo . id ) ; fs . removeSync ( dest ) ; if ( ! link && dest . indexOf ( path . resolve ( plugin_dir ) + path . sep ) === 0 ) { events . emit ( 'verbose' , 'Copy plugin destination is child of src. Forcing --link mode.' ) ; link = true ; } if ( link ) { var isRelativePath = plugin_dir . charAt ( 1 ) !== ':' && plugin_dir . charAt ( 0 ) !== path . sep ; var fixedPath = isRelativePath ? path . join ( path . relative ( plugins_dir , process . env . PWD || process . cwd ( ) ) , plugin_dir ) : plugin_dir ; events . emit ( 'verbose' , 'Linking "' + dest + '" => "' + fixedPath + '"' ) ; fs . symlinkSync ( fixedPath , dest , 'junction' ) ; } else { events . emit ( 'verbose' , 'Copying plugin "' + plugin_dir + '" => "' + dest + '"' ) ; fs . copySync ( plugin_dir , dest , { dereference : true } ) ; } return dest ; }


Input: / * Deletes plugin from plugins directory and node_modules directory . [CODESPLIT] function ( id ) { var plugin_dir = path . join ( plugins_dir , id ) ; if ( ! fs . existsSync ( plugin_dir ) ) { events . emit ( 'verbose' , 'Plugin "' + id + '" already removed (' + plugin_dir + ')' ) ; return Promise . resolve ( ) ; } fs . removeSync ( plugin_dir ) ; events . emit ( 'verbose' , 'Deleted plugin "' + id + '"' ) ; // remove plugin from node_modules directory return npmUninstall ( id , options . projectRoot , options ) ; }


Input: possible options : cli_variables www_dir is_top_level Returns a promise [CODESPLIT] function runUninstallPlatform ( actions , platform , project_dir , plugin_dir , plugins_dir , options ) { var pluginInfoProvider = options . pluginInfoProvider ; // If this plugin is not really installed, return (CB-7004). if ( ! fs . existsSync ( plugin_dir ) ) { return Promise . resolve ( true ) ; } var pluginInfo = pluginInfoProvider . get ( plugin_dir ) ; var plugin_id = pluginInfo . id ; // Merge cli_variables and plugin.xml variables var variables = variableMerge . mergeVariables ( plugin_dir , platform , options ) ; // Deps info can be passed recusively var platformJson = PlatformJson . load ( plugins_dir , platform ) ; var depsInfo = options . depsInfo || dependencies . generateDependencyInfo ( platformJson , plugins_dir , pluginInfoProvider ) ; // Check that this plugin has no dependents. var dependents = dependencies . dependents ( plugin_id , depsInfo , platformJson , pluginInfoProvider ) ; if ( options . is_top_level && dependents && dependents . length > 0 ) { var msg = 'The plugin \'' + plugin_id + '\' is required by (' + dependents . join ( ', ' ) + ')' ; if ( options . force ) { events . emit ( 'warn' , msg + ' but forcing removal' ) ; } else { return Promise . reject ( new CordovaError ( msg + ', skipping uninstallation. (try --force if trying to update)' ) ) ; } } // Check how many dangling dependencies this plugin has. var deps = depsInfo . graph . getChain ( plugin_id ) ; var danglers = dependencies . danglers ( plugin_id , depsInfo , platformJson , pluginInfoProvider ) ; var promise ; if ( deps && deps . length && danglers && danglers . length ) { // @tests - important this event is checked spec/uninstall.spec.js events . emit ( 'log' , 'Uninstalling ' + danglers . length + ' dependent plugins.' ) ; promise = promiseutil . Q_chainmap ( danglers , function ( dangler ) { var dependent_path = path . join ( plugins_dir , dangler ) ; var opts = underscore . extend ( { } , options , { is_top_level : depsInfo . top_level_plugins . indexOf ( dangler ) > - 1 , depsInfo : depsInfo } ) ; return runUninstallPlatform ( actions , platform , project_dir , dependent_path , plugins_dir , opts ) ; } ) ; } else { promise = Promise . resolve ( ) ; } var projectRoot = cordovaUtil . isCordova ( ) ; if ( projectRoot ) { // CB-10708 This is the case when we're trying to uninstall plugin using plugman from specific // platform inside of the existing CLI project. This option is usually set by cordova-lib for CLI projects // but since we're running this code through plugman, we need to set it here implicitly options . usePlatformWww = true ; options . cli_variables = variables ; } return promise . then ( function ( ) { if ( ! projectRoot ) return ; var hooksRunner = new HooksRunner ( projectRoot ) ; var hooksRunnerOptions = { cordova : { platforms : [ platform ] } , plugin : { id : pluginInfo . id , pluginInfo : pluginInfo , platform : platform , dir : plugin_dir } } ; return hooksRunner . fire ( 'before_plugin_uninstall' , hooksRunnerOptions ) ; } ) . then ( function ( ) { return handleUninstall ( actions , platform , pluginInfo , project_dir , options . www_dir , plugins_dir , options . is_top_level , options ) ; } ) ; }


Input: Returns a promise . [CODESPLIT] function handleUninstall ( actions , platform , pluginInfo , project_dir , www_dir , plugins_dir , is_top_level , options ) { events . emit ( 'log' , 'Uninstalling ' + pluginInfo . id + ' from ' + platform ) ; // Set up platform to uninstall asset files/js modules // from <platform>/platform_www dir instead of <platform>/www. options . usePlatformWww = true ; return platform_modules . getPlatformApi ( platform , project_dir ) . removePlugin ( pluginInfo , options ) . then ( function ( result ) { // Remove plugin from installed list. This already done in platform, // but need to be duplicated here to remove plugin entry from project's // plugin list to manage dependencies properly. PlatformJson . load ( plugins_dir , platform ) . removePlugin ( pluginInfo . id , is_top_level ) . save ( ) ; // CB-11022 propagate `removePlugin` result to the caller return Promise . resolve ( result ) ; } ) ; }


Input: Gets platform details from a directory [CODESPLIT] function getPlatformDetailsFromDir ( dir , platformIfKnown ) { var libDir = path . resolve ( dir ) ; var platform ; var version ; // console.log("getPlatformDetailsFromDir : ", dir, platformIfKnown, libDir); try { var pkgPath = path . join ( libDir , 'package.json' ) ; var pkg = cordova_util . requireNoCache ( pkgPath ) ; platform = module . exports . platformFromName ( pkg . name ) ; version = pkg . version ; } catch ( e ) { return Promise . reject ( new CordovaError ( 'The provided path does not seem to contain a valid package.json or a valid Cordova platform: ' + libDir ) ) ; } // platform does NOT have to exist in 'platforms', but it should have a name, and a version if ( ! version || ! platform ) { return Promise . reject ( new CordovaError ( 'The provided path does not seem to contain a ' + 'Cordova platform: ' + libDir ) ) ; } return Promise . resolve ( { libDir : libDir , platform : platform , version : version } ) ; }


Input: Removes the cordova - prefix from the platform s name for known platforms . [CODESPLIT] function platformFromName ( name ) { var platName = name ; var platMatch = / ^cordova-([a-z0-9-]+)$ / . exec ( name ) ; if ( platMatch && ( platMatch [ 1 ] in platforms ) ) { platName = platMatch [ 1 ] ; events . emit ( 'verbose' , 'Removing "cordova-" prefix from ' + name ) ; } return platName ; }


Input: Processes a single message as encoded by NativeToJsMessageQueue . java . [CODESPLIT] function processMessage ( message ) { var firstChar = message . charAt ( 0 ) ; if ( firstChar == 'J' ) { // This is deprecated on the .java side. It doesn't work with CSP enabled. eval ( message . slice ( 1 ) ) ; } else if ( firstChar == 'S' || firstChar == 'F' ) { var success = firstChar == 'S' ; var keepCallback = message . charAt ( 1 ) == '1' ; var spaceIdx = message . indexOf ( ' ' , 2 ) ; var status = + message . slice ( 2 , spaceIdx ) ; var nextSpaceIdx = message . indexOf ( ' ' , spaceIdx + 1 ) ; var callbackId = message . slice ( spaceIdx + 1 , nextSpaceIdx ) ; var payloadMessage = message . slice ( nextSpaceIdx + 1 ) ; var payload = [ ] ; buildPayload ( payload , payloadMessage ) ; cordova . callbackFromNative ( callbackId , success , status , payload , keepCallback ) ; } else { console . log ( "processMessage failed: invalid message: " + JSON . stringify ( message ) ) ; } }


Input: possible options : subdir cli_variables www_dir git_ref is_top_level Returns a promise . [CODESPLIT] function possiblyFetch ( id , plugins_dir , options ) { var parsedSpec = pluginSpec . parse ( id ) ; // if plugin is a relative path, check if it already exists var plugin_src_dir = isAbsolutePath ( id ) ? id : path . join ( plugins_dir , parsedSpec . id ) ; // Check that the plugin has already been fetched. if ( fs . existsSync ( plugin_src_dir ) ) { return Promise . resolve ( plugin_src_dir ) ; } var opts = underscore . extend ( { } , options , { client : 'plugman' } ) ; // TODO: without runtime require below, we have a circular dependency. return require ( './plugman' ) . fetch ( id , plugins_dir , opts ) ; }


Input: exec engine scripts in order to get the current engine version Returns a promise for the array of engines . [CODESPLIT] function callEngineScripts ( engines , project_dir ) { return Promise . all ( engines . map ( function ( engine ) { // CB-5192; on Windows scriptSrc doesn't have file extension so we shouldn't check whether the script exists var scriptPath = engine . scriptSrc || null ; if ( scriptPath && ( isWindows || fs . existsSync ( engine . scriptSrc ) ) ) { if ( ! isWindows ) { // not required on Windows fs . chmodSync ( engine . scriptSrc , '755' ) ; } return superspawn . spawn ( scriptPath ) . then ( stdout => { engine . currentVersion = cleanVersionOutput ( stdout , engine . name ) ; if ( engine . currentVersion === '' ) { events . emit ( 'warn' , engine . name + ' version check returned nothing (' + scriptPath + '), continuing anyways.' ) ; engine . currentVersion = null ; } } , ( ) => { events . emit ( 'warn' , engine . name + ' version check failed (' + scriptPath + '), continuing anyways.' ) ; engine . currentVersion = null ; } ) . then ( _ => engine ) ; } else { if ( engine . currentVersion ) { engine . currentVersion = cleanVersionOutput ( engine . currentVersion , engine . name ) ; } else { events . emit ( 'warn' , engine . name + ' version not detected (lacks script ' + scriptPath + ' ), continuing.' ) ; } return Promise . resolve ( engine ) ; } } ) ) ; }


Input: Copy or link a plugin from plugin_dir to plugins_dir / plugin_id . [CODESPLIT] function copyPlugin ( plugin_src_dir , plugins_dir , link , pluginInfoProvider ) { var pluginInfo = new PluginInfo ( plugin_src_dir ) ; var dest = path . join ( plugins_dir , pluginInfo . id ) ; if ( link ) { events . emit ( 'verbose' , 'Symlinking from location "' + plugin_src_dir + '" to location "' + dest + '"' ) ; fs . removeSync ( dest ) ; fs . ensureSymlinkSync ( plugin_src_dir , dest , 'junction' ) ; } else { events . emit ( 'verbose' , 'Copying from location "' + plugin_src_dir + '" to location "' + dest + '"' ) ; fs . copySync ( plugin_src_dir , dest ) ; } pluginInfo . dir = dest ; pluginInfoProvider . put ( pluginInfo ) ; return dest ; }


Input: Class that acts as abstraction over particular platform . Encapsulates the platform s properties and methods . [CODESPLIT] function Api ( platform , platformRootDir , events ) { this . platform = PLATFORM ; this . root = path . resolve ( __dirname , '..' ) ; setupEvents ( events ) ; var self = this ; this . locations = { root : self . root , www : path . join ( self . root , 'assets/www' ) , res : path . join ( self . root , 'res' ) , platformWww : path . join ( self . root , 'platform_www' ) , configXml : path . join ( self . root , 'res/xml/config.xml' ) , defaultConfigXml : path . join ( self . root , 'cordova/defaults.xml' ) , strings : path . join ( self . root , 'res/values/strings.xml' ) , manifest : path . join ( self . root , 'AndroidManifest.xml' ) , build : path . join ( self . root , 'build' ) , // NOTE: Due to platformApi spec we need to return relative paths here cordovaJs : 'bin/templates/project/assets/www/cordova.js' , cordovaJsSrc : 'cordova-js-src' } ; // XXX Override some locations for Android Studio projects if ( AndroidStudio . isAndroidStudioProject ( self . root ) === true ) { selfEvents . emit ( 'log' , 'Android Studio project detected' ) ; this . android_studio = true ; this . locations . configXml = path . join ( self . root , 'app/src/main/res/xml/config.xml' ) ; this . locations . strings = path . join ( self . root , 'app/src/main/res/xml/strings.xml' ) ; this . locations . manifest = path . join ( self . root , 'app/src/main/AndroidManifest.xml' ) ; this . locations . www = path . join ( self . root , 'app/src/main/assets/www' ) ; this . locations . res = path . join ( self . root , 'app/src/main/res' ) ; } }


Input: returns a promise [CODESPLIT] function createPackageJson ( plugin_path ) { var pluginInfo = new PluginInfo ( plugin_path ) ; var defaults = { id : pluginInfo . id , version : pluginInfo . version , description : pluginInfo . description , license : pluginInfo . license , keywords : pluginInfo . getKeywordsAndPlatforms ( ) , repository : pluginInfo . repo , engines : pluginInfo . getEngines ( ) , platforms : pluginInfo . getPlatformsArray ( ) } ; var initFile = require . resolve ( './init-defaults' ) ; return initPkgJson ( plugin_path , initFile , defaults ) . then ( _ => { events . emit ( 'verbose' , 'Package.json successfully created' ) ; } ) ; }


Input: Calls platformApi . prepare for each platform in project [CODESPLIT] function preparePlatforms ( platformList , projectRoot , options ) { return Promise . all ( platformList . map ( function ( platform ) { // TODO: this need to be replaced by real projectInfo // instance for current project. var project = { root : projectRoot , projectConfig : new ConfigParser ( cordova_util . projectConfig ( projectRoot ) ) , locations : { plugins : path . join ( projectRoot , 'plugins' ) , www : cordova_util . projectWww ( projectRoot ) , rootConfigXml : cordova_util . projectConfig ( projectRoot ) } } ; // CB-9987 We need to reinstall the plugins for the platform it they were added by cordova@<5.4.0 return module . exports . restoreMissingPluginsForPlatform ( platform , projectRoot , options ) . then ( function ( ) { // platformApi prepare takes care of all functionality // which previously had been executed by cordova.prepare: //   - reset config.xml and then merge changes from project's one, //   - update www directory from project's one and merge assets from platform_www, //   - reapply config changes, made by plugins, //   - update platform's project // Please note that plugins' changes, such as installed js files, assets and // config changes is not being reinstalled on each prepare. var platformApi = platforms . getPlatformApi ( platform ) ; return platformApi . prepare ( project , _ . clone ( options ) ) . then ( function ( ) { // Handle edit-config in config.xml var platformRoot = path . join ( projectRoot , 'platforms' , platform ) ; var platformJson = PlatformJson . load ( platformRoot , platform ) ; var munger = new PlatformMunger ( platform , platformRoot , platformJson ) ; // the boolean argument below is "should_increment" munger . add_config_changes ( project . projectConfig , true ) . save_all ( ) ; } ) ; } ) ; } ) ) ; }


Input: Class that acts as abstraction over particular platform . Encapsulates the platform s properties and methods . [CODESPLIT] function Api ( platform , platformRootDir , eventEmitter ) { this . platform = PLATFORM ; this . root = path . resolve ( __dirname , '..' ) ; setupEvents ( eventEmitter ) ; var self = this ; this . locations = { root : self . root , www : path . join ( self . root , 'www' ) , platformWww : path . join ( self . root , 'platform_www' ) , configXml : path . join ( self . root , 'config.xml' ) , defaultConfigXml : path . join ( self . root , 'cordova/defaults.xml' ) , // NOTE: Due to platformApi spec we need to return relative paths here cordovaJs : 'template/www/cordova.js' , cordovaJsSrc : 'cordova-js-src' } ; }


Input: / * At this point cli and config vars have already merged . Merges those vars ( cli and config ) with plugin . xml variables . [CODESPLIT] function mergeVariables ( plugin_dir , platform , options ) { options . pluginInfoProvider = options . pluginInfoProvider || new PluginInfoProvider ( ) ; var pluginInfoProvider = options . pluginInfoProvider ; var pluginInfo = pluginInfoProvider . get ( plugin_dir ) ; var filtered_variables = { } ; var prefs = pluginInfo . getPreferences ( platform ) ; var keys = underscore . keys ( prefs ) ; options . cli_variables = options . cli_variables || { } ; var missing_vars = underscore . difference ( keys , Object . keys ( options . cli_variables ) ) ; underscore . each ( missing_vars , function ( _key ) { var def = prefs [ _key ] ; if ( def ) { options . cli_variables [ _key ] = def ; } } ) ; // test missing vars once again after having default missing_vars = underscore . difference ( keys , Object . keys ( options . cli_variables ) ) ; if ( missing_vars . length > 0 ) { throw new Error ( 'Variable(s) missing: ' + missing_vars . join ( ', ' ) ) ; } filtered_variables = underscore . pick ( options . cli_variables , keys ) ; return filtered_variables ; }


Input: Consturct the default value for versionCode as PATCH + MINOR * 100 + MAJOR * 10000 see http : // developer . android . com / tools / publishing / versioning . html [CODESPLIT] function default_versionCode ( version ) { var nums = version . split ( '-' ) [ 0 ] . split ( '.' ) ; var versionCode = 0 ; if ( + nums [ 0 ] ) { versionCode += + nums [ 0 ] * 10000 ; } if ( + nums [ 1 ] ) { versionCode += + nums [ 1 ] * 100 ; } if ( + nums [ 2 ] ) { versionCode += + nums [ 2 ] ; } events . emit ( 'verbose' , 'android-versionCode not found in config.xml. Generating a code based on version in config.xml (' + version + '): ' + versionCode ) ; return versionCode ; }


Input: find the best matching icon for a given density or size [CODESPLIT] function ( icon , icon_size ) { // do I have a platform icon for that density already var density = icon . density || sizeToDensityMap [ icon_size ] ; if ( ! density ) { // invalid icon defition ( or unsupported size) return ; } var previous = android_icons [ density ] ; if ( previous && previous . platform ) { return ; } android_icons [ density ] = icon ; }


Input: Gets a map containing resources of a specified name from all drawable folders in a directory . [CODESPLIT] function mapImageResources ( rootDir , subDir , type , resourceName ) { var pathMap = { } ; shell . ls ( path . join ( rootDir , subDir , type + '-*' ) ) . forEach ( function ( drawableFolder ) { var imagePath = path . join ( subDir , path . basename ( drawableFolder ) , resourceName ) ; pathMap [ imagePath ] = null ; } ) ; return pathMap ; }


Input: Gets and validates AndroidLaunchMode prepference from config . xml . Returns preference value and warns if it doesn t seems to be valid [CODESPLIT] function findAndroidLaunchModePreference ( platformConfig ) { var launchMode = platformConfig . getPreference ( 'AndroidLaunchMode' ) ; if ( ! launchMode ) { // Return a default value return 'singleTop' ; } var expectedValues = [ 'standard' , 'singleTop' , 'singleTask' , 'singleInstance' ] ; var valid = expectedValues . indexOf ( launchMode ) >= 0 ; if ( ! valid ) { // Note: warn, but leave the launch mode as developer wanted, in case the list of options changes in the future events . emit ( 'warn' , 'Unrecognized value for AndroidLaunchMode preference: ' + launchMode + '. Expected values are: ' + expectedValues . join ( ', ' ) ) ; } return launchMode ; }


Input: Wraps an AndroidManifest file [CODESPLIT] function AndroidManifest ( path ) { this . path = path ; this . doc = xml . parseElementtreeSync ( path ) ; if ( this . doc . getroot ( ) . tag !== 'manifest' ) { throw new Error ( 'AndroidManifest at ' + path + ' has incorrect root node name (expected "manifest")' ) ; } }


Input: Checks the warnings that were printed by the CLI to ensure that the code is listing the correct reasons for failure . Checks against the global warnings object which is reset before each test [CODESPLIT] function expectUnmetRequirements ( expected ) { const actual = unmetRequirementsCollector . store ; expect ( actual ) . toEqual ( jasmine . arrayWithExactContents ( expected ) ) ; }


Input: Gets the version of a plugin that should be fetched for a given project based on the plugin s engine information from NPM and the platforms / plugins installed in the project . The cordovaDependencies object in the package . json s engines entry takes the form of an object that maps plugin versions to a series of constraints and semver ranges . For example : [CODESPLIT] function getFetchVersion ( projectRoot , pluginInfo , cordovaVersion ) { // Figure out the project requirements if ( pluginInfo . engines && pluginInfo . engines . cordovaDependencies ) { // grab array of already installed plugins var pluginList = plugin_util . getInstalledPlugins ( projectRoot ) ; var pluginMap = { } ; pluginList . forEach ( function ( plugin ) { pluginMap [ plugin . id ] = plugin . version ; } ) ; return cordova_util . getInstalledPlatformsWithVersions ( projectRoot ) . then ( function ( platformVersions ) { return module . exports . determinePluginVersionToFetch ( pluginInfo , pluginMap , platformVersions , cordovaVersion ) ; } ) ; } else { // If we have no engine, we want to fall back to the default behavior events . emit ( 'verbose' , 'npm info for ' + pluginInfo . name + ' did not contain any engine info. Fetching latest release' ) ; return Promise . resolve ( null ) ; } }


Input: / * The engine entry maps plugin versions to constraints like so : { 1 . 0 . 0 : { cordova : <5 . 0 . 0 } <2 . 0 . 0 : { cordova : > = 5 . 0 . 0 cordova - ios : ~5 . 0 . 0 cordova - plugin - camera : ~5 . 0 . 0 } 3 . 0 . 0 : { cordova - ios : > 5 . 0 . 0 } } [CODESPLIT] function determinePluginVersionToFetch ( pluginInfo , pluginMap , platformMap , cordovaVersion ) { var allVersions = pluginInfo . versions ; var engine = pluginInfo . engines . cordovaDependencies ; var name = pluginInfo . name ; // Filters out pre-release versions var latest = semver . maxSatisfying ( allVersions , '>=0.0.0' ) ; var versions = [ ] ; var upperBound = null ; var upperBoundRange = null ; var upperBoundExists = false ; // TODO: lots of 'versions' being thrown around in this function: cordova version, // platform version, plugin version. The below for loop: what version is it // iterating over? plugin version? please clarify the variable name. for ( var version in engine ) { // if a single version && less than latest if ( semver . valid ( semver . clean ( version ) ) && semver . lte ( version , latest ) ) { versions . push ( version ) ; } else { // Check if this is an upperbound; validRange() handles whitespace var cleanedRange = semver . validRange ( version ) ; if ( cleanedRange && UPPER_BOUND_REGEX . exec ( cleanedRange ) ) { upperBoundExists = true ; // We only care about the highest upper bound that our project does not support if ( module . exports . getFailedRequirements ( engine [ version ] , pluginMap , platformMap , cordovaVersion ) . length !== 0 ) { var maxMatchingUpperBound = cleanedRange . substring ( 1 ) ; if ( maxMatchingUpperBound && ( ! upperBound || semver . gt ( maxMatchingUpperBound , upperBound ) ) ) { upperBound = maxMatchingUpperBound ; upperBoundRange = version ; } } } else { events . emit ( 'verbose' , 'Ignoring invalid version in ' + name + ' cordovaDependencies: ' + version + ' (must be a single version <= latest or an upper bound)' ) ; } } } // If there were no valid requirements, we fall back to old behavior if ( ! upperBoundExists && versions . length === 0 ) { events . emit ( 'verbose' , 'Ignoring ' + name + ' cordovaDependencies entry because it did not contain any valid plugin version entries' ) ; return null ; } // Handle the lower end of versions by giving them a satisfied engine if ( ! module . exports . findVersion ( versions , '0.0.0' ) ) { versions . push ( '0.0.0' ) ; engine [ '0.0.0' ] = { } ; } // Add an entry after the upper bound to handle the versions above the // upper bound but below the next entry. For example: 0.0.0, <1.0.0, 2.0.0 // needs a 1.0.0 entry that has the same engine as 0.0.0 if ( upperBound && ! module . exports . findVersion ( versions , upperBound ) && ! semver . gt ( upperBound , latest ) ) { versions . push ( upperBound ) ; var below = semver . maxSatisfying ( versions , upperBoundRange ) ; // Get the original entry without trimmed whitespace below = below ? module . exports . findVersion ( versions , below ) : null ; engine [ upperBound ] = below ? engine [ below ] : { } ; } // Sort in descending order; we want to start at latest and work back versions . sort ( semver . rcompare ) ; for ( var i = 0 ; i < versions . length ; i ++ ) { if ( upperBound && semver . lt ( versions [ i ] , upperBound ) ) { // Because we sorted in desc. order, if the upper bound we found // applies to this version (and thus the ones below) we can just // quit break ; } var range = i ? ( '>=' + versions [ i ] + ' <' + versions [ i - 1 ] ) : ( '>=' + versions [ i ] ) ; var maxMatchingVersion = semver . maxSatisfying ( allVersions , range ) ; if ( maxMatchingVersion && module . exports . getFailedRequirements ( engine [ versions [ i ] ] , pluginMap , platformMap , cordovaVersion ) . length === 0 ) { // Because we sorted in descending order, we can stop searching once // we hit a satisfied constraint if ( maxMatchingVersion !== latest ) { var failedReqs = module . exports . getFailedRequirements ( engine [ versions [ 0 ] ] , pluginMap , platformMap , cordovaVersion ) ; // Warn the user that we are not fetching latest module . exports . listUnmetRequirements ( name , failedReqs ) ; events . emit ( 'warn' , 'Fetching highest version of ' + name + ' that this project supports: ' + maxMatchingVersion + ' (latest is ' + latest + ')' ) ; } return maxMatchingVersion ; } } // No version of the plugin is satisfied. In this case, we fall back to // fetching the latest version, but also output a warning var latestFailedReqs = versions . length > 0 ? module . exports . getFailedRequirements ( engine [ versions [ 0 ] ] , pluginMap , platformMap , cordovaVersion ) : [ ] ; // If the upper bound is greater than latest, we need to combine its engine // requirements with latest to print out in the warning if ( upperBound && semver . satisfies ( latest , upperBoundRange ) ) { var upperFailedReqs = module . exports . getFailedRequirements ( engine [ upperBoundRange ] , pluginMap , platformMap , cordovaVersion ) ; upperFailedReqs . forEach ( function ( failedReq ) { for ( var i = 0 ; i < latestFailedReqs . length ; i ++ ) { if ( latestFailedReqs [ i ] . dependency === failedReq . dependency ) { // Not going to overcomplicate things and actually merge the ranges latestFailedReqs [ i ] . required += ' AND ' + failedReq . required ; return ; } } // There is no req to merge it with latestFailedReqs . push ( failedReq ) ; } ) ; } module . exports . listUnmetRequirements ( name , latestFailedReqs ) ; events . emit ( 'warn' , 'Current project does not satisfy the engine requirements specified by any version of ' + name + '. Fetching latest version of plugin anyway (may be incompatible)' ) ; // No constraints were satisfied return null ; }


Input: / * Returns an array full of objects of dependency requirements that are not met . reqs - CordovaDependency object from plugin s package . json pluginMap - previously installed plugins in the project platformMap - previously installed platforms in the project cordovaVersion - version of cordova being used [CODESPLIT] function getFailedRequirements ( reqs , pluginMap , platformMap , cordovaVersion ) { var failed = [ ] ; var version = cordovaVersion ; if ( semver . prerelease ( version ) ) { //  semver.inc with 'patch' type removes prereleased tag from version version = semver . inc ( version , 'patch' ) ; } for ( var req in reqs ) { if ( reqs . hasOwnProperty ( req ) && typeof req === 'string' && semver . validRange ( reqs [ req ] ) ) { var badInstalledVersion = null ; // remove potential whitespace var trimmedReq = req . trim ( ) ; if ( pluginMap [ trimmedReq ] && ! semver . satisfies ( pluginMap [ trimmedReq ] , reqs [ req ] ) ) { badInstalledVersion = pluginMap [ req ] ; } else if ( trimmedReq === 'cordova' && ! semver . satisfies ( version , reqs [ req ] ) ) { badInstalledVersion = cordovaVersion ; } else if ( trimmedReq . indexOf ( 'cordova-' ) === 0 ) { // Might be a platform constraint var platform = trimmedReq . substring ( 8 ) ; if ( platformMap [ platform ] && ! semver . satisfies ( platformMap [ platform ] , reqs [ req ] ) ) { badInstalledVersion = platformMap [ platform ] ; } } if ( badInstalledVersion ) { failed . push ( { dependency : trimmedReq , installed : badInstalledVersion . trim ( ) , required : reqs [ req ] . trim ( ) } ) ; } } else { events . emit ( 'verbose' , 'Ignoring invalid plugin dependency constraint ' + req + ':' + reqs [ req ] ) ; } } return failed ; }


Input: return the version if it is in the versions array return null if the version doesn t exist in the array [CODESPLIT] function findVersion ( versions , version ) { var cleanedVersion = semver . clean ( version ) ; for ( var i = 0 ; i < versions . length ; i ++ ) { if ( semver . clean ( versions [ i ] ) === cleanedVersion ) { return versions [ i ] ; } } return null ; }


Input: emits warnings to users of failed dependnecy requirements in their projects [CODESPLIT] function listUnmetRequirements ( name , failedRequirements ) { events . emit ( 'warn' , 'Unmet project requirements for latest version of ' + name + ':' ) ; failedRequirements . forEach ( function ( req ) { events . emit ( 'warn' , '    ' + req . dependency + ' (' + req . installed + ' in project, ' + req . required + ' required)' ) ; } ) ; }


Input: ret is { output : string code : number } [CODESPLIT] function utilExec ( cmdLine ) { var defer = Q . defer ( ) ; shell . exec ( cmdLine , function ( code , output ) { defer . resolve ( { code : code , output : output } ) ; } ) ; return defer . promise ; }


Input:
Validates the structure of a task . json file . [CODESPLIT] function ( folderName , task ) { var defer = Q . defer ( ) ; var vn = ( task . name || folderName ) ; if ( ! task . id || ! check . isUUID ( task . id ) ) { defer . reject ( createError ( vn + ': id is a required guid' ) ) ; } ; if ( ! task . name || ! check . isAlphanumeric ( task . name ) ) { defer . reject ( createError ( vn + ': name is a required alphanumeric string' ) ) ; } if ( ! task . friendlyName || ! check . isLength ( task . friendlyName , 1 , 40 ) ) { defer . reject ( createError ( vn + ': friendlyName is a required string <= 40 chars' ) ) ; } if ( ! task . instanceNameFormat ) { defer . reject ( createError ( vn + ': instanceNameFormat is required' ) ) ; } // resolve if not already rejected
 defer . resolve ( ) ; return defer . promise ; }


Input: ----------------------------------------------------- Results and Exiting ----------------------------------------------------- [CODESPLIT] function setResult ( result , message ) { debug ( 'task result: ' + TaskResult [ result ] ) ; command ( 'task.complete' , { 'result' : TaskResult [ result ] } , message ) ; if ( result == TaskResult . Failed ) { _writeError ( message ) ; } if ( result == TaskResult . Failed ) { process . exit ( 0 ) ; } }


Input: ----------------------------------------------------- Input Helpers ----------------------------------------------------- [CODESPLIT] function getVariable ( name ) { var varval = process . env [ name . replace ( / \. / g , '_' ) . toUpperCase ( ) ] ; debug ( name + '=' + varval ) ; var mocked = mock . getResponse ( 'getVariable' , name ) ; return mocked || varval ; }


Input: Split - do not use for splitting args! Instead use arg () - it will split and handle this is for splitting a simple list of items like targets [CODESPLIT] function getDelimitedInput ( name , delim , required ) { var inval = getInput ( name , required ) ; if ( ! inval ) { return [ ] ; } return inval . split ( delim ) ; }


Input: ----------------------------------------------------- Endpoint Helpers ----------------------------------------------------- [CODESPLIT] function getEndpointUrl ( id , optional ) { var urlval = getVariable ( 'ENDPOINT_URL_' + id ) ; debug ( id + '=' + urlval ) ; if ( ! optional && ! urlval ) { _writeError ( 'Endpoint not present: ' + id ) ; exit ( 1 ) ; } return urlval ; }


Input: ----------------------------------------------------- Cmd Helpers ----------------------------------------------------- [CODESPLIT] function command ( command , properties , message ) { var taskCmd = new tcm . TaskCommand ( command , properties , message ) ; _writeLine ( taskCmd . toString ( ) ) ; }


Input: ------------------------------------------------ Validation Helpers ------------------------------------------------ [CODESPLIT] function checkPath ( p , name ) { debug ( 'check path : ' + p ) ; if ( ! p || ! mock . getResponse ( 'checkPath' , p ) ) { setResult ( TaskResult . Failed , 'not found ' + name + ': ' + p ) ; // exit } }


Input: ----------------------------------------------------- Exec convenience wrapper ----------------------------------------------------- [CODESPLIT] function exec ( tool , args , options ) { var toolPath = which ( tool , true ) ; var tr = createToolRunner ( toolPath ) ; if ( args ) { tr . arg ( args ) ; } return tr . exec ( options ) ; }


Input: Adapted from https : // github . com / polvo - labs / card - type / blob / aaab11f80fa1939bccc8f24905a06ae3cd864356 / src / cardType . js#L37 - L42 [CODESPLIT] function matchesRange ( cardNumber , min , max ) { var maxLengthToCheck = String ( min ) . length ; var substr = cardNumber . substr ( 0 , maxLengthToCheck ) ; var integerRepresentationOfCardNumber = parseInt ( substr , 10 ) ; min = parseInt ( String ( min ) . substr ( 0 , substr . length ) , 10 ) ; max = parseInt ( String ( max ) . substr ( 0 , substr . length ) , 10 ) ; return integerRepresentationOfCardNumber >= min && integerRepresentationOfCardNumber <= max ; }


Input: legacy repoDocs have only true / false set at repository . files [ yarn . lock ] ect newer repoDocs have an array ( empty or with the paths ) packageFilename : path of pckage . json [CODESPLIT] function ( files , packageFilename ) { const convertedFiles = _ . flatten ( Object . keys ( files ) . map ( key => { if ( files [ key ] === true ) return key else return files [ key ] } ) ) const hasPackageLock = _ . includes ( convertedFiles , packageFilename . replace ( 'package.json' , 'package-lock.json' ) ) if ( hasPackageLock ) return packageFilename . replace ( 'package.json' , 'package-lock.json' ) const hasYarnLock = _ . includes ( convertedFiles , packageFilename . replace ( 'package.json' , 'yarn.lock' ) ) if ( hasYarnLock ) return packageFilename . replace ( 'package.json' , 'yarn.lock' ) return null }


Input: version is a string : v8 . 10 - 10 Dubnium - lts / * etc returns a boolean versionOnly : true will _not_ match placeholder strings for current versions such as stable [CODESPLIT] function ( version , newVersion , newCodeName , versionOnly = false ) { let matches = [ ` ${ newCodeName } ` , newCodeName , newVersion ] // eslint-disable-line const tags = [ 'node' , 'stable' , 'lts/\\*' ] if ( ! versionOnly ) { matches = matches . concat ( tags ) } const overallResult = ! ! matches . find ( ( match ) => { // first regex matches in array form ('- 10'), second regex matches the inline form ('10') return ! ! ( version . match ( RegExp ( ` ${ match } ` , 'i' ) ) || version . match ( RegExp ( ` ${ match } ` , 'i' ) ) ) } ) return overallResult }


Input: existingVersionStrings is just an array of strings : [ - 7 - 8 ] or [ 9 ] or [ v8 . 10 ] returns an index [CODESPLIT] function ( existingVersionStrings , newVersion , newCodeName , versionOnly = false ) { if ( ! existingVersionStrings || existingVersionStrings . length === 0 ) return - 1 return existingVersionStrings . findIndex ( ( version ) => { return hasNodeVersion ( version , newVersion , newCodeName , versionOnly ) } ) }


Input: Stop! YAMLtime! existingVersions is the output of getNodeVersionsFromTravisYML [CODESPLIT] function ( travisYML , newVersion , newCodeName , existingVersions ) { // Should only add the new version if it is not present in any form if ( existingVersions . versions . length === 0 ) return travisYML const nodeVersionIndex = getNodeVersionIndex ( existingVersions . versions , newVersion , newCodeName ) const travisYMLLines = travisYML . split ( '\n' ) // We only need to do something if the new version isn’t present if ( nodeVersionIndex === - 1 ) { let delimiter = '' let leadingSpaces = '' if ( existingVersions . versions && existingVersions . versions . length > 0 ) { if ( existingVersions . versions [ 0 ] . match ( / " / ) ) { delimiter = '"' } if ( existingVersions . versions [ 0 ] . match ( / ' / ) ) { delimiter = "'" } leadingSpaces = existingVersions . versions [ 0 ] . match ( / ^([ ]*) / ) [ 1 ] } // splice the new version back onto the end of the node version list in the original travisYMLLines array, // unless it wasn’t an array but an inline definition of a single version, eg: `node_js: 9` if ( existingVersions . versions . length === 1 && existingVersions . startIndex === existingVersions . endIndex ) { // A single node version was defined in inline format, now we want to define two versions in array format travisYMLLines . splice ( existingVersions . startIndex , 1 , 'node_js:' ) travisYMLLines . splice ( existingVersions . startIndex + 1 , 0 , ` ${ leadingSpaces } ${ existingVersions . versions [ 0 ] } ` ) travisYMLLines . splice ( existingVersions . startIndex + 2 , 0 , ` ${ leadingSpaces } ${ delimiter } ${ newVersion } ${ delimiter } ` ) } else { // Multiple node versions were defined in array format travisYMLLines . splice ( existingVersions . endIndex + 1 , 0 , ` ${ leadingSpaces } ${ delimiter } ${ newVersion } ${ delimiter } ` ) } } return travisYMLLines . join ( '\n' ) }


Input: existingVersions is the output of getNodeVersionsFromTravisYML [CODESPLIT] function ( travisYML , newVersion , newCodeName , existingVersions ) { // Should only remove the old version if it is actually present in any form if ( existingVersions . versions . length === 0 ) return travisYML const nodeVersionIndex = getNodeVersionIndex ( existingVersions . versions , newVersion , newCodeName , true ) let travisYMLLines = travisYML . split ( '\n' ) // We only need to do something if the old version is present if ( nodeVersionIndex !== - 1 ) { // If it’s the only version we don’t want to remove it if ( existingVersions . versions . length !== 1 ) { // Multiple node versions were defined in array format // set lines we want to remove to undefined in existingVersion.versions and filter them out afterwards const updatedVersionsArray = _ . filter ( existingVersions . versions . map ( ( version ) => { return hasNodeVersion ( version , newVersion , newCodeName , true ) ? undefined : version } ) , Boolean ) // splice the updated existingversions into travisymllines travisYMLLines . splice ( existingVersions . startIndex + 1 , existingVersions . endIndex - existingVersions . startIndex , updatedVersionsArray ) // has an array in an array, needs to be flattened travisYMLLines = _ . flatten ( travisYMLLines ) } } return travisYMLLines . join ( '\n' ) }


Input: Not closing the issue so decision whether to explicitly upgrade or just close is with the user await github . issues . update ( { owner repo number state : closed } ) [CODESPLIT] function hasVersionComment ( issue , version ) { if ( ! issue . version && ! issue . comments ) { log . error ( 'no version information on issue document' , { issue } ) return false } return issue . version === version || ( issue . comments && issue . comments . includes ( version ) ) }


Input: trigger ( several ) initial - subgroup - pr ( s ) : - if a package . json is added / renamed / moved in the greenkeeper . json - if a greenkeeper . json is added [CODESPLIT] async function updateRepoDoc ( { installationId , doc , filePaths , log } ) { const fullName = doc . fullName const oldGreenkeeperConfig = doc . greenkeeper // set a default empty config so the job can continue if the file get fails for some reason let greenkeeperConfigFile = { } try { greenkeeperConfigFile = await getGreenkeeperConfigFile ( installationId , fullName , log ) } catch ( e ) { throw e } finally { if ( ! _ . isEmpty ( greenkeeperConfigFile ) ) { log . info ( 'UpdateRepoDoc: Fetched greenkeeper.json from GitHub' , greenkeeperConfigFile ) } _ . set ( doc , [ 'greenkeeper' ] , greenkeeperConfigFile ) const defaultFiles = { 'package.json' : [ ] , 'package-lock.json' : [ ] , 'yarn.lock' : [ ] , 'npm-shrinkwrap.json' : [ ] } let filePathsFromConfig = [ ] if ( ! _ . isEmpty ( greenkeeperConfigFile ) ) { if ( validate ( greenkeeperConfigFile ) . error ) { log . info ( 'UpdateRepoDoc: setting file paths to the ones from the old greenkeeper.json' ) filePathsFromConfig = getPackagePathsFromConfigFile ( oldGreenkeeperConfig ) } else { log . info ( 'UpdateRepoDoc: setting file paths to the ones found via greenkeeper.json' ) filePathsFromConfig = getPackagePathsFromConfigFile ( greenkeeperConfigFile ) } } // try to get file paths from either the autodiscovered filePaths // or from the greenkeeper.json if ( ! _ . isEmpty ( filePaths ) ) { log . info ( 'UpdateRepoDoc: setting file paths to the ones found per autodiscovery' ) filePathsFromConfig = getPackagePathsFromConfigFile ( { groups : { default : { packages : filePaths } } } ) } log . info ( 'UpdateRepoDoc: requesting files from GitHub' , { files : filePathsFromConfig } ) const filesFromConfig = _ . isEmpty ( filePathsFromConfig ) ? await getFiles ( { installationId , fullName , sha : doc . headSha , log } ) : await getFiles ( { installationId , fullName , files : filePathsFromConfig , sha : doc . headSha , log } ) const files = _ . merge ( filesFromConfig , defaultFiles ) // handles multiple paths for files like this: // files: { //   package.json: ['package.json', 'backend/package.json', 'frontend/package.json'] //   package-lock.json: ['package-lock.json', 'backend/package-lock.json'] //   npm-shrinkwrap.json: [], //   yarn.lock: [] // } doc . files = _ . mapValues ( files , fileType => fileType . filter ( file => ! ! file . content ) . map ( file => file . path ) ) // formats *all* the package.json files const pkg = formatPackageJson ( files [ 'package.json' ] ) if ( ! pkg ) { _ . unset ( doc , [ 'packages' ] ) } else { _ . set ( doc , [ 'packages' ] , pkg ) } log . info ( 'UpdateRepoDoc: doc updated' , { doc } ) } }


Input: Returns an array of objects where each object describes a package . json : [ { content : eyJuYW1lIjoidGVzdCJ9 name : package . json path : frontend / package . json type : file } ] [CODESPLIT] async function discoverPackageFiles ( { installationId , fullName , defaultBranch , log } ) { const ghqueue = githubQueue ( installationId ) const relevantPackageFilePaths = await discoverPackageFilePaths ( { installationId , fullName , defaultBranch , log } ) const [ owner , repo ] = fullName . split ( '/' ) // Fetch the content for each relevant package.json file const packageFiles = await Promise . all ( relevantPackageFilePaths . map ( ( path ) => getGithubFile ( ghqueue , { path , owner , repo } ) ) ) log . info ( ` ${ packageFiles . length } ` ) return packageFiles }


Input: Returns an array of paths of package . json files : [ package . json frontend / package . json backend / package . json ] [CODESPLIT] async function discoverPackageFilePaths ( { installationId , fullName , defaultBranch , log } ) { // https://api.github.com/repos/neighbourhoodie/gk-test-lerna-yarn-workspaces/git/trees/master?recursive=1 const [ owner , repo ] = fullName . split ( '/' ) const ghqueue = githubQueue ( installationId ) try { const result = ( await ghqueue . read ( github => github . gitdata . getTree ( { owner , repo , tree_sha : defaultBranch , recursive : 1 } ) ) ) const filesInRepo = result . tree && result . tree . length ? result . tree : [ ] // Construct an array of all relevant package.json paths const relevantPackageFilePaths = filesInRepo . map ( ( item ) => { // Just pick out the paths, eg. `packages/retext-dutch/package.json` return item . path } ) . filter ( ( item ) => { // We don’t want any package.json files from `node_modules` return ! ( item . includes ( 'node_modules' ) || item . includes ( 'test/' ) || item . includes ( 'tests/' ) || item . includes ( 'elm-package.json' ) ) && item . match ( / (.+\/package.json$|^package.json$) / ) } ) log . info ( 'relevant package file paths' , { relevantPackageFilePaths } ) return relevantPackageFilePaths } catch ( error ) { log . warn ( ` ${ defaultBranch } ` , { error : error . message } ) return [ ] } }


Input: needs to handle files as an array of arrays! [CODESPLIT] function hasLockFileText ( files ) { if ( ! files ) return const lockFiles = [ 'package-lock.json' , 'npm-shrinkwrap.json' , 'yarn.lock' ] . filter ( ( key ) => { if ( _ . isArray ( files [ key ] ) && files [ key ] . length ) { return true } if ( files [ key ] === true ) { return true } return false } ) if ( lockFiles . length === 0 ) return if ( lockFiles . includes ( 'npm-shrinkwrap.json' ) ) { return md ` .c od e ('np m -shrinkwrap.json')} f i l  } const lockFile = lockFiles [ 0 ] return md ` d. co d e(lo c kFile)}  f i  }


Input: 1 . fetch . travis . yml [CODESPLIT] function travisTransform ( travisYML ) { try { var travisJSON = yaml . safeLoad ( travisYML , { schema : yaml . FAILSAFE_SCHEMA } ) } catch ( e ) { // ignore .travis.yml if it can not be parsed return } // No node versions specified in root level of travis YML // There may be node versions defined in the matrix or jobs keys, but those can become // far too complex for us to handle, so we don’t if ( ! _ . get ( travisJSON , 'node_js' ) ) return const nodeVersionFromYaml = getNodeVersionsFromTravisYML ( travisYML ) const hasNodeVersion = getNodeVersionIndex ( nodeVersionFromYaml . versions , nodeVersion , codeName ) !== - 1 if ( hasNodeVersion ) return const updatedTravisYaml = addNodeVersionToTravisYML ( travisYML , nodeVersion , codeName , nodeVersionFromYaml ) return updatedTravisYaml }


Input: Given a groups array and a package path returns the package file’s group or undefined [CODESPLIT] function getGroupForPackageFile ( groups , packageFilePath ) { return Object . keys ( groups ) . find ( ( group ) => { return groups [ group ] . packages && groups [ group ] . packages . includes ( packageFilePath ) } ) }


Input: Given a groups array a package path and a dependency name returns whether that dep is ignored for that package in any group [CODESPLIT] function isDependencyIgnoredInGroups ( groups , packageFilePath , dependencyName ) { const groupName = getGroupForPackageFile ( groups , packageFilePath ) return groupName && _ . includes ( groups [ groupName ] . ignore , dependencyName ) }


Input: returns a url object if you pass in a GitHub repositoryURL returns a string with an npm URL if you just pass in a dependency name [CODESPLIT] function getDependencyURL ( { repositoryURL , dependency } ) { // githubURL is an object! const githubURL = url . parse ( githubFromGit ( repositoryURL ) || '' ) if ( dependency && ! githubURL . href ) { return ` ${ dependency } ` } return githubURL }


Input: expects an array of package . json paths returns an array of unique dependencies from those package . jsons : / * Returns : [ { name : [CODESPLIT] function getDependenciesFromPackageFiles ( packagePaths , packageJsonContents ) { return _ . compact ( _ . uniqWith ( _ . flatten ( packagePaths . map ( path => { return _ . flatten ( [ 'dependencies' , 'devDependencies' , 'optionalDependencies' ] . map ( type => { if ( packageJsonContents [ path ] ) { return _ . map ( packageJsonContents [ path ] [ type ] , ( version , name ) => ( { name , version , type } ) ) } } ) ) } ) ) , _ . isEqual ) ) }


Input: add npm package data to dependency info from previous function / * Returns : [ { name : [CODESPLIT] async function addNPMPackageData ( dependencyInfo , registryGet , log ) { return Promise . mapSeries ( dependencyInfo , async dep => { try { dep . data = await registryGet ( registryUrl + dep . name . replace ( '/' , '%2F' ) , { } ) return dep } catch ( err ) { log . error ( 'npm: Could not get package data' , { dependency : dep , error : err } ) } } ) }


Input: get new version for all dependencies in files / * Arguments : packagePaths : array of strings eg . [ package . json frontend / package . json ] packageJsonContents : array of objects eg . [ { devDependencies : { @finnpauls / dep : 1 . 0 . 0 } } ] registryGet : instance of promisified npm - registry - client ignore : array of strings eg . [ eslint standard ] from config ( package . json greenkeeper . json etc . ) log : an instance of the logger [CODESPLIT] async function getUpdatedDependenciesForFiles ( { packagePaths , packageJsonContents , registryGet , ignore , log } ) { const dependencyInfo = module . exports . getDependenciesFromPackageFiles ( packagePaths , packageJsonContents , log ) // Filter out ignored dependencies const unignoredDependencyInfo = dependencyInfo . filter ( ( dep ) => ! ignore . includes ( dep . name ) ) log . info ( 'dependencies found' , { parsedDependencies : unignoredDependencyInfo , ignoredDependencies : ignore , packageJsonContents : packageJsonContents } ) let dependencies = await module . exports . addNPMPackageData ( unignoredDependencyInfo , registryGet , log ) let dependencyActionsLog = { } // add `newVersion` to each dependency object in the array const outputDependencies = _ ( dependencies ) . filter ( Boolean ) // remove falsy values from input array . map ( dependency => { // neither version nor range, so it's something weird (git url) // better not touch it if ( ! semver . validRange ( dependency . version ) ) { dependencyActionsLog [ dependency . name ] = 'invalid range' return } // new version is prerelease const oldIsPrerelease = _ . get ( semver . parse ( dependency . version ) , 'prerelease.length' ) > 0 let latest = _ . get ( dependency , 'data.dist-tags.latest' ) const prereleaseDiff = oldIsPrerelease && semver . diff ( dependency . version , latest ) === 'prerelease' if ( ! prereleaseDiff && _ . get ( semver . parse ( latest ) , 'prerelease.length' , 0 ) > 0 ) { const versions = _ . keys ( _ . get ( dependency , 'data.versions' ) ) latest = _ . reduce ( versions , function ( current , next ) { const parsed = semver . parse ( next ) if ( ! parsed ) return current if ( _ . get ( parsed , 'prerelease.length' , 0 ) > 0 ) return current if ( semver . gtr ( next , current ) ) return next return current } ) } // no to need change anything :) if ( semver . satisfies ( latest , dependency . version ) ) { dependencyActionsLog [ dependency . name ] = 'satisfies semver' return } // no downgrades if ( semver . ltr ( latest , dependency . version ) ) { dependencyActionsLog [ dependency . name ] = 'would be a downgrade' return } dependency . newVersion = getRangedVersion ( latest , dependency . version ) dependencyActionsLog [ dependency . name ] = ` ${ dependency . newVersion } ` return dependency } ) . filter ( Boolean ) // remove falsy values from output array . value ( ) // run lodash chain log . info ( 'parsed dependency actions' , { dependencyActionsLog } ) return outputDependencies }


Input: a hack suggested here : https : // github . com / amir20 / phantomjs - node / issues / 292 [CODESPLIT] function checkForData ( ) { ph . windowProperty ( "DATA" ) . then ( function ( data ) { if ( data !== undefined ) { writeToFile ( data ) ; ph . exit ( ) ; } else { setTimeout ( checkForData , 100 ) ; } } ) ; }


Input: extracts lists of methods from each service object . [CODESPLIT] function extractApis ( services ) { var filterTypes = arguments . length <= 1 || arguments [ 1 ] === undefined ? [ ] : arguments [ 1 ] ; services = Array . isArray ( services ) ? services : [ services ] ; var apis = services . reduce ( function ( total , service ) { var obj = service . constructor === Object ? service : Object . getPrototypeOf ( service ) ; var keys = aggregateApisByType ( obj , total , filterTypes ) ; total . push . apply ( total , keys ) ; return total ; } , [ ] ) ; return apis ; }


Input:
/ * eslint - disable Constructor for SearchResults [CODESPLIT] function SearchResults ( state , results ) { var mainSubResponse = results [ 0 ] ; this . _rawResults = results ; /**
   * query used to generate the results
   * @member {string}
   */ this . query = mainSubResponse . query ; /**
   * The query as parsed by the engine given all the rules.
   * @member {string}
   */ this . parsedQuery = mainSubResponse . parsedQuery ; /**
   * all the records that match the search parameters. Each record is
   * augmented with a new attribute `_highlightResult`
   * which is an object keyed by attribute and with the following properties:
   *  - `value` : the value of the facet highlighted (html)
   *  - `matchLevel`: full, partial or none depending on how the query terms match
   * @member {object[]}
   */ this . hits = mainSubResponse . hits ; /**
   * index where the results come from
   * @member {string}
   */ this . index = mainSubResponse . index ; /**
   * number of hits per page requested
   * @member {number}
   */ this . hitsPerPage = mainSubResponse . hitsPerPage ; /**
   * total number of hits of this query on the index
   * @member {number}
   */ this . nbHits = mainSubResponse . nbHits ; /**
   * total number of pages with respect to the number of hits per page and the total number of hits
   * @member {number}
   */ this . nbPages = mainSubResponse . nbPages ; /**
   * current page
   * @member {number}
   */ this . page = mainSubResponse . page ; /**
   * sum of the processing time of all the queries
   * @member {number}
   */ this . processingTimeMS = sumBy ( results , 'processingTimeMS' ) ; /**
   * The position if the position was guessed by IP.
   * @member {string}
   * @example "48.8637,2.3615",
   */ this . aroundLatLng = mainSubResponse . aroundLatLng ; /**
   * The radius computed by Algolia.
   * @member {string}
   * @example "126792922",
   */ this . automaticRadius = mainSubResponse . automaticRadius ; /**
   * String identifying the server used to serve this request.
   * @member {string}
   * @example "c7-use-2.algolia.net",
   */ this . serverUsed = mainSubResponse . serverUsed ; /**
   * Boolean that indicates if the computation of the counts did time out.
   * @deprecated
   * @member {boolean}
   */ this . timeoutCounts = mainSubResponse . timeoutCounts ; /**
   * Boolean that indicates if the computation of the hits did time out.
   * @deprecated
   * @member {boolean}
   */ this . timeoutHits = mainSubResponse . timeoutHits ; /**
   * True if the counts of the facets is exhaustive
   * @member {boolean}
   */ this . exhaustiveFacetsCount = mainSubResponse . exhaustiveFacetsCount ; /**
   * True if the number of hits is exhaustive
   * @member {boolean}
   */ this . exhaustiveNbHits = mainSubResponse . exhaustiveNbHits ; /**
   * Contains the userData if they are set by a [query rule](https://www.algolia.com/doc/guides/query-rules/query-rules-overview/).
   * @member {object[]}
   */ this . userData = mainSubResponse . userData ; /**
   * queryID is the unique identifier of the query used to generate the current search results.
   * This value is only available if the `clickAnalytics` search parameter is set to `true`.
   * @member {string}
   */ this . queryID = mainSubResponse . queryID ; /**
   * disjunctive facets results
   * @member {SearchResults.Facet[]}
   */ this . disjunctiveFacets = [ ] ; /**
   * disjunctive facets results
   * @member {SearchResults.HierarchicalFacet[]}
   */ this . hierarchicalFacets = map ( state . hierarchicalFacets , function initFutureTree ( ) { return [ ] ; } ) ; /**
   * other facets results
   * @member {SearchResults.Facet[]}
   */ this . facets = [ ] ; var disjunctiveFacets = state . getRefinedDisjunctiveFacets ( ) ; var facetsIndices = getIndices ( state . facets ) ; var disjunctiveFacetsIndices = getIndices ( state . disjunctiveFacets ) ; var nextDisjunctiveResult = 1 ; var self = this ; // Since we send request only for disjunctive facets that have been refined, // we get the facets informations from the first, general, response. forEach ( mainSubResponse . facets , function ( facetValueObject , facetKey ) { var hierarchicalFacet = findMatchingHierarchicalFacetFromAttributeName ( state . hierarchicalFacets , facetKey ) ; if ( hierarchicalFacet ) { // Place the hierarchicalFacet data at the correct index depending on // the attributes order that was defined at the helper initialization var facetIndex = hierarchicalFacet . attributes . indexOf ( facetKey ) ; var idxAttributeName = findIndex ( state . hierarchicalFacets , { name : hierarchicalFacet . name } ) ; self . hierarchicalFacets [ idxAttributeName ] [ facetIndex ] = { attribute : facetKey , data : facetValueObject , exhaustive : mainSubResponse . exhaustiveFacetsCount } ; } else { var isFacetDisjunctive = indexOf ( state . disjunctiveFacets , facetKey ) !== - 1 ; var isFacetConjunctive = indexOf ( state . facets , facetKey ) !== - 1 ; var position ; if ( isFacetDisjunctive ) { position = disjunctiveFacetsIndices [ facetKey ] ; self . disjunctiveFacets [ position ] = { name : facetKey , data : facetValueObject , exhaustive : mainSubResponse . exhaustiveFacetsCount } ; assignFacetStats ( self . disjunctiveFacets [ position ] , mainSubResponse . facets_stats , facetKey ) ; } if ( isFacetConjunctive ) { position = facetsIndices [ facetKey ] ; self . facets [ position ] = { name : facetKey , data : facetValueObject , exhaustive : mainSubResponse . exhaustiveFacetsCount } ; assignFacetStats ( self . facets [ position ] , mainSubResponse . facets_stats , facetKey ) ; } } } ) ; // Make sure we do not keep holes within the hierarchical facets this . hierarchicalFacets = compact ( this . hierarchicalFacets ) ; // aggregate the refined disjunctive facets forEach ( disjunctiveFacets , function ( disjunctiveFacet ) { var result = results [ nextDisjunctiveResult ] ; var hierarchicalFacet = state . getHierarchicalFacetByName ( disjunctiveFacet ) ; // There should be only item in facets. forEach ( result . facets , function ( facetResults , dfacet ) { var position ; if ( hierarchicalFacet ) { position = findIndex ( state . hierarchicalFacets , { name : hierarchicalFacet . name } ) ; var attributeIndex = findIndex ( self . hierarchicalFacets [ position ] , { attribute : dfacet } ) ; // previous refinements and no results so not able to find it if ( attributeIndex === - 1 ) { return ; } self . hierarchicalFacets [ position ] [ attributeIndex ] . data = merge ( { } , self . hierarchicalFacets [ position ] [ attributeIndex ] . data , facetResults ) ; } else { position = disjunctiveFacetsIndices [ dfacet ] ; var dataFromMainRequest = mainSubResponse . facets && mainSubResponse . facets [ dfacet ] || { } ; self . disjunctiveFacets [ position ] = { name : dfacet , data : defaults ( { } , facetResults , dataFromMainRequest ) , exhaustive : result . exhaustiveFacetsCount } ; assignFacetStats ( self . disjunctiveFacets [ position ] , result . facets_stats , dfacet ) ; if ( state . disjunctiveFacetsRefinements [ dfacet ] ) { forEach ( state . disjunctiveFacetsRefinements [ dfacet ] , function ( refinementValue ) { // add the disjunctive refinements if it is no more retrieved if ( ! self . disjunctiveFacets [ position ] . data [ refinementValue ] && indexOf ( state . disjunctiveFacetsRefinements [ dfacet ] , refinementValue ) > - 1 ) { self . disjunctiveFacets [ position ] . data [ refinementValue ] = 0 ; } } ) ; } } } ) ; nextDisjunctiveResult ++ ; } ) ; // if we have some root level values for hierarchical facets, merge them forEach ( state . getRefinedHierarchicalFacets ( ) , function ( refinedFacet ) { var hierarchicalFacet = state . getHierarchicalFacetByName ( refinedFacet ) ; var separator = state . _getHierarchicalFacetSeparator ( hierarchicalFacet ) ; var currentRefinement = state . getHierarchicalRefinement ( refinedFacet ) ; // if we are already at a root refinement (or no refinement at all), there is no // root level values request if ( currentRefinement . length === 0 || currentRefinement [ 0 ] . split ( separator ) . length < 2 ) { return ; } var result = results [ nextDisjunctiveResult ] ; forEach ( result . facets , function ( facetResults , dfacet ) { var position = findIndex ( state . hierarchicalFacets , { name : hierarchicalFacet . name } ) ; var attributeIndex = findIndex ( self . hierarchicalFacets [ position ] , { attribute : dfacet } ) ; // previous refinements and no results so not able to find it if ( attributeIndex === - 1 ) { return ; } // when we always get root levels, if the hits refinement is `beers > IPA` (count: 5), // then the disjunctive values will be `beers` (count: 100), // but we do not want to display //   | beers (100) //     > IPA (5) // We want //   | beers (5) //     > IPA (5) var defaultData = { } ; if ( currentRefinement . length > 0 ) { var root = currentRefinement [ 0 ] . split ( separator ) [ 0 ] ; defaultData [ root ] = self . hierarchicalFacets [ position ] [ attributeIndex ] . data [ root ] ; } self . hierarchicalFacets [ position ] [ attributeIndex ] . data = defaults ( defaultData , facetResults , self . hierarchicalFacets [ position ] [ attributeIndex ] . data ) ; } ) ; nextDisjunctiveResult ++ ; } ) ; // add the excludes forEach ( state . facetsExcludes , function ( excludes , facetName ) { var position = facetsIndices [ facetName ] ; self . facets [ position ] = { name : facetName , data : mainSubResponse . facets [ facetName ] , exhaustive : mainSubResponse . exhaustiveFacetsCount } ; forEach ( excludes , function ( facetValue ) { self . facets [ position ] = self . facets [ position ] || { name : facetName } ; self . facets [ position ] . data = self . facets [ position ] . data || { } ; self . facets [ position ] . data [ facetValue ] = 0 ; } ) ; } ) ; this . hierarchicalFacets = map ( this . hierarchicalFacets , generateHierarchicalTree ( state ) ) ; this . facets = compact ( this . facets ) ; this . disjunctiveFacets = compact ( this . disjunctiveFacets ) ; this . _state = state ; }


Input: Get the facet values of a specified attribute from a SearchResults object . [CODESPLIT] function extractNormalizedFacetValues ( results , attribute ) { var predicate = { name : attribute } ; if ( results . _state . isConjunctiveFacet ( attribute ) ) { var facet = find ( results . facets , predicate ) ; if ( ! facet ) return [ ] ; return map ( facet . data , function ( v , k ) { return { name : k , count : v , isRefined : results . _state . isFacetRefined ( attribute , k ) , isExcluded : results . _state . isExcludeRefined ( attribute , k ) } ; } ) ; } else if ( results . _state . isDisjunctiveFacet ( attribute ) ) { var disjunctiveFacet = find ( results . disjunctiveFacets , predicate ) ; if ( ! disjunctiveFacet ) return [ ] ; return map ( disjunctiveFacet . data , function ( v , k ) { return { name : k , count : v , isRefined : results . _state . isDisjunctiveFacetRefined ( attribute , k ) } ; } ) ; } else if ( results . _state . isHierarchicalFacet ( attribute ) ) { return find ( results . hierarchicalFacets , predicate ) ; } }


Input: Sort nodes of a hierarchical facet results [CODESPLIT] function recSort ( sortFn , node ) { if ( ! node . data || node . data . length === 0 ) { return node ; } var children = map ( node . data , partial ( recSort , sortFn ) ) ; var sortedChildren = sortFn ( children ) ; var newNode = merge ( { } , node , { data : sortedChildren } ) ; return newNode ; }


Input:
Structure to store numeric filters with the operator as the key . The supported operators are = > < > = < = and ! = . [CODESPLIT] function SearchParameters ( newParameters ) { var params = newParameters ? SearchParameters . _parseNumbers ( newParameters ) : { } ; /**
   * Targeted index. This parameter is mandatory.
   * @member {string}
   */ this . index = params . index || '' ; // Query /**
   * Query string of the instant search. The empty string is a valid query.
   * @member {string}
   * @see https://www.algolia.com/doc/rest#param-query
   */ this . query = params . query || '' ; // Facets /**
   * This attribute contains the list of all the conjunctive facets
   * used. This list will be added to requested facets in the
   * [facets attribute](https://www.algolia.com/doc/rest-api/search#param-facets) sent to algolia.
   * @member {string[]}
   */ this . facets = params . facets || [ ] ; /**
   * This attribute contains the list of all the disjunctive facets
   * used. This list will be added to requested facets in the
   * [facets attribute](https://www.algolia.com/doc/rest-api/search#param-facets) sent to algolia.
   * @member {string[]}
   */ this . disjunctiveFacets = params . disjunctiveFacets || [ ] ; /**
   * This attribute contains the list of all the hierarchical facets
   * used. This list will be added to requested facets in the
   * [facets attribute](https://www.algolia.com/doc/rest-api/search#param-facets) sent to algolia.
   * Hierarchical facets are a sub type of disjunctive facets that
   * let you filter faceted attributes hierarchically.
   * @member {string[]|object[]}
   */ this . hierarchicalFacets = params . hierarchicalFacets || [ ] ; // Refinements /**
   * This attribute contains all the filters that need to be
   * applied on the conjunctive facets. Each facet must be properly
   * defined in the `facets` attribute.
   *
   * The key is the name of the facet, and the `FacetList` contains all
   * filters selected for the associated facet name.
   *
   * When querying algolia, the values stored in this attribute will
   * be translated into the `facetFilters` attribute.
   * @member {Object.<string, SearchParameters.FacetList>}
   */ this . facetsRefinements = params . facetsRefinements || { } ; /**
   * This attribute contains all the filters that need to be
   * excluded from the conjunctive facets. Each facet must be properly
   * defined in the `facets` attribute.
   *
   * The key is the name of the facet, and the `FacetList` contains all
   * filters excluded for the associated facet name.
   *
   * When querying algolia, the values stored in this attribute will
   * be translated into the `facetFilters` attribute.
   * @member {Object.<string, SearchParameters.FacetList>}
   */ this . facetsExcludes = params . facetsExcludes || { } ; /**
   * This attribute contains all the filters that need to be
   * applied on the disjunctive facets. Each facet must be properly
   * defined in the `disjunctiveFacets` attribute.
   *
   * The key is the name of the facet, and the `FacetList` contains all
   * filters selected for the associated facet name.
   *
   * When querying algolia, the values stored in this attribute will
   * be translated into the `facetFilters` attribute.
   * @member {Object.<string, SearchParameters.FacetList>}
   */ this . disjunctiveFacetsRefinements = params . disjunctiveFacetsRefinements || { } ; /**
   * This attribute contains all the filters that need to be
   * applied on the numeric attributes.
   *
   * The key is the name of the attribute, and the value is the
   * filters to apply to this attribute.
   *
   * When querying algolia, the values stored in this attribute will
   * be translated into the `numericFilters` attribute.
   * @member {Object.<string, SearchParameters.OperatorList>}
   */ this . numericRefinements = params . numericRefinements || { } ; /**
   * This attribute contains all the tags used to refine the query.
   *
   * When querying algolia, the values stored in this attribute will
   * be translated into the `tagFilters` attribute.
   * @member {string[]}
   */ this . tagRefinements = params . tagRefinements || [ ] ; /**
   * This attribute contains all the filters that need to be
   * applied on the hierarchical facets. Each facet must be properly
   * defined in the `hierarchicalFacets` attribute.
   *
   * The key is the name of the facet, and the `FacetList` contains all
   * filters selected for the associated facet name. The FacetList values
   * are structured as a string that contain the values for each level
   * separated by the configured separator.
   *
   * When querying algolia, the values stored in this attribute will
   * be translated into the `facetFilters` attribute.
   * @member {Object.<string, SearchParameters.FacetList>}
   */ this . hierarchicalFacetsRefinements = params . hierarchicalFacetsRefinements || { } ; /**
   * Contains the numeric filters in the raw format of the Algolia API. Setting
   * this parameter is not compatible with the usage of numeric filters methods.
   * @see https://www.algolia.com/doc/javascript#numericFilters
   * @member {string}
   */ this . numericFilters = params . numericFilters ; /**
   * Contains the tag filters in the raw format of the Algolia API. Setting this
   * parameter is not compatible with the of the add/remove/toggle methods of the
   * tag api.
   * @see https://www.algolia.com/doc/rest#param-tagFilters
   * @member {string}
   */ this . tagFilters = params . tagFilters ; /**
   * Contains the optional tag filters in the raw format of the Algolia API.
   * @see https://www.algolia.com/doc/rest#param-tagFilters
   * @member {string}
   */ this . optionalTagFilters = params . optionalTagFilters ; /**
   * Contains the optional facet filters in the raw format of the Algolia API.
   * @see https://www.algolia.com/doc/rest#param-tagFilters
   * @member {string}
   */ this . optionalFacetFilters = params . optionalFacetFilters ; // Misc. parameters /**
   * Number of hits to be returned by the search API
   * @member {number}
   * @see https://www.algolia.com/doc/rest#param-hitsPerPage
   */ this . hitsPerPage = params . hitsPerPage ; /**
   * Number of values for each faceted attribute
   * @member {number}
   * @see https://www.algolia.com/doc/rest#param-maxValuesPerFacet
   */ this . maxValuesPerFacet = params . maxValuesPerFacet ; /**
   * The current page number
   * @member {number}
   * @see https://www.algolia.com/doc/rest#param-page
   */ this . page = params . page || 0 ; /**
   * How the query should be treated by the search engine.
   * Possible values: prefixAll, prefixLast, prefixNone
   * @see https://www.algolia.com/doc/rest#param-queryType
   * @member {string}
   */ this . queryType = params . queryType ; /**
   * How the typo tolerance behave in the search engine.
   * Possible values: true, false, min, strict
   * @see https://www.algolia.com/doc/rest#param-typoTolerance
   * @member {string}
   */ this . typoTolerance = params . typoTolerance ; /**
   * Number of characters to wait before doing one character replacement.
   * @see https://www.algolia.com/doc/rest#param-minWordSizefor1Typo
   * @member {number}
   */ this . minWordSizefor1Typo = params . minWordSizefor1Typo ; /**
   * Number of characters to wait before doing a second character replacement.
   * @see https://www.algolia.com/doc/rest#param-minWordSizefor2Typos
   * @member {number}
   */ this . minWordSizefor2Typos = params . minWordSizefor2Typos ; /**
   * Configure the precision of the proximity ranking criterion
   * @see https://www.algolia.com/doc/rest#param-minProximity
   */ this . minProximity = params . minProximity ; /**
   * Should the engine allow typos on numerics.
   * @see https://www.algolia.com/doc/rest#param-allowTyposOnNumericTokens
   * @member {boolean}
   */ this . allowTyposOnNumericTokens = params . allowTyposOnNumericTokens ; /**
   * Should the plurals be ignored
   * @see https://www.algolia.com/doc/rest#param-ignorePlurals
   * @member {boolean}
   */ this . ignorePlurals = params . ignorePlurals ; /**
   * Restrict which attribute is searched.
   * @see https://www.algolia.com/doc/rest#param-restrictSearchableAttributes
   * @member {string}
   */ this . restrictSearchableAttributes = params . restrictSearchableAttributes ; /**
   * Enable the advanced syntax.
   * @see https://www.algolia.com/doc/rest#param-advancedSyntax
   * @member {boolean}
   */ this . advancedSyntax = params . advancedSyntax ; /**
   * Enable the analytics
   * @see https://www.algolia.com/doc/rest#param-analytics
   * @member {boolean}
   */ this . analytics = params . analytics ; /**
   * Tag of the query in the analytics.
   * @see https://www.algolia.com/doc/rest#param-analyticsTags
   * @member {string}
   */ this . analyticsTags = params . analyticsTags ; /**
   * Enable the synonyms
   * @see https://www.algolia.com/doc/rest#param-synonyms
   * @member {boolean}
   */ this . synonyms = params . synonyms ; /**
   * Should the engine replace the synonyms in the highlighted results.
   * @see https://www.algolia.com/doc/rest#param-replaceSynonymsInHighlight
   * @member {boolean}
   */ this . replaceSynonymsInHighlight = params . replaceSynonymsInHighlight ; /**
   * Add some optional words to those defined in the dashboard
   * @see https://www.algolia.com/doc/rest#param-optionalWords
   * @member {string}
   */ this . optionalWords = params . optionalWords ; /**
   * Possible values are "lastWords" "firstWords" "allOptional" "none" (default)
   * @see https://www.algolia.com/doc/rest#param-removeWordsIfNoResults
   * @member {string}
   */ this . removeWordsIfNoResults = params . removeWordsIfNoResults ; /**
   * List of attributes to retrieve
   * @see https://www.algolia.com/doc/rest#param-attributesToRetrieve
   * @member {string}
   */ this . attributesToRetrieve = params . attributesToRetrieve ; /**
   * List of attributes to highlight
   * @see https://www.algolia.com/doc/rest#param-attributesToHighlight
   * @member {string}
   */ this . attributesToHighlight = params . attributesToHighlight ; /**
   * Code to be embedded on the left part of the highlighted results
   * @see https://www.algolia.com/doc/rest#param-highlightPreTag
   * @member {string}
   */ this . highlightPreTag = params . highlightPreTag ; /**
   * Code to be embedded on the right part of the highlighted results
   * @see https://www.algolia.com/doc/rest#param-highlightPostTag
   * @member {string}
   */ this . highlightPostTag = params . highlightPostTag ; /**
   * List of attributes to snippet
   * @see https://www.algolia.com/doc/rest#param-attributesToSnippet
   * @member {string}
   */ this . attributesToSnippet = params . attributesToSnippet ; /**
   * Enable the ranking informations in the response, set to 1 to activate
   * @see https://www.algolia.com/doc/rest#param-getRankingInfo
   * @member {number}
   */ this . getRankingInfo = params . getRankingInfo ; /**
   * Remove duplicates based on the index setting attributeForDistinct
   * @see https://www.algolia.com/doc/rest#param-distinct
   * @member {boolean|number}
   */ this . distinct = params . distinct ; /**
   * Center of the geo search.
   * @see https://www.algolia.com/doc/rest#param-aroundLatLng
   * @member {string}
   */ this . aroundLatLng = params . aroundLatLng ; /**
   * Center of the search, retrieve from the user IP.
   * @see https://www.algolia.com/doc/rest#param-aroundLatLngViaIP
   * @member {boolean}
   */ this . aroundLatLngViaIP = params . aroundLatLngViaIP ; /**
   * Radius of the geo search.
   * @see https://www.algolia.com/doc/rest#param-aroundRadius
   * @member {number}
   */ this . aroundRadius = params . aroundRadius ; /**
   * Precision of the geo search.
   * @see https://www.algolia.com/doc/rest#param-aroundPrecision
   * @member {number}
   */ this . minimumAroundRadius = params . minimumAroundRadius ; /**
   * Precision of the geo search.
   * @see https://www.algolia.com/doc/rest#param-minimumAroundRadius
   * @member {number}
   */ this . aroundPrecision = params . aroundPrecision ; /**
   * Geo search inside a box.
   * @see https://www.algolia.com/doc/rest#param-insideBoundingBox
   * @member {string}
   */ this . insideBoundingBox = params . insideBoundingBox ; /**
   * Geo search inside a polygon.
   * @see https://www.algolia.com/doc/rest#param-insidePolygon
   * @member {string}
   */ this . insidePolygon = params . insidePolygon ; /**
   * Allows to specify an ellipsis character for the snippet when we truncate the text
   * (added before and after if truncated).
   * The default value is an empty string and we recommend to set it to "…"
   * @see https://www.algolia.com/doc/rest#param-insidePolygon
   * @member {string}
   */ this . snippetEllipsisText = params . snippetEllipsisText ; /**
   * Allows to specify some attributes name on which exact won't be applied.
   * Attributes are separated with a comma (for example "name,address" ), you can also use a
   * JSON string array encoding (for example encodeURIComponent('["name","address"]') ).
   * By default the list is empty.
   * @see https://www.algolia.com/doc/rest#param-disableExactOnAttributes
   * @member {string|string[]}
   */ this . disableExactOnAttributes = params . disableExactOnAttributes ; /**
   * Applies 'exact' on single word queries if the word contains at least 3 characters
   * and is not a stop word.
   * Can take two values: true or false.
   * By default, its set to false.
   * @see https://www.algolia.com/doc/rest#param-enableExactOnSingleWordQuery
   * @member {boolean}
   */ this . enableExactOnSingleWordQuery = params . enableExactOnSingleWordQuery ; // Undocumented parameters, still needed otherwise we fail this . offset = params . offset ; this . length = params . length ; var self = this ; forOwn ( params , function checkForUnknownParameter ( paramValue , paramName ) { if ( SearchParameters . PARAMETERS . indexOf ( paramName ) === - 1 ) { self [ paramName ] = paramValue ; } } ) ; }


Input: Remove all refinements ( disjunctive + conjunctive + excludes + numeric filters ) [CODESPLIT] function clearRefinements ( attribute ) { var clear = RefinementList . clearRefinement ; var patch = { numericRefinements : this . _clearNumericRefinements ( attribute ) , facetsRefinements : clear ( this . facetsRefinements , attribute , 'conjunctiveFacet' ) , facetsExcludes : clear ( this . facetsExcludes , attribute , 'exclude' ) , disjunctiveFacetsRefinements : clear ( this . disjunctiveFacetsRefinements , attribute , 'disjunctiveFacet' ) , hierarchicalFacetsRefinements : clear ( this . hierarchicalFacetsRefinements , attribute , 'hierarchicalFacet' ) } ; if ( patch . numericRefinements === this . numericRefinements && patch . facetsRefinements === this . facetsRefinements && patch . facetsExcludes === this . facetsExcludes && patch . disjunctiveFacetsRefinements === this . disjunctiveFacetsRefinements && patch . hierarchicalFacetsRefinements === this . hierarchicalFacetsRefinements ) { return this ; } return this . setQueryParameters ( patch ) ; }


Input: Add a numeric filter for a given attribute When value is an array they are combined with OR When value is a single value it will combined with AND [CODESPLIT] function ( attribute , operator , v ) { var value = valToNumber ( v ) ; if ( this . isNumericRefined ( attribute , operator , value ) ) return this ; var mod = merge ( { } , this . numericRefinements ) ; mod [ attribute ] = merge ( { } , mod [ attribute ] ) ; if ( mod [ attribute ] [ operator ] ) { // Array copy mod [ attribute ] [ operator ] = mod [ attribute ] [ operator ] . slice ( ) ; // Add the element. Concat can't be used here because value can be an array. mod [ attribute ] [ operator ] . push ( value ) ; } else { mod [ attribute ] [ operator ] = [ value ] ; } return this . setQueryParameters ( { numericRefinements : mod } ) ; }


Input: Remove all the numeric filter for a given ( attribute operator ) [CODESPLIT] function ( attribute , operator , paramValue ) { if ( paramValue !== undefined ) { var paramValueAsNumber = valToNumber ( paramValue ) ; if ( ! this . isNumericRefined ( attribute , operator , paramValueAsNumber ) ) return this ; return this . setQueryParameters ( { numericRefinements : this . _clearNumericRefinements ( function ( value , key ) { return key === attribute && value . op === operator && isEqual ( value . val , paramValueAsNumber ) ; } ) } ) ; } else if ( operator !== undefined ) { if ( ! this . isNumericRefined ( attribute , operator ) ) return this ; return this . setQueryParameters ( { numericRefinements : this . _clearNumericRefinements ( function ( value , key ) { return key === attribute && value . op === operator ; } ) } ) ; } if ( ! this . isNumericRefined ( attribute ) ) return this ; return this . setQueryParameters ( { numericRefinements : this . _clearNumericRefinements ( function ( value , key ) { return key === attribute ; } ) } ) ; }


Input: Clear numeric filters . [CODESPLIT] function _clearNumericRefinements ( attribute ) { if ( isUndefined ( attribute ) ) { if ( isEmpty ( this . numericRefinements ) ) return this . numericRefinements ; return { } ; } else if ( isString ( attribute ) ) { if ( isEmpty ( this . numericRefinements [ attribute ] ) ) return this . numericRefinements ; return omit ( this . numericRefinements , attribute ) ; } else if ( isFunction ( attribute ) ) { var hasChanged = false ; var newNumericRefinements = reduce ( this . numericRefinements , function ( memo , operators , key ) { var operatorList = { } ; forEach ( operators , function ( values , operator ) { var outValues = [ ] ; forEach ( values , function ( value ) { var predicateResult = attribute ( { val : value , op : operator } , key , 'numeric' ) ; if ( ! predicateResult ) outValues . push ( value ) ; } ) ; if ( ! isEmpty ( outValues ) ) { if ( outValues . length !== values . length ) hasChanged = true ; operatorList [ operator ] = outValues ; } else hasChanged = true ; } ) ; if ( ! isEmpty ( operatorList ) ) memo [ key ] = operatorList ; return memo ; } , { } ) ; if ( hasChanged ) return newNumericRefinements ; return this . numericRefinements ; } }


Input: Add a hierarchical facet to the hierarchicalFacets attribute of the helper configuration . [CODESPLIT] function addHierarchicalFacet ( hierarchicalFacet ) { if ( this . isHierarchicalFacet ( hierarchicalFacet . name ) ) { throw new Error ( 'Cannot declare two hierarchical facets with the same name: `' + hierarchicalFacet . name + '`' ) ; } return this . setQueryParameters ( { hierarchicalFacets : this . hierarchicalFacets . concat ( [ hierarchicalFacet ] ) } ) ; }


Input: Add a refinement on a normal facet [CODESPLIT] function addFacetRefinement ( facet , value ) { if ( ! this . isConjunctiveFacet ( facet ) ) { throw new Error ( facet + ' is not defined in the facets attribute of the helper configuration' ) ; } if ( RefinementList . isRefined ( this . facetsRefinements , facet , value ) ) return this ; return this . setQueryParameters ( { facetsRefinements : RefinementList . addRefinement ( this . facetsRefinements , facet , value ) } ) ; }


Input: Exclude a value from a normal facet [CODESPLIT] function addExcludeRefinement ( facet , value ) { if ( ! this . isConjunctiveFacet ( facet ) ) { throw new Error ( facet + ' is not defined in the facets attribute of the helper configuration' ) ; } if ( RefinementList . isRefined ( this . facetsExcludes , facet , value ) ) return this ; return this . setQueryParameters ( { facetsExcludes : RefinementList . addRefinement ( this . facetsExcludes , facet , value ) } ) ; }


Input: Adds a refinement on a disjunctive facet . [CODESPLIT] function addDisjunctiveFacetRefinement ( facet , value ) { if ( ! this . isDisjunctiveFacet ( facet ) ) { throw new Error ( facet + ' is not defined in the disjunctiveFacets attribute of the helper configuration' ) ; } if ( RefinementList . isRefined ( this . disjunctiveFacetsRefinements , facet , value ) ) return this ; return this . setQueryParameters ( { disjunctiveFacetsRefinements : RefinementList . addRefinement ( this . disjunctiveFacetsRefinements , facet , value ) } ) ; }


Input: addTagRefinement adds a tag to the list used to filter the results [CODESPLIT] function addTagRefinement ( tag ) { if ( this . isTagRefined ( tag ) ) return this ; var modification = { tagRefinements : this . tagRefinements . concat ( tag ) } ; return this . setQueryParameters ( modification ) ; }


Input: Remove a facet from the facets attribute of the helper configuration if it is present . [CODESPLIT] function removeFacet ( facet ) { if ( ! this . isConjunctiveFacet ( facet ) ) { return this ; } return this . clearRefinements ( facet ) . setQueryParameters ( { facets : filter ( this . facets , function ( f ) { return f !== facet ; } ) } ) ; }


Input: Remove a disjunctive facet from the disjunctiveFacets attribute of the helper configuration if it is present . [CODESPLIT] function removeDisjunctiveFacet ( facet ) { if ( ! this . isDisjunctiveFacet ( facet ) ) { return this ; } return this . clearRefinements ( facet ) . setQueryParameters ( { disjunctiveFacets : filter ( this . disjunctiveFacets , function ( f ) { return f !== facet ; } ) } ) ; }


Input: Remove a hierarchical facet from the hierarchicalFacets attribute of the helper configuration if it is present . [CODESPLIT] function removeHierarchicalFacet ( facet ) { if ( ! this . isHierarchicalFacet ( facet ) ) { return this ; } return this . clearRefinements ( facet ) . setQueryParameters ( { hierarchicalFacets : filter ( this . hierarchicalFacets , function ( f ) { return f . name !== facet ; } ) } ) ; }


Input: Remove a refinement set on facet . If a value is provided it will clear the refinement for the given value otherwise it will clear all the refinement values for the faceted attribute . [CODESPLIT] function removeFacetRefinement ( facet , value ) { if ( ! this . isConjunctiveFacet ( facet ) ) { throw new Error ( facet + ' is not defined in the facets attribute of the helper configuration' ) ; } if ( ! RefinementList . isRefined ( this . facetsRefinements , facet , value ) ) return this ; return this . setQueryParameters ( { facetsRefinements : RefinementList . removeRefinement ( this . facetsRefinements , facet , value ) } ) ; }


Input: Remove a negative refinement on a facet [CODESPLIT] function removeExcludeRefinement ( facet , value ) { if ( ! this . isConjunctiveFacet ( facet ) ) { throw new Error ( facet + ' is not defined in the facets attribute of the helper configuration' ) ; } if ( ! RefinementList . isRefined ( this . facetsExcludes , facet , value ) ) return this ; return this . setQueryParameters ( { facetsExcludes : RefinementList . removeRefinement ( this . facetsExcludes , facet , value ) } ) ; }


Input: Remove a refinement on a disjunctive facet [CODESPLIT] function removeDisjunctiveFacetRefinement ( facet , value ) { if ( ! this . isDisjunctiveFacet ( facet ) ) { throw new Error ( facet + ' is not defined in the disjunctiveFacets attribute of the helper configuration' ) ; } if ( ! RefinementList . isRefined ( this . disjunctiveFacetsRefinements , facet , value ) ) return this ; return this . setQueryParameters ( { disjunctiveFacetsRefinements : RefinementList . removeRefinement ( this . disjunctiveFacetsRefinements , facet , value ) } ) ; }


Input: Remove a tag from the list of tag refinements [CODESPLIT] function removeTagRefinement ( tag ) { if ( ! this . isTagRefined ( tag ) ) return this ; var modification = { tagRefinements : filter ( this . tagRefinements , function ( t ) { return t !== tag ; } ) } ; return this . setQueryParameters ( modification ) ; }


Input: Generic toggle refinement method to use with facet disjunctive facets and hierarchical facets [CODESPLIT] function toggleFacetRefinement ( facet , value ) { if ( this . isHierarchicalFacet ( facet ) ) { return this . toggleHierarchicalFacetRefinement ( facet , value ) ; } else if ( this . isConjunctiveFacet ( facet ) ) { return this . toggleConjunctiveFacetRefinement ( facet , value ) ; } else if ( this . isDisjunctiveFacet ( facet ) ) { return this . toggleDisjunctiveFacetRefinement ( facet , value ) ; } throw new Error ( 'Cannot refine the undeclared facet ' + facet + '; it should be added to the helper options facets, disjunctiveFacets or hierarchicalFacets' ) ; }


Input: Switch the refinement applied over a facet / value [CODESPLIT] function toggleConjunctiveFacetRefinement ( facet , value ) { if ( ! this . isConjunctiveFacet ( facet ) ) { throw new Error ( facet + ' is not defined in the facets attribute of the helper configuration' ) ; } return this . setQueryParameters ( { facetsRefinements : RefinementList . toggleRefinement ( this . facetsRefinements , facet , value ) } ) ; }


Input: Switch the refinement applied over a facet / value [CODESPLIT] function toggleExcludeFacetRefinement ( facet , value ) { if ( ! this . isConjunctiveFacet ( facet ) ) { throw new Error ( facet + ' is not defined in the facets attribute of the helper configuration' ) ; } return this . setQueryParameters ( { facetsExcludes : RefinementList . toggleRefinement ( this . facetsExcludes , facet , value ) } ) ; }


Input: Switch the refinement applied over a facet / value [CODESPLIT] function toggleDisjunctiveFacetRefinement ( facet , value ) { if ( ! this . isDisjunctiveFacet ( facet ) ) { throw new Error ( facet + ' is not defined in the disjunctiveFacets attribute of the helper configuration' ) ; } return this . setQueryParameters ( { disjunctiveFacetsRefinements : RefinementList . toggleRefinement ( this . disjunctiveFacetsRefinements , facet , value ) } ) ; }


Input: Switch the refinement applied over a facet / value [CODESPLIT] function toggleHierarchicalFacetRefinement ( facet , value ) { if ( ! this . isHierarchicalFacet ( facet ) ) { throw new Error ( facet + ' is not defined in the hierarchicalFacets attribute of the helper configuration' ) ; } var separator = this . _getHierarchicalFacetSeparator ( this . getHierarchicalFacetByName ( facet ) ) ; var mod = { } ; var upOneOrMultipleLevel = this . hierarchicalFacetsRefinements [ facet ] !== undefined && this . hierarchicalFacetsRefinements [ facet ] . length > 0 && ( // remove current refinement: // refinement was 'beer > IPA', call is toggleRefine('beer > IPA'), refinement should be `beer` this . hierarchicalFacetsRefinements [ facet ] [ 0 ] === value || // remove a parent refinement of the current refinement: //  - refinement was 'beer > IPA > Flying dog' //  - call is toggleRefine('beer > IPA') //  - refinement should be `beer` this . hierarchicalFacetsRefinements [ facet ] [ 0 ] . indexOf ( value + separator ) === 0 ) ; if ( upOneOrMultipleLevel ) { if ( value . indexOf ( separator ) === - 1 ) { // go back to root level mod [ facet ] = [ ] ; } else { mod [ facet ] = [ value . slice ( 0 , value . lastIndexOf ( separator ) ) ] ; } } else { mod [ facet ] = [ value ] ; } return this . setQueryParameters ( { hierarchicalFacetsRefinements : defaults ( { } , mod , this . hierarchicalFacetsRefinements ) } ) ; }