<commit_before>'use strict';

const isArray = require('lodash.isarray');
const partialRight = require('lodash.partialright');
const Request = require('./Request');
const Response = require('./Response');
const Transformer = require('./transformers/Transformer');
const Middleware = require('./Middleware');
const ServerlessTransformer = require('./transformers/ServerlessTransformer');

class Kernel {
  /**
   * @param {Transformer} transformer
   * @param {Middleware[]} middlewares
   */
  constructor(transformer, middlewares) {
    // default to the Serverless transformer and parsing the body as JSON
    if (typeof transformer === 'undefined') {
      transformer = new ServerlessTransformer(JSON.parse);
    } else if (!(transformer instanceof Transformer)) {
      throw new TypeError(
        'transformer provided to Kernel is not an ' +
        'instance of Transformer, it is: ' + typeof transformer
      );
    }

    this.transformer = transformer;

    if (!isArray(middlewares)) {
      throw new TypeError(
        'middlewares provided to Kernel is' +
        'not an Array, it is: ' + typeof middlewares
      );
    }

    for (let i of middlewares) {
      if (!(middlewares[i] instanceof Middleware)) {
        throw new TypeError(
          `middleware ${i} provided to Kernel is not an ` +
          'instance of Middleware, it is: ' + typeof middlewares[i]
        );
      }
    }

    this.middlewares = middlewares;
  }

  /**
   * @access public
   * @param action
   * @param middleware
   * @return function
   */
  dispatch(action, middleware) {
    return partialRight(
      this.dispatcher.bind(this),
      action,
      middleware
    );
  }

  /**
   * @access private
   * @param {object} event
   * @param {object} context
   * @param {function} cb
   * @param {function} action
   * @param {Middleware[]} middlewares
   * @return {void}
   **/
  dispatcher(event, context, cb, action, middlewares) {
    const stage = event.requestContext.stage.toUpperCase();
    const env = {
      stage: stage,
      debug: ['DEV', 'QA', 'TEST'].indexOf(stage) > -1
    };

    if (typeof action !== 'function') {
      throw new TypeError(
        'action provided to dispatcher must be a callable'
      );
    }

    if (!isArray(middlewares)) {
      middlewares = this.middlewares;
    } else {
      middlewares = this.middlewares.concat(middlewares);
    }

    try {
      // construct the request from the event using provided transformer
      const req = new Request(event, this.transformer);
      const mwValues = middlewares.map(mw => mw.create(req, env));
      // construct response from provided method
      const res = action.apply(null, [req, env].concat(mwValues));

      if (typeof res !== 'object') {
        throw new TypeError('controller methods must return a Response or a Promise');
      } else if (res instanceof Response) {
        context.done(null, res.simplify());
      } else if (typeof res.then === 'function') {
        res.then(promised => {
          if (promised instanceof Response) {
            context.done(null, promised.simplify());
          } else {
            throw new TypeError('Promises returned by controller methods must resolve to a Response');
          }
        }, err => {
          context.done(null, Kernel.parseErr(err).simplify());
        });
      } else throw new TypeError('controller methods must return a Response or a Promise');
    } catch (err) {
      // using context.done instead of cb because of cb() holding connection open
      context.done(null, Kernel.parseErr(err).simplify());
    } finally {
      middlewares.forEach(mw => mw.destroy());
    }
  }

  /**
   * @access private
   * @param err
   * @return {Response}
   */
  static parseErr(err) {
    let message = '';
    if (err.hasOwnProperty('message'))
      message = err.message;
    else message = err;

    const codes = /^\[([0-9]{3})]\s/.exec(message);<commit_msg>add forceEnd option to Kernel<commit_after>'use strict';

const isArray = require('lodash.isarray');
const partialRight = require('lodash.partialright');
const Request = require('./Request');
const Response = require('./Response');
const Transformer = require('./transformers/Transformer');
const Middleware = require('./Middleware');
const ServerlessTransformer = require('./transformers/ServerlessTransformer');

class Kernel {
  /**
   * @param {Transformer} [transformer]
   * @param {Middleware[]} [middlewares]
   * @param {Object} [options]
   */
  constructor(transformer, middlewares, options) {
    // default to the Serverless transformer and parsing the body as JSON
    if (typeof transformer === 'undefined') {
      transformer = new ServerlessTransformer(JSON.parse);
    } else if (!(transformer instanceof Transformer)) {
      throw new TypeError(
        'transformer provided to Kernel is not an ' +
        'instance of Transformer, it is: ' + typeof transformer
      );
    }

    this.transformer = transformer;

    if (!isArray(middlewares)) {
      throw new TypeError(
        'middlewares provided to Kernel is' +
        'not an Array, it is: ' + typeof middlewares
      );
    }

    for (let i of middlewares) {
      if (!(middlewares[i] instanceof Middleware)) {
        throw new TypeError(
          `middleware ${i} provided to Kernel is not an ` +
          'instance of Middleware, it is: ' + typeof middlewares[i]
        );
      }
    }

    this.middlewares = middlewares;

    const defaultOptions = {
      forceEnd: true,
    };

    if (typeof options === 'object') {
      this.options = Object.assign(defaultOptions, options);
    } else this.options = defaultOptions;
  }

  /**
   * @access public
   * @param action
   * @param middleware
   * @return function
   */
  dispatch(action, middleware) {
    return partialRight(
      this.dispatcher.bind(this),
      action,
      middleware
    );
  }

  /**
   * @access private
   * @param {object} event
   * @param {object} context
   * @param {function} cb
   * @param {function} action
   * @param {Middleware[]} middlewares
   * @return {void}
   **/
  dispatcher(event, context, cb, action, middlewares) {
    const respond = this.respond.bind(this, context, cb);
    const stage = event.requestContext.stage.toUpperCase();
    const env = {
      stage: stage,
      debug: ['DEV', 'QA', 'TEST'].indexOf(stage) > -1
    };

    if (typeof action !== 'function') {
      throw new TypeError(
        'action provided to dispatcher must be a callable'
      );
    }

    if (!isArray(middlewares)) {
      middlewares = this.middlewares;
    } else {
      middlewares = this.middlewares.concat(middlewares);
    }

    try {
      // construct the request from the event using provided transformer
      const req = new Request(event, this.transformer);
      const mwValues = middlewares.map(mw => mw.create(req, env));
      // construct response from provided method
      const response = action.apply(null, [req, env].concat(mwValues));

      if (typeof response !== 'object') {
        throw new TypeError('controller methods must return a Response or a Promise');
      } else if (response instanceof Response) {
        respond(null, response.simplify());
      } else if (typeof response.then === 'function') {
        response.then(promised => {
          if (promised instanceof Response) {
            respond(null, promised.simplify());
          } else {
            throw new TypeError('Promises returned by controller methods must resolve to a Response');
          }
        }, err => {
          respond(null, Kernel.parseErr(err).simplify());
        });
      } else throw new TypeError('controller methods must return a Response or a Promise');
    } catch (err) {
      // using context.done instead of cb because of cb() holding connection open
      respond(null, Kernel.parseErr(err).simplify());
    } finally {
      middlewares.forEach(mw => mw.destroy());
    }
  }


  /**
   * Respond to the Lambda integration layer with
   * the provided error or response.
   * @access private
   * @param {function} cb
   * @param {object} context
   * @param {object} [err]
   * @param {Response} [response]
   * @return {void}
   **/
  respond(cb, context, err, response) {
    if (this.options.forceEnd) {
      context.done(err, response);
    } else cb(err, response);
  };

  /**
   * @access private
   * @param err
   * @return {Response}
   */
  static parseErr(err) {
    let message = '';
    if (err.hasOwnProperty('message'))
      message = err.message;
    else message = err;

    const codes = /^\[([0-9]{3})]\s/.exec(message);
{'fraction_non_alphanumeric': 0.12763982362497098, 'fraction_numerical': 0.0009282896263634254, 'mean_word_length': 2.6864841745081267, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 13, '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': '5579913', 'n_tokens_mistral': 2491, 'n_tokens_neox': 2440, 'n_words': 713}