<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.
 *
 * @flow
 */

'use strict';

const path = require('path');
const reporting = require('./reporting');
const terminal = require('./terminal');
const throttle = require('lodash/throttle');
const util = require('util');

import type {ReportableEvent, GlobalCacheDisabledReason} from './reporting';

const DEP_GRAPH_MESSAGE = 'Loading dependency graph';
const GLOBAL_CACHE_DISABLED_MESSAGE_FORMAT =
  'The global cache is now disabled because %s';

type BundleProgress = {
  transformedFileCount: number,
  totalFileCount: number,
  ratio: number,
};

const DARK_BLOCK_CHAR = '\u2593';
const LIGHT_BLOCK_CHAR = '\u2591';

function getProgressBar(ratio: number, length: number) {
  const blockCount = Math.floor(ratio * length);
  return (
    DARK_BLOCK_CHAR.repeat(blockCount) +
    LIGHT_BLOCK_CHAR.repeat(length - blockCount)
  );
}

export type TerminalReportableEvent = ReportableEvent | {
  type: 'bundle_transform_progressed_throttled',
  entryFilePath: string,
  transformedFileCount: number,
  totalFileCount: number,
};

type BuildPhase = 'in_progress' | 'done' | 'failed';

/**
 * We try to print useful information to the terminal for interactive builds.
 * This implements the `Reporter` interface from the './reporting' module.
 */
class TerminalReporter {

  /**
   * The bundle builds for which we are actively maintaining the status on the
   * terminal, ie. showing a progress bar. There can be several bundles being
   * built at the same time.
   */
  _activeBundles: Map<string, BundleProgress>;

  _dependencyGraphHasLoaded: boolean;
  _scheduleUpdateBundleProgress: (data: {
    entryFilePath: string,
    transformedFileCount: number,
    totalFileCount: number,
  }) => void;

  constructor() {
    this._dependencyGraphHasLoaded = false;
    this._activeBundles = new Map();
    this._scheduleUpdateBundleProgress = throttle(data => {
      this.update({...data, type: 'bundle_transform_progressed_throttled'});
    }, 200);
  }

  /**
   * Construct a message that represents the progress of a
   * single bundle build, for example:
   *
   *     Bunding `foo.js`  |####         | 34.2% (324/945)
   */
  _getBundleStatusMessage(
    entryFilePath: string,
    {totalFileCount, transformedFileCount, ratio}: BundleProgress,
    phase: BuildPhase,
  ): string {
    const localPath = path.relative('.', entryFilePath);
    return util.format(
      'Bundling `%s`  %s%s% (%s/%s)%s',
      localPath,
      phase === 'in_progress' ? getProgressBar(ratio, 16) + '  ' : '',
      (100 * ratio).toFixed(1),
      transformedFileCount,
      totalFileCount,
      phase === 'done' ? ', done.' : (phase === 'failed' ? ', failed.' : ''),
    );
  }

  _logCacheDisabled(reason: GlobalCacheDisabledReason): void {
    const format = GLOBAL_CACHE_DISABLED_MESSAGE_FORMAT;
    switch (reason) {
      case 'too_many_errors':
        reporting.logWarning(terminal, format, 'it has been failing too many times.');
        break;
      case 'too_many_misses':
        reporting.logWarning(terminal, format, 'it has been missing too many consecutive keys.');
        break;
    }
  }

  _logBundleBuildDone(entryFilePath: string) {
    const progress = this._activeBundles.get(entryFilePath);
    if (progress != null) {
      const msg = this._getBundleStatusMessage(entryFilePath, {
        ...progress,
        ratio: 1,
        transformedFileCount: progress.totalFileCount,
      }, 'done');
      terminal.log(msg);
    }
  }

  _logBundleBuildFailed(entryFilePath: string, error: Error) {
    reporting.logError(terminal, 'bundling: %s', error.stack);
    const progress = this._activeBundles.get(entryFilePath);
    if (progress != null) {
      const msg = this._getBundleStatusMessage(entryFilePath, progress, 'failed');
      terminal.log(msg);
    }
  }

  /**
   * This function is only concerned with logging and should not do state
   * or terminal status updates.
   */
  _log(event: TerminalReportableEvent): void {
    switch (event.type) {
      case 'bundle_build_done':
        this._logBundleBuildDone(event.entryFilePath);
        break;
      case 'bundle_build_failed':
        this._logBundleBuildFailed(event.entryFilePath, event.error);
        break;
      case 'dep_graph_loaded':
        terminal.log(`${DEP_GRAPH_MESSAGE}, done.`);
        break;
      case 'global_cache_error':
        const message = JSON.stringify(event.error.message);
        reporting.logWarning(terminal, 'the global cache failed: %s', message);
        break;
      case 'global_cache_disabled':
        this._logCacheDisabled(event.reason);
        break;
      case 'transform_cache_reset':
        reporting.logWarning(terminal, 'the transform cache was reset.');
        break;
    }
  }

  /**
   * We use Math.pow(ratio, 2) to as a conservative measure of progress because
   * we know the `totalCount` is going to progressively increase as well. We
   * also prevent the ratio from going backwards.<commit_msg>packager: TerminalReporter: stop reporting global cache errors<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.
 *
 * @flow
 */

'use strict';

const path = require('path');
const reporting = require('./reporting');
const terminal = require('./terminal');
const throttle = require('lodash/throttle');
const util = require('util');

import type {ReportableEvent, GlobalCacheDisabledReason} from './reporting';

const DEP_GRAPH_MESSAGE = 'Loading dependency graph';
const GLOBAL_CACHE_DISABLED_MESSAGE_FORMAT =
  'The global cache is now disabled because %s';

type BundleProgress = {
  transformedFileCount: number,
  totalFileCount: number,
  ratio: number,
};

const DARK_BLOCK_CHAR = '\u2593';
const LIGHT_BLOCK_CHAR = '\u2591';

function getProgressBar(ratio: number, length: number) {
  const blockCount = Math.floor(ratio * length);
  return (
    DARK_BLOCK_CHAR.repeat(blockCount) +
    LIGHT_BLOCK_CHAR.repeat(length - blockCount)
  );
}

export type TerminalReportableEvent = ReportableEvent | {
  type: 'bundle_transform_progressed_throttled',
  entryFilePath: string,
  transformedFileCount: number,
  totalFileCount: number,
};

type BuildPhase = 'in_progress' | 'done' | 'failed';

/**
 * We try to print useful information to the terminal for interactive builds.
 * This implements the `Reporter` interface from the './reporting' module.
 */
class TerminalReporter {

  /**
   * The bundle builds for which we are actively maintaining the status on the
   * terminal, ie. showing a progress bar. There can be several bundles being
   * built at the same time.
   */
  _activeBundles: Map<string, BundleProgress>;

  _dependencyGraphHasLoaded: boolean;
  _scheduleUpdateBundleProgress: (data: {
    entryFilePath: string,
    transformedFileCount: number,
    totalFileCount: number,
  }) => void;

  constructor() {
    this._dependencyGraphHasLoaded = false;
    this._activeBundles = new Map();
    this._scheduleUpdateBundleProgress = throttle(data => {
      this.update({...data, type: 'bundle_transform_progressed_throttled'});
    }, 200);
  }

  /**
   * Construct a message that represents the progress of a
   * single bundle build, for example:
   *
   *     Bunding `foo.js`  |####         | 34.2% (324/945)
   */
  _getBundleStatusMessage(
    entryFilePath: string,
    {totalFileCount, transformedFileCount, ratio}: BundleProgress,
    phase: BuildPhase,
  ): string {
    const localPath = path.relative('.', entryFilePath);
    return util.format(
      'Bundling `%s`  %s%s% (%s/%s)%s',
      localPath,
      phase === 'in_progress' ? getProgressBar(ratio, 16) + '  ' : '',
      (100 * ratio).toFixed(1),
      transformedFileCount,
      totalFileCount,
      phase === 'done' ? ', done.' : (phase === 'failed' ? ', failed.' : ''),
    );
  }

  _logCacheDisabled(reason: GlobalCacheDisabledReason): void {
    const format = GLOBAL_CACHE_DISABLED_MESSAGE_FORMAT;
    switch (reason) {
      case 'too_many_errors':
        reporting.logWarning(terminal, format, 'it has been failing too many times.');
        break;
      case 'too_many_misses':
        reporting.logWarning(terminal, format, 'it has been missing too many consecutive keys.');
        break;
    }
  }

  _logBundleBuildDone(entryFilePath: string) {
    const progress = this._activeBundles.get(entryFilePath);
    if (progress != null) {
      const msg = this._getBundleStatusMessage(entryFilePath, {
        ...progress,
        ratio: 1,
        transformedFileCount: progress.totalFileCount,
      }, 'done');
      terminal.log(msg);
    }
  }

  _logBundleBuildFailed(entryFilePath: string, error: Error) {
    reporting.logError(terminal, 'bundling: %s', error.stack);
    const progress = this._activeBundles.get(entryFilePath);
    if (progress != null) {
      const msg = this._getBundleStatusMessage(entryFilePath, progress, 'failed');
      terminal.log(msg);
    }
  }

  /**
   * This function is only concerned with logging and should not do state
   * or terminal status updates.
   */
  _log(event: TerminalReportableEvent): void {
    switch (event.type) {
      case 'bundle_build_done':
        this._logBundleBuildDone(event.entryFilePath);
        break;
      case 'bundle_build_failed':
        this._logBundleBuildFailed(event.entryFilePath, event.error);
        break;
      case 'dep_graph_loaded':
        terminal.log(`${DEP_GRAPH_MESSAGE}, done.`);
        break;
      case 'global_cache_disabled':
        this._logCacheDisabled(event.reason);
        break;
      case 'transform_cache_reset':
        reporting.logWarning(terminal, 'the transform cache was reset.');
        break;
    }
  }

  /**
   * We use Math.pow(ratio, 2) to as a conservative measure of progress because
   * we know the `totalCount` is going to progressively increase as well. We
   * also prevent the ratio from going backwards.
{'fraction_non_alphanumeric': 0.11176470588235295, 'fraction_numerical': 0.006171648987463838, 'mean_word_length': 3.4453493356193743, 'pattern_counts': {'":': 0, '<': 5, '<?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': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7303248', 'n_tokens_mistral': 3058, 'n_tokens_neox': 2955, 'n_words': 844}