<commit_before>import Observable from './observable';
import Command, { UndoableCommand, CommandWrapper } from './command';

export default class CommandInvoker extends Observable {
  constructor(receiver) {
    super();
    this.commandChain = [];
    this.commandStack = [];
    this.redoStack = [];
    this.receiver = receiver;
  }

  // <summary>
  // Add a command to the command chain
  // </summary>
  enqueueCommand(command) {
    if (typeof command === 'undefined' || command === 'null') {
      throw Error('Null argument exception.');
    }

    let cmd = null;
    if (command instanceof Command) {
      cmd = command;
    } else if (typeof command === 'function') {
      cmd = new CommandWrapper({ execute: command });
    } else {
      cmd = new CommandWrapper(command);
    }

    cmd.receiver = this.receiver;
    cmd.invoker = this;

    this.commandChain.push(cmd);

    try {
      cmd.validate(this.commandStack, this.commandChain);
    } catch (e) {
      this.commandChain.pop();
      throw Error(e);
    }
    return cmd;
  }

  // <summary>
  // Removes a command from the command chain
  // </summary>
  dequeueCommand(command) {
    const index = this.commandChain.indexOf(command);

    if (index >= 0) {
      this.commandChain.splice(index, 1);
    }
  }

  // <summary>
  // Executes a promise for execute a single command
  // </summary>
  apply(command) {
    this.enqueueCommand(command);
    return this.execute();
  }

  // <summary>
  // Starts execution of the command chain
  // </summary>
  execute() {
    return new Promise((resolve, reject) => {
      this.inProgress = true;
      this.on('nextCommand', this.executeNext);
      this.on('commandComplete', this.onCommandComplete);
      this.on('complete', this.onComplete.bind(this, resolve));
      this.on('commandFailure', this.onCommandFailure.bind(this, reject));
      this.trigger('start', this.commandChain.length);
      this.trigger('nextCommand');
    });
  }

  // <summary>
  // Executes next command from the command chain
  // </summary>
  executeNext() {
    if (this.commandChain.length === 0) {
      this.trigger('complete');
      return;
    }

    const action = this.commandChain.shift();

    try {
      const promise = Promise.resolve(action.execute());

      promise.then(() => {
        this.trigger('commandComplete', action);
      }).catch((e) => {<commit_msg>Sending response as part of the promise<commit_after>import Observable from './observable';
import Command, { UndoableCommand, CommandWrapper } from './command';

export default class CommandInvoker extends Observable {
  constructor(receiver) {
    super();
    this.commandChain = [];
    this.commandStack = [];
    this.redoStack = [];
    this.receiver = receiver;
  }

  // <summary>
  // Add a command to the command chain
  // </summary>
  enqueueCommand(command) {
    if (typeof command === 'undefined' || command === 'null') {
      throw Error('Null argument exception.');
    }

    let cmd = null;
    if (command instanceof Command) {
      cmd = command;
    } else if (typeof command === 'function') {
      cmd = new CommandWrapper({ execute: command });
    } else {
      cmd = new CommandWrapper(command);
    }

    cmd.receiver = this.receiver;
    cmd.invoker = this;

    this.commandChain.push(cmd);

    try {
      cmd.validate(this.commandStack, this.commandChain);
    } catch (e) {
      this.commandChain.pop();
      throw Error(e);
    }
    return cmd;
  }

  // <summary>
  // Removes a command from the command chain
  // </summary>
  dequeueCommand(command) {
    const index = this.commandChain.indexOf(command);

    if (index >= 0) {
      this.commandChain.splice(index, 1);
    }
  }

  // <summary>
  // Executes a promise for execute a single command
  // </summary>
  apply(command) {
    this.enqueueCommand(command);
    return this.execute();
  }

  // <summary>
  // Starts execution of the command chain
  // </summary>
  execute() {
    return new Promise((resolve, reject) => {
      this.inProgress = true;
      this.on('nextCommand', this.executeNext);
      this.on('commandComplete', this.onCommandComplete);
      this.on('complete', this.onComplete.bind(this, resolve));
      this.on('commandFailure', this.onCommandFailure.bind(this, reject));
      this.trigger('start', this.commandChain.length);
      this.trigger('nextCommand');
    });
  }

  // <summary>
  // Executes next command from the command chain
  // </summary>
  executeNext() {
    if (this.commandChain.length === 0) {
      this.trigger('complete');
      return;
    }

    const action = this.commandChain.shift();

    try {
      const promise = Promise.resolve(action.execute());

      promise.then((response) => {
        this.trigger('commandComplete', action, response);
      }).catch((e) => {
{'fraction_non_alphanumeric': 0.14566929133858267, 'fraction_numerical': 0.0012432656444260257, 'mean_word_length': 2.736068111455108, 'pattern_counts': {'":': 0, '<': 23, '<?xml version=': 0, '>': 31, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '482283', 'n_tokens_mistral': 1428, 'n_tokens_neox': 1399, 'n_words': 341}