<commit_before>import React from 'react';
import isEqual from 'lodash/isEqual';
import PropTypes from 'prop-types';

// Components
import Spinner from 'components/ui/Spinner';

// Redux
import { connect } from 'react-redux';

// Leaflet can't be imported on the server because it's not isomorphic
const L = (typeof window !== 'undefined') ? require('leaflet') : null;

const MAP_CONFIG = {
  zoom: 2,
  minZoom: 2,
  latLng: {
    lat: 30,
    lng: -120
  },
  zoomControl: true
};

class Map extends React.Component {

  constructor(props) {
    super(props);
    this.state = {
      loading: false,
      sidebar: {
        open: props.sidebar.open,
        width: props.sidebar.width
      }
    };
  }

  componentDidMount() {
    this.hasBeenMounted = true;

    const mapOptions = Object.assign({}, MAP_CONFIG, this.props.mapConfig || {});

    // If leaflet haven't been imported, we can just skip the next steps
    if (!L) return;

    requestAnimationFrame(() => {
      this.map = L.map(this.mapNode, mapOptions);

      if (this.props.mapConfig && this.props.mapConfig.bounds) {
        this.fitBounds(this.props.mapConfig.bounds.geometry);
      }

      // Disable interaction if necessary
      if (!this.props.interactionEnabled) {
        this.map.dragging.disable();
        this.map.touchZoom.disable();
        this.map.doubleClickZoom.disable();
        this.map.scrollWheelZoom.disable();
        this.map.boxZoom.disable();
        this.map.keyboard.disable();
      }

      // SETTERS
      this.setAttribution();
      this.setZoomControl();
      this.setBasemap();
      this.setMapEventListeners();

      // Add layers
      this.setLayerManager();
      this.addLayers(this.props.layersActive, this.props.filters);
    });
  }

  componentWillReceiveProps(nextProps) {
    const filtersChanged = !isEqual(nextProps.filters, this.props.filters);
    const layersActiveChanged = !isEqual(nextProps.layersActive, this.props.layersActive);

    if (filtersChanged || layersActiveChanged) {
      const newLayers = nextProps.layersActive.map(l => l.id);
      const oldLayers = this.props.layersActive.map(l => l.id);

      const setNew = new Set(newLayers);
      const setOld = new Set(oldLayers);
      const union = new Set([...newLayers, ...oldLayers]);
      const difference = newLayers.filter(n => !setOld.has(n));
      let layer;
      // Test whether old & new layers are the same & only have to change the order
      if (newLayers.length === oldLayers.length && !difference.length) {
        this.layerManager.setZIndex(nextProps.layersActive);
      } else {
        union.forEach((parsedLayer) => {
          if (!setOld.has(parsedLayer)) {
            layer = nextProps.layersActive.filter(l => l.id === parsedLayer)[0];
            this.addLayers(layer);
          } else if (!setNew.has(parsedLayer)) {
            layer = this.props.layersActive.filter(l => l.id === parsedLayer)[0];
            this.removeLayers(layer);
          }
        });
      }
    }

    if (this.props.sidebar.width !== nextProps.sidebar.width) {
      this.setState({
        sidebar: nextProps.sidebar
      });
    }
  }

  shouldComponentUpdate(nextProps, nextState) {
    const loadingChanged = this.state.loading !== nextState.loading;
    const sidebarWidthChanged = this.props.sidebar.width !== nextProps.sidebar.width;
    return loadingChanged || sidebarWidthChanged;
  }

  componentWillUnmount() {
    this.hasBeenMounted = false;

    // Remember to remove the listeners before removing the map
    // or they will stay in memory
    if (this.props.setMapParams) this.removeMapEventListeners();
    if (this.map) this.map.remove();
  }

  // SETTERS
  setLayerManager() {
    const stopLoading = () => {
      // Don't execute callback if component has been unmounted
      if (!this.hasBeenMounted) return;
      this.setState({ loading: false });
    };

    this.layerManager = new this.props.LayerManager(this.map, {
      onLayerAddedSuccess: stopLoading,
      onLayerAddedError: stopLoading
    });
  }

  setAttribution() {
    this.map.attributionControl.addAttribution('© OpenStreetMap');
  }

  setZoomControl() {
    if (this.map.zoomControl) {
      this.map.zoomControl.setPosition('topright');
    }
  }

  setBasemap() {
    this.tileLayer = L.tileLayer(process.env.BASEMAP_TILE_URL, {})
                      .addTo(this.map)
                      .setZIndex(0);
  }

  // GETTERS
  getMapParams() {
    const params = {
      zoom: this.getZoom(),
      latLng: this.getCenter()
    };
    return params;
  }

  // MAP FUNCTIONS
  getCenter() { return this.map.getCenter(); }

  getZoom() { return this.map.getZoom(); }

  // MAP LISTENERS
  setMapEventListeners() {
    function mapChangeHandler() {
      // Dispatch the action to set the params
      this.props.setMapParams(this.getMapParams());
    }

    if (this.props.setMapParams) {
      this.map.on('zoomend', mapChangeHandler.bind(this));
      this.map.on('dragend', mapChangeHandler.bind(this));
    }
  }

  setSpinnerPosition() {
    const windowWidth = window.innerWidth;
    const sidebarWidth = this.state.sidebar.width;

    return ((windowWidth - sidebarWidth) / 2);
  }

  fitBounds(geoJson, sidebarWidth) {
    const geojsonLayer = L.geoJson(geoJson);
    this.map.fitBounds(geojsonLayer.getBounds(), {
      paddingTopLeft: [sidebarWidth || 0, 0],
      paddingBottomRight: [0, 0]
    });
  }

  removeMapEventListeners() {
    this.map.off('zoomend');
    this.map.off('dragend');
  }

  // LAYER METHODS
  addLayers(layers, filters) {
    if (!layers) return;
    const arrayLayers = layers instanceof Array ? layers : [layers];

    arrayLayers.forEach((layer) => {
      this.setState({
        loading: true
      });
      this.layerManager.addLayer(layer, filters || this.props.filters);
    });
  }

  removeLayers(layer) {
    if (layer) this.layerManager.removeLayer(layer.id);
    else this.layerManager.removeLayers();
  }

  // RENDER
  render() {
    const spinnerStyles = (typeof window === 'undefined') ? {} : { marginLeft: this.setSpinnerPosition() };
    const mapClass = !this.state.sidebar.open ? '-fullWidth' : '';

    return (
      <div className={`c-map ${mapClass}`}>
        {this.state.loading && <Spinner isLoading style={spinnerStyles} />}

 { this.mapNode = node; }} className="map-leaflet" />

    );
  }
}

Map.defaultProps = {
  interactionEnabled: true
};

Map.propTypes = {
  interactionEnabled: PropTypes.bool.isRequired,
  // STORE
  mapConfig: PropTypes.object,
  filters: PropTypes.object,
  sidebar: PropTypes.object,
  LayerManager: PropTypes.func,
  layersActive: PropTypes.array,
  // ACTIONS
  setMapParams: PropTypes.func
};

const mapStateToProps = state => ({
  sidebar: state.explore.sidebar
});

export default connect(mapStateToProps, null)(Map);
<commit_msg>fix mapConfig center<commit_after>import React from 'react';
import isEqual from 'lodash/isEqual';
import PropTypes from 'prop-types';

// Components
import Spinner from 'components/ui/Spinner';

// Redux
import { connect } from 'react-redux';

// Leaflet can't be imported on the server because it's not isomorphic
const L = (typeof window !== 'undefined') ? require('leaflet') : null;

const MAP_CONFIG = {
  zoom: 2,
  minZoom: 2,
  latLng: {
    lat: 30,
    lng: -120
  },
  zoomControl: true
};

class Map extends React.Component {

  constructor(props) {
    super(props);
    this.state = {
      loading: false,
      sidebar: {
        open: props.sidebar.open,
        width: props.sidebar.width
      }
    };
  }

  componentDidMount() {
    this.hasBeenMounted = true;

    const mapOptions = Object.assign({}, MAP_CONFIG, this.props.mapConfig || {});
    mapOptions.center = [mapOptions.latLng.lat, mapOptions.latLng.lng];

    // If leaflet haven't been imported, we can just skip the next steps
    if (!L) return;

    requestAnimationFrame(() => {
      this.map = L.map(this.mapNode, mapOptions);

      if (this.props.mapConfig && this.props.mapConfig.bounds) {
        this.fitBounds(this.props.mapConfig.bounds.geometry);
      }

      // Disable interaction if necessary
      if (!this.props.interactionEnabled) {
        this.map.dragging.disable();
        this.map.touchZoom.disable();
        this.map.doubleClickZoom.disable();
        this.map.scrollWheelZoom.disable();
        this.map.boxZoom.disable();
        this.map.keyboard.disable();
      }

      // SETTERS
      this.setAttribution();
      this.setZoomControl();
      this.setBasemap();
      this.setMapEventListeners();

      // Add layers
      this.setLayerManager();
      this.addLayers(this.props.layersActive, this.props.filters);
    });
  }

  componentWillReceiveProps(nextProps) {
    const filtersChanged = !isEqual(nextProps.filters, this.props.filters);
    const layersActiveChanged = !isEqual(nextProps.layersActive, this.props.layersActive);

    if (filtersChanged || layersActiveChanged) {
      const newLayers = nextProps.layersActive.map(l => l.id);
      const oldLayers = this.props.layersActive.map(l => l.id);

      const setNew = new Set(newLayers);
      const setOld = new Set(oldLayers);
      const union = new Set([...newLayers, ...oldLayers]);
      const difference = newLayers.filter(n => !setOld.has(n));
      let layer;
      // Test whether old & new layers are the same & only have to change the order
      if (newLayers.length === oldLayers.length && !difference.length) {
        this.layerManager.setZIndex(nextProps.layersActive);
      } else {
        union.forEach((parsedLayer) => {
          if (!setOld.has(parsedLayer)) {
            layer = nextProps.layersActive.filter(l => l.id === parsedLayer)[0];
            this.addLayers(layer);
          } else if (!setNew.has(parsedLayer)) {
            layer = this.props.layersActive.filter(l => l.id === parsedLayer)[0];
            this.removeLayers(layer);
          }
        });
      }
    }

    if (this.props.sidebar.width !== nextProps.sidebar.width) {
      this.setState({
        sidebar: nextProps.sidebar
      });
    }
  }

  shouldComponentUpdate(nextProps, nextState) {
    const loadingChanged = this.state.loading !== nextState.loading;
    const sidebarWidthChanged = this.props.sidebar.width !== nextProps.sidebar.width;
    return loadingChanged || sidebarWidthChanged;
  }

  componentWillUnmount() {
    this.hasBeenMounted = false;

    // Remember to remove the listeners before removing the map
    // or they will stay in memory
    if (this.props.setMapParams) this.removeMapEventListeners();
    if (this.map) this.map.remove();
  }

  // SETTERS
  setLayerManager() {
    const stopLoading = () => {
      // Don't execute callback if component has been unmounted
      if (!this.hasBeenMounted) return;
      this.setState({ loading: false });
    };

    this.layerManager = new this.props.LayerManager(this.map, {
      onLayerAddedSuccess: stopLoading,
      onLayerAddedError: stopLoading
    });
  }

  setAttribution() {
    this.map.attributionControl.addAttribution('© OpenStreetMap');
  }

  setZoomControl() {
    if (this.map.zoomControl) {
      this.map.zoomControl.setPosition('topright');
    }
  }

  setBasemap() {
    this.tileLayer = L.tileLayer(process.env.BASEMAP_TILE_URL, {})
                      .addTo(this.map)
                      .setZIndex(0);
  }

  // GETTERS
  getMapParams() {
    const params = {
      zoom: this.getZoom(),
      latLng: this.getCenter()
    };
    return params;
  }

  // MAP FUNCTIONS
  getCenter() { return this.map.getCenter(); }

  getZoom() { return this.map.getZoom(); }

  // MAP LISTENERS
  setMapEventListeners() {
    function mapChangeHandler() {
      // Dispatch the action to set the params
      this.props.setMapParams(this.getMapParams());
    }

    if (this.props.setMapParams) {
      this.map.on('zoomend', mapChangeHandler.bind(this));
      this.map.on('dragend', mapChangeHandler.bind(this));
    }
  }

  setSpinnerPosition() {
    const windowWidth = window.innerWidth;
    const sidebarWidth = this.state.sidebar.width;

    return ((windowWidth - sidebarWidth) / 2);
  }

  fitBounds(geoJson, sidebarWidth) {
    const geojsonLayer = L.geoJson(geoJson);
    this.map.fitBounds(geojsonLayer.getBounds(), {
      paddingTopLeft: [sidebarWidth || 0, 0],
      paddingBottomRight: [0, 0]
    });
  }

  removeMapEventListeners() {
    this.map.off('zoomend');
    this.map.off('dragend');
  }

  // LAYER METHODS
  addLayers(layers, filters) {
    if (!layers) return;
    const arrayLayers = layers instanceof Array ? layers : [layers];

    arrayLayers.forEach((layer) => {
      this.setState({
        loading: true
      });
      this.layerManager.addLayer(layer, filters || this.props.filters);
    });
  }

  removeLayers(layer) {
    if (layer) this.layerManager.removeLayer(layer.id);
    else this.layerManager.removeLayers();
  }

  // RENDER
  render() {
    const spinnerStyles = (typeof window === 'undefined') ? {} : { marginLeft: this.setSpinnerPosition() };
    const mapClass = !this.state.sidebar.open ? '-fullWidth' : '';

    return (
      <div className={`c-map ${mapClass}`}>
        {this.state.loading && <Spinner isLoading style={spinnerStyles} />}

 { this.mapNode = node; }} className="map-leaflet" />

    );
  }
}

Map.defaultProps = {
  interactionEnabled: true
};

Map.propTypes = {
  interactionEnabled: PropTypes.bool.isRequired,
  // STORE
  mapConfig: PropTypes.object,
  filters: PropTypes.object,
  sidebar: PropTypes.object,
  LayerManager: PropTypes.func,
  layersActive: PropTypes.array,
  // ACTIONS
  setMapParams: PropTypes.func
};

const mapStateToProps = state => ({
  sidebar: state.explore.sidebar
});

export default connect(mapStateToProps, null)(Map);
<|endoftext|>


<commit_before>/**
 * 'timeFormat' formats time into more readable formats.
 */
const months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
const timeFormat = module.exports = {
  toShortDateTime: function (d) {
    return d.getDay() + ' ' + months[d.getMonth()] + ' ' + d.getFullYear() + ', ' +
        d.getHours() + ':' + d.getMinutes();
  }
};
<commit_msg>Fix dates to show with leading zero<commit_after>/**
 * 'timeFormat' formats time into more readable formats.
 */
const months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
const to2Digits = (i) => i < 10 ? '0' + i : i;
const timeFormat = module.exports = {
  toShortDateTime: function (d) {
    return to2Digits(d.getDay()) + ' ' + months[d.getMonth()] + ' ' + d.getFullYear() + ', ' +
        to2Digits(d.getHours()) + ':' + to2Digits(d.getMinutes());
  }
};
<|endoftext|>


<commit_before>var Client = require(__dirname + '/../lib/client').Client;
var EventEmitter = require('events').EventEmitter;
var xml2js = require('xml2js');

var statusCodeTable = {
  500: 'Inetnal Server Error',
  404: 'Not Found',
  409: 'Conflict',
  400: 'Bad Request',
  200: 'OK'
};

function ScenariosRunner(options) {
  this.options = options;
}

ScenariosRunner.prototype = new EventEmitter();

ScenariosRunner.prototype.run = function(scenario) {
  this._process({ scenarios: scenario });
};

ScenariosRunner.prototype._process = function(params) {
  if (!params.start) params.start = Date.now();
  var scenario = params.scenarios.shift();
  var self = this;

  var runner = new ScenarioRunner(this.options);

  runner.on('error:fatal', function(event) {
    self.emit('error:fatal', event);
  });

  runner.on('start', function(event) {
    self.emit('scenario', { runner: runner,
                            scenario: event.scenario });

    runner.on('end', function(event) {
      if (params.scenarios.length) {
        self._process(params);
      } else {
        var elapsedTime = Date.now() - params.start;
        self.emit('end', { elapsedTime: elapsedTime });
      }
    });
  });

  runner.run(scenario);
};

function ScenarioRunner(options) {
  this.client = new Client(options);
  this.options = options;
  if (options.documentEndpoint)
    this.client.docEndpoint = options.documentEndpoint;
}

ScenarioRunner.prototype = new EventEmitter();

ScenarioRunner.prototype.run = function(scenario) {
  var self = this;
  this.client.assertNoDomain(function(error) {
    if (error)
      self.emit('error:fatal', { error: error });
    else
      self._process(scenario);
  });
};

ScenarioRunner.prototype.assertNoDomain = function(callback) {
  this.client.assertNoDomain(function(error) {
    callback();
  });
};

ScenarioRunner.prototype._process = function(scenario, callback) {
  if (!scenario.toBeProcessedRequests) {
    scenario.toBeProcessedRequests = scenario.requests.slice(0);
    scenario.start = Date.now();
    scenario.processed = {};
    this.emit('start', { scenario: scenario });
  }

  var request = scenario.toBeProcessedRequests.shift();
  var self = this;
  function processNext() {
    if (scenario.toBeProcessedRequests.length) {
      self._process(scenario, callback);
    } else {
      var elapsedTime = Date.now() - scenario.start;
      var event = {
        elapsedTime: elapsedTime,
        scenario: scenario
      };
      self.emit('end', event);
    }
  }

  var name = request.name;
  var count = 1;
  while (name in scenario.processed) {
    name = request.name + count++;
  }

  this.emit('request:start', { scenario: scenario, request: request });

  this.client.rawConfigurationRequest(request.params.Action, request.params, function(error, response) {
    if (error) response = error;

    var statusCode = response.StatusCode;
    if (statusCode == 400) {
      var parser = new xml2js.Parser({ explicitRoot: true });
      parser.parseString(response.Body, function(error, result) {
        var errorCode = result.Response.Errors.Error.Code;
        if (errorCode === 'Throttling') {
          self.emit('error:throttling');
        }
      });
    }
    if (!statusCodeTable[statusCode]) {
      self.emit('error:status_unknown', { statusCode: statusCode });
      if (callback)
        callback(statusCode, null);
      return;
    }

    var output = '';
    output += 'HTTP/1.1 ' + statusCode + ' ' + statusCodeTable[statusCode] + '\r\n';
    for (var key in response.Headers) {
      output += key + ': ' + response.Headers[key] + '\r\n';
    };
    output += '\r\n';
    output += response.Body.toString();

    request.response = output;
    self.emit('request:end', { scenario: scenario, request: request });
    processNext();
  });
};

function toSafeName(name) {
  return name
           .replace(/[^a-zA-Z0-9]+/g, '-')
           .replace(/-$/, '');
};
ScenariosRunner.toSafeName =
  ScenarioRunner.toSafeName = toSafeName;

function Response(source) {
  source = source.split('\r\n\r\n');
  this.headers = source[0];
  this.body = source.slice(1).join('\r\n\r\n');
}
Response.prototype = {
  get bodyRawJSON() {
    if (!this._bodyRawJSON)
      this._bodyRawJSON = this._XMLStringToJSON(this.body);
    return this._bodyRawJSON;
  },
  _XMLStringToJSON: function(xml) {
    var parser = new xml2js.Parser({
                   explicitRoot: true
                 });
    var json;
    parser.addListener('end', function(result) {
      json = result;
    });
    try {
      parser.parseString(xml);
    } catch (e) {
      console.log(xml);
      throw e;
    }
    return json;
  },

  get bodySortedJSON() {
    if (!this._bodySortedJSON)
      this._bodySortedJSON = this._toSortedJSON(this.bodyRawJSON);
    return this._bodySortedJSON;
  },
  _toSortedJSON: function(fragment) {
    switch (typeof fragment) {
      default:
        return fragment;
      case 'object':
        var format = {};
        Object.keys(fragment).sort().forEach(function(key) {
          if (!fragment.hasOwnProperty(key))
            return;
          format[key] = this._toSortedJSON(fragment[key]);
        }, this);
        return format;
    }
  },

  get bodyNormalizedJSON() {
    if (!this._bodyNormalizedJSON)
      this._bodyNormalizedJSON = this._normalize(this.bodySortedJSON);
    return this._bodyNormalizedJSON;
  },
  _normalize: function(fragment) {
    switch (typeof fragment) {
      default:
        return fragment;
      case 'object':
        var format = {};
        Object.keys(fragment).sort().forEach(function(key) {
          if (!fragment.hasOwnProperty(key))
            return;

          var value = fragment[key];
          var normalized;
          switch (key) {
            case 'RequestId':
              normalized = '%REQUEST_ID%';
              break;

            case 'DomainId':
              normalized = value.replace(/^.+\//, '%DOMAIN_ID%/');
              break;

            default:
              normalized = this._normalize(value);
              break;
          }
          format[key] = normalized;
        }, this);
        return format;
    }
  }
};

exports.ScenariosRunner = ScenariosRunner;
exports.ScenarioRunner = ScenarioRunner;
exports.Response = Response;
<commit_msg>Normalize "Endpoint" and "Arn" of domain statuses<commit_after>var Client = require(__dirname + '/../lib/client').Client;
var EventEmitter = require('events').EventEmitter;
var xml2js = require('xml2js');

var statusCodeTable = {
  500: 'Inetnal Server Error',
  404: 'Not Found',
  409: 'Conflict',
  400: 'Bad Request',
  200: 'OK'
};

function ScenariosRunner(options) {
  this.options = options;
}

ScenariosRunner.prototype = new EventEmitter();

ScenariosRunner.prototype.run = function(scenario) {
  this._process({ scenarios: scenario });
};

ScenariosRunner.prototype._process = function(params) {
  if (!params.start) params.start = Date.now();
  var scenario = params.scenarios.shift();
  var self = this;

  var runner = new ScenarioRunner(this.options);

  runner.on('error:fatal', function(event) {
    self.emit('error:fatal', event);
  });

  runner.on('start', function(event) {
    self.emit('scenario', { runner: runner,
                            scenario: event.scenario });

    runner.on('end', function(event) {
      if (params.scenarios.length) {
        self._process(params);
      } else {
        var elapsedTime = Date.now() - params.start;
        self.emit('end', { elapsedTime: elapsedTime });
      }
    });
  });

  runner.run(scenario);
};

function ScenarioRunner(options) {
  this.client = new Client(options);
  this.options = options;
  if (options.documentEndpoint)
    this.client.docEndpoint = options.documentEndpoint;
}

ScenarioRunner.prototype = new EventEmitter();

ScenarioRunner.prototype.run = function(scenario) {
  var self = this;
  this.client.assertNoDomain(function(error) {
    if (error)
      self.emit('error:fatal', { error: error });
    else
      self._process(scenario);
  });
};

ScenarioRunner.prototype.assertNoDomain = function(callback) {
  this.client.assertNoDomain(function(error) {
    callback();
  });
};

ScenarioRunner.prototype._process = function(scenario, callback) {
  if (!scenario.toBeProcessedRequests) {
    scenario.toBeProcessedRequests = scenario.requests.slice(0);
    scenario.start = Date.now();
    scenario.processed = {};
    this.emit('start', { scenario: scenario });
  }

  var request = scenario.toBeProcessedRequests.shift();
  var self = this;
  function processNext() {
    if (scenario.toBeProcessedRequests.length) {
      self._process(scenario, callback);
    } else {
      var elapsedTime = Date.now() - scenario.start;
      var event = {
        elapsedTime: elapsedTime,
        scenario: scenario
      };
      self.emit('end', event);
    }
  }

  var name = request.name;
  var count = 1;
  while (name in scenario.processed) {
    name = request.name + count++;
  }

  this.emit('request:start', { scenario: scenario, request: request });

  this.client.rawConfigurationRequest(request.params.Action, request.params, function(error, response) {
    if (error) response = error;

    var statusCode = response.StatusCode;
    if (statusCode == 400) {
      var parser = new xml2js.Parser({ explicitRoot: true });
      parser.parseString(response.Body, function(error, result) {
        var errorCode = result.Response.Errors.Error.Code;
        if (errorCode === 'Throttling') {
          self.emit('error:throttling');
        }
      });
    }
    if (!statusCodeTable[statusCode]) {
      self.emit('error:status_unknown', { statusCode: statusCode });
      if (callback)
        callback(statusCode, null);
      return;
    }

    var output = '';
    output += 'HTTP/1.1 ' + statusCode + ' ' + statusCodeTable[statusCode] + '\r\n';
    for (var key in response.Headers) {
      output += key + ': ' + response.Headers[key] + '\r\n';
    };
    output += '\r\n';
    output += response.Body.toString();

    request.response = output;
    self.emit('request:end', { scenario: scenario, request: request });
    processNext();
  });
};

function toSafeName(name) {
  return name
           .replace(/[^a-zA-Z0-9]+/g, '-')
           .replace(/-$/, '');
};
ScenariosRunner.toSafeName =
  ScenarioRunner.toSafeName = toSafeName;

function Response(source) {
  source = source.split('\r\n\r\n');
  this.headers = source[0];
  this.body = source.slice(1).join('\r\n\r\n');
}
Response.prototype = {
  get bodyRawJSON() {
    if (!this._bodyRawJSON)
      this._bodyRawJSON = this._XMLStringToJSON(this.body);
    return this._bodyRawJSON;
  },
  _XMLStringToJSON: function(xml) {
    var parser = new xml2js.Parser({
                   explicitRoot: true
                 });
    var json;
    parser.addListener('end', function(result) {
      json = result;
    });
    try {
      parser.parseString(xml);
    } catch (e) {
      console.log(xml);
      throw e;
    }
    return json;
  },

  get bodySortedJSON() {
    if (!this._bodySortedJSON)
      this._bodySortedJSON = this._toSortedJSON(this.bodyRawJSON);
    return this._bodySortedJSON;
  },
  _toSortedJSON: function(fragment) {
    switch (typeof fragment) {
      default:
        return fragment;
      case 'object':
        var format = {};
        Object.keys(fragment).sort().forEach(function(key) {
          if (!fragment.hasOwnProperty(key))
            return;
          format[key] = this._toSortedJSON(fragment[key]);
        }, this);
        return format;
    }
  },

  get bodyNormalizedJSON() {
    if (!this._bodyNormalizedJSON)
      this._bodyNormalizedJSON = this._normalize(this.bodySortedJSON);
    return this._bodyNormalizedJSON;
  },
  _normalize: function(fragment) {
    switch (typeof fragment) {
      default:
        return fragment;
      case 'object':
        var format = {};
        Object.keys(fragment).sort().forEach(function(key) {
          if (!fragment.hasOwnProperty(key))
            return;

          var value = fragment[key];
          var normalized;
          switch (key) {
            case 'RequestId':
              normalized = '%REQUEST_ID%';
              break;

            case 'DomainId':
              normalized = value.replace(/^.+\//, '%DOMAIN_ID%/');
              break;

            case 'Endpoint':
              return; // this doesn't appear in ACS's response!

            case 'Arn':
              normalized = value.replace(/^(arn:aws:cs:us-east-1:)[^:]+(:[^\/]+\/[^\/]+)$/, '$1%DOMAIN_ID%$2');
              break;

            default:
              normalized = this._normalize(value);
              break;
          }
          format[key] = normalized;
        }, this);
        return format;
    }
  }
};

exports.ScenariosRunner = ScenariosRunner;
exports.ScenarioRunner = ScenarioRunner;
exports.Response = Response;
<|endoftext|>


<commit_before>/**
 * guy
 * 这仅仅只是一个超类, 所有简单控件的基类
 * 1、类的控制，
 * 2、title的控制
 * 3、文字超过边界显示3个点
 * 4、cursor默认pointor
 * @class BI.Single
 * @extends BI.Widget
 * @abstract
 */
BI.Single = BI.inherit(BI.Widget, {
    _defaultConfig: function () {
        var conf = BI.Single.superclass._defaultConfig.apply(this, arguments);
        return BI.extend(conf, {
            readonly: false,
            title: null,
            warningTitle: null,
            tipType: null, // success或warning
            value: null,
            belowMouse: false   // title是否跟随鼠标
        });
    },

    _showToolTip: function (e, opt) {
        opt || (opt = {});
        var self = this, o = this.options;
        var type = this.getTipType() || (this.isEnabled() ? "success" : "warning");
        var title = type === "success" ? this.getTitle() : (this.getWarningTitle() || this.getTitle());
        if (BI.isKey(title)) {
            BI.Tooltips.show(e, this.getName(), title, type, this, opt);
            if (o.action) {
                BI.Actions.runAction(o.action, "hover", o, this);
            }
            BI.Actions.runGlobalAction("hover", o, this);
        }
    },

    _hideTooltip: function () {
        var self = this;
        var tooltip = BI.Tooltips.get(this.getName());
        if (BI.isNotNull(tooltip)) {
            tooltip.element.fadeOut(200, function () {
                BI.Tooltips.remove(self.getName());
            });
        }
    },

    _init: function () {
        BI.Single.superclass._init.apply(this, arguments);
        var self = this, o = this.options;
        if (BI.isKey(o.title) || BI.isKey(o.warningTitle)
            || BI.isFunction(o.title) || BI.isFunction(o.warningTitle)) {
            this.enableHover({
                belowMouse: o.belowMouse,
                container: o.container
            });
        }
    },

    _clearTimeOut: function () {
        if (BI.isNotNull(this.showTimeout)) {
            clearTimeout(this.showTimeout);
            this.showTimeout = null;
        }
        if (BI.isNotNull(this.hideTimeout)) {
            clearTimeout(this.hideTimeout);
            this.hideTimeout = null;
        }
    },

    enableHover: function (opt) {
        opt || (opt = {});
        var self = this;
        if (!this._hoverBinded) {
            this.element.on("mouseenter.title" + this.getName(), function (e) {
                self._e = e;
                if (self.getTipType() === "warning" || (BI.isKey(self.getWarningTitle()) && !self.isEnabled())) {
                    self.showTimeout = BI.delay(function () {
                        if (BI.isNotNull(self.showTimeout)) {
                            self._showToolTip(self._e || e, opt);
                        }
                    }, 200);
                } else if (self.getTipType() === "success" || self.isEnabled()) {
                    self.showTimeout = BI.delay(function () {
                        if (BI.isNotNull(self.showTimeout)) {
                            self._showToolTip(self._e || e, opt);
                        }
                    }, 500);
                }
            });
            this.element.on("mousemove.title" + this.getName(), function (e) {
                self._e = e;
                if (BI.isNotNull(self.showTimeout)) {
                    clearTimeout(self.showTimeout);
                    self.showTimeout = null;
                }
                if (BI.isNull(self.hideTimeout)) {
                    self.hideTimeout = BI.delay(function () {
                        if (BI.isNotNull(self.hideTimeout)) {
                            self._hideTooltip();
                        }
                    }, 500);
                }

                self.showTimeout = BI.delay(function () {
                    // DEC-5321 IE下如果回调已经进入事件队列，clearTimeout将不会起作用
                    if (BI.isNotNull(self.showTimeout)) {
                        if (BI.isNotNull(self.hideTimeout)) {
                            clearTimeout(self.hideTimeout);
                            self.hideTimeout = null;
                        }
                        // CHART-10611 在拖拽的情况下, 鼠标拖拽着元素离开了拖拽元素的容器，但是子元素在dom结构上仍然属于容器
                        // 这样会认为鼠标仍然在容器中, 500ms内放开的话，会在容器之外显示鼠标停留处显示容器的title
                        if (self.element.__isMouseInBounds__(self._e || e)) {
                            self._showToolTip(self._e || e, opt);
                        }
                    }
                }, 500);

            });
            this.element.on("mouseleave.title" + this.getName(), function (e) {
                self._e = null;
                self._clearTimeOut();
                self._hideTooltip();
            });
            this._hoverBinded = true;
        }
    },

    disabledHover: function () {
        // 取消hover事件
        this._clearTimeOut();
        this._hideTooltip();
        this.element.unbind("mouseenter.title" + this.getName())
            .unbind("mousemove.title" + this.getName())
            .unbind("mouseleave.title" + this.getName());
        this._hoverBinded = false;
    },

    // opt: {container: '', belowMouse: false}
    setTitle: function (title, opt) {
        this.options.title = title;
        if (BI.isKey(title) || BI.isFunction(title)) {
            this.enableHover(opt);
        } else {
            this.disabledHover();
        }
    },

    setWarningTitle: function (title, opt) {
        this.options.warningTitle = title;
        if (BI.isKey(title) || BI.isFunction(title)) {
            this.enableHover(opt);
        } else {
            this.disabledHover();
        }
    },

    setTipType: function (type) {
        this.options.tipType = type;
    },

    getTipType: function () {
        return this.options.tipType;
    },

    isReadOnly: function () {
        return !!this.options.readonly;
    },

    getTitle: function () {
        var title = this.options.title;
        if (BI.isFunction(title)) {
            return title();
        }
        return title;
    },

    getWarningTitle: function () {
        var title = this.options.warningTitle;
        if (BI.isFunction(title)) {
            return title();
        }
        return title;
    },

    setValue: function (val) {
        if (!this.options.readonly) {
            this.options.value = val;
            this.options.setValue && this.options.setValue(val);
        }
    },

    getValue: function () {
        return this.options.value;
    },

    __d: function () {
        BI.Single.superclass.__d.call(this);
        if (BI.isNotNull(this.showTimeout)) {
            clearTimeout(this.showTimeout);
            this.showTimeout = null;
        }
        BI.Tooltips.remove(this.getName());
    }
});
BI.shortcut("bi.single", BI.Single);
<commit_msg>Pull request #2182: 无JIAR任务 优化一下<commit_after>/**
 * guy
 * 这仅仅只是一个超类, 所有简单控件的基类
 * 1、类的控制，
 * 2、title的控制
 * 3、文字超过边界显示3个点
 * 4、cursor默认pointor
 * @class BI.Single
 * @extends BI.Widget
 * @abstract
 */
BI.Single = BI.inherit(BI.Widget, {
    _defaultConfig: function () {
        var conf = BI.Single.superclass._defaultConfig.apply(this, arguments);
        return BI.extend(conf, {
            el: {},
            readonly: false,
            title: null,
            warningTitle: null,
            tipType: null, // success或warning
            value: null,
            belowMouse: false   // title是否跟随鼠标
        });
    },

    render: function () {
        return this.options.el;
    },

    _showToolTip: function (e, opt) {
        opt || (opt = {});
        var self = this, o = this.options;
        var type = this.getTipType() || (this.isEnabled() ? "success" : "warning");
        var title = type === "success" ? this.getTitle() : (this.getWarningTitle() || this.getTitle());
        if (BI.isKey(title)) {
            BI.Tooltips.show(e, this.getName(), title, type, this, opt);
            if (o.action) {
                BI.Actions.runAction(o.action, "hover", o, this);
            }
            BI.Actions.runGlobalAction("hover", o, this);
        }
    },

    _hideTooltip: function () {
        var self = this;
        var tooltip = BI.Tooltips.get(this.getName());
        if (BI.isNotNull(tooltip)) {
            tooltip.element.fadeOut(200, function () {
                BI.Tooltips.remove(self.getName());
            });
        }
    },

    _init: function () {
        BI.Single.superclass._init.apply(this, arguments);
        var self = this, o = this.options;
        if (BI.isKey(o.title) || BI.isKey(o.warningTitle)
            || BI.isFunction(o.title) || BI.isFunction(o.warningTitle)) {
            this.enableHover({
                belowMouse: o.belowMouse,
                container: o.container
            });
        }
    },

    _clearTimeOut: function () {
        if (BI.isNotNull(this.showTimeout)) {
            clearTimeout(this.showTimeout);
            this.showTimeout = null;
        }
        if (BI.isNotNull(this.hideTimeout)) {
            clearTimeout(this.hideTimeout);
            this.hideTimeout = null;
        }
    },

    enableHover: function (opt) {
        opt || (opt = {});
        var self = this;
        if (!this._hoverBinded) {
            this.element.on("mouseenter.title" + this.getName(), function (e) {
                self._e = e;
                if (self.getTipType() === "warning" || (BI.isKey(self.getWarningTitle()) && !self.isEnabled())) {
                    self.showTimeout = BI.delay(function () {
                        if (BI.isNotNull(self.showTimeout)) {
                            self._showToolTip(self._e || e, opt);
                        }
                    }, 200);
                } else if (self.getTipType() === "success" || self.isEnabled()) {
                    self.showTimeout = BI.delay(function () {
                        if (BI.isNotNull(self.showTimeout)) {
                            self._showToolTip(self._e || e, opt);
                        }
                    }, 500);
                }
            });
            this.element.on("mousemove.title" + this.getName(), function (e) {
                self._e = e;
                if (BI.isNotNull(self.showTimeout)) {
                    clearTimeout(self.showTimeout);
                    self.showTimeout = null;
                }
                if (BI.isNull(self.hideTimeout)) {
                    self.hideTimeout = BI.delay(function () {
                        if (BI.isNotNull(self.hideTimeout)) {
                            self._hideTooltip();
                        }
                    }, 500);
                }

                self.showTimeout = BI.delay(function () {
                    // DEC-5321 IE下如果回调已经进入事件队列，clearTimeout将不会起作用
                    if (BI.isNotNull(self.showTimeout)) {
                        if (BI.isNotNull(self.hideTimeout)) {
                            clearTimeout(self.hideTimeout);
                            self.hideTimeout = null;
                        }
                        // CHART-10611 在拖拽的情况下, 鼠标拖拽着元素离开了拖拽元素的容器，但是子元素在dom结构上仍然属于容器
                        // 这样会认为鼠标仍然在容器中, 500ms内放开的话，会在容器之外显示鼠标停留处显示容器的title
                        if (self.element.__isMouseInBounds__(self._e || e)) {
                            self._showToolTip(self._e || e, opt);
                        }
                    }
                }, 500);

            });
            this.element.on("mouseleave.title" + this.getName(), function (e) {
                self._e = null;
                self._clearTimeOut();
                self._hideTooltip();
            });
            this._hoverBinded = true;
        }
    },

    disabledHover: function () {
        // 取消hover事件
        this._clearTimeOut();
        this._hideTooltip();
        this.element.unbind("mouseenter.title" + this.getName())
            .unbind("mousemove.title" + this.getName())
            .unbind("mouseleave.title" + this.getName());
        this._hoverBinded = false;
    },

    // opt: {container: '', belowMouse: false}
    setTitle: function (title, opt) {
        this.options.title = title;
        if (BI.isKey(title) || BI.isFunction(title)) {
            this.enableHover(opt);
        } else {
            this.disabledHover();
        }
    },

    setWarningTitle: function (title, opt) {
        this.options.warningTitle = title;
        if (BI.isKey(title) || BI.isFunction(title)) {
            this.enableHover(opt);
        } else {
            this.disabledHover();
        }
    },

    setTipType: function (type) {
        this.options.tipType = type;
    },

    getTipType: function () {
        return this.options.tipType;
    },

    isReadOnly: function () {
        return !!this.options.readonly;
    },

    getTitle: function () {
        var title = this.options.title;
        if (BI.isFunction(title)) {
            return title();
        }
        return title;
    },

    getWarningTitle: function () {
        var title = this.options.warningTitle;
        if (BI.isFunction(title)) {
            return title();
        }
        return title;
    },

    setValue: function (val) {
        if (!this.options.readonly) {
            this.options.value = val;
            this.options.setValue && this.options.setValue(val);
        }
    },

    getValue: function () {
        return this.options.value;
    },

    __d: function () {
        BI.Single.superclass.__d.call(this);
        if (BI.isNotNull(this.showTimeout)) {
            clearTimeout(this.showTimeout);
            this.showTimeout = null;
        }
        BI.Tooltips.remove(this.getName());
    }
});
BI.shortcut("bi.single", BI.Single);
<|endoftext|>


<commit_before>"use strict";
//为了防止因message而形成环形引用，message文件夹中的内容不允许被外界调用
var cluster = require("cluster");
var JSAM = require("../basic/JSAM");
// message 文件夹中定义主进程的方法
// 子进程可通过message的属性访问主进程中的方法
var onmessage = function (msg, __then) {
    var index = msg.indexOf(":");
    var run, args, key, stamp;
    if (index < 0) {
        key = msg;
        run = onmessage[key];
    } else {
        key = msg.slice(0, index);
        run = onmessage[key];
        args = msg.slice(index + 1);
    }
    if (run instanceof Function) {
        if (args) {
            var { params, stamp } = JSAM.parse(args);
            var sended = false;
            var error = null, status = 200;
            var then = stamp ? (result) => {
                if (__then) __then();
                if (sended) return;
                sended = true;
                __send(this, "onresponse", {
                    params: result,
                    error,
                    status,
                    stamp
                });
            } : null;
        } else {
            params = null;
        }
        if (then) {
            var crash = function (error) {
                error = String(error);
                status = 403,
                    then(null);
            };
            try {
                Promise.resolve(run.call(onmessage, params)).then(then, crash);
            } catch (e) {
                crash(e);
            }
        } else {
            try {
                Promise.resolve(run.call(onmessage, params)).catch(console.error);
            } catch (e) {
                console.error(e);
            }
        }
        if (__then && !then) __then();
    }
};
var callback_maps = {};
// 发送消息到指定进程
var send, __send = send = function (worker, key, params, onsuccess, onerror, onfinish) {
    var stamp;
    if (arguments.length === 4) {
        onfinish = onsuccess;
        onsuccess = null;
    }
    if (onsuccess instanceof Function || onerror instanceof Function || onfinish instanceof Function) {
        do {
            stamp = Math.random().toString("36").slice(2);
        } while (stamp in callback_maps);
        callback_maps[stamp] = [onsuccess, onerror, onfinish];
    }
    worker.connected && worker.send([key, JSAM.stringify({
        params, stamp
    })].join(":"));
};
// if (isDebug) {
//     __send = send = function () {
//     };
// }
//收到其他进程的回复
var onresponse = function ({ stamp, params, error }) {
    var callback = callback_maps[stamp];
    delete callback_maps[stamp];
    if (callback instanceof Array) {
        var [onsuccess, onerror, onfinish] = callback;
        if (onfinish instanceof Function) {
            onfinish(error, params);
        }
        if (!error) {
            if (onsuccess instanceof Function) onsuccess(params);
        } else {
            if (onerror instanceof Function) onerror(error);
            else console.error(error);
        }
    }
};
onmessage.onresponse = onresponse;

if (cluster.isMaster) {
    onmessage["abpi"] = require("./abpi");
    onmessage["count"] = require("./count");
    onmessage["log"] = require("./log");
    onmessage.send = send;
} else {
    onmessage["abpi"] = __send.bind(onmessage, process, "abpi");
    onmessage["count"] = __send.bind(onmessage, process, "count");
    onmessage["log"] = __send.bind(onmessage, process, "log");
    process.on("message", onmessage);

    onmessage.send = send = send.bind(onmessage, process);
    onmessage.broadcast = function (key, data) {
        __send(process, 'broadcast', { key, data });
    };
    onmessage.onbroadcast = function ({ key, data }) {
        if (onmessage[key] instanceof Function) onmessage[key](data);
    };
}
module.exports = onmessage;<commit_msg>解决无法从主进程往子进程发送消息的问题<commit_after>"use strict";
//为了防止因message而形成环形引用，message文件夹中的内容不允许被外界调用
var cluster = require("cluster");
var JSAM = require("../basic/JSAM");
// message 文件夹中定义主进程的方法
// 子进程可通过message的属性访问主进程中的方法
var onmessage = function (msg, __then) {
    var index = msg.indexOf(":");
    var run, args, key, stamp;
    if (index < 0) {
        key = msg;
        run = onmessage[key];
    } else {
        key = msg.slice(0, index);
        run = onmessage[key];
        args = msg.slice(index + 1);
    }
    if (run instanceof Function) {
        if (args) {
            var { params, stamp } = JSAM.parse(args);
            var sended = false;
            var error = null, status = 200;
            var then = stamp ? (result) => {
                if (__then) __then();
                if (sended) return;
                sended = true;
                __send(this, "onresponse", {
                    params: result,
                    error,
                    status,
                    stamp
                });
            } : null;
        } else {
            params = null;
        }
        if (then) {
            var crash = function (error) {
                error = String(error);
                status = 403,
                    then(null);
            };
            try {
                Promise.resolve(run.call(onmessage, params)).then(then, crash);
            } catch (e) {
                crash(e);
            }
        } else {
            try {
                Promise.resolve(run.call(onmessage, params)).catch(console.error);
            } catch (e) {
                console.error(e);
            }
        }
        if (__then && !then) __then();
    }
};
var callback_maps = {};
// 发送消息到指定进程
var send, __send = send = function (worker, key, params, onsuccess, onerror, onfinish) {
    var stamp;
    if (arguments.length === 4) {
        onfinish = onsuccess;
        onsuccess = null;
    }
    if (onsuccess instanceof Function || onerror instanceof Function || onfinish instanceof Function) {
        do {
            stamp = Math.random().toString("36").slice(2);
        } while (stamp in callback_maps);
        callback_maps[stamp] = [onsuccess, onerror, onfinish];
    }
    (worker.process || worker).connected && worker.send([key, JSAM.stringify({
        params, stamp
    })].join(":"));
};
// if (isDebug) {
//     __send = send = function () {
//     };
// }
//收到其他进程的回复
var onresponse = function ({ stamp, params, error }) {
    var callback = callback_maps[stamp];
    delete callback_maps[stamp];
    if (callback instanceof Array) {
        var [onsuccess, onerror, onfinish] = callback;
        if (onfinish instanceof Function) {
            onfinish(error, params);
        }
        if (!error) {
            if (onsuccess instanceof Function) onsuccess(params);
        } else {
            if (onerror instanceof Function) onerror(error);
            else console.error(error);
        }
    }
};
onmessage.onresponse = onresponse;

if (cluster.isMaster) {
    onmessage["abpi"] = require("./abpi");
    onmessage["count"] = require("./count");
    onmessage["log"] = require("./log");
    onmessage.send = send;
} else {
    onmessage["abpi"] = __send.bind(onmessage, process, "abpi");
    onmessage["count"] = __send.bind(onmessage, process, "count");
    onmessage["log"] = __send.bind(onmessage, process, "log");
    process.on("message", onmessage);

    onmessage.send = send = send.bind(onmessage, process);
    onmessage.broadcast = function (key, data) {
        __send(process, 'broadcast', { key, data });
    };
    onmessage.onbroadcast = function ({ key, data }) {
        if (onmessage[key] instanceof Function) onmessage[key](data);
    };
}
module.exports = onmessage;<|endoftext|>


<commit_before>// js/controllers/nw-category-select.controller

(function() {
  "use strict";

  angular.module("NoteWrangler")
    .controller("nwCategorySelectController", nwCategorySelectController);

  nwCategorySelectController.$inject = ["Category"];

  function nwCategorySelectController(Category) {
    let vm = this;

    vm.query = _query;
    vm.getActiveCategory = _getActiveCategory;
    vm.setActiveCategory = _setActiveCategory;
    vm.getCategoryCount = _getCategoryCount;

    function _query() {
      return Category.query();
    }

    function _getActiveCategory() {
      return vm.activeCategory;
    }

    function _setActiveCategory(newCategory) {
      vm.activeCategory = newCategory.name;
    }

    function _getCategoryCount(notes, category) {

      let categoryNotes = notes.filter( (v) => {
        return v.category.name == category.name;
      });

      return categoryNotes.length;
    }
  }
})();
<commit_msg>Use  to store activeCategory for filtering<commit_after>// js/controllers/nw-category-select.controller

(function() {
  "use strict";

  angular.module("NoteWrangler")
    .controller("nwCategorySelectController", nwCategorySelectController);

  nwCategorySelectController.$inject = ["Category", "$scope"];

  function nwCategorySelectController(Category, $scope) {
    let vm = this;

    vm.query = _query;
    vm.getActiveCategory = _getActiveCategory;
    vm.setActiveCategory = _setActiveCategory;
    vm.getCategoryCount = _getCategoryCount;

    function _query() {
      return Category.query();
    }

    function _getActiveCategory() {
      return vm.activeCategory;
    }

    function _setActiveCategory(newCategory) {
      vm.activeCategory = newCategory.name;

      // need refactoring
      $scope.activeCategory = newCategory.name;
    }

    function _getCategoryCount(notes, category) {

      let categoryNotes = notes.filter( (v) => {
        return v.category.name == category.name;
      });

      return categoryNotes.length;
    }
  }
})();
<|endoftext|>


<commit_before>const Gadget = require('mongoose').model('Gadget')
const Comment = require('mongoose').model('Comment')

function validateGadgetForm (payload) {
  const errors = {}
  let isFormValid = true
  let message = ''

  if (!payload || typeof payload.title !== 'string') {
    isFormValid = false
    errors.email = 'Please provide a correct title.'
  }

  if (!payload || typeof payload.title !== 'string' || payload.title.trim().length < 4) {
    isFormValid = false
    errors.title = 'Title must have at least 4 characters.'
  }

  if (!payload || typeof payload.description !== 'string' || payload.description.trim().length === 0) {
    isFormValid = false
    errors.description = 'Please provide a valid description.'
  }

  if (!payload || typeof payload.description !== 'string' || payload.description.trim().length < 10) {
    isFormValid = false
    errors.description = 'Description must have at least 10 characters.'
  }

  if (!payload || (Number(payload.quantityOnStock) < 0 || Number(payload.quantityOnStock) > 100) ||
  typeof Number(payload.quantityOnStock) !== 'number') {
    isFormValid = false
    errors.quantity = 'Quantity must be between 0 and 100pcs.'
  }
  if (!payload || typeof Number(payload.price) !== 'number' || !payload.price > 1) {
    isFormValid = false
    errors.price = 'Price must be greater than 1.'
  }
  if (!isFormValid) {
    message = 'Check the form for errors.'
  }

  return {
    success: isFormValid,
    message,
    errors
  }
}
module.exports = {
  create: (req, res) => {
    let gadgetBody = req.body
    let userId = req.user._id
    const validationResult = validateGadgetForm(gadgetBody)
    if (!validationResult.success) {
      return res.status(200).json({
        success: false,
        message: validationResult.message,
        errors: validationResult.errors
      })
    }
    Gadget.create({
      title: gadgetBody.title,
      image: gadgetBody.image,
      description: gadgetBody.description,
      quantityOnStock: gadgetBody.quantityOnStock,
      userId: userId,
      price: gadgetBody.price,
      comments: [],
      isBought: false
    })
    .then((gadget) => {
      res.status(200).json({
        success: true,
        message: 'Gadget added successfuly.',
        gadget
      })
    })
    .catch(() => {
      res.status(200).json({
        success: false,
        message: 'Title must be unique.',
        errors: 'Title must be unique.'
      })
    })
  },
  all: (req, res) => {
    const page = parseInt(req.query.page) || 1
    let getGadgets = new Promise((resolve, reject) => {
      const pageSize = 3
      Gadget
        .find({})
        .skip((page - 1) * pageSize)
        .limit(pageSize)
        .then(gadgets => {
          return resolve(gadgets)
        })
        .catch(err => res.status(200).json(err))
    })

    getGadgets
      .then(gadget => {
        res.status(200).json(gadget)
      })
      .catch(err => res.status(200).json(err))
  },
  getDetails: (req, res) => {
    const id = req.params.id
    Gadget
        .findById(id)
        .populate('comments')
        .then(gadget => {
          if (!gadget) {
            return res.status(200).json({
              success: false,
              message: 'Gadget does not exists!'
            })
          }
          return res.status(200).json(gadget)
        })
        .catch((err) => {
          console.log(err)
          return res.status(200).json(err)
        })
  },
  editGet: (req, res) => {
    let idEditGadget = req.params.id
    Gadget
      .findById(idEditGadget)
      .then(gadget => {
        if (!gadget) {
          return res.status(200).json({
            success: false,
            message: 'Gadget does not exists!'
          })
        }
        res.status(200).json(gadget)
      }).catch(err => {
        console.log(err)
        res.status(200).json(err)
      })
  },
  editPost: (req, res) => {
    let idEditGadget = req.params.id
    let reqbody = req.body
    let title = reqbody.title
    let description = reqbody.description
    let image = req.body.image
    let quantityOnStock = Number(req.body.quantityOnStock)
    let price = Number(req.body.price)
    Gadget
      .findByIdAndUpdate(idEditGadget, {
        $set: {
          title: title,
          description: description,
          image: image,
          quantityOnStock: quantityOnStock,
          price: price
        }
      })
      .then(gadget => {
        gadget.save()
        .then(() => {
          return res.status(200).json({
            success: true,
            message: 'Edit successful!',
            gadget
          })
        })
      })
  },
  deleteGet: (req, res) => {
    let idDeleteGadget = req.params.id
    Gadget
      .findById(idDeleteGadget)
      .then(gadget => {
        if (!gadget) {
          return res.status(200).json({
            success: false,
            message: 'Gadget does not exists!'
          })
        }
        res.status(200).json(gadget)
      }).catch(err => {
        console.log(err)
        res.status(200).json(err)
      })
  },
  deletePost: (req, res) => {
    let idDeleteGadget = req.params.id
    Comment
      .remove({gadgetId: idDeleteGadget})
      .then(() => {
        Gadget.findByIdAndRemove(idDeleteGadget)
          .then(gadget => {
            res.status(200).json({
              success: true,
              message: 'Gadget deleted successfuly.'
            })
          })
      }).catch(err => {
        console.log(err)
        res.status(200).json(err)
      })
  },
  search: (req, res) => {
    const search = req.query.search
    let query = Gadget.find({})
    if (search) {
      query = query.where('title').regex(new RegExp(search, 'i'))
    }
    query
      .then(gadgets => {
        return res.status(200).json(gadgets)
      })
      .catch(err => res.status(200).json(err))
  },
  buyGadget: (req, res) => {
    let idReqUser = req.user._id
    let idGadgetBought = req.body.gadgetId
    Gadget
      .findById(idGadgetBought)
      .then(gadget => {
        if (gadget === null) {
          return res.status(200).json({
            success: false,
            message: 'No gadget purchased by the current user found!'
          })
        }
        if (gadget.quantityOnStock > 0) {
          let isBoughtIndex = gadget.buyerUsers.indexOf(idReqUser)

          // Check if current user already bought this gadget before
          if (isBoughtIndex > -1) {
            let quantityBoughtByUser = gadget.quantityBought[isBoughtIndex]
            gadget.quantityBought[isBoughtIndex] = ++quantityBoughtByUser
          } else {
            gadget.buyerUsers.push(idReqUser.toString())
            gadget.quantityBought.push(1)
          }
          Gadget.update(
          {_id: idGadgetBought},
            {$set: {
              buyerUsers: gadget.buyerUsers,
              quantityBought: gadget.quantityBought,
              quantityOnStock: --gadget.quantityOnStock,
              quantitySold: ++gadget.quantitySold
            }}
        )
          .then(() => {
            return res.status(200).json({
              success: true,
              message: 'Gadget bought successfuly.'
            })
          }).catch(err => {
            console.log(err)
            res.status(200).json(err)
          })
        } else {
          return res.status(200).json({
            success: false,
            message: 'Thre are no available quantities on stock for this article at the moment.'
          })
        }
      }).catch(err => {
        console.log(err)
        res.status(200).json(err)
      })
  },
  findGadgetsBought: (req, res) => {
    let idReqUser = req.params.id

    Gadget
     .find({buyerUsers: idReqUser})
     .then(gadgets => {
       let qtyBoughtGadgets = {}
       for (let gadget of gadgets) {
         let searchedIndex = gadget.buyerUsers.indexOf(idReqUser)
         let totalPrice = gadget.quantityBought[searchedIndex] * gadget.price
         let userQuantityBought = gadget.quantityBought[searchedIndex]
         qtyBoughtGadgets[gadget.title] = [userQuantityBought, totalPrice]
       }
       return res.status(200).json({
         success: true,
         qtyBoughtGadgets
       })
     }).catch(err => {
       console.log(err)
       res.status(200).json(err)
     })
  }
}
<commit_msg>Added reurn of  err message in gadgets-controller when user still did not bought any gadgets<commit_after>const Gadget = require('mongoose').model('Gadget')
const Comment = require('mongoose').model('Comment')

function validateGadgetForm (payload) {
  const errors = {}
  let isFormValid = true
  let message = ''

  if (!payload || typeof payload.title !== 'string') {
    isFormValid = false
    errors.email = 'Please provide a correct title.'
  }

  if (!payload || typeof payload.title !== 'string' || payload.title.trim().length < 4) {
    isFormValid = false
    errors.title = 'Title must have at least 4 characters.'
  }

  if (!payload || typeof payload.description !== 'string' || payload.description.trim().length === 0) {
    isFormValid = false
    errors.description = 'Please provide a valid description.'
  }

  if (!payload || typeof payload.description !== 'string' || payload.description.trim().length < 10) {
    isFormValid = false
    errors.description = 'Description must have at least 10 characters.'
  }

  if (!payload || (Number(payload.quantityOnStock) < 0 || Number(payload.quantityOnStock) > 100) ||
  typeof Number(payload.quantityOnStock) !== 'number') {
    isFormValid = false
    errors.quantity = 'Quantity must be between 0 and 100pcs.'
  }
  if (!payload || typeof Number(payload.price) !== 'number' || !payload.price > 1) {
    isFormValid = false
    errors.price = 'Price must be greater than 1.'
  }
  if (!isFormValid) {
    message = 'Check the form for errors.'
  }

  return {
    success: isFormValid,
    message,
    errors
  }
}
module.exports = {
  create: (req, res) => {
    let gadgetBody = req.body
    let userId = req.user._id
    const validationResult = validateGadgetForm(gadgetBody)
    if (!validationResult.success) {
      return res.status(200).json({
        success: false,
        message: validationResult.message,
        errors: validationResult.errors
      })
    }
    Gadget.create({
      title: gadgetBody.title,
      image: gadgetBody.image,
      description: gadgetBody.description,
      quantityOnStock: gadgetBody.quantityOnStock,
      userId: userId,
      price: gadgetBody.price,
      comments: [],
      isBought: false
    })
    .then((gadget) => {
      res.status(200).json({
        success: true,
        message: 'Gadget added successfuly.',
        gadget
      })
    })
    .catch(() => {
      res.status(200).json({
        success: false,
        message: 'Title must be unique.',
        errors: 'Title must be unique.'
      })
    })
  },
  all: (req, res) => {
    const page = parseInt(req.query.page) || 1
    let getGadgets = new Promise((resolve, reject) => {
      const pageSize = 3
      Gadget
        .find({})
        .skip((page - 1) * pageSize)
        .limit(pageSize)
        .then(gadgets => {
          return resolve(gadgets)
        })
        .catch(err => res.status(200).json(err))
    })

    getGadgets
      .then(gadget => {
        res.status(200).json(gadget)
      })
      .catch(err => res.status(200).json(err))
  },
  getDetails: (req, res) => {
    const id = req.params.id
    Gadget
        .findById(id)
        .populate('comments')
        .then(gadget => {
          if (!gadget) {
            return res.status(200).json({
              success: false,
              message: 'Gadget does not exists!'
            })
          }
          return res.status(200).json(gadget)
        })
        .catch((err) => {
          console.log(err)
          return res.status(200).json(err)
        })
  },
  editGet: (req, res) => {
    let idEditGadget = req.params.id
    Gadget
      .findById(idEditGadget)
      .then(gadget => {
        if (!gadget) {
          return res.status(200).json({
            success: false,
            message: 'Gadget does not exists!'
          })
        }
        res.status(200).json(gadget)
      }).catch(err => {
        console.log(err)
        res.status(200).json(err)
      })
  },
  editPost: (req, res) => {
    let idEditGadget = req.params.id
    let reqbody = req.body
    let title = reqbody.title
    let description = reqbody.description
    let image = req.body.image
    let quantityOnStock = Number(req.body.quantityOnStock)
    let price = Number(req.body.price)
    Gadget
      .findByIdAndUpdate(idEditGadget, {
        $set: {
          title: title,
          description: description,
          image: image,
          quantityOnStock: quantityOnStock,
          price: price
        }
      })
      .then(gadget => {
        gadget.save()
        .then(() => {
          return res.status(200).json({
            success: true,
            message: 'Edit successful!',
            gadget
          })
        })
      })
  },
  deleteGet: (req, res) => {
    let idDeleteGadget = req.params.id
    Gadget
      .findById(idDeleteGadget)
      .then(gadget => {
        if (!gadget) {
          return res.status(200).json({
            success: false,
            message: 'Gadget does not exists!'
          })
        }
        res.status(200).json(gadget)
      }).catch(err => {
        console.log(err)
        res.status(200).json(err)
      })
  },
  deletePost: (req, res) => {
    let idDeleteGadget = req.params.id
    Comment
      .remove({gadgetId: idDeleteGadget})
      .then(() => {
        Gadget.findByIdAndRemove(idDeleteGadget)
          .then(gadget => {
            res.status(200).json({
              success: true,
              message: 'Gadget deleted successfuly.'
            })
          })
      }).catch(err => {
        console.log(err)
        res.status(200).json(err)
      })
  },
  search: (req, res) => {
    const search = req.query.search
    let query = Gadget.find({})
    if (search) {
      query = query.where('title').regex(new RegExp(search, 'i'))
    }
    query
      .then(gadgets => {
        return res.status(200).json(gadgets)
      })
      .catch(err => res.status(200).json(err))
  },
  buyGadget: (req, res) => {
    let idReqUser = req.user._id
    let idGadgetBought = req.body.gadgetId
    Gadget
      .findById(idGadgetBought)
      .then(gadget => {
        if (gadget.quantityOnStock > 0) {
          let isBoughtIndex = gadget.buyerUsers.indexOf(idReqUser)

          // Check if current user already bought this gadget before
          if (isBoughtIndex > -1) {
            let quantityBoughtByUser = gadget.quantityBought[isBoughtIndex]
            gadget.quantityBought[isBoughtIndex] = ++quantityBoughtByUser
          } else {
            gadget.buyerUsers.push(idReqUser.toString())
            gadget.quantityBought.push(1)
          }
          Gadget.update(
          {_id: idGadgetBought},
            {$set: {
              buyerUsers: gadget.buyerUsers,
              quantityBought: gadget.quantityBought,
              quantityOnStock: --gadget.quantityOnStock,
              quantitySold: ++gadget.quantitySold
            }}
        )
          .then(() => {
            return res.status(200).json({
              success: true,
              message: 'Gadget bought successfuly.'
            })
          }).catch(err => {
            console.log(err)
            res.status(200).json(err)
          })
        } else {
          return res.status(200).json({
            success: false,
            message: 'Thre are no available quantities on stock for this article at the moment.'
          })
        }
      }).catch(err => {
        console.log(err)
        res.status(200).json(err)
      })
  },
  findGadgetsBought: (req, res) => {
    let idReqUser = req.params.id

    Gadget
     .find({buyerUsers: idReqUser})
     .then(gadgets => {
       if (gadgets.length < 1) {
         return res.status(200).json({
           success: false,
           message: 'No gadget purchased by current user found!'
         })
       }
       let qtyBoughtGadgets = {}
       for (let gadget of gadgets) {
         let searchedIndex = gadget.buyerUsers.indexOf(idReqUser)
         let totalPrice = gadget.quantityBought[searchedIndex] * gadget.price
         let userQuantityBought = gadget.quantityBought[searchedIndex]
         qtyBoughtGadgets[gadget.title] = [userQuantityBought, totalPrice]
       }
       return res.status(200).json({
         success: true,
         qtyBoughtGadgets
       })
     }).catch(err => {
       console.log(err)
       res.status(200).json(err)
     })
  }
}
<|endoftext|>


<commit_before>import { expect } from "code";
import * as Lab from "lab";
import getHelper from "lab-testing";
import createMapper from "../lib/index";
import existingSuite from "./suites/existing-modifier-suite";
import alwaysSuite from "./suites/always-modifier-suite";

const lab = exports.lab = Lab.script();
const testing = getHelper(lab);
const group = testing.createExperiment("The createMapper() method");

group("when setting options", () => {

  lab.test("sets the defaults correctly when no options are provided", done => {

    const map = createMapper();

    const mapping = map("a");

    expect(mapping).to.be.an.object();
    expect(mapping.alwaysSet).to.be.false();
    expect(mapping.alwaysTransform).to.be.false();
    expect(mapping.flatten).to.be.null();
    expect(mapping.flattenInverted).to.be.false();

    return done();

  });

  lab.test("sets the defaults correctly when empty options are provided", done => {

    const map = createMapper({});

    const mapping = map("a");

    expect(mapping).to.be.an.object();
    expect(mapping.alwaysSet).to.be.false();
    expect(mapping.alwaysTransform).to.be.false();
    expect(mapping.flatten).to.be.null();
    expect(mapping.flattenInverted).to.be.false();

    return done();

  });

  lab.test("sets the alwaysTransform option correctly", done => {

    const map = createMapper({ alwaysTransform: true });

    const mapping = map("a");

    expect(mapping).to.be.an.object();
    expect(mapping.alwaysSet).to.be.false();
    expect(mapping.alwaysTransform).to.be.true();
    expect(mapping.flatten).to.be.null();
    expect(mapping.flattenInverted).to.be.false();

    return done();

  });

  lab.test("sets the alwaysSet option correctly", done => {

    const map = createMapper({ alwaysSet: true });

    const mapping = map("a");

    expect(mapping).to.be.an.object();
    expect(mapping.alwaysSet).to.be.true();
    expect(mapping.alwaysTransform).to.be.false();
    expect(mapping.flatten).to.be.null();
    expect(mapping.flattenInverted).to.be.false();

    return done();

  });

  lab.test("sets the flattenInverted option correctly", done => {

    const map = createMapper({ flattenInverted: true });

    const mapping = map("a");

    expect(mapping).to.be.an.object();
    expect(mapping.alwaysSet).to.be.false();
    expect(mapping.alwaysTransform).to.be.false();
    expect(mapping.flatten).to.be.null();
    expect(mapping.flattenInverted).to.be.true();

    return done();

  });

  lab.test("sets the flatten option correctly", done => {

    const map = createMapper({ flatten: true });

    const mapping = map("a");

    expect(mapping).to.be.an.object();
    expect(mapping.alwaysSet).to.be.false();
    expect(mapping.alwaysTransform).to.be.false();
    expect(mapping.flatten).to.be.true();
    expect(mapping.flattenInverted).to.be.false();

    return done();

  });

  lab.test("the existing modifier sets more alwaysSet and alwaysTransform to false", done => {

    const map = createMapper({ alwaysSet: true, alwaysTransform: true });

    const mapping = map("a").existing;

    expect(mapping).to.be.an.object();
    expect(mapping.alwaysSet).to.be.false();
    expect(mapping.alwaysTransform).to.be.false();

    return done();

  });

  lab.test("the always modifier sets more alwaysSet and alwaysTransform to true", done => {

    const map = createMapper({ alwaysSet: false, alwaysTransform: false });

    const mapping = map("a").always;

    expect(mapping).to.be.an.object();
    expect(mapping.alwaysSet).to.be.true();
    expect(mapping.alwaysTransform).to.be.true();

    return done();

  });

});

group("when executing with options set, the single source mapper", () => {

  lab.test("suppresses a transform when the source value is not present", done => {

    const source = {
      "my": {
        "source": {
          "is": {}
        }
      }
    };

    const expected = {
      "your": {
        "source": {
          "is": {}
        }
      }
    };

    const map = createMapper({ alwaysTransform: false, alwaysSet: true });

    map("my.source.is.missing").to("your.source.is.missing", () => {
      return "found";
    });

    const actual = map.execute(source);

    expect(actual).to.equal(expected);

    return done();

  });

  lab.test("suppresses a set when the source value is not present", done => {

    const source = {
      "my": {
        "source": {
          "is": {}
        }
      }
    };

    const expected = {
    };

    const map = createMapper({ alwaysTransform: false, alwaysSet: false });
    let count = 0;

    map("my.source.is.missing").to("your.source.is.missing", () => {
      count++;
      return "found";
    });

    const actual = map.execute(source);

    expect(actual).to.equal(expected);
    expect(count).to.equal(0);

    return done();

  });

  lab.test("a set is not supressed when the source value is not present if a transform returns a value", done => {

    const source = {
      "my": {
        "source": {
          "is": {}
        }
      }
    };

    const expected = {
      "your": {
        "source": {
          "is": {
            "missing": "found"
          }
        }
      }
    };

    const map = createMapper({ alwaysTransform: true, alwaysSet: false });

    map("my.source.is.missing").to("your.source.is.missing", () => {
      return "found";
    });

    const actual = map.execute(source);

    expect(actual).to.equal(expected);

    return done();

  });

  lab.test("if a transform returns undefined a set will be called", done => {

    const source = {
      "my": {
        "source": {
          "is": {}
        }
      }
    };

    const expected = {
      "your": {
        "source": {
          "is": {}
        }
      }
    };

    const map = createMapper({ alwaysTransform: true, alwaysSet: true });

    map("my.source.is.missing").to("your.source.is.missing", () => {
      return undefined;
    });

    const actual = map.execute(source);

    expect(actual).to.equal(expected);

    return done();

  });

  lab.test("if source value is false set will be called", done => {

    const source = {
      "my": {
        "source": {
          "is": {
            "missing": false
          }
        }
      }
    };

    const expected = {
      "your": {
        "source": {
          "is": {
            "missing": false
          }
        }
      }
    };

    const map = createMapper({ alwaysTransform: false, alwaysSet: false });

    map("my.source.is.missing").to("your.source.is.missing");

    const actual = map.execute(source);

    expect(actual).to.equal(expected);

    return done();

  });

});

group("when executing with options set, the multi source mapper", () => {

  lab.test("suppresses a transform when the source values are all not present", done => {

    const source = {
      "my": {
        "source": {
          "is": {}
        },
        "other": {
          "source": {
            "is": {}
          }
        }
      }
    };

    const expected = {
      "your": {
        "source": {
          "is": {}
        }
      }
    };

    const map = createMapper({ alwaysTransform: false, alwaysSet: true });

    map(["my.source.is.missing", "my.other.source.is.missing"]).to("your.source.is.missing", () => {
      return "found";
    });

    const actual = map.execute(source);

    expect(actual).to.equal(expected);

    return done();

  });

  lab.test("suppresses a set if a transform returns null", done => {

    const source = {
      "my": {
        "source": {
          "is": {}
        },
        "other": {
          "source": {
            "is": {
              "here": "value"
            }
          }
        }
      }
    };

    const expected = {
    };

    const map = createMapper({ alwaysTransform: false, alwaysSet: false });
    let count = 0;

    map(["my.source.is.missing", "my.other.source.is.here"]).to("your.source.is.missing", () => {
      count++;
      return null;
    });

    const actual = map.execute(source);

    expect(actual).to.equal(expected);
    expect(count).to.equal(1);

    return done();

  });

  lab.test("suppresses a set if a transform returns undefined", done => {

    const source = {
      "my": {
        "source": {
          "is": {}
        },
        "other": {
          "source": {
            "is": {
              "here": "value"
            }
          }
        }
      }
    };

    const expected = {
    };

    const map = createMapper({ alwaysTransform: false, alwaysSet: false });

    let count = 0;

    map(["my.source.is.missing", "my.other.source.is.here"]).to("your.source.is.missing", () => {
      count++;
      return undefined;
    });

    const actual = map.execute(source);

    expect(actual).to.equal(expected);
    expect(count).to.equal(1);

    return done();

  });

  lab.test("a transform executes when one source value is present", done => {

    const source = {
      "my": {
        "source": {
          "is": {
            "here": "value"
          }
        },
        "other": {
          "source": {
            "is": {}
          }
        }
      }
    };

    const expected = {
      "your": {
        "source": {
          "is": {
            "here": "found"
          }
        }
      }
    };

    const map = createMapper({ alwaysTransform: false, alwaysSet: true });

    map(["my.source.is.here", "my.other.source.is.missing"]).to("your.source.is.here", () => {
      return "found";
    });

    const actual = map.execute(source);

    expect(actual).to.equal(expected);

    return done();

  });
});

group("when executing with options set, the or-mode source map", () => {

  lab.test("a transform executes when no sources are present but alwaysTransform is true", done => {

    const source = {
      "my": {
        "source": {
          "is": {}
        },
        "other": {
          "source": {
            "is": {}
          }
        }
      }
    };

    const expected = {
      "your": {
        "source": {
          "is": {
            "here": "found"
          }
        }
      }
    };

    const map = createMapper({ alwaysTransform: true, alwaysSet: false });

    map("my.source.is.here").or("my.other.source.is.missing").to("your.source.is.here", () => {
      return "found";
    });

    const actual = map.execute(source);

    expect(actual).to.equal(expected);

    return done();

  });

  lab.test("a transform does not execute when no sources are present and alwaysTransform is false", done => {
    const source = {
      "my": {
        "source": {
          "is": {}
        },
        "other": {
          "source": {
            "is": {}
          }
        }
      }
    };

    const expected = {};

    const map = createMapper({ alwaysTransform: false, alwaysSet: false });

    map("my.source.is.here").or("my.other.source.is.missing").to("your.source.is.here", () => {
      return "whoops";
    });

    const actual = map.execute(source);

    expect(actual).to.equal(expected);

    return done();

  });

  lab.test("no set is called when no values are present and alwaysSet is false", done => {

    const source = {
      "my": {
        "source": {
          "is": {}
        },
        "other": {
          "source": {
            "is": {}
          }
        }
      }
    };

    const expected = {};

    const map = createMapper({ alwaysTransform: false, alwaysSet: false });

    map("my.source.is.here").or("my.other.source.is.missing").to("your.source.is.here");

    const actual = map.execute(source);

    expect(actual).to.equal(expected);

    return done();

  });

  lab.test("set is called when no values are present but alwaysSet is true", done => {

    const source = {
      "my": {
        "source": {
          "is": {}
        },
        "other": {
          "source": {
            "is": {}
          }
        }
      }
    };

    const expected = {
      "your": {
        "source": {
          "is": {}
        }
      }
    };
    const map = createMapper({ alwaysTransform: false, alwaysSet: true });

    map("my.source.is.here").or("my.other.source.is.missing").to("your.source.is.here");

    const actual = map.execute(source);

    expect(actual).to.equal(expected);

    return done();

  });

});

group("the always modifier", () => {

  alwaysSuite.run(lab, { OPTIONS: null });
  alwaysSuite.run(lab, {});
  alwaysSuite.run(lab, { OPTIONS: { alwaysTransform: false, alwaysSet: false } });
  alwaysSuite.run(lab, { OPTIONS: { alwaysTransform: false, alwaysSet: true } });
  alwaysSuite.run(lab, { OPTIONS: { alwaysTransform: true, alwaysSet: false } });
  alwaysSuite.run(lab, { OPTIONS: { alwaysTransform: false, alwaysSet: true } });

});

group("the existing modifier", () => {

  existingSuite.run(lab, { OPTIONS: null });
  existingSuite.run(lab, {});
  existingSuite.run(lab, { OPTIONS: { alwaysTransform: false, alwaysSet: false } });
  existingSuite.run(lab, { OPTIONS: { alwaysTransform: false, alwaysSet: true } });
  existingSuite.run(lab, { OPTIONS: { alwaysTransform: true, alwaysSet: false } });
  existingSuite.run(lab, { OPTIONS: { alwaysTransform: false, alwaysSet: true } });

});

group("the failureTransform as a option for default use", () => {
  lab.test("should use the global failure transformed if its defined and failure transform is not provided as part of the mapping", done => {
    const source = {
      "foo": "name1",
      "bar": "name2",
      "fooNull": null
    };

    const expected = {
      "foo1": "bar",
      "foo2": "bar",
      "foo3": "from global",
      "fooOr": "from global",
      "foo4": "from global",
      "foo5": "from global"
    };

    const mapper = createMapper({ failureTransform: () => "from global"});

    mapper
      .map("foo1").to("foo1", null, "bar")
      .map("foo2").to("foo2", null, () => "bar")
      .map("foo2").to("foo5")
      .map(["foo1", "foo2"]).to("foo3", () => "check")
      .map("foo1").or("foo2").to("fooOr")
      .map("foo4").always.to("foo4");

    const actual = mapper.execute(source);

    expect(actual).to.equal(expected);

    return done();
  });
});
<commit_msg>[incorporating review comment]<commit_after>import { expect } from "code";
import * as Lab from "lab";
import getHelper from "lab-testing";
import createMapper from "../lib/index";
import existingSuite from "./suites/existing-modifier-suite";
import alwaysSuite from "./suites/always-modifier-suite";

const lab = exports.lab = Lab.script();
const testing = getHelper(lab);
const group = testing.createExperiment("The createMapper() method");

group("when setting options", () => {

  lab.test("sets the defaults correctly when no options are provided", done => {

    const map = createMapper();

    const mapping = map("a");

    expect(mapping).to.be.an.object();
    expect(mapping.alwaysSet).to.be.false();
    expect(mapping.alwaysTransform).to.be.false();
    expect(mapping.flatten).to.be.null();
    expect(mapping.flattenInverted).to.be.false();

    return done();

  });

  lab.test("sets the defaults correctly when empty options are provided", done => {

    const map = createMapper({});

    const mapping = map("a");

    expect(mapping).to.be.an.object();
    expect(mapping.alwaysSet).to.be.false();
    expect(mapping.alwaysTransform).to.be.false();
    expect(mapping.flatten).to.be.null();
    expect(mapping.flattenInverted).to.be.false();

    return done();

  });

  lab.test("sets the alwaysTransform option correctly", done => {

    const map = createMapper({ alwaysTransform: true });

    const mapping = map("a");

    expect(mapping).to.be.an.object();
    expect(mapping.alwaysSet).to.be.false();
    expect(mapping.alwaysTransform).to.be.true();
    expect(mapping.flatten).to.be.null();
    expect(mapping.flattenInverted).to.be.false();

    return done();

  });

  lab.test("sets the alwaysSet option correctly", done => {

    const map = createMapper({ alwaysSet: true });

    const mapping = map("a");

    expect(mapping).to.be.an.object();
    expect(mapping.alwaysSet).to.be.true();
    expect(mapping.alwaysTransform).to.be.false();
    expect(mapping.flatten).to.be.null();
    expect(mapping.flattenInverted).to.be.false();

    return done();

  });

  lab.test("sets the flattenInverted option correctly", done => {

    const map = createMapper({ flattenInverted: true });

    const mapping = map("a");

    expect(mapping).to.be.an.object();
    expect(mapping.alwaysSet).to.be.false();
    expect(mapping.alwaysTransform).to.be.false();
    expect(mapping.flatten).to.be.null();
    expect(mapping.flattenInverted).to.be.true();

    return done();

  });

  lab.test("sets the flatten option correctly", done => {

    const map = createMapper({ flatten: true });

    const mapping = map("a");

    expect(mapping).to.be.an.object();
    expect(mapping.alwaysSet).to.be.false();
    expect(mapping.alwaysTransform).to.be.false();
    expect(mapping.flatten).to.be.true();
    expect(mapping.flattenInverted).to.be.false();

    return done();

  });

  lab.test("the existing modifier sets more alwaysSet and alwaysTransform to false", done => {

    const map = createMapper({ alwaysSet: true, alwaysTransform: true });

    const mapping = map("a").existing;

    expect(mapping).to.be.an.object();
    expect(mapping.alwaysSet).to.be.false();
    expect(mapping.alwaysTransform).to.be.false();

    return done();

  });

  lab.test("the always modifier sets more alwaysSet and alwaysTransform to true", done => {

    const map = createMapper({ alwaysSet: false, alwaysTransform: false });

    const mapping = map("a").always;

    expect(mapping).to.be.an.object();
    expect(mapping.alwaysSet).to.be.true();
    expect(mapping.alwaysTransform).to.be.true();

    return done();

  });

});

group("when executing with options set, the single source mapper", () => {

  lab.test("suppresses a transform when the source value is not present", done => {

    const source = {
      "my": {
        "source": {
          "is": {}
        }
      }
    };

    const expected = {
      "your": {
        "source": {
          "is": {}
        }
      }
    };

    const map = createMapper({ alwaysTransform: false, alwaysSet: true });

    map("my.source.is.missing").to("your.source.is.missing", () => {
      return "found";
    });

    const actual = map.execute(source);

    expect(actual).to.equal(expected);

    return done();

  });

  lab.test("suppresses a set when the source value is not present", done => {

    const source = {
      "my": {
        "source": {
          "is": {}
        }
      }
    };

    const expected = {
    };

    const map = createMapper({ alwaysTransform: false, alwaysSet: false });
    let count = 0;

    map("my.source.is.missing").to("your.source.is.missing", () => {
      count++;
      return "found";
    });

    const actual = map.execute(source);

    expect(actual).to.equal(expected);
    expect(count).to.equal(0);

    return done();

  });

  lab.test("a set is not supressed when the source value is not present if a transform returns a value", done => {

    const source = {
      "my": {
        "source": {
          "is": {}
        }
      }
    };

    const expected = {
      "your": {
        "source": {
          "is": {
            "missing": "found"
          }
        }
      }
    };

    const map = createMapper({ alwaysTransform: true, alwaysSet: false });

    map("my.source.is.missing").to("your.source.is.missing", () => {
      return "found";
    });

    const actual = map.execute(source);

    expect(actual).to.equal(expected);

    return done();

  });

  lab.test("if a transform returns undefined a set will be called", done => {

    const source = {
      "my": {
        "source": {
          "is": {}
        }
      }
    };

    const expected = {
      "your": {
        "source": {
          "is": {}
        }
      }
    };

    const map = createMapper({ alwaysTransform: true, alwaysSet: true });

    map("my.source.is.missing").to("your.source.is.missing", () => {
      return undefined;
    });

    const actual = map.execute(source);

    expect(actual).to.equal(expected);

    return done();

  });

  lab.test("if source value is false set will be called", done => {

    const source = {
      "my": {
        "source": {
          "is": {
            "missing": false
          }
        }
      }
    };

    const expected = {
      "your": {
        "source": {
          "is": {
            "missing": false
          }
        }
      }
    };

    const map = createMapper({ alwaysTransform: false, alwaysSet: false });

    map("my.source.is.missing").to("your.source.is.missing");

    const actual = map.execute(source);

    expect(actual).to.equal(expected);

    return done();

  });

});

group("when executing with options set, the multi source mapper", () => {

  lab.test("suppresses a transform when the source values are all not present", done => {

    const source = {
      "my": {
        "source": {
          "is": {}
        },
        "other": {
          "source": {
            "is": {}
          }
        }
      }
    };

    const expected = {
      "your": {
        "source": {
          "is": {}
        }
      }
    };

    const map = createMapper({ alwaysTransform: false, alwaysSet: true });

    map(["my.source.is.missing", "my.other.source.is.missing"]).to("your.source.is.missing", () => {
      return "found";
    });

    const actual = map.execute(source);

    expect(actual).to.equal(expected);

    return done();

  });

  lab.test("suppresses a set if a transform returns null", done => {

    const source = {
      "my": {
        "source": {
          "is": {}
        },
        "other": {
          "source": {
            "is": {
              "here": "value"
            }
          }
        }
      }
    };

    const expected = {
    };

    const map = createMapper({ alwaysTransform: false, alwaysSet: false });
    let count = 0;

    map(["my.source.is.missing", "my.other.source.is.here"]).to("your.source.is.missing", () => {
      count++;
      return null;
    });

    const actual = map.execute(source);

    expect(actual).to.equal(expected);
    expect(count).to.equal(1);

    return done();

  });

  lab.test("suppresses a set if a transform returns undefined", done => {

    const source = {
      "my": {
        "source": {
          "is": {}
        },
        "other": {
          "source": {
            "is": {
              "here": "value"
            }
          }
        }
      }
    };

    const expected = {
    };

    const map = createMapper({ alwaysTransform: false, alwaysSet: false });

    let count = 0;

    map(["my.source.is.missing", "my.other.source.is.here"]).to("your.source.is.missing", () => {
      count++;
      return undefined;
    });

    const actual = map.execute(source);

    expect(actual).to.equal(expected);
    expect(count).to.equal(1);

    return done();

  });

  lab.test("a transform executes when one source value is present", done => {

    const source = {
      "my": {
        "source": {
          "is": {
            "here": "value"
          }
        },
        "other": {
          "source": {
            "is": {}
          }
        }
      }
    };

    const expected = {
      "your": {
        "source": {
          "is": {
            "here": "found"
          }
        }
      }
    };

    const map = createMapper({ alwaysTransform: false, alwaysSet: true });

    map(["my.source.is.here", "my.other.source.is.missing"]).to("your.source.is.here", () => {
      return "found";
    });

    const actual = map.execute(source);

    expect(actual).to.equal(expected);

    return done();

  });
});

group("when executing with options set, the or-mode source map", () => {

  lab.test("a transform executes when no sources are present but alwaysTransform is true", done => {

    const source = {
      "my": {
        "source": {
          "is": {}
        },
        "other": {
          "source": {
            "is": {}
          }
        }
      }
    };

    const expected = {
      "your": {
        "source": {
          "is": {
            "here": "found"
          }
        }
      }
    };

    const map = createMapper({ alwaysTransform: true, alwaysSet: false });

    map("my.source.is.here").or("my.other.source.is.missing").to("your.source.is.here", () => {
      return "found";
    });

    const actual = map.execute(source);

    expect(actual).to.equal(expected);

    return done();

  });

  lab.test("a transform does not execute when no sources are present and alwaysTransform is false", done => {
    const source = {
      "my": {
        "source": {
          "is": {}
        },
        "other": {
          "source": {
            "is": {}
          }
        }
      }
    };

    const expected = {};

    const map = createMapper({ alwaysTransform: false, alwaysSet: false });

    map("my.source.is.here").or("my.other.source.is.missing").to("your.source.is.here", () => {
      return "whoops";
    });

    const actual = map.execute(source);

    expect(actual).to.equal(expected);

    return done();

  });

  lab.test("no set is called when no values are present and alwaysSet is false", done => {

    const source = {
      "my": {
        "source": {
          "is": {}
        },
        "other": {
          "source": {
            "is": {}
          }
        }
      }
    };

    const expected = {};

    const map = createMapper({ alwaysTransform: false, alwaysSet: false });

    map("my.source.is.here").or("my.other.source.is.missing").to("your.source.is.here");

    const actual = map.execute(source);

    expect(actual).to.equal(expected);

    return done();

  });

  lab.test("set is called when no values are present but alwaysSet is true", done => {

    const source = {
      "my": {
        "source": {
          "is": {}
        },
        "other": {
          "source": {
            "is": {}
          }
        }
      }
    };

    const expected = {
      "your": {
        "source": {
          "is": {}
        }
      }
    };
    const map = createMapper({ alwaysTransform: false, alwaysSet: true });

    map("my.source.is.here").or("my.other.source.is.missing").to("your.source.is.here");

    const actual = map.execute(source);

    expect(actual).to.equal(expected);

    return done();

  });

});

group("the always modifier", () => {

  alwaysSuite.run(lab, { OPTIONS: null });
  alwaysSuite.run(lab, {});
  alwaysSuite.run(lab, { OPTIONS: { alwaysTransform: false, alwaysSet: false } });
  alwaysSuite.run(lab, { OPTIONS: { alwaysTransform: false, alwaysSet: true } });
  alwaysSuite.run(lab, { OPTIONS: { alwaysTransform: true, alwaysSet: false } });
  alwaysSuite.run(lab, { OPTIONS: { alwaysTransform: false, alwaysSet: true } });

});

group("the existing modifier", () => {

  existingSuite.run(lab, { OPTIONS: null });
  existingSuite.run(lab, {});
  existingSuite.run(lab, { OPTIONS: { alwaysTransform: false, alwaysSet: false } });
  existingSuite.run(lab, { OPTIONS: { alwaysTransform: false, alwaysSet: true } });
  existingSuite.run(lab, { OPTIONS: { alwaysTransform: true, alwaysSet: false } });
  existingSuite.run(lab, { OPTIONS: { alwaysTransform: false, alwaysSet: true } });

});

group("the failureTransform as a option for default use", () => {
  lab.test("should use the global failure transformed if its defined and failure transform is not provided as part of the mapping", done => {
    const source = {
      "foo": "name1",
      "bar": "name2",
      "fooNull": null
    };

    const expected = {
      "foo1": "bar",
      "foo2": "bar",
      "foo3": "from global",
      "fooOr": "from global",
      "foo4": "from global",
      "foo5": "from global",
      "fooNull": "foo"
    };

    const mapper = createMapper({ failureTransform: val => val === null ? "foo" : "from global"});

    mapper
      .map("foo1").to("foo1", null, "bar")
      .map("foo2").to("foo2", null, () => "bar")
      .map("foo2").to("foo5")
      .map(["foo1", "foo2"]).to("foo3", () => "check")
      .map("foo1").or("foo2").to("fooOr")
      .map("foo4").always.to("foo4")
      .map("fooNull").to("fooNull");

    const actual = mapper.execute(source);

    expect(actual).to.equal(expected);

    return done();
  });
});
<|endoftext|>