<commit_before>var should = require('should');
var rest = require('restler');
var async = require('async');
var config = require('./config.js');
var redis = require("redis"),rc = redis.createClient(6379,'localhost');

var host = config.hostname;
var port = config.port;
var protocol = config.protocol;

var trans, trans1 = {};

describe('Inbox', function () {
  "use strict";

  function onError(err, response){
    console.log('error form restler');
    console.dir(err);
    console.log('error form PopBox');
    console.dir(response);
    throw new Error({'err': err, 'response': response});
  }

    after(function (done) {
        this.timeout(8000);
        rc.flushall();
        rc.end();
        done();
    });
    beforeEach(function (done) {
        this.timeout(8000);
        rc.flushall();
        done();
    });

    it('Should return all the transactions', function (done) {
        this.timeout(8000); //Mocha timeout
        var trans = {
            'payload': 'Test',
            'priority': 'H',
            'callback': protocol + '://foo.bar',
            'queue': [
                { 'id': 'q1' },
                { 'id': 'q2' }
            ]
        };

        async.series([
            function (callback) {

                rest.postJson(protocol + '://' + host + ':' + port + '/trans',
                    trans).on('success', function (data, response) {
                        callback();
                    }).on('error', onError);

            },
            function (callback) {

                trans.payload='Test 2';
                rest.postJson(protocol + '://' + host + ':' + port + '/trans',
                    trans).on('success', function (data, response) {
                        callback();
                    }).on('error', onError);

            },
            function (callback) {

                var checkQueue = function (queue, callback) {
                    rest.post(protocol + '://' + host + ':' + port + '/queue/' + queue + '/pop')
                        .on('success', function (data, response) {
                            data.should.not.have.property('error');
                            data.should.have.property('ok');
                            data.should.have.property('data');
                            data.data.length.should.be.equal(2);
                            data.data.should.include('Test');
                            data.data.should.include('Test 2');
                            callback();
                        }).on('error', onError);
                };

                checkQueue('q1', checkQueue.bind({}, 'q2', callback));
            }
        ], function () {
            done();
        });
    });

    it('Should return the high priority transaction', function (done) {

        var transLow = {
            'payload': 'Low priority',
            'priority': 'L',
            'callback': protocol + '://foo.bar',
            'queue': [
                { 'id': 'q1' },
                { 'id': 'q2' }
            ]
        };

        var transHigh = {
            'payload': 'High priority',
            'priority': 'H',
            'callback': protocol + '://foo.bar',
            'queue': [
                { 'id': 'q1' }
            ]
        };

        async.series([
            function (callback) {
                rest.postJson(protocol + '://' + host + ':' + port + '/trans',
                    transLow).on('success', function (data, response) {
                        callback();
                    }).on('error', onError);
            },
            function (callback) {
                rest.postJson(protocol + '://' + host + ':' + port + '/trans',
                    transHigh).on('success', function (data, response) {
                        callback();
                    }).on('error', onError);
            },
            function (callback) {
                rest.post(protocol + '://' + host + ':' + port + '/queue/q1/pop?max=1')
                    .on('success', function (data, response) {
                    data.should.not.have.property('error');
                    data.should.have.property('ok');
                    data.should.have.property('data');
                    data.data.length.should.be.equal(1);
                        (data.data.pop()).should.be.equal('High priority');
                        callback();
                    }).on('error', onError);
            }
        ], function () {
            done();
        });
    });

    it('Should return empty data (timeout)', function (done) {
        this.timeout(8000); //Mocha timeout

        var trans5 = {
            'payload': 'Test timeout - empty data',
            'priority': 'L',
            'callback': protocol + '://foo.bar',
            'queue': [
                { 'id': 'q1' }
            ]
        };

        var funcs = [
            function (cb) {
                rest.post(protocol + '://' + host + ':' + port + '/queue/q1/pop?timeout=1',
                    {headers: {'Accept': 'application/json'}})
                    .on('success', function (data, response) {
                        //console.log(data);
                       data.should.not.have.property('error');
                       data.should.have.property('ok');
                       data.should.have.property('data');
                       data.data.length.should.be.equal(0);
                        cb();
                    }).on('error', onError);
            },
            function (cb) {
                setTimeout(function () {
                    rest.postJson(protocol + '://' + host + ':' + port + '/trans',
                        trans5).on('success', function (data, response) {
                            cb();
                        }).on('error', onError);
                }, 1500);

            }
        ];

        var cb = function () {
            done();
        };

        async.parallel(funcs, cb);
    });

    it('Should not return empty data (timeout)', function (done) {
        this.timeout(8000); //Mocha timeout
        var trans6 = {
            'payload': 'Test timeout - NOT empty data',
            'priority': 'L',
            'callback': protocol + '://foo.bar',
            'queue': [
                { 'id': 'q1' }
            ]
        };

        var funcs = [
            function (cb) {
                rest.post(protocol + '://' + host + ':' + port + '/queue/q1/pop?timeout=3',
                    {headers: {'Accept': 'application/json'}})
                    .on('success', function (data, response) {
                        data.should.not.have.property('error');
                        data.should.have.property('ok');
                        data.should.have.property('data');
                        data.data.length.should.be.equal(1);
                        data.data.should.include('Test timeout - NOT empty data');
                        cb();
                    }).on('error', onError);
            },
            function (cb) {
                setTimeout(function () {
                    rest.postJson(protocol + '://' + host + ':' + port + '/trans',
                        trans6).on('success', function (data, response) {
                            cb();
                        }).on('error', onError);
                }, 1000);

            }
        ];

        var cb = function () {
            done();
        };

        async.parallel(funcs, cb);
    });

});
<commit_msg>fix testing in travis<commit_after>var should = require('should');
var rest = require('restler');
var async = require('async');
var config = require('./config.js');
var redis = require("redis"),rc = redis.createClient(6379,'localhost');

var host = config.hostname;
var port = config.port;
var protocol = config.protocol;

var trans, trans1 = {};

describe('Inbox', function () {
  "use strict";

  function onError(err, response){
    console.log('error form restler');
    console.dir(err);
    console.log('error form PopBox');
    console.dir(response);
    throw new Error({'err': err, 'response': response});
  }

    after(function (done) {
        this.timeout(8000);
        rc.flushall();
        rc.end();
        done();
    });
    beforeEach(function (done) {
        this.timeout(8000);
        rc.flushall();
        done();
    });

    it('Should return all the transactions', function (done) {
        this.timeout(8000); //Mocha timeout
        var trans = {
            'payload': 'Test',
            'priority': 'H',
            'callback': protocol + '://foo.bar',
            'queue': [
                { 'id': 'q1' },
                { 'id': 'q2' }
            ]
        };

        async.series([
            function (callback) {

                rest.postJson(protocol + '://' + host + ':' + port + '/trans',
                    trans).on('success', function (data, response) {
                        callback();
                    }).on('error', onError);

            },
            function (callback) {

                trans.payload='Test 2';
                rest.postJson(protocol + '://' + host + ':' + port + '/trans',
                    trans).on('success', function (data, response) {
                        callback();
                    }).on('error', onError);

            },
            function (callback) {

                var checkQueue = function (queue, callback) {
                    rest.post(protocol + '://' + host + ':' + port + '/queue/' + queue + '/pop')
                        .on('success', function (data, response) {
                            data.should.not.have.property('error');
                            data.should.have.property('ok');
                            data.should.have.property('data');
                            data.data.length.should.be.equal(2);
                            data.data.should.include('Test');
                            data.data.should.include('Test 2');
                            callback();
                        }).on('error', onError);
                };

                checkQueue('q1', checkQueue.bind({}, 'q2', callback));
            }
        ], function () {
            done();
        });
    });

    it('Should return the high priority transaction', function (done) {

        var transLow = {
            'payload': 'Low priority',
            'priority': 'L',
            'callback': protocol + '://foo.bar',
            'queue': [
                { 'id': 'q1' },
                { 'id': 'q2' }
            ]
        };

        var transHigh = {
            'payload': 'High priority',
            'priority': 'H',
            'callback': protocol + '://foo.bar',
            'queue': [
                { 'id': 'q1' }
            ]
        };

        async.series([
            function (callback) {
                rest.postJson(protocol + '://' + host + ':' + port + '/trans',
                    transLow).on('success', function (data, response) {
                        callback();
                    }).on('error', onError);
            },
            function (callback) {
                rest.postJson(protocol + '://' + host + ':' + port + '/trans',
                    transHigh).on('success', function (data, response) {
                        callback();
                    }).on('error', onError);
            },
            function (callback) {
                rest.post(protocol + '://' + host + ':' + port + '/queue/q1/pop?max=1')
                    .on('success', function (data, response) {
                    data.should.not.have.property('error');
                    data.should.have.property('ok');
                    data.should.have.property('data');
                    data.data.length.should.be.equal(1);
                        (data.data.pop()).should.be.equal('High priority');
                        callback();
                    }).on('error', onError);
            }
        ], function () {
            done();
        });
    });

    it('Should return empty data (timeout)', function (done) {
        this.timeout(8000); //Mocha timeout

        var trans5 = {
            'payload': 'Test timeout - empty data',
            'priority': 'L',
            'callback': protocol + '://foo.bar',
            'queue': [
                { 'id': 'q1' }
            ]
        };

        var funcs = [
            function (cb) {
                rest.post(protocol + '://' + host + ':' + port + '/queue/q1/pop?timeout=1',
                    {headers: {'Accept': 'application/json'}})
                    .on('success', function (data, response) {
                        //console.log(data);
                       data.should.not.have.property('error');
                       data.should.have.property('ok');
                       data.should.have.property('data');
                       data.data.length.should.be.equal(0);
                        cb();
                    }).on('error', onError);
            },
            function (cb) {
                setTimeout(function () {
                    rest.postJson(protocol + '://' + host + ':' + port + '/trans',
                        trans5).on('success', function (data, response) {
                            cb();
                        }).on('error', onError);
                }, 4000);

            }
        ];

        var cb = function () {
            done();
        };

        async.parallel(funcs, cb);
    });

    it('Should not return empty data (timeout)', function (done) {
        this.timeout(8000); //Mocha timeout
        var trans6 = {
            'payload': 'Test timeout - NOT empty data',
            'priority': 'L',
            'callback': protocol + '://foo.bar',
            'queue': [
                { 'id': 'q1' }
            ]
        };

        var funcs = [
            function (cb) {
                rest.post(protocol + '://' + host + ':' + port + '/queue/q1/pop?timeout=3',
                    {headers: {'Accept': 'application/json'}})
                    .on('success', function (data, response) {
                        data.should.not.have.property('error');
                        data.should.have.property('ok');
                        data.should.have.property('data');
                        data.data.length.should.be.equal(1);
                        data.data.should.include('Test timeout - NOT empty data');
                        cb();
                    }).on('error', onError);
            },
            function (cb) {
                setTimeout(function () {
                    rest.postJson(protocol + '://' + host + ':' + port + '/trans',
                        trans6).on('success', function (data, response) {
                            cb();
                        }).on('error', onError);
                }, 1000);

            }
        ];

        var cb = function () {
            done();
        };

        async.parallel(funcs, cb);
    });

});
<|endoftext|>


<commit_before>var path = require('path');

function TestRepoHelper() {
  var testRepoDir;
  var self = this;

  this.setupTestRepo = function(repoName, callback) {
    this.createTmpDir();

    var ncp = require('ncp').ncp;

    // Copy test repo to tmp dir
    ncp(path.join(__dirname, 'repos', repoName), self.testRepoDir.path, function(err) {
      if(err) throw err;

      callback(self.testRepoDir.path);
    });
  };

  this.setupAllTestRepos = function(callback) {
    this.createTmpDir();

    var ncp = require('ncp').ncp;

    // Copy all test repos to tmp dir
    ncp(path.join(__dirname, 'repos'), self.testRepoDir.path, function(err) {
      if(err) throw err;

      callback(self.testRepoDir.path);
    });
  }

  this.createTmpDir = function() {
    var temporary = require('temporary');
    self.testRepoDir = new temporary.Dir();
    console.log(self.testRepoDir.path);
  }

  this.cleanup = function() {
    this.testRepoDir.rmdir();
  }
}

module.exports = TestRepoHelper;<commit_msg>Added constructor that sets up tmp dir<commit_after>var path = require('path');
var ncp = require('ncp').ncp;

function TestRepoHelper() {
  var testRepoDir;
  var self = this;

  this.setupTestRepo = function(repoName, callback) {
    // Copy test repo to tmp dir
    ncp(path.join(__dirname, 'repos', repoName), self.testRepoDir.path, function(err) {
      if(err) throw err;

      callback(self.testRepoDir.path);
    });
  };

  this.setupAllTestRepos = function(callback) {
    // Copy all test repos to tmp dir
    ncp(path.join(__dirname, 'repos'), self.testRepoDir.path, function(err) {
      if(err) throw err;

      callback(self.testRepoDir.path);
    });
  }

  this.createTmpDir = function() {
    var temporary = require('temporary');
    self.testRepoDir = new temporary.Dir();
    console.log(self.testRepoDir.path);
  }

  this.cleanup = function() {
    this.testRepoDir.rmdir();
  }

  var __construct = function() {
    self.createTmpDir();
  }()
}

module.exports = TestRepoHelper;<|endoftext|>


<commit_before>/*=============================================================================
 * Orange - Auto Avoid Obstacles Diagonally
 * By Hudell - www.hudell.com
 * OrangeAutoAvoidObstaclesDiagonally.js
 * Version: 1.0
 * Free for commercial and non commercial use.
 *=============================================================================
 * @plugindesc Makes the player automatically Avoid small obstacles, by diagonally
 *
 * @param AvoidEvents
 * @desc Set this to false if you don't want the player to avoid events
 * Default: true
 * @default true
 *
 * @param OnlyWhenDashing
 * @desc Set this to true to only avoid obstacles when the player is dashing
 * Default: false
 * @default false
 *
 * @param DashingDelay
 * @desc Makes the character wait a little before trying to avoid an obstacle
 *       when dashing. Set this to the number of frames the character should wait
 * Default: 0
 * @default 0
 *
 * @param WalkingDelay
 * @desc Makes the character wait a little before trying to avoid an obstacle
 *       when walking. Set this to the number of frames the character should wait
 * Default: 0
 * @default 0
 *
 * @author Hudell
 *
 *=============================================================================*/

var Imported = Imported || {};
if (Imported['MVCommons'] === undefined) {
  console.log('Download MVCommons: http://link.hudell.com/mvcommons');
  throw new Error("This library needs MVCommons to work properly!");
}

if (Imported['SuperOrangeMovement'] === undefined) {
  console.log('Download SuperOrangeMovement: http://link.hudell.com/super-orange-movement');
  throw new Error("This library needs SuperOrangeMovement to work properly!");
}

var OrangeAutoAvoidObstaclesDiagonally = OrangeAutoAvoidObstaclesDiagonally || {};

(function($) {
  "use strict";

  $.Parameters = PluginManager.parameters('OrangeAutoAvoidObstaclesDiagonally');
  $.Param = $.Param || {};

  $.Param.AvoidEvents = $.Param["AvoidEvents"] !== "false";
  $.Param.OnlyWhenDashing = $.Param["OnlyWhenDashing"] === "true";
  $.Param.DashingDelay = Number($.Param["DashingDelay"] || 0);
  $.Param.WalkingDelay = Number($.Param["WalkingDelay"] || 0);

  var avoidObstaclesDelay = 0;

  // Every time the player succesfully moves, reset the delay
  var oldGamePlayer_onBeforeMove = Game_Player.prototype.onBeforeMove;
  Game_Player.prototype.onBeforeMove = function() {
    if (this.isDashing()) {
      avoidObstaclesDelay = $.Param.DashingDelay;
    }
    else {
      avoidObstaclesDelay = $.Param.WalkingDelay;
    }

    if (oldGamePlayer_onBeforeMove !== undefined) {
      oldGamePlayer_onBeforeMove.call(this);
    }
  };

  var oldGamePlayer_trySavingFailedMovement = Game_Player.prototype.trySavingFailedMovement;
  Game_Player.prototype.trySavingFailedMovement = function(direction) {
    if (oldGamePlayer_trySavingFailedMovement !== undefined) {
      if (oldGamePlayer_trySavingFailedMovement.call(this, direction)) {
        return true;
      }
    }

    if (avoidObstaclesDelay > 0) {
      avoidObstaclesDelay--;
    }

    if ($.Param.OnlyWhenDashing === true) {
      if (!this.isDashing()) {
        return false;
      }
    }

    if ($.Param.AvoidEvents !== true) {
      if (this.isTilesetPassable(this._x, this._y, direction)) {
        var x2 = $gameMap.roundFractionXWithDirection(this._x, direction, this.myStepSize());
        var y2 = $gameMap.roundFractionYWithDirection(this._y, direction, this.myStepSize());

        if (this.isCollidedWithCharacters(x2, y2)) {
          return false;
        }
      }
    }

    if (this.tryToAvoid(direction)) {
      return true;
    }

    return false;
  };

  Game_Player.prototype.tryToAvoid = function(direction) {
    if (avoidObstaclesDelay > 0) {
      return false;
    }

    if (direction == Direction.LEFT || direction == Direction.RIGHT) {
      if (this.canPassDiagonally(this._x, this._y, direction, Direction.DOWN)) {
        this.executeMove(direction - 3);
        return true;
      }
      else if (this.canPassDiagonally(this._x, this._y, direction, Direction.UP)) {
        this.executeMove(direction + 3);
        return true;
      }
    }
    else if (direction == Direction.UP || direction == Direction.DOWN) {
      if (this.canPassDiagonally(this._x, this._y, Direction.LEFT, direction)) {
        this.executeMove(direction - 1);
        return true;
      }
      else if (this.canPassDiagonally(this._x, this._y, Direction.RIGHT, direction)) {
        this.executeMove(direction + 1);
        return true;
      }
    }

    return false;
  };

})(OrangeAutoAvoidObstaclesDiagonally);

PluginManager.register("OrangeAutoAvoidObstaclesDiagonally", "1.0.0", "Will make the player avoid small obstacles automatically by walking diagonally around them", {
  email: "plugins@hudell.com",
  name: "Hudell",
  website: "http://www.hudell.com"
}, "2015-10-21");
<commit_msg>Update OrangeAutoAvoidObstaclesDiagonally.js<commit_after>/*=============================================================================
 * Orange - Auto Avoid Obstacles Diagonally
 * By Hudell - www.hudell.com
 * OrangeAutoAvoidObstaclesDiagonally.js
 * Version: 1.0
 * Free for commercial and non commercial use.
 *=============================================================================
 * @plugindesc Makes the player automatically Avoid small obstacles, by diagonally
 *
 * @param AvoidEvents
 * @desc Set this to false if you don't want the player to avoid events
 * Default: true
 * @default true
 *
 * @param OnlyWhenDashing
 * @desc Set this to true to only avoid obstacles when the player is dashing
 * Default: false
 * @default false
 *
 * @param DashingDelay
 * @desc Makes the character wait a little before trying to avoid an obstacle
 *       when dashing. Set this to the number of frames the character should wait
 * Default: 0
 * @default 0
 *
 * @param WalkingDelay
 * @desc Makes the character wait a little before trying to avoid an obstacle
 *       when walking. Set this to the number of frames the character should wait
 * Default: 0
 * @default 0
 *
 * @author Hudell
 *
 *
 * @help
 * ============================================================================
 * Latest Version
 * ============================================================================
 *
 * Get the latest version of this script on http://link.hudell.com/auto-avoid-diagonal
 *
 *=============================================================================*/

var Imported = Imported || {};
if (Imported['MVCommons'] === undefined) {
  console.log('Download MVCommons: http://link.hudell.com/mvcommons');
  throw new Error("This library needs MVCommons to work properly!");
}

if (Imported['SuperOrangeMovement'] === undefined) {
  console.log('Download SuperOrangeMovement: http://link.hudell.com/super-orange-movement');
  throw new Error("This library needs SuperOrangeMovement to work properly!");
}

var OrangeAutoAvoidObstaclesDiagonally = OrangeAutoAvoidObstaclesDiagonally || {};

(function($) {
  "use strict";

  $.Parameters = PluginManager.parameters('OrangeAutoAvoidObstaclesDiagonally');
  $.Param = $.Param || {};

  $.Param.AvoidEvents = $.Param["AvoidEvents"] !== "false";
  $.Param.OnlyWhenDashing = $.Param["OnlyWhenDashing"] === "true";
  $.Param.DashingDelay = Number($.Param["DashingDelay"] || 0);
  $.Param.WalkingDelay = Number($.Param["WalkingDelay"] || 0);

  var avoidObstaclesDelay = 0;

  // Every time the player succesfully moves, reset the delay
  var oldGamePlayer_onBeforeMove = Game_Player.prototype.onBeforeMove;
  Game_Player.prototype.onBeforeMove = function() {
    if (this.isDashing()) {
      avoidObstaclesDelay = $.Param.DashingDelay;
    }
    else {
      avoidObstaclesDelay = $.Param.WalkingDelay;
    }

    if (oldGamePlayer_onBeforeMove !== undefined) {
      oldGamePlayer_onBeforeMove.call(this);
    }
  };

  var oldGamePlayer_trySavingFailedMovement = Game_Player.prototype.trySavingFailedMovement;
  Game_Player.prototype.trySavingFailedMovement = function(direction) {
    if (oldGamePlayer_trySavingFailedMovement !== undefined) {
      if (oldGamePlayer_trySavingFailedMovement.call(this, direction)) {
        return true;
      }
    }

    if (avoidObstaclesDelay > 0) {
      avoidObstaclesDelay--;
    }

    if ($.Param.OnlyWhenDashing === true) {
      if (!this.isDashing()) {
        return false;
      }
    }

    if ($.Param.AvoidEvents !== true) {
      if (this.isTilesetPassable(this._x, this._y, direction)) {
        var x2 = $gameMap.roundFractionXWithDirection(this._x, direction, this.myStepSize());
        var y2 = $gameMap.roundFractionYWithDirection(this._y, direction, this.myStepSize());

        if (this.isCollidedWithCharacters(x2, y2)) {
          return false;
        }
      }
    }

    if (this.tryToAvoid(direction)) {
      return true;
    }

    return false;
  };

  Game_Player.prototype.tryToAvoid = function(direction) {
    if (avoidObstaclesDelay > 0) {
      return false;
    }

    if (direction == Direction.LEFT || direction == Direction.RIGHT) {
      if (this.canPassDiagonally(this._x, this._y, direction, Direction.DOWN)) {
        this.executeMove(direction - 3);
        return true;
      }
      else if (this.canPassDiagonally(this._x, this._y, direction, Direction.UP)) {
        this.executeMove(direction + 3);
        return true;
      }
    }
    else if (direction == Direction.UP || direction == Direction.DOWN) {
      if (this.canPassDiagonally(this._x, this._y, Direction.LEFT, direction)) {
        this.executeMove(direction - 1);
        return true;
      }
      else if (this.canPassDiagonally(this._x, this._y, Direction.RIGHT, direction)) {
        this.executeMove(direction + 1);
        return true;
      }
    }

    return false;
  };

})(OrangeAutoAvoidObstaclesDiagonally);

PluginManager.register("OrangeAutoAvoidObstaclesDiagonally", "1.0.0", "Will make the player avoid small obstacles automatically by walking diagonally around them", {
  email: "plugins@hudell.com",
  name: "Hudell",
  website: "http://www.hudell.com"
}, "2015-10-21");
<|endoftext|>


<commit_before>import NativePromise from 'native-promise-only';
import _ from 'lodash';
import Webform from './Webform';
import Component from './components/_classes/component/Component';
import Formio from './Formio';
import { checkCondition, firstNonNil } from './utils/utils';

export default class Wizard extends Webform {
  /**
   * Constructor for wizard based forms
   * @param element Dom element to place this wizard.
   * @param {Object} options Options object, supported options are:
   *    - breadcrumbSettings.clickable: true (default) determines if the breadcrumb bar is clickable or not
   *    - buttonSettings.show*(Previous, Next, Cancel): true (default) determines if the button is shown or not
   */
  constructor() {
    let element, options;
    if (arguments[0] instanceof HTMLElement || arguments[1]) {
      element = arguments[0];
      options = arguments[1];
    }
    else {
      options = arguments[0];
    }
    super(element, options);
    this.panels = [];
    this.pages = [];
    this.globalComponents = [];
    this.components = [];
    this.page = 0;
    this.currentNextPage = 0;
    this._seenPages = [0];
  }

  isLastPage() {
    const next = this.getNextPage();

    if (_.isNumber(next)) {
      return 0 < next && next >= this.pages.length;
    }

    return _.isNull(next);
  }

  getPages(args = {}) {
    const { all = false } = args;
    const pageOptions = _.clone(this.options);
    const components = _.clone(this.components);
    const pages = this.pages
          .filter(all ? _.identity : (p, index) => this._seenPages.includes(index))
          .map((page, index) => this.createComponent(
            page,
            _.assign(pageOptions, { components: index === this.page ? components : null })
          ));

    this.components = components;

    return pages;
  }

  getComponents() {
    return this.submitting
      ? this.getPages({ all: this.isLastPage() })
      : super.getComponents();
  }

  resetValue() {
    this.getPages({ all: true }).forEach((page) => page.resetValue());
    this.setPristine(true);
  }

  init() {
    // Check for and initlize button settings object
    this.options.buttonSettings = _.defaults(this.options.buttonSettings, {
      showPrevious: true,
      showNext: true,
      showSubmit: true,
      showCancel: !this.options.readOnly
    });

    this.options.breadcrumbSettings = _.defaults(this.options.breadcrumbSettings, {
      clickable: true
    });

    this.page = 0;
    return super.init();
  }

  get wizardKey() {
    return `wizard-${this.key}`;
  }

  get form() {
    return this.wizard;
  }

  set form(value) {
    super.form = value;
  }

  get buttons() {
    const buttons = {};
    ['cancel', 'previous', 'next', 'submit'].forEach((button) => {
      if (this.hasButton(button)) {
        buttons[button] = true;
      }
    });
    return buttons;
  }

  render() {
    return this.renderTemplate('wizard', {
      wizardKey: this.wizardKey,
      panels: this.panels,
      buttons: this.buttons,
      currentPage: this.page,
      components: this.renderComponents([...this.globalComponents, ...this.pages[this.page]]),
    }, this.builderMode ? 'builder' : 'form');
  }

  attach(element) {
    this.element = element;
    this.loadRefs(element, {
      [this.wizardKey]: 'single',
      [`${this.wizardKey}-cancel`]: 'single',
      [`${this.wizardKey}-previous`]: 'single',
      [`${this.wizardKey}-next`]: 'single',
      [`${this.wizardKey}-submit`]: 'single',
      [`${this.wizardKey}-link`]: 'multiple',
    });

    const promises = this.attachComponents(this.refs[this.wizardKey], [...this.globalComponents, ...this.pages[this.page]]);

    [
      { name: 'cancel',    method: 'cancel' },
      { name: 'previous',  method: 'prevPage' },
      { name: 'next',      method: 'nextPage' },
      { name: 'submit',    method: 'submit' }
    ].forEach((button) => {
      const buttonElement = this.refs[`${this.wizardKey}-${button.name}`];
      if (!buttonElement) {
        return;
      }
      this.addEventListener(buttonElement, 'click', (event) => {
        event.preventDefault();

        // Disable the button until done.
        buttonElement.setAttribute('disabled', 'disabled');
        this.setLoading(buttonElement, true);

        // Call the button method, then re-enable the button.
        this[button.method]().then(() => {
          buttonElement.removeAttribute('disabled');
          this.setLoading(buttonElement, false);
        }).catch(() => {
          buttonElement.removeAttribute('disabled');
          this.setLoading(buttonElement, false);
        });
      });
    });

    this.refs[`${this.wizardKey}-link`].forEach((link, index) => {
      this.addEventListener(link, 'click', (event) => {
        this.emit('wizardNavigationClicked', this.pages[index]);
        event.preventDefault();
        this.setPage(index);
      });
    });

    return promises;
  }

  addComponents() {
    this.pages = [];
    this.panels = [];
    _.each(this.component.components, (item) => {
      const pageOptions = _.clone(this.options);
      if (item.type === 'panel') {
        if (checkCondition(item, this.data, this.data, this.component, this)) {
          this.panels.push(item);
          const page = [];
          _.each(item.components, (comp) => {
            const component = this.createComponent(comp, pageOptions);
            component.page = this.page;
            page.push(component);
          });
          this.pages.push(page);
        }
      }
      else if (item.type === 'hidden') {
        const component = this.createComponent(item, pageOptions);
        this.globalComponents.push(component);
      }
    });
  }

  setPage(num) {
    if (num === this.page) {
      return NativePromise.resolve();
    }
    if (!this.wizard.full && num >= 0 && num < this.pages.length) {
      this.page = num;
      this.getNextPage();
      if (!this._seenPages.includes(num)) {
        this._seenPages = this._seenPages.concat(num);
      }
      this.redraw();
      return NativePromise.resolve();
    }
    else if (this.wizard.full || !this.pages.length) {
      this.redraw();
      return NativePromise.resolve();
    }
    return NativePromise.reject('Page not found');
  }

  get currentPage() {
    return (this.pages && (this.pages.length >= this.page)) ? this.pages[this.page] : null;
  }

  getNextPage() {
    const data = this.submission.data;
    const form = this.panels[this.page];
    // Check conditional nextPage
    if (form) {
      const page = this.page + 1;
      if (form.nextPage) {
        const next = this.evaluate(form.nextPage, {
          next: page,
          data,
          page,
          form
        }, 'next');
        if (next === null) {
          this.currentNextPage = null;
          return null;
        }

        const pageNum = parseInt(next, 10);
        if (!isNaN(parseInt(pageNum, 10)) && isFinite(pageNum)) {
          this.currentNextPage = pageNum;
          return pageNum;
        }

        this.currentNextPage = this.getPageIndexByKey(next);
        return this.currentNextPage;
      }

      this.currentNextPage = page;
      return page;
    }

    this.currentNextPage = null;
    return null;
  }

  getPreviousPage() {
    return Math.max(this.page - 1, 0);
  }

  beforeSubmit() {
    return NativePromise.all(this.getPages().map((page) => {
      page.options.beforeSubmit = true;
      return page.beforeSubmit();
    }));
  }

  beforePage(next) {
    return new NativePromise((resolve, reject) => {
      this.hook(next ? 'beforeNext' : 'beforePrev', this.currentPage, this.submission, (err) => {
        if (err) {
          this.showErrors(err, true);
          reject(err);
        }

        const form = this.currentPage;
        if (form) {
          NativePromise.all(form.map((comp) => comp.beforePage(next))).then(resolve).catch(reject);
        }
        else {
          resolve();
        }
      });
    });
  }

  nextPage() {
    // Read-only forms should not worry about validation before going to next page, nor should they submit.
    if (this.options.readOnly) {
      return this.setPage(this.getNextPage()).then(() => {
        this.emit('nextPage', { page: this.page, submission: this.submission });
      });
    }

    // Validate the form, before go to the next page
    if (this.checkCurrentPageValidity(this.submission.data, true)) {
      this.checkData(this.submission.data);
      return this.beforePage(true).then(() => {
        return this.setPage(this.getNextPage()).then(() => {
          this.emit('nextPage', { page: this.page, submission: this.submission });
        });
      });
    }
    else {
      return NativePromise.reject(this.showErrors(null, true));
    }
  }

  prevPage() {
    return this.beforePage().then(() => {
      return this.setPage(this.getPreviousPage()).then(() => {
        this.emit('prevPage', { page: this.page, submission: this.submission });
      });
    });
  }

  cancel(noconfirm) {
    if (super.cancel(noconfirm)) {
      return this.setPage(0);
    }
    else {
      return this.setPage();
    }
  }

  getPageIndexByKey(key) {
    let pageIndex = this.page;
    this.panels.forEach((page, index) => {
      if (page.key === key) {
        pageIndex = index;
        return false;
      }
    });
    return pageIndex;
  }

  checkPageValidity(data, dirty, page) {
    page = page || this.page;

    let check = true;
    this.pages[page].forEach((comp) => {
      check &= comp.checkValidity(data, dirty);
    });
    return check;
  }

  get schema() {
    return this.wizard;
  }

  setForm(form) {
    if (!form) {
      return;
    }
    this.wizard = form;
    this.component.components = form.components || [];

    // Check if there are no panel components.
    if (this.component.components.filter(component => component.type === 'panel').length === 0) {
      this.component.components = [
        {
          type: 'panel',
          title: 'Page 1',
          label: 'Page 1',
          key: 'page1',
          components: this.component.components
        }
      ];
    }
    return super.setForm(form);
  }

  isClickable(page, index) {
    return this.page !== index && firstNonNil([
      _.get(page, 'breadcrumbClickable'),
      this.options.breadcrumbSettings.clickable
    ]);
  }

  hasButton(name, nextPage) {
    const currentPage = this.currentPage;
    if (name === 'previous') {
      const show = firstNonNil([
        _.get(currentPage, 'buttonSettings.previous'),
        this.options.buttonSettings.showPrevious
      ]);
      return (this.page > 0) && show;
    }
    nextPage = (nextPage === undefined) ? this.getNextPage() : nextPage;
    if (name === 'next') {
      const show = firstNonNil([
        _.get(currentPage, 'buttonSettings.next'),
        this.options.buttonSettings.showNext
      ]);
      return (nextPage !== null) && (nextPage < this.pages.length) && show;
    }
    if (name === 'cancel') {
      return firstNonNil([
        _.get(currentPage, 'buttonSettings.cancel'),
        this.options.buttonSettings.showCancel
      ]);
    }
    if (name === 'submit') {
      const show = firstNonNil([
        _.get(currentPage, 'buttonSettings.submit'),
        this.options.buttonSettings.showSubmit
      ]);
      return show && !this.options.readOnly && ((nextPage === null) || (this.page === (this.pages.length - 1)));
    }
    return true;
  }

  pageId(page) {
    if (page.key) {
      // Some panels have the same key....
      return `${page.key}-${page.title}`;
    }
    else if (
      page.components &&
      page.components.length > 0
    ) {
      return this.pageId(page.components[0]);
    }
    else {
      return page.title;
    }
  }

  calculateVisiblePanels() {
    const visible = [];
    _.each(this.wizard.components, (component) => {
      if (component.type === 'panel') {
        // Ensure that this page can be seen.
        if (checkCondition(component, this.data, this.data, this.wizard, this)) {
          visible.push(component);
        }
      }
    });
    return visible;
  }

  onChange(flags, changed) {
    super.onChange(flags, changed);

    // Only rebuild if there is a page visibility change.
    const panels = this.calculateVisiblePanels();
    const currentNextPage = this.currentNextPage;
    const nextPage = this.getNextPage();
    if (
      (nextPage !== currentNextPage) ||
      !_.isEqual(panels.map(panel => panel.key), this.panels.map(panel => panel.key))
    ) {
      // If visible panels changes we need to build this template again.
      this.rebuild();
    }
  }

  rebuild() {
    this.destroyComponents();
    this.addComponents();
    return this.redraw();
  }

  checkCurrentPageValidity(...args) {
    return super.checkValidity(...args);
  }

  checkPagesValidity(pages, ...args) {
    const isValid = Component.prototype.checkValidity.apply(this, args);
    return pages.reduce((check, pageComp) => {
      return pageComp.checkValidity(...args) && check;
    }, isValid);
  }

  checkValidity(data, dirty) {
    if (this.submitting) {
      return this.checkPagesValidity(this.getPages(), data, dirty);
    }
    else {
      return this.checkCurrentPageValidity(data, dirty);
    }
  }

  get errors() {
    if (this.isLastPage()) {
      const pages = this.getPages({ all: true });

      this.checkPagesValidity(pages, this.submission.data, true);

      return pages.reduce((errors, pageComp) => {
        return errors.concat(pageComp.errors || []);
      }, []);
    }

    return super.errors;
  }
}

Wizard.setBaseUrl = Formio.setBaseUrl;
Wizard.setApiUrl = Formio.setApiUrl;
Wizard.setAppUrl = Formio.setAppUrl;
<commit_msg>Add field logic functionality to wizard pages since they are a special case.<commit_after>import NativePromise from 'native-promise-only';
import _ from 'lodash';
import Webform from './Webform';
import Component from './components/_classes/component/Component';
import Formio from './Formio';
import { checkCondition, firstNonNil } from './utils/utils';

export default class Wizard extends Webform {
  /**
   * Constructor for wizard based forms
   * @param element Dom element to place this wizard.
   * @param {Object} options Options object, supported options are:
   *    - breadcrumbSettings.clickable: true (default) determines if the breadcrumb bar is clickable or not
   *    - buttonSettings.show*(Previous, Next, Cancel): true (default) determines if the button is shown or not
   */
  constructor() {
    let element, options;
    if (arguments[0] instanceof HTMLElement || arguments[1]) {
      element = arguments[0];
      options = arguments[1];
    }
    else {
      options = arguments[0];
    }
    super(element, options);
    this.panels = [];
    this.pages = [];
    this.globalComponents = [];
    this.components = [];
    this.page = 0;
    this.currentNextPage = 0;
    this._seenPages = [0];
  }

  isLastPage() {
    const next = this.getNextPage();

    if (_.isNumber(next)) {
      return 0 < next && next >= this.pages.length;
    }

    return _.isNull(next);
  }

  getPages(args = {}) {
    const { all = false } = args;
    const pageOptions = _.clone(this.options);
    const components = _.clone(this.components);
    const pages = this.pages
          .filter(all ? _.identity : (p, index) => this._seenPages.includes(index))
          .map((page, index) => this.createComponent(
            page,
            _.assign(pageOptions, { components: index === this.page ? components : null })
          ));

    this.components = components;

    return pages;
  }

  getComponents() {
    return this.submitting
      ? this.getPages({ all: this.isLastPage() })
      : super.getComponents();
  }

  resetValue() {
    this.getPages({ all: true }).forEach((page) => page.resetValue());
    this.setPristine(true);
  }

  init() {
    // Check for and initlize button settings object
    this.options.buttonSettings = _.defaults(this.options.buttonSettings, {
      showPrevious: true,
      showNext: true,
      showSubmit: true,
      showCancel: !this.options.readOnly
    });

    this.options.breadcrumbSettings = _.defaults(this.options.breadcrumbSettings, {
      clickable: true
    });

    this.page = 0;
    return super.init();
  }

  get wizardKey() {
    return `wizard-${this.key}`;
  }

  get form() {
    return this.wizard;
  }

  set form(value) {
    super.form = value;
  }

  get buttons() {
    const buttons = {};
    ['cancel', 'previous', 'next', 'submit'].forEach((button) => {
      if (this.hasButton(button)) {
        buttons[button] = true;
      }
    });
    return buttons;
  }

  render() {
    return this.renderTemplate('wizard', {
      wizardKey: this.wizardKey,
      panels: this.panels,
      buttons: this.buttons,
      currentPage: this.page,
      components: this.renderComponents([...this.globalComponents, ...this.pages[this.page]]),
    }, this.builderMode ? 'builder' : 'form');
  }

  attach(element) {
    this.element = element;
    this.loadRefs(element, {
      [this.wizardKey]: 'single',
      [`${this.wizardKey}-cancel`]: 'single',
      [`${this.wizardKey}-previous`]: 'single',
      [`${this.wizardKey}-next`]: 'single',
      [`${this.wizardKey}-submit`]: 'single',
      [`${this.wizardKey}-link`]: 'multiple',
    });

    const promises = this.attachComponents(this.refs[this.wizardKey], [...this.globalComponents, ...this.pages[this.page]]);

    [
      { name: 'cancel',    method: 'cancel' },
      { name: 'previous',  method: 'prevPage' },
      { name: 'next',      method: 'nextPage' },
      { name: 'submit',    method: 'submit' }
    ].forEach((button) => {
      const buttonElement = this.refs[`${this.wizardKey}-${button.name}`];
      if (!buttonElement) {
        return;
      }
      this.addEventListener(buttonElement, 'click', (event) => {
        event.preventDefault();

        // Disable the button until done.
        buttonElement.setAttribute('disabled', 'disabled');
        this.setLoading(buttonElement, true);

        // Call the button method, then re-enable the button.
        this[button.method]().then(() => {
          buttonElement.removeAttribute('disabled');
          this.setLoading(buttonElement, false);
        }).catch(() => {
          buttonElement.removeAttribute('disabled');
          this.setLoading(buttonElement, false);
        });
      });
    });

    this.refs[`${this.wizardKey}-link`].forEach((link, index) => {
      this.addEventListener(link, 'click', (event) => {
        this.emit('wizardNavigationClicked', this.pages[index]);
        event.preventDefault();
        this.setPage(index);
      });
    });

    return promises;
  }

  addComponents() {
    this.pages = [];
    this.panels = [];
    _.each(this.component.components, (item) => {
      const pageOptions = _.clone(this.options);
      if (item.type === 'panel') {
        if (checkCondition(item, this.data, this.data, this.component, this)) {
          this.panels.push(item);
          const page = [];
          _.each(item.components, (comp) => {
            const component = this.createComponent(comp, pageOptions);
            component.page = this.page;
            page.push(component);
          });
          this.pages.push(page);
        }
      }
      else if (item.type === 'hidden') {
        const component = this.createComponent(item, pageOptions);
        this.globalComponents.push(component);
      }
    });
  }

  setPage(num) {
    if (num === this.page) {
      return NativePromise.resolve();
    }
    if (!this.wizard.full && num >= 0 && num < this.pages.length) {
      this.page = num;

      // Handle field logic on pages.
      this.component = this.panels[num];
      this.originalComponent = _.cloneDeep(this.component);
      this.fieldLogic(this.data);
      // If disabled changed, be sure to distribute the setting.
      this.disabled = this.shouldDisabled;

      this.getNextPage();
      if (!this._seenPages.includes(num)) {
        this._seenPages = this._seenPages.concat(num);
      }
      this.redraw();
      return NativePromise.resolve();
    }
    else if (this.wizard.full || !this.pages.length) {
      this.redraw();
      return NativePromise.resolve();
    }
    return NativePromise.reject('Page not found');
  }

  get currentPage() {
    return (this.pages && (this.pages.length >= this.page)) ? this.pages[this.page] : null;
  }

  getNextPage() {
    const data = this.submission.data;
    const form = this.panels[this.page];
    // Check conditional nextPage
    if (form) {
      const page = this.page + 1;
      if (form.nextPage) {
        const next = this.evaluate(form.nextPage, {
          next: page,
          data,
          page,
          form
        }, 'next');
        if (next === null) {
          this.currentNextPage = null;
          return null;
        }

        const pageNum = parseInt(next, 10);
        if (!isNaN(parseInt(pageNum, 10)) && isFinite(pageNum)) {
          this.currentNextPage = pageNum;
          return pageNum;
        }

        this.currentNextPage = this.getPageIndexByKey(next);
        return this.currentNextPage;
      }

      this.currentNextPage = page;
      return page;
    }

    this.currentNextPage = null;
    return null;
  }

  getPreviousPage() {
    return Math.max(this.page - 1, 0);
  }

  beforeSubmit() {
    return NativePromise.all(this.getPages().map((page) => {
      page.options.beforeSubmit = true;
      return page.beforeSubmit();
    }));
  }

  beforePage(next) {
    return new NativePromise((resolve, reject) => {
      this.hook(next ? 'beforeNext' : 'beforePrev', this.currentPage, this.submission, (err) => {
        if (err) {
          this.showErrors(err, true);
          reject(err);
        }

        const form = this.currentPage;
        if (form) {
          NativePromise.all(form.map((comp) => comp.beforePage(next))).then(resolve).catch(reject);
        }
        else {
          resolve();
        }
      });
    });
  }

  nextPage() {
    // Read-only forms should not worry about validation before going to next page, nor should they submit.
    if (this.options.readOnly) {
      return this.setPage(this.getNextPage()).then(() => {
        this.emit('nextPage', { page: this.page, submission: this.submission });
      });
    }

    // Validate the form, before go to the next page
    if (this.checkCurrentPageValidity(this.submission.data, true)) {
      this.checkData(this.submission.data);
      return this.beforePage(true).then(() => {
        return this.setPage(this.getNextPage()).then(() => {
          this.emit('nextPage', { page: this.page, submission: this.submission });
        });
      });
    }
    else {
      return NativePromise.reject(this.showErrors(null, true));
    }
  }

  prevPage() {
    return this.beforePage().then(() => {
      return this.setPage(this.getPreviousPage()).then(() => {
        this.emit('prevPage', { page: this.page, submission: this.submission });
      });
    });
  }

  cancel(noconfirm) {
    if (super.cancel(noconfirm)) {
      return this.setPage(0);
    }
    else {
      return this.setPage();
    }
  }

  getPageIndexByKey(key) {
    let pageIndex = this.page;
    this.panels.forEach((page, index) => {
      if (page.key === key) {
        pageIndex = index;
        return false;
      }
    });
    return pageIndex;
  }

  checkPageValidity(data, dirty, page) {
    page = page || this.page;

    let check = true;
    this.pages[page].forEach((comp) => {
      check &= comp.checkValidity(data, dirty);
    });
    return check;
  }

  get schema() {
    return this.wizard;
  }

  setForm(form) {
    if (!form) {
      return;
    }
    this.wizard = form;
    this.component.components = form.components || [];

    // Check if there are no panel components.
    if (this.component.components.filter(component => component.type === 'panel').length === 0) {
      this.component.components = [
        {
          type: 'panel',
          title: 'Page 1',
          label: 'Page 1',
          key: 'page1',
          components: this.component.components
        }
      ];
    }
    return super.setForm(form);
  }

  isClickable(page, index) {
    return this.page !== index && firstNonNil([
      _.get(page, 'breadcrumbClickable'),
      this.options.breadcrumbSettings.clickable
    ]);
  }

  hasButton(name, nextPage) {
    const currentPage = this.currentPage;
    if (name === 'previous') {
      const show = firstNonNil([
        _.get(currentPage, 'buttonSettings.previous'),
        this.options.buttonSettings.showPrevious
      ]);
      return (this.page > 0) && show;
    }
    nextPage = (nextPage === undefined) ? this.getNextPage() : nextPage;
    if (name === 'next') {
      const show = firstNonNil([
        _.get(currentPage, 'buttonSettings.next'),
        this.options.buttonSettings.showNext
      ]);
      return (nextPage !== null) && (nextPage < this.pages.length) && show;
    }
    if (name === 'cancel') {
      return firstNonNil([
        _.get(currentPage, 'buttonSettings.cancel'),
        this.options.buttonSettings.showCancel
      ]);
    }
    if (name === 'submit') {
      const show = firstNonNil([
        _.get(currentPage, 'buttonSettings.submit'),
        this.options.buttonSettings.showSubmit
      ]);
      return show && !this.options.readOnly && ((nextPage === null) || (this.page === (this.pages.length - 1)));
    }
    return true;
  }

  pageId(page) {
    if (page.key) {
      // Some panels have the same key....
      return `${page.key}-${page.title}`;
    }
    else if (
      page.components &&
      page.components.length > 0
    ) {
      return this.pageId(page.components[0]);
    }
    else {
      return page.title;
    }
  }

  calculateVisiblePanels() {
    const visible = [];
    _.each(this.wizard.components, (component) => {
      if (component.type === 'panel') {
        // Ensure that this page can be seen.
        if (checkCondition(component, this.data, this.data, this.wizard, this)) {
          visible.push(component);
        }
      }
    });
    return visible;
  }

  onChange(flags, changed) {
    super.onChange(flags, changed);

    // Only rebuild if there is a page visibility change.
    const panels = this.calculateVisiblePanels();
    const currentNextPage = this.currentNextPage;
    const nextPage = this.getNextPage();
    if (
      (nextPage !== currentNextPage) ||
      !_.isEqual(panels.map(panel => panel.key), this.panels.map(panel => panel.key))
    ) {
      // If visible panels changes we need to build this template again.
      this.rebuild();
    }
  }

  rebuild() {
    this.destroyComponents();
    this.addComponents();
    return this.redraw();
  }

  checkCurrentPageValidity(...args) {
    return super.checkValidity(...args);
  }

  checkPagesValidity(pages, ...args) {
    const isValid = Component.prototype.checkValidity.apply(this, args);
    return pages.reduce((check, pageComp) => {
      return pageComp.checkValidity(...args) && check;
    }, isValid);
  }

  checkValidity(data, dirty) {
    if (this.submitting) {
      return this.checkPagesValidity(this.getPages(), data, dirty);
    }
    else {
      return this.checkCurrentPageValidity(data, dirty);
    }
  }

  get errors() {
    if (this.isLastPage()) {
      const pages = this.getPages({ all: true });

      this.checkPagesValidity(pages, this.submission.data, true);

      return pages.reduce((errors, pageComp) => {
        return errors.concat(pageComp.errors || []);
      }, []);
    }

    return super.errors;
  }
}

Wizard.setBaseUrl = Formio.setBaseUrl;
Wizard.setApiUrl = Formio.setApiUrl;
Wizard.setAppUrl = Formio.setAppUrl;
<|endoftext|>


<commit_before>/*
 *  Copyright (c) 2015-present, Facebook, Inc.
 *  All rights reserved.
 *
 *  This source code is licensed under the BSD-style license found in the
 *  LICENSE file in the root directory of this source tree. An additional grant
 *  of patent rights can be found in the PATENTS file in the same directory.
 *
 */

'use strict';

const EventEmitter = require('events').EventEmitter;

const async = require('async');
const fs = require('fs');

const jscodeshift = require('./core');

let emitter;
let finish;
let notify;
let transform;

if (module.parent) {
  emitter = new EventEmitter();
  emitter.send = (data) => { run(data); };
  finish = () => { emitter.emit('disconnect'); };
  notify = (data) => { emitter.emit('message', data); };
  module.exports = (args) => {
    setup(args[0], args[1]);
    return emitter;
  };
} else {
  finish = () => { process.disconnect(); };
  notify = (data) => { process.send(data); };
  process.on('message', (data) => { run(data); });
  setup(process.argv[2], process.argv[3]);
}

function setup(tr, babel) {
  if (babel === 'babel') {
    // FIXME: use { babelrc: false } after migration to Babel 6
    require('babel-core/register')({ breakConfig: true });
  }
  transform = require(tr);
}

function free() {
  notify({action: 'free'});
}

function updateStatus(status, file, msg) {
  msg = msg  ?  file + ' ' + msg : file;
  notify({action: 'status', status: status, msg: msg});
}

function empty() {}

function stats(name, quantity) {
  quantity = typeof quantity !== 'number' ? 1 : quantity;
  notify({action: 'update', name: name, quantity: quantity});
}

function trimStackTrace(trace) {
  // Remove this file from the stack trace of an error thrown in the transformer
  var lines = trace.split('\n');
  var result = [];
  lines.every(function(line) {
    if (line.indexOf(__filename) === -1) {
      result.push(line);
      return true;
    }
  });
  return result.join('\n');
}

function run(data) {
  var files = data.files;
  var options = data.options;
  if (!files.length) {
    finish();
    return;
  }
  async.each(
    files,
    function(file, callback) {
      fs.readFile(file, function(err, source) {
        if (err) {
          updateStatus('error', file, 'File error: ' + err);
          callback();
          return;
        }
        source = source.toString();
        try {
          var out = transform(
            {
              path: file,
              source: source,
            },
            {
              jscodeshift: jscodeshift,
              stats: options.dry ? stats : empty
            },
            options
          );
          if (!out || out === source) {
            updateStatus(out ? 'nochange' : 'skip', file);
            callback();
            return;
          }
          if (options.print) {
            console.log(out);
          }
          if (!options.dry) {
            fs.writeFile(file, out, function(err) {
              if (err) {
                updateStatus('error', file, 'File writer error: ' + err);
              } else {
                updateStatus('ok', file);
              }
              callback();
            });
          } else {
            updateStatus('ok', file);
            callback();
          }
        } catch(err) {
          updateStatus(
            'error',
            file,
            'Transformation error\n' + trimStackTrace(err.stack)
          );
          callback();
        }
      });
    },
    function(err) {
      if (err) {
        updateStatus('error', '', 'This should never be shown!');
      }
      free();
    }
  );
}
<commit_msg>Fix process disconnection<commit_after>/*
 *  Copyright (c) 2015-present, Facebook, Inc.
 *  All rights reserved.
 *
 *  This source code is licensed under the BSD-style license found in the
 *  LICENSE file in the root directory of this source tree. An additional grant
 *  of patent rights can be found in the PATENTS file in the same directory.
 *
 */

'use strict';

const EventEmitter = require('events').EventEmitter;

const async = require('async');
const fs = require('fs');

const jscodeshift = require('./core');

let emitter;
let finish;
let notify;
let transform;

if (module.parent) {
  emitter = new EventEmitter();
  emitter.send = (data) => { run(data); };
  finish = () => { emitter.emit('disconnect'); };
  notify = (data) => { emitter.emit('message', data); };
  module.exports = (args) => {
    setup(args[0], args[1]);
    return emitter;
  };
} else {
  finish = () => { setImmediate(process.disconnect) };
  notify = (data) => { process.send(data); };
  process.on('message', (data) => { run(data); });
  setup(process.argv[2], process.argv[3]);
}

function setup(tr, babel) {
  if (babel === 'babel') {
    // FIXME: use { babelrc: false } after migration to Babel 6
    require('babel-core/register')({ breakConfig: true });
  }
  transform = require(tr);
}

function free() {
  notify({action: 'free'});
}

function updateStatus(status, file, msg) {
  msg = msg  ?  file + ' ' + msg : file;
  notify({action: 'status', status: status, msg: msg});
}

function empty() {}

function stats(name, quantity) {
  quantity = typeof quantity !== 'number' ? 1 : quantity;
  notify({action: 'update', name: name, quantity: quantity});
}

function trimStackTrace(trace) {
  // Remove this file from the stack trace of an error thrown in the transformer
  var lines = trace.split('\n');
  var result = [];
  lines.every(function(line) {
    if (line.indexOf(__filename) === -1) {
      result.push(line);
      return true;
    }
  });
  return result.join('\n');
}

function run(data) {
  var files = data.files;
  var options = data.options;
  if (!files.length) {
    finish();
    return;
  }
  async.each(
    files,
    function(file, callback) {
      fs.readFile(file, function(err, source) {
        if (err) {
          updateStatus('error', file, 'File error: ' + err);
          callback();
          return;
        }
        source = source.toString();
        try {
          var out = transform(
            {
              path: file,
              source: source,
            },
            {
              jscodeshift: jscodeshift,
              stats: options.dry ? stats : empty
            },
            options
          );
          if (!out || out === source) {
            updateStatus(out ? 'nochange' : 'skip', file);
            callback();
            return;
          }
          if (options.print) {
            console.log(out);
          }
          if (!options.dry) {
            fs.writeFile(file, out, function(err) {
              if (err) {
                updateStatus('error', file, 'File writer error: ' + err);
              } else {
                updateStatus('ok', file);
              }
              callback();
            });
          } else {
            updateStatus('ok', file);
            callback();
          }
        } catch(err) {
          updateStatus(
            'error',
            file,
            'Transformation error\n' + trimStackTrace(err.stack)
          );
          callback();
        }
      });
    },
    function(err) {
      if (err) {
        updateStatus('error', '', 'This should never be shown!');
      }
      free();
    }
  );
}
<|endoftext|>


<commit_before>/**
 * @file Th component
 * @author liangxiaojun(liangxiaojun@derbysoft.com)
 */

import React, {Component} from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';

import ThSortIcon from '../_ThSortingIcon';

import HorizontalAlign from '../_statics/HorizontalAlign';
import SortingType from '../_statics/SortingType';

import Util from '../_vendors/Util';

class Th extends Component {

    static Align = HorizontalAlign;
    static SortingType = SortingType;

    constructor(props, ...restArgs) {
        super(props, ...restArgs);
    }

    /**
     * handle th content render
     * @returns {*}
     */
    handleRender = () => {

        const {colIndex, data, renderer} = this.props;

        switch (typeof renderer) {
            case 'function':
                return renderer(data, colIndex);
            default:
                return renderer;
        }

    };

    /**
     * handle th click and trigger sorting callback
     */
    handleClick = () => {

        const {sortable, onSortChange} = this.props;

        if (!sortable || !onSortChange) {
            return;
        }

        const {sorting, defaultSortingType, sortingProp} = this.props,
            result = {};

        if (sorting && sorting.prop === sortingProp) {
            result.prop = sorting.prop;
            result.type = -sorting.type;
        } else {
            result.prop = sortingProp;
            result.type = defaultSortingType;
        }

        onSortChange && onSortChange(result);

    };

    render() {

        const {
            className, style, renderer, align,
            sortable, sortingProp, sorting, sortingAscIconCls, sortingDescIconCls
        } = this.props;

        return (
            <th className={classNames({
                [`align-${align}`]: align && align !== HorizontalAlign.LEFT,
                sortable: sortable,
                sorting: sortable && sortingProp && sorting && sorting.prop && sorting.prop === sortingProp,
                [className]: className
            })}
                style={style}
                title={typeof renderer === 'string' ? renderer : null}
                onClick={this.handleClick}>

                        {this.handleRender()}

                    {
                        sortable ?
                            <ThSortIcon sorting={sorting}
                                        sortingProp={sortingProp}
                                        sortingAscIconCls={sortingAscIconCls}
                                        sortingDescIconCls={sortingDescIconCls}/>
                            :
                            null
                    }

        );

    }
}

Th.propTypes = {

    className: PropTypes.string,
    style: PropTypes.object,

    renderer: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),
    align: PropTypes.oneOf(Util.enumerateValue(HorizontalAlign)),
    colIndex: PropTypes.number,
    data: PropTypes.array,

    /**
     * sorting
     */
    sorting: PropTypes.shape({
        prop: PropTypes.string,
        type: PropTypes.oneOf(Util.enumerateValue(SortingType))
    }),
    defaultSortingType: PropTypes.oneOf(Util.enumerateValue(SortingType)),
    sortingAscIconCls: PropTypes.string,
    sortingDescIconCls: PropTypes.string,
    sortable: PropTypes.bool,
    sortingProp: PropTypes.string,

    onSortChange: PropTypes.func

};

Th.defaultProps = {

    colIndex: 0,

    defaultSortingType: SortingType.ASC,
    sortingAscIconCls: 'fas fa-sort-up',
    sortingDescIconCls: 'fas fa-sort-down',
    sortable: false

};

export default Th;
<commit_msg>update Th<commit_after>/**
 * @file Th component
 * @author liangxiaojun(liangxiaojun@derbysoft.com)
 */

import React, {Component} from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';

import ThSortIcon from '../_ThSortingIcon';

import HorizontalAlign from '../_statics/HorizontalAlign';
import SortingType from '../_statics/SortingType';

import Util from '../_vendors/Util';

class Th extends Component {

    static Align = HorizontalAlign;
    static SortingType = SortingType;

    constructor(props, ...restArgs) {
        super(props, ...restArgs);
    }

    /**
     * handle th content render
     * @returns {*}
     */
    handleRender = () => {

        const {colIndex, data, renderer} = this.props;

        switch (typeof renderer) {
            case 'function':
                return renderer(data, colIndex);
            default:
                return renderer;
        }

    };

    /**
     * handle th click and trigger sorting callback
     */
    handleClick = () => {

        const {sortable, onSortChange} = this.props;

        if (!sortable || !onSortChange) {
            return;
        }

        const {sorting, defaultSortingType, sortingProp} = this.props,
            result = {};

        if (sorting && sorting.prop === sortingProp) {
            result.prop = sorting.prop;
            result.type = -sorting.type;
        } else {
            result.prop = sortingProp;
            result.type = defaultSortingType;
        }

        onSortChange && onSortChange(result);

    };

    render() {

        const {
            className, style, renderer, align, rowSpan, colSpan,
            sortable, sortingProp, sorting, sortingAscIconCls, sortingDescIconCls
        } = this.props;

        return (
            <th className={classNames({
                [`align-${align}`]: align && align !== HorizontalAlign.LEFT,
                sortable: sortable,
                sorting: sortable && sortingProp && sorting && sorting.prop && sorting.prop === sortingProp,
                [className]: className
            })}
                style={style}
                title={typeof renderer === 'string' ? renderer : null}
                rowSpan={rowSpan}
                colSpan={colSpan}
                onClick={this.handleClick}>

                        {this.handleRender()}

                    {
                        sortable ?
                            <ThSortIcon sorting={sorting}
                                        sortingProp={sortingProp}
                                        sortingAscIconCls={sortingAscIconCls}
                                        sortingDescIconCls={sortingDescIconCls}/>
                            :
                            null
                    }

        );

    }
}

Th.propTypes = {

    className: PropTypes.string,
    style: PropTypes.object,

    renderer: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),
    align: PropTypes.oneOf(Util.enumerateValue(HorizontalAlign)),
    colIndex: PropTypes.number,
    data: PropTypes.array,

    /**
     * sorting
     */
    sorting: PropTypes.shape({
        prop: PropTypes.string,
        type: PropTypes.oneOf(Util.enumerateValue(SortingType))
    }),
    defaultSortingType: PropTypes.oneOf(Util.enumerateValue(SortingType)),
    sortingAscIconCls: PropTypes.string,
    sortingDescIconCls: PropTypes.string,
    sortable: PropTypes.bool,
    sortingProp: PropTypes.string,

    onSortChange: PropTypes.func

};

Th.defaultProps = {

    colIndex: 0,

    defaultSortingType: SortingType.ASC,
    sortingAscIconCls: 'fas fa-sort-up',
    sortingDescIconCls: 'fas fa-sort-down',
    sortable: false

};

export default Th;
<|endoftext|>