<commit_before>// Copyright 2002-2015, University of Colorado Boulder

/**
 * Gets configuration information that is required by the 'build' task.
 * Reads information from multiple places, including:
 *
 * chipper/build.json
 * $HOME/.phet/build-local.json
 * REPO/package.json
 * grunt.options( optionName )
 *
 * The information is shared via global variable global.phet.chipper.buildConfig.
 * All entries are @public (read-only).
 * Entries include:
 *
 * {string} name - name of the repository being built
 * {string} version - version identifier
 * {string} license - license
 * {string} simTitleStringKey - key of the sim's title string
 * {string} brand - brand identifier
 * {string[]} phetLibs - other repositories that are required by the sim
 * {string[]} preload - scripts that need to be preloaded in the .html file, in the order that they will be preloaded
 * {string[]} licenseKeys - keys to licenses in sherpa/lib/license.json, for third-party dependencies
 * {string} fallbackLocale - the locale to use if none is specified
 * {string[]} locales - locales to build
 * {Object} gruntConfig
 *
 * @author Chris Malley (PixelZoom, Inc.)
 */

// The following comment permits node-specific globals (such as process.cwd()) to pass jshint
/* jslint node: true */
'use strict';

// built-in node APIs
var assert = require( 'assert' );
var fs = require( 'fs' );

// 3rd-party packages
/* jshint -W079 */
var _ = require( '../../../sherpa/lib/lodash-2.4.1.min' ); // allow _ to be redefined, contrary to jshintOptions.js
/* jshint +W079 */

/**
 * @param {Object} grunt - the grunt instance
 */
module.exports = function( grunt ) {

  /**
   * Gets the brand identifier.
   *
   * @param {Object} grunt - the grunt instance
   * @param {Object} buildLocalJSON - build-local.json
   * @returns {string}
   */
  function getBrand( grunt, buildLocalJSON ) {
    return grunt.option( 'brand' ) || buildLocalJSON.brand || 'adapted-from-phet';
  }

  /**
   * Gets phetLibs, the set of repositories on which the repository being built depends.
   *
   * @param {Object} packageJSON - package.json
   * @param {Object} buildJSON - build.json
   * @param {string} brand
   * @returns {string[]}
   */
  function getPhetLibs( packageJSON, buildJSON, brand ) {

    // start with package.json
    var phetLibs = packageJSON.phet.phetLibs || [];

    // add the repo that's being built
    phetLibs.push( packageJSON.name );

    // add common and brand-specific entries from build.json
    [ 'common', brand ].forEach( function( id ) {
      if ( buildJSON[ id ] && buildJSON[ id ].phetLibs ) {
        phetLibs = phetLibs.concat( buildJSON[ id ].phetLibs );
      }
    } );

    // sort and remove duplicates
    return _.uniq( phetLibs.sort() );
  }

  /**
   * Gets preload, the set of scripts to be preloaded in the .html file.
   * NOTE! Order of the return value is significant, since it corresponds to the order in which scripts will be preloaded.
   *
   * @param {Object} packageJSON - package.json
   * @param {Object} buildJSON - build.json
   * @param {string} brand
   * @returns {string[]}
   */
  function getPreload( packageJSON, buildJSON, brand ) {

    var preload = [];

    // add preloads that are common to all sims, from build.json
    if ( buildJSON.common && buildJSON.common.preload ) {
      preload = preload.concat( buildJSON.common.preload );
    }

    // add sim-specific preloads from package.json
    if ( packageJSON.preload ) {
      preload = preload.concat( packageJSON.preload );
    }

    // add brand-specific preloads from build.json
    if ( buildJSON[ buildConfig.brand ] && buildJSON[ buildConfig.brand ].preload ) {
      preload = preload.concat( buildJSON[ buildConfig.brand ].preload );
    }

    // add the together API file
    if ( brand === 'phet-io' ) {
      var TOGETHER_API_FILENAME = '../together/js/api/' + packageJSON.name + '-api.js';
      assert( fs.existsSync( TOGETHER_API_FILENAME ), 'together API file does not exist: ' + TOGETHER_API_FILENAME );
      preload.push( TOGETHER_API_FILENAME );
    }

    // sort and remove duplicates
    return _.uniq( preload.sort() );
  }

  /**
   * Gets the license keys for sherpa (third-party) libs that are used.
   *
   * @param {Object} packageJSON - package.json
   * @param {Object} buildJSON - build.json
   * @param {string} brand
   * @param {string[]} preload
   * @returns {string[]}
   */
  function getLicenseKeys( packageJSON, buildJSON, brand, preload ) {

    // start with package.json
    var licenseKeys = packageJSON.phet.licenseKeys || [];

    // add common and brand-specific entries from build.json
    [ 'common', brand ].forEach( function( id ) {
      if ( buildJSON[ id ] && buildJSON[ id ].licenseKeys ) {
        licenseKeys = licenseKeys.concat( buildJSON[ id ].licenseKeys );
      }
    } );

    // Extract keys from preload for sherpa (third-party) dependencies
    preload.forEach( function( path ) {
      if ( path.indexOf( '/sherpa/' ) !== -1 ) {
        var lastSlash = path.lastIndexOf( '/' );
        var key = path.substring( lastSlash + 1 );
        licenseKeys.push( key );
      }
    } );

    // sort and remove duplicates
    return _.uniq( _.sortBy( licenseKeys, function( key ) { return key.toUpperCase(); } ) );
  }

  /*
   * Gets the locales from a repository, by inspecting the names of the string files in that repository.
   *
   * @param {string} repository - name of the repository to get locales from
   */
  function getLocalesFromRepository( repository ) {

    // confirm that the repository has a strings directory
    var stringsDirectory = '../babel/' + repository;
    var stats = fs.statSync( stringsDirectory );
    assert( stats.isDirectory(), stringsDirectory + 'is not a directory' );

    // Get names of string files.
    var stringFiles = fs.readdirSync( stringsDirectory ).filter( function( filename ) {
      return (/^.*-strings.*\.json/).test( filename );
    } );
    assert( stringFiles.length > 0, 'no string files found in ' + stringsDirectory );

    // Extract the locales from the file names.
    // File names must have a form like 'graphing-lines-strings_ar_SA.json', where no '_' appear in the repo name.
    var locales = stringFiles.map( function( filename ) {
      return filename.substring( filename.indexOf( '_' ) + 1, filename.lastIndexOf( '.' ) );
    } );
    assert( locales.length > 0, 'no locales found in ' + stringsDirectory );

    return locales;
  }

  /*
   * Gets the set of locales to be built.
   *
   * The grunt options are:
   *
   * --locales=* : all locales from the repo's strings/ directory
   * --locales=fr : French
   * --locales=ar,fr,es : Arabic, French and Spanish (comma-separated locales)
   * --localesRepo=beers-law-lab: all locales from another repository's strings/ directory, ignored if --locales is specified
   *
   * @param {Object} grunt - the grunt instance
   * @param {string} repository - name of the repository that is being built
   * @param {string} fallbackLocale - the locale to build if no locales are specified
   */
  function getLocales( grunt, repository, fallbackLocale ) {

    var locales = grunt.option( 'locales' );

    if ( locales ) {
      if ( locales === '*' ) {
        locales = getLocalesFromRepository( repository ); // all locales for the repository that we're building
      }
      else {
        buildConfig.locales = _.uniq( gruntOptions.locales.split( ',' ) );
      }
    }
    else {
      var localesRepo = grunt.option( 'localesRepo' );
      if ( localesRepo ) {
        locales = getLocalesFromRepository( localesRepo ); // all locales for some other repository
      }
      else {
        locales = [ fallbackLocale ];
      }
    }
    return locales;
  }

  /**
   * Gets the JSHint configuration object.
   *
   * @param {Object} packageJSON - package.json
   * @param {string[]} phetLibs
   * @returns {Object}
   */
  function getJSHintConfig( packageJSON, phetLibs ) {

    // Repository files to be linted. brand has a non-standard directory structure.
    var repoFilesToLint = ( packageJSON.name === 'brand' ) ? [ '*/js/**/*.js' ] : [ 'js/**/*.js' ];

    // All files to be linted
    var allFilesToLint = _.map( phetLibs, function( repo ) {
      return '../' + repo + '/js/**/*.js';
    } );

    // brand repo has a non-standard directory structure, so add it explicitly if it's a dependency.
    if ( packageJSON.name !== 'brand' ) {
      allFilesToLint.push( '../brand/*/js/**/*.js' );
    }

    // Exclude svgPath.js, it was automatically generated and doesn't match pass lint.
    allFilesToLint.push( '!../kite/js/parser/svgPath.js' );
    allFilesToLint = _.uniq( allFilesToLint );

    //TODO provide a reference for where these fields are defined
    return {

      // Source files that are specific to this repository
      repoFiles: repoFilesToLint,

      // All source files for this repository (repository-specific and dependencies).
      allFiles: allFilesToLint,

      // Reference external options in jshintOptions.js
      options: require( './jshintOptions' )
    };
  }

  //------------------------------------------------------------------------------------
  // grunt config

  /**
   * Gets the Grunt configuration object.
   *
   * @param {Object} packageJSON - package.json
   * @param {strings[]} phetLibs
   */
  function getGruntConfig( packageJSON, phetLibs ) {
    return {

      // Setting pkg allows us to refer to package.json entries from within this config
      pkg: packageJSON,

      jshint: getJSHintConfig( packageJSON, phetLibs ),

      //TODO provide a reference for where these fields are defined
      // configure the RequireJS plugin
      requirejs: {

        // builds the minified script
        build: {

          options: {

            almond: true,
            mainConfigFile: 'js/<%= pkg.name %>-config.js',
            out: 'build/<%= pkg.name %>.min.js',
            name: '<%= pkg.name %>-config',

            // Minification strategy.  Put this to none if you want to debug a non-minified but compiled version
            optimize: 'uglify2',
            wrap: true,
            // generateSourceMaps: true, //#42 commented out this line until source maps are fixed
            preserveLicenseComments: false,
            uglify2: {
              output: {
                inline_script: true // escape </script
              },
              compress: {
                global_defs: {
                  // global assertions
                  assert: false,
                  assertSlow: false,
                  // scenery logging
                  sceneryLog: false,
                  sceneryLayerLog: false,
                  sceneryEventLog: false,
                  sceneryAccessibilityLog: false,
                  phetAllocation: false
                },
                dead_code: true
              }
            },

            //TODO should 'mipmap' be in here too?
            // stub out the plugins, so their source code won't be included in the minified file
            stubModules: [ 'string', 'audio', 'image' ]
          }
        }
      }
    };
  }

  //------------------------------------------------------------------------------------
  // read configuration files

  // ./package.json (required)
  var PACKAGE_FILENAME = 'package.json';
  assert( fs.existsSync( PACKAGE_FILENAME ), 'missing ' + PACKAGE_FILENAME );
  var packageJSON = grunt.file.readJSON( PACKAGE_FILENAME );
  assert( packageJSON.name, 'name missing from ' + PACKAGE_FILENAME );
  assert( packageJSON.version, 'version missing from ' + PACKAGE_FILENAME );
  assert( packageJSON.license, 'license missing from ' + PACKAGE_FILENAME );

  // chipper/build.json (required)
  var BUILD_FILENAME = '../chipper/build.json';
  assert( fs.existsSync( BUILD_FILENAME ), 'missing ' + BUILD_FILENAME );
  var buildJSON = grunt.file.readJSON( BUILD_FILENAME );

  // $HOME/.phet/build-local.json (optional)
  var BUILD_LOCAL_FILENAME = process.env.HOME + '/.phet/build-local.json';
  var buildLocalJSON = {};
  if ( fs.existsSync( BUILD_LOCAL_FILENAME ) ) {
    buildLocalJSON = grunt.file.readJSON( BUILD_LOCAL_FILENAME );
  }

  //------------------------------------------------------------------------------------
  // Assemble the buildConfig

  var buildConfig = {
    // These entries have no dependencies on other entries in buildConfig.
    name: packageJSON.name,
    version: packageJSON.version,
    license: packageJSON.name,
    simTitleStringKey: packageJSON.simTitleStringKey,
    brand: getBrand( grunt, buildLocalJSON ),
    fallbackLocale: 'en'
  };

  // These entries depend on other entries in buildConfig.
  buildConfig.phetLibs = getPhetLibs( packageJSON, buildJSON, buildConfig.brand );
  buildConfig.preload = getPreload( packageJSON, buildJSON, buildConfig.brand );
  buildConfig.licenseKeys = getLicenseKeys( packageJSON, buildJSON, buildConfig.brand, buildConfig.preload );
  buildConfig.locales = getLocales( grunt, buildConfig.name, buildConfig.fallbackLocale );
  buildConfig.gruntConfig = getGruntConfig( packageJSON, buildConfig.phetLibs );

  grunt.log.debug( 'buildConfig=' + JSON.stringify( buildConfig, null, 2 ) );
  return buildConfig;
};
<commit_msg>delete vestigial comment<commit_after>// Copyright 2002-2015, University of Colorado Boulder

/**
 * Gets configuration information that is required by the 'build' task.
 * Reads information from multiple places, including:
 *
 * chipper/build.json
 * $HOME/.phet/build-local.json
 * REPO/package.json
 * grunt.options( optionName )
 *
 * The information is shared via global variable global.phet.chipper.buildConfig.
 * All entries are @public (read-only).
 * Entries include:
 *
 * {string} name - name of the repository being built
 * {string} version - version identifier
 * {string} license - license
 * {string} simTitleStringKey - key of the sim's title string
 * {string} brand - brand identifier
 * {string[]} phetLibs - other repositories that are required by the sim
 * {string[]} preload - scripts that need to be preloaded in the .html file, in the order that they will be preloaded
 * {string[]} licenseKeys - keys to licenses in sherpa/lib/license.json, for third-party dependencies
 * {string} fallbackLocale - the locale to use if none is specified
 * {string[]} locales - locales to build
 * {Object} gruntConfig
 *
 * @author Chris Malley (PixelZoom, Inc.)
 */

// The following comment permits node-specific globals (such as process.cwd()) to pass jshint
/* jslint node: true */
'use strict';

// built-in node APIs
var assert = require( 'assert' );
var fs = require( 'fs' );

// 3rd-party packages
/* jshint -W079 */
var _ = require( '../../../sherpa/lib/lodash-2.4.1.min' ); // allow _ to be redefined, contrary to jshintOptions.js
/* jshint +W079 */

/**
 * @param {Object} grunt - the grunt instance
 */
module.exports = function( grunt ) {

  /**
   * Gets the brand identifier.
   *
   * @param {Object} grunt - the grunt instance
   * @param {Object} buildLocalJSON - build-local.json
   * @returns {string}
   */
  function getBrand( grunt, buildLocalJSON ) {
    return grunt.option( 'brand' ) || buildLocalJSON.brand || 'adapted-from-phet';
  }

  /**
   * Gets phetLibs, the set of repositories on which the repository being built depends.
   *
   * @param {Object} packageJSON - package.json
   * @param {Object} buildJSON - build.json
   * @param {string} brand
   * @returns {string[]}
   */
  function getPhetLibs( packageJSON, buildJSON, brand ) {

    // start with package.json
    var phetLibs = packageJSON.phet.phetLibs || [];

    // add the repo that's being built
    phetLibs.push( packageJSON.name );

    // add common and brand-specific entries from build.json
    [ 'common', brand ].forEach( function( id ) {
      if ( buildJSON[ id ] && buildJSON[ id ].phetLibs ) {
        phetLibs = phetLibs.concat( buildJSON[ id ].phetLibs );
      }
    } );

    // sort and remove duplicates
    return _.uniq( phetLibs.sort() );
  }

  /**
   * Gets preload, the set of scripts to be preloaded in the .html file.
   * NOTE! Order of the return value is significant, since it corresponds to the order in which scripts will be preloaded.
   *
   * @param {Object} packageJSON - package.json
   * @param {Object} buildJSON - build.json
   * @param {string} brand
   * @returns {string[]}
   */
  function getPreload( packageJSON, buildJSON, brand ) {

    var preload = [];

    // add preloads that are common to all sims, from build.json
    if ( buildJSON.common && buildJSON.common.preload ) {
      preload = preload.concat( buildJSON.common.preload );
    }

    // add sim-specific preloads from package.json
    if ( packageJSON.preload ) {
      preload = preload.concat( packageJSON.preload );
    }

    // add brand-specific preloads from build.json
    if ( buildJSON[ buildConfig.brand ] && buildJSON[ buildConfig.brand ].preload ) {
      preload = preload.concat( buildJSON[ buildConfig.brand ].preload );
    }

    // add the together API file
    if ( brand === 'phet-io' ) {
      var TOGETHER_API_FILENAME = '../together/js/api/' + packageJSON.name + '-api.js';
      assert( fs.existsSync( TOGETHER_API_FILENAME ), 'together API file does not exist: ' + TOGETHER_API_FILENAME );
      preload.push( TOGETHER_API_FILENAME );
    }

    // sort and remove duplicates
    return _.uniq( preload.sort() );
  }

  /**
   * Gets the license keys for sherpa (third-party) libs that are used.
   *
   * @param {Object} packageJSON - package.json
   * @param {Object} buildJSON - build.json
   * @param {string} brand
   * @param {string[]} preload
   * @returns {string[]}
   */
  function getLicenseKeys( packageJSON, buildJSON, brand, preload ) {

    // start with package.json
    var licenseKeys = packageJSON.phet.licenseKeys || [];

    // add common and brand-specific entries from build.json
    [ 'common', brand ].forEach( function( id ) {
      if ( buildJSON[ id ] && buildJSON[ id ].licenseKeys ) {
        licenseKeys = licenseKeys.concat( buildJSON[ id ].licenseKeys );
      }
    } );

    // Extract keys from preload for sherpa (third-party) dependencies
    preload.forEach( function( path ) {
      if ( path.indexOf( '/sherpa/' ) !== -1 ) {
        var lastSlash = path.lastIndexOf( '/' );
        var key = path.substring( lastSlash + 1 );
        licenseKeys.push( key );
      }
    } );

    // sort and remove duplicates
    return _.uniq( _.sortBy( licenseKeys, function( key ) { return key.toUpperCase(); } ) );
  }

  /*
   * Gets the locales from a repository, by inspecting the names of the string files in that repository.
   *
   * @param {string} repository - name of the repository to get locales from
   */
  function getLocalesFromRepository( repository ) {

    // confirm that the repository has a strings directory
    var stringsDirectory = '../babel/' + repository;
    var stats = fs.statSync( stringsDirectory );
    assert( stats.isDirectory(), stringsDirectory + 'is not a directory' );

    // Get names of string files.
    var stringFiles = fs.readdirSync( stringsDirectory ).filter( function( filename ) {
      return (/^.*-strings.*\.json/).test( filename );
    } );
    assert( stringFiles.length > 0, 'no string files found in ' + stringsDirectory );

    // Extract the locales from the file names.
    // File names must have a form like 'graphing-lines-strings_ar_SA.json', where no '_' appear in the repo name.
    var locales = stringFiles.map( function( filename ) {
      return filename.substring( filename.indexOf( '_' ) + 1, filename.lastIndexOf( '.' ) );
    } );
    assert( locales.length > 0, 'no locales found in ' + stringsDirectory );

    return locales;
  }

  /*
   * Gets the set of locales to be built.
   *
   * The grunt options are:
   *
   * --locales=* : all locales from the repo's strings/ directory
   * --locales=fr : French
   * --locales=ar,fr,es : Arabic, French and Spanish (comma-separated locales)
   * --localesRepo=beers-law-lab: all locales from another repository's strings/ directory, ignored if --locales is specified
   *
   * @param {Object} grunt - the grunt instance
   * @param {string} repository - name of the repository that is being built
   * @param {string} fallbackLocale - the locale to build if no locales are specified
   */
  function getLocales( grunt, repository, fallbackLocale ) {

    var locales = grunt.option( 'locales' );

    if ( locales ) {
      if ( locales === '*' ) {
        locales = getLocalesFromRepository( repository ); // all locales for the repository that we're building
      }
      else {
        buildConfig.locales = _.uniq( gruntOptions.locales.split( ',' ) );
      }
    }
    else {
      var localesRepo = grunt.option( 'localesRepo' );
      if ( localesRepo ) {
        locales = getLocalesFromRepository( localesRepo ); // all locales for some other repository
      }
      else {
        locales = [ fallbackLocale ];
      }
    }
    return locales;
  }

  /**
   * Gets the JSHint configuration object.
   *
   * @param {Object} packageJSON - package.json
   * @param {string[]} phetLibs
   * @returns {Object}
   */
  function getJSHintConfig( packageJSON, phetLibs ) {

    // Repository files to be linted. brand has a non-standard directory structure.
    var repoFilesToLint = ( packageJSON.name === 'brand' ) ? [ '*/js/**/*.js' ] : [ 'js/**/*.js' ];

    // All files to be linted
    var allFilesToLint = _.map( phetLibs, function( repo ) {
      return '../' + repo + '/js/**/*.js';
    } );

    // brand repo has a non-standard directory structure, so add it explicitly if it's a dependency.
    if ( packageJSON.name !== 'brand' ) {
      allFilesToLint.push( '../brand/*/js/**/*.js' );
    }

    // Exclude svgPath.js, it was automatically generated and doesn't match pass lint.
    allFilesToLint.push( '!../kite/js/parser/svgPath.js' );
    allFilesToLint = _.uniq( allFilesToLint );

    //TODO provide a reference for where these fields are defined
    return {

      // Source files that are specific to this repository
      repoFiles: repoFilesToLint,

      // All source files for this repository (repository-specific and dependencies).
      allFiles: allFilesToLint,

      // Reference external options in jshintOptions.js
      options: require( './jshintOptions' )
    };
  }

  /**
   * Gets the Grunt configuration object.
   *
   * @param {Object} packageJSON - package.json
   * @param {strings[]} phetLibs
   */
  function getGruntConfig( packageJSON, phetLibs ) {
    return {

      // Setting pkg allows us to refer to package.json entries from within this config
      pkg: packageJSON,

      jshint: getJSHintConfig( packageJSON, phetLibs ),

      //TODO provide a reference for where these fields are defined
      // configure the RequireJS plugin
      requirejs: {

        // builds the minified script
        build: {

          options: {

            almond: true,
            mainConfigFile: 'js/<%= pkg.name %>-config.js',
            out: 'build/<%= pkg.name %>.min.js',
            name: '<%= pkg.name %>-config',

            // Minification strategy.  Put this to none if you want to debug a non-minified but compiled version
            optimize: 'uglify2',
            wrap: true,
            // generateSourceMaps: true, //#42 commented out this line until source maps are fixed
            preserveLicenseComments: false,
            uglify2: {
              output: {
                inline_script: true // escape </script
              },
              compress: {
                global_defs: {
                  // global assertions
                  assert: false,
                  assertSlow: false,
                  // scenery logging
                  sceneryLog: false,
                  sceneryLayerLog: false,
                  sceneryEventLog: false,
                  sceneryAccessibilityLog: false,
                  phetAllocation: false
                },
                dead_code: true
              }
            },

            //TODO should 'mipmap' be in here too?
            // stub out the plugins, so their source code won't be included in the minified file
            stubModules: [ 'string', 'audio', 'image' ]
          }
        }
      }
    };
  }

  //------------------------------------------------------------------------------------
  // read configuration files

  // ./package.json (required)
  var PACKAGE_FILENAME = 'package.json';
  assert( fs.existsSync( PACKAGE_FILENAME ), 'missing ' + PACKAGE_FILENAME );
  var packageJSON = grunt.file.readJSON( PACKAGE_FILENAME );
  assert( packageJSON.name, 'name missing from ' + PACKAGE_FILENAME );
  assert( packageJSON.version, 'version missing from ' + PACKAGE_FILENAME );
  assert( packageJSON.license, 'license missing from ' + PACKAGE_FILENAME );

  // chipper/build.json (required)
  var BUILD_FILENAME = '../chipper/build.json';
  assert( fs.existsSync( BUILD_FILENAME ), 'missing ' + BUILD_FILENAME );
  var buildJSON = grunt.file.readJSON( BUILD_FILENAME );

  // $HOME/.phet/build-local.json (optional)
  var BUILD_LOCAL_FILENAME = process.env.HOME + '/.phet/build-local.json';
  var buildLocalJSON = {};
  if ( fs.existsSync( BUILD_LOCAL_FILENAME ) ) {
    buildLocalJSON = grunt.file.readJSON( BUILD_LOCAL_FILENAME );
  }

  //------------------------------------------------------------------------------------
  // Assemble the buildConfig

  var buildConfig = {
    // These entries have no dependencies on other entries in buildConfig.
    name: packageJSON.name,
    version: packageJSON.version,
    license: packageJSON.name,
    simTitleStringKey: packageJSON.simTitleStringKey,
    brand: getBrand( grunt, buildLocalJSON ),
    fallbackLocale: 'en'
  };

  // These entries depend on other entries in buildConfig.
  buildConfig.phetLibs = getPhetLibs( packageJSON, buildJSON, buildConfig.brand );
  buildConfig.preload = getPreload( packageJSON, buildJSON, buildConfig.brand );
  buildConfig.licenseKeys = getLicenseKeys( packageJSON, buildJSON, buildConfig.brand, buildConfig.preload );
  buildConfig.locales = getLocales( grunt, buildConfig.name, buildConfig.fallbackLocale );
  buildConfig.gruntConfig = getGruntConfig( packageJSON, buildConfig.phetLibs );

  grunt.log.debug( 'buildConfig=' + JSON.stringify( buildConfig, null, 2 ) );
  return buildConfig;
};
<|endoftext|>


<commit_before>var crc32 = require('crc-32');
var pad = function(n, width, z) {
    z = z || '0';
    n = n + '';
    return n.length >= width ? n : new Array(width - n.length + 1).join(z) + n;
};

module.exports = function(str) {
    var checksum = crc32.str(str);
    // convert to 2's complement hex
    var str = (checksum >>> 0).toString(16);
    return pad(str, 8);
};
<commit_msg>fixes jshint error<commit_after>var crc32 = require('crc-32');
var pad = function(n, width, z) {
    z = z || '0';
    n = n + '';
    return n.length >= width ? n : new Array(width - n.length + 1).join(z) + n;
};

module.exports = function(str) {
    var checksum = crc32.str(str);
    // convert to 2's complement hex
    return pad((checksum >>> 0).toString(16), 8);
};
<|endoftext|>


<commit_before>module.exports = {
  preset: 'ts-jest',
  testEnvironment: 'node',
};<commit_msg>Format js files<commit_after>module.exports = {
  preset: 'ts-jest',
  testEnvironment: 'node'
}
<|endoftext|>


<commit_before>/**
 * @module datasource-executor
 */
'use strict';

var _ = require('lodash');
var Promise = require('when').Promise;
var cast = require('./cast');
var Status = require('flora-cluster').Status;
var Profiler = require('./profiler');

/**
 * Actually execute a resolved request and call the DataSources.
 *
 * @param {Api}     api
 * @param {flora.Request} request
 * @param {Object}  dst         - DataSourceTree
 * @param {Function}callback
 */
module.exports = function execute(api, request, dst, callback) {
    dst._profiler = dst._profiler || new Profiler();
    executeDst(api, request, dst)
        .then(function (results) {
            callback(null, results);
        }, callback);
};

/**
 * Execute all DataSources.
 *
 * Executes all subFilters, the main request and the subRequests, and may be
 * recursively called by the subRequests.
 *
 * @param {Api}    api
 * @param {flora.Request} request
 * @param {Object} dst DataSourceTree
 * @return {Promise}
 * @private
 */
function executeDst(api, request, dst) {
    var globalResults;

    return (new Promise(function (resolve) {
        resolve();
    }))

        // Execute subFilters
        .then(function executeSubFilters() {
            var subFilters = [];
            if (dst.subFilters) {
                subFilters = dst.subFilters.map(function (subFilter) {
                    subFilter._profiler = dst._profiler;
                    return executeDst(api, request, subFilter);
                });
            }

            return Promise.all(subFilters);
        })

        // Adjust the main request's filter to include the results from the subFilters
        .then(function handleSubFilterResults(allSubFilterResults) {
            /*
             * allSubFilterResults:
             * Results from all subFilters.
             * - Outer array: foreach subFilter
             * - Inner array: list of results per subFilter request.
             *   As there are no subRequests in subFilters, the length is 1
             */

            if (!dst.request.filter) return true;

            // Build filter array for the main request
            var parentValues = {};
            /*
             * parentValues:
             * case 1: combined key:
             *   indexed by concatenated filter field:
             *   Example:
             *     {
             *       'instrumentId-exchangeId': [
             *         [133962, 12],
             *         [134000, 12]
             *       ]
             *     }
             * case 2: single key:
             *    Example:
             *     {
             *       'instrumentId': [133962, 134000]
             *     }
             */

            allSubFilterResults.forEach(function (subFilterResults) {
                var subFilterResult = subFilterResults[0]; // only main result from each subFilter
                var parentKey = subFilterResult.parentKey.join('-');
                parentValues[parentKey] = parentValues[parentKey] || [];
                parentValues[parentKey].push(subFilterResult.data.map(function (ff) {
                    if (subFilterResult.parentKey.length === 1) {
                        return ff[subFilterResult.childKey[0]];
                    }
                    return subFilterResult.childKey.map(function (childKeyPart) {
                        return ff[childKeyPart];
                    });
                }));
            });

            // Prevent duplicates for all parentValues properties
            for (var parentKeyIdx in parentValues) {
                for (var i = 0; i < parentValues[parentKeyIdx].length; i++) {
                    parentValues[parentKeyIdx][i] = _.uniqWith(parentValues[parentKeyIdx][i], _.isEqual);
                }
            }

            // Replace "valueFromSubFilter" properties for the main resource
            // by the values from the parentValues object
            var requestFilter = [];
            dst.request.filter.forEach(function (filter) {
                var filterNew = [];
                filter.forEach(function (filterPart) {
                    if (dst._isEmpty) return;

                    if (!filterPart.valueFromSubFilter) {
                        filterNew.push(filterPart);
                        return;
                    }

                    var attributeIdx = Array.isArray(filterPart.attribute)
                        ? filterPart.attribute.join('-')
                        : filterPart.attribute;

                    if (!parentValues[attributeIdx]) {
                        throw new Error('Missing subFilter for attribute "' + filterPart.attribute + '"');
                    }

                    parentValues[attributeIdx].forEach(function (pv) {
                        if (dst._isEmpty) return;

                        if (pv.length === 0) {
                            // One of the subFilters return an empty result,
                            // so the main results will also be empty, no need to execute
                            dst._isEmpty = true;
                            filterNew.push(filterPart);
                            return;
                        }

                        var filterPartNew = _.clone(filterPart);

                        if (!Array.isArray(filterPart.attribute)) {
                            filterPartNew.value = pv;
                        } else {
                            filterPartNew.value = [];
                            for (var j = 0; j < filterPart.attribute.length; j++) {
                                filterPartNew.value[j] = pv[j];
                            }
                        }

                        filterNew.push(filterPartNew);
                    });
                });
                requestFilter.push(filterNew);
            });

            dst.request.filter = requestFilter;
        })

        // Cast filter values to their storedType
        .then(function castFilterValues() {
            if (dst._isEmpty) return;
            if (!dst.request.filter) return;
            if (!dst.attributeOptions) return;

            dst.request.filter.forEach(function (filter) {
                if (!filter) return;

                filter.forEach(function (filterPart) {
                    var storedType;

                    if (Array.isArray(filterPart.attribute)) {
                        for (var j = 0; j < filterPart.attribute.length; j++) {
                            storedType = (dst.attributeOptions[filterPart.attribute[j]]) ?
                                dst.attributeOptions[filterPart.attribute[j]].storedType : null;
                            if (!storedType) continue;
                            if (Array.isArray(filterPart.value[j])) {
                                filterPart.value[j] = filterPart.value[j].map(function (valuePart) {
                                    return cast(valuePart, storedType);
                                });
                            } else {
                                filterPart.value[j] = cast(filterPart.value[j], storedType);
                            }
                        }
                    } else {
                        storedType = (dst.attributeOptions[filterPart.attribute]) ?
                            dst.attributeOptions[filterPart.attribute].storedType : null;
                        if (!storedType) return;
                        if (Array.isArray(filterPart.value)) {
                            filterPart.value = filterPart.value.map(function (valuePart) {
                                return cast(valuePart, storedType);
                            });
                        } else {
                            filterPart.value = cast(filterPart.value, storedType);
                        }
                    }
                });
            });
        })

        // extension: "preExecute" (resource)
        .then(function invokePreExecute() {
            var resource = api.getResource(dst.resourceName);
            if (resource && resource.extensions && resource.extensions.preExecute) {
                api.log.trace('handle: "preExecute" extension (%s)', dst.resourceName);
                resource.extensions.preExecute({
                    name: dst.dataSourceName,
                    request: dst.request,
                    dataSourceTree: dst,
                    floraRequest: request
                });
            }
        })

        // Execute the main request
        .then(function executeMainRequest() {
            var result = {
                data: [],
                totalCount: 0
            };
            [
                'attributePath', 'dataSourceName', 'childKey', 'parentKey',
                'multiValuedParentKey', 'uniqueChildKey'
            ].forEach(function (key) {
                if (dst.hasOwnProperty(key)) result[key] = dst[key];
            });

            return new Promise(function (resolve, reject) {
                if (dst._isEmpty) return resolve(result);

                var ds = api.dataSources[dst.request.type];
                if (!ds) return reject(new Error('Unknown DataSource type "' + dst.request.type + '"'));

                // TODO: Move requestName generation into request-resolver:
                var requestName = 'unnamedRequest';
                if (dst.attributePath) {
                    requestName = (dst.attributePath.length > 0 ? dst.attributePath.join('.') : '{root}') +
                        ':' + dst.dataSourceName;
                }

                dst.request._status = request._status ? request._status.addChild('dataSourceRequests') : new Status();
                dst.request._status.set('requestName', requestName);
                dst.request._status.set('type', dst.request.type);

                if (request._explain) dst.request._explain = {};

                dst.request._profiler = dst._profiler.child(requestName);

                ds.process(dst.request, function (err, rows) {
                    dst.request._profiler.end();
                    dst.request._status.close();
                    if (dst.request._explain) {
                        if (!err && Array.isArray(rows.data)) {
                            dst.request._explain.countRows = rows.data.length;
                        }
                        if (err) dst.request._explain.error = '' + err;
                        if (!dst.request._explain.duration) {
                            dst.request._explain.duration = dst.request._profiler.getDuration();
                        }
                    }
                    if (err) {
                        err.info = err.info || {};
                        err.info.dataSource = requestName;
                        return reject(err);
                    }

                    result.data = rows.data;
                    result.totalCount = rows.totalCount;
                    resolve(result);
                });
            });
        })

        // Transform the main results, do type casting
        .then(function transformMainResults(mainResults) {
            /*
             * mainResults:
             * {
             *   "data": [
             *      {id: 1, firstname: "Alice"},
             *      {id: 3, firstname: "Bob"}, ...
             *   ]
             *   "totalCount": null // or the real count
             * }
             */
            if (!dst.attributeOptions) return mainResults;
            if (typeof dst.attributeOptions !== 'object') return mainResults;

            for (var idx in mainResults.data) {
                if (typeof mainResults.data[idx] !== 'object') continue;
                for (var key in mainResults.data[idx]) {
                    if (!dst.attributeOptions[key] || !dst.attributeOptions[key].type) continue;
                    mainResults.data[idx][key] = cast(mainResults.data[idx][key], dst.attributeOptions[key]);
                }
            }

            return mainResults;
        })

        // extension: "postExecute" (resource)
        .then(function invokePostExecute(mainResults) {
            var resource = api.getResource(dst.resourceName);
            if (resource && resource.extensions && resource.extensions.postExecute) {
                api.log.trace('handle: "postExecute" extension (%s)', dst.resourceName);
                resource.extensions.postExecute({
                    name: dst.dataSourceName,
                    request: dst.request,
                    floraRequest: request,
                    rawResults: mainResults
                });
            }

            return mainResults;
        })

        // Add the main results to our global results array
        .then(function handleMainResults(mainResults) {
            /*
             * globalResults
             * This is whats is being returned by executeDst:
             * [
             *    {data: ...}, // results of the main request
             *    {data: ...}, // results of the first subRequest
             *    {data: ...}, // results of the second subRequest
             *    ...
             * ]
             */
            globalResults = [mainResults];
            return mainResults;
        })

        // Execute the subRequests
        .then(function executeSubRequests(mainResults) {
            if (!dst.subRequests) return [];
            if (!mainResults || mainResults.data.length === 0) return [];

            // Prepare the subRequests that may be dependent from the main results.
            // "valueFromParentKey" properties are replaced by the appropriate values.
            var subRequests = dst.subRequests.map(function (subRequest) {
                var parentValues = [];

                mainResults.data.forEach(function (mainResult) {
                    var isNull = true;
                    var value = subRequest.parentKey.map(function (m) {
                        if (mainResult[m] !== null && typeof mainResult[m] !== 'undefined') isNull = false;
                        return mainResult[m];
                    });
                    if (!isNull) parentValues.push(value);
                });

                // Flatten multiValued keys (not supported for combined keys!)
                if (subRequest.parentKey.length === 1 &&
                    dst.attributeOptions &&
                    dst.attributeOptions[subRequest.parentKey[0]] &&
                    dst.attributeOptions[subRequest.parentKey[0]].multiValued) {
                    var newParentValues = [];
                    parentValues.forEach(function (parentValue) {
                        if (!Array.isArray(parentValue[0])) return;
                        Array.prototype.push.apply(newParentValues, parentValue[0].map(function (value) {
                            return [value];
                        }));
                    });
                    parentValues = newParentValues;
                }

                parentValues = _.uniqWith(parentValues, _.isEqual);
                if (!parentValues.length) subRequest._isEmpty = true;

                subRequest.request.filter.forEach(function (filters) {
                    filters.forEach(function (filter) {
                        if (!filter.valueFromParentKey) return;
                        if (!Array.isArray(filter.attribute)) {
                            filter.value = parentValues.map(function (value) {
                                return value[0];
                            });
                        } else {
                            filter.value = parentValues;
                        }
                    });
                });

                subRequest._profiler = dst._profiler;
                return executeDst(api, request, subRequest);
            });

            return Promise.all(subRequests);
        })

        // Add the subRequest results to the global results array
        .then(function handleSubResults(subResults) {
            delete(dst._isEmpty); // clean up

            subResults.forEach(function (subResult) {
                globalResults = globalResults.concat(subResult);
            });
            return globalResults;
        });
}
<commit_msg>datasource-executor: optimize uniq calls in sub requests<commit_after>/**
 * @module datasource-executor
 */
'use strict';

var _ = require('lodash');
var Promise = require('when').Promise;
var cast = require('./cast');
var Status = require('flora-cluster').Status;
var Profiler = require('./profiler');

/**
 * Actually execute a resolved request and call the DataSources.
 *
 * @param {Api}     api
 * @param {flora.Request} request
 * @param {Object}  dst         - DataSourceTree
 * @param {Function}callback
 */
module.exports = function execute(api, request, dst, callback) {
    dst._profiler = dst._profiler || new Profiler();
    executeDst(api, request, dst)
        .then(function (results) {
            callback(null, results);
        }, callback);
};

/**
 * Execute all DataSources.
 *
 * Executes all subFilters, the main request and the subRequests, and may be
 * recursively called by the subRequests.
 *
 * @param {Api}    api
 * @param {flora.Request} request
 * @param {Object} dst DataSourceTree
 * @return {Promise}
 * @private
 */
function executeDst(api, request, dst) {
    var globalResults;

    return (new Promise(function (resolve) {
        resolve();
    }))

        // Execute subFilters
        .then(function executeSubFilters() {
            var subFilters = [];
            if (dst.subFilters) {
                subFilters = dst.subFilters.map(function (subFilter) {
                    subFilter._profiler = dst._profiler;
                    return executeDst(api, request, subFilter);
                });
            }

            return Promise.all(subFilters);
        })

        // Adjust the main request's filter to include the results from the subFilters
        .then(function handleSubFilterResults(allSubFilterResults) {
            /*
             * allSubFilterResults:
             * Results from all subFilters.
             * - Outer array: foreach subFilter
             * - Inner array: list of results per subFilter request.
             *   As there are no subRequests in subFilters, the length is 1
             */

            if (!dst.request.filter) return true;

            // Build filter array for the main request
            var parentValues = {};
            /*
             * parentValues:
             * case 1: combined key:
             *   indexed by concatenated filter field:
             *   Example:
             *     {
             *       'instrumentId-exchangeId': [
             *         [133962, 12],
             *         [134000, 12]
             *       ]
             *     }
             * case 2: single key:
             *    Example:
             *     {
             *       'instrumentId': [133962, 134000]
             *     }
             */

            allSubFilterResults.forEach(function (subFilterResults) {
                var subFilterResult = subFilterResults[0]; // only main result from each subFilter
                var parentKey = subFilterResult.parentKey.join('-');
                parentValues[parentKey] = parentValues[parentKey] || [];
                parentValues[parentKey].push(subFilterResult.data.map(function (ff) {
                    if (subFilterResult.parentKey.length === 1) {
                        return ff[subFilterResult.childKey[0]];
                    }
                    return subFilterResult.childKey.map(function (childKeyPart) {
                        return ff[childKeyPart];
                    });
                }));
            });

            // Prevent duplicates for all parentValues properties
            for (var parentKeyIdx in parentValues) {
                for (var i = 0; i < parentValues[parentKeyIdx].length; i++) {
                    parentValues[parentKeyIdx][i] = _.uniqWith(parentValues[parentKeyIdx][i], _.isEqual);
                }
            }

            // Replace "valueFromSubFilter" properties for the main resource
            // by the values from the parentValues object
            var requestFilter = [];
            dst.request.filter.forEach(function (filter) {
                var filterNew = [];
                filter.forEach(function (filterPart) {
                    if (dst._isEmpty) return;

                    if (!filterPart.valueFromSubFilter) {
                        filterNew.push(filterPart);
                        return;
                    }

                    var attributeIdx = Array.isArray(filterPart.attribute)
                        ? filterPart.attribute.join('-')
                        : filterPart.attribute;

                    if (!parentValues[attributeIdx]) {
                        throw new Error('Missing subFilter for attribute "' + filterPart.attribute + '"');
                    }

                    parentValues[attributeIdx].forEach(function (pv) {
                        if (dst._isEmpty) return;

                        if (pv.length === 0) {
                            // One of the subFilters return an empty result,
                            // so the main results will also be empty, no need to execute
                            dst._isEmpty = true;
                            filterNew.push(filterPart);
                            return;
                        }

                        var filterPartNew = _.clone(filterPart);

                        if (!Array.isArray(filterPart.attribute)) {
                            filterPartNew.value = pv;
                        } else {
                            filterPartNew.value = [];
                            for (var j = 0; j < filterPart.attribute.length; j++) {
                                filterPartNew.value[j] = pv[j];
                            }
                        }

                        filterNew.push(filterPartNew);
                    });
                });
                requestFilter.push(filterNew);
            });

            dst.request.filter = requestFilter;
        })

        // Cast filter values to their storedType
        .then(function castFilterValues() {
            if (dst._isEmpty) return;
            if (!dst.request.filter) return;
            if (!dst.attributeOptions) return;

            dst.request.filter.forEach(function (filter) {
                if (!filter) return;

                filter.forEach(function (filterPart) {
                    var storedType;

                    if (Array.isArray(filterPart.attribute)) {
                        for (var j = 0; j < filterPart.attribute.length; j++) {
                            storedType = (dst.attributeOptions[filterPart.attribute[j]]) ?
                                dst.attributeOptions[filterPart.attribute[j]].storedType : null;
                            if (!storedType) continue;
                            if (Array.isArray(filterPart.value[j])) {
                                filterPart.value[j] = filterPart.value[j].map(function (valuePart) {
                                    return cast(valuePart, storedType);
                                });
                            } else {
                                filterPart.value[j] = cast(filterPart.value[j], storedType);
                            }
                        }
                    } else {
                        storedType = (dst.attributeOptions[filterPart.attribute]) ?
                            dst.attributeOptions[filterPart.attribute].storedType : null;
                        if (!storedType) return;
                        if (Array.isArray(filterPart.value)) {
                            filterPart.value = filterPart.value.map(function (valuePart) {
                                return cast(valuePart, storedType);
                            });
                        } else {
                            filterPart.value = cast(filterPart.value, storedType);
                        }
                    }
                });
            });
        })

        // extension: "preExecute" (resource)
        .then(function invokePreExecute() {
            var resource = api.getResource(dst.resourceName);
            if (resource && resource.extensions && resource.extensions.preExecute) {
                api.log.trace('handle: "preExecute" extension (%s)', dst.resourceName);
                resource.extensions.preExecute({
                    name: dst.dataSourceName,
                    request: dst.request,
                    dataSourceTree: dst,
                    floraRequest: request
                });
            }
        })

        // Execute the main request
        .then(function executeMainRequest() {
            var result = {
                data: [],
                totalCount: 0
            };
            [
                'attributePath', 'dataSourceName', 'childKey', 'parentKey',
                'multiValuedParentKey', 'uniqueChildKey'
            ].forEach(function (key) {
                if (dst.hasOwnProperty(key)) result[key] = dst[key];
            });

            return new Promise(function (resolve, reject) {
                if (dst._isEmpty) return resolve(result);

                var ds = api.dataSources[dst.request.type];
                if (!ds) return reject(new Error('Unknown DataSource type "' + dst.request.type + '"'));

                // TODO: Move requestName generation into request-resolver:
                var requestName = 'unnamedRequest';
                if (dst.attributePath) {
                    requestName = (dst.attributePath.length > 0 ? dst.attributePath.join('.') : '{root}') +
                        ':' + dst.dataSourceName;
                }

                dst.request._status = request._status ? request._status.addChild('dataSourceRequests') : new Status();
                dst.request._status.set('requestName', requestName);
                dst.request._status.set('type', dst.request.type);

                if (request._explain) dst.request._explain = {};

                dst.request._profiler = dst._profiler.child(requestName);

                ds.process(dst.request, function (err, rows) {
                    dst.request._profiler.end();
                    dst.request._status.close();
                    if (dst.request._explain) {
                        if (!err && Array.isArray(rows.data)) {
                            dst.request._explain.countRows = rows.data.length;
                        }
                        if (err) dst.request._explain.error = '' + err;
                        if (!dst.request._explain.duration) {
                            dst.request._explain.duration = dst.request._profiler.getDuration();
                        }
                    }
                    if (err) {
                        err.info = err.info || {};
                        err.info.dataSource = requestName;
                        return reject(err);
                    }

                    result.data = rows.data;
                    result.totalCount = rows.totalCount;
                    resolve(result);
                });
            });
        })

        // Transform the main results, do type casting
        .then(function transformMainResults(mainResults) {
            /*
             * mainResults:
             * {
             *   "data": [
             *      {id: 1, firstname: "Alice"},
             *      {id: 3, firstname: "Bob"}, ...
             *   ]
             *   "totalCount": null // or the real count
             * }
             */
            if (!dst.attributeOptions) return mainResults;
            if (typeof dst.attributeOptions !== 'object') return mainResults;

            for (var idx in mainResults.data) {
                if (typeof mainResults.data[idx] !== 'object') continue;
                for (var key in mainResults.data[idx]) {
                    if (!dst.attributeOptions[key] || !dst.attributeOptions[key].type) continue;
                    mainResults.data[idx][key] = cast(mainResults.data[idx][key], dst.attributeOptions[key]);
                }
            }

            return mainResults;
        })

        // extension: "postExecute" (resource)
        .then(function invokePostExecute(mainResults) {
            var resource = api.getResource(dst.resourceName);
            if (resource && resource.extensions && resource.extensions.postExecute) {
                api.log.trace('handle: "postExecute" extension (%s)', dst.resourceName);
                resource.extensions.postExecute({
                    name: dst.dataSourceName,
                    request: dst.request,
                    floraRequest: request,
                    rawResults: mainResults
                });
            }

            return mainResults;
        })

        // Add the main results to our global results array
        .then(function handleMainResults(mainResults) {
            /*
             * globalResults
             * This is whats is being returned by executeDst:
             * [
             *    {data: ...}, // results of the main request
             *    {data: ...}, // results of the first subRequest
             *    {data: ...}, // results of the second subRequest
             *    ...
             * ]
             */
            globalResults = [mainResults];
            return mainResults;
        })

        // Execute the subRequests
        .then(function executeSubRequests(mainResults) {
            if (!dst.subRequests) return [];
            if (!mainResults || mainResults.data.length === 0) return [];

            // Prepare the subRequests that may be dependent from the main results.
            // "valueFromParentKey" properties are replaced by the appropriate values.
            var subRequests = dst.subRequests.map(function (subRequest) {
                var parentValues = [];

                mainResults.data.forEach(function (mainResult) {
                    var isNull = true;
                    var value;
                    if (subRequest.parentKey.length === 1) {
                        value = mainResult[subRequest.parentKey[0]];
                        if (value !== null && typeof value !== 'undefined') isNull = false;
                    } else {
                        value = subRequest.parentKey.map(function (m) {
                            if (mainResult[m] !== null && typeof mainResult[m] !== 'undefined') isNull = false;
                            return mainResult[m];
                        });
                    }
                    if (!isNull) parentValues.push(value);
                });

                // Flatten multiValued keys (not supported for combined keys!)
                if (subRequest.parentKey.length === 1 &&
                    dst.attributeOptions &&
                    dst.attributeOptions[subRequest.parentKey[0]] &&
                    dst.attributeOptions[subRequest.parentKey[0]].multiValued) {
                    var newParentValues = [];
                    parentValues.forEach(function (parentValue) {
                        if (!Array.isArray(parentValue)) return;
                        Array.prototype.push.apply(newParentValues, parentValue);
                    });
                    parentValues = _.uniq(newParentValues);
                }

                parentValues = _.uniqWith(parentValues, _.isEqual);

                if (!parentValues.length) subRequest._isEmpty = true;

                subRequest.request.filter.forEach(function (filters) {
                    filters.forEach(function (filter) {
                        if (!filter.valueFromParentKey) return;
                        filter.value = parentValues;
                    });
                });

                subRequest._profiler = dst._profiler;
                return executeDst(api, request, subRequest);
            });

            return Promise.all(subRequests);
        })

        // Add the subRequest results to the global results array
        .then(function handleSubResults(subResults) {
            delete(dst._isEmpty); // clean up

            subResults.forEach(function (subResult) {
                globalResults = globalResults.concat(subResult);
            });
            return globalResults;
        });
}
<|endoftext|>


<commit_before>/*
* jQuery Mobile Framework : "navbar" plugin
* Copyright (c) jQuery Project
* Dual licensed under the MIT (MIT-LICENSE.txt) and GPL (GPL-LICENSE.txt) licenses.
* Note: Code is in draft form and is subject to change
*/
(function($, undefined ) {
$.widget( "mobile.navbar", $.mobile.widget, {
	options: {
		iconpos: 'top'
	},
	_create: function(){
		var $navbar = this.element,
			$navbtns = $navbar.find("a"),
			iconpos = $navbtns.filter('data-icon').length ? this.options.iconpos : undefined;

		$navbar
			.addClass('ui-navbar')
			.attr("role","navigation")
			.find("ul")
				.grid({grid: $navbtns.length > 2 ? "b" : "a"});

		if( !iconpos ){
			$navbar.addClass("ui-navbar-noicons");
		}

		$navbtns
			.buttonMarkup({
				corners:	false,
				shadow:		false,
				iconpos:	iconpos
			});

		$navbar.delegate("a", "click",function(event){
			$navbtns.removeClass("ui-btn-active");
		});
	}
});
})( jQuery );<commit_msg>fixed a bug with icon positioning<commit_after>/*
* jQuery Mobile Framework : "navbar" plugin
* Copyright (c) jQuery Project
* Dual licensed under the MIT (MIT-LICENSE.txt) and GPL (GPL-LICENSE.txt) licenses.
* Note: Code is in draft form and is subject to change
*/
(function($, undefined ) {
$.widget( "mobile.navbar", $.mobile.widget, {
	options: {
		iconpos: 'top'
	},
	_create: function(){
		var $navbar = this.element,
			$navbtns = $navbar.find("a"),
			iconpos = $navbtns.filter('[data-icon]').length ? this.options.iconpos : undefined;

		$navbar
			.addClass('ui-navbar')
			.attr("role","navigation")
			.find("ul")
				.grid({grid: $navbtns.length > 2 ? "b" : "a"});

		if( !iconpos ){
			$navbar.addClass("ui-navbar-noicons");
		}

		$navbtns
			.buttonMarkup({
				corners:	false,
				shadow:		false,
				iconpos:	iconpos
			});

		$navbar.delegate("a", "click",function(event){
			$navbtns.removeClass("ui-btn-active");
		});
	}
});
})( jQuery );<|endoftext|>


<commit_before>module.exports = {
  verbose: false,
  roots: [
    '<rootDir>/src',
    '<rootDir>/test/unit'
  ],
  moduleFileExtensions: [
    'ts',
    'js'
  ],
  moduleDirectories: [
    'node_modules'
  ],
  moduleNameMapper: {
    '^@/test$': '<rootDir>/test/index.js',
    '^@/test/(.*)$': '<rootDir>/test/$1',
    '^@/(.*)$': '<rootDir>/src/$1',
    '\\.(css|sass|scss)$': 'identity-obj-proxy'
  },
  transform: {
    '\\.(styl)$': 'jest-css-modules',
    '\\.(scss)$': 'jest-css-modules',
    '.*\\.(j|t)s$': 'ts-jest'
  },
  mapCoverage: true,
  collectCoverageFrom: [
    'src/**/*.{js,ts,tsx}',
    '!**/*.d.ts'
  ],
  transformIgnorePatterns: [
    'node_modules/(?!vue-router)'
  ],
  snapshotSerializers: [
    'jest-serializer-html'
  ],
  testMatch: [
    // Default
    '**/test/**/*.js',
    '**/__tests__/**/*.spec.js',
    '**/__tests__/**/*.spec.ts'
  ],
  globals: {
    'ts-jest': {
      'useBabelrc': true
    }
  }
}
<commit_msg>build(jest): add SASS files to transform<commit_after>module.exports = {
  verbose: false,
  roots: [
    '<rootDir>/src',
    '<rootDir>/test/unit'
  ],
  moduleFileExtensions: [
    'ts',
    'js'
  ],
  moduleDirectories: [
    'node_modules'
  ],
  moduleNameMapper: {
    '^@/test$': '<rootDir>/test/index.js',
    '^@/test/(.*)$': '<rootDir>/test/$1',
    '^@/(.*)$': '<rootDir>/src/$1',
    '\\.(css|sass|scss)$': 'identity-obj-proxy'
  },
  transform: {
    '\\.(styl)$': 'jest-css-modules',
    '\\.(sass|scss)$': 'jest-css-modules',
    '.*\\.(j|t)s$': 'ts-jest'
  },
  mapCoverage: true,
  collectCoverageFrom: [
    'src/**/*.{js,ts,tsx}',
    '!**/*.d.ts'
  ],
  transformIgnorePatterns: [
    'node_modules/(?!vue-router)'
  ],
  snapshotSerializers: [
    'jest-serializer-html'
  ],
  testMatch: [
    // Default
    '**/test/**/*.js',
    '**/__tests__/**/*.spec.js',
    '**/__tests__/**/*.spec.ts'
  ],
  globals: {
    'ts-jest': {
      'useBabelrc': true
    }
  }
}
<|endoftext|>


<commit_before>/**
 * hermes-bus <https://github.com/jahnestacado/hermes-bus>
 * Copyright (c) 2014 Ioannis Tzanellis
 * Licensed under the MIT License (MIT).
 */
var Q = require("q");

var observerBusLines = {
    main: []
};

var mainBusLineRegisteredFunctions = [];

function createObserver(event, cb) {
    return {
        event: event,
        cb: cb,
        location: "Unknown",
        active: true
    }
}

function on(busline, event, cb) {
    if (typeof (busline) !== typeof (event)) {
        cb = event;
        event = busline;
        busline = 'main';
    }
    var observer = createObserver(event, cb);
    if (observerBusLines[busline]) {
        observerBusLines[busline].push(observer);
        buildNamespace(busline, event);
    } else {
        observerBusLines[busline] = [observer];
        buildNamespace(busline, event);
    }

    return {
        registerLocation: function(path) {
            observer.location = path;
        }
    }
}

function getEventHandler(busline, event) {
    return function() {
        //on-event-callback-arguments to array
        var args = Array.prototype.slice.call(arguments);
        args.push(function() {
            console.log("WARN - 'resolve' callback is undefined on emitted event '" + event + "'. Try bus.resolve" + firstLetterToUpperCase(event) + "(...)");
        });

        observerBusLines[busline].forEach(function(element) {
            if (element.event === event && element.active === true) {
                element.cb.apply(element, args);
            }
        });
    }
}

function getPromiseEventHandler(busline, event) {
    return function() {
        //on-event callback arguments to array
        var args = Array.prototype.slice.call(arguments);
        var promises = [];

        observerBusLines[busline].forEach(function(observer) {
            if (observer.event === event && observer.active === true) {
                promises.push(createPromiseEvent(observer, args));
            }
        });
        return Q.all(promises);
    }
}

function createPromiseEvent(element, args) {
    var deferred = Q.defer();

    var appliedArgs = args.slice(0);
    appliedArgs.push(deferred.resolve)
    element.cb.apply(element, appliedArgs);

    return deferred.promise;
}

function buildNamespace(busline, event) {
    var exportedNamespace = exports;
    var triggerFunctionName = "trigger" + firstLetterToUpperCase(event);
    var resolveFunctionName = "resolve" + firstLetterToUpperCase(event);
    if (busline !== 'main') {
        if (!exportedNamespace[busline]) {
            exportedNamespace[busline] = buildBuslineUtils(busline);
        }
        exportedNamespace = exportedNamespace[busline];
    } else {
        mainBusLineRegisteredFunctions.push(triggerFunctionName, resolveFunctionName);
    }

    exportedNamespace[resolveFunctionName] = getPromiseEventHandler(busline, event);
    exportedNamespace[triggerFunctionName] = getEventHandler(busline, event);

}

function buildBuslineUtils(busline) {
    var utils = {
        activateEvent: buildStatusSwitch(busline, true),
        deactivateEvent: buildStatusSwitch(busline, false),
        destroy: buildDestroyBusline(busline)
    };

    return utils;
}

function buildStatusSwitch(busline, enabled) {
    return function(event) {
        observerBusLines[busline].forEach(function(observer) {
            if (observer.event === event) {
                observer.active = enabled;
            }
        });
    }
}

function buildDestroyBusline(busline) {
    return function() {
        destroyBusLine(busline);
    }
}

function reset() {
    observerBusLines['main'] = [];
    mainBusLineRegisteredFunctions.forEach(function(funcName) {
        exports[funcName] = undefined;
    });
    mainBusLineRegisteredFunctions = [];
}

function hardReset() {
    var buslines = Object.getOwnPropertyNames(observerBusLines);
    buslines.forEach(function(busline) {
        destroyBusLine(busline);
    });
    reset();
}

function destroyBusLine(busline) {
    observerBusLines[busline] = undefined;
    exports[busline] = undefined;
}

function firstLetterToUpperCase(event) {
    return event.charAt(0).toUpperCase() + event.slice(1);
}

function busRequire() {
    var modulePaths = Array.prototype.slice.call(arguments);
    console.log(modulePaths);
    modulePaths.forEach(function(modulePath) {
        if (modulePath.substring(0, 2) === './') {
            require('./../../.' + modulePath);
        } else {
            require(modulePath);
        }
    });
}

exports.on = on;
exports.require = busRequire;
exports.reset = reset;
exports.hardReset = hardReset;
exports.activateEvent = buildStatusSwitch('main', true);
exports.deactivateEvent = buildStatusSwitch("main", false);<commit_msg>lib/hermes-bus.js: Improved warning message<commit_after>/**
 * hermes-bus <https://github.com/jahnestacado/hermes-bus>
 * Copyright (c) 2014 Ioannis Tzanellis
 * Licensed under the MIT License (MIT).
 */
var Q = require("q");

var observerBusLines = {
    main: []
};

var mainBusLineRegisteredFunctions = [];

function createObserver(event, cb) {
    return {
        event: event,
        cb: cb,
        location: "Unknown",
        active: true
    }
}

function on(busline, event, cb) {
    if (typeof (busline) !== typeof (event)) {
        cb = event;
        event = busline;
        busline = 'main';
    }
    var observer = createObserver(event, cb);
    if (observerBusLines[busline]) {
        observerBusLines[busline].push(observer);
        buildNamespace(busline, event);
    } else {
        observerBusLines[busline] = [observer];
        buildNamespace(busline, event);
    }

    return {
        registerLocation: function(path) {
            observer.location = path;
        }
    }
}

function getEventHandler(busline, event) {
    return function() {
        //on-event-callback-arguments to array
        var args = Array.prototype.slice.call(arguments);
        args.push(function() {
            console.log("WARN - 'resolve' callback is undefined on triggered event '" + event + "'. Try bus.resolve" + firstLetterToUpperCase(event) + "(...)");
        });

        observerBusLines[busline].forEach(function(element) {
            if (element.event === event && element.active === true) {
                element.cb.apply(element, args);
            }
        });
    }
}

function getPromiseEventHandler(busline, event) {
    return function() {
        //on-event callback arguments to array
        var args = Array.prototype.slice.call(arguments);
        var promises = [];

        observerBusLines[busline].forEach(function(observer) {
            if (observer.event === event && observer.active === true) {
                promises.push(createPromiseEvent(observer, args));
            }
        });
        return Q.all(promises);
    }
}

function createPromiseEvent(element, args) {
    var deferred = Q.defer();

    var appliedArgs = args.slice(0);
    appliedArgs.push(deferred.resolve)
    element.cb.apply(element, appliedArgs);

    return deferred.promise;
}

function buildNamespace(busline, event) {
    var exportedNamespace = exports;
    var triggerFunctionName = "trigger" + firstLetterToUpperCase(event);
    var resolveFunctionName = "resolve" + firstLetterToUpperCase(event);
    if (busline !== 'main') {
        if (!exportedNamespace[busline]) {
            exportedNamespace[busline] = buildBuslineUtils(busline);
        }
        exportedNamespace = exportedNamespace[busline];
    } else {
        mainBusLineRegisteredFunctions.push(triggerFunctionName, resolveFunctionName);
    }

    exportedNamespace[resolveFunctionName] = getPromiseEventHandler(busline, event);
    exportedNamespace[triggerFunctionName] = getEventHandler(busline, event);

}

function buildBuslineUtils(busline) {
    var utils = {
        activateEvent: buildStatusSwitch(busline, true),
        deactivateEvent: buildStatusSwitch(busline, false),
        destroy: buildDestroyBusline(busline)
    };

    return utils;
}

function buildStatusSwitch(busline, enabled) {
    return function(event) {
        observerBusLines[busline].forEach(function(observer) {
            if (observer.event === event) {
                observer.active = enabled;
            }
        });
    }
}

function buildDestroyBusline(busline) {
    return function() {
        destroyBusLine(busline);
    }
}

function reset() {
    observerBusLines['main'] = [];
    mainBusLineRegisteredFunctions.forEach(function(funcName) {
        exports[funcName] = undefined;
    });
    mainBusLineRegisteredFunctions = [];
}

function hardReset() {
    var buslines = Object.getOwnPropertyNames(observerBusLines);
    buslines.forEach(function(busline) {
        destroyBusLine(busline);
    });
    reset();
}

function destroyBusLine(busline) {
    observerBusLines[busline] = undefined;
    exports[busline] = undefined;
}

function firstLetterToUpperCase(event) {
    return event.charAt(0).toUpperCase() + event.slice(1);
}

function busRequire() {
    var modulePaths = Array.prototype.slice.call(arguments);
    console.log(modulePaths);
    modulePaths.forEach(function(modulePath) {
        if (modulePath.substring(0, 2) === './') {
            require('./../../.' + modulePath);
        } else {
            require(modulePath);
        }
    });
}

exports.on = on;
exports.require = busRequire;
exports.reset = reset;
exports.hardReset = hardReset;
exports.activateEvent = buildStatusSwitch('main', true);
exports.deactivateEvent = buildStatusSwitch("main", false);<|endoftext|>


<commit_before>//>>excludeStart("jqmBuildExclude", pragmas.jqmBuildExclude);
//>>description: Widget factory extentions for mobile.
//>>label: Widget Factory
//>>group: Core
//>>css.theme: ../css/themes/default/jquery.mobile.theme.css

define( [ "jquery", "./jquery.mobile.ns", "jquery.ui.widget" ], function( jQuery ) {
//>>excludeEnd("jqmBuildExclude");
(function( $, undefined ) {

$.extend( $.Widget.prototype, {
	_getCreateOptions: function() {

		var elem = this.element,
			options = {};

		$.each( this.options, function( option ) {

			var value = $.mobile.getAttribute( elem[ 0 ], option.replace( /[A-Z]/g, function( c ) {
							return "-" + c.toLowerCase();
						}), true );

			if ( value !== undefined ) {
				options[ option ] = value;
			}
		});

		return options;
	},

	enhanceWithin: function( target, useKeepNative ) {
		this.enhance( $( $[ this.namespace ][ this.widgetName ].initSelector, $( target ) ), useKeepNative );
	},

	enhance: function( targets, useKeepNative ) {
		var page, keepNative, $widgetElements = $( targets );

		// if ignoreContentEnabled is set to true the framework should
		// only enhance the selected elements when they do NOT have a
		// parent with the data-namespace-ignore attribute
		$widgetElements = $.mobile.enhanceable( $widgetElements );

		if ( useKeepNative && $widgetElements.length ) {
			// TODO remove dependency on the page widget for the keepNative.
			// Currently the keepNative value is defined on the page prototype so
			// the method is as well
			page = $.mobile.closestPageData( $widgetElements );
			keepNative = ( page && page.keepNativeSelector()) || "";

			$widgetElements = $widgetElements.not( keepNative );
		}

		$widgetElements[ this.widgetName ]();
	}
});
//TODO: Remove in 1.5 for backcompat only
$.mobile.widget = $.Widget;
})( jQuery );
//>>excludeStart("jqmBuildExclude", pragmas.jqmBuildExclude);
});
//>>excludeEnd("jqmBuildExclude");
<commit_msg>Base class: Ignore null option values coming in from the DOM.<commit_after>//>>excludeStart("jqmBuildExclude", pragmas.jqmBuildExclude);
//>>description: Widget factory extentions for mobile.
//>>label: Widget Factory
//>>group: Core
//>>css.theme: ../css/themes/default/jquery.mobile.theme.css

define( [ "jquery", "./jquery.mobile.ns", "jquery.ui.widget" ], function( jQuery ) {
//>>excludeEnd("jqmBuildExclude");
(function( $, undefined ) {

$.extend( $.Widget.prototype, {
	_getCreateOptions: function() {

		var elem = this.element,
			options = {};

		$.each( this.options, function( option ) {

			var value = $.mobile.getAttribute( elem[ 0 ], option.replace( /[A-Z]/g, function( c ) {
							return "-" + c.toLowerCase();
						}), true );

			if ( value != null ) {
				options[ option ] = value;
			}
		});

		return options;
	},

	enhanceWithin: function( target, useKeepNative ) {
		this.enhance( $( $[ this.namespace ][ this.widgetName ].initSelector, $( target ) ), useKeepNative );
	},

	enhance: function( targets, useKeepNative ) {
		var page, keepNative, $widgetElements = $( targets );

		// if ignoreContentEnabled is set to true the framework should
		// only enhance the selected elements when they do NOT have a
		// parent with the data-namespace-ignore attribute
		$widgetElements = $.mobile.enhanceable( $widgetElements );

		if ( useKeepNative && $widgetElements.length ) {
			// TODO remove dependency on the page widget for the keepNative.
			// Currently the keepNative value is defined on the page prototype so
			// the method is as well
			page = $.mobile.closestPageData( $widgetElements );
			keepNative = ( page && page.keepNativeSelector()) || "";

			$widgetElements = $widgetElements.not( keepNative );
		}

		$widgetElements[ this.widgetName ]();
	}
});
//TODO: Remove in 1.5 for backcompat only
$.mobile.widget = $.Widget;
})( jQuery );
//>>excludeStart("jqmBuildExclude", pragmas.jqmBuildExclude);
});
//>>excludeEnd("jqmBuildExclude");
<|endoftext|>


<commit_before>module.exports = {
  roots: [
    '<rootDir>/src',
  ],
};
<commit_msg>chore(jest): transform `text-mask-core` by jest<commit_after>module.exports = {
  roots: [
    '<rootDir>/src',
  ],
  transformIgnorePatterns: [
    'node_modules/(?!(text-mask-core)/)',
  ],
};
<|endoftext|>


<commit_before>var profiles = require('../collections/profiles'),
    uuid     = require('../helpers/uuid'),
		wrap	   = require('../helpers/wrapper'),
		time     = require('microtime');

function profile(fn) {

  var modul = arguments[arguments.length - 1]

  return function __profiler__() {

    var u    = uuid(fn, modul),
        prof = {
          id: u.id,
          invokation: u.invokations,
          initialized: time.now(),
          observers: [ ],
          anonymous: u.anonymous },
        last = profiles.mostRecent();

    /*
      If the last profile added was for an anonymous function, that means
      it's the function that wrapped us, so:

      1. Specify it as our owner
      2. Add us as an observer
     */
    if (last && last.anonymous) {
      prof.owner = last.id;
      last.observers.push(u.uid);
    }

    // Add this profile so it can be picked up on the next iteration
    profiles.add(prof);

    // Again, I know assigning properties to prof in this method is a very bad thing,
    // it's just to damned easy to avoid. Sorry.
    function decorate(af) {
      var a = [ ];

      for (var k = 0; k < af.length; k++)
        if (af[k] instanceof Function) {

          // Wrap any function arguments in profile a decorator
          a.push(wrap(profile, 'OWNER:' + u.uid, af[k], modul));

          // Record this function as an observer of the current function.
          // false here instructs uuid to not count this as an invokation
          // of our function.
          prof.observers.push(uuid(af[k], false, modul).id + '.0');

          if (k === af.length - 1)
            prof.callback = 1;

        } else if (af[k] instanceof String && af[k].indexOf('OWNER:') === 0) {

          // This function has an owner, so mark it appropriatly
          prof.owner = af[k].substring(6);
        } else {

          // For standard arguments, just push them into the array
          a.push(af[k]);
        }

      return a;
    }

    // Keep the raw arguments for reporting/forensics
    prof.rawArgs = arguments;
    prof.args 	 = decorate(arguments);
    prof.start   = time.now();
    prof.result  = fn.apply(this, prof.args);

    // This is the end for the current function. Callbacks will be ended seperately.
    prof.end = time.now();

    // If we don't have any observers we can return our results (if we have any)
    if (prof.observers.length === 0)
      return prof.result;
  };
}

module.exports = profile;<commit_msg>A profiler is now a dynamically generated named function<commit_after>var profiles = require('../collections/profiles'),
    uuid     = require('../helpers/uuid'),
		wrap	   = require('../helpers/wrapper'),
		time     = require('microtime'),
		vm       = require('vm'),

		// The template for the functions that will get generated
		body = "var u = uuid(fn, modul),"+
        "prof = {" +
          "id: u.id," +
          "invokation: u.invokations," +
          "initialized: time.now()," +
          "observers: [ ]," +
          "anonymous: u.anonymous }," +
        "last = profiles.mostRecent();" +
    "if (last && last.anonymous) {" +
      "prof.owner = last.id;" +
      "last.observers.push(u.uid);" +
    "}" +
    "profiles.add(prof);" +
    "function decorate(af) {" +
      "var a = [ ];" +
      "for (var k = 0; k < af.length; k++)" +
        "if (typeof af[k] === 'function') {" +
          "a.push(wrap(profile, 'OWNER:' + u.uid, af[k], modul));" +
          "prof.observers.push(uuid(af[k], false, modul).id + '.0');" +
          "if (k === af.length - 1)" +
            "prof.callback = 1;" +
        "} else if (af[k] instanceof String && af[k].indexOf('OWNER:') === 0) {" +
          "prof.owner = af[k].substring(6);" +
        "} else {" +
          "a.push(af[k]);" +
        "}" +
      "return a;" +
    "}" +
    "prof.rawArgs = arguments;" +
    "prof.args 	  = decorate(arguments);" +
    "prof.start   = time.now();" +
    "prof.result  = fn.apply(this, prof.args);" +
    "prof.end     = time.now();" +
    "return prof.result;";

function profile(fn) {

  var modul   = arguments[arguments.length - 1],
      context = {
        profiles : profiles,
        profile  : profile,
        console  : console,
        modul    : modul,
        wrap     : wrap,
        uuid     : uuid,
        time     : time,
        fn       : fn },
      profiler = 'funk = function ' + fn.name + ' () {' + body + '}'

  return vm.runInNewContext(profiler, context, 'ardus.vm');
}

module.exports = profile;<|endoftext|>


<commit_before>/* eslint-disable react/forbid-prop-types */
import React from 'react';
import PropTypes from 'prop-types';
import { StyleSheet } from 'react-native';

import TouchableCell from './TouchableCell';

/**
 * Renders a cell with an icon, supports touchable interaction and disabling
 *
 * @param {string|number} rowKey  Unique key associated to row cell is in
 * @param {string|number} columnKey Unique key associated to column cell is in
 * @param {bool} isDisabled `true` will render disabled icons passed in
 * @param {bool} isChecked  `true` will render CheckedComponent rather than UncheckedComponent
 * @param {React.element} CheckedComponent  Component to render when cell is checked
 * @param {React.element} UncheckedComponent  Component to render when cell is checked
 * @param {React.element} DisabledCheckedComponent  Component to render when cell is
 *                                                  checked and disabled
 * @param {React.element} DisabledUncheckedComponent  Component to render when cell is
 *                                                    checked and disabled
 * @param {func} onCheckAction Action creator for handling checking of this cell.
 *                          `(rowKey, columnKey) => {...}`
 * @param {func} onUncheckAction Action creator for handling unchecking of this cell.
 *                          `(rowKey, columnKey) => {...}`
 * @param {func} dispatch Reducer dispatch callback for handling actions
 * @param {Object} containerStyle Style object for the containing Touchable component
 */

const CheckableCell = React.memo(
  ({
    rowKey,
    columnKey,
    isChecked,
    isDisabled,
    CheckedComponent,
    UncheckedComponent,
    DisabledCheckedComponent,
    DisabledUncheckedComponent,
    onCheckAction,
    onUncheckAction,
    dispatch,
    containerStyle,
  }) => {
    console.log(`- CheckableCell: ${rowKey},${columnKey}`);

    const onPressAction = isChecked ? onUncheckAction : onCheckAction;

    const renderCheck = () => {
      if (isDisabled) {
        return isChecked ? DisabledCheckedComponent : DisabledUncheckedComponent;
      }
      return isChecked ? CheckedComponent : UncheckedComponent;
    };

    return (
      <TouchableCell
        renderChildren={renderCheck}
        rowKey={rowKey}
        columnKey={columnKey}
        onPressAction={onPressAction}
        dispatch={dispatch}
        containerStyle={containerStyle}
      />
    );
  }
);

const defaultStyles = StyleSheet.create({
  containerStyle: {
    flex: 1,
    justifyContent: 'center',
  },
});

CheckableCell.propTypes = {
  rowKey: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
  columnKey: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
  isChecked: PropTypes.bool,
  isDisabled: PropTypes.bool,
  CheckedComponent: PropTypes.element.isRequired,
  UncheckedComponent: PropTypes.element.isRequired,
  DisabledCheckedComponent: PropTypes.element,
  DisabledUncheckedComponent: PropTypes.element,
  onCheckAction: PropTypes.func.isRequired,
  onUncheckAction: PropTypes.func.isRequired,
  dispatch: PropTypes.func.isRequired,
  containerStyle: PropTypes.object,
};

CheckableCell.defaultProps = {
  isChecked: false,
  DisabledCheckedComponent: null,
  DisabledUncheckedComponent: null,
  isDisabled: false,
  containerStyle: defaultStyles.containerStyle,
};

export default CheckableCell;
<commit_msg>Add update to CheckableCell component, add styling and width prop<commit_after>/* eslint-disable react/forbid-prop-types */
import React from 'react';
import PropTypes from 'prop-types';
import { StyleSheet } from 'react-native';

import TouchableCell from './TouchableCell';

/**
 * Renders a cell with an icon, supports touchable interaction and disabling
 *
 * @param {string|number} rowKey  Unique key associated to row cell is in
 * @param {string|number} columnKey Unique key associated to column cell is in
 * @param {bool} isDisabled `true` will render disabled icons passed in
 * @param {bool} isChecked  `true` will render CheckedComponent rather than UncheckedComponent
 * @param {React.element} CheckedComponent  Component to render when cell is checked
 * @param {React.element} UncheckedComponent  Component to render when cell is checked
 * @param {React.element} DisabledCheckedComponent  Component to render when cell is
 *                                                  checked and disabled
 * @param {React.element} DisabledUncheckedComponent  Component to render when cell is
 *                                                    checked and disabled
 * @param {func} onCheckAction Action creator for handling checking of this cell.
 *                          `(rowKey, columnKey) => {...}`
 * @param {func} onUncheckAction Action creator for handling unchecking of this cell.
 *                          `(rowKey, columnKey) => {...}`
 * @param {func} dispatch Reducer dispatch callback for handling actions
 * @param {Object} containerStyle Style object for the containing Touchable component
 */

const CheckableCell = React.memo(
  ({
    rowKey,
    columnKey,
    isChecked,
    isDisabled,
    CheckedComponent,
    UncheckedComponent,
    DisabledCheckedComponent,
    DisabledUncheckedComponent,
    onCheckAction,
    onUncheckAction,
    dispatch,
    containerStyle,
    width,
  }) => {
    console.log(`- CheckableCell: ${rowKey},${columnKey}`);

    const onPressAction = isChecked ? onUncheckAction : onCheckAction;

    const renderCheck = () => {
      if (isDisabled) {
        return isChecked ? DisabledCheckedComponent : DisabledUncheckedComponent;
      }
      return isChecked ? CheckedComponent : UncheckedComponent;
    };

    return (
      <TouchableCell
        renderChildren={renderCheck}
        rowKey={rowKey}
        columnKey={columnKey}
        onPressAction={onPressAction}
        dispatch={dispatch}
        containerStyle={containerStyle}
        width={width}
      />
    );
  }
);

const defaultStyles = StyleSheet.create({
  containerStyle: {},
});

CheckableCell.propTypes = {
  rowKey: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
  columnKey: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
  isChecked: PropTypes.bool,
  isDisabled: PropTypes.bool,
  CheckedComponent: PropTypes.element.isRequired,
  UncheckedComponent: PropTypes.element.isRequired,
  DisabledCheckedComponent: PropTypes.element,
  DisabledUncheckedComponent: PropTypes.element,
  onCheckAction: PropTypes.func.isRequired,
  onUncheckAction: PropTypes.func.isRequired,
  dispatch: PropTypes.func.isRequired,
  containerStyle: PropTypes.object,
  width: PropTypes.number,
};

CheckableCell.defaultProps = {
  isChecked: false,
  DisabledCheckedComponent: null,
  DisabledUncheckedComponent: null,
  isDisabled: false,
  containerStyle: defaultStyles.containerStyle,
  width: 1,
};

export default CheckableCell;
<|endoftext|>


<commit_before>'use strict'

const inherits = require('util').inherits
const EE = require('events').EventEmitter
const net = require('net')
const tls = require('tls')
const retimer = require('retimer')
const HTTPParser = require('http-parser-js').HTTPParser
const RequestIterator = require('./requestIterator')

function Client (opts) {
  if (!(this instanceof Client)) {
    return new Client(opts)
  }

  opts.setupClient = opts.setupClient || noop
  opts.pipelining = opts.pipelining || 1
  opts.port = opts.port || 80

  this.opts = opts
  this.timeout = (opts.timeout || 10) * 1000
  this.secure = opts.protocol === 'https:'
  if (this.secure && this.opts.port == 80) this.opts.port = 443
  this.parser = new HTTPParser(HTTPParser.RESPONSE)
  this.requestIterator = new RequestIterator(opts.requests, opts)

  this.resData = new Array(opts.pipelining)
  for (var i = 0; i < this.resData.length; i++) {
    this.resData[i] = {
      bytes: 0,
      headers: {},
      startTime: [0, 0]
    }
  }

  // cer = current expected response
  this.cer = 0
  this.destroyed = false

  opts.setupClient(this)

  const handleTimeout = () => {
    // all pipelined requests have timed out here
    this.resData.forEach(() => this.emit('timeout'))
    this.cer = 0
    this._destroyConnection()
    this._connect()

    // timeout has already occured, need to set a new timeoutTicker
    this.timeoutTicker = retimer(handleTimeout, this.timeout)
  }

  this.timeoutTicker = retimer(handleTimeout, this.timeout)

  this.parser[HTTPParser.kOnHeadersComplete] = (opts) => {
    this.resData[this.cer].headers = opts
  }

  this.parser[HTTPParser.kOnBody] = () => {}

  this.parser[HTTPParser.kOnMessageComplete] = () => {
    let end = process.hrtime(this.resData[this.cer].startTime)
    let responseTime = end[0] * 1e3 + end[1] / 1e6
    this.emit('response', this.resData[this.cer].headers.statusCode, this.resData[this.cer].bytes, responseTime)
    this.resData[this.cer].bytes = 0

    this.cer = this.cer === opts.pipelining - 1 ? 0 : this.cer++
    this._doRequest(this.cer)

    this.timeoutTicker.reschedule(this.timeout)
  }

  this._connect()
}

inherits(Client, EE)

Client.prototype._connect = function () {
  if (this.secure) {
    this.conn = tls.connect(this.opts.port, this.opts.hostname, { rejectUnauthorized: false })
  } else {
    this.conn = net.connect(this.opts.port, this.opts.hostname)
  }

  this.conn.on('error', (error) => {
    this.emit('connError', error)
    if (!this.destroyed) this._connect()
  })

  this.conn.on('data', (chunk) => {
    this.resData[this.cer].bytes += chunk.length
    this.parser.execute(chunk)
  })

  this.conn.on('end', () => {
    if (!this.destroyed) this._connect()
  })

  for (let i = 0; i < this.opts.pipelining; i++) {
    this._doRequest(i)
  }
}

// rpi = request pipelining index
Client.prototype._doRequest = function (rpi) {
  this.resData[rpi].startTime = process.hrtime()
  this.conn.write(this.requestIterator.move())
}

Client.prototype._destroyConnection = function () {
  // if (!this.conn) return
  this.conn.removeAllListeners('error')
  this.conn.removeAllListeners('end')
  this.conn.on('error', () => {})
  this.conn.destroy()
}

Client.prototype.destroy = function () {
  this.destroyed = true
  this.timeoutTicker.clear()
  this._destroyConnection()
}

Client.prototype.getRequestBuffer = function (newHeaders) {
  return this.requestIterator.currentRequest.requestBuffer
}

Client.prototype.setHeaders = function (newHeaders) {
  this._okayToUpdateCheck()
  this.requestIterator.setHeaders(newHeaders)
}

Client.prototype.setBody = function (newBody) {
  this._okayToUpdateCheck()
  this.requestIterator.setBody(newBody)
}

Client.prototype.setHeadersAndBody = function (newHeaders, newBody) {
  this._okayToUpdateCheck()
  this.requestIterator.setHeadersAndBody(newHeaders, newBody)
}

Client.prototype.setRequest = function (newRequest) {
  this._okayToUpdateCheck()
  this.requestIterator.setRequest(newRequest)
}

Client.prototype.setRequests = function (newRequests) {
  this._okayToUpdateCheck()
  this.requestIterator.setRequests(newRequests)
}

Client.prototype._okayToUpdateCheck = function () {
  if (this.opts.pipelining > 1) {
    throw new Error('cannot update requests when the piplining factor is greater than 1')
  }
}

function noop () {}

module.exports = Client
<commit_msg>Fix style error<commit_after>'use strict'

const inherits = require('util').inherits
const EE = require('events').EventEmitter
const net = require('net')
const tls = require('tls')
const retimer = require('retimer')
const HTTPParser = require('http-parser-js').HTTPParser
const RequestIterator = require('./requestIterator')

function Client (opts) {
  if (!(this instanceof Client)) {
    return new Client(opts)
  }

  opts.setupClient = opts.setupClient || noop
  opts.pipelining = opts.pipelining || 1
  opts.port = opts.port || 80

  this.opts = opts
  this.timeout = (opts.timeout || 10) * 1000
  this.secure = opts.protocol === 'https:'
  if (this.secure && this.opts.port === 80) this.opts.port = 443
  this.parser = new HTTPParser(HTTPParser.RESPONSE)
  this.requestIterator = new RequestIterator(opts.requests, opts)

  this.resData = new Array(opts.pipelining)
  for (var i = 0; i < this.resData.length; i++) {
    this.resData[i] = {
      bytes: 0,
      headers: {},
      startTime: [0, 0]
    }
  }

  // cer = current expected response
  this.cer = 0
  this.destroyed = false

  opts.setupClient(this)

  const handleTimeout = () => {
    // all pipelined requests have timed out here
    this.resData.forEach(() => this.emit('timeout'))
    this.cer = 0
    this._destroyConnection()
    this._connect()

    // timeout has already occured, need to set a new timeoutTicker
    this.timeoutTicker = retimer(handleTimeout, this.timeout)
  }

  this.timeoutTicker = retimer(handleTimeout, this.timeout)

  this.parser[HTTPParser.kOnHeadersComplete] = (opts) => {
    this.resData[this.cer].headers = opts
  }

  this.parser[HTTPParser.kOnBody] = () => {}

  this.parser[HTTPParser.kOnMessageComplete] = () => {
    let end = process.hrtime(this.resData[this.cer].startTime)
    let responseTime = end[0] * 1e3 + end[1] / 1e6
    this.emit('response', this.resData[this.cer].headers.statusCode, this.resData[this.cer].bytes, responseTime)
    this.resData[this.cer].bytes = 0

    this.cer = this.cer === opts.pipelining - 1 ? 0 : this.cer++
    this._doRequest(this.cer)

    this.timeoutTicker.reschedule(this.timeout)
  }

  this._connect()
}

inherits(Client, EE)

Client.prototype._connect = function () {
  if (this.secure) {
    this.conn = tls.connect(this.opts.port, this.opts.hostname, { rejectUnauthorized: false })
  } else {
    this.conn = net.connect(this.opts.port, this.opts.hostname)
  }

  this.conn.on('error', (error) => {
    this.emit('connError', error)
    if (!this.destroyed) this._connect()
  })

  this.conn.on('data', (chunk) => {
    this.resData[this.cer].bytes += chunk.length
    this.parser.execute(chunk)
  })

  this.conn.on('end', () => {
    if (!this.destroyed) this._connect()
  })

  for (let i = 0; i < this.opts.pipelining; i++) {
    this._doRequest(i)
  }
}

// rpi = request pipelining index
Client.prototype._doRequest = function (rpi) {
  this.resData[rpi].startTime = process.hrtime()
  this.conn.write(this.requestIterator.move())
}

Client.prototype._destroyConnection = function () {
  // if (!this.conn) return
  this.conn.removeAllListeners('error')
  this.conn.removeAllListeners('end')
  this.conn.on('error', () => {})
  this.conn.destroy()
}

Client.prototype.destroy = function () {
  this.destroyed = true
  this.timeoutTicker.clear()
  this._destroyConnection()
}

Client.prototype.getRequestBuffer = function (newHeaders) {
  return this.requestIterator.currentRequest.requestBuffer
}

Client.prototype.setHeaders = function (newHeaders) {
  this._okayToUpdateCheck()
  this.requestIterator.setHeaders(newHeaders)
}

Client.prototype.setBody = function (newBody) {
  this._okayToUpdateCheck()
  this.requestIterator.setBody(newBody)
}

Client.prototype.setHeadersAndBody = function (newHeaders, newBody) {
  this._okayToUpdateCheck()
  this.requestIterator.setHeadersAndBody(newHeaders, newBody)
}

Client.prototype.setRequest = function (newRequest) {
  this._okayToUpdateCheck()
  this.requestIterator.setRequest(newRequest)
}

Client.prototype.setRequests = function (newRequests) {
  this._okayToUpdateCheck()
  this.requestIterator.setRequests(newRequests)
}

Client.prototype._okayToUpdateCheck = function () {
  if (this.opts.pipelining > 1) {
    throw new Error('cannot update requests when the piplining factor is greater than 1')
  }
}

function noop () {}

module.exports = Client
<|endoftext|>