<commit_before>import { readFileSync } from 'fs';
import { merge, isEmpty } from 'lodash';
import * as exceptions from './exceptions';

/**
 * debugger module that displays stack traces in readable html
 */
export class Tracy {

  private enabled = false; // disable by default
  private options: Options;
  public environment: string;
  public readonly exceptions = exceptions;

  constructor() {
    this.environment = process.env.NODE_ENV || 'development';
    this.options = {
      logger: process.stderr.write,
      baseDir: process.cwd(),
      productionErrorMessage: 'Internal Server Error',
      hideProductionErrorMessage: true,
      showLinesBeforeError: 10,
      showLinesAfterError: 5,
      editor: 'editor://open',
      enableHtmlResponse: true,
    } as Options;
  }

  static enable(options = {} as Options): Tracy {
    const tracy = new Tracy();
    tracy.enable(options);

    return tracy;
  }

  enable(options = {} as Options): void {
    this.options = merge(this.options, options);
    this.enabled = true;
  }

  isEnabled(): boolean {
    return this.enabled;
  }

  /**
   * Create wrapper for route handlers, that automatically catches all thrown exceptions and promise rejections
   * When using promises inside handler, you need to return the Promise from it to allow proper rejection handling
   *
   * @param {Function} callback with `req`, `res` and `next` parameters
   */
  catcher(callback: Function): Function {
    return (req: any, res: any, next: Function) => {
      Promise
        .resolve()
        .then(() => callback(req, res, next))
        .catch(err => this.errorResponse(req, res, err || {}));
    };
  }

  errorResponse(req: any, res: any, err: any) {
    let code = 500;

    if (err.code && !isNaN(err.code)) {
      code = err.code;
    }

    res.status(code);
    this.logToConsole(err, code, req);

    // is browser request?
    const ua = (req.headers['user-agent'] || '').toLowerCase();
    const browser = ua && (ua.includes('mozilla') || ua.includes('chrome') || ua.includes('edge') || ua.includes('webkit'));

    // Only include errors in response if application environment
    // is not set to 'production'.  In production, we shouldn't
    // send back any identifying information about errors.
    let json;

    if (this.getEnvironment() === 'production') {
      if (err.message && err.message.indexOf(' ') === -1 && this.options.hideProductionErrorMessage) {
        json = { message: err.message };
      } else {
        json = { message: this.options.productionErrorMessage };
      }
    } else if (browser && this.options.enableHtmlResponse) { // tracy like json response when request accepts text/html
      return res.end(this.generateHtmlError(err, req));<commit_msg>Fix turning off hiding of production message toggle working the opposite way<commit_after>import { readFileSync } from 'fs';
import { merge, isEmpty } from 'lodash';
import * as exceptions from './exceptions';

/**
 * debugger module that displays stack traces in readable html
 */
export class Tracy {

  private enabled = false; // disable by default
  private options: Options;
  public environment: string;
  public readonly exceptions = exceptions;

  constructor() {
    this.environment = process.env.NODE_ENV || 'development';
    this.options = {
      logger: process.stderr.write,
      baseDir: process.cwd(),
      productionErrorMessage: 'Internal Server Error',
      hideProductionErrorMessage: true,
      showLinesBeforeError: 10,
      showLinesAfterError: 5,
      editor: 'editor://open',
      enableHtmlResponse: true,
    } as Options;
  }

  static enable(options = {} as Options): Tracy {
    const tracy = new Tracy();
    tracy.enable(options);

    return tracy;
  }

  enable(options = {} as Options): void {
    this.options = merge(this.options, options);
    this.enabled = true;
  }

  isEnabled(): boolean {
    return this.enabled;
  }

  /**
   * Create wrapper for route handlers, that automatically catches all thrown exceptions and promise rejections
   * When using promises inside handler, you need to return the Promise from it to allow proper rejection handling
   *
   * @param {Function} callback with `req`, `res` and `next` parameters
   */
  catcher(callback: Function): Function {
    return (req: any, res: any, next: Function) => {
      Promise
        .resolve()
        .then(() => callback(req, res, next))
        .catch(err => this.errorResponse(req, res, err || {}));
    };
  }

  errorResponse(req: any, res: any, err: any) {
    let code = 500;

    if (err.code && !isNaN(err.code)) {
      code = err.code;
    }

    res.status(code);
    this.logToConsole(err, code, req);

    // is browser request?
    const ua = (req.headers['user-agent'] || '').toLowerCase();
    const browser = ua && (ua.includes('mozilla') || ua.includes('chrome') || ua.includes('edge') || ua.includes('webkit'));

    // Only include errors in response if application environment
    // is not set to 'production'.  In production, we shouldn't
    // send back any identifying information about errors.
    let json;

    if (this.getEnvironment() === 'production') {
      if (err.message && (err.message.indexOf(' ') === -1 || !this.options.hideProductionErrorMessage)) {
        json = { message: err.message };
      } else {
        json = { message: this.options.productionErrorMessage };
      }
    } else if (browser && this.options.enableHtmlResponse) { // tracy like json response when request accepts text/html
      return res.end(this.generateHtmlError(err, req));
{'fraction_non_alphanumeric': 0.1289454806312769, 'fraction_numerical': 0.002510760401721664, 'mean_word_length': 3.0827232796486093, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 9, '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': '1941703', 'n_tokens_mistral': 1598, 'n_tokens_neox': 1537, 'n_words': 492}