<commit_before>import chalk from "chalk";
import Table from "cli-table";
import EventEmitter from "events";
import log from "fancy-log";
import gzipSize from "gzip-size";
import merge from "lodash/merge";
import reduce from "lodash/reduce";
import PluginError from "plugin-error";
import prettyBytes from "pretty-bytes";
import { Transform } from "stream";
import StreamCounter from "stream-counter";
import through, { TransformCallback } from "through2";

export interface IOptions {
  gzip: boolean;
  minifySuffix: string;
  taskName: string;
}

interface IFile {
  calculated: boolean;
  sizes: ISizes;
}

interface IFiles {
  [filename: string]: IFile;
}

interface IPrettySizes {
  [size: string]: string;
}

interface ISizes {
  minified: number;
  minifiedGzipped: number;
  size: number;
  sizeGzipped: number;
}

/**
 * Collect sizes of build files and display it.
 */
export default class Size {
  /**
   * Format sizes in human readable form.
   *
   * @param {ISizes} sizes
   * @return {IPrettySizes}
   * @private
   */
  private static _prettyBytes(sizes: ISizes): IPrettySizes {
    const prettyBytess: IPrettySizes = {};

    Object.keys(sizes).forEach((key: string): void => {
      prettyBytess[key] = prettyBytes((sizes as any)[key]);
    });

    return prettyBytess;
  }

  /**
   * Options.
   * @type {IOptions}
   * @private
   */
  private readonly _options: IOptions = {
    gzip: true,
    minifySuffix: "",
    taskName: "",
  };

  /**
   * Event emitter to know when all sizes are calculated.
   * @type {IOptions}
   * @private
   */
  private readonly _emitter: EventEmitter;

  /**
   * List of generated files.
   * @type {IFiles}
   * @private
   */
  private _files: IFiles = {};

  /**
   * Calculate and display sizes of files in stream.
   *
   * @param {IOptions} options
   */
  public constructor(options: IOptions) {
    this._options = merge(this._options, options);

    // Event emitter to know when all sizes are calculated.
    this._emitter = new EventEmitter();
    this._emitter.on("file-sizes-calculated", (): void => {
      const calculatedCount = reduce(this._files, (count: number, file: IFile) => count + (file.calculated ? 1 : 0), 0);
      const filesCount = Object.keys(this._files).length;

      // Head of the table.
      const head: string[] = ["Filename", "Size"];
      if (this._options.minifySuffix !== "") {
        head.push("Minified", "Saved");
      }

      // If all sizes are calculated, display them.
      if (calculatedCount >= filesCount) {
        // Collect sizes in a simple array.
        const files: string[][] = Object.keys(this._files).map((filename: string): string[] => {
          const file: IFile = this._files[filename];
          const prettySizes: IPrettySizes = Size._prettyBytes(file.sizes);

          const row = [
            chalk.cyan(filename),
            prettySizes.size + (this._options.gzip ? chalk.gray(`\n${prettySizes.sizeGzipped} gzipped`) : ""),
          ];

          // Add minified information and differential value.
          if (this._options.minifySuffix !== "") {
            const saved = Math.max(0, file.sizes.size - file.sizes.minified);
            const savedPercent = file.sizes.size === 0 ? 0 : (saved * 100) / file.sizes.size;

            const formatPercent = ("    " + savedPercent.toFixed(1)).slice(-4);

            row.push(
              prettySizes.minified + (this._options.gzip ? chalk.gray(`\n${prettySizes.minifiedGzipped} gzipped`) : ""),
              `${prettyBytes(saved)} ${chalk.gray(`(${formatPercent}%)`)}`
            );
          }

          return row;
        });

        // Create table to display.
        const table = new Table({
          colAligns: ["left", "right", "right", "right"],
          head: head.map((item: string): string => chalk.blue(item)),
        });

        // Add values to display.
        table.push(...files);

        // Display sizes.
        log(`Sizes from '${chalk.cyan(this._options.taskName)}':\n` + table.toString());
      }
    });
  }

  /**
   * Collect sizes of files in a stream.
   *
   * @return {Transform}
   */
  public collect(): Transform {
    return through.obj(
      (file: any, encoding: string, cb: TransformCallback): void => {
        if (file.isNull()) {
          cb(null, file);
          return;
        }

        // Get relative filename regardless of its suffix.
        const relFilename = file.relative.replace(`${this._options.minifySuffix}${file.extname}`, file.extname);

        // Initialize sizes aggregator.
        if (typeof this._files[relFilename] === "undefined") {
          this._files[relFilename] = {
            calculated: false,
            sizes: {
              minified: -1,
              minifiedGzipped: -1,
              size: -1,
              sizeGzipped: -1,
            },
          };
        }

        // Collect sizes.
        const finish = (error: any, size: number, keys: string[]): void => {
          if (error) {
            cb(new PluginError("size", error));
            return;
          }

          // Collect size.
          this._files[relFilename].sizes = merge(this._files[relFilename].sizes, {
            [file.relative.indexOf(this._options.minifySuffix) >= 0 ? keys[1] : keys[0]]: size,
          });

          // Count calculated sizes.
          const countSizes = (Object.keys(this._files[relFilename].sizes) as any[]).filter(
            (key: string): boolean => (this._files[relFilename].sizes as any)[key] >= 0
          ).length;

          // Determine if all sizes is here.
          const calculated = this._files[relFilename].calculated;
          this._files[relFilename].calculated =
            (this._options.minifySuffix === "" && !this._options.gzip && countSizes === 1) ||
            (this._options.minifySuffix !== "" && !this._options.gzip && countSizes === 2) ||
            (this._options.minifySuffix === "" && this._options.gzip && countSizes === 2) ||
            (this._options.minifySuffix !== "" && this._options.gzip && countSizes === 4);

          // Emit event if all sizes are calculated.
          if (!calculated && this._files[relFilename].calculated) {
            this._emitter.emit("file-sizes-calculated", { relFilename });
          }
        };

        // Collect gzipped sizes.
        const finishGzip = (error: any, size: number) => {<commit_msg>Fix key for the correct size<commit_after>import chalk from "chalk";
import Table from "cli-table";
import EventEmitter from "events";
import log from "fancy-log";
import gzipSize from "gzip-size";
import merge from "lodash/merge";
import reduce from "lodash/reduce";
import PluginError from "plugin-error";
import prettyBytes from "pretty-bytes";
import { Transform } from "stream";
import StreamCounter from "stream-counter";
import through, { TransformCallback } from "through2";

export interface IOptions {
  gzip: boolean;
  minifySuffix: string;
  taskName: string;
}

interface IFile {
  calculated: boolean;
  sizes: ISizes;
}

interface IFiles {
  [filename: string]: IFile;
}

interface IPrettySizes {
  [size: string]: string;
}

interface ISizes {
  minified: number;
  minifiedGzipped: number;
  size: number;
  sizeGzipped: number;
}

/**
 * Collect sizes of build files and display it.
 */
export default class Size {
  /**
   * Format sizes in human readable form.
   *
   * @param {ISizes} sizes
   * @return {IPrettySizes}
   * @private
   */
  private static _prettyBytes(sizes: ISizes): IPrettySizes {
    const prettyBytess: IPrettySizes = {};

    Object.keys(sizes).forEach((key: string): void => {
      prettyBytess[key] = prettyBytes((sizes as any)[key]);
    });

    return prettyBytess;
  }

  /**
   * Options.
   * @type {IOptions}
   * @private
   */
  private readonly _options: IOptions = {
    gzip: true,
    minifySuffix: "",
    taskName: "",
  };

  /**
   * Event emitter to know when all sizes are calculated.
   * @type {IOptions}
   * @private
   */
  private readonly _emitter: EventEmitter;

  /**
   * List of generated files.
   * @type {IFiles}
   * @private
   */
  private _files: IFiles = {};

  /**
   * Calculate and display sizes of files in stream.
   *
   * @param {IOptions} options
   */
  public constructor(options: IOptions) {
    this._options = merge(this._options, options);

    // Event emitter to know when all sizes are calculated.
    this._emitter = new EventEmitter();
    this._emitter.on("file-sizes-calculated", (): void => {
      const calculatedCount = reduce(this._files, (count: number, file: IFile) => count + (file.calculated ? 1 : 0), 0);
      const filesCount = Object.keys(this._files).length;

      // Head of the table.
      const head: string[] = ["Filename", "Size"];
      if (this._options.minifySuffix !== "") {
        head.push("Minified", "Saved");
      }

      // If all sizes are calculated, display them.
      if (calculatedCount >= filesCount) {
        // Collect sizes in a simple array.
        const files: string[][] = Object.keys(this._files).map((filename: string): string[] => {
          const file: IFile = this._files[filename];
          const prettySizes: IPrettySizes = Size._prettyBytes(file.sizes);

          const row = [
            chalk.cyan(filename),
            prettySizes.size + (this._options.gzip ? chalk.gray(`\n${prettySizes.sizeGzipped} gzipped`) : ""),
          ];

          // Add minified information and differential value.
          if (this._options.minifySuffix !== "") {
            const saved = Math.max(0, file.sizes.size - file.sizes.minified);
            const savedPercent = file.sizes.size === 0 ? 0 : (saved * 100) / file.sizes.size;

            const formatPercent = ("    " + savedPercent.toFixed(1)).slice(-4);

            row.push(
              prettySizes.minified + (this._options.gzip ? chalk.gray(`\n${prettySizes.minifiedGzipped} gzipped`) : ""),
              `${prettyBytes(saved)} ${chalk.gray(`(${formatPercent}%)`)}`
            );
          }

          return row;
        });

        // Create table to display.
        const table = new Table({
          colAligns: ["left", "right", "right", "right"],
          head: head.map((item: string): string => chalk.blue(item)),
        });

        // Add values to display.
        table.push(...files);

        // Display sizes.
        log(`Sizes from '${chalk.cyan(this._options.taskName)}':\n` + table.toString());
      }
    });
  }

  /**
   * Collect sizes of files in a stream.
   *
   * @return {Transform}
   */
  public collect(): Transform {
    return through.obj(
      (file: any, encoding: string, cb: TransformCallback): void => {
        if (file.isNull()) {
          cb(null, file);
          return;
        }

        // Get relative filename regardless of its suffix.
        const relFilename = file.relative.replace(`${this._options.minifySuffix}${file.extname}`, file.extname);

        // Initialize sizes aggregator.
        if (typeof this._files[relFilename] === "undefined") {
          this._files[relFilename] = {
            calculated: false,
            sizes: {
              minified: -1,
              minifiedGzipped: -1,
              size: -1,
              sizeGzipped: -1,
            },
          };
        }

        // Collect sizes.
        const finish = (error: any, size: number, keys: string[]): void => {
          if (error) {
            cb(new PluginError("size", error));
            return;
          }

          // Collect size.
          const keySize: string =
            this._options.minifySuffix !== "" && file.relative.indexOf(this._options.minifySuffix) >= 0
              ? keys[1]
              : keys[0];
          this._files[relFilename].sizes = merge(this._files[relFilename].sizes, {
            [keySize]: size,
          });

          // Count calculated sizes.
          const countSizes = (Object.keys(this._files[relFilename].sizes) as any[]).filter(
            (key: string): boolean => (this._files[relFilename].sizes as any)[key] >= 0
          ).length;

          // Determine if all sizes is here.
          const calculated = this._files[relFilename].calculated;
          this._files[relFilename].calculated =
            (this._options.minifySuffix === "" && !this._options.gzip && countSizes === 1) ||
            (this._options.minifySuffix !== "" && !this._options.gzip && countSizes === 2) ||
            (this._options.minifySuffix === "" && this._options.gzip && countSizes === 2) ||
            (this._options.minifySuffix !== "" && this._options.gzip && countSizes === 4);

          // Emit event if all sizes are calculated.
          if (!calculated && this._files[relFilename].calculated) {
            this._emitter.emit("file-sizes-calculated", { relFilename });
          }
        };

        // Collect gzipped sizes.
        const finishGzip = (error: any, size: number) => {
{'fraction_non_alphanumeric': 0.143267365153279, 'fraction_numerical': 0.0037252619324796275, 'mean_word_length': 2.288083694820107, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 27, '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': '876460', 'n_tokens_mistral': 3883, 'n_tokens_neox': 3780, 'n_words': 942}